diff options
2022 files changed, 106273 insertions, 63846 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..ee8a8a8c92 --- /dev/null +++ b/.clang-format @@ -0,0 +1,120 @@ +--- +# clang-format version 10.0.0+ +Language: Cpp +# BasedOnStyle: Microsoft +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: true +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: true +BinPackParameters: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Allman +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: true +BreakConstructorInitializers: AfterColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 140 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: true +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + - Regex: '.*' + Priority: 1 + SortPriority: 0 +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentCaseLabels: true +IndentGotoLabels: true +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: Inner +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 1000 +PointerAlignment: Right +ReflowComments: true +SortIncludes: false +SortUsingDeclarations: true +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +Standard: Latest +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +UseCRLF: false +UseTab: Never +... + diff --git a/.hgignore b/.gitignore index 3a5cbe4d94..d664c0b1d4 100755 --- a/.hgignore +++ b/.gitignore @@ -1,46 +1,61 @@ -syntax: glob - -# WinMerge temp files +# By extension +*.DS_Store *.bak -# Compiled python bytecode +*.diff +*.orig +*.patch *.pyc -# Emacs temp files +*.rej +*.swp *~ -.*.swp -#OSX image cache file -*.DS_Store -#*.orig + +# Specific paths and/or names LICENSES -indra/.distcc -build-linux-* build-darwin-* +build-linux-* +debian/files +debian/secondlife-appearance-utility* +debian/secondlife-viewer* +indra/.distcc build-vc80/ build-vc100/ build-vc120/ build-vc120-32/ build-vc120-64/ -indra/build-vc[0-9]* +build-vc150-32/ +build-vc150-64/ indra/CMakeFiles +indra/build-vc[0-9]* indra/lib/mono/1.0/*.dll indra/lib/mono/indra/*.dll indra/lib/mono/indra/*.exe indra/lib/mono/indra/*.pdb indra/lib/python/eventlet/ +indra/lib/python/mulib.* indra/llwindow/glh/glh_linear.h indra/newview/app_settings/dictionaries indra/newview/app_settings/mozilla indra/newview/app_settings/mozilla-runtime-* indra/newview/app_settings/mozilla_debug indra/newview/app_settings/static_*.db2 +indra/newview/avatar_icons_cache.txt +indra/newview/avatar_lad.log indra/newview/browser_profile indra/newview/character +indra/newview/dbghelp.dll +indra/newview/filters.xml indra/newview/fmod.dll indra/newview/fmod.log indra/newview/fonts indra/newview/mozilla-theme indra/newview/mozilla-universal-darwin.tgz -indra/newview/res/ll_icon.* +indra/newview/pilot.txt +indra/newview/pilot.xml indra/newview/res-sdl/ll_icon.* +indra/newview/res/ll_icon.* +indra/newview/search_history.txt +indra/newview/teleport_history.txt +indra/newview/typed_locations.txt indra/newview/vivox-runtime indra/server-linux-* indra/temp @@ -48,36 +63,16 @@ indra/test/linden_file.dat indra/test_apps/llmediatest/dependencies/i686-win32 indra/test_apps/terrain_mule/*.dll indra/viewer-linux-* +indra/web/dataservice/lib/shared/vault.* +indra/web/dataservice/locale.* +indra/web/dataservice/vendor.* indra/web/doc/asset-upload/plugins/lsl_compiler/lslc indra/web/doc/asset-upload/plugins/verify-notecard indra/web/doc/asset-upload/plugins/verify-texture installed.xml libraries tarfile_tmp -debian/secondlife-viewer* -debian/secondlife-appearance-utility* -debian/files -build-stamp -configure-stamp -^indra/lib/python/mulib.* -^web/locale.* -^web/secondlife.com.* -^web/config.* -^indra/web/dataservice/locale.* -^indra/web/dataservice/lib/shared/vault.* -^indra/web/dataservice/vendor.* -glob:indra/newview/dbghelp.dll -glob:*.cpp.orig -glob:*.cpp.bak -glob:*.h.bak -glob:*.h.orig -glob:indra/newview/typed_locations.txt -glob:indra/newview/teleport_history.txt -glob:indra/newview/search_history.txt -glob:indra/newview/filters.xml -glob:indra/newview/avatar_icons_cache.txt -glob:indra/newview/avatar_lad.log -glob:*.diff -indra/newview/pilot.txt -indra/newview/pilot.xml -*.rej +trivial_change_force_build +web/config.* +web/locale.* +web/secondlife.com.*
\ No newline at end of file @@ -554,3 +554,6 @@ ab2ec5c5423b277d23fd0511ce50c15123ff2e03 6.2.3-release 9777aec6dc4a30a24537297ac040861ce16b82ae 6.3.0-release ece699718f163921717bb95a6131e94af4c4138f 6.3.1-release 07f5d5bc9faebb45695853d40a9549773db816c0 6.3.2-release +d9a4bd15e2c852953d6c8e84d6f3b7ca442c0e7f 6.3.3-release +4033b3f57e76f087235145a3016886ccdc87ffa3 6.3.4-release +27ca5834bfe9b80e82db5ea42f08b7eb990b722a 6.3.5-release diff --git a/BuildParams b/BuildParams index c5f96d5ee3..c5f96d5ee3 100755..100644 --- a/BuildParams +++ b/BuildParams @@ -1,6 +1,5 @@ Second Life Viewer ==================== - This project manages the source code for the [Second Life](https://www.secondlife.com) Viewer. diff --git a/autobuild.xml b/autobuild.xml index 131c7614c0..ac7459ddca 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -76,9 +76,9 @@ <key>archive</key> <map> <key>hash</key> - <string>f65774ebabb256f2d217a872b0cf2b5b</string> + <string>b6357ef3a0ec37877a5831820f25094e</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/4812/15284/apr_suite-1.4.5.504800-darwin64-504800.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80557/759704/apr_suite-1.4.5.558565-darwin64-558565.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -112,9 +112,9 @@ <key>archive</key> <map> <key>hash</key> - <string>dc80eca3d113b038b469003da8cd6638</string> + <string>cb48ac069440f6dcd564cfa9fd02a4c2</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/4813/15290/apr_suite-1.4.5.504800-windows-504800.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80556/759710/apr_suite-1.4.5.558565-windows-558565.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -124,16 +124,16 @@ <key>archive</key> <map> <key>hash</key> - <string>63146d3d3d5fe7aa6be1a1b0afed36dd</string> + <string>646dc3828d9c39fb1e77c4eec44ed739</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/4814/15296/apr_suite-1.4.5.504800-windows64-504800.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80555/759709/apr_suite-1.4.5.558565-windows64-558565.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.4.5.504800</string> + <string>1.4.5.558565</string> </map> <key>boost</key> <map> @@ -166,9 +166,9 @@ <key>archive</key> <map> <key>hash</key> - <string>d318c25353e41215f1f523d58cacfd44</string> + <string>35cc090d942b85c9126ceac9912d52d6</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/893/1984/boost-1.57-darwin64-500883.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78585/744021/boost-1.72-darwin64-557045.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -190,9 +190,9 @@ <key>archive</key> <map> <key>hash</key> - <string>8e7ee97c3083f44385b09420655ebd04</string> + <string>038853b97307a9b65de20c4c50098023</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/892/1989/boost-1.57-linux64-500883.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9675/45694/boost-1.65.1-linux64-509640.tar.bz2</string> </map> <key>name</key> <string>linux64</string> @@ -202,9 +202,9 @@ <key>archive</key> <map> <key>hash</key> - <string>80b1963d635e883cb5ed223e94406adb</string> + <string>9aa4ce32df5f5e36124c990e2d77b885</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/894/1976/boost-1.57-windows-500883.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78586/743982/boost-1.72-windows-557045.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -214,16 +214,16 @@ <key>archive</key> <map> <key>hash</key> - <string>3d6a6373ed0daa490cdb4f92db45de52</string> + <string>a79511c9d8b956767ebaa405155d4238</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/895/1979/boost-1.57-windows64-500883.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78584/743961/boost-1.72-windows64-557045.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.57</string> + <string>1.72</string> </map> <key>bugsplat</key> <map> @@ -244,9 +244,9 @@ <key>archive</key> <map> <key>hash</key> - <string>c3b5e8c57bd1c92bc9e0956586908b99</string> + <string>ae90d19cdcddf539f6d0b41cab12f918</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/26330/207568/bugsplat-1.0.7.520791-darwin64-520791.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/72773/702861/bugsplat-1.0.7.552580-darwin64-552580.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -256,9 +256,9 @@ <key>archive</key> <map> <key>hash</key> - <string>766dfde65a5b42ea5691d41df79c43e0</string> + <string>f5936eceb6a33ff0f1cc31996a40f29c</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/26332/207582/bugsplat-3.6.0.4.520791-windows-520791.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/72774/702905/bugsplat-3.6.0.8.552580-windows-552580.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -268,16 +268,16 @@ <key>archive</key> <map> <key>hash</key> - <string>afd01285e22f27d473fac6f88fac9a3b</string> + <string>9cd940754e53e0670030b3da5ba8f373</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/26331/207576/bugsplat-3.6.0.4.520791-windows64-520791.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/72775/702906/bugsplat-3.6.0.8.552580-windows64-552580.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.0.7.520791</string> + <string>3.6.0.8.552580</string> </map> <key>colladadom</key> <map> @@ -296,7 +296,7 @@ <key>archive</key> <map> <key>hash</key> - <string>66849777a83cb69cec3c06b07da7cd3d</string> + <string>726bc31e562752f081e95e8fcc70e405</string> <key>url</key> <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/colladadom_3p-update-colladadom/rev/297450/arch/Darwin/installer/colladadom-2.3.297450-darwin-297450.tar.bz2</string> </map> @@ -308,9 +308,9 @@ <key>archive</key> <map> <key>hash</key> - <string>fa93a9a10fa379091e3e7b85665690d9</string> + <string>1d063cf1783e7788f17486c234adb1db</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/913/2026/colladadom-2.3.500902-darwin64-500902.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78635/744249/colladadom-2.3.557064-darwin64-557064.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -332,9 +332,9 @@ <key>archive</key> <map> <key>hash</key> - <string>868127582794d6fd32fa69c9be4e83e4</string> + <string>c90613240ba3e3a171d3379275ae4ee3</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/912/2031/colladadom-2.3.500902-linux64-500902.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9695/45732/colladadom-2.3.509683-linux64-509683.tar.bz2</string> </map> <key>name</key> <string>linux64</string> @@ -344,9 +344,9 @@ <key>archive</key> <map> <key>hash</key> - <string>5bd7875e16e7f88e21f4c44fe7c6433f</string> + <string>e78ecf919eee01567556787c3a358d15</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/915/2035/colladadom-2.3.500902-windows-500902.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78637/744269/colladadom-2.3.557064-windows-557064.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -356,16 +356,16 @@ <key>archive</key> <map> <key>hash</key> - <string>8a647129a0a0a31594557785ea85f840</string> + <string>7e63a212c8909a25236138422fe01298</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/914/2034/colladadom-2.3.500902-windows64-500902.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78636/744273/colladadom-2.3.557064-windows64-557064.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>2.3.500902</string> + <string>2.3.557064</string> </map> <key>curl</key> <map> @@ -398,9 +398,9 @@ <key>archive</key> <map> <key>hash</key> - <string>f426c56252c70fe38fcb2251f7c1d762</string> + <string>13f74f43a6363ec998569f731fd869c5</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9265/41615/curl-7.54.1.509254-darwin64-509254.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82637/774617/curl-7.54.1.560191-darwin64-560191.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -434,11 +434,11 @@ <key>archive</key> <map> <key>hash</key> - <string>4c7a960e1ee518acceac6a0c65495800</string> + <string>0df99bd685dc3561ca8ea347b2921987</string> <key>hash_algorithm</key> <string>md5</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9268/41606/curl-7.54.1.509254-windows-509254.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82639/774610/curl-7.54.1.560191-windows-560191.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -448,16 +448,16 @@ <key>archive</key> <map> <key>hash</key> - <string>32df7cce1658ccec893fb46cd476c024</string> + <string>50db2a9e6b74ec4b0c38b1ea8f135735</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9267/41607/curl-7.54.1.509254-windows64-509254.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82638/774608/curl-7.54.1.560191-windows64-560191.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>7.54.1.509254</string> + <string>7.54.1.560191</string> </map> <key>db</key> <map> @@ -550,16 +550,16 @@ <key>archive</key> <map> <key>hash</key> - <string>2fa9e9e89a81ed2ed686a170681f6bbc</string> + <string>d778c6a3475bc35ee8b9615dfc38b4a9</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/571/1225/dictionaries-1.500564-common-500564.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55025/511964/dictionaries-1.538984-common-538984.tar.bz2</string> </map> <key>name</key> <string>common</string> </map> </map> <key>version</key> - <string>1.500564</string> + <string>1.538984</string> </map> <key>dullahan</key> <map> @@ -580,9 +580,9 @@ <key>archive</key> <map> <key>hash</key> - <string>23aeaf23e7db2484a1850017141860dd</string> + <string>45dedb5b09995cd794304150e94fcf21</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/34069/283470/dullahan-1.1.1320_3.3626.1895.g7001d56-darwin64-525361.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87950/806969/dullahan-1.12.2.202109170444_91.1.21_g9dd45fe_chromium-91.0.4472.114-darwin64-563968.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -592,9 +592,9 @@ <key>archive</key> <map> <key>hash</key> - <string>71fa66203326aca918796e874976c080</string> + <string>d0fd9d7086699da4bb5ccc935622a717</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/34070/283477/dullahan-1.1.1320_3.3626.1895.g7001d56-windows-525361.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/88276/809277/dullahan-1.12.2.202109230751_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows-563968.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -604,16 +604,16 @@ <key>archive</key> <map> <key>hash</key> - <string>c7162e4805f50a3609f5dc63d0cf2bc0</string> + <string>7e8c3ccd420ff5aef24ff72d609ba394</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/34071/283480/dullahan-1.1.1320_3.3626.1895.g7001d56-windows64-525361.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/88275/809281/dullahan-1.12.2.202109230751_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows64-563968.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.1.1320_3.3626.1895.g7001d56</string> + <string>1.12.2.202109230751_91.1.21_g9dd45fe_chromium-91.0.4472.114</string> </map> <key>elfio</key> <map> @@ -670,9 +670,9 @@ <key>archive</key> <map> <key>hash</key> - <string>fd182ab5bed66c94899dec3035310945</string> + <string>f4e80e0dfcab713a3da90cd8f7f23e7b</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/384/954/expat-2.1.1.500375-darwin64-500375.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76341/727265/expat-2.1.1.555519-darwin64-555519.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -706,9 +706,9 @@ <key>archive</key> <map> <key>hash</key> - <string>09ece3f04ec0bd21dd0d401235aa20f7</string> + <string>cd4fe03473076c324d80ae3bd91a85bb</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/383/949/expat-2.1.1.500375-windows-500375.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76343/727273/expat-2.1.1.555519-windows-555519.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -718,49 +718,39 @@ <key>archive</key> <map> <key>hash</key> - <string>5c82a3482799fe22b3c8fcb317f87bbb</string> + <string>d2d74d73b914150982b1883a3b96e60b</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/382/946/expat-2.1.1.500375-windows64-500375.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76344/727279/expat-2.1.1.555519-windows64-555519.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>2.1.1.500375</string> + <string>2.1.1.555519</string> </map> - <key>fmodex</key> + <key>fmodstudio</key> <map> <key>copyright</key> - <string>COPYRIGHT 2014 FIRELIGHT TECHNOLOGIES PTY LTD. ALL RIGHTS RESERVED</string> + <string>FMOD Studio by Firelight Technologies Pty Ltd.</string> + <key>description</key> + <string>FMOD Studio API</string> <key>license</key> - <string>fmodex</string> + <string>fmod</string> <key>license_file</key> - <string>LICENSES/fmodex.txt</string> + <string>LICENSES/fmodstudio.txt</string> <key>name</key> - <string>fmodex</string> + <string>fmodstudio</string> <key>platforms</key> <map> - <key>darwin</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>ed0d8767652aecd65a7fef3e28645bad</string> - <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/fmodex_3p-update-fmodex/rev/297261/arch/Darwin/installer/fmodex-4.44.31.297261-darwin-297261.tar.bz2</string> - </map> - <key>name</key> - <string>darwin</string> - </map> <key>darwin64</key> <map> <key>archive</key> <map> <key>hash</key> - <string>93257fce19120c01751362775a01b925</string> + <string>d5528538e67c710387ae0c061a90cb23</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/1545/3481/fmodex-4.44.64.501533-darwin64-501533.tar.bz2</string> + <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76868/730756/fmodstudio-2.01.07.555883-darwin64-555883.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -770,9 +760,9 @@ <key>archive</key> <map> <key>hash</key> - <string>b847ec838da1ad1dd646df9d74e9b395</string> + <string>5283050c22d31877cd9e0afbe6feb9fc</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/p64_3p-fmodex/rev/314207/arch/Linux/installer/fmodex-4.44.61.314207-linux-314207.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/65398/612630/fmodstudio-2.00.11.546392-linux-546392.tar.bz2</string> </map> <key>name</key> <string>linux</string> @@ -782,9 +772,9 @@ <key>archive</key> <map> <key>hash</key> - <string>89a75d8719f7b2cbe1e54cd8407bb992</string> + <string>5a3c78f4a77ae6477986e33836725e8b</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/1544/3476/fmodex-4.44.64.501533-linux64-501533.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/65399/612631/fmodstudio-2.00.11.546392-linux64-546392.tar.bz2</string> </map> <key>name</key> <string>linux64</string> @@ -794,9 +784,9 @@ <key>archive</key> <map> <key>hash</key> - <string>601c2fc41a18812a45678ef9a87ef772</string> + <string>a2bb6eaf51f933993b26a5fe7503a761</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/1546/3486/fmodex-4.44.64.501533-windows-501533.tar.bz2</string> + <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76869/730763/fmodstudio-2.01.07.555883-windows-555883.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -806,16 +796,16 @@ <key>archive</key> <map> <key>hash</key> - <string>e5cde35ae26ebfa256cfe670986e152e</string> + <string>138d07dd516a9ad5b9787192fe6134dd</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/1547/3487/fmodex-4.44.64.501533-windows64-501533.tar.bz2</string> + <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76867/730751/fmodstudio-2.01.07.555883-windows64-555883.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>4.44.64.501533</string> + <string>2.01.07.555883</string> </map> <key>fonts</key> <map> @@ -920,9 +910,9 @@ <key>archive</key> <map> <key>hash</key> - <string>3f0698d53acf14b3f0a11dba889d67f3</string> + <string>3a478d6c8a10d49d9161ef864394b03c</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/875/1919/freetype-2.4.4.500865-darwin64-500865.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78592/744013/freetype-2.4.4.557047-darwin64-557047.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -977,7 +967,7 @@ </map> </map> <key>version</key> - <string>2.4.4.500865</string> + <string>2.4.4.557047</string> </map> <key>glext</key> <map> @@ -993,6 +983,18 @@ <string>glext</string> <key>platforms</key> <map> + <key>darwin64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>1bd3214ac23474ea4c869e386970a1be</string> + <key>url</key> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54835/510029/glext-68-darwin64-538965.tar.bz2</string> + </map> + <key>name</key> + <string>darwin64</string> + </map> <key>linux</key> <map> <key>archive</key> @@ -1022,9 +1024,9 @@ <key>archive</key> <map> <key>hash</key> - <string>731d4adecfcbd9f7d20c4bbd2c183962</string> + <string>6a311615bce59b01cf73ee65012a9b38</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-glext/rev/314200/arch/CYGWIN/installer/glext-68-windows-314200.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54951/511711/glext-68-windows-538965.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -1034,9 +1036,9 @@ <key>archive</key> <map> <key>hash</key> - <string>9635e7e6fded468dfc0874a2ead54123</string> + <string>daf619dab1cf7518af6532b18800c4b0</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-glext/rev/314200/arch/CYGWIN/installer/glext-68-windows64-314200.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54924/511490/glext-68-windows64-538965.tar.bz2</string> </map> <key>name</key> <string>windows64</string> @@ -1064,9 +1066,9 @@ <key>archive</key> <map> <key>hash</key> - <string>fa41756977ad8b9fd2d1465dadd4f956</string> + <string>650e836255b6c2ecb93d3f1f7220051c</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/529/1139/glh_linear-0.0.0-common-500522.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55011/511905/glh_linear-0.0.0-common-538981.tar.bz2</string> </map> <key>name</key> <string>common</string> @@ -1106,9 +1108,9 @@ <key>archive</key> <map> <key>hash</key> - <string>017ef34ddf14293099a90c6eaa3615ca</string> + <string>a9eaa005ff9d387f946283fbcb69b3c8</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1626/3627/glod-1.0pre3.501614-darwin64-501614.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76353/727324/glod-1.0pre3.555522-darwin64-555522.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -1144,101 +1146,11 @@ <key>archive</key> <map> <key>hash</key> - <string>573e68f46f825a1c040daa4994ee2a61</string> + <string>e36c95b0d0fbaa3ff3392facaf5de447</string> <key>hash_algorithm</key> <string>md5</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1627/3633/glod-1.0pre3.501614-windows-501614.tar.bz2</string> - </map> - <key>name</key> - <string>windows</string> - </map> - <key>windows64</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>f8362e1a2f4d03d99c6231101d3d472e</string> - <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1628/3638/glod-1.0pre3.501614-windows64-501614.tar.bz2</string> - </map> - <key>name</key> - <string>windows64</string> - </map> - </map> - <key>version</key> - <string>1.0pre3.501614</string> - </map> - <key>google_breakpad</key> - <map> - <key>copyright</key> - <string>Copyright (c) 2006, Google Inc.</string> - <key>description</key> - <string>Breakpad is a crossplatform library for capturing crash callstacks and runtime data.</string> - <key>license</key> - <string>bsd</string> - <key>license_file</key> - <string>LICENSES/google_breakpad.txt</string> - <key>name</key> - <string>google_breakpad</string> - <key>platforms</key> - <map> - <key>darwin</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>171b39db6d0702535b41fad5b476e39d</string> - <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/google-breakpad_3p-update-google-breakpad/rev/298033/arch/Darwin/installer/google_breakpad-1413.298033-darwin-298033.tar.bz2</string> - </map> - <key>name</key> - <string>darwin</string> - </map> - <key>darwin64</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>2d43c6a149cd9c89ba19e884579b1e25</string> - <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1836/4096/google_breakpad-1413.501824-darwin64-501824.tar.bz2</string> - </map> - <key>name</key> - <string>darwin64</string> - </map> - <key>linux</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>352e673897e8f36f8470150b8ace6ce9</string> - <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-google-breakpad/rev/314225/arch/Linux/installer/google_breakpad-1413.314225-linux-314225.tar.bz2</string> - </map> - <key>name</key> - <string>linux</string> - </map> - <key>linux64</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>6bddcc1ac470dd5eab459220102df9e9</string> - <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1835/4114/google_breakpad-1413.501824-linux64-501824.tar.bz2</string> - </map> - <key>name</key> - <string>linux64</string> - </map> - <key>windows</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>6a7929c7280a5c9b528fdd334da5c2d1</string> - <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1838/4108/google_breakpad-1413.501824-windows-501824.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55008/511893/glod-1.0pre3.538980-windows-538980.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -1248,16 +1160,16 @@ <key>archive</key> <map> <key>hash</key> - <string>4fb761717f3ce6ccabdaeb009272b7ca</string> + <string>6302ee1903ab419e76565d9eb6acd274</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1837/4103/google_breakpad-1413.501824-windows64-501824.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55004/511885/glod-1.0pre3.538980-windows64-538980.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1413.501824</string> + <string>1.0pre3.555522</string> </map> <key>googlemock</key> <map> @@ -1290,9 +1202,9 @@ <key>archive</key> <map> <key>hash</key> - <string>1a8081953bdf1bbbc9b8a8e6e062c02d</string> + <string>19e925604bc1a91efb4b130e1edd8bf2</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/919/2048/googlemock-1.7.0.500908-darwin64-500908.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78620/744140/googlemock-1.7.0.557057-darwin64-557057.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -1314,9 +1226,9 @@ <key>archive</key> <map> <key>hash</key> - <string>0f606bf01f933f00edeb9bf9a2530930</string> + <string>ff459b58695c76838782847a0b792104</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/918/2056/googlemock-1.7.0.500908-linux64-500908.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9697/45717/googlemock-1.7.0.509686-linux64-509686.tar.bz2</string> </map> <key>name</key> <string>linux64</string> @@ -1326,9 +1238,9 @@ <key>archive</key> <map> <key>hash</key> - <string>d01c9b12be6c5bb0749441495d45cba3</string> + <string>eed7b41d0d1f41b24f315349ef78c728</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/920/2051/googlemock-1.7.0.500908-windows-500908.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78622/744148/googlemock-1.7.0.557057-windows-557057.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -1338,16 +1250,16 @@ <key>archive</key> <map> <key>hash</key> - <string>e508a2ac7900853cc551666d0cf06541</string> + <string>a6ad6fe722d2fe4e8137495af3f374c9</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/921/2059/googlemock-1.7.0.500908-windows64-500908.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78621/744152/googlemock-1.7.0.557057-windows64-557057.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.7.0.500908</string> + <string>1.7.0.557057</string> </map> <key>gstreamer</key> <map> @@ -1460,9 +1372,9 @@ <key>archive</key> <map> <key>hash</key> - <string>a0c4405c9e44d4a0135fe20ba8cfbace</string> + <string>ba229348c1d9d58519cd854ff9d8ef3d</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/4693/14627/havok_source-2012.1-2-darwin64-504680.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/55213/512968/havok_source-2012.1-2-darwin64-539117.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -1496,9 +1408,9 @@ <key>archive</key> <map> <key>hash</key> - <string>035572a1929be66f6c56468e0ef7fe74</string> + <string>4ff2af85106907acb171bb1e38a3757e</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/4695/14637/havok_source-2012.1-2-windows-504680.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/55214/512993/havok_source-2012.1-2-windows-539117.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -1508,9 +1420,9 @@ <key>archive</key> <map> <key>hash</key> - <string>d8525d2fbb9e0f7bc31427b47350e468</string> + <string>bcaf4631ea10f7d09eecb73e8f5bef6c</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/4694/14634/havok_source-2012.1-2-windows64-504680.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/55212/512962/havok_source-2012.1-2-windows64-539117.tar.bz2</string> </map> <key>name</key> <string>windows64</string> @@ -1640,9 +1552,9 @@ <key>archive</key> <map> <key>hash</key> - <string>4e7fef9c6ae9b7ccf19b7fdb96912b9c</string> + <string>3f2e34e3a2dac8eea957cad143a71dc5</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/3152/7571/jpeglib-8c.503140-darwin64-503140.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54847/510113/jpeglib-8c.538977-darwin64-538977.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -1676,9 +1588,9 @@ <key>archive</key> <map> <key>hash</key> - <string>00523662f6a7388377166e9415e113e9</string> + <string>c8dee00ef13af40ec68becc25830e195</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/3153/7557/jpeglib-8c.503140-windows-503140.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54992/511854/jpeglib-8c.538977-windows-538977.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -1688,16 +1600,16 @@ <key>archive</key> <map> <key>hash</key> - <string>70ed49ed2317b6dba9af1f186956ac79</string> + <string>6f40620e86f3c9b91b6b5fe3c81776fc</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/3154/7558/jpeglib-8c.503140-windows64-503140.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54991/511847/jpeglib-8c.538977-windows64-538977.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>8c.503140</string> + <string>8c.538977</string> </map> <key>jsoncpp</key> <map> @@ -1730,9 +1642,9 @@ <key>archive</key> <map> <key>hash</key> - <string>3564da2ab285a8652d2ee157d1f167e2</string> + <string>87d32aaac4183590c96edd0b6d9bf3e4</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1478/3283/jsoncpp-0.5.0.501464-darwin64-501464.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54846/510106/jsoncpp-0.5.0.538976-darwin64-538976.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -1766,9 +1678,9 @@ <key>archive</key> <map> <key>hash</key> - <string>ed25115f3e53e59d4d26e0953c273648</string> + <string>b73d9addab278eacc100bd312ab6ec5c</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1476/3277/jsoncpp-0.5.0.501464-windows-501464.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54990/511840/jsoncpp-0.5.0.538976-windows-538976.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -1778,16 +1690,16 @@ <key>archive</key> <map> <key>hash</key> - <string>b328db840fd28532be39556d130c9439</string> + <string>1b9ac5708cc526d2c5358ef0a427109d</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1477/3284/jsoncpp-0.5.0.501464-windows64-501464.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54989/511833/jsoncpp-0.5.0.538976-windows64-538976.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>0.5.0.501464</string> + <string>0.5.0.538976</string> </map> <key>kdu</key> <map> @@ -1820,9 +1732,9 @@ <key>archive</key> <map> <key>hash</key> - <string>d1521becaf21bf7233173722af63f57d</string> + <string>ccfd8eacd1ebe92715944094064ba2e4</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/15257/98440/kdu-7.10.4.513518-darwin64-513518.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/55187/512570/kdu-7.10.4.539108-darwin64-539108.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -1856,9 +1768,9 @@ <key>archive</key> <map> <key>hash</key> - <string>0e5b37a03a3f873d15142473b193ec5f</string> + <string>38574fbcb6c94c42745ef48748002e58</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/15259/98463/kdu-7.10.4.513518-windows-513518.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/55189/512583/kdu-7.10.4.539108-windows-539108.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -1868,16 +1780,16 @@ <key>archive</key> <map> <key>hash</key> - <string>da3b1ea90797b189d80ab5d50fdf05d4</string> + <string>3dfeb869c781a766874f0aedc7d4fcef</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/15260/98469/kdu-7.10.4.513518-windows64-513518.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/55188/512576/kdu-7.10.4.539108-windows64-539108.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>7.A.4.513518</string> + <string>7.10.4.539108</string> </map> <key>libhunspell</key> <map> @@ -1910,9 +1822,9 @@ <key>archive</key> <map> <key>hash</key> - <string>4b238300cf9c405cdcab18030372832f</string> + <string>2021ea3a19b81c82993e733709683303</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/534/1149/libhunspell-1.3.2.500526-darwin64-500526.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76371/727419/libhunspell-1.3.2.555528-darwin64-555528.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -1946,9 +1858,9 @@ <key>archive</key> <map> <key>hash</key> - <string>a2025f748a6311ab390f89068b22c702</string> + <string>2253ec09136cc7c208481030d78d9dd7</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/535/1152/libhunspell-1.3.2.500526-windows-500526.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76369/727412/libhunspell-1.3.2.555528-windows-555528.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -1958,16 +1870,16 @@ <key>archive</key> <map> <key>hash</key> - <string>233d86906ef88fa331263162a53e29f2</string> + <string>858d1708f6b3a74738a3d57a5387e20f</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/536/1155/libhunspell-1.3.2.500526-windows64-500526.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76370/727413/libhunspell-1.3.2.555528-windows64-555528.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.3.2.500526</string> + <string>1.3.2.555528</string> </map> <key>libndofdev</key> <map> @@ -2000,9 +1912,9 @@ <key>archive</key> <map> <key>hash</key> - <string>840bb6219f63a789749f5f6583c44eee</string> + <string>a487fff84208a45844602c4a1f68c974</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/704/1420/libndofdev-0.1.500695-darwin64-500695.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76356/727333/libndofdev-0.1.555523-darwin64-555523.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -2012,9 +1924,9 @@ <key>archive</key> <map> <key>hash</key> - <string>fdbebbbde3b289d93c0c8c294cf859cb</string> + <string>4c839555bf0ed9ae60ffc3f8a7c96f9b</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/708/1426/libndofdev-0.1.500695-windows-500695.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76354/727340/libndofdev-0.1.555523-windows-555523.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -2024,16 +1936,16 @@ <key>archive</key> <map> <key>hash</key> - <string>15cef2cec6c8d1980011e26249bd4e90</string> + <string>cbc033ae3b034b992b59f6de1034247c</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/707/1423/libndofdev-0.1.500695-windows64-500695.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76355/727341/libndofdev-0.1.555523-windows64-555523.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>0.1.500695</string> + <string>0.1.555523</string> </map> <key>libpng</key> <map> @@ -2066,9 +1978,9 @@ <key>archive</key> <map> <key>hash</key> - <string>537b59a75709bd9abe0abe0c7309add4</string> + <string>2a41acc3116ce19a443873216cb882ad</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/883/1951/libpng-1.6.8.500873-darwin64-500873.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78587/743948/libpng-1.6.8.557046-darwin64-557046.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -2102,9 +2014,9 @@ <key>archive</key> <map> <key>hash</key> - <string>9c2950f9d16566979dcd6ca6336778b3</string> + <string>b935b440947f63c69700bdcf5095a8e1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/885/1957/libpng-1.6.8.500873-windows-500873.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78591/743970/libpng-1.6.8.557046-windows-557046.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -2114,16 +2026,16 @@ <key>archive</key> <map> <key>hash</key> - <string>18fe233471e91d5d3ac6d08a296b79ba</string> + <string>d1cc8354ac4e877eefedf16b1be3aac6</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/884/1954/libpng-1.6.8.500873-windows64-500873.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78589/743991/libpng-1.6.8.557046-windows64-557046.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.6.8.500873</string> + <string>1.6.8.557046</string> </map> <key>libuuid</key> <map> @@ -2198,9 +2110,9 @@ <key>archive</key> <map> <key>hash</key> - <string>89a71a652a5ecd7cf6142ff56f40f018</string> + <string>6677173bbbb0ea32369b5e9b6c9aa641</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/891/1973/libxml2-2.9.4.500877-darwin64-500877.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78631/744225/libxml2-2.9.4.557062-darwin64-557062.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -2234,9 +2146,9 @@ <key>archive</key> <map> <key>hash</key> - <string>c2461ba7629c4cef5af623464aded3c6</string> + <string>ad6a596fbf0e83a21d95762da78437bc</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/888/1960/libxml2-2.9.4.500877-windows-500877.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78633/744239/libxml2-2.9.4.557062-windows-557062.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -2246,16 +2158,16 @@ <key>archive</key> <map> <key>hash</key> - <string>8ec25000f5d72e26c2e7555c73898fbb</string> + <string>6b5bb230684ecf28386d7c91c47bb6e1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/889/1963/libxml2-2.9.4.500877-windows64-500877.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78634/744240/libxml2-2.9.4.557062-windows64-557062.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>2.9.4.500877</string> + <string>2.9.4.557062</string> </map> <key>llappearance_utility</key> <map> @@ -2305,16 +2217,18 @@ <key>archive</key> <map> <key>hash</key> - <string>dd008981cac7ede93efa6cefe4ee61a0</string> + <string>0a6349b11c8e9d34f0c80b8081736e75</string> + <key>hash_algorithm</key> + <string>md5</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12484/73813/llca-201801172118.511910-common-511910.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/79438/751815/llca-202104010215.557744-common-557744.tar.bz2</string> </map> <key>name</key> <string>common</string> </map> </map> <key>version</key> - <string>201801172118.511910</string> + <string>202104010215.557744</string> </map> <key>llphysicsextensions_source</key> <map> @@ -2333,9 +2247,9 @@ <key>archive</key> <map> <key>hash</key> - <string>162a3fc9b66626072ec8679361b174f5</string> + <string>14fac452271ebfba37ba5ddcf5bffa54</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/4722/14837/llphysicsextensions_source-1.0.504710-darwin64-504710.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54842/510078/llphysicsextensions_source-1.0.538972-darwin64-538972.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -2357,16 +2271,16 @@ <key>archive</key> <map> <key>hash</key> - <string>dd85c9e0f5fa3ce483ea183db008c4bc</string> + <string>f3c066c1aebed8a6519a3e5ce64b9a3c</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/4726/14858/llphysicsextensions_source-1.0.504710-windows-504710.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54982/511796/llphysicsextensions_source-1.0.538972-windows-538972.tar.bz2</string> </map> <key>name</key> <string>windows</string> </map> </map> <key>version</key> - <string>1.0.504710</string> + <string>1.0.538972</string> </map> <key>llphysicsextensions_stub</key> <map> @@ -2385,9 +2299,9 @@ <key>archive</key> <map> <key>hash</key> - <string>566aa2c6f5b2f40a8b0bedf90d9c6beb</string> + <string>f290b000b31f9e36f2489946cbc99f5e</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/4723/14838/llphysicsextensions_stub-1.0.504712-darwin64-504712.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/59995/563653/llphysicsextensions_stub-1.0.542456-darwin64-542456.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -2409,16 +2323,80 @@ <key>archive</key> <map> <key>hash</key> - <string>d830aca10ea9396557b1e613c2736e49</string> + <string>2e5f1f7046a49d8b0bc295aa878116bc</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/4725/14853/llphysicsextensions_stub-1.0.504712-windows-504712.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/60043/564063/llphysicsextensions_stub-1.0.542456-windows-542456.tar.bz2</string> </map> <key>name</key> <string>windows</string> </map> </map> <key>version</key> - <string>1.0.504712</string> + <string>1.0.542456</string> + </map> + <key>llphysicsextensions_tpv</key> + <map> + <key>copyright</key> + <string>Copyright (c) 2010, Linden Research, Inc.</string> + <key>license</key> + <string>internal</string> + <key>license_file</key> + <string>LICENSES/HavokSublicense.pdf</string> + <key>name</key> + <string>llphysicsextensions_tpv</string> + <key>platforms</key> + <map> + <key>darwin64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>2aa4ec0d72bbe4b755730f1bf92b39e7</string> + <key>url</key> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/30340/257304/llphysicsextensions_tpv-1.0.542327-darwin64-542327.tar.bz2</string> + </map> + <key>name</key> + <string>darwin64</string> + </map> + <key>linux64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>711f4ec769e4b5f59ba25ee43c11bcbc</string> + <key>url</key> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/4724/14846/llphysicsextensions_stub-1.0.504712-linux64-504712.tar.bz2</string> + </map> + <key>name</key> + <string>linux64</string> + </map> + <key>windows</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>ad9aba5e2c43a37b6530a0d2de64df1c</string> + <key>url</key> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/30341/257307/llphysicsextensions_tpv-1.0.542327-windows-542327.tar.bz2</string> + </map> + <key>name</key> + <string>windows</string> + </map> + <key>windows64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>46689ff1442a8eccac3a7f3258308e1e</string> + <key>url</key> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/30341/257307/llphysicsextensions_tpv-1.0.542327-windows64-542327.tar.bz2</string> + </map> + <key>name</key> + <string>windows</string> + </map> + </map> + <key>version</key> + <string>1.0.542327</string> </map> <key>mesa</key> <map> @@ -2466,9 +2444,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>f51bcd9245ed4e4ca1fa250ba9b112ce</string> + <string>e4f784d8a035c51921a1562ca7a1bab6</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9259/41575/nghttp2-1.25.0.509246-darwin64-509246.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76357/727350/nghttp2-1.40.0.555524-darwin64-555524.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -2502,9 +2480,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>8367d6743356ad637e61335ee319f7a7</string> + <string>af05aa2994c9845308fecd094b7b2d25</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9261/41597/nghttp2-1.25.0.509246-windows-509246.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76359/727360/nghttp2-1.40.0.555524-windows-555524.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -2514,9 +2492,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>3267acca5dbfe6b8770deeebd548ee6a</string> + <string>5a55cede40eef16b9d1e47c418a2b77a</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9260/41591/nghttp2-1.25.0.509246-windows64-509246.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76358/727359/nghttp2-1.40.0.555524-windows64-555524.tar.bz2</string> </map> <key>name</key> <string>windows64</string> @@ -2525,7 +2503,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>source_type</key> <string>hg</string> <key>version</key> - <string>1.25.0.509246</string> + <string>1.40.0.555524</string> </map> <key>nvapi</key> <map> @@ -2546,9 +2524,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>22c7be12c1d2ee87b059be903d7f2fbd</string> + <string>4305515ad326c911a390388366a9107b</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-nvapi/rev/314405/arch/CYGWIN/installer/nvapi-352.314405-windows-314405.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54947/511704/nvapi-352.539058-windows-539058.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -2558,16 +2536,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>90e32843a0e21037001dc88240008e1f</string> + <string>25c8ac919f24b8952653d38ec43640e5</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-nvapi/rev/314405/arch/CYGWIN/installer/nvapi-352.314405-windows64-314405.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54945/511697/nvapi-352.539058-windows64-539058.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>352.314405</string> + <string>352.539058</string> </map> <key>ogg_vorbis</key> <map> @@ -2600,9 +2578,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>2c17cfd900c88914e06947fe0f1fdae4</string> + <string>a066f1d12caee1d87fc72f48169f9677</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/25395/199641/ogg_vorbis-1.3.3-1.3.6.520171-darwin64-520171.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54841/510071/ogg_vorbis-1.3.3-1.3.6.538971-darwin64-538971.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -2636,9 +2614,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>1818627d4d1f05b49709717e240bdcf4</string> + <string>d4b8ed3fd679a2b484d2d1a66c063908</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/25396/199634/ogg_vorbis-1.3.3-1.3.6.520171-windows-520171.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54981/511789/ogg_vorbis-1.3.3-1.3.6.538971-windows-538971.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -2648,16 +2626,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>d124788c798684c890c1803fca541a10</string> + <string>ec4a657fe639bb458ee5132062146a7a</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/25397/199631/ogg_vorbis-1.3.3-1.3.6.520171-windows64-520171.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54980/511782/ogg_vorbis-1.3.3-1.3.6.538971-windows64-538971.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.3.3-1.3.6.520171</string> + <string>1.3.3-1.3.6.538971</string> </map> <key>open-libndofdev</key> <map> @@ -2790,9 +2768,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>f7013e1f0b6a877090622fd73ec72cbc</string> + <string>5abf2d9c0b250821c59cc60cd94fd8af</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1114/2576/openjpeg-1.5.1.501102-darwin64-501102.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54840/510064/openjpeg-1.5.1.538970-darwin64-538970.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -2826,9 +2804,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>8a7f0be5647e07235d205ac00805fb78</string> + <string>222a406ecb4071a9cc9635353afa337e</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1116/2586/openjpeg-1.5.1.501102-windows-501102.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54977/511775/openjpeg-1.5.1.538970-windows-538970.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -2838,16 +2816,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>398544058036bc27097fcff208934d11</string> + <string>5b5c80807fa8161f3480be3d89fe9516</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1115/2581/openjpeg-1.5.1.501102-windows64-501102.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54974/511767/openjpeg-1.5.1.538970-windows64-538970.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.5.1.501102</string> + <string>1.5.1.538970</string> </map> <key>openssl</key> <map> @@ -2880,9 +2858,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>6c28cce95e3576daf66252b07d9d151f</string> + <string>5503e4928bcdb0a29685b3242c4a409b</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/8340/33489/openssl-1.0.2l.508328-darwin64-508328.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82619/774464/openssl-1.1.1l.560177-darwin64-560177.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -2916,9 +2894,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>ffdb11a4c7aff72086c01555f931c918</string> + <string>d2153f20dc2d35c609b876a9f019a748</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/8341/33481/openssl-1.0.2l.508328-windows-508328.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82623/774521/openssl-1.1.1l.560177-windows-560177.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -2928,16 +2906,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>d875fc7d1f3a7bd9f85cfde05d9ae3dc</string> + <string>f40b8622ba38084b0962e273988d748f</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/8342/33480/openssl-1.0.2l.508328-windows64-508328.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82624/774520/openssl-1.1.1l.560177-windows64-560177.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.0.2l.508328</string> + <string>1.1.1l.560177</string> </map> <key>pcre</key> <map> @@ -2970,9 +2948,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>addfbc0635b0ea65d7a151dd7ec5ef85</string> + <string>d8c0f97fe5abef43e72b6f84aba698b2</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/909/2015/pcre-8.35.500898-darwin64-500898.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54856/510176/pcre-8.35.538986-darwin64-538986.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -3006,9 +2984,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>150220f39f0aa5a8d9e609b450a9b147</string> + <string>3660db45793df3050b63920bfb7d8479</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/911/2021/pcre-8.35.500898-windows-500898.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55041/512002/pcre-8.35.538986-windows-538986.tar.bz2</string> </map> <key>name</key> <string>linux</string> @@ -3018,16 +2996,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>eaebfb4a96a6306ee8e0b18434d125f9</string> + <string>cdee8e8b48a66266550bf279c40abc22</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/910/2018/pcre-8.35.500898-windows64-500898.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55038/511992/pcre-8.35.538986-windows64-538986.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>8.35.500898</string> + <string>8.35.538986</string> </map> <key>slvoice</key> <map> @@ -3038,7 +3016,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>license</key> <string>Mixed</string> <key>license_file</key> - <string>LICENSES/slvoice.txt</string> + <string>LICENSES/vivox_licenses.txt</string> <key>name</key> <string>slvoice</string> <key>platforms</key> @@ -3060,9 +3038,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>a605ec940768c878527d3b8f2ff61288</string> + <string>6ce3cbaed968a69fb7a2cca80220874d</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/21421/157284/slvoice-4.9.0002.30313.517593-darwin64-517593.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80380/758537/slvoice-4.10.0000.32327.5fc3fe7c.558436-darwin64-558436.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -3096,9 +3074,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>5a78539626b5f23522d0b466247f48b4</string> + <string>2eb38c5eff4d0f18fbb89d0c30c4f0a4</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/21422/157291/slvoice-4.9.0002.30313.517593-windows-517593.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80382/758550/slvoice-4.10.0000.32327.5fc3fe7c.558436-windows-558436.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -3108,16 +3086,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>1f8e09c053c00d9dc44ea74568e63dc1</string> + <string>9ee8f3cbc5369c598a998c61961ed16d</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/21423/157298/slvoice-4.9.0002.30313.517593-windows64-517593.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80381/758551/slvoice-4.10.0000.32327.5fc3fe7c.558436-windows64-558436.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>4.9.0002.30313.517593</string> + <string>4.10.0000.32327.5fc3fe7c.558436</string> </map> <key>tut</key> <map> @@ -3138,9 +3116,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>722563bd6e2ae0c7e53c027d267154f7</string> + <string>64e1c979aea2f74fe9c2d9d04573336d</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/496/1054/tut-2008.11.30-common-500403.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55001/511871/tut-2008.11.30-common-539059.tar.bz2</string> </map> <key>name</key> <string>common</string> @@ -3180,9 +3158,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>5b9cd1d6fac519aad59f6d53a54229c5</string> + <string>c42575ac8997de979eadb082c33a578e</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/347/872/uriparser-0.8.0.1-darwin64-500342.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81322/765512/uriparser-0.9.4-darwin64-559132.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -3216,9 +3194,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>1becd11c19dd1763f0322ba4d1a5ee06</string> + <string>901b1063556fc6b2575e745eef2bf744</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/521/1129/uriparser-0.8.0.1-windows-500342.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81323/765528/uriparser-0.9.4-windows-559132.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -3228,16 +3206,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>587db55a2a3ce57628374b5e27b3272e</string> + <string>962c01d553f286c430102998129fb0d6</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/349/875/uriparser-0.8.0.1-windows64-500342.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81324/765527/uriparser-0.9.4-windows64-559132.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>0.8.0.1</string> + <string>0.9.4</string> </map> <key>viewer-manager</key> <map> @@ -3258,9 +3236,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>42066e2447c7a3359784438d16510992</string> + <string>6989053898b8e81e904e75553e378820</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/40539/348124/viewer_manager-2.0.529188-darwin64-529188.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/77523/735051/viewer_manager-2.0.556340-darwin64-556340.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -3282,9 +3260,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>ca230428635ce13cb7ace0f9522f8546</string> + <string>3446c1e54bb32542677caad0ec0d42ac</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/40538/348130/viewer_manager-2.0.529188-windows-529188.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/77525/735058/viewer_manager-2.0.556340-windows-556340.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -3295,7 +3273,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>source_type</key> <string>hg</string> <key>version</key> - <string>2.0.529188</string> + <string>2.0.556340</string> </map> <key>vlc-bin</key> <map> @@ -3314,9 +3292,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>e5635e173c75dc0675b48ab5f5e4868b</string> + <string>b639d0035f4a8c9b4973be428a1b7e61</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12143/71451/vlc_bin-2.2.8.511703-darwin64-511703.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/69569/671323/vlc_bin-3.0.9.549888-darwin64-549888.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -3338,9 +3316,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>add560654a53cb1c554044a4fac3c718</string> + <string>4f50b0c47daa081dd4fcb83763d5b0b2</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12144/71458/vlc_bin-2.2.8.511703-windows-511703.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/69567/671314/vlc_bin-3.0.9.549888-windows-549888.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -3350,16 +3328,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>94bf04b49acc1e1bf2c06e2232f8a083</string> + <string>c2f8c01fb6c261b72beb07f0c4cd423f</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12145/71463/vlc_bin-2.2.8.511703-windows64-511703.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/69568/671315/vlc_bin-3.0.9.549888-windows64-549888.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>2.2.8.511703</string> + <string>3.0.9.549888</string> </map> <key>xmlrpc-epi</key> <map> @@ -3392,9 +3370,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>b2d31df56a10c634657eed856c8d7895</string> + <string>922a0dea32266897ed1911200438e1e1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/728/1494/xmlrpc_epi-0.54.1.500719-darwin64-500719.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76372/727426/xmlrpc_epi-0.54.1.555529-darwin64-555529.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -3428,9 +3406,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>6c16f020bf01155e6746487af0b26173</string> + <string>34b847e6b280048465fe7c6ce67fe05c</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/729/1497/xmlrpc_epi-0.54.1.500719-windows-500719.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76374/727436/xmlrpc_epi-0.54.1.555529-windows-555529.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -3440,16 +3418,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>a9dda7caa8835c52b3735711cfee4eb9</string> + <string>8fbe7c4ea22bb7f23a93c73884ebb34c</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/730/1500/xmlrpc_epi-0.54.1.500719-windows64-500719.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76373/727435/xmlrpc_epi-0.54.1.555529-windows64-555529.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>0.54.1.500719</string> + <string>0.54.1.555529</string> </map> <key>zlib</key> <map> @@ -3482,9 +3460,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>e204dee29902549f50af1af2bb098df5</string> + <string>9181bc8229f1a8e480d2a40a2744ec28</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/867/1903/zlib-1.2.8.500857-darwin64-500857.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78578/743913/zlib-1.2.11.557041-darwin64-557041.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -3520,9 +3498,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>f92cbb0ab5e5d20789bf6102f9a27aa6</string> + <string>8308cbd2ea0fe290541698b0f63482e2</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/868/1906/zlib-1.2.8.500857-windows-500857.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78579/743926/zlib-1.2.11.557041-windows-557041.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -3532,24 +3510,24 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>70a56767f6a109af412838875d0b5f1b</string> + <string>36bdc34f67d3ad3c57125dc1b16a3129</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/869/1909/zlib-1.2.8.500857-windows64-500857.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78577/743920/zlib-1.2.11.557041-windows64-557041.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.2.8.500857</string> + <string>1.2.11.557041</string> </map> </map> <key>package_description</key> <map> <key>canonical_repo</key> - <string>https://bitbucket.org/lindenlab/viewer-release</string> + <string>https://bitbucket.org/lindenlab/viewer</string> <key>copyright</key> - <string>Copyright (c) 2014, Linden Research, Inc.</string> + <string>Copyright (c) 2020, Linden Research, Inc.</string> <key>description</key> <string>Second Life Viewer</string> <key>license</key> @@ -3893,7 +3871,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>windows</key> <map> <key>build_directory</key> - <string>build-vc120-$AUTOBUILD_ADDRSIZE</string> + <string>build-vc${AUTOBUILD_VSVER|150}-$AUTOBUILD_ADDRSIZE</string> <key>configurations</key> <map> <key>RelWithDebInfo</key> @@ -3960,9 +3938,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <array> <string>-G</string> <string>${AUTOBUILD_WIN_CMAKE_GEN|NOTWIN}</string> - <string>-DUNATTENDED:BOOL=ON</string> <string>-DINSTALL_PROPRIETARY=FALSE</string> <string>-DUSE_KDU=FALSE</string> + <string>-DOPENAL:BOOL=ON</string> </array> </map> <key>name</key> @@ -4033,6 +4011,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <string>-DUNATTENDED:BOOL=ON</string> <string>-DINSTALL_PROPRIETARY=FALSE</string> <string>-DUSE_KDU=FALSE</string> + <string>-DOPENAL:BOOL=ON</string> </array> </map> <key>name</key> @@ -16,6 +16,29 @@ # * The special style in which python is invoked is intentional to permit # use of a native python install on windows - which requires paths in DOS form +retry_cmd() +{ + max_attempts="$1"; shift + initial_wait="$1"; shift + attempt_num=1 + echo "trying" "$@" + until "$@" + do + if ((attempt_num==max_attempts)) + then + echo "Last attempt $attempt_num failed" + return 1 + else + wait_time=$(($attempt_num*$initial_wait)) + echo "Attempt $attempt_num failed. Trying again in $wait_time seconds..." + sleep $wait_time + attempt_num=$(($attempt_num+1)) + fi + done + echo "succeeded" + return 0 +} + build_dir_Darwin() { echo build-darwin-x86_64 @@ -28,7 +51,7 @@ build_dir_Linux() build_dir_CYGWIN() { - echo build-vc120-${AUTOBUILD_ADDRSIZE} + echo build-vc${AUTOBUILD_VSVER:-120}-${AUTOBUILD_ADDRSIZE} } viewer_channel_suffix() @@ -129,11 +152,6 @@ pre_build() then # show that we're doing this, just not the contents echo source "$bugsplat_sh" source "$bugsplat_sh" - # important: we test this and use its value in [grand-]child processes - if [ -n "${BUGSPLAT_DB:-}" ] - then echo export BUGSPLAT_DB - export BUGSPLAT_DB - fi fi set -x @@ -259,6 +277,23 @@ then export additional_packages= fi +begin_section "select viewer channel" +# Look for a branch-specific viewer_channel setting +# changeset_branch is set in the sling-buildscripts +viewer_build_branch=$(echo -n "${changeset_branch:-$(repo_branch ${BUILDSCRIPTS_SRC:-$(pwd)})}" | tr -Cs 'A-Za-z0-9_' '_' | sed -E 's/^_+//; s/_+$//') +if [ -n "$viewer_build_branch" ] +then + branch_viewer_channel_var="${viewer_build_branch}_viewer_channel" + if [ -n "${!branch_viewer_channel_var}" ] + then + viewer_channel="${!branch_viewer_channel_var}" + record_event "Overriding viewer_channel for branch '$changeset_branch' to '$viewer_channel'" + else + record_event "No branch-specific viewer_channel for branch '$viewer_build_branch'; to set a branch build channel set '$branch_viewer_channel_var'" + fi +fi +end_section "select viewer channel" + python_cmd "$helpers/codeticket.py" addinput "Viewer Channel" "${viewer_channel}" initialize_version # provided by buildscripts build.sh; sets version id @@ -412,6 +447,15 @@ then fi fi +# Some of the uploads takes a long time to finish in the codeticket backend, +# causing the next codeticket upload attempt to fail. +# Inserting this after each potentially large upload may prevent those errors. +# JJ is making changes to Codeticket that we hope will eliminate this failure, then this can be removed +wait_for_codeticket() +{ + sleep $(( 60 * 6 )) +} + # check status and upload results to S3 if $succeeded then @@ -426,8 +470,9 @@ then succeeded=$build_coverity else # Upload base package. - python_cmd "$helpers/codeticket.py" addoutput Installer "$package" \ + retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput Installer "$package" \ || fatal "Upload of installer failed" + wait_for_codeticket # Upload additional packages. for package_id in $additional_packages @@ -435,8 +480,9 @@ then package=$(installer_$arch "$package_id") if [ x"$package" != x ] then - python_cmd "$helpers/codeticket.py" addoutput "Installer $package_id" "$package" \ + retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput "Installer $package_id" "$package" \ || fatal "Upload of installer $package_id failed" + wait_for_codeticket else record_failure "Failed to find additional package for '$package_id'." fi @@ -448,8 +494,9 @@ then if [ "${RELEASE_CRASH_REPORTING:-}" != "OFF" ] then # Upload crash reporter file - python_cmd "$helpers/codeticket.py" addoutput "Symbolfile" "$VIEWER_SYMBOL_FILE" \ + retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput "Symbolfile" "$VIEWER_SYMBOL_FILE" \ || fatal "Upload of symbolfile failed" + wait_for_codeticket fi # Upload the llphysicsextensions_tpv package, if one was produced @@ -457,16 +504,19 @@ then if [ -r "$build_dir/llphysicsextensions_package" ] then llphysicsextensions_package=$(cat $build_dir/llphysicsextensions_package) - python_cmd "$helpers/codeticket.py" addoutput "Physics Extensions Package" "$llphysicsextensions_package" --private \ + retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput "Physics Extensions Package" "$llphysicsextensions_package" --private \ || fatal "Upload of physics extensions package failed" fi fi # Run upload extensions + # Ex: bugsplat if [ -d ${build_dir}/packages/upload-extensions ]; then for extension in ${build_dir}/packages/upload-extensions/*.sh; do begin_section "Upload Extension $extension" . $extension + [ $? -eq 0 ] || fatal "Upload of extension $extension failed" + wait_for_codeticket end_section "Upload Extension $extension" done fi @@ -476,7 +526,6 @@ then record_event "skipping upload of installer" fi - else record_event "skipping upload of installer due to failed build" fi diff --git a/doc/contributions.txt b/doc/contributions.txt index ca2e63cf9f..20980fdacd 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -223,6 +223,11 @@ Ansariel Hiller MAINT-8723 SL-10385 SL-10891 + SL-13364 + SL-13858 + SL-13697 + SL-13395 + SL-3136 Aralara Rajal Arare Chantilly CHUIBUG-191 @@ -258,6 +263,13 @@ Beansy Twine Benja Kepler VWR-746 Benjamin Bigdipper +Beq Janus + BUG-227094 + SL-10288 + SL-11300 + SL-13583 + SL-14766 + SL-14927 Beth Walcher Bezilon Kasei Biancaluce Robbiani @@ -347,8 +359,11 @@ Charles Courtois Charlie Sazaland Chaser Zaks BUG-225599 + BUG-227485 Cherry Cheevers ChickyBabes Zuzu +Chorazin Allen + BUG-229753 Christopher Organiser Ciaran Laval Cinder Roxley @@ -485,6 +500,16 @@ Geenz Spad STORM-1900 STORM-1905 NORSPEC-229 + BUG-226611 + BUG-226617 + BUG-226618 + BUG-226646 + BUG-226647 + BUG-226648 + OPEN-339 + BUG-226620 + OPEN-340 + OPEN-343 Gene Frostbite GeneJ Composer Geneko Nemeth @@ -818,6 +843,9 @@ Khyota Wulluf Kimar Coba Kithrak Kirkorian Kitty Barnett + BUG-228664 + BUG-228665 + BUG-228719 VWR-19699 STORM-288 STORM-799 @@ -1074,6 +1102,9 @@ Nicky Dasmijn SL-10291 SL-10293 SL-11061 + SL-11072 + SL-13141 + SL-13642 Nicky Perian OPEN-1 STORM-1087 @@ -1287,6 +1318,7 @@ Shyotl Kuhr MAINT-2334 MAINT-6913 STORM-2143 + SL-11625 Siana Gearz STORM-960 STORM-1088 @@ -1325,6 +1357,14 @@ Sovereign Engineer STORM-2148 MAINT-7343 SL-11079 + OPEN-343 + SL-11625 + SL-14705 + SL-14706 + SL-14707 + SL-14731 + SL-14732 + SL-15096 SpacedOut Frye VWR-34 VWR-45 @@ -1430,6 +1470,8 @@ Thickbrick Sleaford STORM-956 STORM-1147 STORM-1325 +Thoys Pan + SL-12396 Thraxis Epsilon SVC-371 VWR-383 @@ -1504,6 +1546,7 @@ Whirly Fizzle STORM-1930 BUG-6659 STORM-2078 + BUG-17349 Whoops Babii VWR-631 VWR-1640 diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 62a8f3f003..bc2ee2e6cd 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -13,8 +13,14 @@ project(${ROOT_PROJECT_NAME}) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") include(Variables) +include(bugsplat) include(BuildVersion) +set(LEGACY_STDIO_LIBS) +if (WINDOWS) + set(LEGACY_STDIO_LIBS legacy_stdio_definitions) +endif (WINDOWS) + if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Build type. One of: Debug Release RelWithDebInfo" FORCE) @@ -45,7 +51,10 @@ endif (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts) add_custom_target(viewer) +if (NOT USE_BUGSPLAT) add_subdirectory(${LIBS_OPEN_PREFIX}llcrashlogger) +endif (NOT USE_BUGSPLAT) + add_subdirectory(${LIBS_OPEN_PREFIX}llplugin) add_subdirectory(${LIBS_OPEN_PREFIX}llui) add_subdirectory(${LIBS_OPEN_PREFIX}viewer_components) @@ -59,29 +68,18 @@ add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins) endif (ENABLE_MEDIA_PLUGINS) if (LINUX) - add_subdirectory(${VIEWER_PREFIX}linux_crash_logger) if (INSTALL_PROPRIETARY) include(LLAppearanceUtility) add_subdirectory(${LLAPPEARANCEUTILITY_SRC_DIR} ${LLAPPEARANCEUTILITY_BIN_DIR}) endif (INSTALL_PROPRIETARY) - add_dependencies(viewer linux-crash-logger-strip-target) -elseif (DARWIN) - add_subdirectory(${VIEWER_PREFIX}mac_crash_logger) - add_dependencies(viewer mac-crash-logger) -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_dependencies(viewer windows-setup windows-crash-logger) - add_dependencies(viewer windows-crash-logger) endif (LINUX) -add_subdirectory(${VIEWER_PREFIX}newview) -add_dependencies(viewer secondlife-bin) - -add_subdirectory(${VIEWER_PREFIX}doxygen EXCLUDE_FROM_ALL) +if (WINDOWS) + # cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake + if (EXISTS ${VIEWER_DIR}win_setup) + add_subdirectory(${VIEWER_DIR}win_setup) + endif (EXISTS ${VIEWER_DIR}win_setup) +endif (WINDOWS) # sets the 'startup project' for debugging from visual studio. set_property( @@ -89,6 +87,21 @@ set_property( PROPERTY VS_STARTUP_PROJECT secondlife-bin ) +if (USE_BUGSPLAT) + if (BUGSPLAT_DB) + message(STATUS "Building with BugSplat; database '${BUGSPLAT_DB}'") + else (BUGSPLAT_DB) + message(WARNING "Building with BugSplat, but no database name set (BUGSPLAT_DB)") + endif (BUGSPLAT_DB) +else (USE_BUGSPLAT) + message(STATUS "Not building with BugSplat") +endif (USE_BUGSPLAT) + +add_subdirectory(${VIEWER_PREFIX}newview) +add_dependencies(viewer secondlife-bin) + +add_subdirectory(${VIEWER_PREFIX}doxygen EXCLUDE_FROM_ALL) + if (LL_TESTS) # Define after the custom targets are created so # individual apps can add themselves as dependencies diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 03da30649a..8aea50e02b 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -60,7 +60,16 @@ if (WINDOWS) # http://www.cmake.org/pipermail/cmake/2009-September/032143.html string(REPLACE "/Zm1000" " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") + # Without PreferredToolArchitecture=x64, as of 2020-06-26 the 32-bit + # compiler on our TeamCity build hosts has started running out of virtual + # memory for the precompiled header file. + # CP changed to only append the flag for 32bit builds - on 64bit builds, + # locally at least, the build output is spammed with 1000s of 'D9002' + # warnings about this switch being ignored. + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") + if( ADDRESS_SIZE EQUAL 32 ) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /p:PreferredToolArchitecture=x64") + endif() set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Zo" diff --git a/indra/cmake/Atmosphere.cmake b/indra/cmake/Atmosphere.cmake new file mode 100644 index 0000000000..9c14df2a11 --- /dev/null +++ b/indra/cmake/Atmosphere.cmake @@ -0,0 +1,5 @@ +# -*- cmake -*- +include(Prebuilt) +use_prebuilt_binary(libatmosphere) +set(LIBATMOSPHERE_LIBRARIES atmosphere) +set(LIBATMOSPHERE_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/atmosphere) diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake index 180a84dbcf..06a7ab6d75 100644 --- a/indra/cmake/Boost.cmake +++ b/indra/cmake/Boost.cmake @@ -8,7 +8,7 @@ if (USESYSTEMLIBS) include(FindBoost) set(BOOST_CONTEXT_LIBRARY boost_context-mt) - set(BOOST_COROUTINE_LIBRARY boost_coroutine-mt) + set(BOOST_FIBER_LIBRARY boost_fiber-mt) set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-mt) set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-mt) set(BOOST_REGEX_LIBRARY boost_regex-mt) @@ -18,11 +18,15 @@ if (USESYSTEMLIBS) else (USESYSTEMLIBS) use_prebuilt_binary(boost) set(Boost_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include) - set(BOOST_VERSION "1.55") + + # As of sometime between Boost 1.67 and 1.72, Boost libraries are suffixed + # with the address size. + set(addrsfx "-x${ADDRESS_SIZE}") if (WINDOWS) if(MSVC80) # This should be obsolete at this point + set(BOOST_VERSION "1.55") set(BOOST_CONTEXT_LIBRARY optimized libboost_context-vc80-mt-${BOOST_VERSION} debug libboost_context-vc80-mt-gd-${BOOST_VERSION}) @@ -47,80 +51,80 @@ else (USESYSTEMLIBS) else(MSVC80) # MSVC 10.0 config set(BOOST_CONTEXT_LIBRARY - optimized libboost_context-mt - debug libboost_context-mt-gd) - set(BOOST_COROUTINE_LIBRARY - optimized libboost_coroutine-mt - debug libboost_coroutine-mt-gd) + optimized libboost_context-mt${addrsfx} + debug libboost_context-mt${addrsfx}-gd) + set(BOOST_FIBER_LIBRARY + optimized libboost_fiber-mt${addrsfx} + debug libboost_fiber-mt${addrsfx}-gd) set(BOOST_FILESYSTEM_LIBRARY - optimized libboost_filesystem-mt - debug libboost_filesystem-mt-gd) + optimized libboost_filesystem-mt${addrsfx} + debug libboost_filesystem-mt${addrsfx}-gd) set(BOOST_PROGRAM_OPTIONS_LIBRARY - optimized libboost_program_options-mt - debug libboost_program_options-mt-gd) + optimized libboost_program_options-mt${addrsfx} + debug libboost_program_options-mt${addrsfx}-gd) set(BOOST_REGEX_LIBRARY - optimized libboost_regex-mt - debug libboost_regex-mt-gd) + optimized libboost_regex-mt${addrsfx} + debug libboost_regex-mt${addrsfx}-gd) set(BOOST_SIGNALS_LIBRARY - optimized libboost_signals-mt - debug libboost_signals-mt-gd) + optimized libboost_signals-mt${addrsfx} + debug libboost_signals-mt${addrsfx}-gd) set(BOOST_SYSTEM_LIBRARY - optimized libboost_system-mt - debug libboost_system-mt-gd) + optimized libboost_system-mt${addrsfx} + debug libboost_system-mt${addrsfx}-gd) set(BOOST_THREAD_LIBRARY - optimized libboost_thread-mt - debug libboost_thread-mt-gd) + optimized libboost_thread-mt${addrsfx} + debug libboost_thread-mt${addrsfx}-gd) endif (MSVC80) elseif (LINUX) set(BOOST_CONTEXT_LIBRARY - optimized boost_context-mt - debug boost_context-mt-d) - set(BOOST_COROUTINE_LIBRARY - optimized boost_coroutine-mt - debug boost_coroutine-mt-d) + optimized boost_context-mt${addrsfx} + debug boost_context-mt${addrsfx}-d) + set(BOOST_FIBER_LIBRARY + optimized boost_fiber-mt${addrsfx} + debug boost_fiber-mt${addrsfx}-d) set(BOOST_FILESYSTEM_LIBRARY - optimized boost_filesystem-mt - debug boost_filesystem-mt-d) + optimized boost_filesystem-mt${addrsfx} + debug boost_filesystem-mt${addrsfx}-d) set(BOOST_PROGRAM_OPTIONS_LIBRARY - optimized boost_program_options-mt - debug boost_program_options-mt-d) + optimized boost_program_options-mt${addrsfx} + debug boost_program_options-mt${addrsfx}-d) set(BOOST_REGEX_LIBRARY - optimized boost_regex-mt - debug boost_regex-mt-d) + optimized boost_regex-mt${addrsfx} + debug boost_regex-mt${addrsfx}-d) set(BOOST_SIGNALS_LIBRARY - optimized boost_signals-mt - debug boost_signals-mt-d) + optimized boost_signals-mt${addrsfx} + debug boost_signals-mt${addrsfx}-d) set(BOOST_SYSTEM_LIBRARY - optimized boost_system-mt - debug boost_system-mt-d) + optimized boost_system-mt${addrsfx} + debug boost_system-mt${addrsfx}-d) set(BOOST_THREAD_LIBRARY - optimized boost_thread-mt - debug boost_thread-mt-d) + optimized boost_thread-mt${addrsfx} + debug boost_thread-mt${addrsfx}-d) elseif (DARWIN) set(BOOST_CONTEXT_LIBRARY - optimized boost_context-mt - debug boost_context-mt-d) - set(BOOST_COROUTINE_LIBRARY - optimized boost_coroutine-mt - debug boost_coroutine-mt-d) + optimized boost_context-mt${addrsfx} + debug boost_context-mt${addrsfx}-d) + set(BOOST_FIBER_LIBRARY + optimized boost_fiber-mt${addrsfx} + debug boost_fiber-mt${addrsfx}-d) set(BOOST_FILESYSTEM_LIBRARY - optimized boost_filesystem-mt - debug boost_filesystem-mt-d) + optimized boost_filesystem-mt${addrsfx} + debug boost_filesystem-mt${addrsfx}-d) set(BOOST_PROGRAM_OPTIONS_LIBRARY - optimized boost_program_options-mt - debug boost_program_options-mt-d) + optimized boost_program_options-mt${addrsfx} + debug boost_program_options-mt${addrsfx}-d) set(BOOST_REGEX_LIBRARY - optimized boost_regex-mt - debug boost_regex-mt-d) + optimized boost_regex-mt${addrsfx} + debug boost_regex-mt${addrsfx}-d) set(BOOST_SIGNALS_LIBRARY - optimized boost_signals-mt - debug boost_signals-mt-d) + optimized boost_signals-mt${addrsfx} + debug boost_signals-mt${addrsfx}-d) set(BOOST_SYSTEM_LIBRARY - optimized boost_system-mt - debug boost_system-mt-d) + optimized boost_system-mt${addrsfx} + debug boost_system-mt${addrsfx}-d) set(BOOST_THREAD_LIBRARY - optimized boost_thread-mt - debug boost_thread-mt-d) + optimized boost_thread-mt${addrsfx} + debug boost_thread-mt${addrsfx}-d) endif (WINDOWS) endif (USESYSTEMLIBS) diff --git a/indra/cmake/BuildPackagesInfo.cmake b/indra/cmake/BuildPackagesInfo.cmake index 4314cca33d..8f8b6b2330 100644 --- a/indra/cmake/BuildPackagesInfo.cmake +++ b/indra/cmake/BuildPackagesInfo.cmake @@ -1,6 +1,7 @@ # -*- cmake -*- # Construct the version and copyright information based on package data. include(Python) +include(FindAutobuild) # packages-formatter.py runs autobuild install --versions, which needs to know # the build_directory, which (on Windows) depends on AUTOBUILD_ADDRSIZE. @@ -13,7 +14,7 @@ add_custom_command(OUTPUT packages-info.txt 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} + ${CMAKE_SOURCE_DIR}/cmake/run_build_test.py -DAUTOBUILD_ADDRSIZE=${ADDRESS_SIZE} -DAUTOBUILD=${AUTOBUILD_EXECUTABLE} ${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/CEFPlugin.cmake b/indra/cmake/CEFPlugin.cmake index b8e569d3a8..7d8bfb1b0f 100644 --- a/indra/cmake/CEFPlugin.cmake +++ b/indra/cmake/CEFPlugin.cmake @@ -24,7 +24,7 @@ elseif (DARWIN) message(FATAL_ERROR "AppKit not found") endif() - FIND_LIBRARY(CEF_LIBRARY "Chromium Embedded Framework" ${ARCH_PREBUILT_DIRS_RELEASE}) + set(CEF_LIBRARY "'${ARCH_PREBUILT_DIRS_RELEASE}/Chromium\ Embedded\ Framework.framework'") if (NOT CEF_LIBRARY) message(FATAL_ERROR "CEF not found") endif() @@ -33,7 +33,7 @@ elseif (DARWIN) ${ARCH_PREBUILT_DIRS_RELEASE}/libcef_dll_wrapper.a ${ARCH_PREBUILT_DIRS_RELEASE}/libdullahan.a ${APPKIT_LIBRARY} - ${CEF_LIBRARY} + "-F ${CEF_LIBRARY}" ) elseif (LINUX) diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index d64c38b1b3..c65906b853 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -22,15 +22,12 @@ set(cmake_SOURCE_FILES Copy3rdPartyLibs.cmake DBusGlib.cmake DeploySharedLibs.cmake - DirectX.cmake DragDrop.cmake EXPAT.cmake FindAPR.cmake FindAutobuild.cmake FindBerkeleyDB.cmake - FindFMODEX.cmake FindGLH.cmake - FindGoogleBreakpad.cmake FindHUNSPELL.cmake FindICU4C.cmake FindJsonCpp.cmake @@ -40,13 +37,12 @@ set(cmake_SOURCE_FILES FindURIPARSER.cmake FindXmlRpcEpi.cmake FindZLIB.cmake - FMODEX.cmake + FMODSTUDIO.cmake FreeType.cmake GLEXT.cmake GLH.cmake GLOD.cmake ## GStreamer010Plugin.cmake - GoogleBreakpad.cmake GoogleMock.cmake Havok.cmake Hunspell.cmake diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index dde53835fb..b20d23cead 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -7,6 +7,21 @@ include(CMakeCopyIfDifferent) include(Linking) +# When we copy our dependent libraries, we almost always want to copy them to +# both the Release and the RelWithDebInfo staging directories. This has +# resulted in duplicate (or worse, erroneous attempted duplicate) +# copy_if_different commands. Encapsulate that usage. +# Pass FROM_DIR, TARGETS and the files to copy. TO_DIR is implicit. +# to_staging_dirs diverges from copy_if_different in that it appends to TARGETS. +MACRO(to_staging_dirs from_dir targets) + foreach(staging_dir + "${SHARED_LIB_STAGING_DIR_RELEASE}" + "${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}") + copy_if_different("${from_dir}" "${staging_dir}" out_targets ${ARGN}) + list(APPEND "${targets}" "${out_targets}") + endforeach() +ENDMACRO(to_staging_dirs from_dir to_dir targets) + ################################################################### # set up platform specific lists of files that need to be copied ################################################################### @@ -17,17 +32,16 @@ if(WINDOWS) #******************************* # VIVOX - *NOTE: no debug version - set(vivox_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}") - set(vivox_files - SLVoice.exe - ) + set(vivox_lib_dir "${ARCH_PREBUILT_DIRS_RELEASE}") + set(slvoice_src_dir "${ARCH_PREBUILT_BIN_RELEASE}") + set(slvoice_files SLVoice.exe ) if (ADDRESS_SIZE EQUAL 64) - list(APPEND vivox_files + list(APPEND vivox_libs vivoxsdk_x64.dll ortp_x64.dll ) else (ADDRESS_SIZE EQUAL 64) - list(APPEND vivox_files + list(APPEND vivox_libs vivoxsdk.dll ortp.dll ) @@ -42,16 +56,24 @@ if(WINDOWS) libapr-1.dll libaprutil-1.dll libapriconv-1.dll - ssleay32.dll - libeay32.dll nghttp2.dll glod.dll libhunspell.dll + uriparser.dll ) + # OpenSSL + if(ADDRESS_SIZE EQUAL 64) + set(release_files ${release_files} libcrypto-1_1-x64.dll) + set(release_files ${release_files} libssl-1_1-x64.dll) + else(ADDRESS_SIZE EQUAL 64) + set(release_files ${release_files} libcrypto-1_1.dll) + set(release_files ${release_files} libssl-1_1.dll) + endif(ADDRESS_SIZE EQUAL 64) + # Filenames are different for 32/64 bit BugSplat file and we don't # have any control over them so need to branch. - if (BUGSPLAT_DB) + if (USE_BUGSPLAT) if(ADDRESS_SIZE EQUAL 32) set(release_files ${release_files} BugSplat.dll) set(release_files ${release_files} BugSplatRc.dll) @@ -61,119 +83,77 @@ if(WINDOWS) set(release_files ${release_files} BugSplatRc64.dll) set(release_files ${release_files} BsSndRpt64.exe) endif(ADDRESS_SIZE EQUAL 32) - endif (BUGSPLAT_DB) + endif (USE_BUGSPLAT) - if (FMODEX) + if (FMODSTUDIO) + set(debug_files ${debug_files} fmodL.dll) + set(release_files ${release_files} fmod.dll) + endif (FMODSTUDIO) - if(ADDRESS_SIZE EQUAL 32) - set(release_files ${release_files} fmodex.dll) - else(ADDRESS_SIZE EQUAL 32) - set(release_files ${release_files} fmodex64.dll) - endif(ADDRESS_SIZE EQUAL 32) - endif (FMODEX) + if (OPENAL) + list(APPEND release_files openal32.dll alut.dll) + endif (OPENAL) #******************************* # Copy MS C runtime dlls, required for packaging. - # *TODO - Adapt this to support VC9 if (MSVC80) - list(APPEND LMSVC_VER 80) - list(APPEND LMSVC_VERDOT 8.0) + set(MSVC_VER 80) elseif (MSVC_VERSION EQUAL 1600) # VisualStudio 2010 MESSAGE(STATUS "MSVC_VERSION ${MSVC_VERSION}") elseif (MSVC_VERSION EQUAL 1800) # VisualStudio 2013, which is (sigh) VS 12 - list(APPEND LMSVC_VER 120) - list(APPEND LMSVC_VERDOT 12.0) + set(MSVC_VER 120) + elseif (MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) # Visual Studio 2017 + set(MSVC_VER 140) else (MSVC80) MESSAGE(WARNING "New MSVC_VERSION ${MSVC_VERSION} of MSVC: adapt Copy3rdPartyLibs.cmake") endif (MSVC80) - # try to copy VS2010 redist independently of system version - # maint-7360 CP - # list(APPEND LMSVC_VER 100) - # list(APPEND LMSVC_VERDOT 10.0) - - list(LENGTH LMSVC_VER count) - math(EXPR count "${count}-1") - foreach(i RANGE ${count}) - list(GET LMSVC_VER ${i} MSVC_VER) - list(GET LMSVC_VERDOT ${i} MSVC_VERDOT) - MESSAGE(STATUS "Copying redist libs for VC ${MSVC_VERDOT}") - FIND_PATH(debug_msvc_redist_path NAME msvcr${MSVC_VER}d.dll - PATHS - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\${MSVC_VERDOT}\\Setup\\VC;ProductDir]/redist/Debug_NonRedist/x86/Microsoft.VC${MSVC_VER}.DebugCRT - [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Windows;Directory]/SysWOW64 - [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Windows;Directory]/System32 - ${MSVC_DEBUG_REDIST_PATH} - NO_DEFAULT_PATH - ) - - if(EXISTS ${debug_msvc_redist_path}) - set(debug_msvc_files - msvcr${MSVC_VER}d.dll - msvcp${MSVC_VER}d.dll - ) - - copy_if_different( - ${debug_msvc_redist_path} - "${SHARED_LIB_STAGING_DIR_DEBUG}" - out_targets - ${debug_msvc_files} - ) - set(third_party_targets ${third_party_targets} ${out_targets}) - - unset(debug_msvc_redist_path CACHE) - endif() - - if(ADDRESS_SIZE EQUAL 32) - # this folder contains the 32bit DLLs.. (yes really!) - set(registry_find_path "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Windows;Directory]/SysWOW64") - else(ADDRESS_SIZE EQUAL 32) - # this folder contains the 64bit DLLs.. (yes really!) - set(registry_find_path "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Windows;Directory]/System32") - endif(ADDRESS_SIZE EQUAL 32) - - FIND_PATH(release_msvc_redist_path NAME msvcr${MSVC_VER}.dll - PATHS - ${registry_find_path} - NO_DEFAULT_PATH + if(ADDRESS_SIZE EQUAL 32) + # this folder contains the 32bit DLLs.. (yes really!) + set(registry_find_path "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Windows;Directory]/SysWOW64") + else(ADDRESS_SIZE EQUAL 32) + # this folder contains the 64bit DLLs.. (yes really!) + set(registry_find_path "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Windows;Directory]/System32") + endif(ADDRESS_SIZE EQUAL 32) + + # Having a string containing the system registry path is a start, but to + # get CMake to actually read the registry, we must engage some other + # operation. + get_filename_component(registry_path "${registry_find_path}" ABSOLUTE) + + # These are candidate DLL names. Empirically, VS versions before 2015 have + # msvcp*.dll and msvcr*.dll. VS 2017 has msvcp*.dll and vcruntime*.dll. + # Check each of them. + foreach(release_msvc_file + msvcp${MSVC_VER}.dll + msvcr${MSVC_VER}.dll + vcruntime${MSVC_VER}.dll ) - - if(EXISTS ${release_msvc_redist_path}) - set(release_msvc_files - msvcr${MSVC_VER}.dll - msvcp${MSVC_VER}.dll - ) - - copy_if_different( - ${release_msvc_redist_path} - "${SHARED_LIB_STAGING_DIR_RELEASE}" - out_targets - ${release_msvc_files} - ) - set(third_party_targets ${third_party_targets} ${out_targets}) - - copy_if_different( - ${release_msvc_redist_path} - "${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}" - out_targets - ${release_msvc_files} - ) - set(third_party_targets ${third_party_targets} ${out_targets}) - - unset(release_msvc_redist_path CACHE) + if(EXISTS "${registry_path}/${release_msvc_file}") + to_staging_dirs( + ${registry_path} + third_party_targets + ${release_msvc_file}) + else() + # This isn't a WARNING because, as noted above, every VS version + # we've observed has only a subset of the specified DLL names. + MESSAGE(STATUS "Redist lib ${release_msvc_file} not found") endif() endforeach() + MESSAGE(STATUS "Will copy redist files for MSVC ${MSVC_VER}:") + foreach(target ${third_party_targets}) + MESSAGE(STATUS "${target}") + endforeach() 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 + set(vivox_lib_dir "${ARCH_PREBUILT_DIRS_RELEASE}") + set(slvoice_files SLVoice) + set(vivox_libs libortp.dylib - libvivoxplatform.dylib libvivoxsdk.dylib ) set(debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}") @@ -185,19 +165,22 @@ elseif(DARWIN) libapr-1.dylib libaprutil-1.0.dylib libaprutil-1.dylib - libexception_handler.dylib ${EXPAT_COPY} libGLOD.dylib + libhunspell-1.3.0.dylib libndofdev.dylib libnghttp2.dylib libnghttp2.14.dylib - libnghttp2.14.14.0.dylib + libnghttp2.14.19.0.dylib + liburiparser.dylib + liburiparser.1.dylib + liburiparser.1.0.27.dylib ) - if (FMODEX) - set(debug_files ${debug_files} libfmodexL.dylib) - set(release_files ${release_files} libfmodex.dylib) - endif (FMODEX) + if (FMODSTUDIO) + set(debug_files ${debug_files} libfmodL.dylib) + set(release_files ${release_files} libfmod.dylib) + endif (FMODSTUDIO) elseif(LINUX) # linux is weird, multiple side by side configurations aren't supported @@ -206,15 +189,15 @@ elseif(LINUX) 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 + set(vivox_lib_dir "${ARCH_PREBUILT_DIRS_RELEASE}") + set(vivox_libs libsndfile.so.1 libortp.so libvivoxoal.so.1 - libvivoxplatform.so libvivoxsdk.so - SLVoice - ) + ) + set(slvoice_files 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}") @@ -244,15 +227,15 @@ elseif(LINUX) libfontconfig.so.1 ) - if (FMODEX) - set(debug_files ${debug_files} "libfmodexL.so") - set(release_files ${release_files} "libfmodex.so") - endif (FMODEX) + if (FMODSTUDIO) + set(debug_files ${debug_files} "libfmodL.so") + set(release_files ${release_files} "libfmod.so") + endif (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 "") + set(vivox_lib_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-linux") + set(vivox_libs "") # *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") @@ -274,55 +257,28 @@ endif(WINDOWS) # Done building the file lists, now set up the copy commands. ################################################################ +# Curiously, slvoice_files are only copied to SHARED_LIB_STAGING_DIR_RELEASE. +# It's unclear whether this is oversight or intentional, but anyway leave the +# single copy_if_different command rather than using to_staging_dirs. 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} + ${slvoice_src_dir} "${SHARED_LIB_STAGING_DIR_RELEASE}" out_targets - ${vivox_files} + ${slvoice_files} ) -set(third_party_targets ${third_party_targets} ${out_targets}) +list(APPEND third_party_targets ${out_targets}) -copy_if_different( - ${vivox_src_dir} - "${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}" - out_targets - ${vivox_files} +to_staging_dirs( + ${vivox_lib_dir} + third_party_targets + ${vivox_libs} ) -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( +to_staging_dirs( ${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 + third_party_targets ${release_files} ) -set(third_party_targets ${third_party_targets} ${out_targets}) if(NOT USESYSTEMLIBS) add_custom_target( diff --git a/indra/cmake/DirectX.cmake b/indra/cmake/DirectX.cmake deleted file mode 100644 index 25163d0322..0000000000 --- a/indra/cmake/DirectX.cmake +++ /dev/null @@ -1,48 +0,0 @@ -# -*- cmake -*- - -if (WINDOWS) - find_path(DIRECTX_INCLUDE_DIR dxdiag.h - "$ENV{DXSDK_DIR}/Include" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2010)/Include" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (August 2009)/Include" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (March 2009)/Include" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (August 2008)/Include" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2008)/Include" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (March 2008)/Include" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (November 2007)/Include" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (August 2007)/Include" - "C:/DX90SDK/Include" - "$ENV{PROGRAMFILES}/DX90SDK/Include" - ) - 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) - - - find_path(DIRECTX_LIBRARY_DIR dxguid.lib - "$ENV{DXSDK_DIR}/Lib/x86" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2010)/Lib/x86" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (August 2009)/Lib/x86" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (March 2009)/Lib/x86" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (August 2008)/Lib/x86" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2008)/Lib/x86" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (March 2008)/Lib/x86" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (November 2007)/Lib/x86" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (August 2007)/Lib/x86" - "C:/DX90SDK/Lib" - "$ENV{PROGRAMFILES}/DX90SDK/Lib" - ) - 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/FMODEX.cmake b/indra/cmake/FMODEX.cmake deleted file mode 100644 index 720933d1b7..0000000000 --- a/indra/cmake/FMODEX.cmake +++ /dev/null @@ -1,46 +0,0 @@ -# -*- cmake -*- - -# FMOD can be set when launching the make using the argument -DFMOD:BOOL=ON -# When building using proprietary binaries though (i.e. having access to LL private servers), -# we always build with FMODEX. -# Open source devs should use the -DFMODEX:BOOL=ON then if they want to build with FMOD, whether -# they are using USESYSTEMLIBS or not. -if (INSTALL_PROPRIETARY) - set(FMODEX ON CACHE BOOL "Using FMOD Ex sound library.") -endif (INSTALL_PROPRIETARY) - -if (FMODEX) - if (USESYSTEMLIBS) - # In that case, we use the version of the library installed on the system - set(FMODEX_FIND_REQUIRED ON) - include(FindFMODEX) - else (USESYSTEMLIBS) - if (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - # If the path have been specified in the arguments, use that - set(FMODEX_LIBRARIES ${FMODEX_LIBRARY}) - MESSAGE(STATUS "Using FMODEX path: ${FMODEX_LIBRARIES}, ${FMODEX_INCLUDE_DIR}") - else (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - # If not, we're going to try to get the package listed in autobuild.xml - # Note: if you're not using INSTALL_PROPRIETARY, the package URL should be local (file:/// URL) - # as accessing the private LL location will fail if you don't have the credential - include(Prebuilt) - use_prebuilt_binary(fmodex) - if (WINDOWS) - set(FMODEX_LIBRARY - debug fmodexL_vc - optimized fmodex_vc) - elseif (DARWIN) - set(FMODEX_LIBRARY - debug fmodexL - optimized fmodex) - elseif (LINUX) - set(FMODEX_LIBRARY - debug fmodexL - optimized fmodex) - endif (WINDOWS) - set(FMODEX_LIBRARIES ${FMODEX_LIBRARY}) - set(FMODEX_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/fmodex) - endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - endif (USESYSTEMLIBS) -endif (FMODEX) - diff --git a/indra/cmake/FMODSTUDIO.cmake b/indra/cmake/FMODSTUDIO.cmake new file mode 100644 index 0000000000..8840354ac6 --- /dev/null +++ b/indra/cmake/FMODSTUDIO.cmake @@ -0,0 +1,38 @@ +# -*- cmake -*- + +# FMODSTUDIO can be set when launching the make using the argument -DFMODSTUDIO:BOOL=ON +# When building using proprietary binaries though (i.e. having access to LL private servers), +# we always build with FMODSTUDIO. +if (INSTALL_PROPRIETARY) + set(FMODSTUDIO ON CACHE BOOL "Using FMODSTUDIO sound library.") +endif (INSTALL_PROPRIETARY) + +if (FMODSTUDIO) + if (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR) + # If the path have been specified in the arguments, use that + set(FMODSTUDIO_LIBRARIES ${FMODSTUDIO_LIBRARY}) + else (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR) + # If not, we're going to try to get the package listed in autobuild.xml + # Note: if you're not using INSTALL_PROPRIETARY, the package URL should be local (file:/// URL) + # as accessing the private LL location will fail if you don't have the credential + include(Prebuilt) + use_prebuilt_binary(fmodstudio) + if (WINDOWS) + set(FMODSTUDIO_LIBRARY + debug fmodL_vc + optimized fmod_vc) + elseif (DARWIN) + #despite files being called libfmod.dylib, we are searching for fmod + set(FMODSTUDIO_LIBRARY + debug fmodL + optimized fmod) + elseif (LINUX) + set(FMODSTUDIO_LIBRARY + debug fmodL + optimized fmod) + endif (WINDOWS) + set(FMODSTUDIO_LIBRARIES ${FMODSTUDIO_LIBRARY}) + set(FMODSTUDIO_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/fmodstudio) + endif (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR) +endif (FMODSTUDIO) + diff --git a/indra/cmake/FindFMODEX.cmake b/indra/cmake/FindFMODEX.cmake deleted file mode 100644 index b621727c0e..0000000000 --- a/indra/cmake/FindFMODEX.cmake +++ /dev/null @@ -1,65 +0,0 @@ -# -*- cmake -*- - -# - Find FMODEX -# Find the FMODEX includes and library -# This module defines -# FMODEX_INCLUDE_DIR, where to find fmod.h and fmod_errors.h -# FMODEX_LIBRARIES, the libraries needed to use FMODEX. -# FMODEX, If false, do not try to use FMODEX. -# also defined, but not for general use are -# FMODEX_LIBRARY, where to find the FMODEX library. - -FIND_PATH(FMODEX_INCLUDE_DIR fmod.h PATH_SUFFIXES fmod) - -SET(FMODEX_NAMES ${FMODEX_NAMES} fmodex fmodvc fmodexL_vc) -FIND_LIBRARY(FMODEX_LIBRARY - NAMES ${FMODEX_NAMES} - PATH_SUFFIXES fmodex - ) - -IF (FMODEX_SDK_DIR OR WINDOWS) - if(WINDOWS) - set(FMODEX_SDK_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows" CACHE PATH "Path to FMODEX") - STRING(REGEX REPLACE "\\\\" "/" FMODEX_SDK_DIR ${FMODEX_SDK_DIR}) - endif(WINDOWS) - find_library(FMODEX_LIBRARY - fmodex_vc fmodexL_vc - PATHS - ${FMODEX_SDK_DIR}/api/lib - ${FMODEX_SDK_DIR}/api - ${FMODEX_SDK_DIR} - ) - find_path(FMODEX_INCLUDE_DIR fmod.h - ${FMODEX_SDK_DIR}/api/inc - ${FMODEX_SDK_DIR}/api - ${FMODEX_SDK_DIR} - ) - find_path(FMODEX_INCLUDE_DIR fmod.h - ${FMODEX_SDK_DIR}/api/inc - ${FMODEX_SDK_DIR}/api - ${FMODEX_SDK_DIR} - ) - IF (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - SET(FMODEX_LIBRARIES ${FMODEX_LIBRARY}) - SET(FMODEX_FOUND "YES") - endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) -ENDIF (FMODEX_SDK_DIR OR WINDOWS) - -IF (FMODEX_FOUND) - IF (NOT FMODEX_FIND_QUIETLY) - MESSAGE(STATUS "Found FMODEX: ${FMODEX_LIBRARIES}") - ENDIF (NOT FMODEX_FIND_QUIETLY) -ELSE (FMODEX_FOUND) - IF (FMODEX_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find FMODEX library") - ENDIF (FMODEX_FIND_REQUIRED) -ENDIF (FMODEX_FOUND) - -# Deprecated declarations. -SET (NATIVE_FMODEX_INCLUDE_PATH ${FMODEX_INCLUDE_DIR} ) -GET_FILENAME_COMPONENT (NATIVE_FMODEX_LIB_PATH ${FMODEX_LIBRARY} PATH) - -MARK_AS_ADVANCED( - FMODEX_LIBRARY - FMODEX_INCLUDE_DIR - ) diff --git a/indra/cmake/FindGoogleBreakpad.cmake b/indra/cmake/FindGoogleBreakpad.cmake deleted file mode 100644 index 1a0493be5e..0000000000 --- a/indra/cmake/FindGoogleBreakpad.cmake +++ /dev/null @@ -1,40 +0,0 @@ -# -*- cmake -*- - -# - Find Google BreakPad -# Find the Google BreakPad includes and library -# This module defines -# BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR, where to find exception_handler.h, etc. -# BREAKPAD_EXCEPTION_HANDLER_LIBRARIES, the libraries needed to use Google BreakPad. -# BREAKPAD_EXCEPTION_HANDLER_FOUND, If false, do not try to use Google BreakPad. -# also defined, but not for general use are -# BREAKPAD_EXCEPTION_HANDLER_LIBRARY, where to find the Google BreakPad library. - -FIND_PATH(BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR google_breakpad/exception_handler.h) - -SET(BREAKPAD_EXCEPTION_HANDLER_NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES} breakpad_client) -FIND_LIBRARY(BREAKPAD_EXCEPTION_HANDLER_LIBRARY - NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES} - ) - -IF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR) - SET(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES ${BREAKPAD_EXCEPTION_HANDLER_LIBRARY}) - SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "YES") -ELSE (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR) - SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "NO") -ENDIF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR) - - -IF (BREAKPAD_EXCEPTION_HANDLER_FOUND) - IF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY) - MESSAGE(STATUS "Found Google BreakPad: ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}") - ENDIF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY) -ELSE (BREAKPAD_EXCEPTION_HANDLER_FOUND) - IF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find Google BreakPad library") - ENDIF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED) -ENDIF (BREAKPAD_EXCEPTION_HANDLER_FOUND) - -MARK_AS_ADVANCED( - BREAKPAD_EXCEPTION_HANDLER_LIBRARY - BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR - ) diff --git a/indra/cmake/GoogleBreakpad.cmake b/indra/cmake/GoogleBreakpad.cmake deleted file mode 100644 index 829e1ac08a..0000000000 --- a/indra/cmake/GoogleBreakpad.cmake +++ /dev/null @@ -1,22 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) - -if (USESYSTEMLIBS) - set(BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED ON) - include(FindGoogleBreakpad) -else (USESYSTEMLIBS) - use_prebuilt_binary(google_breakpad) - if (DARWIN) - set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler) - endif (DARWIN) - if (LINUX) - set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES breakpad_client) - endif (LINUX) - if (WINDOWS) - set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler crash_generation_client crash_generation_server common) - endif (WINDOWS) - # yes, this does look dumb, no, it's not incorrect - # - set(BREAKPAD_INCLUDE_DIRECTORIES "${LIBS_PREBUILT_DIR}/include/google_breakpad" "${LIBS_PREBUILT_DIR}/include/google_breakpad/google_breakpad") -endif (USESYSTEMLIBS) - diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake index b3f42c1a5e..4937c2a9d7 100644 --- a/indra/cmake/LLAddBuildTest.cmake +++ b/indra/cmake/LLAddBuildTest.cmake @@ -2,6 +2,7 @@ include(00-Common) include(LLTestCommand) include(GoogleMock) +include(bugsplat) include(Tut) #***************************************************************************** @@ -22,7 +23,6 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources) # there is another branch that will conflict heavily with any changes here. INCLUDE(GoogleMock) - IF(LL_TEST_VERBOSE) MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} sources: ${sources}") ENDIF(LL_TEST_VERBOSE) @@ -53,7 +53,7 @@ INCLUDE(GoogleMock) ${GOOGLEMOCK_INCLUDE_DIRS} ) SET(alltest_LIBRARIES - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY} ${GOOGLEMOCK_LIBRARIES} @@ -87,6 +87,12 @@ INCLUDE(GoogleMock) IF(LL_TEST_VERBOSE) MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_SOURCE_FILES ${${name}_test_SOURCE_FILES}") ENDIF(LL_TEST_VERBOSE) + + if (USE_BUGSPLAT) + SET_PROPERTY(SOURCE ${${name}_test_SOURCE_FILES} + APPEND PROPERTY COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}") + endif (USE_BUGSPLAT) + # Headers GET_OPT_SOURCE_FILE_PROPERTY(${name}_test_additional_HEADER_FILES ${source} LL_TEST_ADDITIONAL_HEADER_FILES) SET(${name}_test_HEADER_FILES ${name}.h ${${name}_test_additional_HEADER_FILES}) @@ -200,8 +206,9 @@ FUNCTION(LL_ADD_INTEGRATION_TEST ) SET(libraries + ${LEGACY_STDIO_LIBS} ${library_dependencies} - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY} ${GOOGLEMOCK_LIBRARIES} @@ -223,6 +230,11 @@ FUNCTION(LL_ADD_INTEGRATION_TEST SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES COMPILE_FLAGS -I"${TUT_INCLUDE_DIR}") endif(USESYSTEMLIBS) + if (USE_BUGSPLAT) + SET_PROPERTY(SOURCE ${source_files} + APPEND PROPERTY COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}") + endif (USE_BUGSPLAT) + # The following was copied to llcorehttp/CMakeLists.txt's texture_load target. # Any changes made here should be replicated there. if (WINDOWS) diff --git a/indra/cmake/LLAppearance.cmake b/indra/cmake/LLAppearance.cmake index ae265d07e3..675330ec72 100644 --- a/indra/cmake/LLAppearance.cmake +++ b/indra/cmake/LLAppearance.cmake @@ -18,7 +18,7 @@ endif (BUILD_HEADLESS) set(LLAPPEARANCE_LIBRARIES llappearance llmessage llcorehttp - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY} ) diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake index 3e29297c58..8900419f9b 100644 --- a/indra/cmake/LLCommon.cmake +++ b/indra/cmake/LLCommon.cmake @@ -19,7 +19,7 @@ if (LINUX) # specify all libraries that llcommon uses. # llcommon uses `clock_gettime' which is provided by librt on linux. set(LLCOMMON_LIBRARIES llcommon - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_THREAD_LIBRARY} ${BOOST_SYSTEM_LIBRARY} @@ -27,7 +27,7 @@ if (LINUX) ) else (LINUX) set(LLCOMMON_LIBRARIES llcommon - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_THREAD_LIBRARY} ${BOOST_SYSTEM_LIBRARY} ) diff --git a/indra/cmake/LLCoreHttp.cmake b/indra/cmake/LLCoreHttp.cmake index 379ae207de..613453ab5d 100644 --- a/indra/cmake/LLCoreHttp.cmake +++ b/indra/cmake/LLCoreHttp.cmake @@ -12,6 +12,6 @@ set(LLCOREHTTP_INCLUDE_DIRS ) set(LLCOREHTTP_LIBRARIES llcorehttp - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY}) diff --git a/indra/cmake/OpenSSL.cmake b/indra/cmake/OpenSSL.cmake index eb548bdcc1..32400f5e4e 100644 --- a/indra/cmake/OpenSSL.cmake +++ b/indra/cmake/OpenSSL.cmake @@ -9,7 +9,7 @@ if (USESYSTEMLIBS) else (USESYSTEMLIBS) use_prebuilt_binary(openssl) if (WINDOWS) - set(OPENSSL_LIBRARIES ssleay32 libeay32) + set(OPENSSL_LIBRARIES libssl libcrypto) else (WINDOWS) set(OPENSSL_LIBRARIES ssl crypto) endif (WINDOWS) diff --git a/indra/cmake/URIPARSER.cmake b/indra/cmake/URIPARSER.cmake index de146885a0..ecc5b74ef1 100644 --- a/indra/cmake/URIPARSER.cmake +++ b/indra/cmake/URIPARSER.cmake @@ -29,7 +29,7 @@ else (USESYSTEMLIBS) set(URIPARSER_PRELOAD_ARCHIVES -Wl,--whole-archive uriparser -Wl,--no-whole-archive) set(URIPARSER_LIBRARIES uriparser) elseif (DARWIN) - set(URIPARSER_LIBRARIES uriparser) + set(URIPARSER_LIBRARIES liburiparser.dylib) endif (WINDOWS) set(URIPARSER_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/uriparser) endif (USESYSTEMLIBS) diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index 2b54cd4155..c81b22e572 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -34,7 +34,6 @@ set(LL_TESTS ON CACHE BOOL "Build and run unit and integration tests (disable fo set(INCREMENTAL_LINK OFF CACHE BOOL "Use incremental linking on win32 builds (enable for faster links on some machines)") set(ENABLE_MEDIA_PLUGINS ON CACHE BOOL "Turn off building media plugins if they are imported by third-party library mechanism") set(VIEWER_SYMBOL_FILE "" CACHE STRING "Name of tarball into which to place symbol files") -set(BUGSPLAT_DB "" CACHE STRING "BugSplat database name, if BugSplat crash reporting is desired") if(LIBS_CLOSED_DIR) file(TO_CMAKE_PATH "${LIBS_CLOSED_DIR}" LIBS_CLOSED_DIR) @@ -186,12 +185,17 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") list(GET LL_BUILD_LIST "${sysroot_idx}" CMAKE_OSX_SYSROOT) message(STATUS "CMAKE_OSX_SYSROOT = '${CMAKE_OSX_SYSROOT}'") - set(XCODE_VERSION 7.0) - set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvm.clang.1_0") set(CMAKE_XCODE_ATTRIBUTE_GCC_STRICT_ALIASING NO) set(CMAKE_XCODE_ATTRIBUTE_GCC_FAST_MATH NO) set(CMAKE_XCODE_ATTRIBUTE_CLANG_X86_VECTOR_INSTRUCTIONS ssse3) + # we must hard code this to off for now. xcode's built in signing does not + # handle embedded app bundles such as CEF and others. Any signing for local + # development must be done after the build as we do in viewer_manifest.py for + # released builds + # https://stackoverflow.com/a/54296008 + # "-" represents "Sign to Run Locally" and empty string represents "Do Not Sign" + set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "") set(CMAKE_OSX_ARCHITECTURES "${ARCH}") string(REPLACE "i686" "i386" CMAKE_OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}") diff --git a/indra/cmake/bugsplat.cmake b/indra/cmake/bugsplat.cmake index 59644b73ce..4edc4c59cd 100644 --- a/indra/cmake/bugsplat.cmake +++ b/indra/cmake/bugsplat.cmake @@ -1,25 +1,37 @@ -# BugSplat is engaged by setting BUGSPLAT_DB to the target BugSplat database -# name. -if (BUGSPLAT_DB) - if (USESYSTEMLIBS) - message(STATUS "Looking for system BugSplat") - set(BUGSPLAT_FIND_QUIETLY ON) - set(BUGSPLAT_FIND_REQUIRED ON) - include(FindBUGSPLAT) - else (USESYSTEMLIBS) - message(STATUS "Engaging autobuild BugSplat") - include(Prebuilt) - use_prebuilt_binary(bugsplat) - if (WINDOWS) - set(BUGSPLAT_LIBRARIES - ${ARCH_PREBUILT_DIRS_RELEASE}/bugsplat.lib - ) - elseif (DARWIN) - find_library(BUGSPLAT_LIBRARIES BugsplatMac - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}") - else (WINDOWS) +if (INSTALL_PROPRIETARY) + # Note that viewer_manifest.py makes decision based on BUGSPLAT_DB and not USE_BUGSPLAT + if (BUGSPLAT_DB) + set(USE_BUGSPLAT ON CACHE BOOL "Use the BugSplat crash reporting system") + else (BUGSPLAT_DB) + set(USE_BUGSPLAT OFF CACHE BOOL "Use the BugSplat crash reporting system") + endif (BUGSPLAT_DB) +else (INSTALL_PROPRIETARY) + set(USE_BUGSPLAT OFF CACHE BOOL "Use the BugSplat crash reporting system") +endif (INSTALL_PROPRIETARY) + +if (USE_BUGSPLAT) + if (NOT USESYSTEMLIBS) + include(Prebuilt) + use_prebuilt_binary(bugsplat) + if (WINDOWS) + set(BUGSPLAT_LIBRARIES + ${ARCH_PREBUILT_DIRS_RELEASE}/bugsplat.lib + ) + elseif (DARWIN) + find_library(BUGSPLAT_LIBRARIES BugsplatMac REQUIRED + NO_DEFAULT_PATH PATHS "${ARCH_PREBUILT_DIRS_RELEASE}") + else (WINDOWS) + message(FATAL_ERROR "BugSplat is not supported; add -DUSE_BUGSPLAT=OFF") + endif (WINDOWS) + else (NOT USESYSTEMLIBS) + set(BUGSPLAT_FIND_QUIETLY ON) + set(BUGSPLAT_FIND_REQUIRED ON) + include(FindBUGSPLAT) + endif (NOT USESYSTEMLIBS) + + set(BUGSPLAT_DB "" CACHE STRING "BugSplat crash database name") - endif (WINDOWS) set(BUGSPLAT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/bugsplat) - endif (USESYSTEMLIBS) -endif (BUGSPLAT_DB) + set(BUGSPLAT_DEFINE "LL_BUGSPLAT") +endif (USE_BUGSPLAT) + diff --git a/indra/cmake/run_build_test.py b/indra/cmake/run_build_test.py index 210e43b232..ec5d33f902 100755 --- a/indra/cmake/run_build_test.py +++ b/indra/cmake/run_build_test.py @@ -87,7 +87,6 @@ def main(command, arguments=[], libpath=[], vars={}): # 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'): @@ -105,16 +104,21 @@ def main(command, arguments=[], libpath=[], vars={}): # 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])) + # This output format is intended to make it straightforward to copy + # the variable settings and the command itself from the build output + # and paste the whole thing at a command prompt to rerun it manually. + log.info("%s='%s' \\" % (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()]))) + for key, value in vars.items(): + # As noted a few lines above, facilitate copy-paste rerunning. + log.info("%s='%s' \\" % (key, value)) 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)) + log.info(" ".join((("'%s'" % w) if ' ' in w else w) for w in command_list)) # Make sure we see all relevant output *before* child-process output. sys.stdout.flush() try: @@ -305,8 +309,11 @@ def get_windows_table(): return _windows_table -log=logging.getLogger(__name__) -logging.basicConfig() +# Use this instead of logging.basicConfig() because the latter prefixes +# every line of output with INFO:__main__:... +log=logging.getLogger() +log.setLevel(logging.INFO) +log.addHandler(logging.StreamHandler()) if __name__ == "__main__": import argparse diff --git a/indra/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt index b28b04f643..5366987cff 100644 --- a/indra/edit-me-to-trigger-new-build.txt +++ b/indra/edit-me-to-trigger-new-build.txt @@ -1,3 +1,3 @@ - - - +euclid 5/29/2020 +euclid 7/23/2020 +euclid 4/29/2021
\ No newline at end of file diff --git a/indra/integration_tests/llimage_libtest/CMakeLists.txt b/indra/integration_tests/llimage_libtest/CMakeLists.txt index d9353f904c..5787d4d600 100644 --- a/indra/integration_tests/llimage_libtest/CMakeLists.txt +++ b/indra/integration_tests/llimage_libtest/CMakeLists.txt @@ -64,6 +64,7 @@ endif (DARWIN) # Libraries on which this application depends on # Sort by high-level to low-level target_link_libraries(llimage_libtest + ${LEGACY_STDIO_LIBS} ${LLCOMMON_LIBRARIES} ${LLVFS_LIBRARIES} ${LLMATH_LIBRARIES} diff --git a/indra/integration_tests/llui_libtest/CMakeLists.txt b/indra/integration_tests/llui_libtest/CMakeLists.txt index 34e34c7e47..1cec660eb0 100644 --- a/indra/integration_tests/llui_libtest/CMakeLists.txt +++ b/indra/integration_tests/llui_libtest/CMakeLists.txt @@ -75,6 +75,7 @@ endif (DARWIN) # Libraries on which this library depends, needed for Linux builds # Sort by high-level to low-level target_link_libraries(llui_libtest + ${LEGACY_STDIO_LIBS} llui llinventory llmessage diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py index 2e6cf53912..4bc70b2ca4 100755 --- a/indra/lib/python/indra/util/llmanifest.py +++ b/indra/lib/python/indra/util/llmanifest.py @@ -27,6 +27,7 @@ THE SOFTWARE. $/LicenseInfo$ """ +from collections import namedtuple, defaultdict import commands import errno import filecmp @@ -312,6 +313,8 @@ class LLManifestRegistry(type): if match: cls.manifests[match.group(1).lower()] = cls +MissingFile = namedtuple("MissingFile", ("pattern", "tried")) + class LLManifest(object): __metaclass__ = LLManifestRegistry manifests = {} @@ -333,7 +336,8 @@ class LLManifest(object): self.dst_prefix = [args['dest']] self.created_paths = [] self.package_name = "Unknown" - + self.missing = [] + def default_channel(self): return self.args.get('channel', None) == RELEASE_CHANNEL @@ -592,6 +596,40 @@ class LLManifest(object): def package_action(self, src, dst): pass + def finish(self): + """ + generic finish, always called before the ${action}_finish() methods + """ + # Collecting MissingFile instances in self.missing, and checking that + # here, is intended to minimize the number of (potentially lengthy) + # build cycles a developer must run in order to fix missing-files + # errors. The manifest processing is necessarily the last step in a + # build, and if we only caught a single missing file error per run, + # the developer would need to run a build for each additional missing- + # file error until all were resolved. This way permits the developer + # to resolve them all at once. + if self.missing: + print '*' * 72 + print "Missing files:" + # Instead of just dumping each missing file and all the places we + # looked for it, group by common sets of places we looked. Use a + # set to store the 'tried' directories, to avoid mismatches due to + # reordering -- but since we intend to use the set of 'tried' + # directories as a dict key, it must be a frozenset. + organize = defaultdict(set) + for missingfile in self.missing: + organize[frozenset(missingfile.tried)].add(missingfile.pattern) + # Now dump all the patterns sought in each group of 'tried' + # directories. + for tried, patterns in organize.items(): + print " Could not find in:" + for dir in sorted(tried): + print " %s" % dir + for pattern in sorted(patterns): + print " %s" % pattern + print '*' * 72 + raise MissingError('%s patterns could not be found' % len(self.missing)) + def copy_finish(self): pass @@ -825,17 +863,23 @@ class LLManifest(object): 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) + for pfx in try_prefixes: 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)) + # if we produce MissingError, just try the next prefix + continue + # If we actually found nonzero files, stop looking + if count: + break + else: + # no more prefixes left to try + print("\nunable to find '%s'; looked in:\n %s" % (src, '\n '.join(try_prefixes))) + self.missing.append(MissingFile(pattern=src, tried=try_prefixes)) + # At this point 'count' might never have been successfully + # assigned! Even if it was, though, we can be sure it is 0. + return 0 + print "%d files" % count # Let caller check whether we processed as many files as expected. In @@ -846,6 +890,8 @@ class LLManifest(object): self.actions = actions self.construct() # perform finish actions + # generic finish first + self.finish() for action in self.actions: methodname = action + "_finish" method = getattr(self, methodname, None) diff --git a/indra/linux_crash_logger/CMakeLists.txt b/indra/linux_crash_logger/CMakeLists.txt index 315aed8d11..d789c850a0 100644 --- a/indra/linux_crash_logger/CMakeLists.txt +++ b/indra/linux_crash_logger/CMakeLists.txt @@ -69,7 +69,7 @@ target_link_libraries(linux-crash-logger ${LLMATH_LIBRARIES} ${LLCOREHTTP_LIBRARIES} ${LLCOMMON_LIBRARIES} - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${UI_LIBRARIES} ${DB_LIBRARIES} diff --git a/indra/linux_crash_logger/README.txt b/indra/linux_crash_logger/README.txt new file mode 100644 index 0000000000..6932a8d9c3 --- /dev/null +++ b/indra/linux_crash_logger/README.txt @@ -0,0 +1,3 @@ +This component is no longer used in Linden Lab builds. +Change requests to support continued use by open source +builds are welcome. diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index e60037b739..90dfa04f28 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -81,8 +81,8 @@ public: LLAvatarBoneInfo() : mIsJoint(FALSE) {} ~LLAvatarBoneInfo() { - std::for_each(mChildList.begin(), mChildList.end(), DeletePointer()); - mChildList.clear(); + std::for_each(mChildren.begin(), mChildren.end(), DeletePointer()); + mChildren.clear(); } BOOL parseXml(LLXmlTreeNode* node); @@ -96,8 +96,8 @@ private: LLVector3 mRot; LLVector3 mScale; LLVector3 mPivot; - typedef std::vector<LLAvatarBoneInfo*> child_list_t; - child_list_t mChildList; + typedef std::vector<LLAvatarBoneInfo*> bones_t; + bones_t mChildren; }; //------------------------------------------------------------------------ @@ -171,10 +171,9 @@ LLAvatarAppearance::LLAvatarXmlInfo::~LLAvatarXmlInfo() //----------------------------------------------------------------------------- // Static Data //----------------------------------------------------------------------------- -LLXmlTree LLAvatarAppearance::sXMLTree; -LLXmlTree LLAvatarAppearance::sSkeletonXMLTree; LLAvatarSkeletonInfo* LLAvatarAppearance::sAvatarSkeletonInfo = NULL; LLAvatarAppearance::LLAvatarXmlInfo* LLAvatarAppearance::sAvatarXmlInfo = NULL; +LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary* LLAvatarAppearance::sAvatarDictionary = NULL; LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : @@ -202,7 +201,7 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : mBakedTextureDatas[i].mIsLoaded = false; mBakedTextureDatas[i].mIsUsed = false; mBakedTextureDatas[i].mMaskTexName = 0; - mBakedTextureDatas[i].mTextureIndex = LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((LLAvatarAppearanceDefines::EBakedTextureIndex)i); + mBakedTextureDatas[i].mTextureIndex = sAvatarDictionary->bakedToLocalTextureIndex((LLAvatarAppearanceDefines::EBakedTextureIndex)i); } } @@ -215,8 +214,8 @@ void LLAvatarAppearance::initInstance() mRoot = createAvatarJoint(); mRoot->setName( "mRoot" ); - for (LLAvatarAppearanceDictionary::MeshEntries::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().begin(); - iter != LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().end(); + for (LLAvatarAppearanceDictionary::MeshEntries::const_iterator iter = sAvatarDictionary->getMeshEntries().begin(); + iter != sAvatarDictionary->getMeshEntries().end(); ++iter) { const EMeshIndex mesh_index = iter->first; @@ -261,8 +260,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 = sAvatarDictionary->getMeshEntries().begin(); + iter != sAvatarDictionary->getMeshEntries().end(); ++iter) { const EMeshIndex mesh_index = iter->first; @@ -336,6 +335,12 @@ void LLAvatarAppearance::initClass() //static void LLAvatarAppearance::initClass(const std::string& avatar_file_name_arg, const std::string& skeleton_file_name_arg) { + // init dictionary (don't repeat on second login attempt) + if (!sAvatarDictionary) + { + sAvatarDictionary = new LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary(); + } + std::string avatar_file_name; if (!avatar_file_name_arg.empty()) @@ -346,14 +351,15 @@ void LLAvatarAppearance::initClass(const std::string& avatar_file_name_arg, cons { avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR + "_lad.xml"); } - BOOL success = sXMLTree.parseFile( avatar_file_name, FALSE ); + LLXmlTree xml_tree; + BOOL success = xml_tree.parseFile( avatar_file_name, FALSE ); if (!success) { LL_ERRS() << "Problem reading avatar configuration file:" << avatar_file_name << LL_ENDL; } // now sanity check xml file - LLXmlTreeNode* root = sXMLTree.getRoot(); + LLXmlTreeNode* root = xml_tree.getRoot(); if (!root) { LL_ERRS() << "No root node found in avatar configuration file: " << avatar_file_name << LL_ENDL; @@ -400,8 +406,9 @@ void LLAvatarAppearance::initClass(const std::string& avatar_file_name_arg, cons } std::string skeleton_path; + LLXmlTree skeleton_xml_tree; skeleton_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,skeleton_file_name); - if (!parseSkeletonFile(skeleton_path)) + if (!parseSkeletonFile(skeleton_path, skeleton_xml_tree)) { LL_ERRS() << "Error parsing skeleton file: " << skeleton_path << LL_ENDL; } @@ -414,7 +421,7 @@ void LLAvatarAppearance::initClass(const std::string& avatar_file_name_arg, cons delete sAvatarSkeletonInfo; } sAvatarSkeletonInfo = new LLAvatarSkeletonInfo; - if (!sAvatarSkeletonInfo->parseXml(sSkeletonXMLTree.getRoot())) + if (!sAvatarSkeletonInfo->parseXml(skeleton_xml_tree.getRoot())) { LL_ERRS() << "Error parsing skeleton XML file: " << skeleton_path << LL_ENDL; } @@ -453,9 +460,8 @@ void LLAvatarAppearance::initClass(const std::string& avatar_file_name_arg, cons void LLAvatarAppearance::cleanupClass() { delete_and_clear(sAvatarXmlInfo); - // *TODO: What about sAvatarSkeletonInfo ??? - sSkeletonXMLTree.cleanup(); - sXMLTree.cleanup(); + delete_and_clear(sAvatarDictionary); + delete_and_clear(sAvatarSkeletonInfo); } using namespace LLAvatarAppearanceDefines; @@ -577,12 +583,12 @@ void LLAvatarAppearance::computeBodySize() //----------------------------------------------------------------------------- // parseSkeletonFile() //----------------------------------------------------------------------------- -BOOL LLAvatarAppearance::parseSkeletonFile(const std::string& filename) +BOOL LLAvatarAppearance::parseSkeletonFile(const std::string& filename, LLXmlTree& skeleton_xml_tree) { //------------------------------------------------------------------------- // parse the file //------------------------------------------------------------------------- - BOOL parsesuccess = sSkeletonXMLTree.parseFile( filename, FALSE ); + BOOL parsesuccess = skeleton_xml_tree.parseFile( filename, FALSE ); if (!parsesuccess) { @@ -591,7 +597,7 @@ BOOL LLAvatarAppearance::parseSkeletonFile(const std::string& filename) } // now sanity check xml file - LLXmlTreeNode* root = sSkeletonXMLTree.getRoot(); + LLXmlTreeNode* root = skeleton_xml_tree.getRoot(); if (!root) { LL_ERRS() << "No root node found in avatar skeleton file: " << filename << LL_ENDL; @@ -679,8 +685,8 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent // setup children - LLAvatarBoneInfo::child_list_t::const_iterator iter; - for (iter = info->mChildList.begin(); iter != info->mChildList.end(); ++iter) + LLAvatarBoneInfo::bones_t::const_iterator iter; + for (iter = info->mChildren.begin(); iter != info->mChildren.end(); ++iter) { LLAvatarBoneInfo *child_info = *iter; if (!setupBone(child_info, joint, volume_num, joint_num)) @@ -999,7 +1005,7 @@ BOOL LLAvatarAppearance::loadAvatar() { LLAvatarXmlInfo::LLAvatarMorphInfo *info = *iter; - EBakedTextureIndex baked = LLAvatarAppearanceDictionary::findBakedByRegionName(info->mRegion); + EBakedTextureIndex baked = sAvatarDictionary->findBakedByRegionName(info->mRegion); if (baked != BAKED_NUM_INDICES) { LLVisualParam* morph_param; @@ -1135,8 +1141,8 @@ BOOL LLAvatarAppearance::loadMeshNodes() switch(lod) case 0: mesh = &mHairMesh0; */ - for (LLAvatarAppearanceDictionary::MeshEntries::const_iterator mesh_iter = LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().begin(); - mesh_iter != LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().end(); + for (LLAvatarAppearanceDictionary::MeshEntries::const_iterator mesh_iter = sAvatarDictionary->getMeshEntries().begin(); + mesh_iter != sAvatarDictionary->getMeshEntries().end(); ++mesh_iter) { const EMeshIndex mesh_index = mesh_iter->first; @@ -1264,8 +1270,8 @@ BOOL LLAvatarAppearance::loadLayersets() // scan baked textures and associate the layerset with the appropriate one EBakedTextureIndex baked_index = BAKED_NUM_INDICES; - for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin(); - baked_iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); + for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin(); + baked_iter != sAvatarDictionary->getBakedTextures().end(); ++baked_iter) { const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = baked_iter->second; @@ -1684,7 +1690,7 @@ BOOL LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node) delete child_info; return FALSE; } - mChildList.push_back(child_info); + mChildren.push_back(child_info); } return TRUE; } @@ -1743,10 +1749,9 @@ void LLAvatarAppearance::makeJointAliases(LLAvatarBoneInfo *bone_info) mJointAliasMap[*i] = bone_name; } - LLAvatarBoneInfo::child_list_t::const_iterator iter; - for (iter = bone_info->mChildList.begin(); iter != bone_info->mChildList.end(); ++iter) + for (LLAvatarBoneInfo* bone : bone_info->mChildren) { - makeJointAliases( *iter ); + makeJointAliases(bone); } } diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 6a4dbf3726..b1c70f9064 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -156,7 +156,7 @@ public: protected: - static BOOL parseSkeletonFile(const std::string& filename); + static BOOL parseSkeletonFile(const std::string& filename, LLXmlTree& skeleton_xml_tree); virtual void buildCharacter(); virtual BOOL loadAvatar(); @@ -211,9 +211,6 @@ public: // XML parse tree //-------------------------------------------------------------------- protected: - static LLXmlTree sXMLTree; // avatar config file - static LLXmlTree sSkeletonXMLTree; // avatar skeleton file - static LLAvatarSkeletonInfo* sAvatarSkeletonInfo; static LLAvatarXmlInfo* sAvatarXmlInfo; @@ -255,6 +252,7 @@ public: public: virtual void updateMeshTextures() = 0; virtual void dirtyMesh() = 0; // Dirty the avatar mesh + static const LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary *getDictionary() { return sAvatarDictionary; } protected: virtual void dirtyMesh(S32 priority) = 0; // Dirty the avatar mesh, with priority @@ -263,6 +261,9 @@ protected: polymesh_map_t mPolyMeshes; avatar_joint_list_t mMeshLOD; + // mesh entries and backed textures + static LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary* sAvatarDictionary; + /** Meshes ** ** *******************************************************************************/ diff --git a/indra/llappearance/llavatarappearancedefines.cpp b/indra/llappearance/llavatarappearancedefines.cpp index c72943bb82..2bcfd06c40 100644 --- a/indra/llappearance/llavatarappearancedefines.cpp +++ b/indra/llappearance/llavatarappearancedefines.cpp @@ -30,7 +30,6 @@ const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH = 1024; const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT = 1024; -const S32 LLAvatarAppearanceDefines::IMPOSTOR_PERIOD = 2; using namespace LLAvatarAppearanceDefines; @@ -258,19 +257,17 @@ LLAvatarAppearanceDictionary::BakedEntry::BakedEntry(ETextureIndex tex_index, } } -// static -ETextureIndex LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(EBakedTextureIndex index) +ETextureIndex LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(EBakedTextureIndex index) const { - return LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(index)->mTextureIndex; + return getBakedTexture(index)->mTextureIndex; } -// static EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(std::string name) { U8 index = 0; while (index < BAKED_NUM_INDICES) { - const BakedEntry *be = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex) index); + const BakedEntry *be = getBakedTexture((EBakedTextureIndex) index); if (be && be->mName.compare(name) == 0) { // baked texture found @@ -282,16 +279,15 @@ EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(std::stri return BAKED_NUM_INDICES; } -// static EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByImageName(std::string name) { U8 index = 0; while (index < BAKED_NUM_INDICES) { - const BakedEntry *be = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex) index); + const BakedEntry *be = getBakedTexture((EBakedTextureIndex) index); if (be) { - const TextureEntry *te = LLAvatarAppearanceDictionary::getInstance()->getTexture(be->mTextureIndex); + const TextureEntry *te = getTexture(be->mTextureIndex); if (te && te->mDefaultImageName.compare(name) == 0) { // baked texture found @@ -304,10 +300,9 @@ EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByImageName(std::strin return BAKED_NUM_INDICES; } -// static -LLWearableType::EType LLAvatarAppearanceDictionary::getTEWearableType(ETextureIndex index ) +LLWearableType::EType LLAvatarAppearanceDictionary::getTEWearableType(ETextureIndex index ) const { - return getInstance()->getTexture(index)->mWearableType; + return getTexture(index)->mWearableType; } // static diff --git a/indra/llappearance/llavatarappearancedefines.h b/indra/llappearance/llavatarappearancedefines.h index 5663d24293..49dfbebeea 100644 --- a/indra/llappearance/llavatarappearancedefines.h +++ b/indra/llappearance/llavatarappearancedefines.h @@ -39,7 +39,6 @@ namespace LLAvatarAppearanceDefines extern const S32 SCRATCH_TEX_WIDTH; extern const S32 SCRATCH_TEX_HEIGHT; -extern const S32 IMPOSTOR_PERIOD; static const U32 AVATAR_HOVER = 11001; @@ -143,13 +142,14 @@ typedef std::vector<LLWearableType::EType> wearables_vec_t; // // This holds const data - it is initialized once and the contents never change after that. //------------------------------------------------------------------------ -class LLAvatarAppearanceDictionary : public LLSingleton<LLAvatarAppearanceDictionary> +class LLAvatarAppearanceDictionary { //-------------------------------------------------------------------- // Constructors and Destructors //-------------------------------------------------------------------- - LLSINGLETON(LLAvatarAppearanceDictionary); - virtual ~LLAvatarAppearanceDictionary(); +public: + LLAvatarAppearanceDictionary(); + ~LLAvatarAppearanceDictionary(); private: void createAssociations(); @@ -235,14 +235,14 @@ public: //-------------------------------------------------------------------- public: // Convert from baked texture to associated texture; e.g. BAKED_HEAD -> TEX_HEAD_BAKED - static ETextureIndex bakedToLocalTextureIndex(EBakedTextureIndex t); + ETextureIndex bakedToLocalTextureIndex(EBakedTextureIndex t) const; // find a baked texture index based on its name - static EBakedTextureIndex findBakedByRegionName(std::string name); - static EBakedTextureIndex findBakedByImageName(std::string name); + EBakedTextureIndex findBakedByRegionName(std::string name); + EBakedTextureIndex findBakedByImageName(std::string name); // Given a texture entry, determine which wearable type owns it. - static LLWearableType::EType getTEWearableType(ETextureIndex index); + LLWearableType::EType getTEWearableType(ETextureIndex index) const; static BOOL isBakedImageId(const LLUUID& id); static EBakedTextureIndex assetIdToBakedTextureIndex(const LLUUID& id); diff --git a/indra/llappearance/llavatarjoint.cpp b/indra/llappearance/llavatarjoint.cpp index 29642be099..a1d4fe6423 100644 --- a/indra/llappearance/llavatarjoint.cpp +++ b/indra/llappearance/llavatarjoint.cpp @@ -100,10 +100,10 @@ void LLAvatarJoint::setValid( BOOL valid, BOOL recursive ) //---------------------------------------------------------------- if (recursive) { - for (child_list_t::iterator iter = mChildren.begin(); + for (joints_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { - LLAvatarJoint* joint = (LLAvatarJoint*)(*iter); + LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(*iter); joint->setValid(valid, TRUE); } } @@ -118,10 +118,10 @@ void LLAvatarJoint::setSkeletonComponents( U32 comp, BOOL recursive ) mComponents = comp; if (recursive) { - for (child_list_t::iterator iter = mChildren.begin(); + for (joints_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { - LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter); + LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(*iter); joint->setSkeletonComponents(comp, recursive); } } @@ -133,10 +133,10 @@ void LLAvatarJoint::setVisible(BOOL visible, BOOL recursive) if (recursive) { - for (child_list_t::iterator iter = mChildren.begin(); + for (joints_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { - LLAvatarJoint* joint = (LLAvatarJoint*)(*iter); + LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(*iter); joint->setVisible(visible, recursive); } } @@ -144,30 +144,30 @@ void LLAvatarJoint::setVisible(BOOL visible, BOOL recursive) void LLAvatarJoint::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area) { - for (child_list_t::iterator iter = mChildren.begin(); + for (joints_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { - LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter); + LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(*iter); joint->updateFaceSizes(num_vertices, num_indices, pixel_area); } } void LLAvatarJoint::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind, bool terse_update) { - for (child_list_t::iterator iter = mChildren.begin(); + for (joints_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { - LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter); + LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(*iter); joint->updateFaceData(face, pixel_area, damp_wind, terse_update); } } void LLAvatarJoint::updateJointGeometry() { - for (child_list_t::iterator iter = mChildren.begin(); + for (joints_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { - LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter); + LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(*iter); joint->updateJointGeometry(); } } @@ -178,10 +178,10 @@ BOOL LLAvatarJoint::updateLOD(F32 pixel_area, BOOL activate) BOOL lod_changed = FALSE; BOOL found_lod = FALSE; - for (child_list_t::iterator iter = mChildren.begin(); + for (joints_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { - LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter); + LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(*iter); F32 jointLOD = joint->getLOD(); if (found_lod || jointLOD == DEFAULT_AVATAR_JOINT_LOD) @@ -207,10 +207,10 @@ BOOL LLAvatarJoint::updateLOD(F32 pixel_area, BOOL activate) void LLAvatarJoint::dump() { - for (child_list_t::iterator iter = mChildren.begin(); + for (joints_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { - LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter); + LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(*iter); joint->dump(); } } diff --git a/indra/llappearance/llavatarjointmesh.cpp b/indra/llappearance/llavatarjointmesh.cpp index 7ca0928171..0a23b1fda3 100644 --- a/indra/llappearance/llavatarjointmesh.cpp +++ b/indra/llappearance/llavatarjointmesh.cpp @@ -379,7 +379,7 @@ void LLAvatarJointMesh::setupJoint(LLAvatarJoint* current_joint) } // depth-first traversal - for (LLJoint::child_list_t::iterator iter = current_joint->mChildren.begin(); + for (LLJoint::joints_t::iterator iter = current_joint->mChildren.begin(); iter != current_joint->mChildren.end(); ++iter) { LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter); diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp index e5e502b158..05d26fbe7a 100644 --- a/indra/llappearance/lldriverparam.cpp +++ b/indra/llappearance/lldriverparam.cpp @@ -614,7 +614,7 @@ void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight) mAvatarAppearance->isValid() && driven->mParam->getCrossWearable()) { - LLWearable* wearable = dynamic_cast<LLWearable*> (mWearablep); + LLWearable* wearable = mWearablep; if (mAvatarAppearance->getWearableData()->isOnTop(wearable)) { use_self = true; diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp index 2cb4c65d7c..ce7010984a 100644 --- a/indra/llappearance/llpolymorph.cpp +++ b/indra/llappearance/llpolymorph.cpp @@ -816,8 +816,8 @@ void LLPolyVertexMask::generateMask(U8 *maskTextureData, S32 width, S32 height, U32 s = llclamp((U32)(uvCoords.mV[VX] * (F32)(width - 1)), (U32)0, (U32)width - 1); U32 t = llclamp((U32)(uvCoords.mV[VY] * (F32)(height - 1)), (U32)0, (U32)height - 1); - mWeights[index] = ((F32) maskTextureData[((t * width + s) * num_components) + (num_components - 1)]) / 255.f; - + mWeights[index] = maskTextureData ? ((F32) maskTextureData[((t * width + s) * num_components) + (num_components - 1)]) / 255.f : 0.0f; + if (invert) { mWeights[index] = 1.f - mWeights[index]; diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp index 5b77a7433a..ae38c25dbf 100644 --- a/indra/llappearance/llpolyskeletaldistortion.cpp +++ b/indra/llappearance/llpolyskeletaldistortion.cpp @@ -160,7 +160,7 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info) mJointScales[joint] = bone_info->mScaleDeformation; // apply to children that need to inherit it - for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); + for (LLJoint::joints_t::iterator iter = joint->mChildren.begin(); iter != joint->mChildren.end(); ++iter) { LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter); diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index 186986bf9c..e5039141de 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -137,7 +137,7 @@ void LLTexLayerSetBuffer::postRenderTexLayerSet(BOOL success) popProjection(); } -BOOL LLTexLayerSetBuffer::renderTexLayerSet() +BOOL LLTexLayerSetBuffer::renderTexLayerSet(LLRenderTarget* bound_target) { // Default color mask for tex layer render gGL.setColorMask(true, true); @@ -161,7 +161,7 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet() // Composite the color data LLGLSUIDefault gls_ui; success &= mTexLayerSet->render( getCompositeOriginX(), getCompositeOriginY(), - getCompositeWidth(), getCompositeHeight() ); + getCompositeWidth(), getCompositeHeight(), bound_target ); gGL.flush(); midRenderTexLayerSet(success); @@ -375,7 +375,7 @@ void LLTexLayerSet::deleteCaches() } -BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) +BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target ) { BOOL success = TRUE; mIsVisible = TRUE; @@ -427,12 +427,12 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) if (layer->getRenderPass() == LLTexLayer::RP_COLOR) { gGL.flush(); - success &= layer->render(x, y, width, height); + success &= layer->render(x, y, width, height, bound_target); gGL.flush(); } } - renderAlphaMaskTextures(x, y, width, height, false); + renderAlphaMaskTextures(x, y, width, height, bound_target, false); stop_glerror(); } @@ -523,7 +523,7 @@ const LLTexLayerSetBuffer* LLTexLayerSet::getComposite() const } static LLTrace::BlockTimerStatHandle FTM_GATHER_MORPH_MASK_ALPHA("gatherMorphMaskAlpha"); -void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height) +void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height, LLRenderTarget* bound_target) { LL_RECORD_BLOCK_TIME(FTM_GATHER_MORPH_MASK_ALPHA); memset(data, 255, width * height); @@ -531,15 +531,15 @@ void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) { LLTexLayerInterface* layer = *iter; - layer->gatherAlphaMasks(data, origin_x, origin_y, width, height); + layer->gatherAlphaMasks(data, origin_x, origin_y, width, height, bound_target); } // Set alpha back to that of our alpha masks. - renderAlphaMaskTextures(origin_x, origin_y, width, height, true); + renderAlphaMaskTextures(origin_x, origin_y, width, height, bound_target, true); } static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK_TEXTURES("renderAlphaMaskTextures"); -void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, bool forceClear) +void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target, bool forceClear) { LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_TEXTURES); const LLTexLayerSetInfo *info = getInfo(); @@ -728,8 +728,8 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) /* if ("upper_shirt" == local_texture_name) mLocalTexture = TEX_UPPER_SHIRT; */ mLocalTexture = TEX_NUM_INDICES; - for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); - iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); + for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearance::getDictionary()->getTextures().begin(); + iter != LLAvatarAppearance::getDictionary()->getTextures().end(); iter++) { const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; @@ -979,7 +979,7 @@ LLWearableType::EType LLTexLayerInterface::getWearableType() const return type; } - return LLAvatarAppearanceDictionary::getTEWearableType(te); + return LLAvatarAppearance::getDictionary()->getTEWearableType(te); } LLTexLayerInterface::ERenderPass LLTexLayerInterface::getRenderPass() const @@ -1065,7 +1065,7 @@ LLTexLayer::~LLTexLayer() iter != mAlphaCache.end(); iter++ ) { U8* alpha_data = iter->second; - delete [] alpha_data; + ll_aligned_free_32(alpha_data); } } @@ -1124,7 +1124,7 @@ void LLTexLayer::calculateTexLayerColor(const param_color_list_t ¶m_list, LL } } -BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) +BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target) { LLGLEnable color_mat(GL_COLOR_MATERIAL); // *TODO: Is this correct? @@ -1185,7 +1185,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) }//*/ const bool force_render = true; - renderMorphMasks(x, y, width, height, net_color, force_render); + renderMorphMasks(x, y, width, height, net_color, bound_target, force_render); alpha_mask_specified = TRUE; gGL.flush(); gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ONE_MINUS_DEST_ALPHA); @@ -1428,13 +1428,13 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) return success; } -/*virtual*/ void LLTexLayer::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height) +/*virtual*/ void LLTexLayer::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target) { - addAlphaMask(data, originX, originY, width, height); + addAlphaMask(data, originX, originY, width, height, bound_target); } 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) +void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, LLRenderTarget* bound_target, bool force_render) { if (!force_render && !hasMorph()) { @@ -1572,17 +1572,64 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC { alpha_cache_t::iterator iter2 = mAlphaCache.begin(); // arbitrarily grab the first entry alpha_data = iter2->second; - delete [] alpha_data; + ll_aligned_free_32(alpha_data); mAlphaCache.erase(iter2); } - alpha_data = new U8[width * height]; - mAlphaCache[cache_index] = alpha_data; - - // nSight doesn't support use of glReadPixels - if (!LLRender::sNsightDebugSupport) + + // GPUs tend to be very uptight about memory alignment as the DMA used to convey + // said data to the card works better when well-aligned so plain old default-aligned heap mem is a no-no + //new U8[width * height]; + size_t bytes_per_pixel = 1; // unsigned byte alpha channel only... + size_t row_size = (width + 3) & ~0x3; // OpenGL 4-byte row align (even for things < 4 bpp...) + size_t pixels = (row_size * height); + size_t mem_size = pixels * bytes_per_pixel; + + alpha_data = (U8*)ll_aligned_malloc_32(mem_size); + + bool skip_readback = LLRender::sNsightDebugSupport; // nSight doesn't support use of glReadPixels + + if (!skip_readback) { - glReadPixels(x, y, width, height, GL_ALPHA, GL_UNSIGNED_BYTE, alpha_data); - } + if (gGLManager.mIsIntel) + { // work-around for broken intel drivers which cannot do glReadPixels on an RGBA FBO + // returning only the alpha portion without locking up downstream + U8* temp = (U8*)ll_aligned_malloc_32(mem_size << 2); // allocate same size, but RGBA + + if (bound_target) + { + gGL.getTexUnit(0)->bind(bound_target); + } + else + { + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, 0); + } + + glGetTexImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGBA, GL_UNSIGNED_BYTE, temp); + + U8* alpha_cursor = alpha_data; + U8* pixel = temp; + for (int i = 0; i < pixels; i++) + { + *alpha_cursor++ = pixel[3]; + pixel += 4; + } + + gGL.getTexUnit(0)->disable(); + + ll_aligned_free_32(temp); + } + else + { // platforms with working drivers... + glReadPixels(x, y, width, height, GL_ALPHA, GL_UNSIGNED_BYTE, alpha_data); + } + } + else + { + ll_aligned_free_32(alpha_data); + alpha_data = nullptr; + } + + mAlphaCache[cache_index] = alpha_data; } getTexLayerSet()->getAvatarAppearance()->dirtyMesh(); @@ -1593,7 +1640,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC } static LLTrace::BlockTimerStatHandle FTM_ADD_ALPHA_MASK("addAlphaMask"); -void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height) +void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target) { LL_RECORD_BLOCK_TIME(FTM_ADD_ALPHA_MASK); S32 size = width * height; @@ -1605,7 +1652,7 @@ void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 // TODO: eliminate need for layer morph mask valid flag invalidateMorphMasks(); const bool force_render = false; - renderMorphMasks(originX, originY, width, height, net_color, force_render); + renderMorphMasks(originX, originY, width, height, net_color, bound_target, force_render); alphaData = getAlphaData(); } if (alphaData) @@ -1739,7 +1786,7 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const return layer; } -/*virtual*/ BOOL LLTexLayerTemplate::render(S32 x, S32 y, S32 width, S32 height) +/*virtual*/ BOOL LLTexLayerTemplate::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target) { if(!mInfo) { @@ -1766,7 +1813,7 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const { wearable->writeToAvatar(mAvatarAppearance); layer->setLTO(lto); - success &= layer->render(x,y,width,height); + success &= layer->render(x, y, width, height, bound_target); } } @@ -1788,14 +1835,14 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const return success; } -/*virtual*/ void LLTexLayerTemplate::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height) +/*virtual*/ void LLTexLayerTemplate::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target) { U32 num_wearables = updateWearableCache(); U32 i = num_wearables - 1; // For rendering morph masks, we only want to use the top wearable LLTexLayer *layer = getLayer(i); if (layer) { - layer->addAlphaMask(data, originX, originY, width, height); + layer->addAlphaMask(data, originX, originY, width, height, bound_target); } } diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h index 9318b23fd1..6a5040cf0b 100644 --- a/indra/llappearance/lltexlayer.h +++ b/indra/llappearance/lltexlayer.h @@ -65,7 +65,7 @@ public: LLTexLayerInterface(const LLTexLayerInterface &layer, LLWearable *wearable); virtual ~LLTexLayerInterface() {} - virtual BOOL render(S32 x, S32 y, S32 width, S32 height) = 0; + virtual BOOL render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target) = 0; virtual void deleteCaches() = 0; virtual BOOL blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) = 0; virtual BOOL isInvisibleAlphaMask() const = 0; @@ -85,7 +85,7 @@ public: BOOL isMorphValid() const { return mMorphMasksValid; } void requestUpdate(); - virtual void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height) = 0; + virtual void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target) = 0; BOOL hasAlphaParams() const { return !mParamAlphaList.empty(); } ERenderPass getRenderPass() const; @@ -121,10 +121,10 @@ public: LLTexLayerTemplate(LLTexLayerSet* const layer_set, LLAvatarAppearance* const appearance); LLTexLayerTemplate(const LLTexLayerTemplate &layer); /*virtual*/ ~LLTexLayerTemplate(); - /*virtual*/ BOOL render(S32 x, S32 y, S32 width, S32 height); + /*virtual*/ BOOL render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target); /*virtual*/ BOOL setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // This sets mInfo and calls initialization functions /*virtual*/ BOOL blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer - /*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height); + /*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target); /*virtual*/ void setHasMorph(BOOL newval); /*virtual*/ void deleteCaches(); /*virtual*/ BOOL isInvisibleAlphaMask() const; @@ -152,16 +152,16 @@ public: /*virtual*/ ~LLTexLayer(); /*virtual*/ BOOL setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // This sets mInfo and calls initialization functions - /*virtual*/ BOOL render(S32 x, S32 y, S32 width, S32 height); + /*virtual*/ BOOL render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target); /*virtual*/ void deleteCaches(); const U8* getAlphaData() const; BOOL findNetColor(LLColor4* color) const; /*virtual*/ BOOL blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer - /*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height); - void renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, bool force_render); - void addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height); + /*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target); + void renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, LLRenderTarget* bound_target, bool force_render); + void addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target); /*virtual*/ BOOL isInvisibleAlphaMask() const; void setLTO(LLLocalTextureObject *lto) { mLocalTextureObject = lto; } @@ -194,13 +194,13 @@ public: const LLTexLayerSetBuffer* getComposite() const; // Do not create one if it doesn't exist. virtual void createComposite() = 0; void destroyComposite(); - void gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height); + void gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height, LLRenderTarget* bound_target); const LLTexLayerSetInfo* getInfo() const { return mInfo; } BOOL setInfo(const LLTexLayerSetInfo *info); // This sets mInfo and calls initialization functions - BOOL render(S32 x, S32 y, S32 width, S32 height); - void renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, bool forceClear = false); + BOOL render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target = nullptr); + void renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target = nullptr, bool forceClear = false); BOOL isBodyRegion(const std::string& region) const; void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components); @@ -282,7 +282,7 @@ protected: virtual S32 getCompositeOriginY() const = 0; virtual S32 getCompositeWidth() const = 0; virtual S32 getCompositeHeight() const = 0; - BOOL renderTexLayerSet(); + BOOL renderTexLayerSet(LLRenderTarget* bound_target); LLTexLayerSet* const mTexLayerSet; }; diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index 6079913a8e..28a36e6e41 100644 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -183,7 +183,7 @@ void LLWearable::createVisualParams(LLAvatarAppearance *avatarp) void LLWearable::createLayers(S32 te, LLAvatarAppearance *avatarp) { LLTexLayerSet *layer_set = NULL; - const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te); + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearance::getDictionary()->getTexture((ETextureIndex)te); if (texture_dict && texture_dict->mIsUsedByBakedTexture) { const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; @@ -606,7 +606,7 @@ void LLWearable::syncImages(te_map_t &src, te_map_t &dst) // Deep copy of src (copies only those tes that are current, filling in defaults where needed) for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) { - if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex) te) == mType) + if (LLAvatarAppearance::getDictionary()->getTEWearableType((ETextureIndex) te) == mType) { te_map_t::const_iterator iter = src.find(te); LLUUID image_id; diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp index 2bf3b9085b..66cc4f3766 100644 --- a/indra/llappearance/llwearabledata.cpp +++ b/indra/llappearance/llwearabledata.cpp @@ -339,7 +339,7 @@ U32 LLWearableData::getWearableCount(const LLWearableType::EType type) const U32 LLWearableData::getWearableCount(const U32 tex_index) const { - const LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType((LLAvatarAppearanceDefines::ETextureIndex)tex_index); + const LLWearableType::EType wearable_type = LLAvatarAppearance::getDictionary()->getTEWearableType((LLAvatarAppearanceDefines::ETextureIndex)tex_index); return getWearableCount(wearable_type); } @@ -349,7 +349,7 @@ LLUUID LLWearableData::computeBakedTextureHash(LLAvatarAppearanceDefines::EBaked LLUUID hash_id; bool hash_computed = false; LLMD5 hash; - const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(baked_index); + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearance::getDictionary()->getBakedTexture(baked_index); for (U8 i=0; i < baked_dict->mWearables.size(); i++) { diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp index 0e29bbe783..281060d01d 100644 --- a/indra/llappearance/llwearabletype.cpp +++ b/indra/llappearance/llwearabletype.cpp @@ -29,22 +29,11 @@ #include "llinventorytype.h" #include "llinventorydefines.h" -static LLTranslationBridge* sTrans = NULL; - -// static -void LLWearableType::initClass(LLTranslationBridge* trans) -{ - sTrans = trans; -} - -void LLWearableType::cleanupClass() -{ - delete sTrans; -} struct WearableEntry : public LLDictionaryEntry { - WearableEntry(const std::string &name, + WearableEntry(LLWearableType& wtype, + const std::string &name, const std::string& default_new_name, LLAssetType::EType assetType, LLInventoryType::EIconName iconName, @@ -53,7 +42,7 @@ struct WearableEntry : public LLDictionaryEntry LLDictionaryEntry(name), mAssetType(assetType), mDefaultNewName(default_new_name), - mLabel(sTrans->getString(name)), + mLabel(wtype.mTrans->getString(name)), mIconName(iconName), mDisableCameraSwitch(disable_camera_switch), mAllowMultiwear(allow_multiwear) @@ -68,35 +57,57 @@ struct WearableEntry : public LLDictionaryEntry BOOL mAllowMultiwear; }; -class LLWearableDictionary : public LLSingleton<LLWearableDictionary>, +class LLWearableDictionary : public LLParamSingleton<LLWearableDictionary>, public LLDictionary<LLWearableType::EType, WearableEntry> { - LLSINGLETON(LLWearableDictionary); + LLSINGLETON(LLWearableDictionary, LLWearableType&); }; -LLWearableDictionary::LLWearableDictionary() +LLWearableDictionary::LLWearableDictionary(LLWearableType& wtype) { - addEntry(LLWearableType::WT_SHAPE, new WearableEntry("shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SHAPE, FALSE, FALSE)); - addEntry(LLWearableType::WT_SKIN, new WearableEntry("skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SKIN, FALSE, FALSE)); - addEntry(LLWearableType::WT_HAIR, new WearableEntry("hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_HAIR, FALSE, FALSE)); - addEntry(LLWearableType::WT_EYES, new WearableEntry("eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_EYES, FALSE, FALSE)); - addEntry(LLWearableType::WT_SHIRT, new WearableEntry("shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE)); - addEntry(LLWearableType::WT_PANTS, new WearableEntry("pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PANTS, FALSE, TRUE)); - addEntry(LLWearableType::WT_SHOES, new WearableEntry("shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHOES, FALSE, TRUE)); - addEntry(LLWearableType::WT_SOCKS, new WearableEntry("socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE)); - addEntry(LLWearableType::WT_JACKET, new WearableEntry("jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_JACKET, FALSE, TRUE)); - addEntry(LLWearableType::WT_GLOVES, new WearableEntry("gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE)); - addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry("undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE)); - addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry("underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE)); - 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)); - - addEntry(LLWearableType::WT_INVALID, new WearableEntry("invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_UNKNOWN, FALSE, FALSE)); - addEntry(LLWearableType::WT_NONE, new WearableEntry("none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE)); + addEntry(LLWearableType::WT_SHAPE, new WearableEntry(wtype, "shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SHAPE, FALSE, FALSE)); + addEntry(LLWearableType::WT_SKIN, new WearableEntry(wtype, "skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SKIN, FALSE, FALSE)); + addEntry(LLWearableType::WT_HAIR, new WearableEntry(wtype, "hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_HAIR, FALSE, FALSE)); + addEntry(LLWearableType::WT_EYES, new WearableEntry(wtype, "eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_EYES, FALSE, FALSE)); + addEntry(LLWearableType::WT_SHIRT, new WearableEntry(wtype, "shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE)); + addEntry(LLWearableType::WT_PANTS, new WearableEntry(wtype, "pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PANTS, FALSE, TRUE)); + addEntry(LLWearableType::WT_SHOES, new WearableEntry(wtype, "shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHOES, FALSE, TRUE)); + addEntry(LLWearableType::WT_SOCKS, new WearableEntry(wtype, "socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE)); + addEntry(LLWearableType::WT_JACKET, new WearableEntry(wtype, "jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_JACKET, FALSE, TRUE)); + addEntry(LLWearableType::WT_GLOVES, new WearableEntry(wtype, "gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE)); + addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(wtype, "undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE)); + addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(wtype, "underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE)); + addEntry(LLWearableType::WT_SKIRT, new WearableEntry(wtype, "skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE)); + addEntry(LLWearableType::WT_ALPHA, new WearableEntry(wtype, "alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE)); + addEntry(LLWearableType::WT_TATTOO, new WearableEntry(wtype, "tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE)); + addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry(wtype, "universal", "New Universal", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNIVERSAL, FALSE, TRUE)); + + addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(wtype, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE)); + + addEntry(LLWearableType::WT_INVALID, new WearableEntry(wtype, "invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_UNKNOWN, FALSE, FALSE)); + addEntry(LLWearableType::WT_NONE, new WearableEntry(wtype, "none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE)); +} + + +// class LLWearableType + +LLWearableType::LLWearableType(LLTranslationBridge* trans) +{ + // LLTranslationBridge exists, but is not ready at this point in time since strings.xml is not yet loaded + mTrans = trans; +} + +LLWearableType::~LLWearableType() +{ + delete mTrans; +} + +void LLWearableType::initSingleton() +{ + // To make sure all wrapping functions will crash without initing LLWearableType; + LLWearableDictionary::initParamSingleton(*this); + + // Todo: consider merging LLWearableType and LLWearableDictionary } // static @@ -173,6 +184,6 @@ BOOL LLWearableType::getAllowMultiwear(LLWearableType::EType type) // static LLWearableType::EType LLWearableType::inventoryFlagsToWearableType(U32 flags) { - return (LLWearableType::EType)(flags & LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK); + return (LLWearableType::EType)(flags & LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK); } diff --git a/indra/llappearance/llwearabletype.h b/indra/llappearance/llwearabletype.h index ac81376538..57f3ef160d 100644 --- a/indra/llappearance/llwearabletype.h +++ b/indra/llappearance/llwearabletype.h @@ -31,19 +31,14 @@ #include "lldictionary.h" #include "llinventorytype.h" #include "llsingleton.h" +#include "llinvtranslationbrdg.h" -class LLTranslationBridge -{ -public: - // clang needs this to be happy - virtual ~LLTranslationBridge() {} - - virtual std::string getString(const std::string &xml_desc) = 0; -}; - - -class LLWearableType +class LLWearableType : public LLParamSingleton<LLWearableType> { + LLSINGLETON(LLWearableType, LLTranslationBridge* trans); + ~LLWearableType(); + void initSingleton(); + friend struct WearableEntry; public: enum EType { @@ -70,9 +65,8 @@ public: WT_NONE = -1, }; - static void initClass(LLTranslationBridge* trans); // initializes static members - static void cleanupClass(); // initializes static members - + // Most methods are wrappers for dictionary, but if LLWearableType is not initialized, + // they will crash. Whole LLWearableType is just wrapper for convinient calls. static const std::string& getTypeName(EType type); static const std::string& getTypeDefaultNewName(EType type); static const std::string& getTypeLabel(EType type); @@ -81,11 +75,12 @@ public: static LLInventoryType::EIconName getIconName(EType type); static BOOL getDisableCameraSwitch(EType type); static BOOL getAllowMultiwear(EType type); - static EType inventoryFlagsToWearableType(U32 flags); + + static EType inventoryFlagsToWearableType(U32 flags); protected: - LLWearableType() {} - ~LLWearableType() {} + + LLTranslationBridge* mTrans; }; #endif // LL_LLWEARABLETYPE_H diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index e943dd5d5c..558ede7bf6 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -4,7 +4,7 @@ project(llaudio) include(00-Common) include(LLAudio) -include(FMODEX) +include(FMODSTUDIO) include(OPENAL) include(LLCommon) include(LLMath) @@ -42,24 +42,28 @@ set(llaudio_HEADER_FILES llwindgen.h ) -if (FMODEX) +if (FMODSTUDIO) include_directories( - ${FMODEX_INCLUDE_DIR} + ${FMODSTUDIO_INCLUDE_DIR} ) list(APPEND llaudio_SOURCE_FILES - llaudioengine_fmodex.cpp - lllistener_fmodex.cpp - llstreamingaudio_fmodex.cpp + llaudioengine_fmodstudio.cpp + lllistener_fmodstudio.cpp + llstreamingaudio_fmodstudio.cpp ) list(APPEND llaudio_HEADER_FILES - llaudioengine_fmodex.h - lllistener_fmodex.h - llstreamingaudio_fmodex.h + llaudioengine_fmodstudio.h + lllistener_fmodstudio.h + llstreamingaudio_fmodstudio.h ) -endif (FMODEX) +endif (FMODSTUDIO) if (OPENAL) + include_directories( + ${OPENAL_LIBRARIES} + ) + list(APPEND llaudio_SOURCE_FILES llaudioengine_openal.cpp lllistener_openal.cpp diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp index 6ab61689fd..e7db84f6ab 100644 --- a/indra/llaudio/llaudiodecodemgr.cpp +++ b/indra/llaudio/llaudiodecodemgr.cpp @@ -271,7 +271,7 @@ BOOL LLVorbisDecodeState::initDecode() mWAVBuffer.reserve(size_guess); mWAVBuffer.resize(WAV_HEADER_SIZE); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { LL_WARNS("AudioEngine") << "Out of memory when trying to alloc buffer: " << size_guess << LL_ENDL; delete mInFilep; diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp index f49028aad5..1d447f32ae 100644 --- a/indra/llaudio/llaudioengine.cpp +++ b/indra/llaudio/llaudioengine.cpp @@ -111,7 +111,7 @@ void LLAudioEngine::setDefaults() } -bool LLAudioEngine::init(const S32 num_channels, void* userdata) +bool LLAudioEngine::init(const S32 num_channels, void* userdata, const std::string &app_title) { setDefaults(); diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h index f1e1b4e308..97674f15f7 100644 --- a/indra/llaudio/llaudioengine.h +++ b/indra/llaudio/llaudioengine.h @@ -99,7 +99,7 @@ public: virtual ~LLAudioEngine(); // initialization/startup/shutdown - virtual bool init(const S32 num_channels, void *userdata); + virtual bool init(const S32 num_channels, void *userdata, const std::string &app_title); virtual std::string getDriverName(bool verbose) = 0; virtual void shutdown(); diff --git a/indra/llaudio/llaudioengine_fmodex.cpp b/indra/llaudio/llaudioengine_fmodex.cpp deleted file mode 100644 index 7e65a05e48..0000000000 --- a/indra/llaudio/llaudioengine_fmodex.cpp +++ /dev/null @@ -1,767 +0,0 @@ -/** - * @file audioengine_fmodex.cpp - * @brief Implementation of LLAudioEngine class abstracting the audio - * support as a FMODEX implementation - * - * $LicenseInfo:firstyear=2002&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 "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" - -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}; - -LLAudioEngine_FMODEX::LLAudioEngine_FMODEX(bool enable_profiler) -{ - mInited = false; - mWindGen = NULL; - mWindDSP = NULL; - mSystem = NULL; - mEnableProfiler = enable_profiler; - mWindDSPDesc = new FMOD_DSP_DESCRIPTION(); -} - - -LLAudioEngine_FMODEX::~LLAudioEngine_FMODEX() -{ - delete mWindDSPDesc; -} - - -inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) -{ - if(result == FMOD_OK) - return false; - LL_DEBUGS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; - 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() << "Decode buffer size: " << size << LL_ENDL; - } - else if(type & FMOD_MEMORY_STREAM_FILE) - { - LL_INFOS() << "Strean buffer size: " << size << LL_ENDL; - } - 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) -{ - 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; - - // turn off non-error log spam to fmod.log (TODO: why do we even have an fmod.log if we don't link against log lib?) - FMOD::Debug_SetLevel(FMOD_DEBUG_LEVEL_ERROR); - - 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; - mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers); - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_bufferlength=" << r_bufferlength << " bytes" << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_numbuffers=" << r_numbuffers << LL_ENDL; - - mSystem->getSoftwareFormat(&r_samplerate, NULL, &r_channels, NULL, NULL, &r_bits); - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_samplerate=" << r_samplerate << "Hz" << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_channels=" << r_channels << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_bits =" << r_bits << LL_ENDL; - - char r_name[512]; - mSystem->getDriverInfo(0, r_name, 511, 0); - r_name[511] = '\0'; - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_name=\"" << r_name << "\"" << LL_ENDL; - - int latency = 100; // optimistic default - i suspect if sample rate is 0, everything breaks. - if ( r_samplerate != 0 ) - latency = (int)(1000.0f * r_bufferlength * r_numbuffers / r_samplerate); - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): latency=" << latency << "ms" << LL_ENDL; - - mInited = true; - - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): initialization complete." << LL_ENDL; - - return true; -} - - -std::string LLAudioEngine_FMODEX::getDriverName(bool verbose) -{ - llassert_always(mSystem); - if (verbose) - { - U32 version; - if(!Check_FMOD_Error(mSystem->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() << "Listener creation failed" << LL_ENDL; - } -} - - -void LLAudioEngine_FMODEX::shutdown() -{ - stopInternetStream(); - - LL_INFOS() << "About to LLAudioEngine::shutdown()" << LL_ENDL; - LLAudioEngine::shutdown(); - - LL_INFOS() << "LLAudioEngine_FMODEX::shutdown() closing FMOD Ex" << LL_ENDL; - if ( mSystem ) // speculative fix for MAINT-2657 - { - mSystem->close(); - mSystem->release(); - } - LL_INFOS() << "LLAudioEngine_FMODEX::shutdown() done closing FMOD Ex" << LL_ENDL; - - 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) - { - memset(mWindDSPDesc, 0, sizeof(*mWindDSPDesc)); //Set everything to zero - strncpy(mWindDSPDesc->name, "Wind Unit", sizeof(mWindDSPDesc->name)); - mWindDSPDesc->channels = 2; - mWindDSPDesc->read = &windCallback; // Assign callback - may be called from arbitrary threads - if (Check_FMOD_Error(mSystem->createDSP(mWindDSPDesc, &mWindDSP), "FMOD::createDSP")) - return false; - - if (mWindGen) - delete mWindGen; - - float frequency = 44100; - mWindDSP->getDefaults(&frequency,0,0,0); - mWindGen = new LLWindGen<MIXBUFFERFORMAT>((U32)frequency); - mWindDSP->setUserData((void*)mWindGen); - } - - // *TODO: Should this guard against multiple plays? - 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() -{ - 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(); - - // 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() << "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(FMOD_CHANNEL_FREE, soundp, true, &mChannelp); - Check_FMOD_Error(result, "FMOD::System::playSound"); - } - - //LL_INFOS() << "Setting up channel " << std::hex << mChannelID << std::dec << LL_ENDL; - } - - // If we have a source for the channel, we need to update its gain. - if (mCurrentSourcep) - { - // SJB: warnings can spam and hurt framerate, disabling - //FMOD_RESULT result; - - mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain()); - //Check_FMOD_Error(result, "FMOD::Channel::setVolume"); - - mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF); - /*if(Check_FMOD_Error(result, "FMOD::Channel::setMode")) - { - S32 index; - mChannelp->getIndex(&index); - LL_WARNS() << "Channel " << index << "Source ID: " << mCurrentSourcep->getID() - << " at " << mCurrentSourcep->getPositionGlobal() << LL_ENDL; - }*/ - } - - 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; - } - - 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; - } - - // - // 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; - mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES); - - if (cur_pos < (U32)mLastSamplePos) - { - mLoopedThisFrame = true; - } - mLastSamplePos = cur_pos; -} - - -void LLAudioChannelFMODEX::cleanup() -{ - if (!mChannelp) - { - //LL_INFOS() << "Aborting cleanup with no channel handle." << LL_ENDL; - return; - } - - //LL_INFOS() << "Cleaning up channel: " << mChannelID << LL_ENDL; - Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop"); - - mCurrentBufferp = NULL; - mChannelp = NULL; -} - - -void LLAudioChannelFMODEX::play() -{ - if (!mChannelp) - { - LL_WARNS() << "Playing without a channel handle, aborting" << LL_ENDL; - return; - } - - Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::pause"); - - getSource()->setPlayedOnce(true); - - if(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]) - mChannelp->setChannelGroup(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]); -} - - -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; - } - - 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; - } - - bool paused, playing; - mChannelp->getPaused(&paused); - mChannelp->isPlaying(&playing); - return !paused && playing; -} - - -// -// LLAudioChannelFMODEX implementation -// - - -LLAudioBufferFMODEX::LLAudioBufferFMODEX(FMOD::System *system) : mSystemp(system), mSoundp(NULL) -{ -} - - -LLAudioBufferFMODEX::~LLAudioBufferFMODEX() -{ - if(mSoundp) - { - mSoundp->release(); - 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, NULL, LL_APR_RPB)) - { - // File not found, abort. - return false; - } - - if (mSoundp) - { - // If there's already something loaded in this buffer, clean it up. - mSoundp->release(); - 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() << "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; - } - - // Everything went well, return true - return true; -} - - -U32 LLAudioBufferFMODEX::getLength() -{ - if (!mSoundp) - { - return 0; - } - - U32 length; - mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES); - return length; -} - - -void LLAudioChannelFMODEX::set3DMode(bool use3d) -{ - FMOD_MODE current_mode; - if(mChannelp->getMode(¤t_mode) != FMOD_OK) - 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) - { - mChannelp->setMode(new_mode); - } -} - -// *NOTE: This is almost certainly being called on the mixer thread, -// not the main thread. May have implications for callees or audio -// engine shutdown. - -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<LLAudioEngine_FMODEX::MIXBUFFERFORMAT> *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_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp new file mode 100644 index 0000000000..70b3a08473 --- /dev/null +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -0,0 +1,753 @@ +/** + * @file audioengine_fmodstudio.cpp + * @brief Implementation of LLAudioEngine class abstracting the audio + * support as a FMODSTUDIO implementation + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2020, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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_fmodstudio.h" + +#include "llaudioengine_fmodstudio.h" +#include "lllistener_fmodstudio.h" + +#include "llerror.h" +#include "llmath.h" +#include "llrand.h" + +#include "fmodstudio/fmod.hpp" +#include "fmodstudio/fmod_errors.h" +#include "lldir.h" +#include "llapr.h" + +#include "sound_ids.h" + +FMOD_RESULT F_CALLBACK windCallback(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}; + +LLAudioEngine_FMODSTUDIO::LLAudioEngine_FMODSTUDIO(bool enable_profiler) +: mInited(false), + mWindGen(NULL), + mWindDSP(NULL), + mSystem(NULL), + mEnableProfiler(enable_profiler), + mWindDSPDesc(NULL) +{ +} + + +LLAudioEngine_FMODSTUDIO::~LLAudioEngine_FMODSTUDIO() +{ + // mWindDSPDesc, mWindGen and mWindDSP get cleaned up on cleanupWind in LLAudioEngine::shutdown() + // mSystem gets cleaned up at shutdown() +} + + +static inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) +{ + if (result == FMOD_OK) + return false; + LL_DEBUGS("FMOD") << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + return true; +} + +bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, const std::string &app_title) +{ + U32 version; + 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, app_title); + + result = mSystem->getVersion(&version); + Check_FMOD_Error(result, "FMOD::System::getVersion"); + + if (version < FMOD_VERSION) + { + LL_WARNS("AppInit") << "FMOD Studio version mismatch, actual: " << version + << " expected:" << 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"); + + FMOD_ADVANCEDSETTINGS settings; + memset(&settings, 0, sizeof(settings)); + settings.cbSize = sizeof(FMOD_ADVANCEDSETTINGS); + settings.resamplerMethod = FMOD_DSP_RESAMPLER_LINEAR; + + result = mSystem->setAdvancedSettings(&settings); + Check_FMOD_Error(result, "FMOD::System::setAdvancedSettings"); + + // FMOD_INIT_THREAD_UNSAFE Disables thread safety for API calls. + // Only use this if FMOD is being called from a single thread, and if Studio API is not being used. + 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) + { + const char* env_string = getenv("LL_BAD_FMOD_PULSEAUDIO"); + if (NULL == env_string) + { + 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, const_cast<char*>(app_title.c_str()))) == 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) + { + const char* env_string = getenv("LL_BAD_FMOD_ALSA"); + if (NULL == env_string) + { + 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) + { + 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; + default: + LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break; + }; +#else // LL_LINUX + + // initialize the FMOD engine + // number of channel in this case looks to be identiacal to number of max simultaneously + // playing objects and we can set practically any number + result = mSystem->init(num_channels + 2, fmod_flags, 0); + if (Check_FMOD_Error(result, "Error initializing FMOD Studio with default settins, retrying with other format")) + { + result = mSystem->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 0/*- ignore*/); + if (Check_FMOD_Error(result, "Error setting sotware format. Can't init.")) + { + return false; + } + result = mSystem->init(num_channels + 2, fmod_flags, 0); + } + if (Check_FMOD_Error(result, "Error initializing FMOD Studio")) + { + // If it fails here and (result == FMOD_ERR_OUTPUT_CREATEBUFFER), + // we can retry with other settings + 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_FMODSTUDIO(mSystem)); + + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() FMOD Studio initialized correctly" << LL_ENDL; + + int r_numbuffers, r_samplerate, r_channels; + unsigned int r_bufferlength; + char r_name[512]; + int latency = 100; + mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers); + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_bufferlength=" << r_bufferlength << " bytes" << LL_ENDL; + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_numbuffers=" << r_numbuffers << LL_ENDL; + + mSystem->getDriverInfo(0, r_name, 511, NULL, &r_samplerate, NULL, &r_channels); + r_name[511] = '\0'; + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_name=\"" << r_name << "\"" << LL_ENDL; + + if (r_samplerate != 0) + latency = (int)(1000.0f * r_bufferlength * r_numbuffers / r_samplerate); + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): latency=" << latency << "ms" << LL_ENDL; + + mInited = true; + + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): initialization complete." << LL_ENDL; + + 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("FMOD") << "Listener creation failed" << LL_ENDL; + } +} + + +void LLAudioEngine_FMODSTUDIO::shutdown() +{ + stopInternetStream(); + + LL_INFOS("FMOD") << "About to LLAudioEngine::shutdown()" << LL_ENDL; + LLAudioEngine::shutdown(); + + LL_INFOS("FMOD") << "LLAudioEngine_FMODSTUDIO::shutdown() closing FMOD Studio" << LL_ENDL; + if (mSystem) + { + mSystem->close(); + mSystem->release(); + } + LL_INFOS("FMOD") << "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; + + if (!mWindDSPDesc) + { + mWindDSPDesc = new FMOD_DSP_DESCRIPTION(); + } + + if (!mWindDSP) + { + memset(mWindDSPDesc, 0, sizeof(*mWindDSPDesc)); //Set everything to zero + strncpy(mWindDSPDesc->name, "Wind Unit", sizeof(mWindDSPDesc->name)); + mWindDSPDesc->pluginsdkversion = FMOD_PLUGIN_SDK_VERSION; + mWindDSPDesc->read = &windCallback; // Assign callback - may be called from arbitrary threads + if (Check_FMOD_Error(mSystem->createDSP(mWindDSPDesc, &mWindDSP), "FMOD::createDSP")) + return false; + + if (mWindGen) + delete mWindGen; + + int frequency = 44100; + + FMOD_SPEAKERMODE mode; + if (Check_FMOD_Error(mSystem->getSoftwareFormat(&frequency, &mode, nullptr), "FMOD::System::getSoftwareFormat")) + { + cleanupWind(); + return false; + } + + mWindGen = new LLWindGen<MIXBUFFERFORMAT>((U32)frequency); + + if (Check_FMOD_Error(mWindDSP->setUserData((void*)mWindGen), "FMOD::DSP::setUserData")) + { + cleanupWind(); + return false; + } + if (Check_FMOD_Error(mWindDSP->setChannelFormat(FMOD_CHANNELMASK_STEREO, 2, mode), "FMOD::DSP::setChannelFormat")) + { + cleanupWind(); + return false; + } + } + + // *TODO: Should this guard against multiple plays? + if (Check_FMOD_Error(mSystem->playDSP(mWindDSP, nullptr, false, nullptr), "FMOD::System::playDSP")) + { + cleanupWind(); + return false; + } + return true; +} + + +void LLAudioEngine_FMODSTUDIO::cleanupWind() +{ + if (mWindDSP) + { + FMOD::ChannelGroup* master_group = NULL; + if (!Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup") + && master_group) + { + master_group->removeDSP(mWindDSP); + } + mWindDSP->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 = NULL; + if (!Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::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()); + } +} + +// +// LLAudioChannelFMODSTUDIO implementation +// + +LLAudioChannelFMODSTUDIO::LLAudioChannelFMODSTUDIO(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0) +{ +} + + +LLAudioChannelFMODSTUDIO::~LLAudioChannelFMODSTUDIO() +{ + cleanup(); +} + +bool LLAudioChannelFMODSTUDIO::updateBuffer() +{ + if (!mCurrentSourcep) + { + // This channel isn't associated with any source, nothing + // to be updated + return false; + } + + if (LLAudioChannel::updateBuffer()) + { + // Base class update returned true, which means that we need to actually + // set up the channel for a different buffer. + + LLAudioBufferFMODSTUDIO *bufferp = (LLAudioBufferFMODSTUDIO *)mCurrentSourcep->getCurrentBuffer(); + + // 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() << "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 /*free channel?*/, true, &mChannelp); + Check_FMOD_Error(result, "FMOD::System::playSound"); + } + + // Setting up channel mChannelID + } + + // If we have a source for the channel, we need to update its gain. + if (mCurrentSourcep) + { + // SJB: warnings can spam and hurt framerate, disabling + //FMOD_RESULT result; + + mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain()); + //Check_FMOD_Error(result, "FMOD::Channel::setVolume"); + + mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF); + /*if(Check_FMOD_Error(result, "FMOD::Channel::setMode")) + { + S32 index; + mChannelp->getIndex(&index); + LL_WARNS() << "Channel " << index << "Source ID: " << mCurrentSourcep->getID() + << " at " << mCurrentSourcep->getPositionGlobal() << LL_ENDL; + }*/ + } + + 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; + } + + 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; + } + + // + // 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; + mChannelp->getPosition(&cur_pos, FMOD_TIMEUNIT_PCMBYTES); + + if (cur_pos < (U32)mLastSamplePos) + { + mLoopedThisFrame = true; + } + mLastSamplePos = cur_pos; +} + + +void LLAudioChannelFMODSTUDIO::cleanup() +{ + if (!mChannelp) + { + // Aborting cleanup with no channel handle. + return; + } + + //Cleaning up channel mChannelID + Check_FMOD_Error(mChannelp->stop(), "FMOD::Channel::stop"); + + mCurrentBufferp = NULL; + mChannelp = NULL; +} + + +void LLAudioChannelFMODSTUDIO::play() +{ + if (!mChannelp) + { + LL_WARNS() << "Playing without a channel handle, aborting" << LL_ENDL; + return; + } + + Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::pause"); + + getSource()->setPlayedOnce(true); + + if (LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]) + mChannelp->setChannelGroup(LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]); +} + + +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; + } + + 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 LLAudioChannelFMODSTUDIO::isPlaying() +{ + if (!mChannelp) + { + return false; + } + + bool paused, playing; + mChannelp->getPaused(&paused); + mChannelp->isPlaying(&playing); + return !paused && playing; +} + + +// +// LLAudioChannelFMODSTUDIO implementation +// + + +LLAudioBufferFMODSTUDIO::LLAudioBufferFMODSTUDIO(FMOD::System *system) : mSystemp(system), mSoundp(NULL) +{ +} + + +LLAudioBufferFMODSTUDIO::~LLAudioBufferFMODSTUDIO() +{ + if (mSoundp) + { + mSoundp->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 (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) + { + // File not found, abort. + return false; + } + + if (mSoundp) + { + // If there's already something loaded in this buffer, clean it up. + mSoundp->release(); + mSoundp = NULL; + } + + FMOD_MODE base_mode = FMOD_LOOP_NORMAL; + 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 (since 1.05 fmod studio expects everything in UTF-8) + 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() << "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; + } + + // Everything went well, return true + return true; +} + + +U32 LLAudioBufferFMODSTUDIO::getLength() +{ + if (!mSoundp) + { + return 0; + } + + U32 length; + mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES); + return length; +} + + +void LLAudioChannelFMODSTUDIO::set3DMode(bool use3d) +{ + FMOD_MODE current_mode; + if (mChannelp->getMode(¤t_mode) != FMOD_OK) + 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) + { + mChannelp->setMode(new_mode); + } +} + +// *NOTE: This is almost certainly being called on the mixer thread, +// not the main thread. May have implications for callees or audio +// engine shutdown. + +FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels) +{ + // inbuffer = fmod's original mixbuffer. + // outbuffer = the buffer passed from the previous DSP unit. + // length = length in samples at this mix time. + + LLWindGen<LLAudioEngine_FMODSTUDIO::MIXBUFFERFORMAT> *windgen = NULL; + 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_fmodex.h b/indra/llaudio/llaudioengine_fmodstudio.h index ca389d489f..f2361df1b6 100644 --- a/indra/llaudio/llaudioengine_fmodex.h +++ b/indra/llaudio/llaudioengine_fmodstudio.h @@ -1,11 +1,11 @@ /** - * @file audioengine_fmodex.h + * @file audioengine_fmodstudio.h * @brief Definition of LLAudioEngine class abstracting the audio - * support as a FMODEX implementation + * support as a FMODSTUDIO implementation * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2014, Linden Research, Inc. + * Copyright (C) 2020, Linden 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,14 +25,14 @@ * $/LicenseInfo$ */ -#ifndef LL_AUDIOENGINE_FMODEX_H -#define LL_AUDIOENGINE_FMODEX_H +#ifndef LL_AUDIOENGINE_FMODSTUDIO_H +#define LL_AUDIOENGINE_FMODSTUDIO_H #include "llaudioengine.h" #include "llwindgen.h" //Stubs -class LLAudioStreamManagerFMODEX; +class LLAudioStreamManagerFMODSTUDIO; namespace FMOD { class System; @@ -44,14 +44,14 @@ namespace FMOD typedef struct FMOD_DSP_DESCRIPTION FMOD_DSP_DESCRIPTION; //Interfaces -class LLAudioEngine_FMODEX : public LLAudioEngine +class LLAudioEngine_FMODSTUDIO : public LLAudioEngine { public: - LLAudioEngine_FMODEX(bool enable_profiler); - virtual ~LLAudioEngine_FMODEX(); + LLAudioEngine_FMODSTUDIO(bool enable_profiler); + virtual ~LLAudioEngine_FMODSTUDIO(); // initialization/startup/shutdown - virtual bool init(const S32 num_channels, void *user_data); + virtual bool init(const S32 num_channels, void *user_data, const std::string &app_title); virtual std::string getDriverName(bool verbose); virtual void allocateListener(); @@ -85,11 +85,11 @@ public: }; -class LLAudioChannelFMODEX : public LLAudioChannel +class LLAudioChannelFMODSTUDIO : public LLAudioChannel { public: - LLAudioChannelFMODEX(FMOD::System *audioengine); - virtual ~LLAudioChannelFMODEX(); + LLAudioChannelFMODSTUDIO(FMOD::System *audioengine); + virtual ~LLAudioChannelFMODSTUDIO(); protected: /*virtual*/ void play(); @@ -110,15 +110,15 @@ protected: }; -class LLAudioBufferFMODEX : public LLAudioBuffer +class LLAudioBufferFMODSTUDIO : public LLAudioBuffer { public: - LLAudioBufferFMODEX(FMOD::System *audioengine); - virtual ~LLAudioBufferFMODEX(); + LLAudioBufferFMODSTUDIO(FMOD::System *audioengine); + virtual ~LLAudioBufferFMODSTUDIO(); /*virtual*/ bool loadWAV(const std::string& filename); /*virtual*/ U32 getLength(); - friend class LLAudioChannelFMODEX; + friend class LLAudioChannelFMODSTUDIO; protected: FMOD::System *getSystem() const {return mSystemp;} FMOD::System *mSystemp; @@ -127,4 +127,4 @@ protected: }; -#endif // LL_AUDIOENGINE_FMODEX_H +#endif // LL_AUDIOENGINE_FMODSTUDIO_H diff --git a/indra/llaudio/llaudioengine_openal.cpp b/indra/llaudio/llaudioengine_openal.cpp index e6ac586618..3bdd0302ee 100644 --- a/indra/llaudio/llaudioengine_openal.cpp +++ b/indra/llaudio/llaudioengine_openal.cpp @@ -52,10 +52,10 @@ LLAudioEngine_OpenAL::~LLAudioEngine_OpenAL() } // virtual -bool LLAudioEngine_OpenAL::init(const S32 num_channels, void* userdata) +bool LLAudioEngine_OpenAL::init(const S32 num_channels, void* userdata, const std::string &app_title) { mWindGen = NULL; - LLAudioEngine::init(num_channels, userdata); + LLAudioEngine::init(num_channels, userdata, app_title); if(!alutInit(NULL, NULL)) { @@ -239,6 +239,13 @@ bool LLAudioChannelOpenAL::isPlaying() bool LLAudioChannelOpenAL::updateBuffer() { + if (!mCurrentSourcep) + { + // This channel isn't associated with any source, nothing + // to be updated + return false; + } + if (LLAudioChannel::updateBuffer()) { // Base class update returned true, which means that we need to actually diff --git a/indra/llaudio/llaudioengine_openal.h b/indra/llaudio/llaudioengine_openal.h index 6639d9dfe6..366f9259e3 100644 --- a/indra/llaudio/llaudioengine_openal.h +++ b/indra/llaudio/llaudioengine_openal.h @@ -40,8 +40,8 @@ class LLAudioEngine_OpenAL : public LLAudioEngine LLAudioEngine_OpenAL(); virtual ~LLAudioEngine_OpenAL(); - virtual bool init(const S32 num_channels, void *user_data); - virtual std::string getDriverName(bool verbose); + virtual bool init(const S32 num_channels, void *user_data, const std::string &app_title); + virtual std::string getDriverName(bool verbose); virtual void allocateListener(); virtual void shutdown(); diff --git a/indra/llaudio/lllistener_fmodex.cpp b/indra/llaudio/lllistener_fmodex.cpp deleted file mode 100644 index 31ab47a635..0000000000 --- a/indra/llaudio/lllistener_fmodex.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/** - * @file listener_fmodex.cpp - * @brief Implementation of LISTENER class abstracting the audio - * support as a FMODEX 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 "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() -{ - if(!mSystem) - { - return; - } - - 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_fmodstudio.cpp b/indra/llaudio/lllistener_fmodstudio.cpp new file mode 100644 index 0000000000..abd5e345b5 --- /dev/null +++ b/indra/llaudio/lllistener_fmodstudio.cpp @@ -0,0 +1,136 @@ +/** + * @file listener_fmodstudio.cpp + * @brief Implementation of LISTENER class abstracting the audio + * support as a FMODSTUDIO implementation + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2020, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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_fmodstudio.h" +#include "fmodstudio/fmod.hpp" + +//----------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------- +LLListener_FMODSTUDIO::LLListener_FMODSTUDIO(FMOD::System *system) +{ + mSystem = system; + init(); +} + +//----------------------------------------------------------------------- +LLListener_FMODSTUDIO::~LLListener_FMODSTUDIO() +{ +} + +//----------------------------------------------------------------------- +void LLListener_FMODSTUDIO::init(void) +{ + // do inherited + LLListener::init(); + mDopplerFactor = 1.0f; + mRolloffFactor = 1.0f; +} + +//----------------------------------------------------------------------- +void LLListener_FMODSTUDIO::translate(LLVector3 offset) +{ + LLListener::translate(offset); + + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); +} + +//----------------------------------------------------------------------- +void LLListener_FMODSTUDIO::setPosition(LLVector3 pos) +{ + LLListener::setPosition(pos); + + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); +} + +//----------------------------------------------------------------------- +void LLListener_FMODSTUDIO::setVelocity(LLVector3 vel) +{ + LLListener::setVelocity(vel); + + mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); +} + +//----------------------------------------------------------------------- +void LLListener_FMODSTUDIO::orient(LLVector3 up, LLVector3 at) +{ + LLListener::orient(up, at); + + // at = -at; by default Fmod studio is 'left-handed' but we are providing + // flag FMOD_INIT_3D_RIGHTHANDED so no correction are needed + + 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 optimization skips 3D updates if there have not been changes to the 3D sound environment. + // (this was true for FMODex, looks to be still true for FMOD STUDIO, but needs a recheck) + //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, which makes it not skip 3D processing next update call. + if (mRolloffFactor != factor) + { + LLVector3 pos = mPosition - LLVector3(0.f, 0.f, .1f); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)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_fmodex.h b/indra/llaudio/lllistener_fmodstudio.h index 073b65d53a..6ad85d9700 100644 --- a/indra/llaudio/lllistener_fmodex.h +++ b/indra/llaudio/lllistener_fmodstudio.h @@ -1,11 +1,11 @@ /** - * @file listener_fmodex.h + * @file listener_fmodstudio.h * @brief Description of LISTENER class abstracting the audio support - * as an FMOD 3D implementation (windows and Linux) + * as an FMOD 3D implementation * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2020, Linden 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,8 +25,8 @@ * $/LicenseInfo$ */ -#ifndef LL_LISTENER_FMODEX_H -#define LL_LISTENER_FMODEX_H +#ifndef LL_LISTENER_FMODSTUDIO_H +#define LL_LISTENER_FMODSTUDIO_H #include "lllistener.h" @@ -37,27 +37,27 @@ namespace FMOD } //Interfaces -class LLListener_FMODEX : public LLListener +class LLListener_FMODSTUDIO : public LLListener { - public: - LLListener_FMODEX(FMOD::System *system); - virtual ~LLListener_FMODEX(); - virtual void init(); +public: + LLListener_FMODSTUDIO(FMOD::System *system); + virtual ~LLListener_FMODSTUDIO(); + 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 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; + 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/llstreamingaudio_fmodex.cpp b/indra/llaudio/llstreamingaudio_fmodex.cpp deleted file mode 100644 index 9c9e85c00c..0000000000 --- a/indra/llaudio/llstreamingaudio_fmodex.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/** - * @file streamingaudio_fmodex.cpp - * @brief LLStreamingAudio_FMODEX 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 "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) -{ - // 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) - //{ - // 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()) - { - LL_INFOS() << "Starting internet stream: " << url << LL_ENDL; - mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,url); - mURL = url; - } - else - { - LL_INFOS() << "Set internet stream to null" << LL_ENDL; - mURL.clear(); - } -} - - -void LLStreamingAudio_FMODEX::update() -{ - // Kill dead internet streams, if possible - std::list<LLAudioStreamManagerFMODEX *>::iterator iter; - for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) - { - LLAudioStreamManagerFMODEX *streamp = *iter; - if (streamp->stopStream()) - { - LL_INFOS() << "Closed dead stream" << LL_ENDL; - delete streamp; - mDeadStreams.erase(iter++); - } - else - { - iter++; - } - } - - // 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) - { - 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) - { - for(S32 i = 0; i < tagcount; ++i) - { - if(sound->getTag(NULL, i, &tag)!=FMOD_OK) - continue; - - if (tag.type == FMOD_TAGTYPE_FMOD) - { - if (!strcmp(tag.name, "Sample Rate Change")) - { - LL_INFOS() << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL; - mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)); - } - continue; - } - } - } - - if(starving) - { - bool paused = false; - mFMODInternetStreamChannelp->getPaused(&paused); - if(!paused) - { - LL_INFOS() << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL; - LL_INFOS() << " (diskbusy="<<diskbusy<<")" << LL_ENDL; - LL_INFOS() << " (progress="<<progress<<")" << LL_ENDL; - mFMODInternetStreamChannelp->setPaused(true); - } - } - else if(progress > 80) - { - mFMODInternetStreamChannelp->setPaused(false); - } - } - } -} - -void LLStreamingAudio_FMODEX::stop() -{ - if (mFMODInternetStreamChannelp) - { - mFMODInternetStreamChannelp->setPaused(true); - mFMODInternetStreamChannelp->setPriority(0); - 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; - //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()) - { - 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); - } -} - -/////////////////////////////////////////////////////// -// 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_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 *LLAudioStreamManagerFMODEX::startStream() -{ - // We need a live and opened stream before we try and play it. - if (!mInternetStream || getOpenState() != 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. - - 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; - default: - close = true; - } - - if (close) - { - mInternetStream->release(); - 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 2787840ba1..0000000000 --- a/indra/llaudio/llstreamingaudio_fmodex.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file streamingaudio_fmodex.h - * @brief Definition of LLStreamingAudio_FMODEX 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_STREAMINGAUDIO_FMODEX_H -#define LL_STREAMINGAUDIO_FMODEX_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(S32 pause); - /*virtual*/ void update(); - /*virtual*/ S32 isPlaying(); - /*virtual*/ void setGain(F32 vol); - /*virtual*/ F32 getGain(); - /*virtual*/ std::string getURL(); - - /*virtual*/ bool supportsAdjustableBufferSizes(){return true;} - /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime); -private: - FMOD::System *mSystem; - - LLAudioStreamManagerFMODEX *mCurrentInternetStreamp; - FMOD::Channel *mFMODInternetStreamChannelp; - std::list<LLAudioStreamManagerFMODEX *> mDeadStreams; - - std::string mURL; - F32 mGain; -}; - - -#endif // LL_STREAMINGAUDIO_FMODEX_H diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.cpp b/indra/llaudio/llstreamingaudio_fmodstudio.cpp new file mode 100644 index 0000000000..08d19209aa --- /dev/null +++ b/indra/llaudio/llstreamingaudio_fmodstudio.cpp @@ -0,0 +1,392 @@ +/** + * @file streamingaudio_fmodstudio.cpp + * @brief LLStreamingAudio_FMODSTUDIO implementation + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2020, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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 "fmodstudio/fmod.hpp" +#include "fmodstudio/fmod_errors.h" + +#include "llstreamingaudio_fmodstudio.h" + + +class LLAudioStreamManagerFMODSTUDIO +{ +public: + LLAudioStreamManagerFMODSTUDIO(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_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) : +mSystem(system), +mCurrentInternetStreamp(NULL), +mFMODInternetStreamChannelp(NULL), +mGain(1.0f) +{ + // 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_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO() +{ + // nothing interesting/safe to do. +} + + +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()) + { + LL_INFOS() << "Starting internet stream: " << url << LL_ENDL; + mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, url); + mURL = url; + } + else + { + LL_INFOS() << "Set internet stream to null" << LL_ENDL; + mURL.clear(); + } +} + + +void LLStreamingAudio_FMODSTUDIO::update() +{ + // Kill dead internet streams, if possible + std::list<LLAudioStreamManagerFMODSTUDIO *>::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++; + } + } + + // 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) + { + 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) + { + for (S32 i = 0; i < tagcount; ++i) + { + if (sound->getTag(NULL, i, &tag) != FMOD_OK) + continue; + + if (tag.type == FMOD_TAGTYPE_FMOD) + { + if (!strcmp(tag.name, "Sample Rate Change")) + { + LL_INFOS() << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL; + mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)); + } + continue; + } + } + } + + if (starving) + { + bool paused = false; + mFMODInternetStreamChannelp->getPaused(&paused); + if (!paused) + { + LL_INFOS() << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL; + LL_INFOS() << " (diskbusy=" << diskbusy << ")" << LL_ENDL; + LL_INFOS() << " (progress=" << progress << ")" << LL_ENDL; + mFMODInternetStreamChannelp->setPaused(true); + } + } + else if (progress > 80) + { + mFMODInternetStreamChannelp->setPaused(false); + } + } + } +} + +void LLStreamingAudio_FMODSTUDIO::stop() +{ + if (mFMODInternetStreamChannelp) + { + mFMODInternetStreamChannelp->setPaused(true); + mFMODInternetStreamChannelp->setPriority(0); + 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; + //mURL.clear(); + } +} + +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()) + { + 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? + + mFMODInternetStreamChannelp->setVolume(vol); + } +} + +/////////////////////////////////////////////////////// +// manager of possibly-multiple internet audio streams + +LLAudioStreamManagerFMODSTUDIO::LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, const std::string& url) : +mSystem(system), +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. + if (!mInternetStream || getOpenState() != 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. + + mSystem->playSound(mInternetStream, NULL, true, &mStreamChannel); + return mStreamChannel; +} + +bool LLAudioStreamManagerFMODSTUDIO::stopStream() +{ + if (mInternetStream) + { + + + bool close = true; + switch (getOpenState()) + { + case FMOD_OPENSTATE_CONNECTING: + close = false; + break; + default: + close = true; + } + + if (close) + { + mInternetStream->release(); + mStreamChannel = NULL; + mInternetStream = NULL; + return true; + } + else + { + return false; + } + } + else + { + return true; + } +} + +FMOD_OPENSTATE LLAudioStreamManagerFMODSTUDIO::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy) +{ + FMOD_OPENSTATE state; + mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy); + return state; +} + +void LLStreamingAudio_FMODSTUDIO::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_fmodstudio.h b/indra/llaudio/llstreamingaudio_fmodstudio.h new file mode 100644 index 0000000000..1fc3c54d79 --- /dev/null +++ b/indra/llaudio/llstreamingaudio_fmodstudio.h @@ -0,0 +1,73 @@ +/** + * @file streamingaudio_fmodstudio.h + * @brief Definition of LLStreamingAudio_FMODSTUDIO implementation + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2020, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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_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; +} + +//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(S32 pause); + /*virtual*/ void update(); + /*virtual*/ S32 isPlaying(); + /*virtual*/ void setGain(F32 vol); + /*virtual*/ F32 getGain(); + /*virtual*/ std::string getURL(); + + /*virtual*/ bool supportsAdjustableBufferSizes(){return true;} + /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime); +private: + FMOD::System *mSystem; + + LLAudioStreamManagerFMODSTUDIO *mCurrentInternetStreamp; + FMOD::Channel *mFMODInternetStreamChannelp; + std::list<LLAudioStreamManagerFMODSTUDIO *> mDeadStreams; + + std::string mURL; + F32 mGain; +}; + + +#endif // LL_STREAMINGAUDIO_FMODSTUDIO_H diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index 4df975ecc5..b764ef0c7e 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -252,7 +252,7 @@ void LLCharacter::dumpCharacter( LLJoint* joint ) 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(); + for (LLJoint::joints_t::iterator iter = joint->mChildren.begin(); iter != joint->mChildren.end(); ++iter) { LLJoint* child_joint = *iter; diff --git a/indra/llcharacter/llgesture.cpp b/indra/llcharacter/llgesture.cpp index 1549c41e62..37904936d8 100644 --- a/indra/llcharacter/llgesture.cpp +++ b/indra/llcharacter/llgesture.cpp @@ -107,11 +107,11 @@ BOOL LLGesture::trigger(const std::string& trigger_string) // NOT endian-neutral U8 *LLGesture::serialize(U8 *buffer) const { - htonmemcpy(buffer, &mKey, MVT_S8, 1); + htolememcpy(buffer, &mKey, MVT_S8, 1); buffer += sizeof(mKey); - htonmemcpy(buffer, &mMask, MVT_U32, 4); + htolememcpy(buffer, &mMask, MVT_U32, 4); buffer += sizeof(mMask); - htonmemcpy(buffer, mSoundItemID.mData, MVT_LLUUID, 16); + htolememcpy(buffer, mSoundItemID.mData, MVT_LLUUID, 16); buffer += 16; memcpy(buffer, mTrigger.c_str(), mTrigger.length() + 1); /* Flawfinder: ignore */ @@ -134,11 +134,11 @@ U8 *LLGesture::deserialize(U8 *buffer, S32 max_size) return buffer; } - htonmemcpy(&mKey, tmp, MVT_S8, 1); + htolememcpy(&mKey, tmp, MVT_S8, 1); tmp += sizeof(mKey); - htonmemcpy(&mMask, tmp, MVT_U32, 4); + htolememcpy(&mMask, tmp, MVT_U32, 4); tmp += sizeof(mMask); - htonmemcpy(mSoundItemID.mData, tmp, MVT_LLUUID, 16); + htolememcpy(mSoundItemID.mData, tmp, MVT_LLUUID, 16); tmp += 16; mTrigger.assign((char *)tmp); @@ -284,7 +284,7 @@ U8 *LLGestureList::serialize(U8 *buffer) const { // a single S32 serves as the header that tells us how many to read U32 count = mList.size(); - htonmemcpy(buffer, &count, MVT_S32, 4); + htolememcpy(buffer, &count, MVT_S32, 4); buffer += sizeof(count); for (S32 i = 0; i < count; i++) @@ -310,7 +310,7 @@ U8 *LLGestureList::deserialize(U8 *buffer, S32 max_size) return buffer; } - htonmemcpy(&count, tmp, MVT_S32, 4); + htolememcpy(&count, tmp, MVT_S32, 4); if (count > MAX_GESTURES) { diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index e2f512f86e..dee642310e 100644 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -209,7 +209,7 @@ void LLJoint::touch(U32 flags) child_flags |= POSITION_DIRTY; } - for (child_list_t::iterator iter = mChildren.begin(); + for (joints_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { LLJoint* joint = *iter; @@ -251,7 +251,7 @@ LLJoint *LLJoint::findJoint( const std::string &name ) if (name == getName()) return this; - for (child_list_t::iterator iter = mChildren.begin(); + for (joints_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { LLJoint* joint = *iter; @@ -286,7 +286,7 @@ void LLJoint::addChild(LLJoint* joint) //-------------------------------------------------------------------- void LLJoint::removeChild(LLJoint* joint) { - child_list_t::iterator iter = std::find(mChildren.begin(), mChildren.end(), joint); + joints_t::iterator iter = std::find(mChildren.begin(), mChildren.end(), joint); if (iter != mChildren.end()) { mChildren.erase(iter); @@ -303,16 +303,17 @@ void LLJoint::removeChild(LLJoint* joint) //-------------------------------------------------------------------- void LLJoint::removeAllChildren() { - for (child_list_t::iterator iter = mChildren.begin(); - iter != mChildren.end();) + for (LLJoint* joint : mChildren) { - child_list_t::iterator curiter = iter++; - LLJoint* joint = *curiter; - mChildren.erase(curiter); - joint->mXform.setParent(NULL); - joint->mParent = NULL; - joint->touch(); + if (joint) + { + joint->mXform.setParent(NULL); + joint->mParent = NULL; + joint->touch(); + //delete joint; + } } + mChildren.clear(); } @@ -407,7 +408,7 @@ void showJointScaleOverrides( const LLJoint& joint, const std::string& note, con bool LLJoint::aboveJointPosThreshold(const LLVector3& pos) const { LLVector3 diff = pos - getDefaultPosition(); - const F32 max_joint_pos_offset = 0.0001f; // 0.1 mm + const F32 max_joint_pos_offset = LL_JOINT_TRESHOLD_POS_OFFSET; // 0.1 mm return diff.lengthSquared() > max_joint_pos_offset * max_joint_pos_offset; } @@ -510,7 +511,7 @@ void LLJoint::clearAttachmentPosOverrides() // getAllAttachmentPosOverrides() //-------------------------------------------------------------------- void LLJoint::getAllAttachmentPosOverrides(S32& num_pos_overrides, - std::set<LLVector3>& distinct_pos_overrides) + std::set<LLVector3>& distinct_pos_overrides) const { num_pos_overrides = m_attachmentPosOverrides.count(); LLVector3OverrideMap::map_type::const_iterator it = m_attachmentPosOverrides.getMap().begin(); @@ -524,7 +525,7 @@ void LLJoint::getAllAttachmentPosOverrides(S32& num_pos_overrides, // getAllAttachmentScaleOverrides() //-------------------------------------------------------------------- void LLJoint::getAllAttachmentScaleOverrides(S32& num_scale_overrides, - std::set<LLVector3>& distinct_scale_overrides) + std::set<LLVector3>& distinct_scale_overrides) const { num_scale_overrides = m_attachmentScaleOverrides.count(); LLVector3OverrideMap::map_type::const_iterator it = m_attachmentScaleOverrides.getMap().begin(); @@ -985,7 +986,7 @@ void LLJoint::updateWorldMatrixChildren() { updateWorldMatrix(); } - for (child_list_t::iterator iter = mChildren.begin(); + for (joints_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { LLJoint* joint = *iter; @@ -1031,7 +1032,7 @@ void LLJoint::clampRotation(LLQuaternion old_rot, LLQuaternion new_rot) { LLVector3 main_axis(1.f, 0.f, 0.f); - for (child_list_t::iterator iter = mChildren.begin(); + for (joints_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { LLJoint* joint = *iter; diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index 8112d246f2..1b646b641f 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -53,6 +53,8 @@ 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; +const F32 LL_JOINT_TRESHOLD_POS_OFFSET = 0.0001f; //0.1 mm + class LLVector3OverrideMap { public: @@ -139,8 +141,8 @@ public: S32 mJointNum; // child joints - typedef std::list<LLJoint*> child_list_t; - child_list_t mChildren; + typedef std::vector<LLJoint*> joints_t; + joints_t mChildren; // debug statics static S32 sNumTouches; @@ -287,9 +289,9 @@ public: void showAttachmentScaleOverrides(const std::string& av_info) const; void getAllAttachmentPosOverrides(S32& num_pos_overrides, - std::set<LLVector3>& distinct_pos_overrides); + std::set<LLVector3>& distinct_pos_overrides) const; void getAllAttachmentScaleOverrides(S32& num_scale_overrides, - std::set<LLVector3>& distinct_scale_overrides); + std::set<LLVector3>& distinct_scale_overrides) const; // These are used in checks of whether a pos/scale override is considered significant. bool aboveJointPosThreshold(const LLVector3& pos) const; diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index 5d323ed5d6..cde38c8091 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -2321,7 +2321,7 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs, LLCharacter* character = *char_iter; // look for an existing instance of this motion - LLKeyframeMotion* motionp = dynamic_cast<LLKeyframeMotion*> (character->findMotion(asset_uuid)); + LLKeyframeMotion* motionp = static_cast<LLKeyframeMotion*> (character->findMotion(asset_uuid)); if (motionp) { if (0 == status) diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index ba87d93fec..89eefd8ce1 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -1,4 +1,3 @@ - # -*- cmake -*- project(llcommon) @@ -6,11 +5,11 @@ project(llcommon) include(00-Common) include(ICU4C) include(LLCommon) +include(bugsplat) include(Linking) include(Boost) include(LLSharedLibs) include(JsonCpp) -include(GoogleBreakpad) include(Copy3rdPartyLibs) include(ZLIB) include(URIPARSER) @@ -20,7 +19,6 @@ include_directories( ${LLCOMMON_INCLUDE_DIRS} ${JSONCPP_INCLUDE_DIR} ${ZLIB_INCLUDE_DIRS} - ${BREAKPAD_INCLUDE_DIRECTORIES} ${URIPARSER_INCLUDE_DIRS} ) @@ -45,7 +43,6 @@ set(llcommon_SOURCE_FILES llcleanup.cpp llcommon.cpp llcommonutils.cpp - llcoro_get_id.cpp llcoros.cpp llcrc.cpp llcriticaldamp.cpp @@ -74,6 +71,7 @@ set(llcommon_SOURCE_FILES llinitparam.cpp llinitdestroyclass.cpp llinstancetracker.cpp + llkeybind.cpp llleap.cpp llleaplistener.cpp llliveappconfig.cpp @@ -107,6 +105,7 @@ set(llcommon_SOURCE_FILES llstring.cpp llstringtable.cpp llsys.cpp + lltempredirect.cpp llthread.cpp llthreadlocalstorage.cpp llthreadsafequeue.cpp @@ -147,7 +146,7 @@ set(llcommon_HEADER_FILES llcleanup.h llcommon.h llcommonutils.h - llcoro_get_id.h + llcond.h llcoros.h llcrc.h llcriticaldamp.h @@ -184,12 +183,13 @@ set(llcommon_HEADER_FILES llinitdestroyclass.h llinitparam.h llinstancetracker.h + llkeybind.h llkeythrottle.h llleap.h llleaplistener.h - lllistenerwrapper.h llliveappconfig.h lllivefile.h + llmainthreadtask.h llmd5.h llmemory.h llmemorystream.h @@ -231,6 +231,7 @@ set(llcommon_HEADER_FILES llstaticstringtable.h llstatsaccumulator.h llsys.h + lltempredirect.h llthread.h llthreadlocalstorage.h llthreadsafequeue.h @@ -248,6 +249,7 @@ set(llcommon_HEADER_FILES llwin32headers.h llwin32headerslean.h llworkerthread.h + lockstatic.h stdtypes.h stringize.h timer.h @@ -258,10 +260,10 @@ set(llcommon_HEADER_FILES set_source_files_properties(${llcommon_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) -if (BUGSPLAT_DB) - set_source_files_properties(llapp.cpp - PROPERTIES COMPILE_DEFINITIONS "LL_BUGSPLAT") -endif (BUGSPLAT_DB) +if (USE_BUGSPLAT) + set_source_files_properties(${llcommon_SOURCE_FILES} + PROPERTIES COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}") +endif (USE_BUGSPLAT) list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES}) @@ -285,7 +287,6 @@ endif(LLCOMMON_LINK_SHARED) target_link_libraries( llcommon - ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES} ${APRUTIL_LIBRARIES} ${APR_LIBRARIES} ${EXPAT_LIBRARIES} @@ -293,7 +294,7 @@ target_link_libraries( ${JSONCPP_LIBRARIES} ${ZLIB_LIBRARIES} ${WINDOWS_LIBRARIES} - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_PROGRAM_OPTIONS_LIBRARY} ${BOOST_REGEX_LIBRARY} @@ -322,13 +323,14 @@ if (LL_TESTS) ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES} ${GOOGLEMOCK_LIBRARIES} - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_THREAD_LIBRARY} ${BOOST_SYSTEM_LIBRARY}) LL_ADD_INTEGRATION_TEST(commonmisc "" "${test_libs}") LL_ADD_INTEGRATION_TEST(bitpack "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llbase64 "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llcond "" "${test_libs}") LL_ADD_INTEGRATION_TEST(lldate "" "${test_libs}") LL_ADD_INTEGRATION_TEST(lldeadmantimer "" "${test_libs}") LL_ADD_INTEGRATION_TEST(lldependencies "" "${test_libs}") @@ -340,6 +342,7 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(llheteromap "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llinstancetracker "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llleap "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llmainthreadtask "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llpounceable "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llprocess "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llprocessor "" "${test_libs}") diff --git a/indra/llcommon/StackWalker.cpp b/indra/llcommon/StackWalker.cpp index c0d3104099..56defc6465 100644 --- a/indra/llcommon/StackWalker.cpp +++ b/indra/llcommon/StackWalker.cpp @@ -98,7 +98,10 @@ // If VC7 and later, then use the shipped 'dbghelp.h'-file #pragma pack(push,8) #if _MSC_VER >= 1300 +#pragma warning (push) +#pragma warning (disable:4091) // a microsoft header has warnings. Very nice. #include <dbghelp.h> +#pragma warning (pop) #else // inline the important dbghelp.h-declarations... typedef enum { @@ -422,7 +425,7 @@ public: LPSTR m_szSymPath; #pragma pack(push,8) -typedef struct IMAGEHLP_MODULE64_V3 { +struct IMAGEHLP_MODULE64_V3 { DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) DWORD64 BaseOfImage; // base load address of module DWORD ImageSize; // virtual size of the loaded module @@ -450,7 +453,7 @@ typedef struct IMAGEHLP_MODULE64_V3 { BOOL Publics; // contains public symbols }; -typedef struct IMAGEHLP_MODULE64_V2 { +struct IMAGEHLP_MODULE64_V2 { DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) DWORD64 BaseOfImage; // base load address of module DWORD ImageSize; // virtual size of the loaded module @@ -657,7 +660,7 @@ private: pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" ); if ( (pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL) ) { - // we couldn´t find all functions + // we couldn't find all functions FreeLibrary(hPsapi); return FALSE; } diff --git a/indra/llcommon/StackWalker.h b/indra/llcommon/StackWalker.h index 834f89c471..4634765d0b 100644 --- a/indra/llcommon/StackWalker.h +++ b/indra/llcommon/StackWalker.h @@ -148,7 +148,7 @@ protected: CHAR loadedImageName[STACKWALK_MAX_NAMELEN]; } CallstackEntry; - typedef enum CallstackEntryType {firstEntry, nextEntry, lastEntry}; + enum CallstackEntryType {firstEntry, nextEntry, lastEntry}; virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName); virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion); diff --git a/indra/llcommon/indra_constants.cpp b/indra/llcommon/indra_constants.cpp index e13176e8fa..1b48e4daf3 100644 --- a/indra/llcommon/indra_constants.cpp +++ b/indra/llcommon/indra_constants.cpp @@ -64,7 +64,6 @@ const LLUUID IMG_ALPHA_GRAD ("e97cf410-8e61-7005-ec06-629eba4cd1fb"); // VIEW const LLUUID IMG_ALPHA_GRAD_2D ("38b86f85-2575-52a9-a531-23108d8da837"); // VIEWER const LLUUID IMG_TRANSPARENT ("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"); // VIEWER -const LLUUID IMG_BLOOM1 ("3c59f7fe-9dc8-47f9-8aaf-a9dd1fbc3bef"); // VIEWER const LLUUID TERRAIN_DIRT_DETAIL ("0bc58228-74a0-7e83-89bc-5c23464bcec5"); // VIEWER const LLUUID TERRAIN_GRASS_DETAIL ("63338ede-0037-c4fd-855b-015d77112fc8"); // VIEWER const LLUUID TERRAIN_MOUNTAIN_DETAIL ("303cd381-8560-7579-23f1-f0a880799740"); // VIEWER diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 0fbf4b966b..10b98f49aa 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -54,6 +54,17 @@ enum ETerrainBrushType E_LANDBRUSH_INVALID = 6 }; +enum EMouseClickType{ + CLICK_NONE = -1, + CLICK_LEFT = 0, + CLICK_MIDDLE, + CLICK_RIGHT, + CLICK_BUTTON4, + CLICK_BUTTON5, + CLICK_DOUBLELEFT, + CLICK_COUNT // 'size', CLICK_NONE does not counts +}; + // keys // Bit masks for various keyboard modifier keys. const MASK MASK_NONE = 0x0000; @@ -200,7 +211,6 @@ LL_COMMON_API extern const LLUUID IMG_ALPHA_GRAD; LL_COMMON_API extern const LLUUID IMG_ALPHA_GRAD_2D; LL_COMMON_API extern const LLUUID IMG_TRANSPARENT; -LL_COMMON_API extern const LLUUID IMG_BLOOM1; LL_COMMON_API extern const LLUUID TERRAIN_DIRT_DETAIL; LL_COMMON_API extern const LLUUID TERRAIN_GRASS_DETAIL; LL_COMMON_API extern const LLUUID TERRAIN_MOUNTAIN_DETAIL; diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 421af3006e..df2a066f62 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -46,9 +46,10 @@ #include "llstl.h" // for DeletePointer() #include "llstring.h" #include "lleventtimer.h" -#include "google_breakpad/exception_handler.h" #include "stringize.h" #include "llcleanup.h" +#include "llevents.h" +#include "llsdutil.h" // // Signal handling @@ -60,12 +61,6 @@ LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop); BOOL ConsoleCtrlHandler(DWORD fdwCtrlType); -bool windows_post_minidump_callback(const wchar_t* dump_path, - const wchar_t* minidump_id, - void* context, - EXCEPTION_POINTERS* exinfo, - MDRawAssertionInfo* assertion, - bool succeeded); #else # include <signal.h> # include <unistd.h> // for fork() @@ -144,8 +139,6 @@ void LLApp::commonCtor() // Set the application to this instance. sApplication = this; - - mExceptionHandler = 0; // initialize the buffer to write the minidump filename to // (this is used to avoid allocating memory in the crash handler) @@ -175,10 +168,8 @@ LLApp::~LLApp() delete mThreadErrorp; mThreadErrorp = NULL; } - - if(mExceptionHandler != 0) delete mExceptionHandler; - SUBSYSTEM_CLEANUP(LLCommon); + SUBSYSTEM_CLEANUP_DBG(LLCommon); } // static @@ -392,141 +383,25 @@ void LLApp::setupErrorHandling(bool second_instance) #if LL_WINDOWS -#if LL_SEND_CRASH_REPORTS && ! defined(LL_BUGSPLAT) - EnableCrashingOnCrashes(); - - // 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); - - // Install the Google Breakpad crash handler for Windows - if(mExceptionHandler == 0) - { - if ( second_instance ) //BUG-5707 Firing teleport from a web browser causes second - { - mExceptionHandler = new google_breakpad::ExceptionHandler( - L"C:\\Temp\\", - 0, //No filter - windows_post_minidump_callback, - 0, - google_breakpad::ExceptionHandler::HANDLER_ALL); //No custom client info. - } - else - { - LL_WARNS() << "adding breakpad exception handler" << LL_ENDL; - - std::wstring wpipe_name; - wpipe_name = mCrashReportPipeStr + wstringize(getPid()); - - const std::wstring wdump_path(utf8str_to_utf16str(mDumpPath)); - - int retries = 30; - for (; retries > 0; --retries) - { - if (mExceptionHandler != 0) delete mExceptionHandler; - - mExceptionHandler = new google_breakpad::ExceptionHandler( - wdump_path, - NULL, //No filter - windows_post_minidump_callback, - 0, - google_breakpad::ExceptionHandler::HANDLER_ALL, - MiniDumpNormal, //Generate a 'normal' minidump. - wpipe_name.c_str(), - NULL); //No custom client info. - if (mExceptionHandler->IsOutOfProcess()) - { - LL_INFOS("CRASHREPORT") << "Successfully attached to Out of Process exception handler." << LL_ENDL; - break; - } - else - { - LL_WARNS("CRASHREPORT") << "Unable to attach to Out of Process exception handler. " << retries << " retries remaining." << LL_ENDL; - ::Sleep(100); //Wait a tick and try again. - } - } - - if (retries == 0) LL_WARNS("CRASHREPORT") << "Unable to attach to Out of Process exception handler." << LL_ENDL; - } - - if (mExceptionHandler) - { - mExceptionHandler->set_handle_debug_exceptions(true); - } - } -#endif // LL_SEND_CRASH_REPORTS && ! defined(LL_BUGSPLAT) #else // ! LL_WINDOWS -#if defined(LL_BUGSPLAT) - // Don't install our own signal handlers -- BugSplat needs to hook them, - // or it's completely ineffectual. - bool installHandler = false; - -#else // ! LL_BUGSPLAT - // - // 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(); - - // Add google breakpad exception handler configured for Darwin/Linux. - bool installHandler = true; +#if ! defined(LL_BUGSPLAT) + // + // 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_BUGSPLAT -#if LL_DARWIN - // For the special case of Darwin, we do not want to install the handler if - // the process is being debugged as the app will exit with value ABRT (6) if - // we do. Unfortunately, the code below which performs that test relies on - // the structure kinfo_proc which has been tagged by apple as an unstable - // API. We disable this test for shipping versions to avoid conflicts with - // future releases of Darwin. This test is really only needed for developers - // starting the app from a debugger anyway. - #ifndef LL_RELEASE_FOR_DOWNLOAD - int mib[4]; - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = getpid(); - - struct kinfo_proc info; - memset(&info, 0, sizeof(info)); - - size_t size = sizeof(info); - int result = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); - if((result == 0) || (errno == ENOMEM)) - { - // P_TRACED flag is set, so this process is being debugged; do not install - // the handler - if(info.kp_proc.p_flag & P_TRACED) installHandler = false; - } - else - { - // Failed to discover if the process is being debugged; default to - // installing the handler. - installHandler = true; - } - #endif // ! LL_RELEASE_FOR_DOWNLOAD - - if(installHandler && (mExceptionHandler == 0)) - { - mExceptionHandler = new google_breakpad::ExceptionHandler(mDumpPath, 0, &unix_post_minidump_callback, 0, true, 0); - } -#elif LL_LINUX - if(installHandler && (mExceptionHandler == 0)) - { - if (mDumpPath.empty()) - { - mDumpPath = "/tmp"; - } - google_breakpad::MinidumpDescriptor desc(mDumpPath); - mExceptionHandler = new google_breakpad::ExceptionHandler(desc, NULL, unix_minidump_callback, NULL, true, -1); - } -#endif // LL_LINUX - #endif // ! LL_WINDOWS + +#ifdef LL_BUGSPLAT + // do not start our own error thread +#else // ! LL_BUGSPLAT startErrorThread(); +#endif } void LLApp::startErrorThread() @@ -561,10 +436,42 @@ void LLApp::runErrorHandler() LLApp::setStopped(); } +namespace +{ + +static std::map<LLApp::EAppStatus, const char*> statusDesc +{ + { LLApp::APP_STATUS_RUNNING, "running" }, + { LLApp::APP_STATUS_QUITTING, "quitting" }, + { LLApp::APP_STATUS_STOPPED, "stopped" }, + { LLApp::APP_STATUS_ERROR, "error" } +}; + +} // anonymous namespace + // static void LLApp::setStatus(EAppStatus status) { - sStatus = status; + sStatus = status; + + // This can also happen very late in the application lifecycle -- don't + // resurrect a deleted LLSingleton + if (! LLEventPumps::wasDeleted()) + { + // notify interested parties of status change + LLSD statsd; + auto found = statusDesc.find(status); + if (found != statusDesc.end()) + { + statsd = found->second; + } + else + { + // unknown status? at least report value + statsd = LLSD::Integer(status); + } + LLEventPumps::instance().obtain("LLApp").post(llsd::map("status", statsd)); + } } @@ -575,31 +482,6 @@ void LLApp::setError() setStatus(APP_STATUS_ERROR); } -void LLApp::setMiniDumpDir(const std::string &path) -{ - if (path.empty()) - { - mDumpPath = "/tmp"; - } - else - { - mDumpPath = path; - } - - if(mExceptionHandler == 0) return; -#ifdef LL_WINDOWS - std::wstring buffer(utf8str_to_utf16str(mDumpPath)); - if (buffer.size() > MAX_MINDUMP_PATH_LENGTH) buffer.resize(MAX_MINDUMP_PATH_LENGTH); - mExceptionHandler->set_dump_path(buffer); -#elif LL_LINUX - //google_breakpad::MinidumpDescriptor desc("/tmp"); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched. - google_breakpad::MinidumpDescriptor desc(mDumpPath); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched. - mExceptionHandler->set_minidump_descriptor(desc); -#else - mExceptionHandler->set_dump_path(mDumpPath); -#endif -} - void LLApp::setDebugFileNames(const std::string &path) { mStaticDebugFileName = path + "static_debug_info.log"; @@ -608,8 +490,6 @@ void LLApp::setDebugFileNames(const std::string &path) void LLApp::writeMiniDump() { - if(mExceptionHandler == 0) return; - mExceptionHandler->WriteMinidump(); } // static @@ -666,13 +546,6 @@ bool LLApp::isExiting() void LLApp::disableCrashlogger() { - // Disable Breakpad exception handler. - if (mExceptionHandler != 0) - { - delete mExceptionHandler; - mExceptionHandler = 0; - } - sDisableCrashlogger = TRUE; } @@ -774,7 +647,9 @@ void setup_signals() act.sa_flags = SA_SIGINFO; // Synchronous signals +# ifndef LL_BUGSPLAT sigaction(SIGABRT, &act, NULL); +# endif sigaction(SIGALRM, &act, NULL); sigaction(SIGBUS, &act, NULL); sigaction(SIGFPE, &act, NULL); @@ -811,7 +686,9 @@ void clear_signals() act.sa_flags = SA_SIGINFO; // Synchronous signals +# ifndef LL_BUGSPLAT sigaction(SIGABRT, &act, NULL); +# endif sigaction(SIGALRM, &act, NULL); sigaction(SIGBUS, &act, NULL); sigaction(SIGFPE, &act, NULL); @@ -864,6 +741,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) return; case SIGABRT: + // Note that this handler is not set for SIGABRT when using Bugsplat // Abort just results in termination of the app, no funky error handling. if (LLApp::sLogInSignal) { @@ -1061,64 +939,3 @@ bool unix_post_minidump_callback(const char *dump_dir, } #endif // !WINDOWS -#ifdef LL_WINDOWS -bool windows_post_minidump_callback(const wchar_t* dump_path, - const wchar_t* minidump_id, - void* context, - EXCEPTION_POINTERS* exinfo, - MDRawAssertionInfo* assertion, - bool succeeded) -{ - char * path = LLApp::instance()->getMiniDumpFilename(); - S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH; - size_t bytesUsed; - - LL_INFOS("MINIDUMPCALLBACK") << "Dump file was generated." << LL_ENDL; - bytesUsed = wcstombs(path, dump_path, static_cast<size_t>(remaining)); - remaining -= bytesUsed; - path += bytesUsed; - if(remaining > 0 && bytesUsed > 0 && path[-1] != '\\') - { - *path++ = '\\'; - --remaining; - } - if(remaining > 0) - { - bytesUsed = wcstombs(path, minidump_id, static_cast<size_t>(remaining)); - remaining -= bytesUsed; - path += bytesUsed; - } - if(remaining > 0) - { - strncpy(path, ".dmp", remaining); - } - - LL_INFOS("CRASHREPORT") << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL; - // *NOTE:Mani - this code is stolen from LLApp, where its never actually used. - //OSMessageBox("Attach Debugger Now", "Error", OSMB_OK); - // *TODO: Translate the signals/exceptions into cross-platform stuff - // Windows implementation - LL_INFOS() << "Entering Windows Exception Handler..." << LL_ENDL; - - if (LLApp::isError()) - { - LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL; - } - - // 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); - } - -#ifndef LL_RELEASE_FOR_DOWNLOAD - return false; -#else - return true; -#endif -} -#endif diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index 245c73e3a2..83f3bf3f93 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -49,10 +49,6 @@ void clear_signals(); #endif -namespace google_breakpad { - class ExceptionHandler; // See exception_handler.h -} - class LL_COMMON_API LLApp { friend class LLErrorThread; @@ -236,7 +232,6 @@ public: static const U32 MAX_MINDUMP_PATH_LENGTH = 256; // change the directory where Breakpad minidump files are written to - void setMiniDumpDir(const std::string &path); void setDebugFileNames(const std::string &path); // Return the Google Breakpad minidump filename after a crash. @@ -259,6 +254,10 @@ public: */ LLRunner& getRunner() { return mRunner; } +#ifdef LL_WINDOWS + virtual void reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { } +#endif + public: typedef std::map<std::string, std::string> string_map; string_map mOptionMap; // Contains all command-line options and arguments in a map @@ -312,9 +311,6 @@ private: private: // the static application instance if it was created. static LLApp* sApplication; - - google_breakpad::ExceptionHandler * mExceptionHandler; - #if !LL_WINDOWS friend void default_unix_signal_handler(int signum, siginfo_t *info, void *); diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 29f0c7da9a..db94765871 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -68,7 +68,7 @@ void ll_cleanup_apr() { gAPRInitialized = false; - LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL; + LL_DEBUGS("APR") << "Cleaning up APR" << LL_ENDL; LLThreadLocalPointerBase::destroyAllThreadLocalStorage(); @@ -242,6 +242,64 @@ void _ll_apr_assert_status(apr_status_t status, const char* file, int line) //--------------------------------------------------------------------- // +// Scope based pool access +// +//--------------------------------------------------------------------- + +class LLAPRFilePoolScope +{ +public: + LLAPRFilePoolScope() : pPool(NULL), mInitialized(false) {} + LLAPRFilePoolScope(LLVolatileAPRPool* poolp) : mInitialized(false) + { + setFilePool(poolp); + } + ~LLAPRFilePoolScope() + { + reset(); + } + apr_pool_t* getVolatileAPRPool(LLVolatileAPRPool* poolp = NULL) + { + if (!pPool) + { + setFilePool(poolp); + } + if (mInitialized) + { + // We need one clear per one get + // At the moment no need to support multiple calls + LL_ERRS() << "LLAPRFilePoolScope is not supposed to be initialized twice" << LL_ENDL; + } + mInitialized = true; + return pPool->getVolatileAPRPool(); + } + void reset() + { + if (mInitialized) + { + pPool->clearVolatileAPRPool(); + } + } + +private: + void setFilePool(LLVolatileAPRPool* poolp = NULL) + { + if (poolp) + { + pPool = poolp; + } + else + { + pPool = LLAPRFile::sAPRFilePoolp; + } + } + + LLVolatileAPRPool *pPool; + bool mInitialized; +}; + +//--------------------------------------------------------------------- +// // LLAPRFile functions // LLAPRFile::LLAPRFile() @@ -287,9 +345,10 @@ apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLV //check if already open some file llassert_always(!mFile) ; llassert_always(!mCurrentFilePoolp) ; - - apr_pool_t* apr_pool = pool ? pool->getVolatileAPRPool() : NULL ; - s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, getAPRFilePool(apr_pool)); + + mCurrentFilePoolp = pool ? pool : sAPRFilePoolp; + apr_pool_t* apr_pool = mCurrentFilePoolp->getVolatileAPRPool(); //paired with clear in close() + s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, apr_pool); if (s != APR_SUCCESS || !mFile) { @@ -314,14 +373,10 @@ apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLV *sizep = file_size; } - if(!mCurrentFilePoolp) + if (!mFile) { - mCurrentFilePoolp = pool ; - - if(!mFile) - { - close() ; - } + // It will clean pool + close() ; } return s ; @@ -348,17 +403,6 @@ apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOO return s; } -apr_pool_t* LLAPRFile::getAPRFilePool(apr_pool_t* pool) -{ - if(!pool) - { - mCurrentFilePoolp = sAPRFilePoolp ; - return mCurrentFilePoolp->getVolatileAPRPool() ; - } - - return pool ; -} - // File I/O S32 LLAPRFile::read(void *buf, S32 nbytes) { @@ -415,7 +459,7 @@ S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset) // //static -apr_status_t LLAPRFile::close(apr_file_t* file_handle, LLVolatileAPRPool* pool) +apr_status_t LLAPRFile::close(apr_file_t* file_handle) { apr_status_t ret = APR_SUCCESS ; if(file_handle) @@ -424,29 +468,23 @@ apr_status_t LLAPRFile::close(apr_file_t* file_handle, LLVolatileAPRPool* pool) file_handle = NULL ; } - if(pool) - { - pool->clearVolatileAPRPool() ; - } - return ret ; } //static -apr_file_t* LLAPRFile::open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags) +apr_file_t* LLAPRFile::open(const std::string& filename, apr_pool_t* apr_pool, apr_int32_t flags) { apr_status_t s; apr_file_t* file_handle ; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool()); + s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, apr_pool); if (s != APR_SUCCESS || !file_handle) { ll_apr_warn_status(s); LL_WARNS("APR") << " Attempting to open filename: " << filename << LL_ENDL; file_handle = NULL ; - close(file_handle, pool) ; + close(file_handle) ; return NULL; } @@ -489,8 +527,9 @@ S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset) S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) { //***************************************** - apr_file_t* file_handle = open(filename, pool, APR_READ|APR_BINARY); - //***************************************** + LLAPRFilePoolScope scope(pool); + apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), APR_READ|APR_BINARY); + //***************************************** if (!file_handle) { return 0; @@ -523,7 +562,7 @@ S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nb } //***************************************** - close(file_handle, pool) ; + close(file_handle) ; //***************************************** return (S32)bytes_read; } @@ -537,9 +576,10 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n flags |= APR_APPEND; offset = 0; } - + //***************************************** - apr_file_t* file_handle = open(filename, pool, flags); + LLAPRFilePoolScope scope(pool); + apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), flags); //***************************************** if (!file_handle) { @@ -573,7 +613,7 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n } //***************************************** - LLAPRFile::close(file_handle, pool); + LLAPRFile::close(file_handle); //***************************************** return (S32)bytes_written; @@ -584,9 +624,8 @@ bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool) { apr_status_t s; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_remove(filename.c_str(), pool->getVolatileAPRPool()); - pool->clearVolatileAPRPool() ; + LLAPRFilePoolScope scope(pool); + s = apr_file_remove(filename.c_str(), scope.getVolatileAPRPool()); if (s != APR_SUCCESS) { @@ -602,9 +641,8 @@ bool LLAPRFile::rename(const std::string& filename, const std::string& newname, { apr_status_t s; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_rename(filename.c_str(), newname.c_str(), pool->getVolatileAPRPool()); - pool->clearVolatileAPRPool() ; + LLAPRFilePoolScope scope(pool); + s = apr_file_rename(filename.c_str(), newname.c_str(), scope.getVolatileAPRPool()); if (s != APR_SUCCESS) { @@ -621,18 +659,16 @@ bool LLAPRFile::isExist(const std::string& filename, LLVolatileAPRPool* pool, ap apr_file_t* apr_file; apr_status_t s; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool()); + LLAPRFilePoolScope scope(pool); + s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, scope.getVolatileAPRPool()); if (s != APR_SUCCESS || !apr_file) { - pool->clearVolatileAPRPool() ; return false; } else { apr_file_close(apr_file) ; - pool->clearVolatileAPRPool() ; return true; } } @@ -643,14 +679,12 @@ S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool) apr_file_t* apr_file; apr_finfo_t info; apr_status_t s; - - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool->getVolatileAPRPool()); + + LLAPRFilePoolScope scope(pool); + s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, scope.getVolatileAPRPool()); if (s != APR_SUCCESS || !apr_file) - { - pool->clearVolatileAPRPool() ; - + { return 0; } else @@ -658,7 +692,6 @@ S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool) apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file); apr_file_close(apr_file) ; - pool->clearVolatileAPRPool() ; if (s == APR_SUCCESS) { @@ -676,9 +709,8 @@ bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool) { apr_status_t s; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool->getVolatileAPRPool()); - pool->clearVolatileAPRPool() ; + LLAPRFilePoolScope scope(pool); + s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, scope.getVolatileAPRPool()); if (s != APR_SUCCESS) { @@ -694,9 +726,8 @@ bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool) { apr_status_t s; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_remove(dirname.c_str(), pool->getVolatileAPRPool()); - pool->clearVolatileAPRPool() ; + LLAPRFilePoolScope scope(pool); + s = apr_file_remove(dirname.c_str(), scope.getVolatileAPRPool()); if (s != APR_SUCCESS) { diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index da50dda103..565d7cfb63 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -29,7 +29,7 @@ #ifndef LL_LLAPR_H #define LL_LLAPR_H -#if LL_LINUX || LL_SOLARIS +#if LL_LINUX #include <sys/param.h> // Need PATH_MAX in APR headers... #endif @@ -41,17 +41,7 @@ #include "llstring.h" -#if LL_WINDOWS -#pragma warning (push) -#pragma warning (disable:4265) -#endif -// warning C4265: 'std::_Pad' : class has virtual functions, but destructor is not virtual - -#include <mutex> - -#if LL_WINDOWS -#pragma warning (pop) -#endif +#include "mutex.h" struct apr_dso_handle_t; /** @@ -180,9 +170,6 @@ public: S32 write(const void* buf, S32 nbytes); apr_file_t* getFileHandle() {return mFile;} - -private: - apr_pool_t* getAPRFilePool(apr_pool_t* pool) ; // //******************************************************************************************************************************* @@ -192,8 +179,8 @@ public: static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist. private: - static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags); - static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ; + static apr_file_t* open(const std::string& filename, apr_pool_t* apr_pool, apr_int32_t flags); + static apr_status_t close(apr_file_t* file) ; static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset); public: // returns false if failure: diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 7e5a157cdf..e6cc06e8d0 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -95,11 +95,14 @@ LLAssetDictionary::LLAssetDictionary() addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false)); addEntry(LLAssetType::AT_WIDGET, new AssetEntry("WIDGET", "widget", "widget", false, false, false)); addEntry(LLAssetType::AT_PERSON, new AssetEntry("PERSON", "person", "person", false, false, false)); + 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)); + addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE)); }; +const std::string LLAssetType::BADLOOKUP("llassettype_bad_lookup"); + // static LLAssetType::EType LLAssetType::getType(const std::string& desc_name) { @@ -118,7 +121,7 @@ const std::string &LLAssetType::getDesc(LLAssetType::EType asset_type) } else { - return badLookup(); + return BADLOOKUP; } } @@ -133,7 +136,7 @@ const char *LLAssetType::lookup(LLAssetType::EType asset_type) } else { - return badLookup().c_str(); + return BADLOOKUP.c_str(); } } @@ -171,7 +174,7 @@ const char *LLAssetType::lookupHumanReadable(LLAssetType::EType asset_type) } else { - return badLookup().c_str(); + return BADLOOKUP.c_str(); } } @@ -222,14 +225,6 @@ bool LLAssetType::lookupIsLinkType(EType asset_type) } // static -const std::string &LLAssetType::badLookup() -{ - static const std::string sBadLookup = "llassettype_bad_lookup"; - return sBadLookup; - -} - -// static bool LLAssetType::lookupIsAssetFetchByIDAllowed(EType asset_type) { const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 79ab3d7efe..652c548d59 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -116,10 +116,19 @@ public: AT_PERSON = 45, // A user uuid which is not an inventory asset type, used in viewer only for adding a person to a chat via drag and drop. - AT_MESH = 49, - // Mesh data in our proprietary SLM format - - AT_COUNT = 50, + AT_MESH = 49, + // Mesh data in our proprietary SLM format + + 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: | @@ -153,7 +162,7 @@ public: static bool lookupIsAssetFetchByIDAllowed(EType asset_type); // the asset allows direct download static bool lookupIsAssetIDKnowable(EType asset_type); // asset data can be known by the viewer - static const std::string& badLookup(); // error string when a lookup fails + static const std::string BADLOOKUP; protected: LLAssetType() {} diff --git a/indra/llcommon/llcleanup.cpp b/indra/llcommon/llcleanup.cpp index c5283507bf..1f34c2036a 100644 --- a/indra/llcommon/llcleanup.cpp +++ b/indra/llcommon/llcleanup.cpp @@ -20,10 +20,13 @@ #include "llerror.h" #include "llerrorcontrol.h" -void log_subsystem_cleanup(const char* file, int line, const char* function, +void log_subsystem_cleanup(LLError::ELevel level, + const char* file, + int line, + const char* function, const char* classname) { - LL_INFOS("Cleanup") << LLError::abbreviateFile(file) << "(" << line << "): " + LL_VLOGS(level, "Cleanup") << LLError::abbreviateFile(file) << "(" << line << "): " << "calling " << classname << "::cleanupClass() in " << function << LL_ENDL; } diff --git a/indra/llcommon/llcleanup.h b/indra/llcommon/llcleanup.h index a319171b5f..0f567ed5f6 100644 --- a/indra/llcommon/llcleanup.h +++ b/indra/llcommon/llcleanup.h @@ -21,13 +21,22 @@ // shutdown schemes. #define SUBSYSTEM_CLEANUP(CLASSNAME) \ do { \ - log_subsystem_cleanup(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, #CLASSNAME); \ + log_subsystem_cleanup(LLError::LEVEL_INFO, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, #CLASSNAME); \ + CLASSNAME::cleanupClass(); \ + } while (0) + +#define SUBSYSTEM_CLEANUP_DBG(CLASSNAME) \ + do { \ + log_subsystem_cleanup(LLError::LEVEL_DEBUG, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, #CLASSNAME); \ CLASSNAME::cleanupClass(); \ } while (0) // Use ancient do { ... } while (0) macro trick to permit a block of // statements with the same syntax as a single statement. -void log_subsystem_cleanup(const char* file, int line, const char* function, +void log_subsystem_cleanup(LLError::ELevel level, + const char* file, + int line, + const char* function, const char* classname); #endif /* ! defined(LL_LLCLEANUP_H) */ diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp index 2d665c611b..96be913d17 100644 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -63,7 +63,7 @@ void LLCommon::cleanupClass() sMasterThreadRecorder = NULL; LLTrace::set_master_thread_recorder(NULL); LLThreadSafeRefCount::cleanupThreadSafeRefCount(); - SUBSYSTEM_CLEANUP(LLTimer); + SUBSYSTEM_CLEANUP_DBG(LLTimer); if (sAprInitialized) { ll_cleanup_apr(); diff --git a/indra/llcommon/llcond.h b/indra/llcommon/llcond.h new file mode 100644 index 0000000000..e31b67d893 --- /dev/null +++ b/indra/llcommon/llcond.h @@ -0,0 +1,405 @@ +/** + * @file llcond.h + * @author Nat Goodspeed + * @date 2019-07-10 + * @brief LLCond is a wrapper around condition_variable to encapsulate the + * obligatory condition_variable usage pattern. We also provide + * simplified versions LLScalarCond, LLBoolCond and LLOneShotCond. + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Copyright (c) 2019, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLCOND_H) +#define LL_LLCOND_H + +#include "llunits.h" +#include "llcoros.h" +#include LLCOROS_MUTEX_HEADER +#include "mutex.h" +#include <chrono> + +/** + * LLCond encapsulates the pattern required to use a condition_variable. It + * bundles subject data, a mutex and a condition_variable: the three required + * data objects. It provides wait() methods analogous to condition_variable, + * but using the contained condition_variable and the contained mutex. It + * provides modify() methods accepting an invocable to safely modify the + * contained data and notify waiters. These methods implicitly perform the + * required locking. + * + * The generic LLCond template assumes that DATA might be a struct or class. + * For a scalar DATA type, consider LLScalarCond instead. For specifically + * bool, consider LLBoolCond. + * + * Use of LLCoros::ConditionVariable makes LLCond work between + * coroutines as well as between threads. + */ +template <typename DATA> +class LLCond +{ +public: + typedef DATA value_type; + +private: + // This is the DATA controlled by the condition_variable. + value_type mData; + // condition_variable must be used in conjunction with a mutex. Use + // LLCoros::Mutex instead of std::mutex because the latter blocks + // the entire calling thread, whereas the former blocks only the current + // coroutine within the calling thread. Yet LLCoros::Mutex is safe to + // use across threads as well: it subsumes std::mutex functionality. + LLCoros::Mutex mMutex; + // Use LLCoros::ConditionVariable for the same reason. + LLCoros::ConditionVariable mCond; + +public: + /// LLCond can be explicitly initialized with a specific value for mData if + /// desired. + LLCond(const value_type& init=value_type()): + mData(init) + {} + + /// LLCond is move-only + LLCond(const LLCond&) = delete; + LLCond& operator=(const LLCond&) = delete; + + /// get() returns a const reference to the stored DATA. The only way to + /// get a non-const reference -- to modify the stored DATA -- is via + /// update_one() or update_all(). + const value_type& get() const { return mData; } + + /** + * Pass update_one() an invocable accepting non-const (DATA&). The + * invocable will presumably modify the referenced DATA. update_one() + * will lock the mutex, call the invocable and then call notify_one() on + * the condition_variable. + * + * For scalar DATA, it's simpler to use LLScalarCond::set_one(). Use + * update_one() when DATA is a struct or class. + */ + template <typename MODIFY> + void update_one(MODIFY modify) + { + { // scope of lock can/should end before notify_one() + LLCoros::LockType lk(mMutex); + modify(mData); + } + mCond.notify_one(); + } + + /** + * Pass update_all() an invocable accepting non-const (DATA&). The + * invocable will presumably modify the referenced DATA. update_all() + * will lock the mutex, call the invocable and then call notify_all() on + * the condition_variable. + * + * For scalar DATA, it's simpler to use LLScalarCond::set_all(). Use + * update_all() when DATA is a struct or class. + */ + template <typename MODIFY> + void update_all(MODIFY modify) + { + { // scope of lock can/should end before notify_all() + LLCoros::LockType lk(mMutex); + modify(mData); + } + mCond.notify_all(); + } + + /** + * Pass wait() a predicate accepting (const DATA&), returning bool. The + * predicate returns true when the condition for which it is waiting has + * been satisfied, presumably determined by examining the referenced DATA. + * wait() locks the mutex and, until the predicate returns true, calls + * wait() on the condition_variable. + */ + template <typename Pred> + void wait(Pred pred) + { + LLCoros::LockType lk(mMutex); + // We must iterate explicitly since the predicate accepted by + // condition_variable::wait() requires a different signature: + // condition_variable::wait() calls its predicate with no arguments. + // Fortunately, the loop is straightforward. + // We advise the caller to pass a predicate accepting (const DATA&). + // But what if they instead pass a predicate accepting non-const + // (DATA&)? Such a predicate could modify mData, which would be Bad. + // Forbid that. + while (! pred(const_cast<const value_type&>(mData))) + { + mCond.wait(lk); + } + } + + /** + * Pass wait_for() a chrono::duration, indicating how long we're willing + * to wait, and a predicate accepting (const DATA&), returning bool. The + * predicate returns true when the condition for which it is waiting has + * been satisfied, presumably determined by examining the referenced DATA. + * wait_for() locks the mutex and, until the predicate returns true, calls + * wait_for() on the condition_variable. wait_for() returns false if + * condition_variable::wait_for() timed out without the predicate + * returning true. + */ + template <typename Rep, typename Period, typename Pred> + bool wait_for(const std::chrono::duration<Rep, Period>& timeout_duration, Pred pred) + { + // Instead of replicating wait_until() logic, convert duration to + // time_point and just call wait_until(). + // An implementation in which we repeatedly called + // condition_variable::wait_for() with our passed duration would be + // wrong! We'd keep pushing the timeout time farther and farther into + // the future. This way, we establish a definite timeout time and + // stick to it. + return wait_until(std::chrono::steady_clock::now() + timeout_duration, pred); + } + + /** + * This wait_for() overload accepts F32Milliseconds as the duration. Any + * duration unit defined in llunits.h is implicitly convertible to + * F32Milliseconds. The semantics of this method are the same as the + * generic wait_for() method. + */ + template <typename Pred> + bool wait_for(F32Milliseconds timeout_duration, Pred pred) + { + return wait_for(convert(timeout_duration), pred); + } + +protected: + // convert F32Milliseconds to a chrono::duration + auto convert(F32Milliseconds duration) + { + // std::chrono::milliseconds doesn't like to be constructed from a + // float (F32), rubbing our nose in the thought that + // std::chrono::duration::rep is probably integral. Therefore + // converting F32Milliseconds to std::chrono::milliseconds would lose + // precision. Use std::chrono::microseconds instead. Extract the F32 + // milliseconds from F32Milliseconds, scale to microseconds, construct + // std::chrono::microseconds from that value. + return std::chrono::microseconds{ std::chrono::microseconds::rep(duration.value() * 1000) }; + } + +private: + /** + * Pass wait_until() a chrono::time_point, indicating the time at which we + * should stop waiting, and a predicate accepting (const DATA&), returning + * bool. The predicate returns true when the condition for which it is + * waiting has been satisfied, presumably determined by examining the + * referenced DATA. wait_until() locks the mutex and, until the predicate + * returns true, calls wait_until() on the condition_variable. + * wait_until() returns false if condition_variable::wait_until() timed + * out without the predicate returning true. + * + * Originally this class and its subclasses published wait_until() methods + * corresponding to each wait_for() method. But that raised all sorts of + * fascinating questions about the time zone of the passed time_point: + * local time? server time? UTC? The bottom line is that for LLCond + * timeout purposes, we really shouldn't have to care -- timeout duration + * is all we need. This private method remains because it's the simplest + * way to support iteratively waiting across spurious wakeups while + * honoring a fixed timeout. + */ + template <typename Clock, typename Duration, typename Pred> + bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, Pred pred) + { + LLCoros::LockType lk(mMutex); + // We advise the caller to pass a predicate accepting (const DATA&). + // But what if they instead pass a predicate accepting non-const + // (DATA&)? Such a predicate could modify mData, which would be Bad. + // Forbid that. + while (! pred(const_cast<const value_type&>(mData))) + { + if (LLCoros::cv_status::timeout == mCond.wait_until(lk, timeout_time)) + { + // It's possible that wait_until() timed out AND the predicate + // became true more or less simultaneously. Even though + // wait_until() timed out, check the predicate one more time. + return pred(const_cast<const value_type&>(mData)); + } + } + return true; + } +}; + +template <typename DATA> +class LLScalarCond: public LLCond<DATA> +{ + using super = LLCond<DATA>; + +public: + using typename super::value_type; + using super::get; + using super::wait; + using super::wait_for; + + /// LLScalarCond can be explicitly initialized with a specific value for + /// mData if desired. + LLScalarCond(const value_type& init=value_type()): + super(init) + {} + + /// Pass set_one() a new value to which to update mData. set_one() will + /// lock the mutex, update mData and then call notify_one() on the + /// condition_variable. + void set_one(const value_type& value) + { + super::update_one([&value](value_type& data){ data = value; }); + } + + /// Pass set_all() a new value to which to update mData. set_all() will + /// lock the mutex, update mData and then call notify_all() on the + /// condition_variable. + void set_all(const value_type& value) + { + super::update_all([&value](value_type& data){ data = value; }); + } + + /** + * Pass wait_equal() a value for which to wait. wait_equal() locks the + * mutex and, until the stored DATA equals that value, calls wait() on the + * condition_variable. + */ + void wait_equal(const value_type& value) + { + super::wait([&value](const value_type& data){ return (data == value); }); + } + + /** + * Pass wait_for_equal() a chrono::duration, indicating how long we're + * willing to wait, and a value for which to wait. wait_for_equal() locks + * the mutex and, until the stored DATA equals that value, calls + * wait_for() on the condition_variable. wait_for_equal() returns false if + * condition_variable::wait_for() timed out without the stored DATA being + * equal to the passed value. + */ + template <typename Rep, typename Period> + bool wait_for_equal(const std::chrono::duration<Rep, Period>& timeout_duration, + const value_type& value) + { + return super::wait_for(timeout_duration, + [&value](const value_type& data){ return (data == value); }); + } + + /** + * This wait_for_equal() overload accepts F32Milliseconds as the duration. + * Any duration unit defined in llunits.h is implicitly convertible to + * F32Milliseconds. The semantics of this method are the same as the + * generic wait_for_equal() method. + */ + bool wait_for_equal(F32Milliseconds timeout_duration, const value_type& value) + { + return wait_for_equal(super::convert(timeout_duration), value); + } + + /** + * Pass wait_unequal() a value from which to move away. wait_unequal() + * locks the mutex and, until the stored DATA no longer equals that value, + * calls wait() on the condition_variable. + */ + void wait_unequal(const value_type& value) + { + super::wait([&value](const value_type& data){ return (data != value); }); + } + + /** + * Pass wait_for_unequal() a chrono::duration, indicating how long we're + * willing to wait, and a value from which to move away. + * wait_for_unequal() locks the mutex and, until the stored DATA no longer + * equals that value, calls wait_for() on the condition_variable. + * wait_for_unequal() returns false if condition_variable::wait_for() + * timed out with the stored DATA still being equal to the passed value. + */ + template <typename Rep, typename Period> + bool wait_for_unequal(const std::chrono::duration<Rep, Period>& timeout_duration, + const value_type& value) + { + return super::wait_for(timeout_duration, + [&value](const value_type& data){ return (data != value); }); + } + + /** + * This wait_for_unequal() overload accepts F32Milliseconds as the duration. + * Any duration unit defined in llunits.h is implicitly convertible to + * F32Milliseconds. The semantics of this method are the same as the + * generic wait_for_unequal() method. + */ + bool wait_for_unequal(F32Milliseconds timeout_duration, const value_type& value) + { + return wait_for_unequal(super::convert(timeout_duration), value); + } + +protected: + using super::convert; +}; + +/// Using bool as LLScalarCond's DATA seems like a particularly useful case +using LLBoolCond = LLScalarCond<bool>; + +/// LLOneShotCond -- init false, set (and wait for) true +class LLOneShotCond: public LLBoolCond +{ + using super = LLBoolCond; + +public: + using typename super::value_type; + using super::get; + using super::wait; + using super::wait_for; + using super::wait_equal; + using super::wait_for_equal; + using super::wait_unequal; + using super::wait_for_unequal; + + /// The bool stored in LLOneShotCond is initially false + LLOneShotCond(): super(false) {} + + /// LLOneShotCond assumes that nullary set_one() means to set its bool true + void set_one(bool value=true) + { + super::set_one(value); + } + + /// LLOneShotCond assumes that nullary set_all() means to set its bool true + void set_all(bool value=true) + { + super::set_all(value); + } + + /** + * wait() locks the mutex and, until the stored bool is true, calls wait() + * on the condition_variable. + */ + void wait() + { + super::wait_unequal(false); + } + + /** + * Pass wait_for() a chrono::duration, indicating how long we're willing + * to wait. wait_for() locks the mutex and, until the stored bool is true, + * calls wait_for() on the condition_variable. wait_for() returns false if + * condition_variable::wait_for() timed out without the stored bool being + * true. + */ + template <typename Rep, typename Period> + bool wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) + { + return super::wait_for_unequal(timeout_duration, false); + } + + /** + * This wait_for() overload accepts F32Milliseconds as the duration. + * Any duration unit defined in llunits.h is implicitly convertible to + * F32Milliseconds. The semantics of this method are the same as the + * generic wait_for() method. + */ + bool wait_for(F32Milliseconds timeout_duration) + { + return wait_for(super::convert(timeout_duration)); + } +}; + +#endif /* ! defined(LL_LLCOND_H) */ diff --git a/indra/llcommon/llcoro_get_id.cpp b/indra/llcommon/llcoro_get_id.cpp deleted file mode 100644 index 24ed1fe0c9..0000000000 --- a/indra/llcommon/llcoro_get_id.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @file llcoro_get_id.cpp - * @author Nat Goodspeed - * @date 2016-09-03 - * @brief Implementation for llcoro_get_id. - * - * $LicenseInfo:firstyear=2016&license=viewerlgpl$ - * Copyright (c) 2016, Linden Research, Inc. - * $/LicenseInfo$ - */ - -// Precompiled header -#include "linden_common.h" -// associated header -#include "llcoro_get_id.h" -// STL headers -// std headers -// external library headers -// other Linden headers -#include "llcoros.h" - -namespace llcoro -{ - -id get_id() -{ - // An instance of Current can convert to LLCoros::CoroData*, which can - // implicitly convert to void*, which is an llcoro::id. - return LLCoros::Current(); -} - -} // llcoro diff --git a/indra/llcommon/llcoro_get_id.h b/indra/llcommon/llcoro_get_id.h deleted file mode 100644 index 4c1dca6f19..0000000000 --- a/indra/llcommon/llcoro_get_id.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file llcoro_get_id.h - * @author Nat Goodspeed - * @date 2016-09-03 - * @brief Supplement the functionality in llcoro.h. - * - * This is broken out as a separate header file to resolve - * circularity: LLCoros isa LLSingleton, yet LLSingleton machinery - * requires llcoro::get_id(). - * - * Be very suspicious of anyone else #including this header. - * - * $LicenseInfo:firstyear=2016&license=viewerlgpl$ - * Copyright (c) 2016, Linden Research, Inc. - * $/LicenseInfo$ - */ - -#if ! defined(LL_LLCORO_GET_ID_H) -#define LL_LLCORO_GET_ID_H - -namespace llcoro -{ - -/// Get an opaque, distinct token for the running coroutine (or main). -typedef void* id; -id get_id(); - -} // llcoro - -#endif /* ! defined(LL_LLCORO_GET_ID_H) */ diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 67e9fad1ab..111c50af93 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -26,15 +26,30 @@ * $/LicenseInfo$ */ +#include "llwin32headers.h" + // Precompiled header #include "linden_common.h" // associated header #include "llcoros.h" // STL headers // std headers +#include <atomic> // external library headers #include <boost/bind.hpp> +#include <boost/fiber/fiber.hpp> +#ifndef BOOST_DISABLE_ASSERTS +#define UNDO_BOOST_DISABLE_ASSERTS +// with Boost 1.65.1, needed for Mac with this specific header +#define BOOST_DISABLE_ASSERTS +#endif +#include <boost/fiber/protected_fixedsize_stack.hpp> +#ifdef UNDO_BOOST_DISABLE_ASSERTS +#undef UNDO_BOOST_DISABLE_ASSERTS +#undef BOOST_DISABLE_ASSERTS +#endif // other Linden headers +#include "llapp.h" #include "lltimer.h" #include "llevents.h" #include "llerror.h" @@ -45,85 +60,43 @@ #include <excpt.h> #endif -namespace { -void no_op() {} -} // anonymous namespace - -// Do nothing, when we need nothing done. This is a static member of LLCoros -// because CoroData is a private nested class. -void LLCoros::no_cleanup(CoroData*) {} - -// CoroData for the currently-running coroutine. Use a thread_specific_ptr -// because each thread potentially has its own distinct pool of coroutines. -LLCoros::Current::Current() +// static +LLCoros::CoroData& LLCoros::get_CoroData(const std::string& caller) { - // Use a function-static instance so this thread_specific_ptr is - // instantiated on demand. Since we happen to know it's consumed by - // LLSingleton, this is likely to happen before the runtime has finished - // initializing module-static data. For the same reason, we can't package - // this pointer in an LLSingleton. - - // This thread_specific_ptr does NOT own the CoroData object! That's owned - // by LLCoros::mCoros. It merely identifies it. For this reason we - // instantiate it with a no-op cleanup function. - static boost::thread_specific_ptr<LLCoros::CoroData> sCurrent(LLCoros::no_cleanup); - - // If this is the first time we're accessing sCurrent for the running - // thread, its get() will be NULL. This could be a problem, in that - // llcoro::get_id() would return the same (NULL) token value for the "main - // coroutine" in every thread, whereas what we really want is a distinct - // value for every distinct stack in the process. So if get() is NULL, - // give it a heap CoroData: this ensures that llcoro::get_id() will return - // distinct values. - // This tactic is "leaky": sCurrent explicitly does not destroy any - // CoroData to which it points, and we do NOT enter these "main coroutine" - // CoroData instances in the LLCoros::mCoros map. They are dummy entries, - // and they will leak at process shutdown: one CoroData per thread. - if (! sCurrent.get()) + CoroData* current{ nullptr }; + // be careful about attempted accesses in the final throes of app shutdown + if (! wasDeleted()) { - // It's tempting to provide a distinct name for each thread's "main - // coroutine." But as getName() has always returned the empty string - // to mean "not in a coroutine," empty string should suffice here -- - // and truthfully the additional (thread-safe!) machinery to ensure - // uniqueness just doesn't feel worth the trouble. - // We use a no-op callable and a minimal stack size because, although - // CoroData's constructor in fact initializes its mCoro with a - // coroutine with that stack size, no one ever actually enters it by - // calling mCoro(). - sCurrent.reset(new CoroData(0, // no prev - "", // not a named coroutine - no_op, // no-op callable - 1024)); // stacksize moot + current = instance().mCurrent.get(); + } + // For the main() coroutine, the one NOT explicitly launched by launch(), + // we never explicitly set mCurrent. Use a static CoroData instance with + // canonical values. + if (! current) + { + static std::atomic<int> which_thread(0); + // Use alternate CoroData constructor. + static thread_local CoroData sMain(which_thread++); + // We need not reset() the local_ptr to this instance; we'll simply + // find it again every time we discover that current is null. + current = &sMain; } - - mCurrent = &sCurrent; -} - -//static -LLCoros::CoroData& LLCoros::get_CoroData(const std::string& caller) -{ - CoroData* current = Current(); - // With the dummy CoroData set in LLCoros::Current::Current(), this - // pointer should never be NULL. - llassert_always(current); return *current; } //static -LLCoros::coro::self& LLCoros::get_self() +LLCoros::coro::id LLCoros::get_self() { - CoroData& current = get_CoroData("get_self()"); - if (! current.mSelf) - { - LL_ERRS("LLCoros") << "Calling get_self() from non-coroutine context!" << LL_ENDL; - } - return *current.mSelf; + return boost::this_fiber::get_id(); } //static void LLCoros::set_consuming(bool consuming) { - get_CoroData("set_consuming()").mConsuming = consuming; + CoroData& data(get_CoroData("set_consuming()")); + // DO NOT call this on the main() coroutine. + llassert_always(! data.mName.empty()); + data.mConsuming = consuming; } //static @@ -132,89 +105,59 @@ bool LLCoros::get_consuming() return get_CoroData("get_consuming()").mConsuming; } -llcoro::Suspending::Suspending() +// static +void LLCoros::setStatus(const std::string& status) { - LLCoros::Current current; - // Remember currently-running coroutine: we're about to suspend it. - mSuspended = current; - // Revert Current to the value it had at the moment we last switched - // into this coroutine. - current.reset(mSuspended->mPrev); + get_CoroData("setStatus()").mStatus = status; } -llcoro::Suspending::~Suspending() +// static +std::string LLCoros::getStatus() { - LLCoros::Current current; - // Okay, we're back, update our mPrev - mSuspended->mPrev = current; - // and reinstate our Current. - current.reset(mSuspended); + return get_CoroData("getStatus()").mStatus; } 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. + // empirically this is insufficient. #if ADDRESS_SIZE == 64 - mStackSize(512*1024) + mStackSize(512*1024), #else - mStackSize(256*1024) + mStackSize(256*1024), #endif + // mCurrent does NOT own the current CoroData instance -- it simply + // points to it. So initialize it with a no-op deleter. + mCurrent{ [](CoroData*){} } { - // Register our cleanup() method for "mainloop" ticks - LLEventPumps::instance().obtain("mainloop").listen( - "LLCoros", boost::bind(&LLCoros::cleanup, this, _1)); } -bool LLCoros::cleanup(const LLSD&) +LLCoros::~LLCoros() { - static std::string previousName; - static int previousCount = 0; - // Walk the mCoros map, checking and removing completed coroutines. - for (CoroMap::iterator mi(mCoros.begin()), mend(mCoros.end()); mi != mend; ) + printActiveCoroutines("at entry to ~LLCoros()"); + // Other LLApp status-change listeners do things like close + // work queues and inject the Stop exception into pending + // promises, to force coroutines waiting on those things to + // notice and terminate. The only problem is that by the time + // LLApp sets "quitting" status, the main loop has stopped + // pumping the fiber scheduler with yield() calls. A waiting + // coroutine still might not wake up until after resources on + // which it depends have been freed. Pump it a few times + // ourselves. Of course, stop pumping as soon as the last of + // the coroutines has terminated. + for (size_t count = 0; count < 10 && CoroData::instanceCount() > 0; ++count) { - // Has this coroutine exited (normal return, exception, exit() call) - // since last tick? - if (mi->second->mCoro.exited()) - { - if (previousName != mi->first) - { - previousName = mi->first; - previousCount = 1; - } - else - { - ++previousCount; - } - - if ((previousCount < 5) || !(previousCount % 50)) - { - if (previousCount < 5) - LL_DEBUGS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL; - else - LL_DEBUGS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << "("<< previousCount << ")" << 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. - mCoros.erase(mi++); - } - else - { - // Still live, just skip this entry as if incrementing at the top - // of the loop as usual. - ++mi; - } + // don't use llcoro::suspend() because that module depends + // on this one + boost::this_fiber::yield(); } - return false; + printActiveCoroutines("after pumping"); } std::string LLCoros::generateDistinctName(const std::string& prefix) const { - static std::string previousName; - static int previousCount = 0; + static int unique = 0; // Allowing empty name would make getName()'s not-found return ambiguous. if (prefix.empty()) @@ -225,37 +168,15 @@ std::string LLCoros::generateDistinctName(const std::string& prefix) const // If the specified name isn't already in the map, just use that. std::string name(prefix); - // Find the lowest numeric suffix that doesn't collide with an existing - // entry. Start with 2 just to make it more intuitive for any interested - // parties: e.g. "joe", "joe2", "joe3"... - for (int i = 2; ; name = STRINGIZE(prefix << i++)) + // Until we find an unused name, append a numeric suffix for uniqueness. + while (CoroData::getInstance(name)) { - if (mCoros.find(name) == mCoros.end()) - { - if (previousName != name) - { - previousName = name; - previousCount = 1; - } - else - { - ++previousCount; - } - - if ((previousCount < 5) || !(previousCount % 50)) - { - if (previousCount < 5) - LL_DEBUGS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL; - else - LL_DEBUGS("LLCoros") << "LLCoros: launching coroutine " << name << "(" << previousCount << ")" << LL_ENDL; - - } - - return name; - } + name = STRINGIZE(prefix << unique++); } + return name; } +/*==========================================================================*| bool LLCoros::kill(const std::string& name) { CoroMap::iterator found = mCoros.find(name); @@ -269,10 +190,19 @@ bool LLCoros::kill(const std::string& name) mCoros.erase(found); return true; } +|*==========================================================================*/ -std::string LLCoros::getName() const +//static +std::string LLCoros::getName() { - return Current()->mName; + return get_CoroData("getName()").mName; +} + +//static +std::string LLCoros::logname() +{ + LLCoros::CoroData& data(get_CoroData("logname()")); + return data.mName.empty()? data.getKey() : data.mName; } void LLCoros::setStackSize(S32 stacksize) @@ -281,31 +211,65 @@ void LLCoros::setStackSize(S32 stacksize) mStackSize = stacksize; } -void LLCoros::printActiveCoroutines() +void LLCoros::printActiveCoroutines(const std::string& when) { - LL_INFOS("LLCoros") << "Number of active coroutines: " << (S32)mCoros.size() << LL_ENDL; - if (mCoros.size() > 0) + LL_INFOS("LLCoros") << "Number of active coroutines " << when + << ": " << CoroData::instanceCount() << LL_ENDL; + if (CoroData::instanceCount() > 0) { LL_INFOS("LLCoros") << "-------------- List of active coroutines ------------"; - CoroMap::iterator iter; - CoroMap::iterator end = mCoros.end(); F64 time = LLTimer::getTotalSeconds(); - for (iter = mCoros.begin(); iter != end; iter++) + for (auto& cd : CoroData::instance_snapshot()) { - F64 life_time = time - iter->second->mCreationTime; - LL_CONT << LL_NEWLINE << "Name: " << iter->first << " life: " << life_time; + F64 life_time = time - cd.mCreationTime; + LL_CONT << LL_NEWLINE + << cd.getKey() << ' ' << cd.mStatus << " life: " << life_time; } LL_CONT << LL_ENDL; LL_INFOS("LLCoros") << "-----------------------------------------------------" << LL_ENDL; } } +std::string LLCoros::launch(const std::string& prefix, const callable_t& callable) +{ + std::string name(generateDistinctName(prefix)); + // 'dispatch' means: enter the new fiber immediately, returning here only + // when the fiber yields for whatever reason. + // std::allocator_arg is a flag to indicate that the following argument is + // a StackAllocator. + // protected_fixedsize_stack sets a guard page past the end of the new + // stack so that stack underflow will result in an access violation + // instead of weird, subtle, possibly undiagnosed memory stomps. + boost::fibers::fiber newCoro(boost::fibers::launch::dispatch, + std::allocator_arg, + boost::fibers::protected_fixedsize_stack(mStackSize), + [this, &name, &callable](){ toplevel(name, callable); }); + // You have two choices with a fiber instance: you can join() it or you + // can detach() it. If you try to destroy the instance before doing + // either, the program silently terminates. We don't need this handle. + newCoro.detach(); + return name; +} + #if LL_WINDOWS static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific -U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) +U32 cpp_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop, const std::string& name) { + // C++ exceptions were logged in toplevelTryWrapper, but not SEH + // log SEH exceptions here, to make sure it gets into bugsplat's + // report and because __try won't allow std::string operations + if (code != STATUS_MSC_EXCEPTION) + { + LL_WARNS() << "SEH crash in " << name << ", code: " << code << LL_ENDL; + } + // Handle bugsplat here, since GetExceptionInformation() can only be + // called from within filter for __except(filter), not from __except's {} + // Bugsplat should get all exceptions, C++ and SEH + LLApp::instance()->reportCrashToBugsplat(exception_infop); + + // Only convert non C++ exceptions. if (code == STATUS_MSC_EXCEPTION) { // C++ exception, go on @@ -318,110 +282,118 @@ U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) } } -void LLCoros::winlevel(const callable_t& callable) +void LLCoros::winlevel(const std::string& name, const callable_t& callable) { __try { - callable(); + toplevelTryWrapper(name, callable); } - __except (exception_filter(GetExceptionCode(), GetExceptionInformation())) + __except (cpp_exception_filter(GetExceptionCode(), GetExceptionInformation(), name)) { - // convert to C++ styled exception + // convert to C++ styled exception for handlers other than bugsplat // Note: it might be better to use _se_set_translator // if you want exception to inherit full callstack - char integer_string[32]; - sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); + // + // in case of bugsplat this will get to exceptionTerminateHandler and + // looks like fiber will terminate application after that + char integer_string[512]; + sprintf(integer_string, "SEH crash in %s, code: %lu\n", name.c_str(), GetExceptionCode()); throw std::exception(integer_string); } } #endif -// Top-level wrapper around caller's coroutine callable. This function accepts -// the coroutine library's implicit coro::self& parameter and saves it, but -// does not pass it down to the caller's callable. -void LLCoros::toplevel(coro::self& self, CoroData* data, const callable_t& callable) +void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& callable) { - // capture the 'self' param in CoroData - data->mSelf = &self; + // keep the CoroData on this top-level function's stack frame + CoroData corodata(name); + // set it as current + mCurrent.reset(&corodata); + // run the code the caller actually wants in the coroutine try { -#if LL_WINDOWS - winlevel(callable); -#else callable(); -#endif + } + catch (const Stop& exc) + { + LL_INFOS("LLCoros") << "coroutine " << name << " terminating because " + << exc.what() << LL_ENDL; } catch (const LLContinueError&) { // Any uncaught exception derived from LLContinueError will be caught // here and logged. This coroutine will terminate but the rest of the // viewer will carry on. - LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << data->mName)); + LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name)); } catch (...) { // Any OTHER kind of uncaught exception will cause the viewer to // crash, hopefully informatively. - CRASH_ON_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << data->mName)); + LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name)); + // to not modify callstack + throw; } - // This cleanup isn't perfectly symmetrical with the way we initially set - // data->mPrev, but this is our last chance to reset Current. - Current().reset(data->mPrev); } -/***************************************************************************** -* MUST BE LAST -*****************************************************************************/ -// Turn off MSVC optimizations for just LLCoros::launch() -- see -// DEV-32777. But MSVC doesn't support push/pop for optimization flags as it -// does for warning suppression, and we really don't want to force -// optimization ON for other code even in Debug or RelWithDebInfo builds. - -#if LL_MSVC -// work around broken optimizations -#pragma warning(disable: 4748) -#pragma warning(disable: 4355) // 'this' used in initializer list: yes, intentionally -#pragma optimize("", off) -#endif // LL_MSVC - -LLCoros::CoroData::CoroData(CoroData* prev, const std::string& name, - const callable_t& callable, S32 stacksize): - mPrev(prev), +// Top-level wrapper around caller's coroutine callable. +// Normally we like to pass strings and such by const reference -- but in this +// case, we WANT to copy both the name and the callable to our local stack! +void LLCoros::toplevel(std::string name, callable_t callable) +{ +#if LL_WINDOWS + // Can not use __try in functions that require unwinding, so use one more wrapper + winlevel(name, callable); +#else + toplevelTryWrapper(name, callable); +#endif +} + +//static +void LLCoros::checkStop() +{ + if (wasDeleted()) + { + LLTHROW(Shutdown("LLCoros was deleted")); + } + // do this AFTER the check above, because getName() depends on + // get_CoroData(), which depends on the local_ptr in our instance(). + if (getName().empty()) + { + // Our Stop exception and its subclasses are intended to stop loitering + // coroutines. Don't throw it from the main coroutine. + return; + } + if (LLApp::isStopped()) + { + LLTHROW(Stopped("viewer is stopped")); + } + if (! LLApp::isRunning()) + { + LLTHROW(Stopping("viewer is stopping")); + } +} + +LLCoros::CoroData::CoroData(const std::string& name): + LLInstanceTracker<CoroData, std::string>(name), mName(name), - // Wrap the caller's callable in our toplevel() function so we can manage - // Current appropriately at startup and shutdown of each coroutine. - mCoro(boost::bind(toplevel, _1, this, callable), stacksize), // don't consume events unless specifically directed mConsuming(false), - mSelf(0), mCreationTime(LLTimer::getTotalSeconds()) { } -std::string LLCoros::launch(const std::string& prefix, const callable_t& callable) +LLCoros::CoroData::CoroData(int n): + // This constructor is used for the thread_local instance belonging to the + // default coroutine on each thread. We must give each one a different + // LLInstanceTracker key because LLInstanceTracker's map spans all + // threads, but we want the default coroutine on each thread to have the + // empty string as its visible name because some consumers test for that. + LLInstanceTracker<CoroData, std::string>("main" + stringize(n)), + mName(), + mConsuming(false), + mCreationTime(LLTimer::getTotalSeconds()) { - std::string name(generateDistinctName(prefix)); - Current current; - // pass the current value of Current as previous context - CoroData* newCoro = new(std::nothrow) CoroData(current, name, callable, mStackSize); - if (newCoro == NULL) - { - // Out of memory? - printActiveCoroutines(); - LL_ERRS("LLCoros") << "Failed to start coroutine: " << name << " Stacksize: " << mStackSize << " Total coroutines: " << mCoros.size() << LL_ENDL; - } - // Store it in our pointer map - mCoros.insert(name, newCoro); - // also set it as current - current.reset(newCoro); - /* Run the coroutine until its first wait, then return here */ - (newCoro->mCoro)(std::nothrow); - return name; } - -#if LL_MSVC -// reenable optimizations -#pragma optimize("", on) -#endif // LL_MSVC diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index c551413811..6c0bec3ef9 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -29,21 +29,26 @@ #if ! defined(LL_LLCOROS_H) #define LL_LLCOROS_H -#include <boost/dcoroutine/coroutine.hpp> -#include <boost/dcoroutine/future.hpp> +#include "llexception.h" +#include <boost/fiber/fss.hpp> +#include <boost/fiber/future/promise.hpp> +#include <boost/fiber/future/future.hpp> +#include "mutex.h" #include "llsingleton.h" -#include <boost/ptr_container/ptr_map.hpp> +#include "llinstancetracker.h" #include <boost/function.hpp> -#include <boost/thread/tss.hpp> -#include <boost/noncopyable.hpp> #include <string> -#include <stdexcept> -#include "llcoro_get_id.h" // for friend declaration -// forward-declare helper class -namespace llcoro -{ -class Suspending; +// e.g. #include LLCOROS_MUTEX_HEADER +#define LLCOROS_MUTEX_HEADER <boost/fiber/mutex.hpp> +#define LLCOROS_CONDVAR_HEADER <boost/fiber/condition_variable.hpp> + +namespace boost { + namespace fibers { + class mutex; + enum class cv_status; + class condition_variable; + } } /** @@ -76,19 +81,21 @@ class Suspending; * name prefix; from your prefix it generates a distinct name, registers the * new coroutine and returns the actual name. * - * The name can be used to kill off the coroutine prematurely, if needed. It - * can also provide diagnostic info: we can look up the name of the + * The name + * can provide diagnostic info: we can look up the name of the * currently-running coroutine. - * - * Finally, the next frame ("mainloop" event) after the coroutine terminates, - * LLCoros will notice its demise and destroy it. */ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros> { LLSINGLETON(LLCoros); + ~LLCoros(); public: - /// Canonical boost::dcoroutines::coroutine signature we use - typedef boost::dcoroutines::coroutine<void()> coro; + /// The viewer's use of the term "coroutine" became deeply embedded before + /// the industry term "fiber" emerged to distinguish userland threads from + /// simpler, more transient kinds of coroutines. Semantically they've + /// always been fibers. But at this point in history, we're pretty much + /// stuck with the term "coroutine." + typedef boost::fibers::fiber coro; /// Canonical callable type typedef boost::function<void()> callable_t; @@ -119,10 +126,10 @@ public: * DEV-32777 comments for an explanation. * * Pass a nullary callable. It works to directly pass a nullary free - * function (or static method); for all other cases use boost::bind(). Of - * course, for a non-static class method, the first parameter must be the - * class instance. Any other parameters should be passed via the bind() - * expression. + * function (or static method); for other cases use a lambda expression, + * std::bind() or boost::bind(). Of course, for a non-static class method, + * the first parameter must be the class instance. Any other parameters + * should be passed via the enclosing expression. * * launch() tweaks the suggested name so it won't collide with any * existing coroutine instance, creates the coroutine instance, registers @@ -138,7 +145,7 @@ public: * one prematurely. Returns @c true if the specified name was found and * still running at the time. */ - bool kill(const std::string& name); +// bool kill(const std::string& name); /** * From within a coroutine, look up the (tweaked) name string by which @@ -146,16 +153,27 @@ public: * (e.g. if the coroutine was launched by hand rather than using * LLCoros::launch()). */ - std::string getName() const; + static std::string getName(); - /// for delayed initialization + /** + * This variation returns a name suitable for log messages: the explicit + * name for an explicitly-launched coroutine, or "mainN" for the default + * coroutine on a thread. + */ + static std::string logname(); + + /** + * For delayed initialization. To be clear, this will only affect + * coroutines launched @em after this point. The underlying facility + * provides no way to alter the stack size of any running coroutine. + */ void setStackSize(S32 stacksize); - /// for delayed initialization - void printActiveCoroutines(); + /// diagnostic + void printActiveCoroutines(const std::string& when=std::string()); - /// get the current coro::self& for those who really really care - static coro::self& get_self(); + /// get the current coro::id for those who really really care + static coro::id get_self(); /** * Most coroutines, most of the time, don't "consume" the events for which @@ -180,6 +198,7 @@ public: { set_consuming(consuming); } + OverrideConsuming(const OverrideConsuming&) = delete; ~OverrideConsuming() { set_consuming(mPrevConsuming); @@ -189,142 +208,125 @@ public: bool mPrevConsuming; }; + /// set string coroutine status for diagnostic purposes + static void setStatus(const std::string& status); + static std::string getStatus(); + + /// RAII control of status + class TempStatus + { + public: + TempStatus(const std::string& status): + mOldStatus(getStatus()) + { + setStatus(status); + } + TempStatus(const TempStatus&) = delete; + ~TempStatus() + { + setStatus(mOldStatus); + } + + private: + std::string mOldStatus; + }; + + /// thrown by checkStop() + // It may sound ironic that Stop is derived from LLContinueError, but the + // point is that LLContinueError is the category of exception that should + // not immediately crash the viewer. Stop and its subclasses are to notify + // coroutines that the viewer intends to shut down. The expected response + // is to terminate the coroutine, rather than abort the viewer. + struct Stop: public LLContinueError + { + Stop(const std::string& what): LLContinueError(what) {} + }; + + /// early stages + struct Stopping: public Stop + { + Stopping(const std::string& what): Stop(what) {} + }; + + /// cleaning up + struct Stopped: public Stop + { + Stopped(const std::string& what): Stop(what) {} + }; + + /// cleaned up -- not much survives! + struct Shutdown: public Stop + { + Shutdown(const std::string& what): Stop(what) {} + }; + + /// Call this intermittently if there's a chance your coroutine might + /// continue running into application shutdown. Throws Stop if LLCoros has + /// been cleaned up. + static void checkStop(); + /** - * Please do NOT directly use boost::dcoroutines::future! It is essential - * to maintain the "current" coroutine at every context switch. This - * Future wraps the essential boost::dcoroutines::future functionality - * with that maintenance. + * Aliases for promise and future. An older underlying future implementation + * required us to wrap future; that's no longer needed. However -- if it's + * important to restore kill() functionality, we might need to provide a + * proxy, so continue using the aliases. */ template <typename T> - class Future; + using Promise = boost::fibers::promise<T>; + template <typename T> + using Future = boost::fibers::future<T>; + template <typename T> + static Future<T> getFuture(Promise<T>& promise) { return promise.get_future(); } + + // use mutex, lock, condition_variable suitable for coroutines + using Mutex = boost::fibers::mutex; + using LockType = std::unique_lock<Mutex>; + using cv_status = boost::fibers::cv_status; + using ConditionVariable = boost::fibers::condition_variable; + + /// for data local to each running coroutine + template <typename T> + using local_ptr = boost::fibers::fiber_specific_ptr<T>; private: - friend class llcoro::Suspending; - friend llcoro::id llcoro::get_id(); std::string generateDistinctName(const std::string& prefix) const; - bool cleanup(const LLSD&); - struct CoroData; - static void no_cleanup(CoroData*); #if LL_WINDOWS - static void winlevel(const callable_t& callable); + void winlevel(const std::string& name, const callable_t& callable); #endif - static void toplevel(coro::self& self, CoroData* data, const callable_t& callable); + void toplevelTryWrapper(const std::string& name, const callable_t& callable); + void toplevel(std::string name, callable_t callable); + struct CoroData; static CoroData& get_CoroData(const std::string& caller); S32 mStackSize; // coroutine-local storage, as it were: one per coro we track - struct CoroData + struct CoroData: public LLInstanceTracker<CoroData, std::string> { - CoroData(CoroData* prev, const std::string& name, - const callable_t& callable, S32 stacksize); - - // The boost::dcoroutines library supports asymmetric coroutines. Every - // time we context switch out of a coroutine, we pass control to the - // previously-active one (or to the non-coroutine stack owned by the - // thread). So our management of the "current" coroutine must be able to - // restore the previous value when we're about to switch away. - CoroData* mPrev; + CoroData(const std::string& name); + CoroData(int n); + // tweaked name of the current coroutine const std::string mName; - // the actual coroutine instance - LLCoros::coro mCoro; // set_consuming() state bool mConsuming; - // When the dcoroutine library calls a top-level callable, it implicitly - // passes coro::self& as the first parameter. All our consumer code used - // to explicitly pass coro::self& down through all levels of call stack, - // because at the leaf level we need it for context-switching. But since - // coroutines are based on cooperative switching, we can cause the - // top-level entry point to stash a pointer to the currently-running - // coroutine, and manage it appropriately as we switch out and back in. - // That eliminates the need to pass it as an explicit parameter down - // through every level, which is unfortunately viral in nature. Finding it - // implicitly rather than explicitly allows minor maintenance in which a - // leaf-level function adds a new async I/O call that suspends the calling - // coroutine, WITHOUT having to propagate coro::self& through every - // function signature down to that point -- and of course through every - // other caller of every such function. - LLCoros::coro::self* mSelf; + // setStatus() state + std::string mStatus; F64 mCreationTime; // since epoch }; - typedef boost::ptr_map<std::string, CoroData> CoroMap; - CoroMap mCoros; - // Identify the current coroutine's CoroData. Use a little helper class so - // a caller can either use a temporary instance, or instantiate a named - // variable and access it multiple times. - class Current - { - public: - Current(); - - operator LLCoros::CoroData*() { return get(); } - LLCoros::CoroData* operator->() { return get(); } - LLCoros::CoroData* get() { return mCurrent->get(); } - void reset(LLCoros::CoroData* ptr) { mCurrent->reset(ptr); } - - private: - boost::thread_specific_ptr<LLCoros::CoroData>* mCurrent; - }; + // Identify the current coroutine's CoroData. This local_ptr isn't static + // because it's a member of an LLSingleton, and we rely on it being + // cleaned up in proper dependency order. + local_ptr<CoroData> mCurrent; }; namespace llcoro { -/// Instantiate one of these in a block surrounding any leaf point when -/// control literally switches away from this coroutine. -class Suspending: boost::noncopyable -{ -public: - Suspending(); - ~Suspending(); - -private: - LLCoros::CoroData* mSuspended; -}; - -} // namespace llcoro - -template <typename T> -class LLCoros::Future -{ - typedef boost::dcoroutines::future<T> dfuture; +inline +std::string logname() { return LLCoros::logname(); } -public: - Future(): - mFuture(get_self()) - {} - - typedef typename boost::dcoroutines::make_callback_result<dfuture>::type callback_t; - - callback_t make_callback() - { - return boost::dcoroutines::make_callback(mFuture); - } - -#ifndef LL_LINUX - explicit -#endif - operator bool() const - { - return bool(mFuture); - } - - bool operator!() const - { - return ! mFuture; - } - - T get() - { - // instantiate Suspending to manage the "current" coroutine - llcoro::Suspending suspended; - return *mFuture; - } - -private: - dfuture mFuture; -}; +} // llcoro #endif /* ! defined(LL_LLCOROS_H) */ diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 335a0995fe..8355df9045 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -39,6 +39,9 @@ #if !LL_WINDOWS # include <syslog.h> # include <unistd.h> +# include <sys/stat.h> +#else +# include <io.h> #endif // !LL_WINDOWS #include <vector> #include "string.h" @@ -53,6 +56,13 @@ #include "llstl.h" #include "lltimer.h" +// On Mac, got: +// #error "Boost.Stacktrace requires `_Unwind_Backtrace` function. Define +// `_GNU_SOURCE` macro or `BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED` if +// _Unwind_Backtrace is available without `_GNU_SOURCE`." +#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED +#include <boost/stacktrace.hpp> + namespace { #if LL_WINDOWS void debugger_print(const std::string& s) @@ -118,27 +128,28 @@ namespace { class RecordToFile : public LLError::Recorder { public: - RecordToFile(const std::string& filename) + RecordToFile(const std::string& filename): + mName(filename) { mFile.open(filename.c_str(), std::ios_base::out | std::ios_base::app); if (!mFile) { LL_INFOS() << "Error setting log file to " << filename << LL_ENDL; } - else - { - if (!LLError::getAlwaysFlush()) - { - mFile.sync_with_stdio(false); - } - } + else + { + if (!LLError::getAlwaysFlush()) + { + mFile.sync_with_stdio(false); + } + } } - + ~RecordToFile() { mFile.close(); } - + virtual bool enabled() override { #ifdef LL_RELEASE_FOR_DOWNLOAD @@ -148,11 +159,13 @@ namespace { #endif } - bool okay() { return mFile.good(); } - - virtual void recordMessage(LLError::ELevel level, - const std::string& message) override - { + bool okay() const { return mFile.good(); } + + std::string getFilename() const { return mName; } + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) override + { if (LLError::getAlwaysFlush()) { mFile << message << std::endl; @@ -161,9 +174,10 @@ namespace { { mFile << message << "\n"; } - } - + } + private: + const std::string mName; llofstream mFile; }; @@ -171,7 +185,7 @@ namespace { class RecordToStderr : public LLError::Recorder { public: - RecordToStderr(bool timestamp) : mUseANSI(ANSI_PROBE) + RecordToStderr(bool timestamp) : mUseANSI(checkANSI()) { this->showMultiline(true); } @@ -181,59 +195,55 @@ namespace { return LLError::getEnabledLogTypesMask() & 0x04; } + LL_FORCE_INLINE std::string createANSI(const std::string& color) + { + std::string ansi_code; + ansi_code += '\033'; + ansi_code += "["; + ansi_code += color; + ansi_code += "m"; + return ansi_code; + } + virtual void recordMessage(LLError::ELevel level, const std::string& message) override { - if (ANSI_PROBE == mUseANSI) - mUseANSI = (checkANSI() ? ANSI_YES : ANSI_NO); + static std::string s_ansi_error = createANSI("31"); // red + static std::string s_ansi_warn = createANSI("34"); // blue + static std::string s_ansi_debug = createANSI("35"); // magenta - if (ANSI_YES == mUseANSI) + if (mUseANSI) { - // Default all message levels to bold so we can distinguish our own messages from those dumped by subprocesses and libraries. - colorANSI("1"); // bold - switch (level) { - case LLError::LEVEL_ERROR: - colorANSI("31"); // red - break; - case LLError::LEVEL_WARN: - colorANSI("34"); // blue - break; - case LLError::LEVEL_DEBUG: - colorANSI("35"); // magenta - break; - default: - break; - } + writeANSI((level == LLError::LEVEL_ERROR) ? s_ansi_error : + (level == LLError::LEVEL_WARN) ? s_ansi_warn : + s_ansi_debug, message); } - fprintf(stderr, "%s\n", message.c_str()); - if (ANSI_YES == mUseANSI) colorANSI("0"); // reset + else + { + fprintf(stderr, "%s\n", message.c_str()); + } } private: - enum ANSIState - { - ANSI_PROBE, - ANSI_YES, - ANSI_NO - } mUseANSI; + bool mUseANSI; - void colorANSI(const std::string color) + LL_FORCE_INLINE void writeANSI(const std::string& ansi_code, const std::string& message) { - // ANSI color code escape sequence - fprintf(stderr, "\033[%sm", color.c_str() ); - }; + static std::string s_ansi_bold = createANSI("1"); // bold + static std::string s_ansi_reset = createANSI("0"); // reset + // ANSI color code escape sequence, message, and reset in one fprintf call + // Default all message levels to bold so we can distinguish our own messages from those dumped by subprocesses and libraries. + fprintf(stderr, "%s%s%s\n%s", s_ansi_bold.c_str(), ansi_code.c_str(), message.c_str(), s_ansi_reset.c_str() ); + } - bool checkANSI(void) + static bool checkANSI(void) { -#if LL_LINUX || LL_DARWIN // Check whether it's okay to use ANSI; if stderr is // a tty then we assume yes. Can be turned off with // the LL_NO_ANSI_COLOR env var. return (0 != isatty(2)) && (NULL == getenv("LL_NO_ANSI_COLOR")); -#endif // LL_LINUX - return false; - }; + } }; class RecordToFixedBuffer : public LLError::Recorder @@ -302,28 +312,32 @@ namespace LLError { #ifdef __GNUC__ // 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 + // 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(mangled, nullptr, 0, &status); - std::string result(name ? name : mangled); - free(name); - return result; -#elif LL_WINDOWS - // DevStudio: type_info::name() includes the text "class " at the start + std::string result(name ? name : mangled); + free(name); + return result; - static const std::string class_prefix = "class "; +#elif LL_WINDOWS + // Visual Studio: type_info::name() includes the text "class " at the start std::string name = mangled; - if (0 != name.compare(0, class_prefix.length(), class_prefix)) + for (const auto& prefix : std::vector<std::string>{ "class ", "struct " }) { - LL_DEBUGS() << "Did not see '" << class_prefix << "' prefix on '" - << name << "'" << LL_ENDL; - return name; + if (0 == name.compare(0, prefix.length(), prefix)) + { + return name.substr(prefix.length()); + } } - - return name.substr(class_prefix.length()); - -#else + // huh, that's odd, we should see one or the other prefix -- but don't + // try to log unless logging is already initialized + // in Python, " or ".join(vector) -- but in C++, a PITB + LL_DEBUGS() << "Did not see 'class' or 'struct' prefix on '" + << name << "'" << LL_ENDL; + return name; + +#else // neither GCC nor Visual Studio return mangled; #endif } @@ -402,7 +416,7 @@ namespace return false; } - if (configuration.isUndefined() || !configuration.isMap() || configuration.emptyMap()) + if (! configuration || !configuration.isMap()) { LL_WARNS() << filename() << " missing, ill-formed, or simply undefined" " content; not changing configuration" @@ -421,12 +435,13 @@ namespace typedef std::vector<LLError::RecorderPtr> Recorders; typedef std::vector<LLError::CallSite*> CallSiteVector; - class Globals : public LLSingleton<Globals> + class Globals { - LLSINGLETON(Globals); + public: + static Globals* getInstance(); + protected: + Globals(); public: - std::ostringstream messageStream; - bool messageStreamInUse; std::string mFatalMessage; void addCallSite(LLError::CallSite&); @@ -436,12 +451,17 @@ namespace CallSiteVector callSites; }; - Globals::Globals() - : messageStream(), - messageStreamInUse(false), - callSites() - { - } + Globals::Globals() {} + + Globals* Globals::getInstance() + { + // According to C++11 Function-Local Initialization + // of static variables is supposed to be thread safe + // without risk of deadlocks. + static Globals inst; + + return &inst; + } void Globals::addCallSite(LLError::CallSite& site) { @@ -484,28 +504,28 @@ namespace LLError LLError::FatalFunction mCrashFunction; LLError::TimeFunction mTimeFunction; - + Recorders mRecorders; - RecorderPtr mFileRecorder; - RecorderPtr mFixedBufferRecorder; - std::string mFileRecorderFileName; - - int mShouldLogCallCounter; - + + int mShouldLogCallCounter; + private: SettingsConfig(); }; typedef LLPointer<SettingsConfig> SettingsConfigPtr; - class Settings : public LLSingleton<Settings> + class Settings { - LLSINGLETON(Settings); + public: + static Settings* getInstance(); + protected: + Settings(); public: SettingsConfigPtr getSettingsConfig(); void reset(); - SettingsStoragePtr saveAndReset(); + SettingsStoragePtr saveAndReset(); void restore(SettingsStoragePtr pSettingsStorage); private: @@ -522,12 +542,9 @@ namespace LLError mFileLevelMap(), mTagLevelMap(), mUniqueLogMessages(), - mCrashFunction(NULL), + mCrashFunction([](const std::string&){}), mTimeFunction(NULL), mRecorders(), - mFileRecorder(), - mFixedBufferRecorder(), - mFileRecorderFileName(), mShouldLogCallCounter(0) { } @@ -542,6 +559,16 @@ namespace LLError { } + Settings* Settings::getInstance() + { + // According to C++11 Function-Local Initialization + // of static variables is supposed to be thread safe + // without risk of deadlocks. + static Settings inst; + + return &inst; + } + SettingsConfigPtr Settings::getSettingsConfig() { return mSettingsConfig; @@ -566,11 +593,6 @@ namespace LLError SettingsConfigPtr newSettingsConfig(dynamic_cast<SettingsConfig *>(pSettingsStorage.get())); mSettingsConfig = newSettingsConfig; } - - bool is_available() - { - return Settings::instanceExists() && Globals::instanceExists(); - } } namespace LLError @@ -650,22 +672,38 @@ namespace LLError namespace { - bool shouldLogToStderr() - { + bool shouldLogToStderr() + { #if LL_DARWIN - // On Mac OS X, stderr from apps launched from the Finder goes to the - // console log. It's generally considered bad form to spam too much - // there. - - // If stdin is a tty, assume the user launched from the command line and - // therefore wants to see stderr. Otherwise, assume we've been launched - // from the finder and shouldn't spam stderr. - return isatty(0); + // On Mac OS X, stderr from apps launched from the Finder goes to the + // console log. It's generally considered bad form to spam too much + // there. That scenario can be detected by noticing that stderr is a + // character device (S_IFCHR). + + // If stderr is a tty or a pipe, assume the user launched from the + // command line or debugger and therefore wants to see stderr. + if (isatty(STDERR_FILENO)) + return true; + // not a tty, but might still be a pipe -- check + struct stat st; + if (fstat(STDERR_FILENO, &st) < 0) + { + // capture errno right away, before engaging any other operations + auto errno_save = errno; + // this gets called during log-system setup -- can't log yet! + std::cerr << "shouldLogToStderr: fstat(" << STDERR_FILENO << ") failed, errno " + << errno_save << std::endl; + // if we can't tell, err on the safe side and don't write stderr + return false; + } + + // fstat() worked: return true only if stderr is a pipe + return ((st.st_mode & S_IFMT) == S_IFIFO); #else - return true; + return true; #endif - } - + } + bool stderrLogWantsTime() { #if LL_WINDOWS @@ -679,20 +717,18 @@ namespace void commonInit(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr = true) { LLError::Settings::getInstance()->reset(); - + LLError::setDefaultLevel(LLError::LEVEL_INFO); - LLError::setAlwaysFlush(true); - LLError::setEnabledLogTypesMask(0xFFFFFFFF); - LLError::setFatalFunction(LLError::crashAndLoop); + LLError::setAlwaysFlush(true); + LLError::setEnabledLogTypesMask(0xFFFFFFFF); LLError::setTimeFunction(LLError::utcTime); // log_to_stderr is only false in the unit and integration tests to keep builds quieter if (log_to_stderr && shouldLogToStderr()) { - LLError::RecorderPtr recordToStdErr(new RecordToStderr(stderrLogWantsTime())); - LLError::addRecorder(recordToStdErr); + LLError::logToStderr(); } - + #if LL_WINDOWS LLError::RecorderPtr recordToWinDebug(new RecordToWinDebug()); LLError::addRecorder(recordToWinDebug); @@ -990,49 +1026,110 @@ namespace LLError s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder), s->mRecorders.end()); } + + // Find an entry in SettingsConfig::mRecorders whose RecorderPtr points to + // a Recorder subclass of type RECORDER. Return, not a RecorderPtr (which + // points to the Recorder base class), but a shared_ptr<RECORDER> which + // specifically points to the concrete RECORDER subclass instance, along + // with a Recorders::iterator indicating the position of that entry in + // mRecorders. The shared_ptr might be empty (operator!() returns true) if + // there was no such RECORDER subclass instance in mRecorders. + template <typename RECORDER> + std::pair<boost::shared_ptr<RECORDER>, Recorders::iterator> + findRecorderPos() + { + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + // Since we promise to return an iterator, use a classic iterator + // loop. + auto end{s->mRecorders.end()}; + for (Recorders::iterator it{s->mRecorders.begin()}; it != end; ++it) + { + // *it is a RecorderPtr, a shared_ptr<Recorder>. Use a + // dynamic_pointer_cast to try to downcast to test if it's also a + // shared_ptr<RECORDER>. + auto ptr = boost::dynamic_pointer_cast<RECORDER>(*it); + if (ptr) + { + // found the entry we want + return { ptr, it }; + } + } + // dropped out of the loop without finding any such entry -- instead + // of default-constructing Recorders::iterator (which might or might + // not be valid), return a value that is valid but not dereferenceable. + return { {}, end }; + } + + // Find an entry in SettingsConfig::mRecorders whose RecorderPtr points to + // a Recorder subclass of type RECORDER. Return, not a RecorderPtr (which + // points to the Recorder base class), but a shared_ptr<RECORDER> which + // specifically points to the concrete RECORDER subclass instance. The + // shared_ptr might be empty (operator!() returns true) if there was no + // such RECORDER subclass instance in mRecorders. + template <typename RECORDER> + boost::shared_ptr<RECORDER> findRecorder() + { + return findRecorderPos<RECORDER>().first; + } + + // Remove an entry from SettingsConfig::mRecorders whose RecorderPtr + // points to a Recorder subclass of type RECORDER. Return true if there + // was one and we removed it, false if there wasn't one to start with. + template <typename RECORDER> + bool removeRecorder() + { + auto found = findRecorderPos<RECORDER>(); + if (found.first) + { + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + s->mRecorders.erase(found.second); + } + return bool(found.first); + } } namespace LLError { void logToFile(const std::string& file_name) { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + // remove any previous Recorder filling this role + removeRecorder<RecordToFile>(); - removeRecorder(s->mFileRecorder); - s->mFileRecorder.reset(); - s->mFileRecorderFileName.clear(); - if (!file_name.empty()) { - RecorderPtr recordToFile(new RecordToFile(file_name)); - if (boost::dynamic_pointer_cast<RecordToFile>(recordToFile)->okay()) - { - s->mFileRecorderFileName = file_name; - s->mFileRecorder = recordToFile; - addRecorder(recordToFile); - } + boost::shared_ptr<RecordToFile> recordToFile(new RecordToFile(file_name)); + if (recordToFile->okay()) + { + addRecorder(recordToFile); + } } } - - void logToFixedBuffer(LLLineBuffer* fixedBuffer) + + std::string logFileName() { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + auto found = findRecorder<RecordToFile>(); + return found? found->getFilename() : std::string(); + } - removeRecorder(s->mFixedBufferRecorder); - s->mFixedBufferRecorder.reset(); - - if (fixedBuffer) - { - RecorderPtr recordToFixedBuffer(new RecordToFixedBuffer(fixedBuffer)); - s->mFixedBufferRecorder = recordToFixedBuffer; - addRecorder(recordToFixedBuffer); + void logToStderr() + { + if (! findRecorder<RecordToStderr>()) + { + RecorderPtr recordToStdErr(new RecordToStderr(stderrLogWantsTime())); + addRecorder(recordToStdErr); } - } + } - std::string logFileName() + void logToFixedBuffer(LLLineBuffer* fixedBuffer) { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); - return s->mFileRecorderFileName; + // remove any previous Recorder filling this role + removeRecorder<RecordToFixedBuffer>(); + + if (fixedBuffer) + { + RecorderPtr recordToFixedBuffer(new RecordToFixedBuffer(fixedBuffer)); + addRecorder(recordToFixedBuffer); + } } } @@ -1148,8 +1245,25 @@ namespace } namespace { - LLMutex gLogMutex; - LLMutex gCallStacksLogMutex; + // We need a couple different mutexes, but we want to use the same mechanism + // for both. Make getMutex() a template function with different instances + // for different MutexDiscriminator values. + enum MutexDiscriminator + { + LOG_MUTEX, + STACKS_MUTEX + }; + // Some logging calls happen very early in processing -- so early that our + // module-static variables aren't yet initialized. getMutex() wraps a + // function-static LLMutex so that early calls can still have a valid + // LLMutex instance. + template <MutexDiscriminator MTX> + LLMutex* getMutex() + { + // guaranteed to be initialized the first time control reaches here + static LLMutex sMutex; + return &sMutex; + } bool checkLevelMap(const LevelMap& map, const std::string& key, LLError::ELevel& level) @@ -1197,20 +1311,12 @@ namespace LLError bool Log::shouldLog(CallSite& site) { - LLMutexTrylock lock(&gLogMutex, 5); + LLMutexTrylock lock(getMutex<LOG_MUTEX>(), 5); if (!lock.isLocked()) { return false; } - // If we hit a logging request very late during shutdown processing, - // when either of the relevant LLSingletons has already been deleted, - // DO NOT resurrect them. - if (Settings::wasDeleted() || Globals::wasDeleted()) - { - return false; - } - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); s->mShouldLogCallCounter++; @@ -1246,101 +1352,22 @@ namespace LLError } - std::ostringstream* Log::out() - { - LLMutexTrylock lock(&gLogMutex,5); - // If we hit a logging request very late during shutdown processing, - // when either of the relevant LLSingletons has already been deleted, - // DO NOT resurrect them. - if (lock.isLocked() && ! (Settings::wasDeleted() || Globals::wasDeleted())) - { - Globals* g = Globals::getInstance(); - - if (!g->messageStreamInUse) - { - g->messageStreamInUse = true; - return &g->messageStream; - } - } - - return new std::ostringstream; - } - - void Log::flush(std::ostringstream* out, char* message) + void Log::flush(const std::ostringstream& out, const CallSite& site) { - LLMutexTrylock lock(&gLogMutex,5); + LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5); if (!lock.isLocked()) { return; } - // If we hit a logging request very late during shutdown processing, - // when either of the relevant LLSingletons has already been deleted, - // DO NOT resurrect them. - if (Settings::wasDeleted() || Globals::wasDeleted()) - { - return; - } - - if(strlen(out->str().c_str()) < 128) - { - strcpy(message, out->str().c_str()); - } - else - { - strncpy(message, out->str().c_str(), 127); - message[127] = '\0' ; - } - - Globals* g = Globals::getInstance(); - if (out == &g->messageStream) - { - g->messageStream.clear(); - g->messageStream.str(""); - g->messageStreamInUse = false; - } - else - { - delete out; - } - return ; - } - - void Log::flush(std::ostringstream* out, const CallSite& site) - { - LLMutexTrylock lock(&gLogMutex,5); - if (!lock.isLocked()) - { - return; - } - - // If we hit a logging request very late during shutdown processing, - // when either of the relevant LLSingletons has already been deleted, - // DO NOT resurrect them. - if (Settings::wasDeleted() || Globals::wasDeleted()) - { - return; - } - Globals* g = Globals::getInstance(); SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); - std::string message = out->str(); - if (out == &g->messageStream) - { - g->messageStream.clear(); - g->messageStream.str(""); - g->messageStreamInUse = false; - } - else - { - delete out; - } - + std::string message = out.str(); if (site.mPrintOnce) { - std::ostringstream message_stream; + std::ostringstream message_stream; std::map<std::string, unsigned int>::iterator messageIter = s->mUniqueLogMessages.find(message); if (messageIter != s->mUniqueLogMessages.end()) @@ -1361,8 +1388,8 @@ namespace LLError message_stream << "ONCE: "; s->mUniqueLogMessages[message] = 1; } - message_stream << message; - message = message_stream.str(); + message_stream << message; + message = message_stream.str(); } writeToRecorders(site, message); @@ -1370,10 +1397,7 @@ namespace LLError if (site.mLevel == LEVEL_ERROR) { g->mFatalMessage = message; - if (s->mCrashFunction) - { - s->mCrashFunction(message); - } + s->mCrashFunction(message); } } } @@ -1437,29 +1461,6 @@ namespace LLError return s->mShouldLogCallCounter; } -#if LL_WINDOWS - // VC80 was optimizing the error away. - #pragma optimize("", off) -#endif - void crashAndLoop(const std::string& message) - { - // Now, we go kaboom! - int* make_me_crash = NULL; - - *make_me_crash = 0; - - while(true) - { - // Loop forever, in case the crash didn't work? - } - - // this is an attempt to let Coverity and other semantic scanners know that this function won't be returning ever. - exit(EXIT_FAILURE); - } -#if LL_WINDOWS - #pragma optimize("", on) -#endif - std::string utcTime() { time_t now = time(NULL); @@ -1476,133 +1477,94 @@ namespace LLError namespace LLError { - char** LLCallStacks::sBuffer = NULL ; - S32 LLCallStacks::sIndex = 0 ; - - //static - void LLCallStacks::allocateStackBuffer() - { - 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 ; - } - } - - void LLCallStacks::freeStackBuffer() - { - if(sBuffer != NULL) - { - delete [] sBuffer[0] ; - delete [] sBuffer ; - sBuffer = NULL ; - } - } - - //static - void LLCallStacks::push(const char* function, const int line) - { - LLMutexTrylock lock(&gCallStacksLogMutex, 5); - if (!lock.isLocked()) - { - return; - } - - if(sBuffer == NULL) - { - allocateStackBuffer(); - } - - if(sIndex > 511) - { - clear() ; - } - - strcpy(sBuffer[sIndex], function) ; - sprintf(sBuffer[sIndex] + strlen(function), " line: %d ", line) ; - sIndex++ ; - - return ; - } - - //static - std::ostringstream* LLCallStacks::insert(const char* function, const int line) - { - std::ostringstream* _out = LLError::Log::out(); - *_out << function << " line " << line << " " ; - - return _out ; - } - - //static - void LLCallStacks::end(std::ostringstream* _out) - { - LLMutexTrylock lock(&gCallStacksLogMutex, 5); - if (!lock.isLocked()) - { - return; - } - - if(sBuffer == NULL) - { - allocateStackBuffer(); - } - - if(sIndex > 511) - { - clear() ; - } - - LLError::Log::flush(_out, sBuffer[sIndex++]) ; - } - - //static - void LLCallStacks::print() - { - LLMutexTrylock lock(&gCallStacksLogMutex, 5); - if (!lock.isLocked()) - { - return; - } - - if(sIndex > 0) - { - LL_INFOS() << " ************* PRINT OUT LL CALL STACKS ************* " << LL_ENDL; - while(sIndex > 0) - { - sIndex-- ; - LL_INFOS() << sBuffer[sIndex] << LL_ENDL; - } - LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL; - } - - if(sBuffer != NULL) - { - freeStackBuffer(); - } - } - - //static - void LLCallStacks::clear() - { - sIndex = 0 ; - } - - //static - void LLCallStacks::cleanup() - { - freeStackBuffer(); - } + LLCallStacks::StringVector LLCallStacks::sBuffer ; + + //static + void LLCallStacks::push(const char* function, const int line) + { + LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5); + if (!lock.isLocked()) + { + return; + } + + if(sBuffer.size() > 511) + { + clear() ; + } + + std::ostringstream out; + insert(out, function, line); + sBuffer.push_back(out.str()); + } + + //static + void LLCallStacks::insert(std::ostream& out, const char* function, const int line) + { + out << function << " line " << line << " " ; + } + + //static + void LLCallStacks::end(const std::ostringstream& out) + { + LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5); + if (!lock.isLocked()) + { + return; + } + + if(sBuffer.size() > 511) + { + clear() ; + } + + sBuffer.push_back(out.str()); + } + + //static + void LLCallStacks::print() + { + LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5); + if (!lock.isLocked()) + { + return; + } + + if(! sBuffer.empty()) + { + LL_INFOS() << " ************* PRINT OUT LL CALL STACKS ************* " << LL_ENDL; + for (StringVector::const_reverse_iterator ri(sBuffer.rbegin()), re(sBuffer.rend()); + ri != re; ++ri) + { + LL_INFOS() << (*ri) << LL_ENDL; + } + LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL; + } + + cleanup(); + } + + //static + void LLCallStacks::clear() + { + sBuffer.clear(); + } + + //static + void LLCallStacks::cleanup() + { + clear(); + } + + std::ostream& operator<<(std::ostream& out, const LLStacktrace&) + { + return out << boost::stacktrace::stacktrace(); + } } bool debugLoggingEnabled(const std::string& tag) { - LLMutexTrylock lock(&gLogMutex, 5); + LLMutexTrylock lock(getMutex<LOG_MUTEX>(), 5); if (!lock.isLocked()) { return false; diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 0a78229555..d439136ca8 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -29,7 +29,9 @@ #define LL_LLERROR_H #include <sstream> +#include <string> #include <typeinfo> +#include <vector> #include "stdtypes.h" @@ -191,19 +193,26 @@ namespace LLError The classes CallSite and Log are used by the logging macros below. They are not intended for general use. */ - + 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*, const CallSite&); + static void flush(const std::ostringstream&, const CallSite&); static std::string demangle(const char* mangled); + /// classname<TYPE>() + template <typename T> + static std::string classname() { return demangle(typeid(T).name()); } + /// classname(some_pointer) + template <typename T> + static std::string classname(T* const ptr) { return ptr? demangle(typeid(*ptr).name()) : "nullptr"; } + /// classname(some_reference) + template <typename T> + static std::string classname(const T& obj) { return demangle(typeid(obj).name()); } }; - + struct LL_COMMON_API CallSite { // Represents a specific place in the code where a message is logged @@ -262,39 +271,43 @@ namespace LLError class LL_COMMON_API NoClassInfo { }; // used to indicate no class info known for logging - //LLCallStacks keeps track of call stacks and output the call stacks to log file - //when LLAppViewer::handleViewerCrash() is triggered. - // - //Note: to be simple, efficient and necessary to keep track of correct call stacks, - //LLCallStacks is designed not to be thread-safe. - //so try not to use it in multiple parallel threads at same time. - //Used in a single thread at a time is fine. - class LL_COMMON_API LLCallStacks - { - private: - static char** sBuffer ; - static S32 sIndex ; - - static void allocateStackBuffer(); - static void freeStackBuffer(); - - public: - static void push(const char* function, const int line) ; - static std::ostringstream* insert(const char* function, const int line) ; - static void print() ; - static void clear() ; - static void end(std::ostringstream* _out) ; - static void cleanup(); - }; + //LLCallStacks keeps track of call stacks and output the call stacks to log file + //when LLAppViewer::handleViewerCrash() is triggered. + // + //Note: to be simple, efficient and necessary to keep track of correct call stacks, + //LLCallStacks is designed not to be thread-safe. + //so try not to use it in multiple parallel threads at same time. + //Used in a single thread at a time is fine. + class LL_COMMON_API LLCallStacks + { + private: + typedef std::vector<std::string> StringVector; + static StringVector sBuffer ; + + public: + static void push(const char* function, const int line) ; + static void insert(std::ostream& out, const char* function, const int line) ; + static void print() ; + static void clear() ; + static void end(const std::ostringstream& out) ; + static void cleanup(); + }; + + // class which, when streamed, inserts the current stack trace + struct LLStacktrace + { + friend std::ostream& operator<<(std::ostream& out, const LLStacktrace&); + }; } //this is cheaper than llcallstacks if no need to output other variables to call stacks. #define LL_PUSH_CALLSTACKS() LLError::LLCallStacks::push(__FUNCTION__, __LINE__) -#define llcallstacks \ - { \ - std::ostringstream* _out = LLError::LLCallStacks::insert(__FUNCTION__, __LINE__) ; \ - (*_out) +#define llcallstacks \ + { \ + std::ostringstream _out; \ + LLError::LLCallStacks::insert(_out, __FUNCTION__, __LINE__) ; \ + _out #define llcallstacksendl \ LLError::End(); \ @@ -340,11 +353,11 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; static LLError::CallSite _site(lllog_site_args_(level, once, tags)); \ lllog_test_() -#define lllog_test_() \ - if (LL_UNLIKELY(_site.shouldLog())) \ - { \ - std::ostringstream* _out = LLError::Log::out(); \ - (*_out) +#define lllog_test_() \ + if (LL_UNLIKELY(_site.shouldLog())) \ + { \ + std::ostringstream _out; \ + _out #define lllog_site_args_(level, once, tags) \ level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), \ @@ -363,15 +376,27 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; // LL_CONT << " for " << t << " seconds" << LL_ENDL; // //Such computation is done iff the message will be logged. -#define LL_CONT (*_out) +#define LL_CONT _out #define LL_NEWLINE '\n' -#define LL_ENDL \ - LLError::End(); \ - LLError::Log::flush(_out, _site); \ - } \ - } while(0) +// Use this only in LL_ERRS or in a place that LL_ERRS may not be used +#define LLERROR_CRASH \ +{ \ + int* make_me_crash = NULL;\ + *make_me_crash = 0; \ + exit(*make_me_crash); \ +} + +#define LL_ENDL \ + LLError::End(); \ + LLError::Log::flush(_out, _site); \ + if (_site.mLevel == LLError::LEVEL_ERROR) \ + { \ + LLERROR_CRASH \ + } \ + } \ + } while(0) // NEW Macros for debugging, allow the passing of a string tag @@ -381,8 +406,13 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; #define LL_WARNS(...) lllog(LLError::LEVEL_WARN, false, ##__VA_ARGS__) #define LL_ERRS(...) lllog(LLError::LEVEL_ERROR, false, ##__VA_ARGS__) // alternative to llassert_always that prints explanatory message -#define LL_WARNS_IF(exp, ...) if (exp) LL_WARNS(##__VA_ARGS__) << "(" #exp ")" -#define LL_ERRS_IF(exp, ...) if (exp) LL_ERRS(##__VA_ARGS__) << "(" #exp ")" +// note ## token paste operator hack used above will only work in gcc following +// a comma and is completely unnecessary in VS since the comma is automatically +// suppressed +// https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html +// https://docs.microsoft.com/en-us/cpp/preprocessor/variadic-macros?view=vs-2015 +#define LL_WARNS_IF(exp, ...) if (exp) LL_WARNS(__VA_ARGS__) << "(" #exp ")" +#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). diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index 276d22fc36..e87bb7bf35 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -94,14 +94,16 @@ namespace LLError */ typedef boost::function<void(const std::string&)> FatalFunction; - LL_COMMON_API void crashAndLoop(const std::string& message); - // Default fatal function: access null pointer and loops forever LL_COMMON_API void setFatalFunction(const FatalFunction&); - // The fatal function will be called when an message of LEVEL_ERROR + // The fatal function will be called after an message of LEVEL_ERROR // is logged. Note: supressing a LEVEL_ERROR message from being logged // (by, for example, setting a class level to LEVEL_NONE), will keep - // the that message from causing the fatal funciton to be invoked. + // that message from causing the fatal function to be invoked. + // The passed FatalFunction will be the LAST log function called + // before LL_ERRS crashes its caller. A FatalFunction can throw an + // exception, or call exit(), to bypass the crash. It MUST disrupt the + // flow of control because no caller expects LL_ERRS to return. LL_COMMON_API FatalFunction getFatalFunction(); // Retrieve the previously-set FatalFunction @@ -147,14 +149,14 @@ namespace LLError virtual void recordMessage(LLError::ELevel, const std::string& message) = 0; // use the level for better display, not for filtering - virtual bool enabled() { return true; } + virtual bool enabled() { return true; } bool wantsTime(); bool wantsTags(); bool wantsLevel(); bool wantsLocation(); bool wantsFunctionName(); - bool wantsMultiline(); + bool wantsMultiline(); void showTime(bool show); void showTags(bool show); @@ -165,15 +167,35 @@ namespace LLError protected: bool mWantsTime; - bool mWantsTags; - bool mWantsLevel; - bool mWantsLocation; - bool mWantsFunctionName; - bool mWantsMultiline; + bool mWantsTags; + bool mWantsLevel; + bool mWantsLocation; + bool mWantsFunctionName; + bool mWantsMultiline; }; typedef boost::shared_ptr<Recorder> RecorderPtr; + /** + * Instantiate GenericRecorder with a callable(level, message) to get + * control on every log message without having to code an explicit + * Recorder subclass. + */ + template <typename CALLABLE> + class GenericRecorder: public Recorder + { + public: + GenericRecorder(const CALLABLE& callable): + mCallable(callable) + {} + void recordMessage(LLError::ELevel level, const std::string& message) override + { + mCallable(level, message); + } + private: + CALLABLE mCallable; + }; + /** * @NOTE: addRecorder() and removeRecorder() uses the boost::shared_ptr to allow for shared ownership * while still ensuring that the allocated memory is eventually freed @@ -181,8 +203,22 @@ namespace LLError LL_COMMON_API void addRecorder(RecorderPtr); LL_COMMON_API void removeRecorder(RecorderPtr); // each error message is passed to each recorder via recordMessage() + /** + * Call addGenericRecorder() with a callable(level, message) to get + * control on every log message without having to code an explicit + * Recorder subclass. Save the returned RecorderPtr if you later want to + * call removeRecorder(). + */ + template <typename CALLABLE> + RecorderPtr addGenericRecorder(const CALLABLE& callable) + { + RecorderPtr ptr{ new GenericRecorder<CALLABLE>(callable) }; + addRecorder(ptr); + return ptr; + } LL_COMMON_API void logToFile(const std::string& filename); + LL_COMMON_API void logToStderr(); LL_COMMON_API void logToFixedBuffer(LLLineBuffer*); // Utilities to add recorders for logging to a file or a fixed buffer // A second call to the same function will remove the logger added @@ -202,11 +238,6 @@ namespace LLError LL_COMMON_API std::string abbreviateFile(const std::string& filePath); LL_COMMON_API int shouldLogCallCount(); - - // Check whether Globals exists. This should only be used by LLSingleton - // infrastructure to avoid trying to log when our internal LLSingleton is - // unavailable -- circularity ensues. - LL_COMMON_API bool is_available(); }; #endif // LL_LLERRORCONTROL_H diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp index 56367b8f54..995356dc52 100644 --- a/indra/llcommon/lleventcoro.cpp +++ b/indra/llcommon/lleventcoro.cpp @@ -31,17 +31,17 @@ // associated header #include "lleventcoro.h" // STL headers -#include <map> +#include <chrono> +#include <exception> // std headers // external library headers +#include <boost/fiber/operations.hpp> // other Linden headers #include "llsdserialize.h" +#include "llsdutil.h" #include "llerror.h" #include "llcoros.h" -#include "llmake.h" -#include "llexception.h" - -#include "lleventfilter.h" +#include "stringize.h" namespace { @@ -62,7 +62,7 @@ namespace std::string listenerNameForCoro() { // If this coroutine was launched by LLCoros::launch(), find that name. - std::string name(LLCoros::instance().getName()); + std::string name(LLCoros::getName()); if (! name.empty()) { return name; @@ -92,137 +92,173 @@ std::string listenerNameForCoro() * In the degenerate case in which @a path is an empty array, @a dest will * @em become @a value rather than @em containing it. */ -void storeToLLSDPath(LLSD& dest, const LLSD& rawPath, const LLSD& value) +void storeToLLSDPath(LLSD& dest, const LLSD& path, const LLSD& value) { - if (rawPath.isUndefined()) + if (path.isUndefined()) { // no-op case return; } - // Arrange to treat rawPath uniformly as an array. If it's not already an - // array, store it as the only entry in one. - LLSD path; - if (rawPath.isArray()) - { - path = rawPath; - } - else - { - path.append(rawPath); - } - - // Need to indicate a current destination -- but that current destination - // needs to change as we step through the path array. Where normally we'd - // use an LLSD& to capture a subscripted LLSD lvalue, this time we must - // instead use a pointer -- since it must be reassigned. - LLSD* pdest = &dest; - - // Now loop through that array - for (LLSD::Integer i = 0; i < path.size(); ++i) - { - if (path[i].isString()) - { - // *pdest is an LLSD map - pdest = &((*pdest)[path[i].asString()]); - } - else if (path[i].isInteger()) - { - // *pdest is an LLSD array - pdest = &((*pdest)[path[i].asInteger()]); - } - else - { - // What do we do with Real or Array or Map or ...? - // As it's a coder error -- not a user error -- rub the coder's - // face in it so it gets fixed. - LL_ERRS("lleventcoro") << "storeToLLSDPath(" << dest << ", " << rawPath << ", " << value - << "): path[" << i << "] bad type " << path[i].type() << LL_ENDL; - } - } - - // Here *pdest is where we should store value. - *pdest = value; + // Drill down to where we should store 'value'. + llsd::drill(dest, path) = value; } -/// For LLCoros::Future<LLSD>::make_callback(), the callback has a signature -/// like void callback(LLSD), which isn't a valid LLEventPump listener: such -/// listeners must return bool. -template <typename LISTENER> -class FutureListener -{ -public: - // FutureListener is instantiated on the coroutine stack: the stack, in - // other words, that wants to suspend. - FutureListener(const LISTENER& listener): - mListener(listener), - // Capture the suspending coroutine's flag as a consuming or - // non-consuming listener. - mConsume(LLCoros::get_consuming()) - {} - - // operator()() is called on the main stack: the stack on which the - // expected event is fired. - bool operator()(const LLSD& event) - { - mListener(event); - // tell upstream LLEventPump whether listener consumed - return mConsume; - } - -protected: - LISTENER mListener; - bool mConsume; -}; - } // anonymous void llcoro::suspend() { - // By viewer convention, we post an event on the "mainloop" LLEventPump - // each iteration of the main event-handling loop. So waiting for a single - // event on "mainloop" gives us a one-frame suspend. - suspendUntilEventOn("mainloop"); + LLCoros::checkStop(); + LLCoros::TempStatus st("waiting one tick"); + boost::this_fiber::yield(); } void llcoro::suspendUntilTimeout(float seconds) { - LLEventTimeout timeout; - - timeout.eventAfter(seconds, LLSD()); - llcoro::suspendUntilEventOn(timeout); + LLCoros::checkStop(); + // We used to call boost::this_fiber::sleep_for(). But some coroutines + // (e.g. LLExperienceCache::idleCoro()) sit in a suspendUntilTimeout() + // loop, in which case a sleep_for() call risks sleeping through shutdown. + // So instead, listen for "LLApp" state-changing events -- which + // fortunately is handled for us by suspendUntilEventOnWithTimeout(). + // Wait for an event on a bogus LLEventPump on which nobody ever posts + // events. Don't make it static because that would force instantiation of + // the LLEventPumps LLSingleton registry at static initialization time. + // DO allow tweaking the name for uniqueness, this definitely gets + // re-entered on multiple coroutines! + // We could use an LLUUID if it were important to actively prohibit anyone + // from ever posting on this LLEventPump. + LLEventStream bogus("xyzzy", true); + // Timeout is the NORMAL case for this call! + static LLSD timedout; + // Deliver, but ignore, timedout when (as usual) we did not receive any + // "LLApp" event. The point is that suspendUntilEventOnWithTimeout() will + // itself throw Stopping when "LLApp" starts broadcasting shutdown events. + suspendUntilEventOnWithTimeout(bogus, seconds, timedout); } -LLSD llcoro::postAndSuspend(const LLSD& event, const LLEventPumpOrPumpName& requestPump, - const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath) +namespace { - // declare the future - LLCoros::Future<LLSD> future; - // make a callback that will assign a value to the future, and listen on - // the specified LLEventPump with that callback - std::string listenerName(listenerNameForCoro()); - LLTempBoundListener connection( - replyPump.getPump().listen(listenerName, - llmake<FutureListener>(future.make_callback()))); + +// returns a listener on replyPumpP, also on "mainloop" -- both should be +// stored in LLTempBoundListeners on the caller's stack frame +std::pair<LLBoundListener, LLBoundListener> +postAndSuspendSetup(const std::string& callerName, + const std::string& listenerName, + LLCoros::Promise<LLSD>& promise, + const LLSD& event, + const LLEventPumpOrPumpName& requestPumpP, + const LLEventPumpOrPumpName& replyPumpP, + const LLSD& replyPumpNamePath) +{ + // Before we get any farther -- should we be stopping instead of + // suspending? + LLCoros::checkStop(); + // Get the consuming attribute for THIS coroutine, the one that's about to + // suspend. Don't call get_consuming() in the lambda body: that would + // return the consuming attribute for some other coroutine, most likely + // the main routine. + bool consuming(LLCoros::get_consuming()); + // listen on the specified LLEventPump with a lambda that will assign a + // value to the promise, thus fulfilling its future + llassert_always_msg(replyPumpP, ("replyPump required for " + callerName)); + LLEventPump& replyPump(replyPumpP.getPump()); + // The relative order of the two listen() calls below would only matter if + // "LLApp" were an LLEventMailDrop. But if we ever go there, we'd want to + // notice the pending LLApp status first. + LLBoundListener stopper( + LLEventPumps::instance().obtain("LLApp").listen( + listenerName, + [&promise, listenerName](const LLSD& status) + { + // anything except "running" should wake up the waiting + // coroutine + auto& statsd = status["status"]; + if (statsd.asString() != "running") + { + LL_DEBUGS("lleventcoro") << listenerName + << " spotted status " << statsd + << ", throwing Stopping" << LL_ENDL; + try + { + promise.set_exception( + std::make_exception_ptr( + LLCoros::Stopping("status " + statsd.asString()))); + } + catch (const boost::fibers::promise_already_satisfied&) + { + LL_WARNS("lleventcoro") << listenerName + << " couldn't throw Stopping " + "because promise already set" << LL_ENDL; + } + } + // do not consume -- every listener must see status + return false; + })); + LLBoundListener connection( + replyPump.listen( + listenerName, + [&promise, consuming, listenerName](const LLSD& result) + { + try + { + promise.set_value(result); + // We did manage to propagate the result value to the + // (real) listener. If we're supposed to indicate that + // we've consumed it, do so. + return consuming; + } + catch(boost::fibers::promise_already_satisfied & ex) + { + LL_DEBUGS("lleventcoro") << "promise already satisfied in '" + << listenerName << "': " << ex.what() << LL_ENDL; + // We could not propagate the result value to the + // listener. + return false; + } + })); + // skip the "post" part if requestPump is default-constructed - if (requestPump) + if (requestPumpP) { + LLEventPump& requestPump(requestPumpP.getPump()); // If replyPumpNamePath is non-empty, store the replyPump name in the // request event. LLSD modevent(event); - storeToLLSDPath(modevent, replyPumpNamePath, replyPump.getPump().getName()); - LL_DEBUGS("lleventcoro") << "postAndSuspend(): coroutine " << listenerName - << " posting to " << requestPump.getPump().getName() + storeToLLSDPath(modevent, replyPumpNamePath, replyPump.getName()); + LL_DEBUGS("lleventcoro") << callerName << ": coroutine " << listenerName + << " posting to " << requestPump.getName() << LL_ENDL; // *NOTE:Mani - Removed because modevent could contain user's hashed passwd. // << ": " << modevent << LL_ENDL; - requestPump.getPump().post(modevent); + requestPump.post(modevent); } - LL_DEBUGS("lleventcoro") << "postAndSuspend(): coroutine " << listenerName - << " about to wait on LLEventPump " << replyPump.getPump().getName() + LL_DEBUGS("lleventcoro") << callerName << ": coroutine " << listenerName + << " about to wait on LLEventPump " << replyPump.getName() << LL_ENDL; + return { connection, stopper }; +} + +} // anonymous + +LLSD llcoro::postAndSuspend(const LLSD& event, const LLEventPumpOrPumpName& requestPump, + const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath) +{ + LLCoros::Promise<LLSD> promise; + std::string listenerName(listenerNameForCoro()); + + // Store both connections into LLTempBoundListeners so we implicitly + // disconnect on return from this function. + auto connections = + postAndSuspendSetup("postAndSuspend()", listenerName, promise, + event, requestPump, replyPump, replyPumpNamePath); + LLTempBoundListener connection(connections.first), stopper(connections.second); + + // declare the future + LLCoros::Future<LLSD> future = LLCoros::getFuture(promise); // calling get() on the future makes us wait for it + LLCoros::TempStatus st(STRINGIZE("waiting for " << replyPump.getPump().getName())); LLSD value(future.get()); LL_DEBUGS("lleventcoro") << "postAndSuspend(): coroutine " << listenerName << " resuming with " << value << LL_ENDL; @@ -230,147 +266,52 @@ LLSD llcoro::postAndSuspend(const LLSD& event, const LLEventPumpOrPumpName& requ return value; } -LLSD llcoro::suspendUntilEventOnWithTimeout(const LLEventPumpOrPumpName& suspendPumpOrName, - F32 timeoutin, const LLSD &timeoutResult) -{ - /** - * The timeout pump is attached upstream of of the waiting pump and will - * pass the timeout event through it. We CAN NOT attach downstream since - * doing so will cause the suspendPump to fire any waiting events immediately - * and they will be lost. This becomes especially problematic with the - * LLEventTimeout(pump) constructor which will also attempt to fire those - * events using the virtual listen_impl method in the not yet fully constructed - * timeoutPump. - */ - LLEventTimeout timeoutPump; - LLEventPump &suspendPump = suspendPumpOrName.getPump(); - - LLTempBoundListener timeoutListener(timeoutPump.listen(suspendPump.getName(), - boost::bind(&LLEventPump::post, &suspendPump, _1))); - - timeoutPump.eventAfter(timeoutin, timeoutResult); - return llcoro::suspendUntilEventOn(suspendPump); -} - -namespace -{ - -/** - * This helper is specifically for postAndSuspend2(). 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::dcoroutines::make_callback() - * (void return) to provide an event listener (bool return), we've adapted - * FutureListener for the purpose. The basic idea is that we construct a - * distinct instance of FutureListener2 -- binding different instance data -- - * for each of the pumps. Then, when a pump delivers an LLSD value to either - * FutureListener2, it can combine that LLSD with its discriminator to feed - * the future object. - * - * DISCRIM is a template argument so we can use llmake() rather than - * having to write our own argument-deducing helper function. - */ -template <typename LISTENER, typename DISCRIM> -class FutureListener2: public FutureListener<LISTENER> +LLSD llcoro::postAndSuspendWithTimeout(const LLSD& event, + const LLEventPumpOrPumpName& requestPump, + const LLEventPumpOrPumpName& replyPump, + const LLSD& replyPumpNamePath, + F32 timeout, const LLSD& timeoutResult) { - typedef FutureListener<LISTENER> super; - -public: - // instantiated on coroutine stack: the stack about to suspend - FutureListener2(const LISTENER& listener, DISCRIM discriminator): - super(listener), - mDiscrim(discriminator) - {} - - // called on main stack: the stack on which event is fired - bool operator()(const LLSD& event) - { - // our future object is defined to accept LLEventWithID - super::mListener(LLEventWithID(event, mDiscrim)); - // tell LLEventPump whether or not event was consumed - return super::mConsume; - } - -private: - const DISCRIM mDiscrim; -}; + LLCoros::Promise<LLSD> promise; + std::string listenerName(listenerNameForCoro()); -} // anonymous + // Store both connections into LLTempBoundListeners so we implicitly + // disconnect on return from this function. + auto connections = + postAndSuspendSetup("postAndSuspendWithTimeout()", listenerName, promise, + event, requestPump, replyPump, replyPumpNamePath); + LLTempBoundListener connection(connections.first), stopper(connections.second); -namespace llcoro -{ - -LLEventWithID postAndSuspend2(const LLSD& event, - const LLEventPumpOrPumpName& requestPump, - const LLEventPumpOrPumpName& replyPump0, - const LLEventPumpOrPumpName& replyPump1, - const LLSD& replyPump0NamePath, - const LLSD& replyPump1NamePath) -{ // declare the future - LLCoros::Future<LLEventWithID> future; - // either callback will assign a value to this future; listen on - // each specified LLEventPump with a callback - std::string name(listenerNameForCoro()); - LLTempBoundListener connection0( - replyPump0.getPump().listen( - name + "a", - llmake<FutureListener2>(future.make_callback(), 0))); - LLTempBoundListener connection1( - replyPump1.getPump().listen( - name + "b", - llmake<FutureListener2>(future.make_callback(), 1))); - // skip the "post" part if requestPump is default-constructed - if (requestPump) + LLCoros::Future<LLSD> future = LLCoros::getFuture(promise); + // wait for specified timeout + boost::fibers::future_status status; { - // If either replyPumpNamePath is non-empty, store the corresponding - // replyPump name in the request event. - LLSD modevent(event); - storeToLLSDPath(modevent, replyPump0NamePath, - replyPump0.getPump().getName()); - storeToLLSDPath(modevent, replyPump1NamePath, - replyPump1.getPump().getName()); - LL_DEBUGS("lleventcoro") << "postAndSuspend2(): coroutine " << name - << " posting to " << requestPump.getPump().getName() - << ": " << modevent << LL_ENDL; - requestPump.getPump().post(modevent); + LLCoros::TempStatus st(STRINGIZE("waiting for " << replyPump.getPump().getName() + << " for " << timeout << "s")); + // The fact that we accept non-integer seconds means we should probably + // use granularity finer than one second. However, given the overhead of + // the rest of our processing, it seems silly to use granularity finer + // than a millisecond. + status = future.wait_for(std::chrono::milliseconds(long(timeout * 1000))); } - LL_DEBUGS("lleventcoro") << "postAndSuspend2(): coroutine " << name - << " about to wait on LLEventPumps " << replyPump0.getPump().getName() - << ", " << replyPump1.getPump().getName() << LL_ENDL; - // calling get() on the future makes us wait for it - LLEventWithID value(future.get()); - LL_DEBUGS("lleventcoro") << "postAndSuspend(): coroutine " << name - << " resuming with (" << value.first << ", " << value.second << ")" - << LL_ENDL; - // returning should disconnect both connections - return value; -} - -LLSD errorException(const LLEventWithID& result, const std::string& desc) -{ - // If the result arrived on the error pump (pump 1), instead of - // returning it, deliver it via exception. - if (result.second) + // if the future is NOT yet ready, return timeoutResult instead + if (status == boost::fibers::future_status::timeout) { - LLTHROW(LLErrorEvent(desc, result.first)); + LL_DEBUGS("lleventcoro") << "postAndSuspendWithTimeout(): coroutine " << listenerName + << " timed out after " << timeout << " seconds," + << " resuming with " << timeoutResult << LL_ENDL; + return timeoutResult; } - // That way, our caller knows a simple return must be from the reply - // pump (pump 0). - return result.first; -} - -LLSD errorLog(const LLEventWithID& result, const std::string& desc) -{ - // If the result arrived on the error pump (pump 1), log it as a fatal - // error. - if (result.second) + else { - LL_ERRS("errorLog") << desc << ":" << std::endl; - LLSDSerialize::toPrettyXML(result.first, LL_CONT); - LL_CONT << LL_ENDL; + llassert_always(status == boost::fibers::future_status::ready); + + // future is now ready, no more waiting + LLSD value(future.get()); + LL_DEBUGS("lleventcoro") << "postAndSuspendWithTimeout(): coroutine " << listenerName + << " resuming with " << value << LL_ENDL; + // returning should disconnect the connection + return value; } - // A simple return must therefore be from the reply pump (pump 0). - return result.first; } - -} // namespace llcoro diff --git a/indra/llcommon/lleventcoro.h b/indra/llcommon/lleventcoro.h index 84827aab4a..c0fe8b094f 100644 --- a/indra/llcommon/lleventcoro.h +++ b/indra/llcommon/lleventcoro.h @@ -29,12 +29,8 @@ #if ! defined(LL_LLEVENTCORO_H) #define LL_LLEVENTCORO_H -#include <boost/optional.hpp> #include <string> -#include <utility> // std::pair #include "llevents.h" -#include "llerror.h" -#include "llexception.h" /** * Like LLListenerOrPumpName, this is a class intended for parameter lists: @@ -147,117 +143,29 @@ LLSD suspendUntilEventOn(const LLEventPumpOrPumpName& pump) return postAndSuspend(LLSD(), LLEventPumpOrPumpName(), pump); } +/// Like postAndSuspend(), but if we wait longer than @a timeout seconds, +/// stop waiting and return @a timeoutResult instead. +LLSD postAndSuspendWithTimeout(const LLSD& event, + const LLEventPumpOrPumpName& requestPump, + const LLEventPumpOrPumpName& replyPump, + const LLSD& replyPumpNamePath, + F32 timeout, const LLSD& timeoutResult); + /// Suspend the coroutine until an event is fired on the identified pump /// or the timeout duration has elapsed. If the timeout duration /// elapses the specified LLSD is returned. -LLSD suspendUntilEventOnWithTimeout(const LLEventPumpOrPumpName& suspendPumpOrName, F32 timeoutin, const LLSD &timeoutResult); - -} // namespace llcoro - -/// return type for two-pump variant of suspendUntilEventOn() -typedef std::pair<LLSD, int> LLEventWithID; - -namespace llcoro -{ - -/** - * This function waits for a reply on either of two specified LLEventPumps. - * Otherwise, it closely resembles postAndSuspend(); please see the documentation - * for that function for detailed parameter info. - * - * While we could have implemented the single-pump variant in terms of this - * one, there's enough added complexity here to make it worthwhile to give the - * single-pump variant its own straightforward implementation. Conversely, - * though we could use preprocessor logic to generate n-pump overloads up to - * BOOST_COROUTINE_WAIT_MAX, we don't foresee a use case. This two-pump - * overload exists because certain event APIs are defined in terms of a reply - * LLEventPump and an error LLEventPump. - * - * The LLEventWithID return value provides not only the received event, but - * the index of the pump on which it arrived (0 or 1). - * - * @note - * I'd have preferred to overload the name postAndSuspend() for both signatures. - * But consider the following ambiguous call: - * @code - * postAndSuspend(LLSD(), requestPump, replyPump, "someString"); - * @endcode - * "someString" could be converted to either LLSD (@a replyPumpNamePath for - * the single-pump function) or LLEventOrPumpName (@a replyPump1 for two-pump - * function). - * - * It seems less burdensome to write postAndSuspend2() than to write either - * LLSD("someString") or LLEventOrPumpName("someString"). - */ -LLEventWithID postAndSuspend2(const LLSD& event, - const LLEventPumpOrPumpName& requestPump, - const LLEventPumpOrPumpName& replyPump0, - const LLEventPumpOrPumpName& replyPump1, - const LLSD& replyPump0NamePath=LLSD(), - const LLSD& replyPump1NamePath=LLSD()); - -/** - * Wait for the next event on either of two specified LLEventPumps. - */ inline -LLEventWithID -suspendUntilEventOn(const LLEventPumpOrPumpName& pump0, const LLEventPumpOrPumpName& pump1) +LLSD suspendUntilEventOnWithTimeout(const LLEventPumpOrPumpName& suspendPumpOrName, + F32 timeoutin, const LLSD &timeoutResult) { - // This is now a convenience wrapper for postAndSuspend2(). - return postAndSuspend2(LLSD(), LLEventPumpOrPumpName(), pump0, pump1); + return postAndSuspendWithTimeout(LLSD(), // event + LLEventPumpOrPumpName(), // requestPump + suspendPumpOrName, // replyPump + LLSD(), // replyPumpNamePath + timeoutin, + timeoutResult); } -/** - * Helper for the two-pump variant of suspendUntilEventOn(), e.g.: - * - * @code - * LLSD reply = errorException(suspendUntilEventOn(replyPump, errorPump), - * "error response from login.cgi"); - * @endcode - * - * Examines an LLEventWithID, assuming that the second pump (pump 1) is - * listening for an error indication. If the incoming data arrived on pump 1, - * throw an LLErrorEvent exception. If the incoming data arrived on pump 0, - * just return it. Since a normal return can only be from pump 0, we no longer - * need the LLEventWithID's discriminator int; we can just return the LLSD. - * - * @note I'm not worried about introducing the (fairly generic) name - * errorException() into global namespace, because how many other overloads of - * the same name are going to accept an LLEventWithID parameter? - */ -LLSD errorException(const LLEventWithID& result, const std::string& desc); - -} // namespace llcoro - -/** - * Exception thrown by errorException(). We don't call this LLEventError - * because it's not an error in event processing: rather, this exception - * announces an event that bears error information (for some other API). - */ -class LL_COMMON_API LLErrorEvent: public LLException -{ -public: - LLErrorEvent(const std::string& what, const LLSD& data): - LLException(what), - mData(data) - {} - virtual ~LLErrorEvent() throw() {} - - LLSD getData() const { return mData; } - -private: - LLSD mData; -}; - -namespace llcoro -{ - -/** - * Like errorException(), save that this trips a fatal error using LL_ERRS - * rather than throwing an exception. - */ -LL_COMMON_API LLSD errorLog(const LLEventWithID& result, const std::string& desc); - } // namespace llcoro /** @@ -304,84 +212,4 @@ private: LLEventStream mPump; }; -/** - * Other event APIs require the names of two different LLEventPumps: one for - * success response, the other for error response. Extend LLCoroEventPump - * for the two-pump use case. - */ -class LL_COMMON_API LLCoroEventPumps -{ -public: - LLCoroEventPumps(const std::string& name="coro", - const std::string& suff0="Reply", - const std::string& suff1="Error"): - mPump0(name + suff0, true), // allow tweaking the pump instance name - mPump1(name + suff1, true) - {} - /// request pump 0's name - std::string getName0() const { return mPump0.getName(); } - /// request pump 1's name - std::string getName1() const { return mPump1.getName(); } - /// request both names - std::pair<std::string, std::string> getNames() const - { - return std::pair<std::string, std::string>(mPump0.getName(), mPump1.getName()); - } - - /// request pump 0 - LLEventPump& getPump0() { return mPump0; } - /// request pump 1 - LLEventPump& getPump1() { return mPump1; } - - /// suspendUntilEventOn(either of our two LLEventPumps) - LLEventWithID suspend() - { - return llcoro::suspendUntilEventOn(mPump0, mPump1); - } - - /// errorException(suspend()) - LLSD suspendWithException() - { - return llcoro::errorException(suspend(), std::string("Error event on ") + getName1()); - } - - /// errorLog(suspend()) - LLSD suspendWithLog() - { - return llcoro::errorLog(suspend(), std::string("Error event on ") + getName1()); - } - - LLEventWithID postAndSuspend(const LLSD& event, - const LLEventPumpOrPumpName& requestPump, - const LLSD& replyPump0NamePath=LLSD(), - const LLSD& replyPump1NamePath=LLSD()) - { - return llcoro::postAndSuspend2(event, requestPump, mPump0, mPump1, - replyPump0NamePath, replyPump1NamePath); - } - - LLSD postAndSuspendWithException(const LLSD& event, - const LLEventPumpOrPumpName& requestPump, - const LLSD& replyPump0NamePath=LLSD(), - const LLSD& replyPump1NamePath=LLSD()) - { - return llcoro::errorException(postAndSuspend(event, requestPump, - replyPump0NamePath, replyPump1NamePath), - std::string("Error event on ") + getName1()); - } - - LLSD postAndSuspendWithLog(const LLSD& event, - const LLEventPumpOrPumpName& requestPump, - const LLSD& replyPump0NamePath=LLSD(), - const LLSD& replyPump1NamePath=LLSD()) - { - return llcoro::errorLog(postAndSuspend(event, requestPump, - replyPump0NamePath, replyPump1NamePath), - std::string("Error event on ") + getName1()); - } - -private: - LLEventStream mPump0, mPump1; -}; - #endif /* ! defined(LL_LLEVENTCORO_H) */ diff --git a/indra/llcommon/lleventfilter.cpp b/indra/llcommon/lleventfilter.cpp index 9fb18dc67d..4cded7f88e 100644 --- a/indra/llcommon/lleventfilter.cpp +++ b/indra/llcommon/lleventfilter.cpp @@ -37,6 +37,9 @@ // other Linden headers #include "llerror.h" // LL_ERRS #include "llsdutil.h" // llsd_matches() +#include "stringize.h" +#include "lleventtimer.h" +#include "lldate.h" /***************************************************************************** * LLEventFilter @@ -182,6 +185,27 @@ bool LLEventTimeout::countdownElapsed() const return mTimer.hasExpired(); } +LLEventTimer* LLEventTimeout::post_every(F32 period, const std::string& pump, const LLSD& data) +{ + return LLEventTimer::run_every( + period, + [pump, data](){ LLEventPumps::instance().obtain(pump).post(data); }); +} + +LLEventTimer* LLEventTimeout::post_at(const LLDate& time, const std::string& pump, const LLSD& data) +{ + return LLEventTimer::run_at( + time, + [pump, data](){ LLEventPumps::instance().obtain(pump).post(data); }); +} + +LLEventTimer* LLEventTimeout::post_after(F32 interval, const std::string& pump, const LLSD& data) +{ + return LLEventTimer::run_after( + interval, + [pump, data](){ LLEventPumps::instance().obtain(pump).post(data); }); +} + /***************************************************************************** * LLEventBatch *****************************************************************************/ @@ -409,3 +433,61 @@ void LLEventBatchThrottle::setSize(std::size_t size) flush(); } } + +/***************************************************************************** +* LLEventLogProxy +*****************************************************************************/ +LLEventLogProxy::LLEventLogProxy(LLEventPump& source, const std::string& name, bool tweak): + // note: we are NOT using the constructor that implicitly connects! + LLEventFilter(name, tweak), + // instead we simply capture a reference to the subject LLEventPump + mPump(source) +{ +} + +bool LLEventLogProxy::post(const LLSD& event) /* override */ +{ + auto counter = mCounter++; + auto eventplus = event; + if (eventplus.type() == LLSD::TypeMap) + { + eventplus["_cnt"] = counter; + } + std::string hdr{STRINGIZE(getName() << ": post " << counter)}; + LL_INFOS("LogProxy") << hdr << ": " << event << LL_ENDL; + bool result = mPump.post(eventplus); + LL_INFOS("LogProxy") << hdr << " => " << result << LL_ENDL; + return result; +} + +LLBoundListener LLEventLogProxy::listen_impl(const std::string& name, + const LLEventListener& target, + const NameList& after, + const NameList& before) +{ + LL_DEBUGS("LogProxy") << "LLEventLogProxy('" << getName() << "').listen('" + << name << "')" << LL_ENDL; + return mPump.listen(name, + [this, name, target](const LLSD& event)->bool + { return listener(name, target, event); }, + after, + before); +} + +bool LLEventLogProxy::listener(const std::string& name, + const LLEventListener& target, + const LLSD& event) const +{ + auto eventminus = event; + std::string counter{"**"}; + if (eventminus.has("_cnt")) + { + counter = stringize(eventminus["_cnt"].asInteger()); + eventminus.erase("_cnt"); + } + std::string hdr{STRINGIZE(getName() << " to " << name << " " << counter)}; + LL_INFOS("LogProxy") << hdr << ": " << eventminus << LL_ENDL; + bool result = target(eventminus); + LL_INFOS("LogProxy") << hdr << " => " << result << LL_ENDL; + return result; +} diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h index ff8fc9bc7f..48c2570732 100644 --- a/indra/llcommon/lleventfilter.h +++ b/indra/llcommon/lleventfilter.h @@ -32,8 +32,12 @@ #include "llevents.h" #include "stdtypes.h" #include "lltimer.h" +#include "llsdutil.h" #include <boost/function.hpp> +class LLEventTimer; +class LLDate; + /** * Generic base class */ @@ -210,6 +214,19 @@ public: LLEventTimeout(); LLEventTimeout(LLEventPump& source); + /// using LLEventTimeout as namespace for free functions + /// Post event to specified LLEventPump every period seconds. Delete + /// returned LLEventTimer* to cancel. + static LLEventTimer* post_every(F32 period, const std::string& pump, const LLSD& data); + /// Post event to specified LLEventPump at specified future time. Call + /// LLEventTimer::getInstance(returned pointer) to check whether it's still + /// pending; if so, delete the pointer to cancel. + static LLEventTimer* post_at(const LLDate& time, const std::string& pump, const LLSD& data); + /// Post event to specified LLEventPump after specified interval. Call + /// LLEventTimer::getInstance(returned pointer) to check whether it's still + /// pending; if so, delete the pointer to cancel. + static LLEventTimer* post_after(F32 interval, const std::string& pump, const LLSD& data); + protected: virtual void setCountdown(F32 seconds); virtual bool countdownElapsed() const; @@ -376,4 +393,149 @@ private: std::size_t mBatchSize; }; +/** + * LLStoreListener self-registers on the LLEventPump of interest, and + * unregisters on destruction. As long as it exists, a particular element is + * extracted from every event that comes through the upstream LLEventPump and + * stored into the target variable. + * + * This is implemented as a subclass of LLEventFilter, though strictly + * speaking it isn't really a "filter" at all: it never passes incoming events + * to its own listeners, if any. + * + * TBD: A variant based on output iterators that stores and then increments + * the iterator. Useful with boost::coroutine2! + */ +template <typename T> +class LLStoreListener: public LLEventFilter +{ +public: + // pass target and optional path to element + LLStoreListener(T& target, const LLSD& path=LLSD(), bool consume=false): + LLEventFilter("store"), + mTarget(target), + mPath(path), + mConsume(consume) + {} + // construct and connect + LLStoreListener(LLEventPump& source, T& target, const LLSD& path=LLSD(), bool consume=false): + LLEventFilter(source, "store"), + mTarget(target), + mPath(path), + mConsume(consume) + {} + + // Calling post() with an LLSD event extracts the element indicated by + // path, then stores it to mTarget. + virtual bool post(const LLSD& event) + { + // Extract the element specified by 'mPath' from 'event'. To perform a + // generic type-appropriate store through mTarget, construct an + // LLSDParam<T> and store that, thus engaging LLSDParam's custom + // conversions. + mTarget = LLSDParam<T>(llsd::drill(event, mPath)); + return mConsume; + } + +private: + T& mTarget; + const LLSD mPath; + const bool mConsume; +}; + +/***************************************************************************** +* LLEventLogProxy +*****************************************************************************/ +/** + * LLEventLogProxy is a little different than the other LLEventFilter + * subclasses declared in this header file, in that it completely wraps the + * passed LLEventPump (both input and output) instead of simply processing its + * output. Of course, if someone directly posts to the wrapped LLEventPump by + * looking up its string name in LLEventPumps, LLEventLogProxy can't intercept + * that post() call. But as long as consuming code is willing to access the + * LLEventLogProxy instance instead of the wrapped LLEventPump, all event data + * both post()ed and received is logged. + * + * The proxy role means that LLEventLogProxy intercepts more of LLEventPump's + * API than a typical LLEventFilter subclass. + */ +class LLEventLogProxy: public LLEventFilter +{ + typedef LLEventFilter super; +public: + /** + * Construct LLEventLogProxy, wrapping the specified LLEventPump. + * Unlike a typical LLEventFilter subclass, the name parameter is @emph + * not optional because typically you want LLEventLogProxy to completely + * replace the wrapped LLEventPump. So you give the subject LLEventPump + * some other name and give the LLEventLogProxy the name that would have + * been used for the subject LLEventPump. + */ + LLEventLogProxy(LLEventPump& source, const std::string& name, bool tweak=false); + + /// register a new listener + LLBoundListener listen_impl(const std::string& name, const LLEventListener& target, + const NameList& after, const NameList& before); + + /// Post an event to all listeners + virtual bool post(const LLSD& event) /* override */; + +private: + /// This method intercepts each call to any target listener. We pass it + /// the listener name and the caller's intended target listener plus the + /// posted LLSD event. + bool listener(const std::string& name, + const LLEventListener& target, + const LLSD& event) const; + + LLEventPump& mPump; + LLSD::Integer mCounter{0}; +}; + +/** + * LLEventPumpHolder<T> is a helper for LLEventLogProxyFor<T>. It simply + * stores an instance of T, presumably a subclass of LLEventPump. We derive + * LLEventLogProxyFor<T> from LLEventPumpHolder<T>, ensuring that + * LLEventPumpHolder's contained mWrappedPump is fully constructed before + * passing it to LLEventLogProxyFor's LLEventLogProxy base class constructor. + * But since LLEventPumpHolder<T> presents none of the LLEventPump API, + * LLEventLogProxyFor<T> inherits its methods unambiguously from + * LLEventLogProxy. + */ +template <class T> +class LLEventPumpHolder +{ +protected: + LLEventPumpHolder(const std::string& name, bool tweak=false): + mWrappedPump(name, tweak) + {} + T mWrappedPump; +}; + +/** + * LLEventLogProxyFor<T> is a wrapper around any of the LLEventPump subclasses. + * Instantiating an LLEventLogProxy<T> instantiates an internal T. Otherwise + * it behaves like LLEventLogProxy. + */ +template <class T> +class LLEventLogProxyFor: private LLEventPumpHolder<T>, public LLEventLogProxy +{ + // We derive privately from LLEventPumpHolder because it's an + // implementation detail of LLEventLogProxyFor. The only reason it's a + // base class at all is to guarantee that it's constructed first so we can + // pass it to our LLEventLogProxy base class constructor. + typedef LLEventPumpHolder<T> holder; + typedef LLEventLogProxy super; + +public: + LLEventLogProxyFor(const std::string& name, bool tweak=false): + // our wrapped LLEventPump subclass instance gets a name suffix + // because that's not the LLEventPump we want consumers to obtain when + // they ask LLEventPumps for this name + holder(name + "-", tweak), + // it's our LLEventLogProxy that gets the passed name + super(holder::mWrappedPump, name, tweak) + {} +}; + #endif /* ! defined(LL_LLEVENTFILTER_H) */ diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index eedd8c92b5..64fb985951 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -45,6 +45,7 @@ #include <cctype> // external library headers #include <boost/range/iterator_range.hpp> +#include <boost/make_shared.hpp> #if LL_WINDOWS #pragma warning (push) #pragma warning (disable : 4701) // compiler thinks might use uninitialized var, but no @@ -63,51 +64,23 @@ #endif /***************************************************************************** -* queue_names: specify LLEventPump names that should be instantiated as -* LLEventQueue -*****************************************************************************/ -/** - * At present, we recognize particular requested LLEventPump names as needing - * LLEventQueues. Later on we'll migrate this information to an external - * configuration file. - */ -const char* queue_names[] = -{ - "placeholder - replace with first real name string" -}; - -/***************************************************************************** -* If there's a "mainloop" pump, listen on that to flush all LLEventQueues +* LLEventPumps *****************************************************************************/ -struct RegisterFlush : public LLEventTrackable -{ - RegisterFlush(): - pumps(LLEventPumps::instance()) +LLEventPumps::LLEventPumps(): + mFactories { - pumps.obtain("mainloop").listen("flushLLEventQueues", boost::bind(&RegisterFlush::flush, this, _1)); - } - bool flush(const LLSD&) + { "LLEventStream", [](const std::string& name, bool tweak) + { return new LLEventStream(name, tweak); } }, + { "LLEventMailDrop", [](const std::string& name, bool tweak) + { return new LLEventMailDrop(name, tweak); } } + }, + mTypes { - pumps.flush(); - return false; + // LLEventStream is the default for obtain(), so even if somebody DOES + // call obtain("placeholder"), this sample entry won't break anything. + { "placeholder", "LLEventStream" } } - ~RegisterFlush() - { - // LLEventTrackable handles stopListening for us. - } - LLEventPumps& pumps; -}; -static RegisterFlush registerFlush; - -/***************************************************************************** -* LLEventPumps -*****************************************************************************/ -LLEventPumps::LLEventPumps(): - // Until we migrate this information to an external config file, - // initialize mQueueNames from the static queue_names array. - mQueueNames(boost::begin(queue_names), boost::end(queue_names)) -{ -} +{} LLEventPump& LLEventPumps::obtain(const std::string& name) { @@ -118,14 +91,31 @@ LLEventPump& LLEventPumps::obtain(const std::string& name) // name. return *found->second; } - // Here we must instantiate an LLEventPump subclass. - LLEventPump* newInstance; - // Should this name be an LLEventQueue? - PumpNames::const_iterator nfound = mQueueNames.find(name); - if (nfound != mQueueNames.end()) - newInstance = new LLEventQueue(name); - else - newInstance = new LLEventStream(name); + + // Here we must instantiate an LLEventPump subclass. Is there a + // preregistered class name override for this specific instance name? + auto nfound = mTypes.find(name); + std::string type; + if (nfound != mTypes.end()) + { + type = nfound->second; + } + // pass tweak=false: we already know there's no existing instance with + // this name + return make(name, false, type); +} + +LLEventPump& LLEventPumps::make(const std::string& name, bool tweak, + const std::string& type) +{ + // find the relevant factory for this (or default) type + auto found = mFactories.find(type.empty()? "LLEventStream" : type); + if (found == mFactories.end()) + { + // Passing an unrecognized type name is a no-no + LLTHROW(BadType(type)); + } + auto newInstance = (found->second)(name, tweak); // LLEventPump's constructor implicitly registers each new instance in // mPumpMap. But remember that we instantiated it (in mOurPumps) so we'll // delete it later. @@ -143,14 +133,23 @@ bool LLEventPumps::post(const std::string&name, const LLSD&message) return (*found).second->post(message); } - void LLEventPumps::flush() { // Flush every known LLEventPump instance. Leave it up to each instance to // decide what to do with the flush() call. - for (PumpMap::iterator pmi = mPumpMap.begin(), pmend = mPumpMap.end(); pmi != pmend; ++pmi) + for (PumpMap::value_type& pair : mPumpMap) + { + pair.second->flush(); + } +} + +void LLEventPumps::clear() +{ + // Clear every known LLEventPump instance. Leave it up to each instance to + // decide what to do with the clear() call. + for (PumpMap::value_type& pair : mPumpMap) { - pmi->second->flush(); + pair.second->clear(); } } @@ -158,9 +157,9 @@ void LLEventPumps::reset() { // Reset every known LLEventPump instance. Leave it up to each instance to // decide what to do with the reset() call. - for (PumpMap::iterator pmi = mPumpMap.begin(), pmend = mPumpMap.end(); pmi != pmend; ++pmi) + for (PumpMap::value_type& pair : mPumpMap) { - pmi->second->reset(); + pair.second->reset(); } } @@ -267,6 +266,9 @@ LLEventPumps::~LLEventPumps() { delete *mOurPumps.begin(); } + // Reset every remaining registered LLEventPump subclass instance: those + // we DIDN'T instantiate using either make() or obtain(). + reset(); } /***************************************************************************** @@ -283,7 +285,7 @@ LLEventPump::LLEventPump(const std::string& name, bool tweak): // Register every new instance with LLEventPumps mRegistry(LLEventPumps::instance().getHandle()), mName(mRegistry.get()->registerNew(*this, name, tweak)), - mSignal(new LLStandardSignal()), + mSignal(boost::make_shared<LLStandardSignal>()), mEnabled(true) {} @@ -311,6 +313,14 @@ std::string LLEventPump::inventName(const std::string& pfx) return STRINGIZE(pfx << suffix++); } +void LLEventPump::clear() +{ + // Destroy the original LLStandardSignal instance, replacing it with a + // whole new one. + mSignal = boost::make_shared<LLStandardSignal>(); + mConnections.clear(); +} + void LLEventPump::reset() { mSignal.reset(); @@ -553,7 +563,7 @@ bool LLEventMailDrop::post(const LLSD& event) // be posted to any future listeners when they attach. mEventHistory.push_back(event); } - + return posted; } @@ -583,46 +593,9 @@ LLBoundListener LLEventMailDrop::listen_impl(const std::string& name, return LLEventStream::listen_impl(name, listener, after, before); } - -/***************************************************************************** -* LLEventQueue -*****************************************************************************/ -bool LLEventQueue::post(const LLSD& event) -{ - if (mEnabled) - { - // Defer sending this event by queueing it until flush() - mEventQueue.push_back(event); - } - // Unconditionally return false. We won't know until flush() whether a - // listener claims to have handled the event -- meanwhile, don't block - // other listeners. - return false; -} - -void LLEventQueue::flush() +void LLEventMailDrop::discard() { - if(!mSignal) return; - - // Consider the case when a given listener on this LLEventQueue posts yet - // another event on the same queue. If we loop over mEventQueue directly, - // we'll end up processing all those events during the same flush() call - // -- rather like an EventStream. Instead, copy mEventQueue and clear it, - // so that any new events posted to this LLEventQueue during flush() will - // be processed in the *next* flush() call. - EventQueue queue(mEventQueue); - mEventQueue.clear(); - // NOTE NOTE NOTE: Any new access to member data beyond this point should - // cause us to move our LLStandardSignal object to a pimpl class along - // with said member data. Then the local shared_ptr will preserve both. - - // DEV-43463: capture a local copy of mSignal. See LLEventStream::post() - // for detailed comments. - boost::shared_ptr<LLStandardSignal> signal(mSignal); - for ( ; ! queue.empty(); queue.pop_front()) - { - (*signal)(queue.front()); - } + mEventHistory.clear(); } /***************************************************************************** diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 62d97007ac..e380c108f4 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -37,6 +37,7 @@ #include <set> #include <vector> #include <deque> +#include <functional> #if LL_WINDOWS #pragma warning (push) #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch @@ -55,7 +56,6 @@ #include <boost/visit_each.hpp> #include <boost/ref.hpp> // reference_wrapper #include <boost/type_traits/is_pointer.hpp> -#include <boost/function.hpp> #include <boost/static_assert.hpp> #include "llsd.h" #include "llsingleton.h" @@ -211,8 +211,7 @@ public: /// exception if you try to call when empty struct Empty: public LLException { - Empty(const std::string& what): - LLException(std::string("LLListenerOrPumpName::Empty: ") + what) {} + Empty(const std::string& what): LLException("LLListenerOrPumpName::Empty: " + what) {} }; private: @@ -247,6 +246,30 @@ public: */ LLEventPump& obtain(const std::string& name); + /// exception potentially thrown by make() + struct BadType: public LLException + { + BadType(const std::string& what): LLException("BadType: " + what) {} + }; + + /** + * Create an LLEventPump with suggested name (optionally of specified + * LLEventPump subclass type). As with obtain(), LLEventPumps owns the new + * instance. + * + * As with LLEventPump's constructor, make() could throw + * LLEventPump::DupPumpName unless you pass tweak=true. + * + * As with a hand-constructed LLEventPump subclass, if you pass + * tweak=true, the tweaked name can be obtained by LLEventPump::getName(). + * + * Pass empty type to get the default LLEventStream. + * + * If you pass an unrecognized type string, make() throws BadType. + */ + LLEventPump& make(const std::string& name, bool tweak=false, + const std::string& type=std::string()); + /** * Find the named LLEventPump instance. If it exists post the message to it. * If the pump does not exist, do nothing. @@ -264,6 +287,11 @@ public: void flush(); /** + * Disconnect listeners from all known LLEventPump instances + */ + void clear(); + + /** * Reset all known LLEventPump instances * workaround for DEV-35406 crash on shutdown */ @@ -298,44 +326,22 @@ testable: // destroyed. typedef std::set<LLEventPump*> PumpSet; PumpSet mOurPumps; - // LLEventPump names that should be instantiated as LLEventQueue rather - // than as LLEventStream - typedef std::set<std::string> PumpNames; - PumpNames mQueueNames; + // for make(), map string type name to LLEventPump subclass factory function + typedef std::map<std::string, std::function<LLEventPump*(const std::string&, bool)>> PumpFactories; + // Data used by make(). + // One might think mFactories and mTypes could reasonably be static. So + // they could -- if not for the fact that make() or obtain() might be + // called before this module's static variables have been initialized. + // This is why we use singletons in the first place. + PumpFactories mFactories; + + // for obtain(), map desired string instance name to string type when + // obtain() must create the instance + typedef std::map<std::string, std::string> InstanceTypes; + InstanceTypes mTypes; }; /***************************************************************************** -* details -*****************************************************************************/ -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<LLBoundListener(const LLEventListener&)> ConnectFunc; - - /// overload of visit_and_connect() when we have a string identifier available - template <typename LISTENER> - LLBoundListener visit_and_connect(const std::string& name, - const LISTENER& listener, - const ConnectFunc& connect_func); - /** - * Utility template function to use Visitor appropriately - * - * @param listener Callable to connect, typically a boost::bind() - * expression. This will be visited by Visitor using boost::visit_each(). - * @param connect_func Callable that will connect() @a listener to an - * LLStandardSignal, returning LLBoundListener. - */ - template <typename LISTENER> - LLBoundListener visit_and_connect(const LISTENER& listener, - const ConnectFunc& connect_func) - { - return visit_and_connect("", listener, connect_func); - } -} // namespace LLEventDetail - -/***************************************************************************** * LLEventTrackable *****************************************************************************/ /** @@ -369,11 +375,6 @@ namespace LLEventDetail * instance, it attempts to dereference the <tt>Foo*</tt> pointer that was * <tt>delete</tt>d but not zeroed.) * - Undefined behavior results. - * If you suspect you may encounter any such scenario, you're better off - * managing the lifespan of your object with <tt>boost::shared_ptr</tt>. - * Passing <tt>LLEventPump::listen()</tt> a <tt>boost::bind()</tt> expression - * involving a <tt>boost::weak_ptr<Foo></tt> is recognized specially, engaging - * thread-safe Boost.Signals2 machinery. */ typedef boost::signals2::trackable LLEventTrackable; @@ -382,7 +383,7 @@ typedef boost::signals2::trackable LLEventTrackable; *****************************************************************************/ /** * LLEventPump is the base class interface through which we access the - * concrete subclasses LLEventStream and LLEventQueue. + * concrete subclasses such as LLEventStream. * * @NOTE * LLEventPump derives from LLEventTrackable so that when you "chain" @@ -403,8 +404,7 @@ public: */ struct DupPumpName: public LLException { - DupPumpName(const std::string& what): - LLException(std::string("DupPumpName: ") + what) {} + DupPumpName(const std::string& what): LLException("DupPumpName: " + what) {} }; /** @@ -440,9 +440,7 @@ public: */ struct DupListenerName: public ListenError { - DupListenerName(const std::string& what): - ListenError(std::string("DupListenerName: ") + what) - {} + DupListenerName(const std::string& what): ListenError("DupListenerName: " + what) {} }; /** * exception thrown by listen(). The order dependencies specified for your @@ -454,7 +452,7 @@ public: */ struct Cycle: public ListenError { - Cycle(const std::string& what): ListenError(std::string("Cycle: ") + what) {} + Cycle(const std::string& what): ListenError("Cycle: " + what) {} }; /** * exception thrown by listen(). This one means that your new listener @@ -475,7 +473,7 @@ public: */ struct OrderChange: public ListenError { - OrderChange(const std::string& what): ListenError(std::string("OrderChange: ") + what) {} + OrderChange(const std::string& what): ListenError("OrderChange: " + what) {} }; /// used by listen() @@ -512,44 +510,13 @@ public: * the result be assigned to a LLTempBoundListener or the listener is * manually disconnected when no longer needed since there will be no * way to later find and disconnect this listener manually. - * - * If (as is typical) you pass a <tt>boost::bind()</tt> expression as @a - * listener, listen() will inspect the components of that expression. If a - * bound object matches any of several cases, the connection will - * automatically be disconnected when that object is destroyed. - * - * * You bind a <tt>boost::weak_ptr</tt>. - * * Binding a <tt>boost::shared_ptr</tt> that way would ensure that the - * referenced object would @em never be destroyed, since the @c - * shared_ptr stored in the LLEventPump would remain an outstanding - * reference. Use the weaken() function to convert your @c shared_ptr to - * @c weak_ptr. Because this is easy to forget, binding a @c shared_ptr - * will produce a compile error (@c BOOST_STATIC_ASSERT failure). - * * You bind a simple pointer or reference to an object derived from - * <tt>boost::enable_shared_from_this</tt>. (UNDER CONSTRUCTION) - * * You bind a simple pointer or reference to an object derived from - * LLEventTrackable. Unlike the cases described above, though, this is - * vulnerable to a couple of cross-thread race conditions, as described - * in the LLEventTrackable documentation. */ - template <typename LISTENER> - LLBoundListener listen(const std::string& name, const LISTENER& listener, + LLBoundListener listen(const std::string& name, + const LLEventListener& listener, const NameList& after=NameList(), const NameList& before=NameList()) { - // Examine listener, using our listen_impl() method to make the - // actual connection. - // This is why listen() is a template. Conversion from boost::bind() - // to LLEventListener performs type erasure, so it's important to look - // at the boost::bind object itself before that happens. - return LLEventDetail::visit_and_connect(name, - listener, - boost::bind(&LLEventPump::listen_invoke, - this, - name, - _1, - after, - before)); + return listen_impl(name, listener, after, before); } /// Get the LLBoundListener associated with the passed name (dummy @@ -587,19 +554,12 @@ public: private: friend class LLEventPumps; - + virtual void clear(); virtual void reset(); private: - LLBoundListener listen_invoke(const std::string& name, const LLEventListener& listener, - const NameList& after, - const NameList& before) - { - return this->listen_impl(name, listener, after, before); - } - // must precede mName; see LLEventPump::LLEventPump() LLHandle<LLEventPumps> mRegistry; @@ -663,11 +623,10 @@ public: * event *must* eventually reach a listener that will consume it, else the * queue will grow to arbitrary length. * - * @NOTE: When using an LLEventMailDrop (or LLEventQueue) with a LLEventTimeout or + * @NOTE: When using an LLEventMailDrop with an LLEventTimeout or * LLEventFilter attaching the filter downstream, using Timeout's constructor will * cause the MailDrop to discharge any of its stored events. The timeout should * instead be connected upstream using its listen() method. - * See llcoro::suspendUntilEventOnWithTimeout() for an example. */ class LL_COMMON_API LLEventMailDrop : public LLEventStream { @@ -679,7 +638,8 @@ public: virtual bool post(const LLSD& event) override; /// Remove any history stored in the mail drop. - virtual void flush() override { mEventHistory.clear(); LLEventStream::flush(); }; + void discard(); + protected: virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&, const NameList& after, @@ -691,30 +651,6 @@ private: }; /***************************************************************************** -* LLEventQueue -*****************************************************************************/ -/** - * LLEventQueue is a LLEventPump whose post() method defers calling registered - * listeners until flush() is called. - */ -class LL_COMMON_API LLEventQueue: public LLEventPump -{ -public: - LLEventQueue(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {} - virtual ~LLEventQueue() {} - - /// Post an event to all listeners - virtual bool post(const LLSD& event); - - /// flush queued events - virtual void flush(); - -private: - typedef std::deque<LLSD> EventQueue; - EventQueue mEventQueue; -}; - -/***************************************************************************** * LLReqID *****************************************************************************/ /** @@ -809,329 +745,6 @@ private: LL_COMMON_API bool sendReply(const LLSD& reply, const LLSD& request, const std::string& replyKey="reply"); -/** - * Base class for LLListenerWrapper. See visit_and_connect() and llwrap(). We - * provide virtual @c accept_xxx() methods, customization points allowing a - * subclass access to certain data visible at LLEventPump::listen() time. - * Example subclass usage: - * - * @code - * myEventPump.listen("somename", - * llwrap<MyListenerWrapper>(boost::bind(&MyClass::method, instance, _1))); - * @endcode - * - * Because of the anticipated usage (note the anonymous temporary - * MyListenerWrapper instance in the example above), the @c accept_xxx() - * methods must be @c const. - */ -class LL_COMMON_API LLListenerWrapperBase -{ -public: - /// New instance. The accept_xxx() machinery makes it important to use - /// shared_ptrs for our data. Many copies of this object are made before - /// the instance that actually ends up in the signal, yet accept_xxx() - /// will later be called on the @em original instance. All copies of the - /// same original instance must share the same data. - LLListenerWrapperBase(): - mName(new std::string), - mConnection(new LLBoundListener) - { - } - - /// Copy constructor. Copy shared_ptrs to original instance data. - LLListenerWrapperBase(const LLListenerWrapperBase& that): - mName(that.mName), - mConnection(that.mConnection) - { - } - virtual ~LLListenerWrapperBase() {} - - /// Ask LLEventPump::listen() for the listener name - virtual void accept_name(const std::string& name) const - { - *mName = name; - } - - /// Ask LLEventPump::listen() for the new connection - virtual void accept_connection(const LLBoundListener& connection) const - { - *mConnection = connection; - } - -protected: - /// Listener name. - boost::shared_ptr<std::string> mName; - /// Connection. - boost::shared_ptr<LLBoundListener> mConnection; -}; - -/***************************************************************************** -* Underpinnings -*****************************************************************************/ -/** - * We originally provided a suite of overloaded - * LLEventTrackable::listenTo(LLEventPump&, ...) methods that would call - * LLEventPump::listen(...) and then pass the returned LLBoundListener to - * LLEventTrackable::track(). This was workable but error-prone: the coder - * must remember to call listenTo() rather than the more straightforward - * listen() method. - * - * Now we publish only the single canonical listen() method, so there's a - * uniform mechanism. Having a single way to do this is good, in that there's - * no question in the coder's mind which of several alternatives to choose. - * - * To support automatic connection management, we use boost::visit_each - * (http://www.boost.org/doc/libs/1_37_0/doc/html/boost/visit_each.html) to - * inspect each argument of a boost::bind expression. (Although the visit_each - * mechanism was first introduced with the original Boost.Signals library, it - * was only later documented.) - * - * Cases: - * * At least one of the function's arguments is a boost::weak_ptr<T>. Pass - * the corresponding shared_ptr to slot_type::track(). Ideally that would be - * the object whose method we want to call, but in fact we do the same for - * any weak_ptr we might find among the bound arguments. If we're passing - * our bound method a weak_ptr to some object, wouldn't the destruction of - * that object invalidate the call? So we disconnect automatically when any - * such object is destroyed. This is the mechanism preferred by boost:: - * signals2. - * * One of the functions's arguments is a boost::shared_ptr<T>. This produces - * a compile error: the bound copy of the shared_ptr stored in the - * boost_bind object stored in the signal object would make the referenced - * T object immortal. We provide a weaken() function. Pass - * weaken(your_shared_ptr) instead. (We can inspect, but not modify, the - * boost::bind object. Otherwise we'd replace the shared_ptr with weak_ptr - * implicitly and just proceed.) - * * One of the function's arguments is a plain pointer/reference to an object - * derived from boost::enable_shared_from_this. We assume that this object - * is managed using boost::shared_ptr, so we implicitly extract a shared_ptr - * and track that. (UNDER CONSTRUCTION) - * * One of the function's arguments is derived from LLEventTrackable. Pass - * the LLBoundListener to its LLEventTrackable::track(). This is vulnerable - * to a couple different race conditions, as described in LLEventTrackable - * documentation. (NOTE: Now that LLEventTrackable is a typedef for - * boost::signals2::trackable, the Signals2 library handles this itself, so - * our visitor needs no special logic for this case.) - * * Any other argument type is irrelevant to automatic connection management. - */ - -namespace LLEventDetail -{ - template <typename F> - const F& unwrap(const F& f) { return f; } - - template <typename F> - const F& unwrap(const boost::reference_wrapper<F>& f) { return f.get(); } - - // Most of the following is lifted from the Boost.Signals use of - // visit_each. - template<bool Cond> struct truth {}; - - /** - * boost::visit_each() Visitor, used on a template argument <tt>const F& - * f</tt> as follows (see visit_and_connect()): - * @code - * LLEventListener listener(f); - * Visitor visitor(listener); // bind listener so it can track() shared_ptrs - * using boost::visit_each; // allow unqualified visit_each() call for ADL - * visit_each(visitor, unwrap(f)); - * @endcode - */ - class Visitor - { - public: - /** - * Visitor binds a reference to LLEventListener so we can track() any - * shared_ptrs we find in the argument list. - */ - Visitor(LLEventListener& listener): - mListener(listener) - { - } - - /** - * boost::visit_each() calls this method for each component of a - * boost::bind() expression. - */ - template <typename T> - void operator()(const T& t) const - { - decode(t, 0); - } - - private: - // decode() decides between a reference wrapper and anything else - // boost::ref() variant - template<typename T> - void decode(const boost::reference_wrapper<T>& t, int) const - { -// add_if_trackable(t.get_pointer()); - } - - // decode() anything else - template<typename T> - void decode(const T& t, long) const - { - typedef truth<(boost::is_pointer<T>::value)> is_a_pointer; - maybe_get_pointer(t, is_a_pointer()); - } - - // maybe_get_pointer() decides between a pointer and a non-pointer - // plain pointer variant - template<typename T> - void maybe_get_pointer(const T& t, truth<true>) const - { -// add_if_trackable(t); - } - - // shared_ptr variant - template<typename T> - void maybe_get_pointer(const boost::shared_ptr<T>& t, truth<false>) const - { - // If we have a shared_ptr to this object, it doesn't matter - // whether the object is derived from LLEventTrackable, so no - // further analysis of T is needed. -// mListener.track(t); - - // Make this case illegal. Passing a bound shared_ptr to - // slot_type::track() is useless, since the bound shared_ptr will - // keep the object alive anyway! Force the coder to cast to weak_ptr. - - // Trivial as it is, make the BOOST_STATIC_ASSERT() condition - // dependent on template param so the macro is only evaluated if - // this method is in fact instantiated, as described here: - // http://www.boost.org/doc/libs/1_34_1/doc/html/boost_staticassert.html - - // ATTENTION: Don't bind a shared_ptr<anything> using - // LLEventPump::listen(boost::bind()). Doing so captures a copy of - // the shared_ptr, making the referenced object effectively - // immortal. Use the weaken() function, e.g.: - // somepump.listen(boost::bind(...weaken(my_shared_ptr)...)); - // This lets us automatically disconnect when the referenced - // object is destroyed. - BOOST_STATIC_ASSERT(sizeof(T) == 0); - } - - // weak_ptr variant - template<typename T> - void maybe_get_pointer(const boost::weak_ptr<T>& t, truth<false>) const - { - // If we have a weak_ptr to this object, it doesn't matter - // whether the object is derived from LLEventTrackable, so no - // further analysis of T is needed. - mListener.track(t); -// std::cout << "Found weak_ptr<" << typeid(T).name() << ">!\n"; - } - -#if 0 - // reference to anything derived from boost::enable_shared_from_this - template <typename T> - inline void maybe_get_pointer(const boost::enable_shared_from_this<T>& ct, - truth<false>) const - { - // Use the slot_type::track(shared_ptr) mechanism. Cast away - // const-ness because (in our code base anyway) it's unusual - // to find shared_ptr<const T>. - boost::enable_shared_from_this<T>& - t(const_cast<boost::enable_shared_from_this<T>&>(ct)); - std::cout << "Capturing shared_from_this()" << std::endl; - boost::shared_ptr<T> sp(t.shared_from_this()); -/*==========================================================================*| - std::cout << "Capturing weak_ptr" << std::endl; - boost::weak_ptr<T> wp(sp); -|*==========================================================================*/ - std::cout << "Tracking shared__ptr" << std::endl; - mListener.track(sp); - } -#endif - - // non-pointer variant - template<typename T> - void maybe_get_pointer(const T& t, truth<false>) const - { - // Take the address of this object, because the object itself may be - // trackable -// add_if_trackable(boost::addressof(t)); - } - -/*==========================================================================*| - // add_if_trackable() adds LLEventTrackable objects to mTrackables - inline void add_if_trackable(const LLEventTrackable* t) const - { - if (t) - { - } - } - - // pointer to anything not an LLEventTrackable subclass - inline void add_if_trackable(const void*) const - { - } - - // pointer to free function - // The following construct uses the preprocessor to generate - // add_if_trackable() overloads accepting pointer-to-function taking - // 0, 1, ..., LLEVENTS_LISTENER_ARITY parameters of arbitrary type. -#define BOOST_PP_LOCAL_MACRO(n) \ - template <typename R \ - BOOST_PP_COMMA_IF(n) \ - BOOST_PP_ENUM_PARAMS(n, typename T)> \ - inline void \ - add_if_trackable(R (*)(BOOST_PP_ENUM_PARAMS(n, T))) const \ - { \ - } -#define BOOST_PP_LOCAL_LIMITS (0, LLEVENTS_LISTENER_ARITY) -#include BOOST_PP_LOCAL_ITERATE() -#undef BOOST_PP_LOCAL_MACRO -#undef BOOST_PP_LOCAL_LIMITS -|*==========================================================================*/ - - /// Bind a reference to the LLEventListener to call its track() method. - LLEventListener& mListener; - }; - - /** - * Utility template function to use Visitor appropriately - * - * @param raw_listener Callable to connect, typically a boost::bind() - * expression. This will be visited by Visitor using boost::visit_each(). - * @param connect_funct Callable that will connect() @a raw_listener to an - * LLStandardSignal, returning LLBoundListener. - */ - template <typename LISTENER> - LLBoundListener visit_and_connect(const std::string& name, - const LISTENER& raw_listener, - const ConnectFunc& connect_func) - { - // Capture the listener - LLEventListener listener(raw_listener); - // Define our Visitor, binding the listener so we can call - // listener.track() if we discover any shared_ptr<Foo>. - LLEventDetail::Visitor visitor(listener); - // Allow unqualified visit_each() call for ADL - using boost::visit_each; - // Visit each component of a boost::bind() expression. Pass - // 'raw_listener', our template argument, rather than 'listener' from - // which type details have been erased. unwrap() comes from - // Boost.Signals, in case we were passed a boost::ref(). - visit_each(visitor, LLEventDetail::unwrap(raw_listener)); - // Make the connection using passed function. - LLBoundListener connection(connect_func(listener)); - // If the LISTENER is an LLListenerWrapperBase subclass, pass it the - // desired information. It's important that we pass the raw_listener - // so the compiler can make decisions based on its original type. - const LLListenerWrapperBase* lwb = - ll_template_cast<const LLListenerWrapperBase*>(&raw_listener); - if (lwb) - { - lwb->accept_name(name); - lwb->accept_connection(connection); - } - // In any case, show new connection to caller. - return connection; - } -} // namespace LLEventDetail - // Somewhat to my surprise, passing boost::bind(...boost::weak_ptr<T>...) to // listen() fails in Boost code trying to instantiate LLEventListener (i.e. // LLStandardSignal::slot_type) because the boost::get_pointer() utility function isn't @@ -1142,12 +755,4 @@ namespace boost T* get_pointer(const weak_ptr<T>& ptr) { return shared_ptr<T>(ptr).get(); } } -/// Since we forbid use of listen(boost::bind(...shared_ptr<T>...)), provide an -/// easy way to cast to the corresponding weak_ptr. -template <typename T> -boost::weak_ptr<T> weaken(const boost::shared_ptr<T>& ptr) -{ - return boost::weak_ptr<T>(ptr); -} - #endif /* ! defined(LL_LLEVENTS_H) */ diff --git a/indra/llcommon/lleventtimer.cpp b/indra/llcommon/lleventtimer.cpp index 0d96e03da4..f575a7b6bf 100644 --- a/indra/llcommon/lleventtimer.cpp +++ b/indra/llcommon/lleventtimer.cpp @@ -57,29 +57,17 @@ LLEventTimer::~LLEventTimer() //static void LLEventTimer::updateClass() { - std::list<LLEventTimer*> completed_timers; - for (instance_iter iter = beginInstances(); iter != endInstances(); ) + for (auto& timer : instance_snapshot()) { - LLEventTimer& timer = *iter++; F32 et = timer.mEventTimer.getElapsedTimeF32(); if (timer.mEventTimer.getStarted() && et > timer.mPeriod) { timer.mEventTimer.reset(); if ( timer.tick() ) { - completed_timers.push_back( &timer ); + delete &timer; } } } - - if ( completed_timers.size() > 0 ) - { - for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin(); - completed_iter != completed_timers.end(); - completed_iter++ ) - { - delete *completed_iter; - } - } } diff --git a/indra/llcommon/lleventtimer.h b/indra/llcommon/lleventtimer.h index dc918121e1..dbbfe0c6e6 100644 --- a/indra/llcommon/lleventtimer.h +++ b/indra/llcommon/lleventtimer.h @@ -40,16 +40,83 @@ public: LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds LLEventTimer(const LLDate& time); virtual ~LLEventTimer(); - + //function to be called at the supplied frequency // Normally return FALSE; TRUE will delete the timer after the function returns. virtual BOOL tick() = 0; static void updateClass(); + /// Schedule recurring calls to generic callable every period seconds. + /// Returns a pointer; if you delete it, cancels the recurring calls. + template <typename CALLABLE> + static LLEventTimer* run_every(F32 period, const CALLABLE& callable); + + /// Schedule a future call to generic callable. Returns a pointer. + /// CAUTION: The object referenced by that pointer WILL BE DELETED once + /// the callback has been called! LLEventTimer::getInstance(pointer) (NOT + /// pointer->getInstance(pointer)!) can be used to test whether the + /// pointer is still valid. If it is, deleting it will cancel the + /// callback. + template <typename CALLABLE> + static LLEventTimer* run_at(const LLDate& time, const CALLABLE& callable); + + /// Like run_at(), but after a time delta rather than at a timestamp. + /// Same CAUTION. + template <typename CALLABLE> + static LLEventTimer* run_after(F32 interval, const CALLABLE& callable); + protected: LLTimer mEventTimer; F32 mPeriod; + +private: + template <typename CALLABLE> + class Generic; +}; + +template <typename CALLABLE> +class LLEventTimer::Generic: public LLEventTimer +{ +public: + // making TIME generic allows engaging either LLEventTimer constructor + template <typename TIME> + Generic(const TIME& time, bool once, const CALLABLE& callable): + LLEventTimer(time), + mOnce(once), + mCallable(callable) + {} + BOOL tick() override + { + mCallable(); + // true tells updateClass() to delete this instance + return mOnce; + } + +private: + bool mOnce; + CALLABLE mCallable; }; +template <typename CALLABLE> +LLEventTimer* LLEventTimer::run_every(F32 period, const CALLABLE& callable) +{ + // return false to schedule recurring calls + return new Generic<CALLABLE>(period, false, callable); +} + +template <typename CALLABLE> +LLEventTimer* LLEventTimer::run_at(const LLDate& time, const CALLABLE& callable) +{ + // return true for one-shot callback + return new Generic<CALLABLE>(time, true, callable); +} + +template <typename CALLABLE> +LLEventTimer* LLEventTimer::run_after(F32 interval, const CALLABLE& callable) +{ + // one-shot callback after specified interval + return new Generic<CALLABLE>(interval, true, callable); +} + #endif //LL_EVENTTIMER_H diff --git a/indra/llcommon/llexception.cpp b/indra/llcommon/llexception.cpp index b32ec2c9c9..b584b0ff8b 100644 --- a/indra/llcommon/llexception.cpp +++ b/indra/llcommon/llexception.cpp @@ -18,10 +18,31 @@ #include <typeinfo> // external library headers #include <boost/exception/diagnostic_information.hpp> +#include <boost/exception/error_info.hpp> +// On Mac, got: +// #error "Boost.Stacktrace requires `_Unwind_Backtrace` function. Define +// `_GNU_SOURCE` macro or `BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED` if +// _Unwind_Backtrace is available without `_GNU_SOURCE`." +#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED + +#if LL_WINDOWS +// On Windows, header-only implementation causes macro collisions -- use +// prebuilt library +#define BOOST_STACKTRACE_LINK +#include <excpt.h> +#endif // LL_WINDOWS + +#include <boost/stacktrace.hpp> // other Linden headers #include "llerror.h" #include "llerrorcontrol.h" +// used to attach and extract stacktrace information to/from boost::exception, +// see https://www.boost.org/doc/libs/release/doc/html/stacktrace/getting_started.html#stacktrace.getting_started.exceptions_with_stacktrace +// apparently the struct passed as the first template param needs no definition? +typedef boost::error_info<struct errinfo_stacktrace_, boost::stacktrace::stacktrace> + errinfo_stacktrace; + namespace { // used by crash_on_unhandled_exception_() and log_unhandled_exception_() void log_unhandled_exception_(LLError::ELevel level, @@ -53,3 +74,39 @@ void log_unhandled_exception_(const char* file, int line, const char* pretty_fun // routinely, but we DO expect to return from this function. log_unhandled_exception_(LLError::LEVEL_WARN, file, line, pretty_function, context); } + +void annotate_exception_(boost::exception& exc) +{ + // https://www.boost.org/doc/libs/release/libs/exception/doc/tutorial_transporting_data.html + // "Adding of Arbitrary Data to Active Exception Objects" + // Given a boost::exception&, we can add boost::error_info items to it + // without knowing its leaf type. + // The stacktrace constructor that lets us skip a level -- and why would + // we always include annotate_exception_()? -- also requires a max depth. + // For the nullary constructor, the stacktrace class declaration itself + // passes static_cast<std::size_t>(-1), but that's kind of dubious. + // Anyway, which of us is really going to examine more than 100 frames? + exc << errinfo_stacktrace(boost::stacktrace::stacktrace(1, 100)); +} + +#if LL_WINDOWS + +// For windows SEH exception handling we sometimes need a filter that will +// separate C++ exceptions from C SEH exceptions +static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific + +U32 msc_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) +{ + if (code == STATUS_MSC_EXCEPTION) + { + // C++ exception, go on + return EXCEPTION_CONTINUE_SEARCH; + } + else + { + // handle it + return EXCEPTION_EXECUTE_HANDLER; + } +} + +#endif //LL_WINDOWS diff --git a/indra/llcommon/llexception.h b/indra/llcommon/llexception.h index dfcb7c192f..375bea4a57 100644 --- a/indra/llcommon/llexception.h +++ b/indra/llcommon/llexception.h @@ -67,9 +67,29 @@ struct LLContinueError: public LLException * enriches the exception's diagnostic_information() with the source file, * line and containing function of the LLTHROW() macro. */ -// Currently we implement that using BOOST_THROW_EXCEPTION(). Wrap it in -// LLTHROW() in case we ever want to revisit that implementation decision. -#define LLTHROW(x) BOOST_THROW_EXCEPTION(x) +#define LLTHROW(x) \ +do { \ + /* Capture the exception object 'x' by value. (Exceptions must */ \ + /* be copyable.) It might seem simpler to use */ \ + /* BOOST_THROW_EXCEPTION(annotate_exception_(x)) instead of */ \ + /* three separate statements, but: */ \ + /* - We want to throw 'x' with its original type, not just a */ \ + /* reference to boost::exception. */ \ + /* - To return x's original type, annotate_exception_() would */ \ + /* have to be a template function. */ \ + /* - We want annotate_exception_() to be opaque. */ \ + /* We also might consider embedding BOOST_THROW_EXCEPTION() in */ \ + /* our helper function, but we want the filename and line info */ \ + /* embedded by BOOST_THROW_EXCEPTION() to be the throw point */ \ + /* rather than always indicating the same line in */ \ + /* llexception.cpp. */ \ + auto exc{x}; \ + annotate_exception_(exc); \ + BOOST_THROW_EXCEPTION(exc); \ + /* Use the classic 'do { ... } while (0)' macro trick to wrap */ \ + /* our multiple statements. */ \ +} while (0) +void annotate_exception_(boost::exception& exc); /// Call this macro from a catch (...) clause #define CRASH_ON_UNHANDLED_EXCEPTION(CONTEXT) \ @@ -82,4 +102,14 @@ void crash_on_unhandled_exception_(const char*, int, const char*, const std::str log_unhandled_exception_(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, CONTEXT) void log_unhandled_exception_(const char*, int, const char*, const std::string&); + +#if LL_WINDOWS + +// SEH exception filtering for use in __try __except +// Separates C++ exceptions from C SEH exceptions +// Todo: might be good idea to do some kind of seh_to_msc_wrapper(function, ARGS&&); +U32 msc_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop); + +#endif //LL_WINDOWS + #endif /* ! defined(LL_LLEXCEPTION_H) */ diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp index 3d28cd15b0..5b6a7b82f8 100644 --- a/indra/llcommon/llfasttimer.cpp +++ b/indra/llcommon/llfasttimer.cpp @@ -43,7 +43,7 @@ #if LL_WINDOWS #include "lltimer.h" -#elif LL_LINUX || LL_SOLARIS +#elif LL_LINUX #include <sys/time.h> #include <sched.h> #include "lltimer.h" @@ -64,7 +64,7 @@ bool BlockTimer::sLog = false; std::string BlockTimer::sLogName = ""; bool BlockTimer::sMetricLog = false; -#if LL_LINUX || LL_SOLARIS +#if LL_LINUX U64 BlockTimer::sClockResolution = 1000000000; // Nanosecond resolution #else U64 BlockTimer::sClockResolution = 1000000; // Microsecond resolution @@ -151,12 +151,12 @@ void BlockTimer::setLogLock(LLMutex* lock) //static -#if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__)) +#if (LL_DARWIN || LL_LINUX) && !(defined(__i386__) || defined(__amd64__)) U64 BlockTimer::countsPerSecond() { return sClockResolution; } -#else // windows or x86-mac or x86-linux or x86-solaris +#else // windows or x86-mac or x86-linux U64 BlockTimer::countsPerSecond() { #if LL_FASTTIMER_USE_RDTSC || !LL_WINDOWS @@ -193,27 +193,26 @@ TimeBlockTreeNode& BlockTimerStatHandle::getTreeNode() const void BlockTimer::bootstrapTimerTree() { - for (BlockTimerStatHandle::instance_tracker_t::instance_iter it = BlockTimerStatHandle::instance_tracker_t::beginInstances(), end_it = BlockTimerStatHandle::instance_tracker_t::endInstances(); - it != end_it; - ++it) + for (auto& base : BlockTimerStatHandle::instance_snapshot()) { - BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(*it); + // because of indirect derivation from LLInstanceTracker, have to downcast + BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base); if (&timer == &BlockTimer::getRootTimeBlock()) continue; // bootstrap tree construction by attaching to last timer to be on stack // when this timer was called if (timer.getParent() == &BlockTimer::getRootTimeBlock()) -{ + { TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator(); if (accumulator.mLastCaller) - { + { timer.setParent(accumulator.mLastCaller); accumulator.mParent = accumulator.mLastCaller; - } + } // no need to push up tree on first use, flag can be set spuriously accumulator.mMoveUpTree = false; - } + } } } @@ -306,12 +305,10 @@ void BlockTimer::processTimes() updateTimes(); // reset for next frame - for (BlockTimerStatHandle::instance_tracker_t::instance_iter it = BlockTimerStatHandle::instance_tracker_t::beginInstances(), - end_it = BlockTimerStatHandle::instance_tracker_t::endInstances(); - it != end_it; - ++it) + for (auto& base : BlockTimerStatHandle::instance_snapshot()) { - BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(*it); + // because of indirect derivation from LLInstanceTracker, have to downcast + BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base); TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator(); accumulator.mLastCaller = NULL; @@ -362,12 +359,10 @@ void BlockTimer::logStats() LLSD sd; { - for (BlockTimerStatHandle::instance_tracker_t::instance_iter it = BlockTimerStatHandle::instance_tracker_t::beginInstances(), - end_it = BlockTimerStatHandle::instance_tracker_t::endInstances(); - it != end_it; - ++it) + for (auto& base : BlockTimerStatHandle::instance_snapshot()) { - BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(*it); + // because of indirect derivation from LLInstanceTracker, have to downcast + BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base); LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording(); sd[timer.getName()]["Time"] = (LLSD::Real) (frame_recording.getLastRecording().getSum(timer).value()); sd[timer.getName()]["Calls"] = (LLSD::Integer) (frame_recording.getLastRecording().getSum(timer.callCount())); diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index d463fc9d65..dfc63d08a2 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -31,6 +31,10 @@ #include "lltrace.h" #include "lltreeiterators.h" +#if LL_WINDOWS +#include <intrin.h> +#endif + #define LL_FAST_TIMER_ON 1 #define LL_FASTTIMER_USE_RDTSC 1 @@ -85,6 +89,8 @@ public: // return __rdtsc(); //} + + // shift off lower 8 bits for lower resolution but longer term timing // on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing #if LL_FASTTIMER_USE_RDTSC @@ -119,9 +125,9 @@ public: #endif -#if (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__)) +#if (LL_LINUX) && !(defined(__i386__) || defined(__amd64__)) // - // Linux and Solaris implementation of CPU clock - non-x86. + // Linux implementation of CPU clock - non-x86. // This is accurate but SLOW! Only use out of desperation. // // Try to use the MONOTONIC clock if available, this is a constant time counter @@ -147,12 +153,12 @@ public: return (U32)(getCPUClockCount64() >> 8); } -#endif // (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__)) +#endif // (LL_LINUX) && !(defined(__i386__) || defined(__amd64__)) -#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__)) +#if (LL_LINUX || LL_DARWIN) && (defined(__i386__) || defined(__amd64__)) // - // Mac+Linux+Solaris FAST x86 implementation of CPU clock + // Mac+Linux FAST x86 implementation of CPU clock static U32 getCPUClockCount32() { U32 low(0),high(0); diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index 398938b729..9de095b45d 100644 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -86,6 +86,69 @@ public: static const char * tmpdir(); }; +/// RAII class +class LLUniqueFile +{ +public: + // empty + LLUniqueFile(): mFileHandle(nullptr) {} + // wrap (e.g.) result of LLFile::fopen() + LLUniqueFile(LLFILE* f): mFileHandle(f) {} + // no copy + LLUniqueFile(const LLUniqueFile&) = delete; + // move construction + LLUniqueFile(LLUniqueFile&& other) + { + mFileHandle = other.mFileHandle; + other.mFileHandle = nullptr; + } + // The point of LLUniqueFile is to close on destruction. + ~LLUniqueFile() + { + close(); + } + + // simple assignment + LLUniqueFile& operator=(LLFILE* f) + { + close(); + mFileHandle = f; + return *this; + } + // copy assignment deleted + LLUniqueFile& operator=(const LLUniqueFile&) = delete; + // move assignment + LLUniqueFile& operator=(LLUniqueFile&& other) + { + close(); + std::swap(mFileHandle, other.mFileHandle); + return *this; + } + + // explicit close operation + void close() + { + if (mFileHandle) + { + // in case close() throws, set mFileHandle null FIRST + LLFILE* h{nullptr}; + std::swap(h, mFileHandle); + LLFile::close(h); + } + } + + // detect whether the wrapped LLFILE is open or not + explicit operator bool() const { return bool(mFileHandle); } + bool operator!() { return ! mFileHandle; } + + // LLUniqueFile should be usable for any operation that accepts LLFILE* + // (or FILE* for that matter) + operator LLFILE*() const { return mFileHandle; } + +private: + LLFILE* mFileHandle; +}; + #if LL_WINDOWS /** * @brief Controlling input for files. diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp index 3f990f4869..e7193b70b5 100644 --- a/indra/llcommon/llinstancetracker.cpp +++ b/indra/llcommon/llinstancetracker.cpp @@ -27,25 +27,15 @@ #include "linden_common.h" // associated header #include "llinstancetracker.h" -#include "llapr.h" - +#include "llerror.h" // STL headers // std headers // external library headers // other Linden headers -void LLInstanceTrackerBase::StaticBase::incrementDepth() -{ - ++sIterationNestDepth; -} - -void LLInstanceTrackerBase::StaticBase::decrementDepth() -{ - llassert(sIterationNestDepth); - --sIterationNestDepth; -} - -U32 LLInstanceTrackerBase::StaticBase::getDepth() +void LLInstanceTrackerPrivate::logerrs(const char* cls, const std::string& arg1, + const std::string& arg2, const std::string& arg3) { - return sIterationNestDepth; + LL_ERRS("LLInstanceTracker") << LLError::Log::demangle(cls) + << arg1 << arg2 << arg3 << LL_ENDL; } diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index 363d0bcbd5..402333cca7 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -28,354 +28,432 @@ #ifndef LL_LLINSTANCETRACKER_H #define LL_LLINSTANCETRACKER_H -#include <atomic> #include <map> +#include <set> +#include <vector> #include <typeinfo> +#include <memory> +#include <type_traits> + +#include "mutex.h" -#include "llstringtable.h" #include <boost/iterator/transform_iterator.hpp> #include <boost/iterator/indirect_iterator.hpp> +#include <boost/iterator/filter_iterator.hpp> -// As of 2017-05-06, as far as nat knows, only clang supports __has_feature(). -// Unfortunately VS2013's preprocessor shortcut logic doesn't prevent it from -// producing (fatal) warnings for defined(__clang__) && __has_feature(...). -// Have to work around that. -#if ! defined(__clang__) -#define __has_feature(x) 0 -#endif // __clang__ - -#if defined(LL_TEST_llinstancetracker) && __has_feature(cxx_noexcept) -// ~LLInstanceTracker() performs llassert_always() validation. That's fine in -// production code, since the llassert_always() is implemented as an LL_ERRS -// message, which will crash-with-message. In our integration test executable, -// though, this llassert_always() throws an exception instead so we can test -// error conditions and continue running the test. However -- as of C++11, -// destructors are implicitly noexcept(true). Unless we mark -// ~LLInstanceTracker() noexcept(false), the test executable crashes even on -// the ATTEMPT to throw. -#define LLINSTANCETRACKER_DTOR_NOEXCEPT noexcept(false) -#else -// If we're building for production, or in fact building *any other* test, or -// we're using a compiler that doesn't support __has_feature(), or we're not -// compiling with a C++ version that supports noexcept -- don't specify it. -#define LLINSTANCETRACKER_DTOR_NOEXCEPT -#endif +#include "lockstatic.h" +#include "stringize.h" -/** - * Base class manages "class-static" data that must actually have singleton - * semantics: one instance per process, rather than one instance per module as - * sometimes happens with data simply declared static. - */ -class LL_COMMON_API LLInstanceTrackerBase +/***************************************************************************** +* StaticBase +*****************************************************************************/ +namespace LLInstanceTrackerPrivate { -protected: - /// It's not essential to derive your STATICDATA (for use with - /// getStatic()) from StaticBase; it's just that both known - /// implementations do. struct StaticBase { - StaticBase(): - sIterationNestDepth(0) - {} - - void incrementDepth(); - void decrementDepth(); - U32 getDepth(); - private: -#ifdef LL_WINDOWS - std::atomic_uint32_t sIterationNestDepth; -#else - std::atomic_uint sIterationNestDepth; -#endif - }; -}; + // We need to be able to lock static data while manipulating it. + std::mutex mMutex; + }; -LL_COMMON_API void assert_main_thread(); + void logerrs(const char* cls, const std::string&, const std::string&, const std::string&); +} // namespace LLInstanceTrackerPrivate +/***************************************************************************** +* LLInstanceTracker with key +*****************************************************************************/ enum EInstanceTrackerAllowKeyCollisions { - LLInstanceTrackerErrorOnCollision, - LLInstanceTrackerReplaceOnCollision + LLInstanceTrackerErrorOnCollision, + LLInstanceTrackerReplaceOnCollision }; /// This mix-in class adds support for tracking all instances of the specified class parameter T /// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup /// If KEY is not provided, then instances are stored in a simple set /// @NOTE: see explicit specialization below for default KEY==void case -/// @NOTE: this class is not thread-safe unless used as read-only -template<typename T, typename KEY = void, EInstanceTrackerAllowKeyCollisions KEY_COLLISION_BEHAVIOR = LLInstanceTrackerErrorOnCollision> -class LLInstanceTracker : public LLInstanceTrackerBase +template<typename T, typename KEY = void, + EInstanceTrackerAllowKeyCollisions KEY_COLLISION_BEHAVIOR = LLInstanceTrackerErrorOnCollision> +class LLInstanceTracker { - typedef LLInstanceTracker<T, KEY> self_t; - typedef typename std::multimap<KEY, T*> InstanceMap; - struct StaticData: public StaticBase - { - InstanceMap sMap; - }; - static StaticData& getStatic() { static StaticData sData; return sData;} - static InstanceMap& getMap_() { return getStatic().sMap; } + typedef std::map<KEY, std::shared_ptr<T>> InstanceMap; + struct StaticData: public LLInstanceTrackerPrivate::StaticBase + { + InstanceMap mMap; + }; + typedef llthread::LockStatic<StaticData> LockStatic; public: - class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> - { - public: - typedef boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> super_t; - - instance_iter(const typename InstanceMap::iterator& it) - : mIterator(it) - { - getStatic().incrementDepth(); - } - - ~instance_iter() - { - getStatic().decrementDepth(); - } - - - private: - friend class boost::iterator_core_access; - - void increment() { mIterator++; } - bool equal(instance_iter const& other) const - { - return mIterator == other.mIterator; - } - - T& dereference() const - { - return *(mIterator->second); - } - - typename InstanceMap::iterator mIterator; - }; - - class key_iter : public boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> - { - public: - typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t; - - key_iter(typename InstanceMap::iterator it) - : mIterator(it) - { - getStatic().incrementDepth(); - } - - key_iter(const key_iter& other) - : mIterator(other.mIterator) - { - getStatic().incrementDepth(); - } - - ~key_iter() - { - getStatic().decrementDepth(); - } - - - private: - friend class boost::iterator_core_access; - - void increment() { mIterator++; } - bool equal(key_iter const& other) const - { - return mIterator == other.mIterator; - } - - KEY& dereference() const - { - return const_cast<KEY&>(mIterator->first); - } - - typename InstanceMap::iterator mIterator; - }; - - static T* getInstance(const KEY& k) - { - const InstanceMap& map(getMap_()); - typename InstanceMap::const_iterator found = map.find(k); - return (found == map.end()) ? NULL : found->second; - } - - static instance_iter beginInstances() - { - return instance_iter(getMap_().begin()); - } - - static instance_iter endInstances() - { - return instance_iter(getMap_().end()); - } - - static S32 instanceCount() - { - return getMap_().size(); - } - - static key_iter beginKeys() - { - return key_iter(getMap_().begin()); - } - static key_iter endKeys() - { - return key_iter(getMap_().end()); - } + // snapshot of std::pair<const KEY, std::shared_ptr<T>> pairs + class snapshot + { + // It's very important that what we store in this snapshot are + // weak_ptrs, NOT shared_ptrs. That's how we discover whether any + // instance has been deleted during the lifespan of a snapshot. + typedef std::vector<std::pair<const KEY, std::weak_ptr<T>>> VectorType; + // Dereferencing our iterator produces a std::shared_ptr for each + // instance that still exists. Since we store weak_ptrs, that involves + // two chained transformations: + // - a transform_iterator to lock the weak_ptr and return a shared_ptr + // - a filter_iterator to skip any shared_ptr that has become invalid. + // It is very important that we filter lazily, that is, during + // traversal. Any one of our stored weak_ptrs might expire during + // traversal. + typedef std::pair<const KEY, std::shared_ptr<T>> strong_pair; + // Note for future reference: nat has not yet had any luck (up to + // Boost 1.67) trying to use boost::transform_iterator with a hand- + // coded functor, only with actual functions. In my experience, an + // internal boost::result_of() operation fails, even with an explicit + // result_type typedef. But this works. + static strong_pair strengthen(typename VectorType::value_type& pair) + { + return { pair.first, pair.second.lock() }; + } + static bool dead_skipper(const strong_pair& pair) + { + return bool(pair.second); + } + + public: + snapshot(): + // populate our vector with a snapshot of (locked!) InstanceMap + // note, this assigns pair<KEY, shared_ptr> to pair<KEY, weak_ptr> + mData(mLock->mMap.begin(), mLock->mMap.end()) + { + // release the lock once we've populated mData + mLock.unlock(); + } + + // You can't make a transform_iterator (or anything else) that + // literally stores a C++ function (decltype(strengthen)) -- but you + // can make a transform_iterator based on a _function pointer._ + typedef boost::transform_iterator<decltype(strengthen)*, + typename VectorType::iterator> strong_iterator; + typedef boost::filter_iterator<decltype(dead_skipper)*, strong_iterator> iterator; + + iterator begin() { return make_iterator(mData.begin()); } + iterator end() { return make_iterator(mData.end()); } + + private: + iterator make_iterator(typename VectorType::iterator iter) + { + // transform_iterator only needs the base iterator and the transform. + // filter_iterator wants the predicate and both ends of the range. + return iterator(dead_skipper, + strong_iterator(iter, strengthen), + strong_iterator(mData.end(), strengthen)); + } + + // lock static data during construction +#if ! LL_WINDOWS + LockStatic mLock; +#else // LL_WINDOWS + // We want to be able to use (e.g.) our instance_snapshot subclass as: + // for (auto& inst : T::instance_snapshot()) ... + // But when this snapshot base class directly contains LockStatic, as + // above, Visual Studio 2017 requires us to code instead: + // for (auto& inst : std::move(T::instance_snapshot())) ... + // nat thinks this should be unnecessary, as an anonymous class + // instance is already a temporary. It shouldn't need to be cast to + // rvalue reference (the role of std::move()). clang evidently agrees, + // as the short form works fine with Xcode on Mac. + // To support the succinct usage, instead of directly storing + // LockStatic, store std::shared_ptr<LockStatic>, which is copyable. + std::shared_ptr<LockStatic> mLockp{std::make_shared<LockStatic>()}; + LockStatic& mLock{*mLockp}; +#endif // LL_WINDOWS + VectorType mData; + }; + + // iterate over this for references to each instance + class instance_snapshot: public snapshot + { + private: + static T& instance_getter(typename snapshot::iterator::reference pair) + { + return *pair.second; + } + public: + typedef boost::transform_iterator<decltype(instance_getter)*, + typename snapshot::iterator> iterator; + iterator begin() { return iterator(snapshot::begin(), instance_getter); } + iterator end() { return iterator(snapshot::end(), instance_getter); } + + void deleteAll() + { + for (auto it(snapshot::begin()), end(snapshot::end()); it != end; ++it) + { + delete it->second.get(); + } + } + }; + + // iterate over this for each key + class key_snapshot: public snapshot + { + private: + static KEY key_getter(typename snapshot::iterator::reference pair) + { + return pair.first; + } + public: + typedef boost::transform_iterator<decltype(key_getter)*, + typename snapshot::iterator> iterator; + iterator begin() { return iterator(snapshot::begin(), key_getter); } + iterator end() { return iterator(snapshot::end(), key_getter); } + }; + + static T* getInstance(const KEY& k) + { + LockStatic lock; + const InstanceMap& map(lock->mMap); + typename InstanceMap::const_iterator found = map.find(k); + return (found == map.end()) ? NULL : found->second.get(); + } + + static S32 instanceCount() + { + return LockStatic()->mMap.size(); + } protected: - LLInstanceTracker(const KEY& key) - { - // make sure static data outlives all instances - getStatic(); - add_(key); - } - virtual ~LLInstanceTracker() LLINSTANCETRACKER_DTOR_NOEXCEPT - { - // it's unsafe to delete instances of this type while all instances are being iterated over. - llassert_always(getStatic().getDepth() == 0); - remove_(); - } - virtual void setKey(KEY key) { remove_(); add_(key); } - virtual const KEY& getKey() const { return mInstanceKey; } + LLInstanceTracker(const KEY& key) + { + // We do not intend to manage the lifespan of this object with + // shared_ptr, so give it a no-op deleter. We store shared_ptrs in our + // InstanceMap specifically so snapshot can store weak_ptrs so we can + // detect deletions during traversals. + std::shared_ptr<T> ptr(static_cast<T*>(this), [](T*){}); + LockStatic lock; + add_(lock, key, ptr); + } +public: + virtual ~LLInstanceTracker() + { + LockStatic lock; + remove_(lock); + } +protected: + virtual void setKey(KEY key) + { + LockStatic lock; + // Even though the shared_ptr we store in our map has a no-op deleter + // for T itself, letting the use count decrement to 0 will still + // delete the use-count object. Capture the shared_ptr we just removed + // and re-add it to the map with the new key. + auto ptr = remove_(lock); + add_(lock, key, ptr); + } +public: + virtual const KEY& getKey() const { return mInstanceKey; } private: - LLInstanceTracker( const LLInstanceTracker& ); - const LLInstanceTracker& operator=( const LLInstanceTracker& ); - - void add_(const KEY& key) - { - mInstanceKey = key; - InstanceMap& map = getMap_(); - typename InstanceMap::iterator insertion_point_it = map.lower_bound(key); - if (insertion_point_it != map.end() - && insertion_point_it->first == key) - { // found existing entry with that key - switch(KEY_COLLISION_BEHAVIOR) - { - case LLInstanceTrackerErrorOnCollision: - { - // use assert here instead of LL_ERRS(), otherwise the error will be ignored since this call is made during global object initialization - llassert_always_msg(false, "Instance with this same key already exists!"); - break; - } - case LLInstanceTrackerReplaceOnCollision: - { - // replace pointer, but leave key (should have compared equal anyway) - insertion_point_it->second = static_cast<T*>(this); - break; - } - default: - break; - } - } - else - { // new key - map.insert(insertion_point_it, std::make_pair(key, static_cast<T*>(this))); - } - } - void remove_() - { - InstanceMap& map = getMap_(); - typename InstanceMap::iterator iter = map.find(mInstanceKey); - if (iter != map.end()) - { - map.erase(iter); - } - } + LLInstanceTracker( const LLInstanceTracker& ) = delete; + LLInstanceTracker& operator=( const LLInstanceTracker& ) = delete; + + // for logging + template <typename K> + static std::string report(K key) { return stringize(key); } + static std::string report(const std::string& key) { return "'" + key + "'"; } + static std::string report(const char* key) { return report(std::string(key)); } + + // caller must instantiate LockStatic + void add_(LockStatic& lock, const KEY& key, const std::shared_ptr<T>& ptr) + { + mInstanceKey = key; + InstanceMap& map = lock->mMap; + switch(KEY_COLLISION_BEHAVIOR) + { + case LLInstanceTrackerErrorOnCollision: + { + // map stores shared_ptr to self + auto pair = map.emplace(key, ptr); + if (! pair.second) + { + LLInstanceTrackerPrivate::logerrs(typeid(*this).name(), " instance with key ", + report(key), " already exists!"); + } + break; + } + case LLInstanceTrackerReplaceOnCollision: + map[key] = ptr; + break; + default: + break; + } + } + std::shared_ptr<T> remove_(LockStatic& lock) + { + InstanceMap& map = lock->mMap; + typename InstanceMap::iterator iter = map.find(mInstanceKey); + if (iter != map.end()) + { + auto ret = iter->second; + map.erase(iter); + return ret; + } + return {}; + } private: - KEY mInstanceKey; + KEY mInstanceKey; }; +/***************************************************************************** +* LLInstanceTracker without key +*****************************************************************************/ +// TODO: +// - For the case of omitted KEY template parameter, consider storing +// std::map<T*, std::shared_ptr<T>> instead of std::set<std::shared_ptr<T>>. +// That might let us share more of the implementation between KEY and +// non-KEY LLInstanceTracker subclasses. +// - Even if not that, consider trying to unify the snapshot implementations. +// The trouble is that the 'iterator' published by each (and by their +// subclasses) must reflect the specific type of the callables that +// distinguish them. (Maybe make instance_snapshot() and key_snapshot() +// factory functions that pass lambdas to a factory function for the generic +// template class?) + /// explicit specialization for default case where KEY is void /// use a simple std::set<T*> template<typename T, EInstanceTrackerAllowKeyCollisions KEY_COLLISION_BEHAVIOR> -class LLInstanceTracker<T, void, KEY_COLLISION_BEHAVIOR> : public LLInstanceTrackerBase +class LLInstanceTracker<T, void, KEY_COLLISION_BEHAVIOR> { - typedef LLInstanceTracker<T, void> self_t; - typedef typename std::set<T*> InstanceSet; - struct StaticData: public StaticBase - { - InstanceSet sSet; - }; - static StaticData& getStatic() { static StaticData sData; return sData; } - static InstanceSet& getSet_() { return getStatic().sSet; } + typedef std::set<std::shared_ptr<T>> InstanceSet; + struct StaticData: public LLInstanceTrackerPrivate::StaticBase + { + InstanceSet mSet; + }; + typedef llthread::LockStatic<StaticData> LockStatic; public: + /** + * Storing a dumb T* somewhere external is a bad idea, since + * LLInstanceTracker subclasses are explicitly destroyed rather than + * managed by smart pointers. It's legal to declare stack instances of an + * LLInstanceTracker subclass. But it's reasonable to store a + * std::weak_ptr<T>, which will become invalid when the T instance is + * destroyed. + */ + std::weak_ptr<T> getWeak() + { + return mSelf; + } + + static S32 instanceCount() { return LockStatic()->mSet.size(); } - /** - * Does a particular instance still exist? Of course, if you already have - * a T* in hand, you need not call getInstance() to @em locate the - * instance -- unlike the case where getInstance() accepts some kind of - * key. Nonetheless this method is still useful to @em validate a - * particular T*, since each instance's destructor removes itself from the - * underlying set. - */ - static T* getInstance(T* k) - { - const InstanceSet& set(getSet_()); - typename InstanceSet::const_iterator found = set.find(k); - return (found == set.end())? NULL : *found; - } - static S32 instanceCount() { return getSet_().size(); } - - class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> - { - public: - instance_iter(const typename InstanceSet::iterator& it) - : mIterator(it) - { - getStatic().incrementDepth(); - } - - instance_iter(const instance_iter& other) - : mIterator(other.mIterator) - { - getStatic().incrementDepth(); - } - - ~instance_iter() - { - getStatic().decrementDepth(); - } - - private: - friend class boost::iterator_core_access; - - void increment() { mIterator++; } - bool equal(instance_iter const& other) const - { - return mIterator == other.mIterator; - } - - T& dereference() const - { - return **mIterator; - } - - typename InstanceSet::iterator mIterator; - }; - - static instance_iter beginInstances() { return instance_iter(getSet_().begin()); } - static instance_iter endInstances() { return instance_iter(getSet_().end()); } + // snapshot of std::shared_ptr<T> pointers + class snapshot + { + // It's very important that what we store in this snapshot are + // weak_ptrs, NOT shared_ptrs. That's how we discover whether any + // instance has been deleted during the lifespan of a snapshot. + typedef std::vector<std::weak_ptr<T>> VectorType; + // Dereferencing our iterator produces a std::shared_ptr for each + // instance that still exists. Since we store weak_ptrs, that involves + // two chained transformations: + // - a transform_iterator to lock the weak_ptr and return a shared_ptr + // - a filter_iterator to skip any shared_ptr that has become invalid. + typedef std::shared_ptr<T> strong_ptr; + static strong_ptr strengthen(typename VectorType::value_type& ptr) + { + return ptr.lock(); + } + static bool dead_skipper(const strong_ptr& ptr) + { + return bool(ptr); + } + + public: + snapshot(): + // populate our vector with a snapshot of (locked!) InstanceSet + // note, this assigns stored shared_ptrs to weak_ptrs for snapshot + mData(mLock->mSet.begin(), mLock->mSet.end()) + { + // release the lock once we've populated mData + mLock.unlock(); + } + + typedef boost::transform_iterator<decltype(strengthen)*, + typename VectorType::iterator> strong_iterator; + typedef boost::filter_iterator<decltype(dead_skipper)*, strong_iterator> iterator; + + iterator begin() { return make_iterator(mData.begin()); } + iterator end() { return make_iterator(mData.end()); } + + private: + iterator make_iterator(typename VectorType::iterator iter) + { + // transform_iterator only needs the base iterator and the transform. + // filter_iterator wants the predicate and both ends of the range. + return iterator(dead_skipper, + strong_iterator(iter, strengthen), + strong_iterator(mData.end(), strengthen)); + } + + // lock static data during construction +#if ! LL_WINDOWS + LockStatic mLock; +#else // LL_WINDOWS + // We want to be able to use our instance_snapshot subclass as: + // for (auto& inst : T::instance_snapshot()) ... + // But when this snapshot base class directly contains LockStatic, as + // above, Visual Studio 2017 requires us to code instead: + // for (auto& inst : std::move(T::instance_snapshot())) ... + // nat thinks this should be unnecessary, as an anonymous class + // instance is already a temporary. It shouldn't need to be cast to + // rvalue reference (the role of std::move()). clang evidently agrees, + // as the short form works fine with Xcode on Mac. + // To support the succinct usage, instead of directly storing + // LockStatic, store std::shared_ptr<LockStatic>, which is copyable. + std::shared_ptr<LockStatic> mLockp{std::make_shared<LockStatic>()}; + LockStatic& mLock{*mLockp}; +#endif // LL_WINDOWS + VectorType mData; + }; + + // iterate over this for references to each instance + struct instance_snapshot: public snapshot + { + typedef boost::indirect_iterator<typename snapshot::iterator> iterator; + iterator begin() { return iterator(snapshot::begin()); } + iterator end() { return iterator(snapshot::end()); } + + void deleteAll() + { + for (auto it(snapshot::begin()), end(snapshot::end()); it != end; ++it) + { + delete it->get(); + } + } + }; protected: - LLInstanceTracker() - { - // make sure static data outlives all instances - getStatic(); - getSet_().insert(static_cast<T*>(this)); - } - virtual ~LLInstanceTracker() LLINSTANCETRACKER_DTOR_NOEXCEPT - { - // it's unsafe to delete instances of this type while all instances are being iterated over. - llassert_always(getStatic().getDepth() == 0); - getSet_().erase(static_cast<T*>(this)); - } - - LLInstanceTracker(const LLInstanceTracker& other) - { - getSet_().insert(static_cast<T*>(this)); - } + LLInstanceTracker() + { + // Since we do not intend for this shared_ptr to manage lifespan, give + // it a no-op deleter. + std::shared_ptr<T> ptr(static_cast<T*>(this), [](T*){}); + // save corresponding weak_ptr for future reference + mSelf = ptr; + // Also store it in our class-static set to track this instance. + LockStatic()->mSet.emplace(ptr); + } +public: + virtual ~LLInstanceTracker() + { + // convert weak_ptr to shared_ptr because that's what we store in our + // InstanceSet + LockStatic()->mSet.erase(mSelf.lock()); + } +protected: + LLInstanceTracker(const LLInstanceTracker& other): + LLInstanceTracker() + {} + +private: + // Storing a weak_ptr to self is a bit like deriving from + // std::enable_shared_from_this(), except more explicit. + std::weak_ptr<T> mSelf; }; #endif diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp new file mode 100644 index 0000000000..38696c2258 --- /dev/null +++ b/indra/llcommon/llkeybind.cpp @@ -0,0 +1,395 @@ +/** + * @file llkeybind.cpp + * @brief Information about key combinations. + * + * $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 "linden_common.h" + +#include "llkeybind.h" + +#include "llsd.h" +#include "llsdutil.h" + +LLKeyData::LLKeyData() + : + mMouse(CLICK_NONE), + mKey(KEY_NONE), + mMask(MASK_NONE), + mIgnoreMasks(false) +{ +} + +LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, MASK mask) + : + mMouse(mouse), + mKey(key), + mMask(mask), + mIgnoreMasks(false) +{ +} + +LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, bool ignore_mask) + : + mMouse(mouse), + mKey(key), + mMask(MASK_NONE), + mIgnoreMasks(ignore_mask) +{ +} + +LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask) + : + mMouse(mouse), + mKey(key), + mMask(mask), + mIgnoreMasks(ignore_mask) +{ +} + +LLKeyData::LLKeyData(const LLSD &key_data) +{ + if (key_data.has("mouse")) + { + mMouse = (EMouseClickType)key_data["mouse"].asInteger(); + } + if (key_data.has("key")) + { + mKey = key_data["key"].asInteger(); + } + if (key_data.has("ignore_accelerators")) + { + mIgnoreMasks = key_data["ignore_accelerators"]; + } + if (key_data.has("mask")) + { + mMask = key_data["mask"].asInteger(); + } +} + +LLSD LLKeyData::asLLSD() const +{ + LLSD data; + data["mouse"] = (LLSD::Integer)mMouse; + data["key"] = (LLSD::Integer)mKey; + data["mask"] = (LLSD::Integer)mMask; + if (mIgnoreMasks) + { + data["ignore_accelerators"] = (LLSD::Boolean)mIgnoreMasks; + } + return data; +} + +bool LLKeyData::isEmpty() const +{ + return mMouse == CLICK_NONE && mKey == KEY_NONE; +} + +void LLKeyData::reset() +{ + mMouse = CLICK_NONE; + mKey = KEY_NONE; + mMask = MASK_NONE; + mIgnoreMasks = false; +} + +LLKeyData& LLKeyData::operator=(const LLKeyData& rhs) +{ + mMouse = rhs.mMouse; + mKey = rhs.mKey; + mMask = rhs.mMask; + mIgnoreMasks = rhs.mIgnoreMasks; + return *this; +} + +bool LLKeyData::operator==(const LLKeyData& rhs) +{ + if (mMouse != rhs.mMouse) return false; + if (mKey != rhs.mKey) return false; + if (mMask != rhs.mMask) return false; + if (mIgnoreMasks != rhs.mIgnoreMasks) return false; + return true; +} + +bool LLKeyData::operator!=(const LLKeyData& rhs) +{ + if (mMouse != rhs.mMouse) return true; + if (mKey != rhs.mKey) return true; + if (mMask != rhs.mMask) return true; + if (mIgnoreMasks != rhs.mIgnoreMasks) return true; + return false; +} + +bool LLKeyData::canHandle(const LLKeyData& data) const +{ + if (data.mKey == mKey + && data.mMouse == mMouse + && ((mIgnoreMasks && (data.mMask & mMask) == mMask) || data.mMask == mMask)) + { + return true; + } + return false; +} + +bool LLKeyData::canHandle(EMouseClickType mouse, KEY key, MASK mask) const +{ + if (mouse == mMouse + && key == mKey + && ((mIgnoreMasks && (mask & mMask) == mMask) || mask == mMask)) + { + return true; + } + return false; +} + +// LLKeyBind + +LLKeyBind::LLKeyBind(const LLSD &key_bind) +{ + if (key_bind.isArray()) + { + for (LLSD::array_const_iterator data = key_bind.beginArray(), endLists = key_bind.endArray(); + data != endLists; + data++ + ) + { + mData.push_back(LLKeyData(*data)); + } + } +} + +bool LLKeyBind::operator==(const LLKeyBind& rhs) +{ + U32 size = mData.size(); + if (size != rhs.mData.size()) return false; + + for (U32 i = 0; i < size; i++) + { + if (mData[i] != rhs.mData[i]) return false; + } + + return true; +} + +bool LLKeyBind::operator!=(const LLKeyBind& rhs) +{ + U32 size = mData.size(); + if (size != rhs.mData.size()) return true; + + for (U32 i = 0; i < size; i++) + { + if (mData[i] != rhs.mData[i]) return true; + } + + return false; +} + +bool LLKeyBind::isEmpty() const +{ + for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++) + { + if (!iter->isEmpty()) return false; + } + return true; +} + +LLSD LLKeyBind::asLLSD() const +{ + S32 last = mData.size() - 1; + while (mData[last].empty()) + { + last--; + } + + LLSD data; + for (S32 i = 0; i <= last; ++i) + { + // append even if empty to not affect visual representation + data.append(mData[i].asLLSD()); + } + return data; +} + +bool LLKeyBind::canHandle(EMouseClickType mouse, KEY key, MASK mask) const +{ + if (mouse == CLICK_NONE && key == KEY_NONE) + { + // assume placeholder + return false; + } + + for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++) + { + if (iter->canHandle(mouse, key, mask)) + { + return true; + } + } + return false; +} + +bool LLKeyBind::canHandleKey(KEY key, MASK mask) const +{ + return canHandle(CLICK_NONE, key, mask); +} + +bool LLKeyBind::canHandleMouse(EMouseClickType mouse, MASK mask) const +{ + return canHandle(mouse, KEY_NONE, mask); +} + +bool LLKeyBind::hasKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const +{ + if (mouse != CLICK_NONE || key != KEY_NONE) + { + for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++) + { + if (iter->mKey == key + && iter->mMask == mask + && iter->mMouse == mouse + && iter->mIgnoreMasks == ignore) + { + return true; + } + } + } + return false; +} + +bool LLKeyBind::hasKeyData(const LLKeyData& data) const +{ + return hasKeyData(data.mMouse, data.mKey, data.mMask, data.mIgnoreMasks); +} + +bool LLKeyBind::hasKeyData(U32 index) const +{ + return mData.size() > index; +} + +S32 LLKeyBind::findKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const +{ + if (mouse != CLICK_NONE || key != KEY_NONE) + { + for (S32 i = 0; i < mData.size(); ++i) + { + if (mData[i].mKey == key + && mData[i].mMask == mask + && mData[i].mMouse == mouse + && mData[i].mIgnoreMasks == ignore) + { + return i; + } + } + } + return -1; +} + +S32 LLKeyBind::findKeyData(const LLKeyData& data) const +{ + return findKeyData(data.mMouse, data.mKey, data.mMask, data.mIgnoreMasks); +} + +LLKeyData LLKeyBind::getKeyData(U32 index) const +{ + if (mData.size() > index) + { + return mData[index]; + } + return LLKeyData(); +} + +bool LLKeyBind::addKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) +{ + if (!hasKeyData(mouse, key, mask, ignore)) + { + mData.push_back(LLKeyData(mouse, key, mask, ignore)); + return true; + } + return false; +} + +bool LLKeyBind::addKeyData(const LLKeyData& data) +{ + if (!hasKeyData(data)) + { + mData.push_back(data); + return true; + } + return false; +} + +void LLKeyBind::replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore, U32 index) +{ + replaceKeyData(LLKeyData(mouse, key, mask, ignore), index); +} + +void LLKeyBind::replaceKeyData(const LLKeyData& data, U32 index) +{ + if (!data.isEmpty()) + { + // if both click and key are none (isEmpty()), we are inserting a placeholder, we don't want to reset anything + // otherwise reset identical key + for (data_vector_t::iterator iter = mData.begin(); iter != mData.end(); iter++) + { + if (iter->mKey == data.mKey + && iter->mMouse == data.mMouse + && iter->mIgnoreMasks == data.mIgnoreMasks + && iter->mMask == data.mMask) + { + // Replacing only fully equal combinations even in case 'ignore' is set + // Reason: Simplicity and user might decide to do a 'move' command as W and Shift+Ctrl+W, and 'run' as Shift+W + iter->reset(); + break; + } + } + } + if (mData.size() <= index) + { + mData.resize(index + 1); + } + mData[index] = data; +} + +void LLKeyBind::resetKeyData(S32 index) +{ + if (mData.size() > index) + { + mData[index].reset(); + } +} + +void LLKeyBind::trimEmpty() +{ + S32 last = mData.size() - 1; + while (last >= 0 && mData[last].empty()) + { + mData.erase(mData.begin() + last); + last--; + } +} + +U32 LLKeyBind::getDataCount() +{ + return mData.size(); +} + diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h new file mode 100644 index 0000000000..c6b4bd970f --- /dev/null +++ b/indra/llcommon/llkeybind.h @@ -0,0 +1,106 @@ +/** + * @file llkeybind.h + * @brief Information about key combinations. + * + * $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_KEYBIND_H +#define LL_KEYBIND_H + +#include "indra_constants.h" + +// KeyData - single key combination (mouse/mask/keyboard) +class LL_COMMON_API LLKeyData +{ +public: + LLKeyData(); + LLKeyData(EMouseClickType mouse, KEY key, MASK mask); + LLKeyData(EMouseClickType mouse, KEY key, bool ignore_mask); + LLKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask); + LLKeyData(const LLSD &key_data); + + LLSD asLLSD() const; + bool isEmpty() const; + bool empty() const { return isEmpty(); }; + void reset(); + LLKeyData& operator=(const LLKeyData& rhs); + bool operator==(const LLKeyData& rhs); + bool operator!=(const LLKeyData& rhs); + + bool canHandle(const LLKeyData& data) const; + bool canHandle(EMouseClickType mouse, KEY key, MASK mask) const; + + EMouseClickType mMouse; + KEY mKey; + MASK mMask; + // Either to expect exact match or ignore not expected masks as long as expected mask-bit is present + bool mIgnoreMasks; +}; + +// One function can bind to multiple Key options +class LLKeyBind +{ +public: + LLKeyBind() {} + LLKeyBind(const LLSD &key_bind); + + bool operator==(const LLKeyBind& rhs); + bool operator!=(const LLKeyBind& rhs); + bool isEmpty() const; + bool empty() const { return isEmpty(); }; + + LLSD asLLSD() const; + + bool canHandle(EMouseClickType mouse, KEY key, MASK mask) const; + bool canHandleKey(KEY key, MASK mask) const; + bool canHandleMouse(EMouseClickType mouse, MASK mask) const; + + // contains specified combination + bool hasKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const; + bool hasKeyData(const LLKeyData& data) const; + bool hasKeyData(U32 index) const; + + // index of contained LLKeyData + S32 findKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const; + S32 findKeyData(const LLKeyData& data) const; + + LLKeyData getKeyData(U32 index) const; + + // these methods enshure there will be no repeats + bool addKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore); + bool addKeyData(const LLKeyData& data); + void replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore, U32 index); + void replaceKeyData(const LLKeyData& data, U32 index); + void resetKeyData(S32 index); + void clear() { mData.clear(); } + // if there any empty LLKeyData in the end of the array, remove them + void trimEmpty(); + U32 getDataCount(); + +private: + typedef std::vector<LLKeyData> data_vector_t; + data_vector_t mData; +}; + + +#endif // LL_KEYBIND_H diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp index cf8f8cc6a5..e8ea0ab398 100644 --- a/indra/llcommon/llleap.cpp +++ b/indra/llcommon/llleap.cpp @@ -59,7 +59,6 @@ public: // pump name -- so it should NOT need tweaking for uniqueness. mReplyPump(LLUUID::generateNewID().asString()), mExpect(0), - mPrevFatalFunction(LLError::getFatalFunction()), // Instantiate a distinct LLLeapListener for this plugin. (Every // plugin will want its own collection of managed listeners, etc.) // Pass it a callback to our connect() method, so it can send events @@ -146,7 +145,9 @@ public: .listen("LLLeap", boost::bind(&LLLeapImpl::rstderr, this, _1)); // For our lifespan, intercept any LL_ERRS so we can notify plugin - LLError::setFatalFunction(boost::bind(&LLLeapImpl::fatalFunction, this, _1)); + mRecorder = LLError::addGenericRecorder( + [this](LLError::ELevel level, const std::string& message) + { onError(level, message); }); // Send child a preliminary event reporting our own reply-pump name -- // which would otherwise be pretty tricky to guess! @@ -162,8 +163,7 @@ public: virtual ~LLLeapImpl() { LL_DEBUGS("LLLeap") << "destroying LLLeap(\"" << mDesc << "\")" << LL_ENDL; - // Restore original FatalFunction - LLError::setFatalFunction(mPrevFatalFunction); + LLError::removeRecorder(mRecorder); } // Listener for failed launch attempt @@ -377,28 +377,28 @@ public: return false; } - void fatalFunction(const std::string& error) + void onError(LLError::ELevel level, const std::string& error) { - // Notify plugin - LLSD event; - event["type"] = "error"; - event["error"] = error; - mReplyPump.post(event); - - // All the above really accomplished was to buffer the serialized - // event in our WritePipe. Have to pump mainloop a couple times to - // really write it out there... but time out in case we can't write. - LLProcess::WritePipe& childin(mChild->getWritePipe(LLProcess::STDIN)); - LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); - LLSD nop; - F64 until = (LLTimer::getElapsedSeconds() + 2).value(); - while (childin.size() && LLTimer::getElapsedSeconds() < until) + if (level == LLError::LEVEL_ERROR) { - mainloop.post(nop); + // Notify plugin + LLSD event; + event["type"] = "error"; + event["error"] = error; + mReplyPump.post(event); + + // All the above really accomplished was to buffer the serialized + // event in our WritePipe. Have to pump mainloop a couple times to + // really write it out there... but time out in case we can't write. + LLProcess::WritePipe& childin(mChild->getWritePipe(LLProcess::STDIN)); + LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); + LLSD nop; + F64 until = (LLTimer::getElapsedSeconds() + 2).value(); + while (childin.size() && LLTimer::getElapsedSeconds() < until) + { + mainloop.post(nop); + } } - - // forward the call to the previous FatalFunction - mPrevFatalFunction(error); } private: @@ -421,7 +421,7 @@ private: mStdinConnection, mStdoutConnection, mStdoutDataConnection, mStderrConnection; boost::scoped_ptr<LLEventPump::Blocker> mBlocker; LLProcess::ReadPipe::size_type mExpect; - LLError::FatalFunction mPrevFatalFunction; + LLError::RecorderPtr mRecorder; boost::scoped_ptr<LLLeapListener> mListener; }; diff --git a/indra/llcommon/llleaplistener.cpp b/indra/llcommon/llleaplistener.cpp index fa5730f112..3e6ce9092c 100644 --- a/indra/llcommon/llleaplistener.cpp +++ b/indra/llcommon/llleaplistener.cpp @@ -14,6 +14,8 @@ // associated header #include "llleaplistener.h" // STL headers +#include <map> +#include <functional> // std headers // external library headers #include <boost/foreach.hpp> @@ -60,16 +62,11 @@ LLLeapListener::LLLeapListener(const ConnectFunc& connect): LLSD need_name(LLSDMap("name", LLSD())); add("newpump", "Instantiate a new LLEventPump named like [\"name\"] and listen to it.\n" - "If [\"type\"] == \"LLEventQueue\", make LLEventQueue, else LLEventStream.\n" + "[\"type\"] == \"LLEventStream\", \"LLEventMailDrop\" et al.\n" "Events sent through new LLEventPump will be decorated with [\"pump\"]=name.\n" "Returns actual name in [\"name\"] (may be different if collision).", &LLLeapListener::newpump, need_name); - add("killpump", - "Delete LLEventPump [\"name\"] created by \"newpump\".\n" - "Returns [\"status\"] boolean indicating whether such a pump existed.", - &LLLeapListener::killpump, - need_name); LLSD need_source_listener(LLSDMap("source", LLSD())("listener", LLSD())); add("listen", "Listen to an existing LLEventPump named [\"source\"], with listener name\n" @@ -124,40 +121,23 @@ void LLLeapListener::newpump(const LLSD& request) Response reply(LLSD(), request); std::string name = request["name"]; - LLSD const & type = request["type"]; + std::string type = request["type"]; - LLEventPump * new_pump = NULL; - if (type.asString() == "LLEventQueue") + try { - new_pump = new LLEventQueue(name, true); // tweak name for uniqueness + // tweak name for uniqueness + LLEventPump& new_pump(LLEventPumps::instance().make(name, true, type)); + name = new_pump.getName(); + reply["name"] = name; + + // Now listen on this new pump with our plugin listener + std::string myname("llleap"); + saveListener(name, myname, mConnect(new_pump, myname)); } - else + catch (const LLEventPumps::BadType& error) { - if (! (type.isUndefined() || type.asString() == "LLEventStream")) - { - reply.warn(STRINGIZE("unknown 'type' " << type << ", using LLEventStream")); - } - new_pump = new LLEventStream(name, true); // tweak name for uniqueness + reply.error(error.what()); } - - name = new_pump->getName(); - - mEventPumps.insert(name, new_pump); - - // Now listen on this new pump with our plugin listener - std::string myname("llleap"); - saveListener(name, myname, mConnect(*new_pump, myname)); - - reply["name"] = name; -} - -void LLLeapListener::killpump(const LLSD& request) -{ - Response reply(LLSD(), request); - - std::string name = request["name"]; - // success == (nonzero number of entries were erased) - reply["status"] = bool(mEventPumps.erase(name)); } void LLLeapListener::listen(const LLSD& request) @@ -228,13 +208,11 @@ void LLLeapListener::getAPIs(const LLSD& request) const { Response reply(LLSD(), request); - for (LLEventAPI::instance_iter eai(LLEventAPI::beginInstances()), - eaend(LLEventAPI::endInstances()); - eai != eaend; ++eai) + for (auto& ea : LLEventAPI::instance_snapshot()) { LLSD info; - info["desc"] = eai->getDesc(); - reply[eai->getName()] = info; + info["desc"] = ea.getDesc(); + reply[ea.getName()] = info; } } diff --git a/indra/llcommon/llleaplistener.h b/indra/llcommon/llleaplistener.h index 2193d81b9e..0ca5893657 100644 --- a/indra/llcommon/llleaplistener.h +++ b/indra/llcommon/llleaplistener.h @@ -40,7 +40,6 @@ public: private: void newpump(const LLSD&); - void killpump(const LLSD&); void listen(const LLSD&); void stoplistening(const LLSD&); void ping(const LLSD&) const; @@ -64,10 +63,6 @@ private: // and listener name. typedef std::map<std::pair<std::string, std::string>, LLBoundListener> ListenersMap; ListenersMap mListeners; - // Similar lifespan reasoning applies to LLEventPumps instantiated by - // newpump() operations. - typedef boost::ptr_map<std::string, LLEventPump> EventPumpsMap; - EventPumpsMap mEventPumps; }; #endif /* ! defined(LL_LLLEAPLISTENER_H) */ diff --git a/indra/llcommon/lllistenerwrapper.h b/indra/llcommon/lllistenerwrapper.h deleted file mode 100644 index 09d074abca..0000000000 --- a/indra/llcommon/lllistenerwrapper.h +++ /dev/null @@ -1,198 +0,0 @@ -/** - * @file lllistenerwrapper.h - * @author Nat Goodspeed - * @date 2009-11-30 - * @brief Introduce LLListenerWrapper template - * - * $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_LLLISTENERWRAPPER_H) -#define LL_LLLISTENERWRAPPER_H - -#include "llevents.h" // LLListenerWrapperBase -#include <boost/visit_each.hpp> - -/** - * Template base class for coding wrappers for LLEventPump listeners. - * - * Derive your listener wrapper from LLListenerWrapper. You must use - * LLLISTENER_WRAPPER_SUBCLASS() so your subclass will play nicely with - * boost::visit_each (q.v.). That way boost::signals2 can still detect - * derivation from LLEventTrackable, and so forth. - */ -template <typename LISTENER> -class LLListenerWrapper: public LLListenerWrapperBase -{ -public: - /// Wrap an arbitrary listener object - LLListenerWrapper(const LISTENER& listener): - mListener(listener) - {} - - /// call - virtual bool operator()(const LLSD& event) - { - return mListener(event); - } - - /// Allow boost::visit_each() to peek at our mListener. - template <class V> - void accept_visitor(V& visitor) const - { - using boost::visit_each; - visit_each(visitor, mListener, 0); - } - -private: - LISTENER mListener; -}; - -/** - * Specialize boost::visit_each() (leveraging ADL) to peek inside an - * LLListenerWrapper<T> to traverse its LISTENER. We borrow the - * accept_visitor() pattern from boost::bind(), avoiding the need to make - * mListener public. - */ -template <class V, typename T> -void visit_each(V& visitor, const LLListenerWrapper<T>& wrapper, int) -{ - wrapper.accept_visitor(visitor); -} - -/// use this (sigh!) for each subclass of LLListenerWrapper<T> you write -#define LLLISTENER_WRAPPER_SUBCLASS(CLASS) \ -template <class V, typename T> \ -void visit_each(V& visitor, const CLASS<T>& wrapper, int) \ -{ \ - visit_each(visitor, static_cast<const LLListenerWrapper<T>&>(wrapper), 0); \ -} \ - \ -/* Have to state this explicitly, rather than using LL_TEMPLATE_CONVERTIBLE, */ \ -/* because the source type is itself a template. */ \ -template <typename T> \ -struct ll_template_cast_impl<const LLListenerWrapperBase*, const CLASS<T>*> \ -{ \ - const LLListenerWrapperBase* operator()(const CLASS<T>* wrapper) \ - { \ - return wrapper; \ - } \ -} - -/** - * Make an instance of a listener wrapper. Every wrapper class must be a - * template accepting a listener object of arbitrary type. In particular, the - * type of a boost::bind() expression is deliberately undocumented. So we - * can't just write Wrapper<CorrectType>(boost::bind(...)). Instead we must - * write llwrap<Wrapper>(boost::bind(...)). - */ -template <template<typename> class WRAPPER, typename T> -WRAPPER<T> llwrap(const T& listener) -{ - return WRAPPER<T>(listener); -} - -/** - * This LLListenerWrapper template subclass is used to report entry/exit to an - * event listener, by changing this: - * @code - * someEventPump.listen("MyClass", - * boost::bind(&MyClass::method, ptr, _1)); - * @endcode - * to this: - * @code - * someEventPump.listen("MyClass", - * llwrap<LLCoutListener>( - * boost::bind(&MyClass::method, ptr, _1))); - * @endcode - */ -template <class LISTENER> -class LLCoutListener: public LLListenerWrapper<LISTENER> -{ - typedef LLListenerWrapper<LISTENER> super; - -public: - /// Wrap an arbitrary listener object - LLCoutListener(const LISTENER& listener): - super(listener) - {} - - /// call - virtual bool operator()(const LLSD& event) - { - std::cout << "Entering listener " << *super::mName << " with " << event << std::endl; - bool handled = super::operator()(event); - std::cout << "Leaving listener " << *super::mName; - if (handled) - { - std::cout << " (handled)"; - } - std::cout << std::endl; - return handled; - } -}; - -LLLISTENER_WRAPPER_SUBCLASS(LLCoutListener); - -/** - * This LLListenerWrapper template subclass is used to log entry/exit to an - * event listener, by changing this: - * @code - * someEventPump.listen("MyClass", - * boost::bind(&MyClass::method, ptr, _1)); - * @endcode - * to this: - * @code - * someEventPump.listen("MyClass", - * llwrap<LLLogListener>( - * boost::bind(&MyClass::method, ptr, _1))); - * @endcode - */ -template <class LISTENER> -class LLLogListener: public LLListenerWrapper<LISTENER> -{ - typedef LLListenerWrapper<LISTENER> super; - -public: - /// Wrap an arbitrary listener object - LLLogListener(const LISTENER& listener): - super(listener) - {} - - /// call - virtual bool operator()(const LLSD& event) - { - LL_DEBUGS("LLLogListener") << "Entering listener " << *super::mName << " with " << event << LL_ENDL; - bool handled = super::operator()(event); - LL_DEBUGS("LLLogListener") << "Leaving listener " << *super::mName; - if (handled) - { - LL_CONT << " (handled)"; - } - LL_CONT << LL_ENDL; - return handled; - } -}; - -LLLISTENER_WRAPPER_SUBCLASS(LLLogListener); - -#endif /* ! defined(LL_LLLISTENERWRAPPER_H) */ diff --git a/indra/llcommon/llmainthreadtask.cpp b/indra/llcommon/llmainthreadtask.cpp new file mode 100644 index 0000000000..e0d70cacd8 --- /dev/null +++ b/indra/llcommon/llmainthreadtask.cpp @@ -0,0 +1,22 @@ +/** + * @file llmainthreadtask.cpp + * @author Nat Goodspeed + * @date 2019-12-05 + * @brief Implementation for llmainthreadtask. + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Copyright (c) 2019, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "llmainthreadtask.h" +// STL headers +// std headers +// external library headers +// other Linden headers + +// This file is required by our CMake integration-test machinery. It +// contributes no code to the viewer executable. diff --git a/indra/llcommon/llmainthreadtask.h b/indra/llcommon/llmainthreadtask.h new file mode 100644 index 0000000000..d509b687c0 --- /dev/null +++ b/indra/llcommon/llmainthreadtask.h @@ -0,0 +1,99 @@ +/** + * @file llmainthreadtask.h + * @author Nat Goodspeed + * @date 2019-12-04 + * @brief LLMainThreadTask dispatches work to the main thread. When invoked on + * the main thread, it performs the work inline. + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Copyright (c) 2019, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLMAINTHREADTASK_H) +#define LL_LLMAINTHREADTASK_H + +#include "lleventtimer.h" +#include "llthread.h" +#include "llmake.h" +#include <future> +#include <type_traits> // std::result_of + +/** + * LLMainThreadTask provides a way to perform some task specifically on the + * main thread, waiting for it to complete. A task consists of a C++ nullary + * invocable (i.e. any callable that requires no arguments) with arbitrary + * return type. + * + * Instead of instantiating LLMainThreadTask, pass your invocable to its + * static dispatch() method. dispatch() returns the result of calling your + * task. (Or, if your task throws an exception, dispatch() throws that + * exception. See std::packaged_task.) + * + * When you call dispatch() on the main thread (as determined by + * on_main_thread() in llthread.h), it simply calls your task and returns the + * result. + * + * When you call dispatch() on a secondary thread, it instantiates an + * LLEventTimer subclass scheduled immediately. Next time the main loop calls + * LLEventTimer::updateClass(), your task will be run, and LLMainThreadTask + * will fulfill a future with its result. Meanwhile the requesting thread + * blocks on that future. As soon as it is set, the requesting thread wakes up + * with the task result. + */ +class LLMainThreadTask +{ +private: + // Don't instantiate this class -- use dispatch() instead. + LLMainThreadTask() {} + +public: + /// dispatch() is the only way to invoke this functionality. + template <typename CALLABLE> + static auto dispatch(CALLABLE&& callable) -> decltype(callable()) + { + if (on_main_thread()) + { + // we're already running on the main thread, perfect + return callable(); + } + else + { + // It's essential to construct LLEventTimer subclass instances on + // the heap because, on completion, LLEventTimer deletes them. + // Once we enable C++17, we can use Class Template Argument + // Deduction. Until then, use llmake_heap(). + auto* task = llmake_heap<Task>(std::forward<CALLABLE>(callable)); + auto future = task->mTask.get_future(); + // Now simply block on the future. + return future.get(); + } + } + +private: + template <typename CALLABLE> + struct Task: public LLEventTimer + { + Task(CALLABLE&& callable): + // no wait time: call tick() next chance we get + LLEventTimer(0), + mTask(std::forward<CALLABLE>(callable)) + {} + BOOL tick() override + { + // run the task on the main thread, will populate the future + // obtained by get_future() + mTask(); + // tell LLEventTimer we're done (one shot) + return TRUE; + } + // Given arbitrary CALLABLE, which might be a lambda, how are we + // supposed to obtain its signature for std::packaged_task? It seems + // redundant to have to add an argument list to engage result_of, then + // add the argument list again to complete the signature. At least we + // only support a nullary CALLABLE. + std::packaged_task<typename std::result_of<CALLABLE()>::type()> mTask; + }; +}; + +#endif /* ! defined(LL_LLMAINTHREADTASK_H) */ diff --git a/indra/llcommon/llmake.h b/indra/llcommon/llmake.h index 08744f90fb..02463d97ea 100644 --- a/indra/llcommon/llmake.h +++ b/indra/llcommon/llmake.h @@ -12,10 +12,8 @@ * * also relevant: * - * Template argument deduction for class templates - * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0091r3.html - * was apparently adopted in June 2016? Unclear when compilers will - * portably support this, but there is hope. + * Template argument deduction for class templates (C++17) + * https://en.cppreference.com/w/cpp/language/class_template_argument_deduction * * $LicenseInfo:firstyear=2015&license=viewerlgpl$ * Copyright (c) 2015, Linden Research, Inc. @@ -25,37 +23,43 @@ #if ! defined(LL_LLMAKE_H) #define LL_LLMAKE_H -/*==========================================================================*| -// When we allow ourselves to compile with C++11 features enabled, this form -// should generically handle an arbitrary number of arguments. - +/** + * Usage: llmake<SomeTemplate>(args...) + * + * Deduces the types T... of 'args' and returns an instance of + * SomeTemplate<T...>(args...). + */ template <template<typename...> class CLASS_TEMPLATE, typename... ARGS> CLASS_TEMPLATE<ARGS...> llmake(ARGS && ... args) { return CLASS_TEMPLATE<ARGS...>(std::forward<ARGS>(args)...); } -|*==========================================================================*/ -// As of 2015-12-18, this is what we'll use instead. Add explicit overloads -// for different numbers of template parameters as use cases arise. +/// dumb pointer template just in case that's what's wanted +template <typename T> +using dumb_pointer = T*; /** - * Usage: llmake<SomeTemplate>(arg) + * Same as llmake(), but returns a pointer to a new heap instance of + * SomeTemplate<T...>(args...) using the pointer of your choice. * - * Deduces the type T of 'arg' and returns an instance of SomeTemplate<T> - * initialized with 'arg'. Assumes a constructor accepting T (by value, - * reference or whatever). + * @code + * auto* dumb = llmake_heap<SomeTemplate>(args...); + * auto shared = llmake_heap<SomeTemplate, std::shared_ptr>(args...); + * auto unique = llmake_heap<SomeTemplate, std::unique_ptr>(args...); + * @endcode */ -template <template<typename> class CLASS_TEMPLATE, typename ARG1> -CLASS_TEMPLATE<ARG1> llmake(const ARG1& arg1) -{ - return CLASS_TEMPLATE<ARG1>(arg1); -} - -template <template<typename, typename> class CLASS_TEMPLATE, typename ARG1, typename ARG2> -CLASS_TEMPLATE<ARG1, ARG2> llmake(const ARG1& arg1, const ARG2& arg2) +// POINTER_TEMPLATE is characterized as template<typename...> rather than as +// template<typename T> because (e.g.) std::unique_ptr has multiple template +// arguments. Even though we only engage one, std::unique_ptr doesn't match a +// template template parameter that itself takes only one template parameter. +template <template<typename...> class CLASS_TEMPLATE, + template<typename...> class POINTER_TEMPLATE=dumb_pointer, + typename... ARGS> +POINTER_TEMPLATE<CLASS_TEMPLATE<ARGS...>> llmake_heap(ARGS&&... args) { - return CLASS_TEMPLATE<ARG1, ARG2>(arg1, arg2); + return POINTER_TEMPLATE<CLASS_TEMPLATE<ARGS...>>( + new CLASS_TEMPLATE<ARGS...>(std::forward<ARGS>(args)...)); } #endif /* ! defined(LL_LLMAKE_H) */ diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index b3debf3550..ea84e4c1ea 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -35,7 +35,7 @@ # include <sys/types.h> # include <mach/task.h> # include <mach/mach_init.h> -#elif LL_LINUX || LL_SOLARIS +#elif LL_LINUX # include <unistd.h> #endif @@ -55,7 +55,6 @@ static LLTrace::SampleStatHandle<F64Megabytes> sVirtualMem("virtual_mem", "virtu U32Kilobytes LLMemory::sAllocatedMemInKB(0); U32Kilobytes LLMemory::sAllocatedPageSizeInKB(0); U32Kilobytes LLMemory::sMaxHeapSizeInKB(U32_MAX); -BOOL LLMemory::sEnableMemoryFailurePrevention = FALSE; void ll_assert_aligned_func(uintptr_t ptr,U32 alignment) { @@ -75,10 +74,9 @@ void ll_assert_aligned_func(uintptr_t ptr,U32 alignment) } //static -void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size, BOOL prevent_heap_failure) +void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size) { - sMaxHeapSizeInKB = max_heap_size; - sEnableMemoryFailurePrevention = prevent_heap_failure ; + sMaxHeapSizeInKB = U32Kilobytes::convert(max_heap_size); } //static @@ -93,9 +91,9 @@ void LLMemory::updateMemoryInfo() return ; } - sAllocatedMemInKB = U64Bytes(counters.WorkingSetSize) ; + sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(counters.WorkingSetSize)); sample(sAllocatedMem, sAllocatedMemInKB); - sAllocatedPageSizeInKB = U64Bytes(counters.PagefileUsage) ; + sAllocatedPageSizeInKB = U32Kilobytes::convert(U64Bytes(counters.PagefileUsage)); sample(sVirtualMem, sAllocatedPageSizeInKB); U32Kilobytes avail_phys, avail_virtual; @@ -158,56 +156,6 @@ void LLMemory::logMemoryInfo(BOOL update) LL_INFOS() << "Current max usable memory(KB): " << sMaxPhysicalMemInKB << LL_ENDL ; } -//return 0: everything is normal; -//return 1: the memory pool is low, but not in danger; -//return -1: the memory pool is in danger, is about to crash. -//static -bool LLMemory::isMemoryPoolLow() -{ - 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) - { - return false ; //no memory failure prevention. - } - - if(sAvailPhysicalMemInKB < (LOW_MEMORY_POOL_THRESHOLD / 4)) //out of physical memory - { - return true ; - } - - if(sAllocatedPageSizeInKB + (LOW_MEMORY_POOL_THRESHOLD / 4) > sMaxHeapSizeInKB) //out of virtual address space. - { - return true ; - } - - 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.value()) ; - } - else - { - 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.value()) ; - } - } - - is_low = !last_reserved_address ; //allocation failed - } - - return is_low ; -} - //static U32Kilobytes LLMemory::getAvailableMemKB() { @@ -309,35 +257,6 @@ U64 LLMemory::getCurrentRSS() return rss; } -#elif LL_SOLARIS -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#define _STRUCTURED_PROC 1 -#include <sys/procfs.h> - -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){ - LL_WARNS() << "LLmemory::getCurrentRSS() unable to open " << path << ". Returning 0 RSS!" << LL_ENDL; - return 0; - } - psinfo_t proc_psinfo; - if(read(proc_fd, &proc_psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)){ - LL_WARNS() << "LLmemory::getCurrentRSS() Unable to read from " << path << ". Returning 0 RSS!" << LL_ENDL; - close(proc_fd); - return 0; - } - - close(proc_fd); - - return((U64)proc_psinfo.pr_rssize * 1024); -} - #else U64 LLMemory::getCurrentRSS() diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index f04ae5f5cb..24f86cc11e 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -344,10 +344,9 @@ public: // Return value is zero if not known. static U64 getCurrentRSS(); static void* tryToAlloc(void* address, U32 size); - static void initMaxHeapSizeGB(F32Gigabytes max_heap_size, BOOL prevent_heap_failure); + static void initMaxHeapSizeGB(F32Gigabytes max_heap_size); static void updateMemoryInfo() ; static void logMemoryInfo(BOOL update = FALSE); - static bool isMemoryPoolLow(); static U32Kilobytes getAvailableMemKB() ; static U32Kilobytes getMaxMemKB() ; @@ -359,7 +358,6 @@ private: static U32Kilobytes sAllocatedPageSizeInKB ; static U32Kilobytes sMaxHeapSizeInKB; - static BOOL sEnableMemoryFailurePrevention; }; // LLRefCount moved to llrefcount.h diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp index 75f43a4704..4d73c04d07 100644 --- a/indra/llcommon/llmutex.cpp +++ b/indra/llcommon/llmutex.cpp @@ -32,8 +32,7 @@ //============================================================================ LLMutex::LLMutex() : - mCount(0), - mLockingThread(NO_THREAD) + mCount(0) { } @@ -55,7 +54,7 @@ void LLMutex::lock() #if MUTEX_DEBUG // Have to have the lock before we can access the debug info - U32 id = LLThread::currentID(); + auto id = LLThread::currentID(); if (mIsLocked[id] != FALSE) LL_ERRS() << "Already locked in Thread: " << id << LL_ENDL; mIsLocked[id] = TRUE; @@ -74,13 +73,13 @@ void LLMutex::unlock() #if MUTEX_DEBUG // Access the debug info while we have the lock - U32 id = LLThread::currentID(); + auto id = LLThread::currentID(); if (mIsLocked[id] != TRUE) LL_ERRS() << "Not locked in Thread: " << id << LL_ENDL; mIsLocked[id] = FALSE; #endif - mLockingThread = NO_THREAD; + mLockingThread = LLThread::id_t(); mMutex.unlock(); } @@ -102,7 +101,7 @@ bool LLMutex::isSelfLocked() return mLockingThread == LLThread::currentID(); } -U32 LLMutex::lockingThread() const +LLThread::id_t LLMutex::lockingThread() const { return mLockingThread; } @@ -122,7 +121,7 @@ bool LLMutex::trylock() #if MUTEX_DEBUG // Have to have the lock before we can access the debug info - U32 id = LLThread::currentID(); + auto id = LLThread::currentID(); if (mIsLocked[id] != FALSE) LL_ERRS() << "Already locked in Thread: " << id << LL_ENDL; mIsLocked[id] = TRUE; diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h index f841d7f950..838d7d34c0 100644 --- a/indra/llcommon/llmutex.h +++ b/indra/llcommon/llmutex.h @@ -28,20 +28,12 @@ #define LL_LLMUTEX_H #include "stdtypes.h" +#include "llthread.h" #include <boost/noncopyable.hpp> -#if LL_WINDOWS -#pragma warning (push) -#pragma warning (disable:4265) -#endif -// 'std::_Pad' : class has virtual functions, but destructor is not virtual -#include <mutex> +#include "mutex.h" #include <condition_variable> -#if LL_WINDOWS -#pragma warning (pop) -#endif - //============================================================================ #define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO) @@ -53,11 +45,6 @@ class LL_COMMON_API LLMutex { public: - typedef enum - { - NO_THREAD = 0xFFFFFFFF - } e_locking_thread; - LLMutex(); virtual ~LLMutex(); @@ -66,15 +53,15 @@ public: void unlock(); // undefined behavior when called on mutex not being held bool isLocked(); // non-blocking, but does do a lock/unlock so not free bool isSelfLocked(); //return true if locked in a same thread - U32 lockingThread() const; //get ID of locking thread - + LLThread::id_t lockingThread() const; //get ID of locking thread + protected: std::mutex mMutex; mutable U32 mCount; - mutable U32 mLockingThread; + mutable LLThread::id_t mLockingThread; #if MUTEX_DEBUG - std::map<U32, BOOL> mIsLocked; + std::map<LLThread::id_t, BOOL> mIsLocked; #endif }; diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index e8f9981437..b17a8e761a 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -34,16 +34,7 @@ #include <endian.h> #endif // LL_LINUX -#if LL_SOLARIS -# ifdef __sparc // Since we're talking Solaris 10 and up, only 64 bit is supported. -# define LL_BIG_ENDIAN 1 -# define LL_SOLARIS_ALIGNED_CPU 1 // used to designate issues where SPARC alignment is addressed -# define LL_SOLARIS_NON_MESA_GL 1 // The SPARC GL does not provide a MESA-based GL API -# endif -# include <sys/isa_defs.h> // ensure we know which end is up -#endif // LL_SOLARIS - -#if (defined(LL_WINDOWS) || (defined(LL_LINUX) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(LL_DARWIN) && defined(__LITTLE_ENDIAN__)) || (defined(LL_SOLARIS) && defined(__i386))) +#if (defined(LL_WINDOWS) || (defined(LL_LINUX) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(LL_DARWIN) && defined(__LITTLE_ENDIAN__))) #define LL_LITTLE_ENDIAN 1 #else #define LL_BIG_ENDIAN 1 @@ -232,4 +223,11 @@ #define LL_COMPILE_TIME_MESSAGE(msg) #endif +// __FUNCTION__ works on all the platforms we care about, but... +#if LL_WINDOWS +#define LL_PRETTY_FUNCTION __FUNCSIG__ +#else +#define LL_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#endif + #endif // not LL_LINDEN_PREPROCESSOR_H diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp index 1fa53f322b..23936f0526 100644 --- a/indra/llcommon/llprocess.cpp +++ b/indra/llcommon/llprocess.cpp @@ -994,9 +994,9 @@ void LLProcess::handle_status(int reason, int status) // wi->rv = apr_proc_wait(wi->child, &wi->rc, &wi->why, APR_NOWAIT); // It's just wrong to call apr_proc_wait() here. The only way APR knows to // call us with APR_OC_REASON_DEATH is that it's already reaped this child - // process, so calling suspend() will only produce "huh?" from the OS. We + // process, so calling wait() will only produce "huh?" from the OS. We // must rely on the status param passed in, which unfortunately comes - // straight from the OS suspend() call, which means we have to decode it by + // straight from the OS wait() call, which means we have to decode it by // hand. mStatus = interpret_status(status); LL_INFOS("LLProcess") << getStatusString() << LL_ENDL; diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index a618a1cc70..5d16a4b74d 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -195,6 +195,8 @@ namespace std::string amd_CPUFamilyName(int composed_family) { + // https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures + // https://developer.amd.com/resources/developer-guides-manuals/ switch(composed_family) { case 4: return "AMD 80486/5x86"; @@ -202,6 +204,13 @@ namespace case 6: return "AMD K7"; case 0xF: return "AMD K8"; case 0x10: return "AMD K8L"; + case 0x12: return "AMD K10"; + case 0x14: return "AMD Bobcat"; + case 0x15: return "AMD Bulldozer"; + case 0x16: return "AMD Jaguar"; + case 0x17: return "AMD Zen/Zen+/Zen2"; + case 0x18: return "AMD Hygon Dhyana"; + case 0x19: return "AMD Zen 3"; } return STRINGIZE("AMD <unknown 0x" << std::hex << composed_family << ">"); } diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index fb0411d27b..7e4af6ea66 100644 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -28,9 +28,10 @@ #include <boost/noncopyable.hpp> #include <boost/intrusive_ptr.hpp> -#include "llmutex.h" #include "llatomic.h" +class LLMutex; + //---------------------------------------------------------------------------- // RefCount objects should generally only be accessed by way of LLPointer<>'s // see llthread.h for LLThreadSafeRefCount diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index 57aa7d9c07..57b746889d 100644 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -132,6 +132,7 @@ public: 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(); } @@ -380,7 +381,8 @@ namespace using LLSD::Impl::erase; // Unhiding erase(LLSD::Integer) using LLSD::Impl::ref; // Unhiding ref(LLSD::Integer) virtual LLSD get(const LLSD::String&) const; - void insert(const LLSD::String& k, const LLSD& v); + virtual LLSD getKeys() const; + void insert(const LLSD::String& k, const LLSD& v); virtual void erase(const LLSD::String&); LLSD& ref(const LLSD::String&); virtual const LLSD& ref(const LLSD::String&) const; @@ -421,7 +423,19 @@ namespace DataMap::const_iterator i = mData.find(k); 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)); @@ -502,7 +516,7 @@ namespace virtual LLSD get(LLSD::Integer) const; void set(LLSD::Integer, const LLSD&); void insert(LLSD::Integer, const LLSD&); - void append(const LLSD&); + LLSD& append(const LLSD&); virtual void erase(LLSD::Integer); LLSD& ref(LLSD::Integer); virtual const LLSD& ref(LLSD::Integer) const; @@ -570,9 +584,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) @@ -862,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) @@ -895,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) diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index 7b9b1285f5..5b6d5545af 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -79,7 +79,7 @@ an LLSD array). An array is a sequence of zero or more LLSD values. - + Thread Safety In general, these LLSD classes offer *less* safety than STL container @@ -284,6 +284,7 @@ public: 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 +302,7 @@ public: 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&); diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 1aaff5628f..022a5d4659 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -55,6 +55,7 @@ static const S32 UNZIP_LLSD_MAX_DEPTH = 96; static const char LEGACY_NON_HEADER[] = "<llsd>"; const std::string LLSD_BINARY_HEADER("LLSD/Binary"); const std::string LLSD_XML_HEADER("LLSD/XML"); +const std::string LLSD_NOTATION_HEADER("llsd/notation"); //used to deflate a gzipped asset (currently used for navmeshes) #define windowBits 15 @@ -65,7 +66,8 @@ const std::string LLSD_XML_HEADER("LLSD/XML"); */ // static -void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize type, U32 options) +void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize type, + LLSDFormatter::EFormatterOptions options) { LLPointer<LLSDFormatter> f = NULL; @@ -81,6 +83,11 @@ void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize f = new LLSDXMLFormatter; break; + case LLSD_NOTATION: + str << "<? " << LLSD_NOTATION_HEADER << " ?>\n"; + f = new LLSDNotationFormatter; + break; + default: LL_WARNS() << "serialize request for unknown ELLSD_Serialize" << LL_ENDL; } @@ -168,6 +175,10 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes) { p = new LLSDXMLParser; } + else if (header == LLSD_NOTATION_HEADER) + { + p = new LLSDNotationParser; + } else { LL_WARNS() << "deserialize request for unknown ELLSD_Serialize" << LL_ENDL; @@ -1224,9 +1235,11 @@ bool LLSDBinaryParser::parseString( /** * LLSDFormatter */ -LLSDFormatter::LLSDFormatter() : - mBoolAlpha(false) +LLSDFormatter::LLSDFormatter(bool boolAlpha, const std::string& realFmt, EFormatterOptions options): + mOptions(options) { + boolalpha(boolAlpha); + realFormat(realFmt); } // virtual @@ -1243,6 +1256,17 @@ void LLSDFormatter::realFormat(const std::string& format) mRealFormat = format; } +S32 LLSDFormatter::format(const LLSD& data, std::ostream& ostr) const +{ + // pass options captured by constructor + return format(data, ostr, mOptions); +} + +S32 LLSDFormatter::format(const LLSD& data, std::ostream& ostr, EFormatterOptions options) const +{ + return format_impl(data, ostr, options, 0); +} + void LLSDFormatter::formatReal(LLSD::Real real, std::ostream& ostr) const { std::string buffer = llformat(mRealFormat.c_str(), real); @@ -1252,7 +1276,9 @@ void LLSDFormatter::formatReal(LLSD::Real real, std::ostream& ostr) const /** * LLSDNotationFormatter */ -LLSDNotationFormatter::LLSDNotationFormatter() +LLSDNotationFormatter::LLSDNotationFormatter(bool boolAlpha, const std::string& realFormat, + EFormatterOptions options): + LLSDFormatter(boolAlpha, realFormat, options) { } @@ -1268,14 +1294,8 @@ std::string LLSDNotationFormatter::escapeString(const std::string& in) return ostr.str(); } -// virtual -S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const -{ - S32 rv = format_impl(data, ostr, options, 0); - return rv; -} - -S32 LLSDNotationFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const +S32 LLSDNotationFormatter::format_impl(const LLSD& data, std::ostream& ostr, + EFormatterOptions options, U32 level) const { S32 format_count = 1; std::string pre; @@ -1396,21 +1416,33 @@ S32 LLSDNotationFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 { // *FIX: memory inefficient. const std::vector<U8>& buffer = data.asBinary(); - ostr << "b(" << buffer.size() << ")\""; - if(buffer.size()) + if (options & LLSDFormatter::OPTIONS_PRETTY_BINARY) { - if (options & LLSDFormatter::OPTIONS_PRETTY_BINARY) + ostr << "b16\""; + if (! buffer.empty()) { std::ios_base::fmtflags old_flags = ostr.flags(); ostr.setf( std::ios::hex, std::ios::basefield ); - ostr << "0x"; + // It shouldn't strictly matter whether the emitted hex digits + // are uppercase; LLSDNotationParser handles either; but as of + // 2020-05-13, Python's llbase.llsd requires uppercase hex. + ostr << std::uppercase; + auto oldfill(ostr.fill('0')); + auto oldwidth(ostr.width()); for (int i = 0; i < buffer.size(); i++) { - ostr << (int) buffer[i]; + // have to restate setw() before every conversion + ostr << std::setw(2) << (int) buffer[i]; } + ostr.width(oldwidth); + ostr.fill(oldfill); ostr.flags(old_flags); } - else + } + else // ! OPTIONS_PRETTY_BINARY + { + ostr << "b(" << buffer.size() << ")\""; + if (! buffer.empty()) { ostr.write((const char*)&buffer[0], buffer.size()); } @@ -1427,11 +1459,12 @@ S32 LLSDNotationFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 return format_count; } - /** * LLSDBinaryFormatter */ -LLSDBinaryFormatter::LLSDBinaryFormatter() +LLSDBinaryFormatter::LLSDBinaryFormatter(bool boolAlpha, const std::string& realFormat, + EFormatterOptions options): + LLSDFormatter(boolAlpha, realFormat, options) { } @@ -1440,7 +1473,8 @@ LLSDBinaryFormatter::~LLSDBinaryFormatter() { } // virtual -S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const +S32 LLSDBinaryFormatter::format_impl(const LLSD& data, std::ostream& ostr, + EFormatterOptions options, U32 level) const { S32 format_count = 1; switch(data.type()) @@ -1456,7 +1490,7 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option { ostr.put('k'); formatString((*iter).first, ostr); - format_count += format((*iter).second, ostr); + format_count += format_impl((*iter).second, ostr, options, level+1); } ostr.put('}'); break; @@ -1471,7 +1505,7 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option LLSD::array_const_iterator end = data.endArray(); for(; iter != end; ++iter) { - format_count += format(*iter, ostr); + format_count += format_impl(*iter, ostr, options, level+1); } ostr.put(']'); break; @@ -2241,7 +2275,7 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is, return ZR_SIZE_ERROR; } #endif - catch (std::bad_alloc) + catch (std::bad_alloc&) { free(result); return ZR_MEM_ERROR; diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index 8165410e80..d6079fd9fa 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -435,7 +435,8 @@ public: /** * @brief Constructor */ - LLSDFormatter(); + LLSDFormatter(bool boolAlpha=false, const std::string& realFormat="", + EFormatterOptions options=OPTIONS_PRETTY_BINARY); /** * @brief Set the boolean serialization format. @@ -459,16 +460,38 @@ public: void realFormat(const std::string& format); /** - * @brief Call this method to format an LLSD to a stream. + * @brief Call this method to format an LLSD to a stream with options as + * set by the constructor. + * + * @param data The data to write. + * @param ostr The destination stream for the data. + * @return Returns The number of LLSD objects formatted out + */ + S32 format(const LLSD& data, std::ostream& ostr) const; + + /** + * @brief Call this method to format an LLSD to a stream, passing options + * explicitly. * * @param data The data to write. * @param ostr The destination stream for the data. - * @return Returns The number of LLSD objects fomatted out + * @param options OPTIONS_NONE to emit LLSD::Binary as raw bytes + * @return Returns The number of LLSD objects formatted out */ - virtual S32 format(const LLSD& data, std::ostream& ostr, U32 options = LLSDFormatter::OPTIONS_NONE) const = 0; + virtual S32 format(const LLSD& data, std::ostream& ostr, EFormatterOptions options) 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 formatted out + */ + virtual S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, + U32 level) const = 0; + + /** * @brief Helper method which appropriately obeys the real format. * * @param real The real value to format. @@ -476,9 +499,9 @@ protected: */ void formatReal(LLSD::Real real, std::ostream& ostr) const; -protected: bool mBoolAlpha; std::string mRealFormat; + EFormatterOptions mOptions; }; @@ -498,7 +521,8 @@ public: /** * @brief Constructor */ - LLSDNotationFormatter(); + LLSDNotationFormatter(bool boolAlpha=false, const std::string& realFormat="", + EFormatterOptions options=OPTIONS_PRETTY_BINARY); /** * @brief Helper static method to return a notation escaped string @@ -512,25 +536,16 @@ public: */ static std::string escapeString(const std::string& in); - /** - * @brief Call this method to format an LLSD to a stream. - * - * @param data The data to write. - * @param ostr The destination stream for the data. - * @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 + * @return Returns The number of LLSD objects formatted out */ - S32 format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const; + S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, + U32 level) const override; }; @@ -550,7 +565,8 @@ public: /** * @brief Constructor */ - LLSDXMLFormatter(); + LLSDXMLFormatter(bool boolAlpha=false, const std::string& realFormat="", + EFormatterOptions options=OPTIONS_PRETTY_BINARY); /** * @brief Helper static method to return an xml escaped string @@ -565,20 +581,23 @@ public: * * @param data The data to write. * @param ostr The destination stream for the data. - * @return Returns The number of LLSD objects fomatted out + * @return Returns The number of LLSD objects formatted out */ - virtual S32 format(const LLSD& data, std::ostream& ostr, U32 options = LLSDFormatter::OPTIONS_NONE) const; + S32 format(const LLSD& data, std::ostream& ostr, EFormatterOptions options) const override; -protected: + // also pull down base-class format() method that isn't overridden + using LLSDFormatter::format; +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 + * @return Returns The number of LLSD objects formatted out */ - S32 format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const; + S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, + U32 level) const override; }; @@ -618,18 +637,20 @@ public: /** * @brief Constructor */ - LLSDBinaryFormatter(); + LLSDBinaryFormatter(bool boolAlpha=false, const std::string& realFormat="", + EFormatterOptions options=OPTIONS_PRETTY_BINARY); +protected: /** - * @brief Call this method to format an LLSD to a stream. + * @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 + * @return Returns The number of LLSD objects formatted out */ - virtual S32 format(const LLSD& data, std::ostream& ostr, U32 options = LLSDFormatter::OPTIONS_NONE) const; + S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, + U32 level) const override; -protected: /** * @brief Helper method to serialize strings * @@ -669,7 +690,8 @@ public: /** * @brief Constructor */ - LLSDOStreamer(const LLSD& data, U32 options = LLSDFormatter::OPTIONS_NONE) : + LLSDOStreamer(const LLSD& data, + LLSDFormatter::EFormatterOptions options=LLSDFormatter::OPTIONS_PRETTY_BINARY) : mSD(data), mOptions(options) {} /** @@ -681,17 +703,17 @@ public: * @return Returns the stream passed in after streaming mSD. */ friend std::ostream& operator<<( - std::ostream& str, - const LLSDOStreamer<Formatter>& formatter) + std::ostream& out, + const LLSDOStreamer<Formatter>& streamer) { LLPointer<Formatter> f = new Formatter; - f->format(formatter.mSD, str, formatter.mOptions); - return str; + f->format(streamer.mSD, out, streamer.mOptions); + return out; } protected: LLSD mSD; - U32 mOptions; + LLSDFormatter::EFormatterOptions mOptions; }; typedef LLSDOStreamer<LLSDNotationFormatter> LLSDNotationStreamer; @@ -706,7 +728,7 @@ class LL_COMMON_API LLSDSerialize public: enum ELLSD_Serialize { - LLSD_BINARY, LLSD_XML + LLSD_BINARY, LLSD_XML, LLSD_NOTATION }; /** @@ -724,7 +746,7 @@ public: * Generic in/outs */ static void serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize, - U32 options = LLSDFormatter::OPTIONS_NONE); + LLSDFormatter::EFormatterOptions options=LLSDFormatter::OPTIONS_PRETTY_BINARY); /** * @brief Examine a stream, and parse 1 sd object out based on contents. @@ -752,9 +774,9 @@ public: static S32 toPrettyBinaryNotation(const LLSD& sd, std::ostream& str) { LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter; - return f->format(sd, str, - LLSDFormatter::OPTIONS_PRETTY | - LLSDFormatter::OPTIONS_PRETTY_BINARY); + return f->format(sd, str, + LLSDFormatter::EFormatterOptions(LLSDFormatter::OPTIONS_PRETTY | + LLSDFormatter::OPTIONS_PRETTY_BINARY)); } static S32 fromNotation(LLSD& sd, std::istream& str, S32 max_bytes) { diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index 6d0fe862b9..0da824d694 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -45,7 +45,9 @@ extern "C" /** * LLSDXMLFormatter */ -LLSDXMLFormatter::LLSDXMLFormatter() +LLSDXMLFormatter::LLSDXMLFormatter(bool boolAlpha, const std::string& realFormat, + EFormatterOptions options): + LLSDFormatter(boolAlpha, realFormat, options) { } @@ -55,7 +57,8 @@ LLSDXMLFormatter::~LLSDXMLFormatter() } // virtual -S32 LLSDXMLFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const +S32 LLSDXMLFormatter::format(const LLSD& data, std::ostream& ostr, + EFormatterOptions options) const { std::streamsize old_precision = ostr.precision(25); @@ -72,7 +75,8 @@ S32 LLSDXMLFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) return rv; } -S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const +S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, + EFormatterOptions options, U32 level) const { S32 format_count = 1; std::string pre; diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index 9d00395c0a..eb3a96b133 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -33,7 +33,7 @@ #if LL_WINDOWS # define WIN32_LEAN_AND_MEAN # include <winsock2.h> // for htonl -#elif LL_LINUX || LL_SOLARIS +#elif LL_LINUX # include <netinet/in.h> #elif LL_DARWIN # include <arpa/inet.h> @@ -322,6 +322,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() *****************************************************************************/ @@ -332,7 +506,7 @@ struct Data const char* name; } typedata[] = { -#define def(type) { LLSD::type, #type + 4 } +#define def(type) { LLSD::type, &#type[4] } def(TypeUndefined), def(TypeBoolean), def(TypeInteger), @@ -681,3 +855,172 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits) return false; // pacify the compiler } } + +/***************************************************************************** +* llsd::drill() +*****************************************************************************/ +namespace llsd +{ + +LLSD& drill(LLSD& blob, const LLSD& rawPath) +{ + // Treat rawPath uniformly as an array. If it's not already an array, + // store it as the only entry in one. (But let's say Undefined means an + // empty array.) + LLSD path; + if (rawPath.isArray() || rawPath.isUndefined()) + { + path = rawPath; + } + else + { + path.append(rawPath); + } + + // Need to indicate a current destination -- but that current destination + // must change as we step through the path array. Where normally we'd use + // an LLSD& to capture a subscripted LLSD lvalue, this time we must + // instead use a pointer -- since it must be reassigned. + // Start by pointing to the input blob exactly as is. + LLSD* located{&blob}; + + // Extract the element of interest by walking path. Use an explicit index + // so that, in case of a bogus type in path, we can identify the specific + // path entry that's bad. + for (LLSD::Integer i = 0; i < path.size(); ++i) + { + const LLSD& key{path[i]}; + if (key.isString()) + { + // a string path element is a map key + located = &((*located)[key.asString()]); + } + else if (key.isInteger()) + { + // an integer path element is an array index + located = &((*located)[key.asInteger()]); + } + else + { + // What do we do with Real or Array or Map or ...? + // As it's a coder error -- not a user error -- rub the coder's + // face in it so it gets fixed. + LL_ERRS("llsdutil") << "drill(" << blob << ", " << rawPath + << "): path[" << i << "] bad type " + << sTypes.lookup(key.type()) << LL_ENDL; + } + } + + // dereference the pointer to return a reference to the element we found + return *located; +} + +LLSD drill(const LLSD& blob, const LLSD& path) +{ + // non-const drill() does exactly what we want. Temporarily cast away + // const-ness and use that. + return drill(const_cast<LLSD&>(blob), path); +} + +} // namespace llsd + +// 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 (LLSD::array_const_iterator ita = value.beginArray(); ita != value.endArray(); ++ita) + { + clone.append(llsd_clone(*ita, 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 (LLSD::array_const_iterator ita = value.beginArray(); ita != value.endArray(); ++ita) + { + shallow.append(*ita); + } + } + else + { + return value; + } + + return shallow; +} diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index 01ab6bcb8d..8678ca97f2 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -30,6 +30,7 @@ #define LL_LLSDUTIL_H #include "llsd.h" +#include <boost/functional/hash.hpp> // U32 LL_COMMON_API LLSD ll_sd_from_U32(const U32); @@ -70,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 @@ -129,6 +143,16 @@ LL_COMMON_API std::string llsd_matches(const LLSD& prototype, const LLSD& data, /// 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, int bits=-1); +/// If you don't care about LLSD::Real equality +inline bool operator==(const LLSD& lhs, const LLSD& rhs) +{ + return llsd_equals(lhs, rhs); +} +inline bool operator!=(const LLSD& lhs, const LLSD& rhs) +{ + // operator!=() should always be the negation of operator==() + return ! (lhs == rhs); +} // Simple function to copy data out of input & output iterators if // there is no need for casting. @@ -142,6 +166,31 @@ template<typename Input> LLSD llsd_copy_array(Input iter, Input end) return dest; } +namespace llsd +{ + +/** + * Drill down to locate an element in 'blob' according to 'path', where 'path' + * is one of the following: + * + * - LLSD::String: 'blob' is an LLSD::Map. Find the entry with key 'path'. + * - LLSD::Integer: 'blob' is an LLSD::Array. Find the entry with index 'path'. + * - Any other 'path' type will be interpreted as LLSD::Array, and 'blob' is a + * nested structure. For each element of 'path': + * - If it's an LLSD::Integer, select the entry with that index from an + * LLSD::Array at that level. + * - If it's an LLSD::String, select the entry with that key from an + * LLSD::Map at that level. + * - Anything else is an error. + * + * By implication, if path.isUndefined() or otherwise equivalent to an empty + * LLSD::Array, drill() returns 'blob' as is. + */ +LLSD drill(const LLSD& blob, const LLSD& path); +LLSD& drill( LLSD& blob, const LLSD& path); + +} + /***************************************************************************** * LLSDArray *****************************************************************************/ @@ -211,6 +260,36 @@ private: LLSD _data; }; +namespace llsd +{ + +/** + * Construct an LLSD::Array inline, using modern C++ variadic arguments. + */ + +// recursion tail +inline +void array_(LLSD&) {} + +// recursive call +template <typename T0, typename... Ts> +void array_(LLSD& data, T0&& v0, Ts&&... vs) +{ + data.append(std::forward<T0>(v0)); + array_(data, std::forward<Ts>(vs)...); +} + +// public interface +template <typename... Ts> +LLSD array(Ts&&... vs) +{ + LLSD data; + array_(data, std::forward<Ts>(vs)...); + return data; +} + +} // namespace llsd + /***************************************************************************** * LLSDMap *****************************************************************************/ @@ -255,6 +334,36 @@ private: LLSD _data; }; +namespace llsd +{ + +/** + * Construct an LLSD::Map inline, using modern C++ variadic arguments. + */ + +// recursion tail +inline +void map_(LLSD&) {} + +// recursive call +template <typename T0, typename... Ts> +void map_(LLSD& data, const LLSD::String& k0, T0&& v0, Ts&&... vs) +{ + data[k0] = v0; + map_(data, std::forward<Ts>(vs)...); +} + +// public interface +template <typename... Ts> +LLSD map(Ts&&... vs) +{ + LLSD data; + map_(data, std::forward<Ts>(vs)...); + return data; +} + +} // namespace llsd + /***************************************************************************** * LLSDParam *****************************************************************************/ @@ -421,4 +530,98 @@ private: } // 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()); + +namespace llsd +{ + +// llsd namespace aliases +inline +LLSD clone (LLSD value, LLSD filter=LLSD()) { return llsd_clone (value, filter); } +inline +LLSD shallow(LLSD value, LLSD filter=LLSD()) { return llsd_shallow(value, filter); } + +} // namespace llsd + +// Specialization for generating a hash value from an LLSD block. +namespace boost +{ +template <> +struct hash<LLSD> +{ + 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 9fbd78a000..6b1986d0e9 100644 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -28,25 +28,16 @@ #include "llsingleton.h" #include "llerror.h" -#include "llerrorcontrol.h" // LLError::is_available() +#include "llerrorcontrol.h" #include "lldependencies.h" -#include "llcoro_get_id.h" +#include "llexception.h" +#include "llcoros.h" #include <boost/foreach.hpp> -#include <boost/unordered_map.hpp> #include <algorithm> #include <iostream> // std::cerr in dire emergency #include <sstream> #include <stdexcept> -namespace { -void log(LLError::ELevel level, - const char* p1, const char* p2, const char* p3, const char* p4); - -void logdebugs(const char* p1="", const char* p2="", const char* p3="", const char* p4=""); - -bool oktolog(); -} // anonymous namespace - // Our master list of all LLSingletons is itself an LLSingleton. We used to // store it in a function-local static, but that could get destroyed before // the last of the LLSingletons -- and ~LLSingletonBase() definitely wants to @@ -57,63 +48,131 @@ bool oktolog(); class LLSingletonBase::MasterList: public LLSingleton<LLSingletonBase::MasterList> { +private: LLSINGLETON_EMPTY_CTOR(MasterList); -public: - // No need to make this private with accessors; nobody outside this source - // file can see it. + // Independently of the LLSingleton locks governing construction, + // destruction and other state changes of the MasterList instance itself, + // we must also defend each of the data structures owned by the + // MasterList. + // This must be a recursive_mutex because, while the lock is held for + // manipulating some data in the master list, we must also check whether + // it's safe to log -- which involves querying a different LLSingleton -- + // which requires accessing the master list. + typedef std::recursive_mutex mutex_t; + typedef std::unique_lock<mutex_t> lock_t; + mutex_t mMutex; + +public: + // Instantiate this to both obtain a reference to MasterList::instance() + // and lock its mutex for the lifespan of this Lock instance. + class Lock + { + public: + Lock(): + mMasterList(MasterList::instance()), + mLock(mMasterList.mMutex) + {} + Lock(const Lock&) = delete; + Lock& operator=(const Lock&) = delete; + MasterList& get() const { return mMasterList; } + operator MasterList&() const { return get(); } + + protected: + MasterList& mMasterList; + MasterList::lock_t mLock; + }; + +private: // This is the master list of all instantiated LLSingletons (save the // MasterList itself) in arbitrary order. You MUST call dep_sort() before // traversing this list. - LLSingletonBase::list_t mMaster; + list_t mMaster; +public: + // Instantiate this to obtain a reference to MasterList::mMaster and to + // hold the MasterList lock for the lifespan of this LockedMaster + // instance. + struct LockedMaster: public Lock + { + list_t& get() const { return mMasterList.mMaster; } + operator list_t&() const { return get(); } + }; + +private: // We need to maintain a stack of LLSingletons currently being // initialized, either in the constructor or in initSingleton(). However, // managing that as a stack depends on having a DISTINCT 'initializing' // stack for every C++ stack in the process! And we have a distinct C++ - // stack for every running coroutine. It would be interesting and cool to - // implement a generic coroutine-local-storage mechanism and use that - // here. The trouble is that LLCoros is itself an LLSingleton, so - // depending on LLCoros functionality could dig us into infinite - // recursion. (Moreover, when we reimplement LLCoros on top of - // Boost.Fiber, that library already provides fiber_specific_ptr -- so - // it's not worth a great deal of time and energy implementing a generic - // equivalent on top of boost::dcoroutine, which is on its way out.) - // Instead, use a map of llcoro::id to select the appropriate - // coro-specific 'initializing' stack. llcoro::get_id() is carefully - // implemented to avoid requiring LLCoros. - typedef boost::unordered_map<llcoro::id, LLSingletonBase::list_t> InitializingMap; - InitializingMap mInitializing; - - // non-static method, cf. LLSingletonBase::get_initializing() + // stack for every running coroutine. Therefore this stack must be based + // on a coroutine-local pointer. + // This local_ptr isn't static because it's a member of an LLSingleton. + LLCoros::local_ptr<list_t> mInitializing; + +public: + // Instantiate this to obtain a reference to the coroutine-specific + // initializing list and to hold the MasterList lock for the lifespan of + // this LockedInitializing instance. + struct LockedInitializing: public Lock + { + public: + LockedInitializing(): + // only do the lookup once, cache the result + // note that the lock is already locked during this lookup + mList(&mMasterList.get_initializing_()) + {} + list_t& get() const + { + if (! mList) + { + LLTHROW(LLException("Trying to use LockedInitializing " + "after cleanup_initializing()")); + } + return *mList; + } + operator list_t&() const { return get(); } + void log(const char* verb, const char* name); + void cleanup_initializing() + { + mMasterList.cleanup_initializing_(); + mList = nullptr; + } + + private: + // Store pointer since cleanup_initializing() must clear it. + list_t* mList; + }; + +private: list_t& get_initializing_() { - // map::operator[] has find-or-create semantics, exactly what we need - // here. It returns a reference to the selected mapped_type instance. - return mInitializing[llcoro::get_id()]; + LLSingletonBase::list_t* current = mInitializing.get(); + if (! current) + { + // If the running coroutine doesn't already have an initializing + // stack, allocate a new one and save it for future reference. + current = new LLSingletonBase::list_t(); + mInitializing.reset(current); + } + return *current; } + // By the time mInitializing is destroyed, its value for every coroutine + // except the running one must have been reset() to nullptr. So every time + // we pop the list to empty, reset() the running coroutine's local_ptr. void cleanup_initializing_() { - InitializingMap::iterator found = mInitializing.find(llcoro::get_id()); - if (found != mInitializing.end()) - { - mInitializing.erase(found); - } + mInitializing.reset(nullptr); } }; -//static -LLSingletonBase::list_t& LLSingletonBase::get_master() -{ - return LLSingletonBase::MasterList::instance().mMaster; -} - void LLSingletonBase::add_master() { // As each new LLSingleton is constructed, add to the master list. - get_master().push_back(this); + // This temporary LockedMaster should suffice to hold the MasterList lock + // during the push_back() call. + MasterList::LockedMaster().get().push_back(this); } void LLSingletonBase::remove_master() @@ -125,38 +184,37 @@ void LLSingletonBase::remove_master() // master list, and remove this item IF FOUND. We have few enough // LLSingletons, and they are so rarely destroyed (once per run), that the // cost of a linear search should not be an issue. - get_master().remove(this); + // This temporary LockedMaster should suffice to hold the MasterList lock + // during the remove() call. + MasterList::LockedMaster().get().remove(this); } //static -LLSingletonBase::list_t& LLSingletonBase::get_initializing() +LLSingletonBase::list_t::size_type LLSingletonBase::get_initializing_size() { - return LLSingletonBase::MasterList::instance().get_initializing_(); -} - -//static -LLSingletonBase::list_t& LLSingletonBase::get_initializing_from(MasterList* master) -{ - return master->get_initializing_(); + return MasterList::LockedInitializing().get().size(); } LLSingletonBase::~LLSingletonBase() {} void LLSingletonBase::push_initializing(const char* name) { + MasterList::LockedInitializing locked_list; // log BEFORE pushing so logging singletons don't cry circularity - log_initializing("Pushing", name); - get_initializing().push_back(this); + locked_list.log("Pushing", name); + locked_list.get().push_back(this); } void LLSingletonBase::pop_initializing() { - list_t& list(get_initializing()); + // Lock the MasterList for the duration of this call + MasterList::LockedInitializing locked_list; + list_t& list(locked_list.get()); if (list.empty()) { - logerrs("Underflow in stack of currently-initializing LLSingletons at ", - demangle(typeid(*this).name()).c_str(), "::getInstance()"); + logerrs({"Underflow in stack of currently-initializing LLSingletons at ", + classname(this), "::getInstance()"}); } // Now we know list.back() exists: capture it @@ -171,40 +229,66 @@ void LLSingletonBase::pop_initializing() // entirely. if (list.empty()) { - MasterList::instance().cleanup_initializing_(); + locked_list.cleanup_initializing(); } // Now validate the newly-popped LLSingleton. if (back != this) { - logerrs("Push/pop mismatch in stack of currently-initializing LLSingletons: ", - demangle(typeid(*this).name()).c_str(), "::getInstance() trying to pop ", - demangle(typeid(*back).name()).c_str()); + logerrs({"Push/pop mismatch in stack of currently-initializing LLSingletons: ", + classname(this), "::getInstance() trying to pop ", + classname(back)}); } // log AFTER popping so logging singletons don't cry circularity - log_initializing("Popping", typeid(*back).name()); + locked_list.log("Popping", typeid(*back).name()); } -//static -void LLSingletonBase::log_initializing(const char* verb, const char* name) +void LLSingletonBase::reset_initializing(list_t::size_type size) { - if (oktolog()) + // called for cleanup in case the LLSingleton subclass constructor throws + // an exception + + // The tricky thing about this, the reason we have a separate method + // instead of just calling pop_initializing(), is (hopefully remote) + // possibility that the exception happened *before* the + // push_initializing() call in LLSingletonBase's constructor. So only + // remove the stack top if in fact we've pushed something more than the + // previous size. + MasterList::LockedInitializing locked_list; + list_t& list(locked_list.get()); + + while (list.size() > size) + { + list.pop_back(); + } + + // as in pop_initializing() + if (list.empty()) { + locked_list.cleanup_initializing(); + } +} + +void LLSingletonBase::MasterList::LockedInitializing::log(const char* verb, const char* name) +{ LL_DEBUGS("LLSingleton") << verb << ' ' << demangle(name) << ';'; - list_t& list(get_initializing()); - for (list_t::const_reverse_iterator ri(list.rbegin()), rend(list.rend()); - ri != rend; ++ri) + if (mList) { - LLSingletonBase* sb(*ri); - LL_CONT << ' ' << demangle(typeid(*sb).name()); + for (list_t::const_reverse_iterator ri(mList->rbegin()), rend(mList->rend()); + ri != rend; ++ri) + { + LLSingletonBase* sb(*ri); + LL_CONT << ' ' << classname(sb); + } } LL_ENDL; - } } -void LLSingletonBase::capture_dependency(list_t& initializing, EInitState initState) +void LLSingletonBase::capture_dependency() { + MasterList::LockedInitializing locked_list; + list_t& initializing(locked_list.get()); // Did this getInstance() call come from another LLSingleton, or from // vanilla application code? Note that although this is a nontrivial // method, the vast majority of its calls arrive here with initializing @@ -231,23 +315,10 @@ void LLSingletonBase::capture_dependency(list_t& initializing, EInitState initSt // 'found' is an iterator; *found is an LLSingletonBase*; **found // is the actual LLSingletonBase instance. LLSingletonBase* foundp(*found); - out << demangle(typeid(*foundp).name()) << " -> "; + out << classname(foundp) << " -> "; } - // We promise to capture dependencies from both the constructor - // and the initSingleton() method, so an LLSingleton's instance - // pointer is on the initializing list during both. Now that we've - // detected circularity, though, we must distinguish the two. If - // the recursive call is from the constructor, we CAN'T honor it: - // otherwise we'd be returning a pointer to a partially- - // constructed object! But from initSingleton() is okay: that - // method exists specifically to support circularity. // Decide which log helper to call. - if (initState == CONSTRUCTING) - { - logerrs("LLSingleton circularity in Constructor: ", out.str().c_str(), - demangle(typeid(*this).name()).c_str(), ""); - } - else if (it_next == initializing.end()) + if (it_next == initializing.end()) { // Points to self after construction, but during initialization. // Singletons can initialize other classes that depend onto them, @@ -255,15 +326,15 @@ void LLSingletonBase::capture_dependency(list_t& initializing, EInitState initSt // // Example: LLNotifications singleton initializes default channels. // Channels register themselves with singleton once done. - logdebugs("LLSingleton circularity: ", out.str().c_str(), - demangle(typeid(*this).name()).c_str(), ""); + logdebugs({"LLSingleton circularity: ", out.str(), + classname(this)}); } else { // Actual circularity with other singleton (or single singleton is used extensively). // Dependency can be unclear. - logwarns("LLSingleton circularity: ", out.str().c_str(), - demangle(typeid(*this).name()).c_str(), ""); + logwarns({"LLSingleton circularity: ", out.str(), + classname(this)}); } } else @@ -276,8 +347,8 @@ void LLSingletonBase::capture_dependency(list_t& initializing, EInitState initSt if (current->mDepends.insert(this).second) { // only log the FIRST time we hit this dependency! - logdebugs(demangle(typeid(*current).name()).c_str(), - " depends on ", demangle(typeid(*this).name()).c_str()); + logdebugs({classname(current), + " depends on ", classname(this)}); } } } @@ -290,12 +361,12 @@ LLSingletonBase::vec_t LLSingletonBase::dep_sort() // SingletonDeps through the life of the program, dynamically adding and // removing LLSingletons as they are created and destroyed, in practice // it's less messy to construct it on demand. The overhead of doing so - // should happen basically twice: once for cleanupAll(), once for - // deleteAll(). + // should happen basically once: for deleteAll(). typedef LLDependencies<LLSingletonBase*> SingletonDeps; SingletonDeps sdeps; - list_t& master(get_master()); - BOOST_FOREACH(LLSingletonBase* sp, master) + // Lock while traversing the master list + MasterList::LockedMaster master; + for (LLSingletonBase* sp : master.get()) { // Build the SingletonDeps structure by adding, for each // LLSingletonBase* sp in the master list, sp itself. It has no @@ -307,51 +378,32 @@ LLSingletonBase::vec_t LLSingletonBase::dep_sort() SingletonDeps::KeyList(sp->mDepends.begin(), sp->mDepends.end())); } vec_t ret; - ret.reserve(master.size()); + ret.reserve(master.get().size()); // We should be able to effect this with a transform_iterator that // extracts just the first (key) element from each sorted_iterator, then // uses vec_t's range constructor... but frankly this is more // straightforward, as long as we remember the above reserve() call! - BOOST_FOREACH(SingletonDeps::sorted_iterator::value_type pair, sdeps.sort()) + for (const SingletonDeps::sorted_iterator::value_type pair : sdeps.sort()) { ret.push_back(pair.first); } // The master list is not itself pushed onto the master list. Add it as // the very last entry -- it is the LLSingleton on which ALL others // depend! -- so our caller will process it. - ret.push_back(MasterList::getInstance()); + ret.push_back(&master.Lock::get()); return ret; } -//static -void LLSingletonBase::cleanupAll() +void LLSingletonBase::cleanup_() { - // It's essential to traverse these in dependency order. - BOOST_FOREACH(LLSingletonBase* sp, dep_sort()) + logdebugs({"calling ", classname(this), "::cleanupSingleton()"}); + try { - // Call cleanupSingleton() only if we haven't already done so for this - // instance. - if (! sp->mCleaned) - { - sp->mCleaned = true; - - logdebugs("calling ", - demangle(typeid(*sp).name()).c_str(), "::cleanupSingleton()"); - try - { - sp->cleanupSingleton(); - } - catch (const std::exception& e) - { - logwarns("Exception in ", demangle(typeid(*sp).name()).c_str(), - "::cleanupSingleton(): ", e.what()); - } - catch (...) - { - logwarns("Unknown exception in ", demangle(typeid(*sp).name()).c_str(), - "::cleanupSingleton()"); - } - } + cleanupSingleton(); + } + catch (...) + { + LOG_UNHANDLED_EXCEPTION(classname(this) + "::cleanupSingleton()"); } } @@ -363,84 +415,71 @@ void LLSingletonBase::deleteAll() { // Capture the class name first: in case of exception, don't count on // being able to extract it later. - const std::string name = demangle(typeid(*sp).name()); + const std::string name = classname(sp); try { // Call static method through instance function pointer. if (! sp->mDeleteSingleton) { // This Should Not Happen... but carry on. - logwarns(name.c_str(), "::mDeleteSingleton not initialized!"); + logwarns({name, "::mDeleteSingleton not initialized!"}); } else { // properly initialized: call it. - logdebugs("calling ", name.c_str(), "::deleteSingleton()"); + logdebugs({"calling ", name, "::deleteSingleton()"}); // From this point on, DO NOT DEREFERENCE sp! sp->mDeleteSingleton(); } } catch (const std::exception& e) { - logwarns("Exception in ", name.c_str(), "::deleteSingleton(): ", e.what()); + logwarns({"Exception in ", name, "::deleteSingleton(): ", e.what()}); } catch (...) { - logwarns("Unknown exception in ", name.c_str(), "::deleteSingleton()"); + logwarns({"Unknown exception in ", name, "::deleteSingleton()"}); } } } /*---------------------------- Logging helpers -----------------------------*/ namespace { -bool oktolog() -{ - // See comments in log() below. - return LLError::is_available(); -} -void log(LLError::ELevel level, - const char* p1, const char* p2, const char* p3, const char* p4) +std::ostream& operator<<(std::ostream& out, const LLSingletonBase::string_params& args) { - // The is_available() test below ensures that we'll stop logging once - // LLError has been cleaned up. If we had a similar portable test for - // std::cerr, this would be a good place to use it. - - // Check LLError::is_available() because some of LLError's infrastructure - // is itself an LLSingleton. If that LLSingleton has not yet been - // initialized, trying to log will engage LLSingleton machinery... and - // around and around we go. - if (LLError::is_available()) - { - LL_VLOGS(level, "LLSingleton") << p1 << p2 << p3 << p4 << LL_ENDL; - } - else + // However many args there are in args, stream each of them to 'out'. + for (auto arg : args) { - // Caller may be a test program, or something else whose stderr is - // visible to the user. - std::cerr << p1 << p2 << p3 << p4 << std::endl; + out << arg; } + return out; } -void logdebugs(const char* p1, const char* p2, const char* p3, const char* p4) +} // anonymous namespace + +//static +void LLSingletonBase::logwarns(const string_params& args) { - log(LLError::LEVEL_DEBUG, p1, p2, p3, p4); + LL_WARNS("LLSingleton") << args << LL_ENDL; +} + +//static +void LLSingletonBase::loginfos(const string_params& args) +{ + LL_INFOS("LLSingleton") << args << LL_ENDL; } -} // anonymous namespace //static -void LLSingletonBase::logwarns(const char* p1, const char* p2, const char* p3, const char* p4) +void LLSingletonBase::logdebugs(const string_params& args) { - log(LLError::LEVEL_WARN, p1, p2, p3, p4); + LL_DEBUGS("LLSingleton") << args << LL_ENDL; } //static -void LLSingletonBase::logerrs(const char* p1, const char* p2, const char* p3, const char* p4) +void LLSingletonBase::logerrs(const string_params& args) { - log(LLError::LEVEL_ERROR, p1, p2, p3, p4); - // The other important side effect of LL_ERRS() is - // https://www.youtube.com/watch?v=OMG7paGJqhQ (emphasis on OMG) - LLError::crashAndLoop(std::string()); + LL_ERRS("LLSingleton") << args << LL_ENDL; } std::string LLSingletonBase::demangle(const char* mangled) diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 859e271e26..7c81d65a8b 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -27,9 +27,14 @@ #include <boost/noncopyable.hpp> #include <boost/unordered_set.hpp> +#include <initializer_list> #include <list> -#include <vector> #include <typeinfo> +#include <vector> +#include "mutex.h" +#include "lockstatic.h" +#include "llthread.h" // on_main_thread() +#include "llmainthreadtask.h" class LLSingletonBase: private boost::noncopyable { @@ -39,16 +44,13 @@ public: private: // All existing LLSingleton instances are tracked in this master list. typedef std::list<LLSingletonBase*> list_t; - static list_t& get_master(); - // This, on the other hand, is a stack whose top indicates the LLSingleton - // currently being initialized. - static list_t& get_initializing(); - static list_t& get_initializing_from(MasterList*); + // Size of stack whose top indicates the LLSingleton currently being + // initialized. + static list_t::size_type get_initializing_size(); // Produce a vector<LLSingletonBase*> of master list, in dependency order. typedef std::vector<LLSingletonBase*> vec_t; static vec_t dep_sort(); - bool mCleaned; // cleanupSingleton() has been called // we directly depend on these other LLSingletons typedef boost::unordered_set<LLSingletonBase*> set_t; set_t mDepends; @@ -57,10 +59,11 @@ protected: typedef enum e_init_state { UNINITIALIZED = 0, // must be default-initialized state - CONSTRUCTING, - INITIALIZING, - INITIALIZED, - DELETED + QUEUED, // construction queued, not yet executing + CONSTRUCTING, // within DERIVED_TYPE constructor + INITIALIZING, // within DERIVED_TYPE::initSingleton() + INITIALIZED, // normal case + DELETED // deleteSingleton() or deleteAll() called } EInitState; // Define tag<T> to pass to our template constructor. You can't explicitly @@ -100,26 +103,37 @@ protected: // That being the case, we control exactly when it happens -- and we can // pop the stack immediately thereafter. void pop_initializing(); -private: - // logging - static void log_initializing(const char* verb, const char* name); + // Remove 'this' from the init stack in case of exception in the + // LLSingleton subclass constructor. + static void reset_initializing(list_t::size_type size); protected: // If a given call to B::getInstance() happens during either A::A() or // A::initSingleton(), record that A directly depends on B. - void capture_dependency(list_t& initializing, EInitState); - - // delegate LL_ERRS() logging to llsingleton.cpp - static void logerrs(const char* p1, const char* p2="", - const char* p3="", const char* p4=""); - // delegate LL_WARNS() logging to llsingleton.cpp - static void logwarns(const char* p1, const char* p2="", - const char* p3="", const char* p4=""); + void capture_dependency(); + + // delegate logging calls to llsingleton.cpp +public: + typedef std::initializer_list<const std::string> string_params; +protected: + static void logerrs (const string_params&); + static void logwarns (const string_params&); + static void loginfos (const string_params&); + static void logdebugs(const string_params&); static std::string demangle(const char* mangled); + // these classname() declarations restate template functions declared in + // llerror.h because we avoid #including that here + template <typename T> + static std::string classname() { return demangle(typeid(T).name()); } + template <typename T> + static std::string classname(T* ptr) { return demangle(typeid(*ptr).name()); } // Default methods in case subclass doesn't declare them. virtual void initSingleton() {} virtual void cleanupSingleton() {} + // internal wrapper around calls to cleanupSingleton() + void cleanup_(); + // deleteSingleton() isn't -- and shouldn't be -- a virtual method. It's a // class static. However, given only Foo*, deleteAll() does need to be // able to reach Foo::deleteSingleton(). Make LLSingleton (which declares @@ -129,32 +143,15 @@ protected: public: /** - * Call this to call the cleanupSingleton() method for every LLSingleton - * constructed since the start of the last cleanupAll() call. (Any - * LLSingleton constructed DURING a cleanupAll() call won't be cleaned up - * until the next cleanupAll() call.) cleanupSingleton() neither deletes - * nor destroys its LLSingleton; therefore it's safe to include logic that - * might take significant realtime or even throw an exception. - * - * The most important property of cleanupAll() is that cleanupSingleton() - * methods are called in dependency order, leaf classes last. Thus, given - * two LLSingleton subclasses A and B, if A's dependency on B is properly - * expressed as a B::getInstance() or B::instance() call during either - * A::A() or A::initSingleton(), B will be cleaned up after A. - * - * If a cleanupSingleton() method throws an exception, the exception is - * logged, but cleanupAll() attempts to continue calling the rest of the - * cleanupSingleton() methods. - */ - static void cleanupAll(); - /** - * Call this to call the deleteSingleton() method for every LLSingleton - * constructed since the start of the last deleteAll() call. (Any - * LLSingleton constructed DURING a deleteAll() call won't be cleaned up - * until the next deleteAll() call.) deleteSingleton() deletes and - * destroys its LLSingleton. Any cleanup logic that might take significant - * realtime -- or throw an exception -- must not be placed in your - * LLSingleton's destructor, but rather in its cleanupSingleton() method. + * deleteAll() calls the cleanupSingleton() and deleteSingleton() methods + * for every LLSingleton constructed since the start of the last + * deleteAll() call. (Any LLSingleton constructed DURING a deleteAll() + * call won't be cleaned up until the next deleteAll() call.) + * deleteSingleton() deletes and destroys its LLSingleton. Any cleanup + * logic that might take significant realtime -- or throw an exception -- + * must not be placed in your LLSingleton's destructor, but rather in its + * cleanupSingleton() method, which is called implicitly by + * deleteSingleton(). * * The most important property of deleteAll() is that deleteSingleton() * methods are called in dependency order, leaf classes last. Thus, given @@ -162,9 +159,9 @@ public: * expressed as a B::getInstance() or B::instance() call during either * A::A() or A::initSingleton(), B will be cleaned up after A. * - * If a deleteSingleton() method throws an exception, the exception is - * logged, but deleteAll() attempts to continue calling the rest of the - * deleteSingleton() methods. + * If a cleanupSingleton() or deleteSingleton() method throws an + * exception, the exception is logged, but deleteAll() attempts to + * continue calling the rest of the deleteSingleton() methods. */ static void deleteAll(); }; @@ -178,7 +175,22 @@ struct LLSingleton_manage_master void remove(LLSingletonBase* sb) { sb->remove_master(); } void push_initializing(LLSingletonBase* sb) { sb->push_initializing(typeid(T).name()); } void pop_initializing (LLSingletonBase* sb) { sb->pop_initializing(); } - LLSingletonBase::list_t& get_initializing(T*) { return LLSingletonBase::get_initializing(); } + // used for init stack cleanup in case an LLSingleton subclass constructor + // throws an exception + void reset_initializing(LLSingletonBase::list_t::size_type size) + { + LLSingletonBase::reset_initializing(size); + } + // For any LLSingleton subclass except the MasterList, obtain the size of + // the init stack from the MasterList singleton instance. + LLSingletonBase::list_t::size_type get_initializing_size() + { + return LLSingletonBase::get_initializing_size(); + } + void capture_dependency(LLSingletonBase* sb) + { + sb->capture_dependency(); + } }; // But for the specific case of LLSingletonBase::MasterList, don't. @@ -189,22 +201,30 @@ struct LLSingleton_manage_master<LLSingletonBase::MasterList> void remove(LLSingletonBase*) {} void push_initializing(LLSingletonBase*) {} void pop_initializing (LLSingletonBase*) {} - LLSingletonBase::list_t& get_initializing(LLSingletonBase::MasterList* instance) - { - return LLSingletonBase::get_initializing_from(instance); - } + // since we never pushed, no need to clean up + void reset_initializing(LLSingletonBase::list_t::size_type size) {} + LLSingletonBase::list_t::size_type get_initializing_size() { return 0; } + void capture_dependency(LLSingletonBase*) {} }; // Now we can implement LLSingletonBase's template constructor. template <typename DERIVED_TYPE> LLSingletonBase::LLSingletonBase(tag<DERIVED_TYPE>): - mCleaned(false), - mDeleteSingleton(NULL) + mDeleteSingleton(nullptr) { - // Make this the currently-initializing LLSingleton. + // This is the earliest possible point at which we can push this new + // instance onto the init stack. LLSingleton::constructSingleton() can't + // do it before calling the constructor, because it doesn't have an + // instance pointer until the constructor returns. Fortunately this + // constructor is guaranteed to be called before any subclass constructor. + // Make this new instance the currently-initializing LLSingleton. LLSingleton_manage_master<DERIVED_TYPE>().push_initializing(this); } +// forward declare for friend directive within LLSingleton +template <typename DERIVED_TYPE> +class LLParamSingleton; + /** * LLSingleton implements the getInstance() method part of the Singleton * pattern. It can't make the derived class constructors protected, though, so @@ -232,10 +252,19 @@ LLSingletonBase::LLSingletonBase(tag<DERIVED_TYPE>): * leading back to yours, move the instance reference from your constructor to * your initSingleton() method. * - * If you override LLSingleton<T>::cleanupSingleton(), your method will be - * called if someone calls LLSingletonBase::cleanupAll(). The significant part - * of this promise is that cleanupAll() will call individual - * cleanupSingleton() methods in reverse dependency order. + * If you override LLSingleton<T>::cleanupSingleton(), your method will + * implicitly be called by LLSingleton<T>::deleteSingleton() just before the + * instance is destroyed. We introduce a special cleanupSingleton() method + * because cleanupSingleton() operations can involve nontrivial realtime, or + * throw an exception. A destructor should do neither! + * + * If your cleanupSingleton() method throws an exception, we log that + * exception but carry on. + * + * If at some point you call LLSingletonBase::deleteAll(), all remaining + * LLSingleton<T> instances will be destroyed in reverse dependency order. (Or + * call MySubclass::deleteSingleton() to specifically destroy the canonical + * MySubclass instance.) * * That is, consider LLSingleton subclasses C, B and A. A depends on B, which * in turn depends on C. These dependencies are expressed as calls to @@ -243,36 +272,116 @@ LLSingletonBase::LLSingletonBase(tag<DERIVED_TYPE>): * It shouldn't matter whether these calls appear in A::A() or * A::initSingleton(), likewise B::B() or B::initSingleton(). * - * We promise that if you later call LLSingletonBase::cleanupAll(): - * 1. A::cleanupSingleton() will be called before - * 2. B::cleanupSingleton(), which will be called before - * 3. C::cleanupSingleton(). + * We promise that if you later call LLSingletonBase::deleteAll(): + * 1. A::deleteSingleton() will be called before + * 2. B::deleteSingleton(), which will be called before + * 3. C::deleteSingleton(). * Put differently, if your LLSingleton subclass constructor or * initSingleton() method explicitly depends on some other LLSingleton * subclass, you may continue to rely on that other subclass in your * cleanupSingleton() method. - * - * We introduce a special cleanupSingleton() method because cleanupSingleton() - * operations can involve nontrivial realtime, or might throw an exception. A - * destructor should do neither! - * - * If your cleanupSingleton() method throws an exception, we log that - * exception but proceed with the remaining cleanupSingleton() calls. - * - * Similarly, if at some point you call LLSingletonBase::deleteAll(), all - * remaining LLSingleton instances will be destroyed in dependency order. (Or - * call MySubclass::deleteSingleton() to specifically destroy the canonical - * MySubclass instance.) - * - * As currently written, LLSingleton is not thread-safe. */ template <typename DERIVED_TYPE> class LLSingleton : public LLSingletonBase { private: - static DERIVED_TYPE* constructSingleton() + // LLSingleton<DERIVED_TYPE> must have a distinct instance of + // SingletonData for every distinct DERIVED_TYPE. It's tempting to + // consider hoisting SingletonData up into LLSingletonBase. Don't do it. + struct SingletonData { - return new DERIVED_TYPE(); + // Use a recursive_mutex in case of constructor circularity. With a + // non-recursive mutex, that would result in deadlock. + typedef std::recursive_mutex mutex_t; + mutex_t mMutex; // LockStatic looks for mMutex + + EInitState mInitState{UNINITIALIZED}; + DERIVED_TYPE* mInstance{nullptr}; + }; + typedef llthread::LockStatic<SingletonData> LockStatic; + + // Allow LLParamSingleton subclass -- but NOT DERIVED_TYPE itself -- to + // access our private members. + friend class LLParamSingleton<DERIVED_TYPE>; + + // LLSingleton only supports a nullary constructor. However, the specific + // purpose for its subclass LLParamSingleton is to support Singletons + // requiring constructor arguments. constructSingleton() supports both use + // cases. + // Accepting LockStatic& requires that the caller has already locked our + // static data before calling. + template <typename... Args> + static void constructSingleton(LockStatic& lk, Args&&... args) + { + auto prev_size = LLSingleton_manage_master<DERIVED_TYPE>().get_initializing_size(); + // Any getInstance() calls after this point are from within constructor + lk->mInitState = CONSTRUCTING; + try + { + lk->mInstance = new DERIVED_TYPE(std::forward<Args>(args)...); + } + catch (const std::exception& err) + { + // LLSingletonBase might -- or might not -- have pushed the new + // instance onto the init stack before the exception. Reset the + // init stack to its previous size BEFORE logging so log-machinery + // LLSingletons don't record a dependency on DERIVED_TYPE! + LLSingleton_manage_master<DERIVED_TYPE>().reset_initializing(prev_size); + logwarns({"Error constructing ", classname<DERIVED_TYPE>(), + ": ", err.what()}); + // There isn't a separate EInitState value meaning "we attempted + // to construct this LLSingleton subclass but could not," so use + // DELETED. That seems slightly more appropriate than UNINITIALIZED. + lk->mInitState = DELETED; + // propagate the exception + throw; + } + + // Any getInstance() calls after this point are from within initSingleton() + lk->mInitState = INITIALIZING; + try + { + // initialize singleton after constructing it so that it can + // reference other singletons which in turn depend on it, thus + // breaking cyclic dependencies + lk->mInstance->initSingleton(); + lk->mInitState = INITIALIZED; + + // pop this off stack of initializing singletons + pop_initializing(lk->mInstance); + } + catch (const std::exception& err) + { + // pop this off stack of initializing singletons here, too -- + // BEFORE logging, so log-machinery LLSingletons don't record a + // dependency on DERIVED_TYPE! + pop_initializing(lk->mInstance); + logwarns({"Error in ", classname<DERIVED_TYPE>(), + "::initSingleton(): ", err.what()}); + // Get rid of the instance entirely. This call depends on our + // recursive_mutex. We could have a deleteSingleton(LockStatic&) + // overload and pass lk, but we don't strictly need it. + deleteSingleton(); + // propagate the exception + throw; + } + } + + static void pop_initializing(LLSingletonBase* sb) + { + // route through LLSingleton_manage_master so we Do The Right Thing + // (namely, nothing) for MasterList + LLSingleton_manage_master<DERIVED_TYPE>().pop_initializing(sb); + } + + static void capture_dependency(LLSingletonBase* sb) + { + // By this point, if DERIVED_TYPE was pushed onto the initializing + // stack, it has been popped off. So the top of that stack, if any, is + // an LLSingleton that directly depends on DERIVED_TYPE. If + // getInstance() was called by another LLSingleton, rather than from + // vanilla application code, record the dependency. + LLSingleton_manage_master<DERIVED_TYPE>().capture_dependency(sb); } // We know of no way to instruct the compiler that every subclass @@ -285,37 +394,6 @@ private: // subclass body. virtual void you_must_use_LLSINGLETON_macro() = 0; - // stores pointer to singleton instance - struct SingletonLifetimeManager - { - SingletonLifetimeManager() - { - construct(); - } - - static void construct() - { - sData.mInitState = CONSTRUCTING; - sData.mInstance = constructSingleton(); - sData.mInitState = INITIALIZING; - } - - ~SingletonLifetimeManager() - { - // The dependencies between LLSingletons, and the arbitrary order - // of static-object destruction, mean that we DO NOT WANT this - // destructor to delete this LLSingleton. This destructor will run - // without regard to any other LLSingleton whose cleanup might - // depend on its existence. If you want to clean up LLSingletons, - // call LLSingletonBase::deleteAll() sometime before static-object - // destruction begins. That method will properly honor cross- - // LLSingleton dependencies. Otherwise we simply leak LLSingleton - // instances at shutdown. Since the whole process is terminating - // anyway, that's not necessarily a bad thing; it depends on what - // resources your LLSingleton instances are managing. - } - }; - protected: // Pass DERIVED_TYPE explicitly to LLSingletonBase's constructor because, // until our subclass constructor completes, *this isn't yet a @@ -330,102 +408,176 @@ protected: LLSingleton_manage_master<DERIVED_TYPE>().add(this); } -public: +protected: virtual ~LLSingleton() { - // remove this instance from the master list + // This phase of cleanup is performed in the destructor rather than in + // deleteSingleton() to defend against manual deletion. When we moved + // cleanup to deleteSingleton(), we hit crashes due to dangling + // pointers in the MasterList. + LockStatic lk; + lk->mInstance = nullptr; + lk->mInitState = DELETED; + + // Remove this instance from the master list. LLSingleton_manage_master<DERIVED_TYPE>().remove(this); - sData.mInstance = NULL; - sData.mInitState = DELETED; } +public: /** - * @brief Immediately delete the singleton. + * @brief Cleanup and destroy the singleton instance. * - * A subsequent call to LLProxy::getInstance() will construct a new - * instance of the class. + * deleteSingleton() calls this instance's cleanupSingleton() method and + * then destroys the instance. * - * Without an explicit call to LLSingletonBase::deleteAll(), LLSingletons - * are implicitly destroyed after main() has exited and the C++ runtime is - * cleaning up statically-constructed objects. Some classes derived from - * LLSingleton have objects that are part of a runtime system that is - * terminated before main() exits. Calling the destructor of those objects - * after the termination of their respective systems can cause crashes and - * other problems during termination of the project. Using this method to - * destroy the singleton early can prevent these crashes. + * A subsequent call to LLSingleton<T>::getInstance() will construct a new + * instance of the class. * - * An example where this is needed is for a LLSingleton that has an APR - * object as a member that makes APR calls on destruction. The APR system is - * shut down explicitly before main() exits. This causes a crash on exit. - * Using this method before the call to apr_terminate() and NOT calling - * getInstance() again will prevent the crash. + * Without an explicit call to LLSingletonBase::deleteAll(), or + * LLSingleton<T>::deleteSingleton(), LLSingleton instances are simply + * leaked. (Allowing implicit destruction at shutdown caused too many + * problems.) */ static void deleteSingleton() { - delete sData.mInstance; - sData.mInstance = NULL; - sData.mInitState = DELETED; + // Hold the lock while we call cleanupSingleton() and the destructor. + // Our destructor also instantiates LockStatic, requiring a recursive + // mutex. + LockStatic lk; + // of course, only cleanup and delete if there's something there + if (lk->mInstance) + { + lk->mInstance->cleanup_(); + delete lk->mInstance; + // destructor clears mInstance (and mInitState) + } } static DERIVED_TYPE* getInstance() { - static SingletonLifetimeManager sLifeTimeMgr; - - switch (sData.mInitState) - { - case UNINITIALIZED: - // should never be uninitialized at this point - logerrs("Uninitialized singleton ", - demangle(typeid(DERIVED_TYPE).name()).c_str()); - return NULL; - - case CONSTRUCTING: - logerrs("Tried to access singleton ", - demangle(typeid(DERIVED_TYPE).name()).c_str(), - " from singleton constructor!"); - return NULL; - - case INITIALIZING: - // go ahead and flag ourselves as initialized so we can be - // reentrant during initialization - sData.mInitState = INITIALIZED; - // initialize singleton after constructing it so that it can - // reference other singletons which in turn depend on it, thus - // breaking cyclic dependencies - sData.mInstance->initSingleton(); - // pop this off stack of initializing singletons - LLSingleton_manage_master<DERIVED_TYPE>().pop_initializing(sData.mInstance); - break; - - case INITIALIZED: - break; - - case DELETED: - logwarns("Trying to access deleted singleton ", - demangle(typeid(DERIVED_TYPE).name()).c_str(), - " -- creating new instance"); - SingletonLifetimeManager::construct(); - // same as first time construction - sData.mInitState = INITIALIZED; - sData.mInstance->initSingleton(); - // pop this off stack of initializing singletons - LLSingleton_manage_master<DERIVED_TYPE>().pop_initializing(sData.mInstance); - break; - } - - // By this point, if DERIVED_TYPE was pushed onto the initializing - // stack, it has been popped off. So the top of that stack, if any, is - // an LLSingleton that directly depends on DERIVED_TYPE. If this call - // came from another LLSingleton, rather than from vanilla application - // code, record the dependency. - sData.mInstance->capture_dependency( - LLSingleton_manage_master<DERIVED_TYPE>().get_initializing(sData.mInstance), - sData.mInitState); - return sData.mInstance; + // We know the viewer has LLSingleton dependency circularities. If you + // feel strongly motivated to eliminate them, cheers and good luck. + // (At that point we could consider a much simpler locking mechanism.) + + // If A and B depend on each other, and thread T1 requests A at the + // same moment thread T2 requests B, you could get a sequence like this: + // - T1 locks A + // - T2 locks B + // - T1, having constructed A, calls A::initSingleton(), which calls + // B::getInstance() and blocks on B's lock + // - T2, having constructed B, calls B::initSingleton(), which calls + // A::getInstance() and blocks on A's lock + // In other words, classic deadlock. + + // Avoid that by constructing and initializing every LLSingleton on + // the main thread. In that scenario: + // - T1 locks A + // - T2 locks B + // - T1 discovers A is UNINITIALIZED, so it queues a task for the main + // thread, unlocks A and blocks on the std::future. + // - T2 discovers B is UNINITIALIZED, so it queues a task for the main + // thread, unlocks B and blocks on the std::future. + // - The main thread executes T1's request for A. It locks A and + // starts to construct it. + // - A::initSingleton() calls B::getInstance(). Fine: nobody's holding + // B's lock. + // - The main thread locks B, constructs B, calls B::initSingleton(), + // which calls A::getInstance(), which returns A. + // - B::getInstance() returns B to A::initSingleton(), unlocking B. + // - A::getInstance() returns A to the task wrapper, unlocking A. + // - The task wrapper passes A to T1 via the future. T1 resumes. + // - The main thread executes T2's request for B. Oh look, B already + // exists. The task wrapper passes B to T2 via the future. T2 + // resumes. + // This still works even if one of T1 or T2 *is* the main thread. + // This still works even if thread T3 requests B at the same moment as + // T2. Finding B still UNINITIALIZED, T3 also queues a task for the + // main thread, unlocks B and blocks on a (distinct) std::future. By + // the time the main thread executes T3's request for B, B already + // exists, and is simply delivered via the future. + + { // nested scope for 'lk' + // In case racing threads call getInstance() at the same moment, + // serialize the calls. + LockStatic lk; + + switch (lk->mInitState) + { + case CONSTRUCTING: + // here if DERIVED_TYPE's constructor (directly or indirectly) + // calls DERIVED_TYPE::getInstance() + logerrs({"Tried to access singleton ", + classname<DERIVED_TYPE>(), + " from singleton constructor!"}); + return nullptr; + + case INITIALIZING: + // here if DERIVED_TYPE::initSingleton() (directly or indirectly) + // calls DERIVED_TYPE::getInstance(): go ahead and allow it + case INITIALIZED: + // normal subsequent calls + // record the dependency, if any: check if we got here from another + // LLSingleton's constructor or initSingleton() method + capture_dependency(lk->mInstance); + return lk->mInstance; + + case DELETED: + // called after deleteSingleton() + logwarns({"Trying to access deleted singleton ", + classname<DERIVED_TYPE>(), + " -- creating new instance"}); + // fall through + case UNINITIALIZED: + case QUEUED: + // QUEUED means some secondary thread has already requested an + // instance, but for present purposes that's semantically + // identical to UNINITIALIZED: either way, we must ourselves + // request an instance. + break; + } + + // Here we need to construct a new instance. + if (on_main_thread()) + { + // On the main thread, directly construct the instance while + // holding the lock. + constructSingleton(lk); + capture_dependency(lk->mInstance); + return lk->mInstance; + } + + // Here we need to construct a new instance, but we're on a secondary + // thread. + lk->mInitState = QUEUED; + } // unlock 'lk' + + // Per the comment block above, dispatch to the main thread. + loginfos({classname<DERIVED_TYPE>(), + "::getInstance() dispatching to main thread"}); + auto instance = LLMainThreadTask::dispatch( + [](){ + // VERY IMPORTANT to call getInstance() on the main thread, + // rather than going straight to constructSingleton()! + // During the time window before mInitState is INITIALIZED, + // multiple requests might be queued. It's essential that, as + // the main thread processes them, only the FIRST such request + // actually constructs the instance -- every subsequent one + // simply returns the existing instance. + loginfos({classname<DERIVED_TYPE>(), + "::getInstance() on main thread"}); + return getInstance(); + }); + // record the dependency chain tracked on THIS thread, not the main + // thread (consider a getInstance() overload with a tag param that + // suppresses dep tracking when dispatched to the main thread) + capture_dependency(instance); + loginfos({classname<DERIVED_TYPE>(), + "::getInstance() returning on requesting thread"}); + return instance; } // Reference version of getInstance() - // Preferred over getInstance() as it disallows checking for NULL + // Preferred over getInstance() as it disallows checking for nullptr static DERIVED_TYPE& instance() { return *getInstance(); @@ -435,7 +587,9 @@ public: // Use this to avoid accessing singletons before they can safely be constructed. static bool instanceExists() { - return sData.mInitState == INITIALIZED; + // defend any access to sData from racing threads + LockStatic lk; + return lk->mInitState == INITIALIZED; } // Has this singleton been deleted? This can be useful during shutdown @@ -443,22 +597,181 @@ public: // cleaned up. static bool wasDeleted() { - return sData.mInitState == DELETED; + // defend any access to sData from racing threads + LockStatic lk; + return lk->mInitState == DELETED; } +}; + +/** + * LLParamSingleton<T> is like LLSingleton<T>, except in the following ways: + * + * * It is NOT instantiated on demand (instance() or getInstance()). You must + * first call initParamSingleton(constructor args...). + * * Before initParamSingleton(), calling instance() or getInstance() dies with + * LL_ERRS. + * * initParamSingleton() may be called only once. A second call dies with + * LL_ERRS. + * * However, distinct initParamSingleton() calls can be used to engage + * different constructors, as long as only one such call is executed at + * runtime. + * * Unlike LLSingleton, an LLParamSingleton cannot be "revived" by an + * instance() or getInstance() call after deleteSingleton(). + * + * Importantly, though, each LLParamSingleton subclass does participate in the + * dependency-ordered LLSingletonBase::deleteAll() processing. + */ +template <typename DERIVED_TYPE> +class LLParamSingleton : public LLSingleton<DERIVED_TYPE> +{ private: - struct SingletonData + typedef LLSingleton<DERIVED_TYPE> super; + using typename super::LockStatic; + + // Passes arguments to DERIVED_TYPE's constructor and sets appropriate + // states, returning a pointer to the new instance. + template <typename... Args> + static DERIVED_TYPE* initParamSingleton_(Args&&... args) { - // 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; - }; - static SingletonData sData; + // In case racing threads both call initParamSingleton() at the same + // time, serialize them. One should initialize; the other should see + // mInitState already set. + LockStatic lk; + // For organizational purposes this function shouldn't be called twice + if (lk->mInitState != super::UNINITIALIZED) + { + super::logerrs({"Tried to initialize singleton ", + super::template classname<DERIVED_TYPE>(), + " twice!"}); + return nullptr; + } + else if (on_main_thread()) + { + // on the main thread, simply construct instance while holding lock + super::logdebugs({super::template classname<DERIVED_TYPE>(), + "::initParamSingleton()"}); + super::constructSingleton(lk, std::forward<Args>(args)...); + return lk->mInstance; + } + else + { + // on secondary thread, dispatch to main thread -- + // set state so we catch any other calls before the main thread + // picks up the task + lk->mInitState = super::QUEUED; + // very important to unlock here so main thread can actually process + lk.unlock(); + super::loginfos({super::template classname<DERIVED_TYPE>(), + "::initParamSingleton() dispatching to main thread"}); + // Normally it would be the height of folly to reference-bind + // 'args' into a lambda to be executed on some other thread! By + // the time that thread executed the lambda, the references would + // all be dangling, and Bad Things would result. But + // LLMainThreadTask::dispatch() promises to block until the passed + // task has completed. So in this case we know the references will + // remain valid until the lambda has run, so we dare to bind + // references. + auto instance = LLMainThreadTask::dispatch( + [&](){ + super::loginfos({super::template classname<DERIVED_TYPE>(), + "::initParamSingleton() on main thread"}); + return initParamSingleton_(std::forward<Args>(args)...); + }); + super::loginfos({super::template classname<DERIVED_TYPE>(), + "::initParamSingleton() returning on requesting thread"}); + return instance; + } + } + +public: + using super::deleteSingleton; + using super::instanceExists; + using super::wasDeleted; + + /// initParamSingleton() constructs the instance, returning a reference. + /// Pass whatever arguments are required to construct DERIVED_TYPE. + template <typename... Args> + static DERIVED_TYPE& initParamSingleton(Args&&... args) + { + return *initParamSingleton_(std::forward<Args>(args)...); + } + + static DERIVED_TYPE* getInstance() + { + // In case racing threads call getInstance() at the same moment as + // initParamSingleton(), serialize the calls. + LockStatic lk; + + switch (lk->mInitState) + { + case super::UNINITIALIZED: + case super::QUEUED: + super::logerrs({"Uninitialized param singleton ", + super::template classname<DERIVED_TYPE>()}); + break; + + case super::CONSTRUCTING: + super::logerrs({"Tried to access param singleton ", + super::template classname<DERIVED_TYPE>(), + " from singleton constructor!"}); + break; + + case super::INITIALIZING: + // As with LLSingleton, explicitly permit circular calls from + // within initSingleton() + case super::INITIALIZED: + // for any valid call, capture dependencies + super::capture_dependency(lk->mInstance); + return lk->mInstance; + + case super::DELETED: + super::logerrs({"Trying to access deleted param singleton ", + super::template classname<DERIVED_TYPE>()}); + break; + } + + // should never actually get here; this is to pacify the compiler, + // which assumes control might return from logerrs() + return nullptr; + } + + // instance() is replicated here so it calls + // LLParamSingleton::getInstance() rather than LLSingleton::getInstance() + // -- avoid making getInstance() virtual + static DERIVED_TYPE& instance() + { + return *getInstance(); + } }; -template<typename T> -typename LLSingleton<T>::SingletonData LLSingleton<T>::sData; +/** + * Initialization locked singleton, only derived class can decide when to initialize. + * Starts locked. + * For cases when singleton has a dependency onto something or. + * + * LLLockedSingleton is like an LLParamSingleton with a nullary constructor. + * It cannot be instantiated on demand (instance() or getInstance() call) -- + * it must be instantiated by calling construct(). However, it does + * participate in dependency-ordered LLSingletonBase::deleteAll() processing. + */ +template <typename DT> +class LLLockedSingleton : public LLParamSingleton<DT> +{ + typedef LLParamSingleton<DT> super; + +public: + using super::deleteSingleton; + using super::getInstance; + using super::instance; + using super::instanceExists; + using super::wasDeleted; + + static DT* construct() + { + return super::initParamSingleton(); + } +}; /** * Use LLSINGLETON(Foo); at the start of an LLSingleton<Foo> subclass body @@ -484,12 +797,23 @@ typename LLSingleton<T>::SingletonData LLSingleton<T>::sData; * file, use 'inline' (unless it's a template class) to avoid duplicate-symbol * errors at link time. */ -#define LLSINGLETON(DERIVED_CLASS) \ +#define LLSINGLETON(DERIVED_CLASS, ...) \ private: \ /* implement LLSingleton pure virtual method whose sole purpose */ \ /* is to remind people to use this macro */ \ virtual void you_must_use_LLSINGLETON_macro() {} \ friend class LLSingleton<DERIVED_CLASS>; \ + DERIVED_CLASS(__VA_ARGS__) + +/** + * A slight variance from the above, but includes the "override" keyword + */ +#define LLSINGLETON_C11(DERIVED_CLASS) \ +private: \ + /* implement LLSingleton pure virtual method whose sole purpose */ \ + /* is to remind people to use this macro */ \ + virtual void you_must_use_LLSINGLETON_macro() override {} \ + friend class LLSingleton<DERIVED_CLASS>; \ DERIVED_CLASS() /** @@ -510,4 +834,8 @@ private: \ /* LLSINGLETON() is carefully implemented to permit exactly this */ \ LLSINGLETON(DERIVED_CLASS) {} +#define LLSINGLETON_EMPTY_CTOR_C11(DERIVED_CLASS) \ + /* LLSINGLETON() is carefully implemented to permit exactly this */ \ + LLSINGLETON_C11(DERIVED_CLASS) {} + #endif diff --git a/indra/llcommon/llstacktrace.cpp b/indra/llcommon/llstacktrace.cpp index bbf0e1e141..80057bf0f2 100644 --- a/indra/llcommon/llstacktrace.cpp +++ b/indra/llcommon/llstacktrace.cpp @@ -33,7 +33,10 @@ #include <sstream> #include "llwin32headerslean.h" -#include "Dbghelp.h" +#pragma warning (push) +#pragma warning (disable:4091) // a microsoft header has warnings. Very nice. +#include <dbghelp.h> +#pragma warning (pop) typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( IN ULONG frames_to_skip, diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index b024b47225..a90c2c7e08 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -36,6 +36,10 @@ #include <set> #include <typeinfo> +#ifdef LL_LINUX +// <ND> For strcmp +#include <string.h> +#endif // Use to compare the first element only of a pair // e.g. typedef std::set<std::pair<int, Data*>, compare_pair<int, Data*> > some_pair_set_t; template <typename T1, typename T2> diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index b272728200..9779e03e8b 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -658,22 +658,6 @@ std::string utf8str_removeCRLF(const std::string& utf8str) } #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); diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index d31d0cafc7..32e66a48b7 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -37,7 +37,7 @@ #include <map> #include "llformat.h" -#if LL_LINUX || LL_SOLARIS +#if LL_LINUX #include <wctype.h> #include <wchar.h> #endif @@ -45,16 +45,10 @@ #include <string.h> #include <boost/scoped_ptr.hpp> -#if LL_SOLARIS -// stricmp and strnicmp do not exist on Solaris: -#define stricmp strcasecmp -#define strnicmp strncasecmp -#endif - const char LL_UNKNOWN_CHAR = '?'; class LLSD; -#if LL_DARWIN || LL_LINUX || LL_SOLARIS +#if LL_DARWIN || LL_LINUX // Template specialization of char_traits for U16s. Only necessary on Mac and Linux (exists on Windows already) #include <cstring> @@ -709,32 +703,6 @@ 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. - * - */ - -// Deal with the differeneces on Windows -namespace snprintf_hack -{ - LL_COMMON_API int snprintf(char *str, size_t size, const char *format, ...); -} - -using snprintf_hack::snprintf; - -/** * @brief Convert a wide string to std::string * * This replaces the unsafe W2A macro from ATL. diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 1f8d558fbe..4e61fb8a58 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -55,6 +55,7 @@ #include <boost/utility/enable_if.hpp> #include <boost/type_traits/is_integral.hpp> #include <boost/type_traits/is_float.hpp> +#include "llfasttimer.h" using namespace llsd; @@ -87,17 +88,6 @@ using namespace llsd; # include <stdexcept> const char MEMINFO_FILE[] = "/proc/meminfo"; # include <gnu/libc-version.h> -#elif LL_SOLARIS -# include <stdio.h> -# include <unistd.h> -# include <sys/utsname.h> -# define _STRUCTURED_PROC 1 -# include <sys/procfs.h> -# include <sys/types.h> -# include <sys/stat.h> -# include <fcntl.h> -# include <errno.h> -extern int errno; #endif LLCPUInfo gSysCPU; @@ -543,8 +533,6 @@ const std::string& LLOSInfo::getOSVersionString() const U32 LLOSInfo::getProcessVirtualSizeKB() { U32 virtual_size = 0; -#if LL_WINDOWS -#endif #if LL_LINUX # define STATUS_SIZE 2048 LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); @@ -564,24 +552,6 @@ U32 LLOSInfo::getProcessVirtualSizeKB() } fclose(status_filep); } -#elif LL_SOLARIS - char proc_ps[LL_MAX_PATH]; - sprintf(proc_ps, "/proc/%d/psinfo", (int)getpid()); - int proc_fd = -1; - if((proc_fd = open(proc_ps, O_RDONLY)) == -1){ - 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)){ - LL_WARNS() << "Unable to read " << proc_ps << LL_ENDL; - close(proc_fd); - return 0; - } - - close(proc_fd); - - virtual_size = proc_psinfo.pr_size; #endif return virtual_size; } @@ -590,8 +560,6 @@ U32 LLOSInfo::getProcessVirtualSizeKB() U32 LLOSInfo::getProcessResidentSizeKB() { U32 resident_size = 0; -#if LL_WINDOWS -#endif #if LL_LINUX LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); if (status_filep != NULL) @@ -610,24 +578,6 @@ U32 LLOSInfo::getProcessResidentSizeKB() } fclose(status_filep); } -#elif LL_SOLARIS - char proc_ps[LL_MAX_PATH]; - sprintf(proc_ps, "/proc/%d/psinfo", (int)getpid()); - int proc_fd = -1; - if((proc_fd = open(proc_ps, O_RDONLY)) == -1){ - 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)){ - LL_WARNS() << "Unable to read " << proc_ps << LL_ENDL; - close(proc_fd); - return 0; - } - - close(proc_fd); - - resident_size = proc_psinfo.pr_rssize; #endif return resident_size; } @@ -772,11 +722,6 @@ U32Kilobytes LLMemoryInfo::getPhysicalMemoryKB() const phys = (U64)(getpagesize()) * (U64)(get_phys_pages()); return U64Bytes(phys); -#elif LL_SOLARIS - U64 phys = 0; - phys = (U64)(getpagesize()) * (U64)(sysconf(_SC_PHYS_PAGES)); - return U64Bytes(phys); - #else return 0; @@ -925,8 +870,12 @@ LLMemoryInfo& LLMemoryInfo::refresh() return *this; } +static LLTrace::BlockTimerStatHandle FTM_MEMINFO_LOAD_STATS("MemInfo Load Stats"); + LLSD LLMemoryInfo::loadStatsMap() { + LL_RECORD_BLOCK_TIME(FTM_MEMINFO_LOAD_STATS); + // This implementation is derived from stream() code (as of 2011-06-29). Stats stats; @@ -948,24 +897,11 @@ LLSD LLMemoryInfo::loadStatsMap() stats.add("Total Virtual KB", state.ullTotalVirtual/div); stats.add("Avail Virtual KB", state.ullAvailVirtual/div); - PERFORMANCE_INFORMATION perf; - perf.cb = sizeof(perf); - GetPerformanceInfo(&perf, sizeof(perf)); - - SIZE_T pagekb(perf.PageSize/1024); - stats.add("CommitTotal KB", perf.CommitTotal * pagekb); - stats.add("CommitLimit KB", perf.CommitLimit * pagekb); - stats.add("CommitPeak KB", perf.CommitPeak * pagekb); - stats.add("PhysicalTotal KB", perf.PhysicalTotal * pagekb); - stats.add("PhysicalAvail KB", perf.PhysicalAvailable * pagekb); - stats.add("SystemCache KB", perf.SystemCache * pagekb); - stats.add("KernelTotal KB", perf.KernelTotal * pagekb); - stats.add("KernelPaged KB", perf.KernelPaged * pagekb); - stats.add("KernelNonpaged KB", perf.KernelNonpaged * pagekb); - stats.add("PageSize KB", pagekb); - stats.add("HandleCount", perf.HandleCount); - stats.add("ProcessCount", perf.ProcessCount); - stats.add("ThreadCount", perf.ThreadCount); + // SL-12122 - Call to GetPerformanceInfo() was removed here. Took + // on order of 10 ms, causing unacceptable frame time spike every + // second, and results were never used. If this is needed in the + // future, must find a way to avoid frame time impact (e.g. move + // to another thread, call much less often). PROCESS_MEMORY_COUNTERS_EX pmem; pmem.cb = sizeof(pmem); @@ -1074,13 +1010,6 @@ LLSD LLMemoryInfo::loadStatsMap() } } -#elif LL_SOLARIS - U64 phys = 0; - - phys = (U64)(sysconf(_SC_PHYS_PAGES)) * (U64)(sysconf(_SC_PAGESIZE)/1024); - - stats.add("Total Physical KB", phys); - #elif LL_LINUX std::ifstream meminfo(MEMINFO_FILE); if (meminfo.is_open()) diff --git a/indra/llcommon/lltempredirect.cpp b/indra/llcommon/lltempredirect.cpp new file mode 100644 index 0000000000..ec194c1d29 --- /dev/null +++ b/indra/llcommon/lltempredirect.cpp @@ -0,0 +1,138 @@ +/** + * @file lltempredirect.cpp + * @author Nat Goodspeed + * @date 2019-10-31 + * @brief Implementation for lltempredirect. + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Copyright (c) 2019, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "lltempredirect.h" +// STL headers +// std headers +#if !LL_WINDOWS +# include <unistd.h> +#else +# include <io.h> +#endif // !LL_WINDOWS +// external library headers +// other Linden headers + +/***************************************************************************** +* llfd +*****************************************************************************/ +// We could restate the implementation of each of llfd::close(), etc., but +// this is way more succinct. +#if LL_WINDOWS +#define fhclose _close +#define fhdup _dup +#define fhdup2 _dup2 +#define fhfdopen _fdopen +#define fhfileno _fileno +#else +#define fhclose ::close +#define fhdup ::dup +#define fhdup2 ::dup2 +#define fhfdopen ::fdopen +#define fhfileno ::fileno +#endif + +int llfd::close(int fd) +{ + return fhclose(fd); +} + +int llfd::dup(int target) +{ + return fhdup(target); +} + +int llfd::dup2(int target, int reference) +{ + return fhdup2(target, reference); +} + +FILE* llfd::open(int fd, const char* mode) +{ + return fhfdopen(fd, mode); +} + +int llfd::fileno(FILE* stream) +{ + return fhfileno(stream); +} + +/***************************************************************************** +* LLTempRedirect +*****************************************************************************/ +LLTempRedirect::LLTempRedirect(): + mOrigTarget(-1), // -1 is an invalid file descriptor + mReference(-1) +{} + +LLTempRedirect::LLTempRedirect(FILE* target, FILE* reference): + LLTempRedirect((target? fhfileno(target) : -1), + (reference? fhfileno(reference) : -1)) +{} + +LLTempRedirect::LLTempRedirect(int target, int reference): + // capture a duplicate file descriptor for the file originally targeted by + // 'reference' + mOrigTarget((reference >= 0)? fhdup(reference) : -1), + mReference(reference) +{ + if (target >= 0 && reference >= 0) + { + // As promised, force 'reference' to refer to 'target'. This first + // implicitly closes 'reference', which is why we first capture a + // duplicate so the original target file stays open. + fhdup2(target, reference); + } +} + +LLTempRedirect::LLTempRedirect(LLTempRedirect&& other) +{ + mOrigTarget = other.mOrigTarget; + mReference = other.mReference; + // other LLTempRedirect must be in moved-from state so its destructor + // won't repeat the same operations as ours! + other.mOrigTarget = -1; + other.mReference = -1; +} + +LLTempRedirect::~LLTempRedirect() +{ + reset(); +} + +void LLTempRedirect::reset() +{ + // If this instance was default-constructed (or constructed with an + // invalid file descriptor), skip the following. + if (mOrigTarget >= 0) + { + // Restore mReference to point to mOrigTarget. This implicitly closes + // the duplicate created by our constructor of its 'target' file + // descriptor. + fhdup2(mOrigTarget, mReference); + // mOrigTarget has served its purpose + fhclose(mOrigTarget); + } + // assign these because reset() is also responsible for a "moved from" + // instance + mOrigTarget = -1; + mReference = -1; +} + +LLTempRedirect& LLTempRedirect::operator=(LLTempRedirect&& other) +{ + reset(); + std::swap(mOrigTarget, other.mOrigTarget); + std::swap(mReference, other.mReference); + return *this; +} diff --git a/indra/llcommon/lltempredirect.h b/indra/llcommon/lltempredirect.h new file mode 100644 index 0000000000..33e05dc06b --- /dev/null +++ b/indra/llcommon/lltempredirect.h @@ -0,0 +1,91 @@ +/** + * @file lltempredirect.h + * @author Nat Goodspeed + * @date 2019-10-31 + * @brief RAII low-level file-descriptor redirection + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Copyright (c) 2019, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLTEMPREDIRECT_H) +#define LL_LLTEMPREDIRECT_H + +// Functions in this namespace are intended to insulate the caller from the +// aggravating distinction between ::close() and Microsoft _close(). +namespace llfd +{ + +int close(int fd); +int dup(int target); +int dup2(int target, int reference); +FILE* open(int fd, const char* mode); +int fileno(FILE* stream); + +} // namespace llfd + +/** + * LLTempRedirect is an RAII class that performs file redirection on low-level + * file descriptors, expressed as ints. (Use llfd::fileno() to obtain the file + * descriptor from a classic-C FILE*. There is no portable way to obtain the + * file descriptor from a std::fstream.) + * + * Instantiate LLTempRedirect with a target file descriptor (e.g. for some + * open file) and a reference file descriptor (e.g. for stderr). From that + * point until the LLTempRedirect instance is destroyed, all OS-level writes + * to the reference file descriptor will be redirected to the target file. + * + * Because dup2() is used for redirection, the original passed target file + * descriptor remains open. If you want LLTempRedirect's destructor to close + * the target file, close() the target file descriptor after passing it to + * LLTempRedirect's constructor. + * + * LLTempRedirect's constructor saves the original target of the reference + * file descriptor. Its destructor restores the reference file descriptor to + * point once again to its original target. + */ +class LLTempRedirect +{ +public: + LLTempRedirect(); + /** + * For the lifespan of this LLTempRedirect instance, all writes to + * 'reference' will be redirected to 'target'. When this LLTempRedirect is + * destroyed, the original target for 'reference' will be restored. + * + * Pass 'target' as NULL if you simply want to save and restore + * 'reference' against possible redirection in the meantime. + */ + LLTempRedirect(FILE* target, FILE* reference); + /** + * For the lifespan of this LLTempRedirect instance, all writes to + * 'reference' will be redirected to 'target'. When this LLTempRedirect is + * destroyed, the original target for 'reference' will be restored. + * + * Pass 'target' as -1 if you simply want to save and restore + * 'reference' against possible redirection in the meantime. + */ + LLTempRedirect(int target, int reference); + LLTempRedirect(const LLTempRedirect&) = delete; + LLTempRedirect(LLTempRedirect&& other); + + ~LLTempRedirect(); + + LLTempRedirect& operator=(const LLTempRedirect&) = delete; + LLTempRedirect& operator=(LLTempRedirect&& other); + + /// returns (duplicate file descriptor for) the original target of the + /// 'reference' file descriptor passed to our constructor + int getOriginalTarget() const { return mOrigTarget; } + /// returns the original 'reference' file descriptor passed to our + /// constructor + int getReference() const { return mReference; } + +private: + void reset(); + + int mOrigTarget, mReference; +}; + +#endif /* ! defined(LL_LLTEMPREDIRECT_H) */ diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index a4171729db..6d531d842d 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -36,7 +36,7 @@ #include "lltracethreadrecorder.h" #include "llexception.h" -#if LL_LINUX || LL_SOLARIS +#if LL_LINUX #include <sched.h> #endif @@ -92,26 +92,39 @@ void set_thread_name( DWORD dwThreadID, const char* threadName) // } // //---------------------------------------------------------------------------- +namespace +{ -U32 LL_THREAD_LOCAL sThreadID = 0; + LLThread::id_t main_thread() + { + // Using a function-static variable to identify the main thread + // requires that control reach here from the main thread before it + // reaches here from any other thread. We simply trust that whichever + // thread gets here first is the main thread. + static LLThread::id_t s_thread_id = LLThread::currentID(); + return s_thread_id; + } -U32 LLThread::sIDIter = 0; +} // anonymous namespace +LL_COMMON_API bool on_main_thread() +{ + return (LLThread::currentID() == main_thread()); +} LL_COMMON_API void assert_main_thread() { - static U32 s_thread_id = LLThread::currentID(); - if (LLThread::currentID() != s_thread_id) + auto curr = LLThread::currentID(); + auto main = main_thread(); + if (curr != main) { - LL_WARNS() << "Illegal execution from thread id " << (S32) LLThread::currentID() - << " outside main thread " << (S32) s_thread_id << LL_ENDL; + LL_WARNS() << "Illegal execution from thread id " << curr + << " outside main thread " << main << LL_ENDL; } } -void LLThread::registerThreadID() -{ - sThreadID = ++sIDIter; -} +// this function has become moot +void LLThread::registerThreadID() {} // // Handed to the APR thread creation function @@ -122,11 +135,12 @@ void LLThread::threadRun() set_thread_name(-1, mName.c_str()); #endif + // this is the first point at which we're actually running in the new thread + mID = currentID(); + // for now, hard code all LLThreads to report to single master thread recorder, which is known to be running on main thread mRecorder = new LLTrace::ThreadRecorder(*LLTrace::get_master_thread_recorder()); - sThreadID = mID; - // Run the user supplied function do { @@ -168,8 +182,6 @@ LLThread::LLThread(const std::string& name, apr_pool_t *poolp) : mStatus(STOPPED), mRecorder(NULL) { - - mID = ++sIDIter; mRunCondition = new LLCondition(); mDataLock = new LLMutex(); mLocalAPRFilePoolp = NULL ; @@ -342,14 +354,15 @@ void LLThread::setQuitting() { mStatus = QUITTING; } + // It's only safe to remove mRunCondition if all locked threads were notified + mRunCondition->broadcast(); mDataLock->unlock(); - wake(); } // static -U32 LLThread::currentID() +LLThread::id_t LLThread::currentID() { - return sThreadID; + return std::this_thread::get_id(); } // static @@ -376,6 +389,16 @@ void LLThread::wakeLocked() } } +void LLThread::lockData() +{ + mDataLock->lock(); +} + +void LLThread::unlockData() +{ + mDataLock->unlock(); +} + //============================================================================ //---------------------------------------------------------------------------- diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 863c9051f3..5cd0731f6c 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -30,12 +30,9 @@ #include "llapp.h" #include "llapr.h" #include "boost/intrusive_ptr.hpp" -#include "llmutex.h" #include "llrefcount.h" #include <thread> -LL_COMMON_API void assert_main_thread(); - namespace LLTrace { class ThreadRecorder; @@ -45,7 +42,6 @@ class LL_COMMON_API LLThread { private: friend class LLMutex; - static U32 sIDIter; public: typedef enum e_thread_status @@ -55,6 +51,7 @@ public: QUITTING= 2, // Someone wants this thread to quit CRASHED = -1 // An uncaught exception was thrown by the thread } EThreadStatus; + typedef std::thread::id id_t; LLThread(const std::string& name, apr_pool_t *poolp = NULL); virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state. @@ -64,7 +61,7 @@ public: bool isStopped() const { return (STOPPED == mStatus) || (CRASHED == mStatus); } bool isCrashed() const { return (CRASHED == mStatus); } - static U32 currentID(); // Return ID of current thread + static id_t currentID(); // Return ID of current thread static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure. public: @@ -88,7 +85,7 @@ public: LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; } - U32 getID() const { return mID; } + id_t getID() const { return mID; } // Called by threads *not* created via LLThread to register some // internal state used by LLMutex. You must call this once early @@ -109,7 +106,7 @@ protected: std::thread *mThreadp; EThreadStatus mStatus; - U32 mID; + id_t mID; LLTrace::ThreadRecorder* mRecorder; //a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used. @@ -126,8 +123,8 @@ protected: virtual bool runCondition(void); // Lock/Unlock Run Condition -- use around modification of any variable used in runCondition() - inline void lockData(); - inline void unlockData(); + void lockData(); + void unlockData(); // This is the predicate that decides whether the thread should sleep. // It should only be called with mDataLock locked, since the virtual runCondition() function may need to access @@ -142,17 +139,6 @@ protected: }; -void LLThread::lockData() -{ - mDataLock->lock(); -} - -void LLThread::unlockData() -{ - mDataLock->unlock(); -} - - //============================================================================ // Simple responder for self destructing callbacks @@ -168,5 +154,6 @@ public: //============================================================================ extern LL_COMMON_API void assert_main_thread(); +extern LL_COMMON_API bool on_main_thread(); #endif // LL_LLTHREAD_H diff --git a/indra/llcommon/llthreadlocalstorage.cpp b/indra/llcommon/llthreadlocalstorage.cpp index 8cef05caac..d8a063e8d5 100644 --- a/indra/llcommon/llthreadlocalstorage.cpp +++ b/indra/llcommon/llthreadlocalstorage.cpp @@ -93,11 +93,9 @@ void LLThreadLocalPointerBase::initAllThreadLocalStorage() { if (!sInitialized) { - for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances(); - it != end_it; - ++it) + for (auto& base : instance_snapshot()) { - (*it).initStorage(); + base.initStorage(); } sInitialized = true; } @@ -108,11 +106,9 @@ void LLThreadLocalPointerBase::destroyAllThreadLocalStorage() { if (sInitialized) { - //for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances(); - // it != end_it; - // ++it) + //for (auto& base : instance_snapshot()) //{ - // (*it).destroyStorage(); + // base.destroyStorage(); //} sInitialized = false; } diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h index b0bddac8e5..26e0d71d31 100644 --- a/indra/llcommon/llthreadsafequeue.h +++ b/indra/llcommon/llthreadsafequeue.h @@ -30,18 +30,12 @@ #include "llexception.h" #include <deque> #include <string> - -#if LL_WINDOWS -#pragma warning (push) -#pragma warning (disable:4265) -#endif -// 'std::_Pad' : class has virtual functions, but destructor is not virtual -#include <mutex> -#include <condition_variable> - -#if LL_WINDOWS -#pragma warning (pop) -#endif +#include <chrono> +#include "mutex.h" +#include "llcoros.h" +#include LLCOROS_MUTEX_HEADER +#include <boost/fiber/timed_mutex.hpp> +#include LLCOROS_CONDVAR_HEADER // // A general queue exception. @@ -88,18 +82,28 @@ public: // Add an element to the front of queue (will block if the queue has // reached capacity). // - // This call will raise an interrupt error if the queue is deleted while + // This call will raise an interrupt error if the queue is closed while // the caller is blocked. void pushFront(ElementT const & element); - // Try to add an element to the front ofqueue without blocking. Returns + // Try to add an element to the front of queue without blocking. Returns // true only if the element was actually added. bool tryPushFront(ElementT const & element); - + + // Try to add an element to the front of queue, blocking if full but with + // timeout. Returns true if the element was added. + // There are potentially two different timeouts involved: how long to try + // to lock the mutex, versus how long to wait for the queue to stop being + // full. Careful settings for each timeout might be orders of magnitude + // apart. However, this method conflates them. + template <typename Rep, typename Period> + bool tryPushFrontFor(const std::chrono::duration<Rep, Period>& timeout, + ElementT const & element); + // Pop the element at the end of the queue (will block if the queue is // empty). // - // This call will raise an interrupt error if the queue is deleted while + // This call will raise an interrupt error if the queue is closed while // the caller is blocked. ElementT popBack(void); @@ -110,13 +114,29 @@ public: // Returns the size of the queue. size_t size(); + // closes the queue: + // - every subsequent pushFront() call will throw LLThreadSafeQueueInterrupt + // - every subsequent tryPushFront() call will return false + // - popBack() calls will return normally until the queue is drained, then + // every subsequent popBack() will throw LLThreadSafeQueueInterrupt + // - tryPopBack() calls will return normally until the queue is drained, + // then every subsequent tryPopBack() call will return false + void close(); + + // detect closed state + bool isClosed(); + // inverse of isClosed() + explicit operator bool(); + private: std::deque< ElementT > mStorage; U32 mCapacity; + bool mClosed; - std::mutex mLock; - std::condition_variable mCapacityCond; - std::condition_variable mEmptyCond; + boost::fibers::timed_mutex mLock; + typedef std::unique_lock<decltype(mLock)> lock_t; + boost::fibers::condition_variable_any mCapacityCond; + boost::fibers::condition_variable_any mEmptyCond; }; // LLThreadSafeQueue @@ -124,7 +144,8 @@ private: template<typename ElementT> LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(U32 capacity) : -mCapacity(capacity) + mCapacity(capacity), + mClosed(false) { } @@ -132,13 +153,18 @@ mCapacity(capacity) template<typename ElementT> void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element) { + lock_t lock1(mLock); while (true) { - std::unique_lock<std::mutex> lock1(mLock); + if (mClosed) + { + LLTHROW(LLThreadSafeQueueInterrupt()); + } if (mStorage.size() < mCapacity) { mStorage.push_front(element); + lock1.unlock(); mEmptyCond.notify_one(); return; } @@ -149,17 +175,61 @@ void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element) } +template <typename ElementT> +template <typename Rep, typename Period> +bool LLThreadSafeQueue<ElementT>::tryPushFrontFor(const std::chrono::duration<Rep, Period>& timeout, + ElementT const & element) +{ + // Convert duration to time_point: passing the same timeout duration to + // each of multiple calls is wrong. + auto endpoint = std::chrono::steady_clock::now() + timeout; + + lock_t lock1(mLock, std::defer_lock); + if (!lock1.try_lock_until(endpoint)) + return false; + + while (true) + { + if (mClosed) + { + return false; + } + + if (mStorage.size() < mCapacity) + { + mStorage.push_front(element); + lock1.unlock(); + mEmptyCond.notify_one(); + return true; + } + + // Storage Full. Wait for signal. + if (LLCoros::cv_status::timeout == mCapacityCond.wait_until(lock1, endpoint)) + { + // timed out -- formally we might recheck both conditions above + return false; + } + // If we didn't time out, we were notified for some reason. Loop back + // to check. + } +} + + template<typename ElementT> bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element) { - std::unique_lock<std::mutex> lock1(mLock, std::defer_lock); + lock_t lock1(mLock, std::defer_lock); if (!lock1.try_lock()) return false; + if (mClosed) + return false; + if (mStorage.size() >= mCapacity) return false; mStorage.push_front(element); + lock1.unlock(); mEmptyCond.notify_one(); return true; } @@ -168,18 +238,23 @@ bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element) template<typename ElementT> ElementT LLThreadSafeQueue<ElementT>::popBack(void) { + lock_t lock1(mLock); while (true) { - std::unique_lock<std::mutex> lock1(mLock); - if (!mStorage.empty()) { ElementT value = mStorage.back(); mStorage.pop_back(); + lock1.unlock(); mCapacityCond.notify_one(); return value; } + if (mClosed) + { + LLTHROW(LLThreadSafeQueueInterrupt()); + } + // Storage empty. Wait for signal. mEmptyCond.wait(lock1); } @@ -189,15 +264,18 @@ ElementT LLThreadSafeQueue<ElementT>::popBack(void) template<typename ElementT> bool LLThreadSafeQueue<ElementT>::tryPopBack(ElementT & element) { - std::unique_lock<std::mutex> lock1(mLock, std::defer_lock); + lock_t lock1(mLock, std::defer_lock); if (!lock1.try_lock()) return false; + // no need to check mClosed: tryPopBack() behavior when the queue is + // closed is implemented by simple inability to push any new elements if (mStorage.empty()) return false; element = mStorage.back(); mStorage.pop_back(); + lock1.unlock(); mCapacityCond.notify_one(); return true; } @@ -206,8 +284,33 @@ bool LLThreadSafeQueue<ElementT>::tryPopBack(ElementT & element) template<typename ElementT> size_t LLThreadSafeQueue<ElementT>::size(void) { - std::lock_guard<std::mutex> lock(mLock); + lock_t lock(mLock); return mStorage.size(); } +template<typename ElementT> +void LLThreadSafeQueue<ElementT>::close() +{ + lock_t lock(mLock); + mClosed = true; + lock.unlock(); + // wake up any blocked popBack() calls + mEmptyCond.notify_all(); + // wake up any blocked pushFront() calls + mCapacityCond.notify_all(); +} + +template<typename ElementT> +bool LLThreadSafeQueue<ElementT>::isClosed() +{ + lock_t lock(mLock); + return mClosed && mStorage.size() == 0; +} + +template<typename ElementT> +LLThreadSafeQueue<ElementT>::operator bool() +{ + return ! isClosed(); +} + #endif diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index 76e892212a..aaa6df325c 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -32,7 +32,7 @@ #if LL_WINDOWS # include "llwin32headerslean.h" -#elif LL_LINUX || LL_SOLARIS || LL_DARWIN +#elif LL_LINUX || LL_DARWIN # include <errno.h> # include <sys/time.h> #else @@ -74,7 +74,7 @@ U32 micro_sleep(U64 us, U32 max_yields) ms_sleep((U32)(us / 1000)); return 0; } -#elif LL_LINUX || LL_SOLARIS || LL_DARWIN +#elif LL_LINUX || LL_DARWIN static void _sleep_loop(struct timespec& thiswait) { struct timespec nextwait; @@ -187,7 +187,7 @@ F64 calc_clock_frequency() #endif // LL_WINDOWS -#if LL_LINUX || LL_DARWIN || LL_SOLARIS +#if LL_LINUX || LL_DARWIN // Both Linux and Mac use gettimeofday for accurate time F64 calc_clock_frequency() { diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index ec70213447..010f290b24 100644 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -27,7 +27,7 @@ #ifndef LL_TIMER_H #define LL_TIMER_H -#if LL_LINUX || LL_DARWIN || LL_SOLARIS +#if LL_LINUX || LL_DARWIN #include <sys/time.h> #endif #include <limits.h> diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h index 79ff55b739..0d0cd6f581 100644 --- a/indra/llcommon/lltrace.h +++ b/indra/llcommon/lltrace.h @@ -57,7 +57,7 @@ class StatBase { public: StatBase(const char* name, const char* description); - virtual ~StatBase() LLINSTANCETRACKER_DTOR_NOEXCEPT {} + virtual ~StatBase() {} virtual const char* getUnitLabel() const; const std::string& getName() const { return mName; } diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp index 385d31edd7..b1c23c6fb7 100644 --- a/indra/llcommon/lltraceaccumulators.cpp +++ b/indra/llcommon/lltraceaccumulators.cpp @@ -291,8 +291,8 @@ void EventAccumulator::reset( const EventAccumulator* other ) { mNumSamples = 0; mSum = 0; - mMin = NaN; - mMax = NaN; + mMin = F32(NaN); + mMax = F32(NaN); mMean = NaN; mSumOfSquares = 0; mLastValue = other ? other->mLastValue : NaN; diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h index 6f27b97dff..8eb5338a2a 100644 --- a/indra/llcommon/lltraceaccumulators.h +++ b/indra/llcommon/lltraceaccumulators.h @@ -242,8 +242,8 @@ namespace LLTrace EventAccumulator() : mSum(0), - mMin(NaN), - mMax(NaN), + mMin(F32(NaN)), + mMax(F32(NaN)), mMean(NaN), mSumOfSquares(0), mNumSamples(0), @@ -313,8 +313,8 @@ namespace LLTrace SampleAccumulator() : mSum(0), - mMin(NaN), - mMax(NaN), + mMin(F32(NaN)), + mMax(F32(NaN)), mMean(NaN), mSumOfSquares(0), mLastSampleTimeStamp(0), diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp index 181fc2f058..025dc57044 100644 --- a/indra/llcommon/lltracethreadrecorder.cpp +++ b/indra/llcommon/lltracethreadrecorder.cpp @@ -28,6 +28,7 @@ #include "lltracethreadrecorder.h" #include "llfasttimer.h" #include "lltrace.h" +#include "llstl.h" namespace LLTrace { @@ -64,16 +65,15 @@ void ThreadRecorder::init() activate(&mThreadRecordingBuffers); // initialize time block parent pointers - for (BlockTimerStatHandle::instance_tracker_t::instance_iter it = BlockTimerStatHandle::instance_tracker_t::beginInstances(), end_it = BlockTimerStatHandle::instance_tracker_t::endInstances(); - it != end_it; - ++it) + for (auto& base : BlockTimerStatHandle::instance_snapshot()) { - BlockTimerStatHandle& time_block = static_cast<BlockTimerStatHandle&>(*it); - TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[it->getIndex()]; + // because of indirect derivation from LLInstanceTracker, have to downcast + BlockTimerStatHandle& time_block = static_cast<BlockTimerStatHandle&>(base); + TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[time_block.getIndex()]; tree_node.mBlock = &time_block; tree_node.mParent = &root_time_block; - it->getCurrentAccumulator().mParent = &root_time_block; + time_block.getCurrentAccumulator().mParent = &root_time_block; } mRootTimer = new BlockTimer(root_time_block); diff --git a/indra/llcommon/llunittype.h b/indra/llcommon/llunittype.h index ac8504ca61..81f244e422 100644 --- a/indra/llcommon/llunittype.h +++ b/indra/llcommon/llunittype.h @@ -132,23 +132,34 @@ struct LLUnit return mValue; } - LL_FORCE_INLINE void value(storage_t value) + LL_FORCE_INLINE void value(const storage_t& value) { mValue = value; } template<typename NEW_UNITS> - storage_t valueInUnits() + storage_t valueInUnits() const { return LLUnit<storage_t, NEW_UNITS>(*this).value(); } template<typename NEW_UNITS> - void valueInUnits(storage_t value) + void valueInUnits(const storage_t& value) const { *this = LLUnit<storage_t, NEW_UNITS>(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; @@ -159,60 +170,60 @@ struct LLUnit mValue -= convert(other).mValue; } - LL_FORCE_INLINE void operator *= (storage_t multiplicand) + LL_FORCE_INLINE void operator *= (const storage_t& multiplicand) { mValue *= multiplicand; } - LL_FORCE_INLINE void operator *= (self_t 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 /= (storage_t divisor) + LL_FORCE_INLINE void operator /= (const storage_t& divisor) { mValue /= divisor; } - void operator /= (self_t 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<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator == (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + LL_FORCE_INLINE bool operator == (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const { return mValue == convert(other).value(); } template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator != (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + LL_FORCE_INLINE bool operator != (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const { return mValue != convert(other).value(); } template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator < (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + LL_FORCE_INLINE bool operator < (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const { return mValue < convert(other).value(); } template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator <= (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + LL_FORCE_INLINE bool operator <= (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const { return mValue <= convert(other).value(); } template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator > (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + LL_FORCE_INLINE bool operator > (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const { return mValue > convert(other).value(); } template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator >= (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + LL_FORCE_INLINE bool operator >= (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const { return mValue >= convert(other).value(); } diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp index 9942bc0cf8..22711a83d2 100644 --- a/indra/llcommon/lluri.cpp +++ b/indra/llcommon/lluri.cpp @@ -276,7 +276,7 @@ std::string LLURI::escapePathAndData(const std::string &str) std::string fragment; size_t fragment_pos = str.find('#'); - if (fragment_pos != std::string::npos) + if ((fragment_pos != std::string::npos) && (fragment_pos > delim_pos)) { query = str.substr(path_size, fragment_pos - path_size); fragment = str.substr(fragment_pos); diff --git a/indra/llcommon/lluriparser.cpp b/indra/llcommon/lluriparser.cpp index c275b90120..e4f229dd16 100644 --- a/indra/llcommon/lluriparser.cpp +++ b/indra/llcommon/lluriparser.cpp @@ -29,10 +29,13 @@ #include "linden_common.h" #include "lluriparser.h" +#if LL_DARWIN +#include <signal.h> +#include <setjmp.h> +#endif + LLUriParser::LLUriParser(const std::string& u) : mTmpScheme(false), mNormalizedTmp(false), mRes(0) { - mState.uri = &mUri; - if (u.find("://") == std::string::npos) { mNormalizedUri = "http://"; @@ -51,7 +54,7 @@ LLUriParser::~LLUriParser() S32 LLUriParser::parse() { - mRes = uriParseUriA(&mState, mNormalizedUri.c_str()); + mRes = uriParseSingleUriA(&mUri, mNormalizedUri.c_str(), NULL); return mRes; } @@ -158,31 +161,69 @@ void LLUriParser::extractParts() } } +#if LL_DARWIN +typedef void(*sighandler_t)(int); +jmp_buf return_to_normalize; +void uri_signal_handler(int signal) +{ + // Apparently signal handler throwing an exception doesn't work. + // This is ugly and unsafe due to not unwinding content of uriparser library, + // but unless we have a way to catch this as NSexception, jump appears to be the only option. + longjmp(return_to_normalize, 1 /*setjmp will return this value*/); +} +#endif + 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<char> label_buf(chars_required); - mRes = uriToStringA(&label_buf[0], &mUri, chars_required, NULL); - - if (!mRes) - { - mNormalizedUri = &label_buf[mTmpScheme ? 7 : 0]; - mTmpScheme = false; - } - } - } +#if LL_DARWIN + sighandler_t last_handler; + last_handler = signal(SIGILL, &uri_signal_handler); // illegal instruction + if (setjmp(return_to_normalize)) + { + // Issue: external library crashed via signal + // If you encountered this, please try to figure out what's wrong: + // 1. Verify that library's input is 'sane' + // 2. Check if we have an NSexception to work with (unlikely) + // 3. See if passing same string causes exception to repeat + // + // Crash happens at uriNormalizeSyntaxExA + // Warning!!! This does not properly unwind stack, + // if this can be handled by NSexception, it needs to be remade + llassert(0); + + LL_WARNS() << "Uriparser crashed with SIGILL, while processing: " << mNormalizedUri << LL_ENDL; + signal(SIGILL, last_handler); + return 1; + } +#endif + + mRes = uriNormalizeSyntaxExA(&mUri, URI_NORMALIZE_SCHEME | URI_NORMALIZE_HOST); + +#if LL_DARWIN + signal(SIGILL, last_handler); +#endif + + if (!mRes) + { + S32 chars_required; + mRes = uriToStringCharsRequiredA(&mUri, &chars_required); + + if (!mRes) + { + chars_required++; + std::vector<char> label_buf(chars_required); + mRes = uriToStringA(&label_buf[0], &mUri, chars_required, NULL); + + if (!mRes) + { + mNormalizedUri = &label_buf[mTmpScheme ? 7 : 0]; + mTmpScheme = false; + } + } + } } if(mTmpScheme) diff --git a/indra/llcommon/lluriparser.h b/indra/llcommon/lluriparser.h index cfbf54f3c8..92626b9054 100644 --- a/indra/llcommon/lluriparser.h +++ b/indra/llcommon/lluriparser.h @@ -76,7 +76,6 @@ private: std::string mFragment; std::string mNormalizedUri; - UriParserStateA mState; UriUriA mUri; S32 mRes; diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 8f33d789eb..e3b293e465 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -43,6 +43,7 @@ #include "llstring.h" #include "lltimer.h" #include "llthread.h" +#include "llmutex.h" const LLUUID LLUUID::null; const LLTransactionID LLTransactionID::tnull; @@ -600,9 +601,7 @@ S32 LLUUID::getNodeID(unsigned char *node_id) #define HAVE_NETINET_IN_H #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> -#if LL_SOLARIS -#include <sys/sockio.h> -#elif !LL_DARWIN +#if !LL_DARWIN #include <linux/sockios.h> #endif #endif @@ -738,7 +737,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 dd8660a3c8..fe7482ba29 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -31,6 +31,7 @@ #include <vector> #include "stdtypes.h" #include "llpreprocessor.h" +#include <boost/functional/hash.hpp> class LLMutex; @@ -164,6 +165,25 @@ public: LLAssetID makeAssetID(const LLUUID& session) const; }; +// Generate a hash of an LLUUID object using the boost hash templates. +template <> +struct boost::hash<LLUUID> +{ + typedef LLUUID argument_type; + typedef std::size_t result_type; + result_type operator()(argument_type const& s) const + { + result_type seed(0); + + for (S32 i = 0; i < UUID_BYTES; ++i) + { + boost::hash_combine(seed, s.mData[i]); + } + + return seed; + } +}; + #endif diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h index b1a6f61360..0387e75c65 100644 --- a/indra/llcommon/llworkerthread.h +++ b/indra/llcommon/llworkerthread.h @@ -34,6 +34,7 @@ #include "llqueuedthread.h" #include "llatomic.h" +#include "llmutex.h" #define USE_FRAME_CALLBACK_MANAGER 0 diff --git a/indra/llcommon/lockstatic.h b/indra/llcommon/lockstatic.h new file mode 100644 index 0000000000..96c53c6473 --- /dev/null +++ b/indra/llcommon/lockstatic.h @@ -0,0 +1,73 @@ +/** + * @file lockstatic.h + * @author Nat Goodspeed + * @date 2019-12-03 + * @brief LockStatic class provides mutex-guarded access to the specified + * static data. + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Copyright (c) 2019, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LOCKSTATIC_H) +#define LL_LOCKSTATIC_H + +#include "mutex.h" // std::unique_lock + +namespace llthread +{ + +// Instantiate this template to obtain a pointer to the canonical static +// instance of Static while holding a lock on that instance. Use of +// Static::mMutex presumes that Static declares some suitable mMutex. +template <typename Static> +class LockStatic +{ + typedef std::unique_lock<decltype(Static::mMutex)> lock_t; +public: + LockStatic(): + mData(getStatic()), + mLock(mData->mMutex) + {} + Static* get() const { return mData; } + operator Static*() const { return get(); } + Static* operator->() const { return get(); } + // sometimes we must explicitly unlock... + void unlock() + { + // but once we do, access is no longer permitted + mData = nullptr; + mLock.unlock(); + } +protected: + Static* mData; + lock_t mLock; +private: + Static* getStatic() + { + // Static::mMutex must be function-local static rather than class- + // static. Some of our consumers must function properly (therefore + // lock properly) even when the containing module's static variables + // have not yet been runtime-initialized. A mutex requires + // construction. A static class member might not yet have been + // constructed. + // + // We could store a dumb mutex_t*, notice when it's NULL and allocate a + // heap mutex -- but that's vulnerable to race conditions. And we can't + // defend the dumb pointer with another mutex. + // + // We could store a std::atomic<mutex_t*> -- but a default-constructed + // std::atomic<T> does not contain a valid T, even a default-constructed + // T! Which means std::atomic, too, requires runtime initialization. + // + // But a function-local static is guaranteed to be initialized exactly + // once: the first time control reaches that declaration. + static Static sData; + return &sData; + } +}; + +} // llthread namespace + +#endif /* ! defined(LL_LOCKSTATIC_H) */ diff --git a/indra/llcommon/mutex.h b/indra/llcommon/mutex.h new file mode 100644 index 0000000000..90d0942270 --- /dev/null +++ b/indra/llcommon/mutex.h @@ -0,0 +1,22 @@ +/** + * @file mutex.h + * @author Nat Goodspeed + * @date 2019-12-03 + * @brief Wrap <mutex> in odious boilerplate + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Copyright (c) 2019, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if LL_WINDOWS +#pragma warning (push) +#pragma warning (disable:4265) +#endif +// warning C4265: 'std::_Pad' : class has virtual functions, but destructor is not virtual + +#include <mutex> + +#if LL_WINDOWS +#pragma warning (pop) +#endif diff --git a/indra/llcommon/stdtypes.h b/indra/llcommon/stdtypes.h index 6c9871e76c..887f6ab733 100644 --- a/indra/llcommon/stdtypes.h +++ b/indra/llcommon/stdtypes.h @@ -57,7 +57,7 @@ typedef unsigned __int64 U64; #else typedef long long int S64; typedef long long unsigned int U64; -#if LL_DARWIN || LL_LINUX || LL_SOLARIS +#if LL_DARWIN || LL_LINUX #define S64L(a) (a##LL) #define U64L(a) (a##ULL) #endif diff --git a/indra/llcommon/tests/llcond_test.cpp b/indra/llcommon/tests/llcond_test.cpp new file mode 100644 index 0000000000..478149eacf --- /dev/null +++ b/indra/llcommon/tests/llcond_test.cpp @@ -0,0 +1,67 @@ +/** + * @file llcond_test.cpp + * @author Nat Goodspeed + * @date 2019-07-18 + * @brief Test for llcond. + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Copyright (c) 2019, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "llcond.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "../test/lltut.h" +#include "llcoros.h" + +/***************************************************************************** +* TUT +*****************************************************************************/ +namespace tut +{ + struct llcond_data + { + LLScalarCond<int> cond{0}; + }; + typedef test_group<llcond_data> llcond_group; + typedef llcond_group::object object; + llcond_group llcondgrp("llcond"); + + template<> template<> + void object::test<1>() + { + set_test_name("Immediate gratification"); + cond.set_one(1); + ensure("wait_for_equal() failed", + cond.wait_for_equal(F32Milliseconds(1), 1)); + ensure("wait_for_unequal() should have failed", + ! cond.wait_for_unequal(F32Milliseconds(1), 1)); + } + + template<> template<> + void object::test<2>() + { + set_test_name("Simple two-coroutine test"); + LLCoros::instance().launch( + "test<2>", + [this]() + { + // Lambda immediately entered -- control comes here first. + ensure_equals(cond.get(), 0); + cond.set_all(1); + cond.wait_equal(2); + ensure_equals(cond.get(), 2); + cond.set_all(3); + }); + // Main coroutine is resumed only when the lambda waits. + ensure_equals(cond.get(), 1); + cond.set_all(2); + cond.wait_equal(3); + } +} // namespace tut diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp index 8e1f4c14ac..148c18aabe 100644 --- a/indra/llcommon/tests/llerror_test.cpp +++ b/indra/llcommon/tests/llerror_test.cpp @@ -26,6 +26,7 @@ */ #include <vector> +#include <stdexcept> #include "linden_common.h" @@ -69,21 +70,41 @@ namespace namespace { - static bool fatalWasCalled; - void fatalCall(const std::string&) { fatalWasCalled = true; } + static bool fatalWasCalled = false; + struct FatalWasCalled: public std::runtime_error + { + FatalWasCalled(const std::string& what): std::runtime_error(what) {} + }; + void fatalCall(const std::string& msg) { throw FatalWasCalled(msg); } } +// Because we use LLError::setFatalFunction(fatalCall), any LL_ERRS call we +// issue will throw FatalWasCalled. But we want the test program to continue. +// So instead of writing: +// LL_ERRS("tag") << "some message" << LL_ENDL; +// write: +// CATCH(LL_ERRS("tag"), "some message"); +#define CATCH(logcall, expr) \ + try \ + { \ + logcall << expr << LL_ENDL; \ + } \ + catch (const FatalWasCalled&) \ + { \ + fatalWasCalled = true; \ + } + namespace tut { class TestRecorder : public LLError::Recorder { public: TestRecorder() - { - showTime(false); - } + { + showTime(false); + } virtual ~TestRecorder() - {} + {} virtual void recordMessage(LLError::ELevel level, const std::string& message) @@ -252,7 +273,7 @@ namespace LL_DEBUGS("WriteTag","AnotherTag") << "one" << LL_ENDL; LL_INFOS("WriteTag") << "two" << LL_ENDL; LL_WARNS("WriteTag") << "three" << LL_ENDL; - LL_ERRS("WriteTag") << "four" << LL_ENDL; + CATCH(LL_ERRS("WriteTag"), "four"); } }; @@ -380,7 +401,7 @@ namespace std::string errorReturningLocation() { - LL_ERRS() << "die" << LL_ENDL; int this_line = __LINE__; + int this_line = __LINE__; CATCH(LL_ERRS(), "die"); return locationString(this_line); } } @@ -701,7 +722,7 @@ public: static void doDebug() { LL_DEBUGS() << "add dice" << LL_ENDL; } static void doInfo() { LL_INFOS() << "any idea" << LL_ENDL; } static void doWarn() { LL_WARNS() << "aim west" << LL_ENDL; } - static void doError() { LL_ERRS() << "ate eels" << LL_ENDL; } + static void doError() { CATCH(LL_ERRS(), "ate eels"); } static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } }; @@ -712,7 +733,7 @@ public: static void doDebug() { LL_DEBUGS() << "bed down" << LL_ENDL; } static void doInfo() { LL_INFOS() << "buy iron" << LL_ENDL; } static void doWarn() { LL_WARNS() << "bad word" << LL_ENDL; } - static void doError() { LL_ERRS() << "big easy" << LL_ENDL; } + static void doError() { CATCH(LL_ERRS(), "big easy"); } static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } }; @@ -874,13 +895,10 @@ namespace tut namespace { std::string writeTagWithSpaceReturningLocation() - { - LL_DEBUGS("Write Tag") << "not allowed" << LL_ENDL; int this_line = __LINE__; - - std::ostringstream location; - location << LLError::abbreviateFile(__FILE__).c_str() << "(" << this_line << ")"; - return location.str(); - } + { + int this_line = __LINE__; CATCH(LL_DEBUGS("Write Tag"), "not allowed"); + return locationString(this_line); + } }; namespace tut @@ -894,9 +912,9 @@ namespace tut std::string location = writeTagWithSpaceReturningLocation(); std::string expected = "Space is not allowed in a log tag at " + location; - ensure_message_field_equals(0, LEVEL_FIELD, "ERROR"); - ensure_message_field_equals(0, MSG_FIELD, expected); - ensure("fatal callback called", fatalWasCalled); + ensure_message_field_equals(0, LEVEL_FIELD, "ERROR"); + ensure_message_field_equals(0, MSG_FIELD, expected); + ensure("fatal callback called", fatalWasCalled); } } diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp index a459d17fb8..032923a108 100644 --- a/indra/llcommon/tests/lleventcoro_test.cpp +++ b/indra/llcommon/tests/lleventcoro_test.cpp @@ -26,102 +26,33 @@ * $/LicenseInfo$ */ -/*****************************************************************************/ -// test<1>() is cloned from a Boost.Coroutine example program whose copyright -// info is reproduced here: -/*---------------------------------------------------------------------------*/ -// Copyright (c) 2006, Giovanni P. Deretta -// -// This code may be used under either of the following two licences: -// -// 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. OF SUCH DAMAGE. -// -// Or: -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -/*****************************************************************************/ - #define BOOST_RESULT_OF_USE_TR1 1 -// On some platforms, Boost.Coroutine must #define magic symbols before -// #including platform-API headers. Naturally, that's ineffective unless the -// Boost.Coroutine #include is the *first* #include of the platform header. -// That means that client code must generally #include Boost.Coroutine headers -// before anything else. -#include <boost/dcoroutine/coroutine.hpp> #include <boost/bind.hpp> #include <boost/range.hpp> #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> +#include <boost/make_shared.hpp> #include "linden_common.h" #include <iostream> #include <string> +#include <typeinfo> #include "../test/lltut.h" +#include "../test/lltestapp.h" #include "llsd.h" #include "llsdutil.h" #include "llevents.h" -#include "tests/wrapllerrs.h" -#include "stringize.h" #include "llcoros.h" +#include "lleventfilter.h" #include "lleventcoro.h" #include "../test/debug.h" +#include "../test/sync.h" using namespace llcoro; /***************************************************************************** -* from the banana.cpp example program borrowed for test<1>() -*****************************************************************************/ -namespace coroutines = boost::dcoroutines; -using coroutines::coroutine; - -template<typename Iter> -bool match(Iter first, Iter last, std::string match) { - std::string::iterator i = match.begin(); - for(; (first != last) && (i != match.end()); ++i) { - if (*first != *i) - return false; - ++first; - } - return i == match.end(); -} - -template<typename BidirectionalIterator> -BidirectionalIterator -match_substring(BidirectionalIterator begin, - BidirectionalIterator end, - std::string xmatch, - BOOST_DEDUCED_TYPENAME coroutine<BidirectionalIterator(void)>::self& self) { -//BidirectionalIterator begin_ = begin; - for(; begin != end; ++begin) - if(match(begin, end, xmatch)) { - self.yield(begin); - } - return end; -} - -typedef coroutine<std::string::iterator(void)> match_coroutine_type; - -/***************************************************************************** * Test helpers *****************************************************************************/ /// Simulate an event API whose response is immediate: sent on receipt of the @@ -131,8 +62,9 @@ typedef coroutine<std::string::iterator(void)> match_coroutine_type; class ImmediateAPI { public: - ImmediateAPI(): - mPump("immediate", true) + ImmediateAPI(Sync& sync): + mPump("immediate", true), + mSync(sync) { mPump.listen("API", boost::bind(&ImmediateAPI::operator(), this, _1)); } @@ -141,20 +73,18 @@ public: // Invoke this with an LLSD map containing: // ["value"]: Integer value. We will reply with ["value"] + 1. - // ["reply"]: Name of LLEventPump on which to send success response. - // ["error"]: Name of LLEventPump on which to send error response. - // ["fail"]: Presence of this key selects ["error"], else ["success"] as - // the name of the pump on which to send the response. + // ["reply"]: Name of LLEventPump on which to send response. bool operator()(const LLSD& event) const { + mSync.bump(); LLSD::Integer value(event["value"]); - LLSD::String replyPumpName(event.has("fail")? "error" : "reply"); - LLEventPumps::instance().obtain(event[replyPumpName]).post(value + 1); + LLEventPumps::instance().obtain(event["reply"]).post(value + 1); return false; } private: LLEventStream mPump; + Sync& mSync; }; /***************************************************************************** @@ -162,644 +92,247 @@ private: *****************************************************************************/ namespace tut { - struct coroutine_data {}; - typedef test_group<coroutine_data> coroutine_group; + struct test_data + { + Sync mSync; + ImmediateAPI immediateAPI{mSync}; + std::string replyName, errorName, threw, stringdata; + LLSD result, errordata; + int which; + LLTestApp testApp; + + void explicit_wait(boost::shared_ptr<LLCoros::Promise<std::string>>& cbp); + void waitForEventOn1(); + void coroPump(); + void postAndWait1(); + void coroPumpPost(); + }; + typedef test_group<test_data> coroutine_group; typedef coroutine_group::object object; coroutine_group coroutinegrp("coroutine"); - template<> template<> - void object::test<1>() - { - set_test_name("From banana.cpp example program in Boost.Coroutine distro"); - std::string buffer = "banananana"; - std::string match = "nana"; - std::string::iterator begin = buffer.begin(); - std::string::iterator end = buffer.end(); - -#if defined(BOOST_CORO_POSIX_IMPL) -// std::cout << "Using Boost.Coroutine " << BOOST_CORO_POSIX_IMPL << '\n'; -#else -// std::cout << "Using non-Posix Boost.Coroutine implementation" << std::endl; -#endif - - typedef std::string::iterator signature(std::string::iterator, - std::string::iterator, - std::string, - match_coroutine_type::self&); - - coroutine<std::string::iterator(void)> matcher - (boost::bind(static_cast<signature*>(match_substring), - begin, - end, - match, - _1)); - - std::string::iterator i = matcher(); -/*==========================================================================*| - while(matcher && i != buffer.end()) { - std::cout <<"Match at: "<< std::distance(buffer.begin(), i)<<'\n'; - i = matcher(); - } -|*==========================================================================*/ - size_t matches[] = { 2, 4, 6 }; - for (size_t *mi(boost::begin(matches)), *mend(boost::end(matches)); - mi != mend; ++mi, i = matcher()) - { - ensure("more", matcher); - ensure("found", i != buffer.end()); - ensure_equals("value", std::distance(buffer.begin(), i), *mi); - } - ensure("done", ! matcher); - } - - // use static data so we can intersperse coroutine functions with the - // tests that engage them - ImmediateAPI immediateAPI; - std::string replyName, errorName, threw, stringdata; - LLSD result, errordata; - int which; - - // reinit vars at the start of each test - void clear() - { - replyName.clear(); - errorName.clear(); - threw.clear(); - stringdata.clear(); - result = LLSD(); - errordata = LLSD(); - which = 0; - } - - void explicit_wait(boost::shared_ptr<LLCoros::Future<std::string>::callback_t>& cbp) + void test_data::explicit_wait(boost::shared_ptr<LLCoros::Promise<std::string>>& cbp) { BEGIN { + mSync.bump(); // The point of this test is to verify / illustrate suspending a // coroutine for something other than an LLEventPump. In other // words, this shows how to adapt to any async operation that // provides a callback-style notification (and prove that it // works). - LLCoros::Future<std::string> future; - // get the callback from that future - LLCoros::Future<std::string>::callback_t callback(future.make_callback()); - // Perhaps we would send a request to a remote server and arrange - // for 'callback' to be called on response. Of course that might - // involve an adapter object from the actual callback signature to - // the signature of 'callback' -- in this case, void(std::string). - // For test purposes, instead of handing 'callback' (or the + // for cbp->set_value() to be called on response. + // For test purposes, instead of handing 'callback' (or an // adapter) off to some I/O subsystem, we'll just pass it back to // our caller. - cbp.reset(new LLCoros::Future<std::string>::callback_t(callback)); + cbp = boost::make_shared<LLCoros::Promise<std::string>>(); + LLCoros::Future<std::string> future = LLCoros::getFuture(*cbp); - ensure("Not yet", ! future); // calling get() on the future causes us to suspend debug("about to suspend"); stringdata = future.get(); - ensure("Got it", bool(future)); + mSync.bump(); + ensure_equals("Got it", stringdata, "received"); } END } template<> template<> - void object::test<2>() + void object::test<1>() { - clear(); set_test_name("explicit_wait"); DEBUG; // Construct the coroutine instance that will run explicit_wait. - boost::shared_ptr<LLCoros::Future<std::string>::callback_t> respond; - LLCoros::instance().launch("test<2>", - boost::bind(explicit_wait, boost::ref(respond))); + boost::shared_ptr<LLCoros::Promise<std::string>> respond; + LLCoros::instance().launch("test<1>", + [this, &respond](){ explicit_wait(respond); }); + mSync.bump(); // When the coroutine waits for the future, it returns here. debug("about to respond"); - // Now we're the I/O subsystem delivering a result. This immediately - // transfers control back to the coroutine. - (*respond)("received"); + // Now we're the I/O subsystem delivering a result. This should make + // the coroutine ready. + respond->set_value("received"); + // but give it a chance to wake up + mSync.yield(); // ensure the coroutine ran and woke up again with the intended result ensure_equals(stringdata, "received"); } - void waitForEventOn1() + void test_data::waitForEventOn1() { BEGIN { + mSync.bump(); result = suspendUntilEventOn("source"); + mSync.bump(); } END } template<> template<> - void object::test<3>() + void object::test<2>() { - clear(); set_test_name("waitForEventOn1"); DEBUG; - LLCoros::instance().launch("test<3>", waitForEventOn1); + LLCoros::instance().launch("test<2>", [this](){ waitForEventOn1(); }); + mSync.bump(); debug("about to send"); LLEventPumps::instance().obtain("source").post("received"); + // give waitForEventOn1() a chance to run + mSync.yield(); debug("back from send"); ensure_equals(result.asString(), "received"); } - void waitForEventOn2() - { - BEGIN - { - LLEventWithID pair = suspendUntilEventOn("reply", "error"); - result = pair.first; - which = pair.second; - debug(STRINGIZE("result = " << result << ", which = " << which)); - } - END - } - - template<> template<> - void object::test<4>() - { - clear(); - set_test_name("waitForEventOn2 reply"); - { - DEBUG; - LLCoros::instance().launch("test<4>", waitForEventOn2); - debug("about to send"); - LLEventPumps::instance().obtain("reply").post("received"); - debug("back from send"); - } - ensure_equals(result.asString(), "received"); - ensure_equals("which pump", which, 0); - } - - template<> template<> - void object::test<5>() - { - clear(); - set_test_name("waitForEventOn2 error"); - DEBUG; - LLCoros::instance().launch("test<5>", waitForEventOn2); - debug("about to send"); - LLEventPumps::instance().obtain("error").post("badness"); - debug("back from send"); - ensure_equals(result.asString(), "badness"); - ensure_equals("which pump", which, 1); - } - - void coroPump() + void test_data::coroPump() { BEGIN { + mSync.bump(); LLCoroEventPump waiter; replyName = waiter.getName(); result = waiter.suspend(); + mSync.bump(); } END } template<> template<> - void object::test<6>() + void object::test<3>() { - clear(); set_test_name("coroPump"); DEBUG; - LLCoros::instance().launch("test<6>", coroPump); + LLCoros::instance().launch("test<3>", [this](){ coroPump(); }); + mSync.bump(); debug("about to send"); LLEventPumps::instance().obtain(replyName).post("received"); + // give coroPump() a chance to run + mSync.yield(); debug("back from send"); ensure_equals(result.asString(), "received"); } - void coroPumps() - { - BEGIN - { - LLCoroEventPumps waiter; - replyName = waiter.getName0(); - errorName = waiter.getName1(); - LLEventWithID pair(waiter.suspend()); - result = pair.first; - which = pair.second; - } - END - } - - template<> template<> - void object::test<7>() - { - clear(); - set_test_name("coroPumps reply"); - DEBUG; - LLCoros::instance().launch("test<7>", coroPumps); - debug("about to send"); - LLEventPumps::instance().obtain(replyName).post("received"); - debug("back from send"); - ensure_equals(result.asString(), "received"); - ensure_equals("which pump", which, 0); - } - - template<> template<> - void object::test<8>() - { - clear(); - set_test_name("coroPumps error"); - DEBUG; - LLCoros::instance().launch("test<8>", coroPumps); - debug("about to send"); - LLEventPumps::instance().obtain(errorName).post("badness"); - debug("back from send"); - ensure_equals(result.asString(), "badness"); - ensure_equals("which pump", which, 1); - } - - void coroPumpsNoEx() - { - BEGIN - { - LLCoroEventPumps waiter; - replyName = waiter.getName0(); - errorName = waiter.getName1(); - result = waiter.suspendWithException(); - } - END - } - - template<> template<> - void object::test<9>() - { - clear(); - set_test_name("coroPumpsNoEx"); - DEBUG; - LLCoros::instance().launch("test<9>", coroPumpsNoEx); - debug("about to send"); - LLEventPumps::instance().obtain(replyName).post("received"); - debug("back from send"); - ensure_equals(result.asString(), "received"); - } - - void coroPumpsEx() - { - BEGIN - { - LLCoroEventPumps waiter; - replyName = waiter.getName0(); - errorName = waiter.getName1(); - try - { - result = waiter.suspendWithException(); - debug("no exception"); - } - catch (const LLErrorEvent& e) - { - debug(STRINGIZE("exception " << e.what())); - errordata = e.getData(); - } - } - END - } - - template<> template<> - void object::test<10>() - { - clear(); - set_test_name("coroPumpsEx"); - DEBUG; - LLCoros::instance().launch("test<10>", coroPumpsEx); - debug("about to send"); - LLEventPumps::instance().obtain(errorName).post("badness"); - debug("back from send"); - ensure("no result", result.isUndefined()); - ensure_equals("got error", errordata.asString(), "badness"); - } - - void coroPumpsNoLog() - { - BEGIN - { - LLCoroEventPumps waiter; - replyName = waiter.getName0(); - errorName = waiter.getName1(); - result = waiter.suspendWithLog(); - } - END - } - - template<> template<> - void object::test<11>() - { - clear(); - set_test_name("coroPumpsNoLog"); - DEBUG; - LLCoros::instance().launch("test<11>", coroPumpsNoLog); - debug("about to send"); - LLEventPumps::instance().obtain(replyName).post("received"); - debug("back from send"); - ensure_equals(result.asString(), "received"); - } - - void coroPumpsLog() - { - BEGIN - { - LLCoroEventPumps waiter; - replyName = waiter.getName0(); - errorName = waiter.getName1(); - WrapLLErrs capture; - try - { - result = waiter.suspendWithLog(); - debug("no exception"); - } - catch (const WrapLLErrs::FatalException& e) - { - debug(STRINGIZE("exception " << e.what())); - threw = e.what(); - } - } - END - } - - template<> template<> - void object::test<12>() - { - clear(); - set_test_name("coroPumpsLog"); - DEBUG; - LLCoros::instance().launch("test<12>", coroPumpsLog); - debug("about to send"); - LLEventPumps::instance().obtain(errorName).post("badness"); - debug("back from send"); - ensure("no result", result.isUndefined()); - ensure_contains("got error", threw, "badness"); - } - - void postAndWait1() + void test_data::postAndWait1() { BEGIN { + mSync.bump(); result = postAndSuspend(LLSDMap("value", 17), // request event immediateAPI.getPump(), // requestPump "reply1", // replyPump "reply"); // request["reply"] = name + mSync.bump(); } END } template<> template<> - void object::test<13>() + void object::test<4>() { - clear(); set_test_name("postAndWait1"); DEBUG; - LLCoros::instance().launch("test<13>", postAndWait1); + LLCoros::instance().launch("test<4>", [this](){ postAndWait1(); }); ensure_equals(result.asInteger(), 18); } - void postAndWait2() - { - BEGIN - { - LLEventWithID pair = ::postAndSuspend2(LLSDMap("value", 18), - immediateAPI.getPump(), - "reply2", - "error2", - "reply", - "error"); - result = pair.first; - which = pair.second; - debug(STRINGIZE("result = " << result << ", which = " << which)); - } - END - } - - template<> template<> - void object::test<14>() - { - clear(); - set_test_name("postAndWait2"); - DEBUG; - LLCoros::instance().launch("test<14>", postAndWait2); - ensure_equals(result.asInteger(), 19); - ensure_equals(which, 0); - } - - void postAndWait2_1() - { - BEGIN - { - LLEventWithID pair = ::postAndSuspend2(LLSDMap("value", 18)("fail", LLSD()), - immediateAPI.getPump(), - "reply2", - "error2", - "reply", - "error"); - result = pair.first; - which = pair.second; - debug(STRINGIZE("result = " << result << ", which = " << which)); - } - END - } - - template<> template<> - void object::test<15>() - { - clear(); - set_test_name("postAndWait2_1"); - DEBUG; - LLCoros::instance().launch("test<15>", postAndWait2_1); - ensure_equals(result.asInteger(), 19); - ensure_equals(which, 1); - } - - void coroPumpPost() + void test_data::coroPumpPost() { BEGIN { + mSync.bump(); LLCoroEventPump waiter; result = waiter.postAndSuspend(LLSDMap("value", 17), immediateAPI.getPump(), "reply"); + mSync.bump(); } END } template<> template<> - void object::test<16>() + void object::test<5>() { - clear(); set_test_name("coroPumpPost"); DEBUG; - LLCoros::instance().launch("test<16>", coroPumpPost); + LLCoros::instance().launch("test<5>", [this](){ coroPumpPost(); }); ensure_equals(result.asInteger(), 18); } - void coroPumpsPost() - { - BEGIN - { - LLCoroEventPumps waiter; - LLEventWithID pair(waiter.postAndSuspend(LLSDMap("value", 23), - immediateAPI.getPump(), "reply", "error")); - result = pair.first; - which = pair.second; - } - END - } - - template<> template<> - void object::test<17>() - { - clear(); - set_test_name("coroPumpsPost reply"); - DEBUG; - LLCoros::instance().launch("test<17>", coroPumpsPost); - ensure_equals(result.asInteger(), 24); - ensure_equals("which pump", which, 0); - } - - void coroPumpsPost_1() - { - BEGIN - { - LLCoroEventPumps waiter; - LLEventWithID pair( - waiter.postAndSuspend(LLSDMap("value", 23)("fail", LLSD()), - immediateAPI.getPump(), "reply", "error")); - result = pair.first; - which = pair.second; - } - END - } - - template<> template<> - void object::test<18>() - { - clear(); - set_test_name("coroPumpsPost error"); - DEBUG; - LLCoros::instance().launch("test<18>", coroPumpsPost_1); - ensure_equals(result.asInteger(), 24); - ensure_equals("which pump", which, 1); - } - - void coroPumpsPostNoEx() - { - BEGIN - { - LLCoroEventPumps waiter; - result = waiter.postAndSuspendWithException(LLSDMap("value", 8), - immediateAPI.getPump(), "reply", "error"); - } - END - } - - template<> template<> - void object::test<19>() - { - clear(); - set_test_name("coroPumpsPostNoEx"); - DEBUG; - LLCoros::instance().launch("test<19>", coroPumpsPostNoEx); - ensure_equals(result.asInteger(), 9); - } - - void coroPumpsPostEx() - { - BEGIN + template <class PUMP> + void test() + { + PUMP pump(typeid(PUMP).name()); + bool running{false}; + LLSD data{LLSD::emptyArray()}; + // start things off by posting once before even starting the listener + // coro + LL_DEBUGS() << "test() posting first" << LL_ENDL; + LLSD first{LLSDMap("desc", "first")("value", 0)}; + bool consumed = pump.post(first); + ensure("should not have consumed first", ! consumed); + // now launch the coro + LL_DEBUGS() << "test() launching listener coro" << LL_ENDL; + running = true; + LLCoros::instance().launch( + "listener", + [&pump, &running, &data](){ + // important for this test that we consume posted values + LLCoros::instance().set_consuming(true); + // should immediately retrieve 'first' without waiting + LL_DEBUGS() << "listener coro waiting for first" << LL_ENDL; + data.append(llcoro::suspendUntilEventOnWithTimeout(pump, 0.1, LLSD())); + // Don't use ensure() from within the coro -- ensure() failure + // throws tut::fail, which won't propagate out to the main + // test driver, which will result in an odd failure. + // Wait for 'second' because it's not already pending. + LL_DEBUGS() << "listener coro waiting for second" << LL_ENDL; + data.append(llcoro::suspendUntilEventOnWithTimeout(pump, 0.1, LLSD())); + // and wait for 'third', which should involve no further waiting + LL_DEBUGS() << "listener coro waiting for third" << LL_ENDL; + data.append(llcoro::suspendUntilEventOnWithTimeout(pump, 0.1, LLSD())); + LL_DEBUGS() << "listener coro done" << LL_ENDL; + running = false; + }); + // back from coro at the point where it's waiting for 'second' + LL_DEBUGS() << "test() posting second" << LL_ENDL; + LLSD second{llsd::map("desc", "second", "value", 1)}; + consumed = pump.post(second); + ensure("should have consumed second", consumed); + // This is a key point: even though we've post()ed the value for which + // the coroutine is waiting, it's actually still suspended until we + // pause for some other reason. The coroutine will only pick up one + // value at a time from our 'pump'. It's important to exercise the + // case when we post() two values before it picks up either. + LL_DEBUGS() << "test() posting third" << LL_ENDL; + LLSD third{llsd::map("desc", "third", "value", 2)}; + consumed = pump.post(third); + ensure("should NOT yet have consumed third", ! consumed); + // now just wait for coro to finish -- which it eventually will, given + // that all its suspend calls have short timeouts. + while (running) { - LLCoroEventPumps waiter; - try - { - result = waiter.postAndSuspendWithException( - LLSDMap("value", 9)("fail", LLSD()), - immediateAPI.getPump(), "reply", "error"); - debug("no exception"); - } - catch (const LLErrorEvent& e) - { - debug(STRINGIZE("exception " << e.what())); - errordata = e.getData(); - } + LL_DEBUGS() << "test() waiting for coro done" << LL_ENDL; + llcoro::suspendUntilTimeout(0.1); } - END + // okay, verify expected results + ensure_equals("should have received three values", data, + llsd::array(first, second, third)); + LL_DEBUGS() << "test() done" << LL_ENDL; } template<> template<> - void object::test<20>() - { - clear(); - set_test_name("coroPumpsPostEx"); - DEBUG; - LLCoros::instance().launch("test<20>", coroPumpsPostEx); - ensure("no result", result.isUndefined()); - ensure_equals("got error", errordata.asInteger(), 10); - } - - void coroPumpsPostNoLog() - { - BEGIN - { - LLCoroEventPumps waiter; - result = waiter.postAndSuspendWithLog(LLSDMap("value", 30), - immediateAPI.getPump(), "reply", "error"); - } - END - } - - template<> template<> - void object::test<21>() - { - clear(); - set_test_name("coroPumpsPostNoLog"); - DEBUG; - LLCoros::instance().launch("test<21>", coroPumpsPostNoLog); - ensure_equals(result.asInteger(), 31); - } - - void coroPumpsPostLog() + void object::test<6>() { - BEGIN - { - LLCoroEventPumps waiter; - WrapLLErrs capture; - try - { - result = waiter.postAndSuspendWithLog( - LLSDMap("value", 31)("fail", LLSD()), - immediateAPI.getPump(), "reply", "error"); - debug("no exception"); - } - catch (const WrapLLErrs::FatalException& e) - { - debug(STRINGIZE("exception " << e.what())); - threw = e.what(); - } - } - END + set_test_name("LLEventMailDrop"); + tut::test<LLEventMailDrop>(); } template<> template<> - void object::test<22>() + void object::test<7>() { - clear(); - set_test_name("coroPumpsPostLog"); - DEBUG; - LLCoros::instance().launch("test<22>", coroPumpsPostLog); - ensure("no result", result.isUndefined()); - ensure_contains("got error", threw, "32"); + set_test_name("LLEventLogProxyFor<LLEventMailDrop>"); + tut::test< LLEventLogProxyFor<LLEventMailDrop> >(); } } - -/*==========================================================================*| -#include <boost/context/guarded_stack_allocator.hpp> - -namespace tut -{ - template<> template<> - void object::test<23>() - { - set_test_name("stacksize"); - std::cout << "default_stacksize: " << boost::context::guarded_stack_allocator::default_stacksize() << '\n'; - } -} // namespace tut -|*==========================================================================*/ diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index 5a4df81bf1..9da1ecfd67 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -22,6 +22,8 @@ #include "llsdutil.h" #include "stringize.h" #include "tests/wrapllerrs.h" +#include "../test/catch_and_store_what_in.h" +#include "../test/debug.h" #include <map> #include <string> @@ -45,15 +47,6 @@ using boost::lambda::var; using namespace llsd; /***************************************************************************** -* Output control -*****************************************************************************/ -#ifdef DEBUG_ON -using std::cout; -#else -static std::ostringstream cout; -#endif - -/***************************************************************************** * Example data, functions, classes *****************************************************************************/ // We don't need a whole lot of different arbitrary-params methods, just (no | @@ -154,13 +147,13 @@ struct Vars /*------------- no-args (non-const, const, static) methods -------------*/ void method0() { - cout << "method0()\n"; + debug()("method0()"); i = 17; } void cmethod0() const { - cout << 'c'; + debug()('c', NONL); const_cast<Vars*>(this)->method0(); } @@ -169,13 +162,13 @@ struct Vars /*------------ Callable (non-const, const, static) methods -------------*/ void method1(const LLSD& obj) { - cout << "method1(" << obj << ")\n"; + debug()("method1(", obj, ")"); llsd = obj; } void cmethod1(const LLSD& obj) const { - cout << 'c'; + debug()('c', NONL); const_cast<Vars*>(this)->method1(obj); } @@ -195,12 +188,12 @@ struct Vars else vcp = std::string("'") + cp + "'"; - cout << "methodna(" << b - << ", " << i - << ", " << f - << ", " << d - << ", " << vcp - << ")\n"; + debug()("methodna(", b, + ", ", i, + ", ", f, + ", ", d, + ", ", vcp, + ")"); this->b = b; this->i = i; @@ -217,12 +210,12 @@ struct Vars vbin << std::hex << std::setfill('0') << std::setw(2) << unsigned(byte); } - cout << "methodnb(" << "'" << s << "'" - << ", " << uuid - << ", " << date - << ", '" << uri << "'" - << ", " << vbin.str() - << ")\n"; + debug()("methodnb(", "'", s, "'", + ", ", uuid, + ", ", date, + ", '", uri, "'", + ", ", vbin.str(), + ")"); this->s = s; this->uuid = uuid; @@ -233,18 +226,30 @@ struct Vars void cmethodna(NPARAMSa) const { - cout << 'c'; + debug()('c', NONL); const_cast<Vars*>(this)->methodna(NARGSa); } void cmethodnb(NPARAMSb) const { - cout << 'c'; + debug()('c', NONL); const_cast<Vars*>(this)->methodnb(NARGSb); } static void smethodna(NPARAMSa); static void smethodnb(NPARAMSb); + + static Debug& debug() + { + // Lazily initialize this Debug instance so it can notice if main() + // has forcibly set LOGTEST. If it were simply a static member, it + // would already have examined the environment variable by the time + // main() gets around to checking command-line switches. Since we have + // a global static Vars instance, the same would be true of a plain + // non-static member. + static Debug sDebug("Vars"); + return sDebug; + } }; /*------- Global Vars instance for free functions and static methods -------*/ static Vars g; @@ -252,25 +257,25 @@ static Vars g; /*------------ Static Vars method implementations reference 'g' ------------*/ void Vars::smethod0() { - cout << "smethod0() -> "; + debug()("smethod0() -> ", NONL); g.method0(); } void Vars::smethod1(const LLSD& obj) { - cout << "smethod1(" << obj << ") -> "; + debug()("smethod1(", obj, ") -> ", NONL); g.method1(obj); } void Vars::smethodna(NPARAMSa) { - cout << "smethodna(...) -> "; + debug()("smethodna(...) -> ", NONL); g.methodna(NARGSa); } void Vars::smethodnb(NPARAMSb) { - cout << "smethodnb(...) -> "; + debug()("smethodnb(...) -> ", NONL); g.methodnb(NARGSb); } @@ -283,25 +288,25 @@ void clear() /*------------------- Free functions also reference 'g' --------------------*/ void free0() { - cout << "free0() -> "; + g.debug()("free0() -> ", NONL); g.method0(); } void free1(const LLSD& obj) { - cout << "free1(" << obj << ") -> "; + g.debug()("free1(", obj, ") -> ", NONL); g.method1(obj); } void freena(NPARAMSa) { - cout << "freena(...) -> "; + g.debug()("freena(...) -> ", NONL); g.methodna(NARGSa); } void freenb(NPARAMSb) { - cout << "freenb(...) -> "; + g.debug()("freenb(...) -> ", NONL); g.methodnb(NARGSb); } @@ -312,6 +317,7 @@ namespace tut { struct lleventdispatcher_data { + Debug debug{"test"}; WrapLLErrs redirect; Dispatcher work; Vars v; @@ -430,12 +436,17 @@ namespace tut // Same for freenb() et al. params = LLSDMap("a", LLSDArray("b")("i")("f")("d")("cp")) ("b", LLSDArray("s")("uuid")("date")("uri")("bin")); - cout << "params:\n" << params << "\nparams[\"a\"]:\n" << params["a"] << "\nparams[\"b\"]:\n" << params["b"] << std::endl; + debug("params:\n", + params, "\n" + "params[\"a\"]:\n", + params["a"], "\n" + "params[\"b\"]:\n", + params["b"]); // default LLSD::Binary value std::vector<U8> binary; for (size_t ix = 0, h = 0xaa; ix < 6; ++ix, h += 0x11) { - binary.push_back(h); + binary.push_back((U8)h); } // Full defaults arrays. We actually don't care what the LLUUID or // LLDate values are, as long as they're different from the @@ -447,7 +458,8 @@ namespace tut (LLDate::now()) (LLURI("http://www.ietf.org/rfc/rfc3986.txt")) (binary)); - cout << "dft_array_full:\n" << dft_array_full << std::endl; + debug("dft_array_full:\n", + dft_array_full); // Partial defaults arrays. foreach(LLSD::String a, ab) { @@ -456,7 +468,8 @@ namespace tut llsd_copy_array(dft_array_full[a].beginArray() + partition, dft_array_full[a].endArray()); } - cout << "dft_array_partial:\n" << dft_array_partial << std::endl; + debug("dft_array_partial:\n", + dft_array_partial); foreach(LLSD::String a, ab) { @@ -472,7 +485,10 @@ namespace tut dft_map_partial[a][params[a][ix].asString()] = dft_array_full[a][ix]; } } - cout << "dft_map_full:\n" << dft_map_full << "\ndft_map_partial:\n" << dft_map_partial << '\n'; + debug("dft_map_full:\n", + dft_map_full, "\n" + "dft_map_partial:\n", + dft_map_partial); // (Free function | static method) with (no | arbitrary) params, // map style, no (empty array) defaults @@ -630,16 +646,9 @@ namespace tut void call_exc(const std::string& func, const LLSD& args, const std::string& exc_frag) { - std::string threw; - try - { - work(func, args); - } - catch (const std::runtime_error& e) - { - cout << "*** " << e.what() << '\n'; - threw = e.what(); - } + std::string threw = catch_what<std::runtime_error>([this, &func, &args](){ + work(func, args); + }); ensure_has(threw, exc_frag); } @@ -717,15 +726,9 @@ namespace tut LLSD attempts(LLSDArray(17)(LLSDMap("pi", 3.14)("two", 2))); foreach(LLSD ae, inArray(attempts)) { - std::string threw; - try - { - work.add("freena_err", "freena", freena, ae); - } - catch (const std::exception& e) - { - threw = e.what(); - } + std::string threw = catch_what<std::exception>([this, &ae](){ + work.add("freena_err", "freena", freena, ae); + }); ensure_has(threw, "must be an array"); } } @@ -734,15 +737,9 @@ namespace tut void object::test<2>() { set_test_name("map-style registration with badly-formed defaults"); - std::string threw; - try - { - work.add("freena_err", "freena", freena, LLSDArray("a")("b"), 17); - } - catch (const std::exception& e) - { - threw = e.what(); - } + std::string threw = catch_what<std::exception>([this](){ + work.add("freena_err", "freena", freena, LLSDArray("a")("b"), 17); + }); ensure_has(threw, "must be a map or an array"); } @@ -750,17 +747,11 @@ namespace tut void object::test<3>() { set_test_name("map-style registration with too many array defaults"); - std::string threw; - try - { - work.add("freena_err", "freena", freena, - LLSDArray("a")("b"), - LLSDArray(17)(0.9)("gack")); - } - catch (const std::exception& e) - { - threw = e.what(); - } + std::string threw = catch_what<std::exception>([this](){ + work.add("freena_err", "freena", freena, + LLSDArray("a")("b"), + LLSDArray(17)(0.9)("gack")); + }); ensure_has(threw, "shorter than"); } @@ -768,17 +759,11 @@ namespace tut void object::test<4>() { set_test_name("map-style registration with too many map defaults"); - std::string threw; - try - { - work.add("freena_err", "freena", freena, - LLSDArray("a")("b"), - LLSDMap("b", 17)("foo", 3.14)("bar", "sinister")); - } - catch (const std::exception& e) - { - threw = e.what(); - } + std::string threw = catch_what<std::exception>([this](){ + work.add("freena_err", "freena", freena, + LLSDArray("a")("b"), + LLSDMap("b", 17)("foo", 3.14)("bar", "sinister")); + }); ensure_has(threw, "nonexistent params"); ensure_has(threw, "foo"); ensure_has(threw, "bar"); @@ -948,7 +933,12 @@ namespace tut params[a].endArray()), dft_array_partial[a]); } - cout << "allreq:\n" << allreq << "\nleftreq:\n" << leftreq << "\nrightdft:\n" << rightdft << std::endl; + debug("allreq:\n", + allreq, "\n" + "leftreq:\n", + leftreq, "\n" + "rightdft:\n", + rightdft); // Generate maps containing parameter names not provided by the // dft_map_partial maps. @@ -960,7 +950,8 @@ namespace tut skipreq[a].erase(me.first); } } - cout << "skipreq:\n" << skipreq << std::endl; + debug("skipreq:\n", + skipreq); LLSD groups(LLSDArray // array of groups @@ -1005,7 +996,11 @@ namespace tut LLSD names(grp[0]); LLSD required(grp[1][0]); LLSD optional(grp[1][1]); - cout << "For " << names << ",\n" << "required:\n" << required << "\noptional:\n" << optional << std::endl; + debug("For ", names, ",\n", + "required:\n", + required, "\n" + "optional:\n", + optional); // Loop through 'names' foreach(LLSD nm, inArray(names)) @@ -1039,16 +1034,9 @@ namespace tut // We don't have a comparable helper function for the one-arg // operator() method, and it's not worth building one just for this // case. Write it out. - std::string threw; - try - { - work(LLSDMap("op", "freek")); - } - catch (const std::runtime_error& e) - { - cout << "*** " << e.what() << "\n"; - threw = e.what(); - } + std::string threw = catch_what<std::runtime_error>([this](){ + work(LLSDMap("op", "freek")); + }); ensure_has(threw, "bad"); ensure_has(threw, "op"); ensure_has(threw, "freek"); @@ -1182,7 +1170,7 @@ namespace tut std::vector<U8> binary; for (size_t h(0x01), i(0); i < 5; h+= 0x22, ++i) { - binary.push_back(h); + binary.push_back((U8)h); } LLSD args(LLSDMap("a", LLSDArray(true)(17)(3.14)(123.456)("char*")) ("b", LLSDArray("string") @@ -1200,7 +1188,7 @@ namespace tut } // Adjust expect["a"]["cp"] for special Vars::cp treatment. expect["a"]["cp"] = std::string("'") + expect["a"]["cp"].asString() + "'"; - cout << "expect: " << expect << '\n'; + debug("expect: ", expect); // Use substantially the same logic for args and argsplus LLSD argsarrays(LLSDArray(args)(argsplus)); @@ -1255,7 +1243,8 @@ namespace tut { array_overfull[a].append("bogus"); } - cout << "array_full: " << array_full << "\narray_overfull: " << array_overfull << std::endl; + debug("array_full: ", array_full, "\n" + "array_overfull: ", array_overfull); // We rather hope that LLDate::now() will generate a timestamp // distinct from the one it generated in the constructor, moments ago. ensure_not_equals("Timestamps too close", @@ -1270,7 +1259,8 @@ namespace tut map_overfull[a] = map_full[a]; map_overfull[a]["extra"] = "ignore"; } - cout << "map_full: " << map_full << "\nmap_overfull: " << map_overfull << std::endl; + debug("map_full: ", map_full, "\n" + "map_overfull: ", map_overfull); LLSD expect(map_full); // Twiddle the const char* param. expect["a"]["cp"] = std::string("'") + expect["a"]["cp"].asString() + "'"; @@ -1285,7 +1275,7 @@ namespace tut // so won't bother returning it. Predict that behavior to match the // LLSD values. expect["a"].erase("b"); - cout << "expect: " << expect << std::endl; + debug("expect: ", expect); // For this test, calling functions registered with different sets of // parameter defaults should make NO DIFFERENCE WHATSOEVER. Every call // should pass all params. diff --git a/indra/llcommon/tests/lleventfilter_test.cpp b/indra/llcommon/tests/lleventfilter_test.cpp index eb98b12ef5..fa2cb03e95 100644 --- a/indra/llcommon/tests/lleventfilter_test.cpp +++ b/indra/llcommon/tests/lleventfilter_test.cpp @@ -36,9 +36,12 @@ // other Linden headers #include "../test/lltut.h" #include "stringize.h" +#include "llsdutil.h" #include "listener.h" #include "tests/wrapllerrs.h" +#include <typeinfo> + /***************************************************************************** * Test classes *****************************************************************************/ @@ -350,15 +353,9 @@ namespace tut // Now let the timer expire. filter.forceTimeout(); // Notice the timeout. - std::string threw; - try - { - mainloop.post(17); - } - catch (const WrapLLErrs::FatalException& e) - { - threw = e.what(); - } + std::string threw = capture.catch_llerrs([this](){ + mainloop.post(17); + }); ensure_contains("errorAfter() timeout exception", threw, "timeout"); // Timing out cancels the timer. Verify that. listener0.reset(0); @@ -407,6 +404,78 @@ namespace tut throttle.post(";17"); ensure_equals("17", cat.result, "136;12;17"); // "17" delivered } + + template<class PUMP> + void test() + { + PUMP pump(typeid(PUMP).name()); + LLSD data{LLSD::emptyArray()}; + bool consumed{true}; + // listener that appends to 'data' + // but that also returns the current value of 'consumed' + // Instantiate this separately because we're going to listen() + // multiple times with the same lambda: LLEventMailDrop only replays + // queued events on a new listen() call. + auto lambda = + [&data, &consumed](const LLSD& event)->bool + { + data.append(event); + return consumed; + }; + { + LLTempBoundListener conn = pump.listen("lambda", lambda); + pump.post("first"); + } + // first post() should certainly be received by listener + ensure_equals("first", data, llsd::array("first")); + // the question is, since consumed was true, did it queue the value? + data = LLSD::emptyArray(); + { + // if it queued the value, it would be delivered on subsequent + // listen() call + LLTempBoundListener conn = pump.listen("lambda", lambda); + } + ensure_equals("empty1", data, LLSD::emptyArray()); + data = LLSD::emptyArray(); + // now let's NOT consume the posted data + consumed = false; + { + LLTempBoundListener conn = pump.listen("lambda", lambda); + pump.post("second"); + pump.post("third"); + } + // the two events still arrive + ensure_equals("second,third1", data, llsd::array("second", "third")); + data = LLSD::emptyArray(); + { + // when we reconnect, these should be delivered again + // but this time they should be consumed + consumed = true; + LLTempBoundListener conn = pump.listen("lambda", lambda); + } + // unconsumed events were delivered again + ensure_equals("second,third2", data, llsd::array("second", "third")); + data = LLSD::emptyArray(); + { + // when we reconnect this time, no more unconsumed events + LLTempBoundListener conn = pump.listen("lambda", lambda); + } + ensure_equals("empty2", data, LLSD::emptyArray()); + } + + template<> template<> + void filter_object::test<6>() + { + set_test_name("LLEventMailDrop"); + tut::test<LLEventMailDrop>(); + } + + template<> template<> + void filter_object::test<7>() + { + set_test_name("LLEventLogProxyFor<LLEventMailDrop>"); + tut::test< LLEventLogProxyFor<LLEventMailDrop> >(); + } } // namespace tut /***************************************************************************** diff --git a/indra/llcommon/tests/llexception_test.cpp b/indra/llcommon/tests/llexception_test.cpp index 6bee1943c2..8ddf636cd1 100644 --- a/indra/llcommon/tests/llexception_test.cpp +++ b/indra/llcommon/tests/llexception_test.cpp @@ -305,4 +305,19 @@ namespace tut std::cout << center("int", '=', margin) << std::endl; catch_several(throw_int, "throw_int"); } + + template<> template<> + void object::test<2>() + { + set_test_name("reporting exceptions"); + + try + { + LLTHROW(LLException("badness")); + } + catch (...) + { + LOG_UNHANDLED_EXCEPTION("llexception test<2>()"); + } + } } // namespace tut diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp index c7d4b8a06b..9b89159625 100644 --- a/indra/llcommon/tests/llinstancetracker_test.cpp +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -41,7 +41,6 @@ #include <boost/scoped_ptr.hpp> // other Linden headers #include "../test/lltut.h" -#include "wrapllerrs.h" struct Badness: public std::runtime_error { @@ -112,24 +111,22 @@ namespace tut void object::test<2>() { ensure_equals(Unkeyed::instanceCount(), 0); - Unkeyed* dangling = NULL; + std::weak_ptr<Unkeyed> dangling; { Unkeyed one; ensure_equals(Unkeyed::instanceCount(), 1); - Unkeyed* found = Unkeyed::getInstance(&one); - ensure_equals(found, &one); + std::weak_ptr<Unkeyed> found = one.getWeak(); + ensure(! found.expired()); { boost::scoped_ptr<Unkeyed> two(new Unkeyed); ensure_equals(Unkeyed::instanceCount(), 2); - Unkeyed* found = Unkeyed::getInstance(two.get()); - ensure_equals(found, two.get()); } ensure_equals(Unkeyed::instanceCount(), 1); - // store an unwise pointer to a temp Unkeyed instance - dangling = &one; + // store a weak pointer to a temp Unkeyed instance + dangling = found; } // make that instance vanish // check the now-invalid pointer to the destroyed instance - ensure("getInstance(T*) failed to track destruction", ! Unkeyed::getInstance(dangling)); + ensure("weak_ptr<Unkeyed> failed to track destruction", dangling.expired()); ensure_equals(Unkeyed::instanceCount(), 0); } @@ -142,7 +139,8 @@ namespace tut // reimplement LLInstanceTracker using, say, a hash map instead of a // std::map. We DO insist that every key appear exactly once. typedef std::vector<std::string> StringVector; - StringVector keys(Keyed::beginKeys(), Keyed::endKeys()); + auto snap = Keyed::key_snapshot(); + StringVector keys(snap.begin(), snap.end()); std::sort(keys.begin(), keys.end()); StringVector::const_iterator ki(keys.begin()); ensure_equals(*ki++, "one"); @@ -153,17 +151,15 @@ namespace tut ensure("didn't reach end", ki == keys.end()); // Use a somewhat different approach to order independence with - // beginInstances(): explicitly capture the instances we know in a + // instance_snapshot(): explicitly capture the instances we know in a // set, and delete them as we iterate through. typedef std::set<Keyed*> InstanceSet; InstanceSet instances; instances.insert(&one); instances.insert(&two); instances.insert(&three); - for (Keyed::instance_iter ii(Keyed::beginInstances()), iend(Keyed::endInstances()); - ii != iend; ++ii) + for (auto& ref : Keyed::instance_snapshot()) { - Keyed& ref = *ii; ensure_equals("spurious instance", instances.erase(&ref), 1); } ensure_equals("unreported instance", instances.size(), 0); @@ -180,11 +176,10 @@ namespace tut instances.insert(&two); instances.insert(&three); - for (Unkeyed::instance_iter ii(Unkeyed::beginInstances()), iend(Unkeyed::endInstances()); ii != iend; ++ii) - { - Unkeyed& ref = *ii; - ensure_equals("spurious instance", instances.erase(&ref), 1); - } + for (auto& ref : Unkeyed::instance_snapshot()) + { + ensure_equals("spurious instance", instances.erase(&ref), 1); + } ensure_equals("unreported instance", instances.size(), 0); } @@ -192,64 +187,49 @@ namespace tut template<> template<> void object::test<5>() { - set_test_name("delete Keyed with outstanding instance_iter"); - std::string what; - Keyed* keyed = new Keyed("delete Keyed with outstanding instance_iter"); - { - WrapLLErrs wrapper; - Keyed::instance_iter i(Keyed::beginInstances()); - try - { - delete keyed; - } - catch (const WrapLLErrs::FatalException& e) - { - what = e.what(); - } - } - ensure(! what.empty()); + std::string desc("delete Keyed with outstanding instance_snapshot"); + set_test_name(desc); + Keyed* keyed = new Keyed(desc); + // capture a snapshot but do not yet traverse it + auto snapshot = Keyed::instance_snapshot(); + // delete the one instance + delete keyed; + // traversing the snapshot should reflect the deletion + // avoid ensure_equals() because it requires the ability to stream the + // two values to std::ostream + ensure(snapshot.begin() == snapshot.end()); } template<> template<> void object::test<6>() { - set_test_name("delete Keyed with outstanding key_iter"); - std::string what; - Keyed* keyed = new Keyed("delete Keyed with outstanding key_it"); - { - WrapLLErrs wrapper; - Keyed::key_iter i(Keyed::beginKeys()); - try - { - delete keyed; - } - catch (const WrapLLErrs::FatalException& e) - { - what = e.what(); - } - } - ensure(! what.empty()); + std::string desc("delete Keyed with outstanding key_snapshot"); + set_test_name(desc); + Keyed* keyed = new Keyed(desc); + // capture a snapshot but do not yet traverse it + auto snapshot = Keyed::key_snapshot(); + // delete the one instance + delete keyed; + // traversing the snapshot should reflect the deletion + // avoid ensure_equals() because it requires the ability to stream the + // two values to std::ostream + ensure(snapshot.begin() == snapshot.end()); } template<> template<> void object::test<7>() { - set_test_name("delete Unkeyed with outstanding instance_iter"); + set_test_name("delete Unkeyed with outstanding instance_snapshot"); std::string what; Unkeyed* unkeyed = new Unkeyed; - { - WrapLLErrs wrapper; - Unkeyed::instance_iter i(Unkeyed::beginInstances()); - try - { - delete unkeyed; - } - catch (const WrapLLErrs::FatalException& e) - { - what = e.what(); - } - } - ensure(! what.empty()); + // capture a snapshot but do not yet traverse it + auto snapshot = Unkeyed::instance_snapshot(); + // delete the one instance + delete unkeyed; + // traversing the snapshot should reflect the deletion + // avoid ensure_equals() because it requires the ability to stream the + // two values to std::ostream + ensure(snapshot.begin() == snapshot.end()); } template<> template<> @@ -261,11 +241,9 @@ namespace tut // We can't use the iterator-range InstanceSet constructor because // beginInstances() returns an iterator that dereferences to an // Unkeyed&, not an Unkeyed*. - for (Unkeyed::instance_iter uki(Unkeyed::beginInstances()), - ukend(Unkeyed::endInstances()); - uki != ukend; ++uki) + for (auto& ref : Unkeyed::instance_snapshot()) { - existing.insert(&*uki); + existing.insert(&ref); } try { @@ -288,11 +266,9 @@ namespace tut // instances was also present in the original set. If that's not true, // it's because our new Unkeyed ended up in the updated set despite // its constructor exception. - for (Unkeyed::instance_iter uki(Unkeyed::beginInstances()), - ukend(Unkeyed::endInstances()); - uki != ukend; ++uki) + for (auto& ref : Unkeyed::instance_snapshot()) { - ensure("failed to remove instance", existing.find(&*uki) != existing.end()); + ensure("failed to remove instance", existing.find(&ref) != existing.end()); } } } // namespace tut diff --git a/indra/llcommon/tests/lllazy_test.cpp b/indra/llcommon/tests/lllazy_test.cpp index 32a717f4fc..542306ee22 100644 --- a/indra/llcommon/tests/lllazy_test.cpp +++ b/indra/llcommon/tests/lllazy_test.cpp @@ -38,6 +38,7 @@ #include <boost/lambda/bind.hpp> // other Linden headers #include "../test/lltut.h" +#include "../test/catch_and_store_what_in.h" namespace bll = boost::lambda; @@ -200,15 +201,9 @@ namespace tut void lllazy_object::test<2>() { TestNeedsTesting tnt; - std::string threw; - try - { - tnt.toolate(); - } - catch (const LLLazyCommon::InstanceChange& e) - { - threw = e.what(); - } + std::string threw = catch_what<LLLazyCommon::InstanceChange>([&tnt](){ + tnt.toolate(); + }); ensure_contains("InstanceChange exception", threw, "replace LLLazy instance"); } diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index 45648536c4..9d71e327d8 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -23,7 +23,7 @@ #include "../test/lltut.h" #include "../test/namedtempfile.h" #include "../test/catch_and_store_what_in.h" -#include "wrapllerrs.h" +#include "wrapllerrs.h" // CaptureLog #include "llevents.h" #include "llprocess.h" #include "llstring.h" @@ -49,24 +49,28 @@ const size_t BUFFERED_LENGTH = 1023*1024; // try wrangling just under a megabyte #endif -void waitfor(const std::vector<LLLeap*>& instances, int timeout=60) +// capture std::weak_ptrs to LLLeap instances so we can tell when they expire +typedef std::vector<std::weak_ptr<LLLeap>> LLLeapVector; + +void waitfor(const LLLeapVector& instances, int timeout=60) { int i; for (i = 0; i < timeout; ++i) { // Every iteration, test whether any of the passed LLLeap instances // still exist (are still running). - std::vector<LLLeap*>::const_iterator vli(instances.begin()), vlend(instances.end()); - for ( ; vli != vlend; ++vli) + bool found = false; + for (auto& ptr : instances) { - // getInstance() returns NULL if it's terminated/gone, non-NULL if - // it's still running - if (LLLeap::getInstance(*vli)) + if (! ptr.expired()) + { + found = true; break; + } } // If we made it through all of 'instances' without finding one that's // still running, we're done. - if (vli == vlend) + if (! found) { /*==========================================================================*| std::cout << instances.size() << " LLLeap instances terminated in " @@ -86,8 +90,8 @@ void waitfor(const std::vector<LLLeap*>& instances, int timeout=60) void waitfor(LLLeap* instance, int timeout=60) { - std::vector<LLLeap*> instances; - instances.push_back(instance); + LLLeapVector instances; + instances.push_back(instance->getWeak()); waitfor(instances, timeout); } @@ -218,11 +222,11 @@ namespace tut NamedTempFile script("py", "import time\n" "time.sleep(1)\n"); - std::vector<LLLeap*> instances; + LLLeapVector instances; instances.push_back(LLLeap::create(get_test_name(), - sv(list_of(PYTHON)(script.getName())))); + sv(list_of(PYTHON)(script.getName())))->getWeak()); instances.push_back(LLLeap::create(get_test_name(), - sv(list_of(PYTHON)(script.getName())))); + sv(list_of(PYTHON)(script.getName())))->getWeak()); // In this case we're simply establishing that two LLLeap instances // can coexist without throwing exceptions or bombing in any other // way. Wait for them to terminate. @@ -290,12 +294,9 @@ namespace tut void object::test<6>() { set_test_name("empty plugin vector"); - std::string threw; - try - { - LLLeap::create("empty", StringVec()); - } - CATCH_AND_STORE_WHAT_IN(threw, LLLeap::Error) + std::string threw = catch_what<LLLeap::Error>([](){ + LLLeap::create("empty", StringVec()); + }); ensure_contains("LLLeap::Error", threw, "no plugin"); // try the suppress-exception variant ensure("bad launch returned non-NULL", ! LLLeap::create("empty", StringVec(), false)); @@ -308,12 +309,9 @@ namespace tut // Synthesize bogus executable name std::string BADPYTHON(PYTHON.substr(0, PYTHON.length()-1) + "x"); CaptureLog log; - std::string threw; - try - { - LLLeap::create("bad exe", BADPYTHON); - } - CATCH_AND_STORE_WHAT_IN(threw, LLLeap::Error) + std::string threw = catch_what<LLLeap::Error>([&BADPYTHON](){ + LLLeap::create("bad exe", BADPYTHON); + }); ensure_contains("LLLeap::create() didn't throw", threw, "failed"); log.messageWith("failed"); log.messageWith(BADPYTHON); diff --git a/indra/llcommon/tests/llmainthreadtask_test.cpp b/indra/llcommon/tests/llmainthreadtask_test.cpp new file mode 100644 index 0000000000..69b11ccafb --- /dev/null +++ b/indra/llcommon/tests/llmainthreadtask_test.cpp @@ -0,0 +1,137 @@ +/** + * @file llmainthreadtask_test.cpp + * @author Nat Goodspeed + * @date 2019-12-05 + * @brief Test for llmainthreadtask. + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Copyright (c) 2019, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "llmainthreadtask.h" +// STL headers +// std headers +#include <atomic> +// external library headers +// other Linden headers +#include "../test/lltut.h" +#include "../test/sync.h" +#include "llthread.h" // on_main_thread() +#include "lleventtimer.h" +#include "lockstatic.h" + +/***************************************************************************** +* TUT +*****************************************************************************/ +namespace tut +{ + struct llmainthreadtask_data + { + // 5-second timeout + Sync mSync{F32Milliseconds(5000.0f)}; + + llmainthreadtask_data() + { + // we're not testing the result; this is just to cache the + // initial thread as the main thread. + on_main_thread(); + } + }; + typedef test_group<llmainthreadtask_data> llmainthreadtask_group; + typedef llmainthreadtask_group::object object; + llmainthreadtask_group llmainthreadtaskgrp("llmainthreadtask"); + + template<> template<> + void object::test<1>() + { + set_test_name("inline"); + bool ran = false; + bool result = LLMainThreadTask::dispatch( + [&ran]()->bool{ + ran = true; + return true; + }); + ensure("didn't run lambda", ran); + ensure("didn't return result", result); + } + + struct StaticData + { + std::mutex mMutex; // LockStatic looks for mMutex + bool ran{false}; + }; + typedef llthread::LockStatic<StaticData> LockStatic; + + template<> template<> + void object::test<2>() + { + set_test_name("cross-thread"); + skip("This test is prone to build-time hangs"); + std::atomic_bool result(false); + // wrapping our thread lambda in a packaged_task will catch any + // exceptions it might throw and deliver them via future + std::packaged_task<void()> thread_work( + [this, &result](){ + // unblock test<2>()'s yield_until(1) + mSync.set(1); + // dispatch work to main thread -- should block here + bool on_main( + LLMainThreadTask::dispatch( + []()->bool{ + // have to lock static mutex to set static data + LockStatic()->ran = true; + // indicate whether task was run on the main thread + return on_main_thread(); + })); + // wait for test<2>() to unblock us again + mSync.yield_until(3); + result = on_main; + }); + auto thread_result = thread_work.get_future(); + std::thread thread; + try + { + // run thread_work + thread = std::thread(std::move(thread_work)); + // wait for thread to set(1) + mSync.yield_until(1); + // try to acquire the lock, should block because thread has it + LockStatic lk; + // wake up when dispatch() unlocks the static mutex + ensure("shouldn't have run yet", !lk->ran); + ensure("shouldn't have returned yet", !result); + // unlock so the task can acquire the lock + lk.unlock(); + // run the task -- should unblock thread, which will immediately block + // on mSync + LLEventTimer::updateClass(); + // 'lk', having unlocked, can no longer be used to access; relock with + // a new LockStatic instance + ensure("should now have run", LockStatic()->ran); + ensure("returned too early", !result); + // okay, let thread perform the assignment + mSync.set(3); + } + catch (...) + { + // A test failure exception anywhere in the try block can cause + // the test program to terminate without explanation when + // ~thread() finds that 'thread' is still joinable. We could + // either join() or detach() it -- but since it might be blocked + // waiting for something from the main thread that now can never + // happen, it's safer to detach it. + thread.detach(); + throw; + } + // 'thread' should be all done now + thread.join(); + // deliver any exception thrown by thread_work + thread_result.get(); + ensure("ran changed", LockStatic()->ran); + ensure("didn't run on main thread", result); + } +} // namespace tut diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp index 5c87cdabd9..f0eafa8201 100644 --- a/indra/llcommon/tests/llprocess_test.cpp +++ b/indra/llcommon/tests/llprocess_test.cpp @@ -25,8 +25,6 @@ #include <boost/function.hpp> #include <boost/algorithm/string/find_iterator.hpp> #include <boost/algorithm/string/finder.hpp> -//#include <boost/lambda/lambda.hpp> -//#include <boost/lambda/bind.hpp> // other Linden headers #include "../test/lltut.h" #include "../test/namedtempfile.h" @@ -35,7 +33,7 @@ #include "llsdutil.h" #include "llevents.h" #include "llstring.h" -#include "wrapllerrs.h" +#include "wrapllerrs.h" // CaptureLog #if defined(LL_WINDOWS) #define sleep(secs) _sleep((secs) * 1000) @@ -45,8 +43,7 @@ #include <sys/wait.h> #endif -//namespace lambda = boost::lambda; - std::string apr_strerror_helper(apr_status_t rv) +std::string apr_strerror_helper(apr_status_t rv) { char errbuf[256]; apr_strerror(rv, errbuf, sizeof(errbuf)); @@ -496,14 +493,18 @@ namespace tut } // std::cout << "child done: rv = " << rv << " (" << manager.strerror(rv) << "), why = " << why << ", rc = " << rc << '\n'; aprchk_("apr_proc_wait(wi->child, &wi->rc, &wi->why, APR_NOWAIT)", wi.rv, APR_CHILD_DONE); - ensure_equals_(wi.why, APR_PROC_EXIT); - ensure_equals_(wi.rc, 0); // Beyond merely executing all the above successfully, verify that we // obtained expected output -- and that we duly got control while // waiting, proving the non-blocking nature of these pipes. try { + // Perform these ensure_equals_() within this try/catch so that if + // we don't get expected results, we'll dump whatever we did get + // to help diagnose. + ensure_equals_(wi.why, APR_PROC_EXIT); + ensure_equals_(wi.rc, 0); + unsigned i = 0; ensure("blocking I/O on child pipe (0)", history[i].tries); ensure_equals_(history[i].which, "out"); @@ -960,12 +961,9 @@ namespace tut #define CATCH_IN(THREW, EXCEPTION, CODE) \ do \ { \ - (THREW).clear(); \ - try \ - { \ - CODE; \ - } \ - CATCH_AND_STORE_WHAT_IN(THREW, EXCEPTION) \ + (THREW) = catch_what<EXCEPTION>([&](){ \ + CODE; \ + }); \ ensure("failed to throw " #EXCEPTION ": " #CODE, ! (THREW).empty()); \ } while (0) diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index 6ac974e659..642c1c3879 100644 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -271,10 +271,10 @@ namespace tut LLSD w; mParser->reset(); // reset() call is needed since test code re-uses mParser mParser->parse(stream, w, stream.str().size()); - + try { - ensure_equals(msg.c_str(), w, v); + ensure_equals(msg, w, v); } catch (...) { @@ -432,6 +432,7 @@ namespace tut const char source[] = "it must be a blue moon again"; std::vector<U8> data; + // note, includes terminating '\0' copy(&source[0], &source[sizeof(source)], back_inserter(data)); v = data; @@ -468,28 +469,36 @@ namespace tut checkRoundTrip(msg + " many nested maps", v); } - typedef tut::test_group<TestLLSDSerializeData> TestLLSDSerialzeGroup; - typedef TestLLSDSerialzeGroup::object TestLLSDSerializeObject; - TestLLSDSerialzeGroup gTestLLSDSerializeGroup("llsd serialization"); + typedef tut::test_group<TestLLSDSerializeData> TestLLSDSerializeGroup; + typedef TestLLSDSerializeGroup::object TestLLSDSerializeObject; + TestLLSDSerializeGroup gTestLLSDSerializeGroup("llsd serialization"); template<> template<> void TestLLSDSerializeObject::test<1>() { - mFormatter = new LLSDNotationFormatter(); + mFormatter = new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_PRETTY_BINARY); mParser = new LLSDNotationParser(); - doRoundTripTests("notation serialization"); + doRoundTripTests("pretty binary notation serialization"); } - + template<> template<> void TestLLSDSerializeObject::test<2>() { + mFormatter = new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE); + mParser = new LLSDNotationParser(); + doRoundTripTests("raw binary notation serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<3>() + { mFormatter = new LLSDXMLFormatter(); mParser = new LLSDXMLParser(); doRoundTripTests("xml serialization"); } - + template<> template<> - void TestLLSDSerializeObject::test<3>() + void TestLLSDSerializeObject::test<4>() { mFormatter = new LLSDBinaryFormatter(); mParser = new LLSDBinaryParser(); diff --git a/indra/llcommon/tests/llsingleton_test.cpp b/indra/llcommon/tests/llsingleton_test.cpp index 56886bc73f..15ffe68e67 100644 --- a/indra/llcommon/tests/llsingleton_test.cpp +++ b/indra/llcommon/tests/llsingleton_test.cpp @@ -29,7 +29,8 @@ #include "llsingleton.h" #include "../test/lltut.h" - +#include "wrapllerrs.h" +#include "llsd.h" // Capture execution sequence by appending to log string. std::string sLog; @@ -142,8 +143,6 @@ namespace tut \ (void)CLS::instance(); \ ensure_equals(sLog, #CLS "i" #CLS); \ - LLSingletonBase::cleanupAll(); \ - ensure_equals(sLog, #CLS "i" #CLS "x" #CLS); \ LLSingletonBase::deleteAll(); \ ensure_equals(sLog, #CLS "i" #CLS "x" #CLS "~" #CLS); \ } \ @@ -158,10 +157,8 @@ namespace tut \ (void)CLS::instance(); \ ensure_equals(sLog, #CLS #OTHER "i" #OTHER "i" #CLS); \ - LLSingletonBase::cleanupAll(); \ - ensure_equals(sLog, #CLS #OTHER "i" #OTHER "i" #CLS "x" #CLS "x" #OTHER); \ LLSingletonBase::deleteAll(); \ - ensure_equals(sLog, #CLS #OTHER "i" #OTHER "i" #CLS "x" #CLS "x" #OTHER "~" #CLS "~" #OTHER); \ + ensure_equals(sLog, #CLS #OTHER "i" #OTHER "i" #CLS "x" #CLS "~" #CLS "x" #OTHER "~" #OTHER); \ } \ \ template<> template<> \ @@ -174,10 +171,8 @@ namespace tut \ (void)CLS::instance(); \ ensure_equals(sLog, #CLS "i" #CLS #OTHER "i" #OTHER); \ - LLSingletonBase::cleanupAll(); \ - ensure_equals(sLog, #CLS "i" #CLS #OTHER "i" #OTHER "x" #CLS "x" #OTHER); \ LLSingletonBase::deleteAll(); \ - ensure_equals(sLog, #CLS "i" #CLS #OTHER "i" #OTHER "x" #CLS "x" #OTHER "~" #CLS "~" #OTHER); \ + ensure_equals(sLog, #CLS "i" #CLS #OTHER "i" #OTHER "x" #CLS "~" #CLS "x" #OTHER "~" #OTHER); \ } \ \ template<> template<> \ @@ -190,12 +185,140 @@ namespace tut \ (void)CLS::instance(); \ ensure_equals(sLog, #CLS "i" #CLS #OTHER "i" #OTHER); \ - LLSingletonBase::cleanupAll(); \ - ensure_equals(sLog, #CLS "i" #CLS #OTHER "i" #OTHER "x" #CLS "x" #OTHER); \ LLSingletonBase::deleteAll(); \ - ensure_equals(sLog, #CLS "i" #CLS #OTHER "i" #OTHER "x" #CLS "x" #OTHER "~" #CLS "~" #OTHER); \ + ensure_equals(sLog, #CLS "i" #CLS #OTHER "i" #OTHER "x" #CLS "~" #CLS "x" #OTHER "~" #OTHER); \ } TESTS(A, B, 4, 5, 6, 7) TESTS(B, A, 8, 9, 10, 11) + +#define PARAMSINGLETON(cls) \ + class cls: public LLParamSingleton<cls> \ + { \ + LLSINGLETON(cls, const LLSD::String& str): mDesc(str) {} \ + cls(LLSD::Integer i): mDesc(i) {} \ + \ + public: \ + std::string desc() const { return mDesc.asString(); } \ + \ + private: \ + LLSD mDesc; \ + } + + // Declare two otherwise-identical LLParamSingleton classes so we can + // validly initialize each using two different constructors. If we tried + // to test that with a single LLParamSingleton class within the same test + // program, we'd get 'trying to use deleted LLParamSingleton' errors. + PARAMSINGLETON(PSing1); + PARAMSINGLETON(PSing2); + + template<> template<> + void singleton_object_t::test<12>() + { + set_test_name("LLParamSingleton"); + + WrapLLErrs catcherr; + // query methods + ensure("false positive on instanceExists()", ! PSing1::instanceExists()); + ensure("false positive on wasDeleted()", ! PSing1::wasDeleted()); + // try to reference before initializing + std::string threw = catcherr.catch_llerrs([](){ + (void)PSing1::instance(); + }); + ensure_contains("too-early instance() didn't throw", threw, "Uninitialized"); + // getInstance() behaves the same as instance() + threw = catcherr.catch_llerrs([](){ + (void)PSing1::getInstance(); + }); + ensure_contains("too-early getInstance() didn't throw", threw, "Uninitialized"); + // initialize using LLSD::String constructor + PSing1::initParamSingleton("string"); + ensure_equals(PSing1::instance().desc(), "string"); + ensure("false negative on instanceExists()", PSing1::instanceExists()); + // try to initialize again + threw = catcherr.catch_llerrs([](){ + PSing1::initParamSingleton("again"); + }); + ensure_contains("second ctor(string) didn't throw", threw, "twice"); + // try to initialize using the other constructor -- should be + // well-formed, but illegal at runtime + threw = catcherr.catch_llerrs([](){ + PSing1::initParamSingleton(17); + }); + ensure_contains("other ctor(int) didn't throw", threw, "twice"); + PSing1::deleteSingleton(); + ensure("false negative on wasDeleted()", PSing1::wasDeleted()); + threw = catcherr.catch_llerrs([](){ + (void)PSing1::instance(); + }); + ensure_contains("accessed deleted LLParamSingleton", threw, "deleted"); + } + + template<> template<> + void singleton_object_t::test<13>() + { + set_test_name("LLParamSingleton alternate ctor"); + + WrapLLErrs catcherr; + // We don't have to restate all the tests for PSing1. Only test validly + // using the other constructor. + PSing2::initParamSingleton(17); + ensure_equals(PSing2::instance().desc(), "17"); + // can't do it twice + std::string threw = catcherr.catch_llerrs([](){ + PSing2::initParamSingleton(34); + }); + ensure_contains("second ctor(int) didn't throw", threw, "twice"); + // can't use the other constructor either + threw = catcherr.catch_llerrs([](){ + PSing2::initParamSingleton("string"); + }); + ensure_contains("other ctor(string) didn't throw", threw, "twice"); + } + + class CircularPCtor: public LLParamSingleton<CircularPCtor> + { + LLSINGLETON(CircularPCtor) + { + // never mind indirection, just go straight for the circularity + (void)instance(); + } + }; + + template<> template<> + void singleton_object_t::test<14>() + { + set_test_name("Circular LLParamSingleton constructor"); + WrapLLErrs catcherr; + std::string threw = catcherr.catch_llerrs([](){ + CircularPCtor::initParamSingleton(); + }); + ensure_contains("constructor circularity didn't throw", threw, "constructor"); + } + + class CircularPInit: public LLParamSingleton<CircularPInit> + { + LLSINGLETON_EMPTY_CTOR(CircularPInit); + public: + virtual void initSingleton() + { + // never mind indirection, just go straight for the circularity + CircularPInit *pt = getInstance(); + if (!pt) + { + throw; + } + } + }; + + template<> template<> + void singleton_object_t::test<15>() + { + set_test_name("Circular LLParamSingleton initSingleton()"); + WrapLLErrs catcherr; + std::string threw = catcherr.catch_llerrs([](){ + CircularPInit::initParamSingleton(); + }); + ensure("initSingleton() circularity threw", threw.empty()); + } } diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h index 08fbf19b1c..3779fb41bc 100644 --- a/indra/llcommon/tests/wrapllerrs.h +++ b/indra/llcommon/tests/wrapllerrs.h @@ -37,16 +37,13 @@ #include "llerrorcontrol.h" #include "llexception.h" #include "stringize.h" +#include "../test/catch_and_store_what_in.h" #include <boost/bind.hpp> #include <boost/noncopyable.hpp> #include <boost/shared_ptr.hpp> #include <list> #include <string> -// statically reference the function in test.cpp... it's short, we could -// replicate, but better to reuse -extern void wouldHaveCrashed(const std::string& message); - struct WrapLLErrs { WrapLLErrs(): @@ -58,7 +55,8 @@ struct WrapLLErrs mPriorFatal(LLError::getFatalFunction()) { // Make LL_ERRS call our own operator() method - LLError::setFatalFunction(boost::bind(&WrapLLErrs::operator(), this, _1)); + LLError::setFatalFunction( + [this](const std::string& message){ (*this)(message); }); } ~WrapLLErrs() @@ -81,6 +79,31 @@ struct WrapLLErrs LLTHROW(FatalException(message)); } + /// Convenience wrapper for catch_what<FatalException>() + // + // The implementation makes it clear that this function need not be a + // member; it could easily be a free function. It is a member because it + // makes no sense to attempt to catch FatalException unless there is a + // WrapLLErrs instance in scope. Without a live WrapLLErrs instance, any + // LL_ERRS() reached by code within 'func' would terminate the test + // program instead of throwing FatalException. + // + // We were tempted to introduce a free function, likewise accepting + // arbitrary 'func', that would instantiate WrapLLErrs and then call + // catch_llerrs() on that instance. We decided against it, for this + // reason: on extending a test function containing a single call to that + // free function, a maintainer would most likely make additional calls to + // that free function, instead of switching to an explicit WrapLLErrs + // declaration with several calls to its catch_llerrs() member function. + // Even a construct such as WrapLLErrs().catch_llerrs(...) would make the + // object declaration more visible; it's not unreasonable to expect a + // maintainer to extend that by naming and reusing the WrapLLErrs instance. + template <typename FUNC> + std::string catch_llerrs(FUNC func) + { + return catch_what<FatalException>(func); + } + std::string error; LLError::SettingsStoragePtr mPriorErrorSettings; LLError::FatalFunction mPriorFatal; @@ -173,11 +196,13 @@ public: // with that output. If it turns out that saveAndResetSettings() has // some bad effect, give up and just let the DEBUG level log messages // display. - : boost::noncopyable(), + : boost::noncopyable(), + mFatalFunction(LLError::getFatalFunction()), mOldSettings(LLError::saveAndResetSettings()), - mRecorder(new CaptureLogRecorder()) + mRecorder(new CaptureLogRecorder()) { - LLError::setFatalFunction(wouldHaveCrashed); + // reinstate the FatalFunction we just reset + LLError::setFatalFunction(mFatalFunction); LLError::setDefaultLevel(level); LLError::addRecorder(mRecorder); } @@ -193,17 +218,18 @@ public: /// for the sought string. std::string messageWith(const std::string& search, bool required=true) { - return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->messageWith(search, required); + return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->messageWith(search, required); } std::ostream& streamto(std::ostream& out) const { - return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->streamto(out); + return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->streamto(out); } private: + LLError::FatalFunction mFatalFunction; LLError::SettingsStoragePtr mOldSettings; - LLError::RecorderPtr mRecorder; + LLError::RecorderPtr mRecorder; }; #endif /* ! defined(LL_WRAPLLERRS_H) */ diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt index 9dbc6f447e..6a301ad50d 100644 --- a/indra/llcorehttp/CMakeLists.txt +++ b/indra/llcorehttp/CMakeLists.txt @@ -13,6 +13,7 @@ include(LLAddBuildTest) include(LLMessage) include(LLCommon) include(Tut) +include(bugsplat) include_directories (${CMAKE_CURRENT_SOURCE_DIR}) @@ -101,12 +102,13 @@ target_link_libraries( ) # tests -if (LL_TESTS) +set(LLCOREHTTP_TESTS ON CACHE BOOL + "Build and run llcorehttp integration tests specifically") +if (LL_TESTS AND LLCOREHTTP_TESTS) SET(llcorehttp_TEST_SOURCE_FILES - tests/test_allocator.cpp ) - set(llcorehttp_TEST_HEADER_FILS + set(llcorehttp_TEST_HEADER_FILES tests/test_httpstatus.hpp tests/test_refcounted.hpp tests/test_httpoperation.hpp @@ -149,7 +151,7 @@ if (LL_TESTS) ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llcorehttp_peer.py" ) - + if (DARWIN) # Path inside the app bundle where we'll need to copy libraries set(LL_TEST_DESTINATION_DIR @@ -175,8 +177,8 @@ if (DARWIN) set(copy_dylibs libapr-1.0.dylib libaprutil-1.0.dylib - libexception_handler.dylib libnghttp2*.dylib + liburiparser*.dylib ${EXPAT_COPY} ) @@ -198,6 +200,7 @@ endif (DARWIN) ) set(example_libs + ${LEGACY_STDIO_LIBS} ${LLCOREHTTP_LIBRARIES} ${WINDOWS_LIBRARIES} ${LLMESSAGE_LIBRARIES} @@ -231,5 +234,4 @@ endif (DARWIN) target_link_libraries(http_texture_load ${example_libs}) -endif (LL_TESTS) - +endif (LL_TESTS AND LLCOREHTTP_TESTS) diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index 0f76ff23ea..ba31290c24 100644 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -567,16 +567,9 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) // Use the viewer-based thread-safe API which has a // fast/safe check for proxy enable. Would like to // encapsulate this someway... - if (LLProxy::instanceExists()) - { - // Make sure proxy won't be initialized from here, - // it might conflict with LLStartUp::startLLProxy() - LLProxy::getInstance()->applyProxySettings(mCurlHandle); - } - else - { - LL_WARNS() << "Proxy is not initialized!" << LL_ENDL; - } + // Make sure proxy won't be getInstance() from here, + // it is not thread safe + LLProxy::applyProxySettings(mCurlHandle); } else if (gpolicy.mHttpProxy.size()) @@ -817,6 +810,7 @@ size_t HttpOpRequest::readCallback(void * data, size_t size, size_t nmemb, void const size_t do_size((std::min)(req_size, body_size - op->mCurlBodyPos)); const size_t read_size(op->mReqBody->read(op->mCurlBodyPos, static_cast<char *>(data), do_size)); + // FIXME: singleton's instance() is Thread unsafe! Even if stats accumulators inside are. HTTPStats::instance().recordDataUp(read_size); op->mCurlBodyPos += read_size; return read_size; @@ -1007,11 +1001,20 @@ CURLcode HttpOpRequest::curlSslCtxCallback(CURL *curl, void *sslctx, void *userd { HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata)); - if (op->mCallbackSSLVerify) - { - SSL_CTX * ctx = (SSL_CTX *)sslctx; - // disable any default verification for server certs - SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + if (op->mCallbackSSLVerify) + { + SSL_CTX * ctx = (SSL_CTX *)sslctx; + if (op->mReqOptions && op->mReqOptions->getSSLVerifyPeer()) + { + // verification for ssl certs + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); + } + else + { + // disable any default verification for server certs + // Ex: setting urls (assume non-SL) for parcel media in LLFloaterURLEntry + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + } // set the verification callback. SSL_CTX_set_cert_verify_callback(ctx, sslCertVerifyCallback, userdata); // the calls are void diff --git a/indra/llcorehttp/_httpreplyqueue.cpp b/indra/llcorehttp/_httpreplyqueue.cpp index 2b138f3ad5..229bfdbe07 100644 --- a/indra/llcorehttp/_httpreplyqueue.cpp +++ b/indra/llcorehttp/_httpreplyqueue.cpp @@ -56,7 +56,6 @@ void HttpReplyQueue::addOp(const HttpReplyQueue::opPtr_t &op) mQueue.push_back(op); } - mQueueCV.notify_all(); } diff --git a/indra/llcorehttp/_httpreplyqueue.h b/indra/llcorehttp/_httpreplyqueue.h index 0e39e22dde..33e205c1c9 100644 --- a/indra/llcorehttp/_httpreplyqueue.h +++ b/indra/llcorehttp/_httpreplyqueue.h @@ -30,6 +30,7 @@ #include "_refcounted.h" #include "_mutex.h" +#include "boost/noncopyable.hpp" namespace LLCore @@ -97,7 +98,6 @@ protected: OpContainer mQueue; LLCoreInt::HttpMutex mQueueMutex; - LLCoreInt::HttpConditionVariable mQueueCV; }; // end class HttpReplyQueue diff --git a/indra/llcorehttp/_httprequestqueue.cpp b/indra/llcorehttp/_httprequestqueue.cpp index c6f4ad789f..ad72bdcce6 100644 --- a/indra/llcorehttp/_httprequestqueue.cpp +++ b/indra/llcorehttp/_httprequestqueue.cpp @@ -142,13 +142,19 @@ void HttpRequestQueue::wakeAll() } -void HttpRequestQueue::stopQueue() +bool HttpRequestQueue::stopQueue() { { HttpScopedLock lock(mQueueMutex); - mQueueStopped = true; - wakeAll(); + if (!mQueueStopped) + { + mQueueStopped = true; + wakeAll(); + return true; + } + wakeAll(); + return false; } } diff --git a/indra/llcorehttp/_httprequestqueue.h b/indra/llcorehttp/_httprequestqueue.h index 3c3d134b07..f0296f30e3 100644 --- a/indra/llcorehttp/_httprequestqueue.h +++ b/indra/llcorehttp/_httprequestqueue.h @@ -124,7 +124,7 @@ public: /// them on their way. /// /// Threading: callable by any thread. - void stopQueue(); + bool stopQueue(); protected: static HttpRequestQueue * sInstance; diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp index 0b72b53186..56f52f1b09 100644 --- a/indra/llcorehttp/_httpservice.cpp +++ b/indra/llcorehttp/_httpservice.cpp @@ -87,7 +87,11 @@ HttpService::~HttpService() // is a bit tricky. if (mRequestQueue) { - mRequestQueue->stopQueue(); + if (mRequestQueue->stopQueue()) + { + // Give mRequestQueue a chance to finish + ms_sleep(10); + } } if (mThread) @@ -318,7 +322,7 @@ void HttpService::threadRun(LLCoreInt::HttpThread * thread) { LOG_UNHANDLED_EXCEPTION(""); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { LLMemory::logMemoryInfo(TRUE); diff --git a/indra/llcorehttp/bufferarray.cpp b/indra/llcorehttp/bufferarray.cpp index be534b3ce4..e0b2876a00 100644 --- a/indra/llcorehttp/bufferarray.cpp +++ b/indra/llcorehttp/bufferarray.cpp @@ -147,7 +147,7 @@ size_t BufferArray::append(const void * src, size_t len) { block = Block::alloc(BLOCK_ALLOC_SIZE); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { LLMemory::logMemoryInfo(TRUE); diff --git a/indra/llcorehttp/examples/http_texture_load.cpp b/indra/llcorehttp/examples/http_texture_load.cpp index b91aaf0593..c7376042b3 100644 --- a/indra/llcorehttp/examples/http_texture_load.cpp +++ b/indra/llcorehttp/examples/http_texture_load.cpp @@ -52,7 +52,7 @@ void init_curl(); void term_curl(); -unsigned long ssl_thread_id_callback(void); +void ssl_thread_id_callback(CRYPTO_THREADID*); void ssl_locking_callback(int mode, int type, const char * file, int line); void usage(std::ostream & out); @@ -624,7 +624,7 @@ void init_curl() } CRYPTO_set_locking_callback(ssl_locking_callback); - CRYPTO_set_id_callback(ssl_thread_id_callback); + CRYPTO_THREADID_set_callback(ssl_thread_id_callback); } } @@ -640,12 +640,12 @@ void term_curl() } -unsigned long ssl_thread_id_callback(void) +void ssl_thread_id_callback(CRYPTO_THREADID* pthreadid) { #if defined(WIN32) - return (unsigned long) GetCurrentThread(); + CRYPTO_THREADID_set_pointer(pthreadid, GetCurrentThread()); #else - return (unsigned long) pthread_self(); + CRYPTO_THREADID_set_pointer(pthreadid, pthread_self()); #endif } diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp index 7c93c54cdf..61ba83594e 100644 --- a/indra/llcorehttp/httpcommon.cpp +++ b/indra/llcorehttp/httpcommon.cpp @@ -23,13 +23,6 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -#if LL_WINDOWS -#define SAFE_SSL 1 -#elif LL_DARWIN -#define SAFE_SSL 1 -#else -#define SAFE_SSL 1 -#endif #include "linden_common.h" // Modifies curl/curl.h interfaces #include "httpcommon.h" @@ -38,9 +31,6 @@ #include <curl/curl.h> #include <string> #include <sstream> -#if SAFE_SSL -#include <openssl/crypto.h> -#endif namespace LLCore @@ -280,9 +270,6 @@ namespace LLHttp { namespace { -typedef boost::shared_ptr<LLMutex> LLMutex_ptr; -std::vector<LLMutex_ptr> sSSLMutex; - CURL *getCurlTemplateHandle() { static CURL *curlpTemplateHandle = NULL; @@ -347,33 +334,6 @@ void deallocateEasyCurl(CURL *curlp) } -#if SAFE_SSL -//static -void ssl_locking_callback(int mode, int type, const char *file, int line) -{ - if (type >= sSSLMutex.size()) - { - LL_WARNS() << "Attempt to get unknown MUTEX in SSL Lock." << LL_ENDL; - } - - if (mode & CRYPTO_LOCK) - { - sSSLMutex[type]->lock(); - } - else - { - sSSLMutex[type]->unlock(); - } -} - -//static -unsigned long ssl_thread_id(void) -{ - return LLThread::currentID(); -} -#endif - - } void initialize() @@ -385,27 +345,11 @@ void initialize() check_curl_code(code, CURL_GLOBAL_ALL); -#if SAFE_SSL - S32 mutex_count = CRYPTO_num_locks(); - for (S32 i = 0; i < mutex_count; i++) - { - sSSLMutex.push_back(LLMutex_ptr(new LLMutex())); - } - CRYPTO_set_id_callback(&ssl_thread_id); - CRYPTO_set_locking_callback(&ssl_locking_callback); -#endif - } void cleanup() { -#if SAFE_SSL - CRYPTO_set_id_callback(NULL); - CRYPTO_set_locking_callback(NULL); - sSSLMutex.clear(); -#endif - curl_global_cleanup(); } diff --git a/indra/llcorehttp/httpcommon.h b/indra/llcorehttp/httpcommon.h index e4bd4957f8..18505e0aad 100644 --- a/indra/llcorehttp/httpcommon.h +++ b/indra/llcorehttp/httpcommon.h @@ -193,6 +193,7 @@ #include "boost/shared_ptr.hpp" #include "boost/weak_ptr.hpp" #include "boost/function.hpp" +#include "boost/noncopyable.hpp" #include <string> #include <curl/curl.h> diff --git a/indra/llcorehttp/httpoptions.cpp b/indra/llcorehttp/httpoptions.cpp index df5aa52fa9..c6365e5091 100644 --- a/indra/llcorehttp/httpoptions.cpp +++ b/indra/llcorehttp/httpoptions.cpp @@ -32,6 +32,7 @@ namespace LLCore { + bool HttpOptions::sDefaultVerifyPeer = false; HttpOptions::HttpOptions() : mWantHeaders(false), @@ -43,7 +44,7 @@ HttpOptions::HttpOptions() : mMaxRetryBackoff(HTTP_RETRY_BACKOFF_MAX_DEFAULT), mUseRetryAfter(HTTP_USE_RETRY_AFTER_DEFAULT), mFollowRedirects(true), - mVerifyPeer(false), + mVerifyPeer(sDefaultVerifyPeer), mVerifyHost(false), mDNSCacheTimeout(-1L), mNoBody(false) @@ -122,7 +123,15 @@ void HttpOptions::setHeadersOnly(bool nobody) { mNoBody = nobody; if (mNoBody) + { setWantHeaders(true); + setSSLVerifyPeer(false); + } +} + +void HttpOptions::setDefaultSSLVerifyPeer(bool verify) +{ + sDefaultVerifyPeer = verify; } } // end namespace LLCore diff --git a/indra/llcorehttp/httpoptions.h b/indra/llcorehttp/httpoptions.h index 8a6de61b04..41f71896b0 100644 --- a/indra/llcorehttp/httpoptions.h +++ b/indra/llcorehttp/httpoptions.h @@ -143,7 +143,7 @@ public: /// Instructs the LLCore::HTTPRequest to verify that the exchanged security /// certificate is authentic. - /// Default: false + /// Default: sDefaultVerifyPeer void setSSLVerifyPeer(bool verify); bool getSSLVerifyPeer() const { @@ -177,6 +177,13 @@ public: { return mNoBody; } + + /// Sets default behavior for verifying that the name in the + /// security certificate matches the name of the host contacted. + /// Defaults false if not set, but should be set according to + /// viewer's initialization options and command argunments, see + /// NoVerifySSLCert + static void setDefaultSSLVerifyPeer(bool verify); protected: bool mWantHeaders; @@ -192,6 +199,8 @@ protected: bool mVerifyHost; int mDNSCacheTimeout; bool mNoBody; + + static bool sDefaultVerifyPeer; }; // end class HttpOptions diff --git a/indra/llcorehttp/tests/llcorehttp_test.cpp b/indra/llcorehttp/tests/llcorehttp_test.cpp index a310fc0508..362b2309ee 100755 --- a/indra/llcorehttp/tests/llcorehttp_test.cpp +++ b/indra/llcorehttp/tests/llcorehttp_test.cpp @@ -41,14 +41,19 @@ #include "test_httpstatus.hpp" #include "test_refcounted.hpp" #include "test_httpoperation.hpp" +// As of 2019-06-28, test_httprequest.hpp consistently crashes on Mac Release +// builds for reasons not yet diagnosed. +#if ! (LL_DARWIN && LL_RELEASE) #include "test_httprequest.hpp" +#endif #include "test_httpheaders.hpp" #include "test_httprequestqueue.hpp" +#include "_httpservice.h" #include "llproxy.h" #include "llcleanup.h" -unsigned long ssl_thread_id_callback(void); +void ssl_thread_id_callback(CRYPTO_THREADID*); void ssl_locking_callback(int mode, int type, const char * file, int line); #if 0 // lltut provides main and runner @@ -93,7 +98,7 @@ void init_curl() } CRYPTO_set_locking_callback(ssl_locking_callback); - CRYPTO_set_id_callback(ssl_thread_id_callback); + CRYPTO_THREADID_set_callback(ssl_thread_id_callback); } LLProxy::getInstance(); @@ -113,12 +118,12 @@ void term_curl() } -unsigned long ssl_thread_id_callback(void) +void ssl_thread_id_callback(CRYPTO_THREADID* pthreadid) { #if defined(WIN32) - return (unsigned long) GetCurrentThread(); + CRYPTO_THREADID_set_pointer(pthreadid, GetCurrentThread()); #else - return (unsigned long) pthread_self(); + CRYPTO_THREADID_set_pointer(pthreadid, pthread_self()); #endif } @@ -172,5 +177,3 @@ void stop_thread(LLCore::HttpRequest * req) } } } - - diff --git a/indra/llcorehttp/tests/test_allocator.cpp b/indra/llcorehttp/tests/test_allocator.cpp index ea12dc58eb..597e0d2fc9 100644 --- a/indra/llcorehttp/tests/test_allocator.cpp +++ b/indra/llcorehttp/tests/test_allocator.cpp @@ -43,16 +43,6 @@ #include <boost/thread.hpp> - -#if defined(WIN32) -#define THROW_BAD_ALLOC() _THROW1(std::bad_alloc) -#define THROW_NOTHING() _THROW0() -#else -#define THROW_BAD_ALLOC() throw(std::bad_alloc) -#define THROW_NOTHING() throw() -#endif - - struct BlockHeader { struct Block * next; @@ -152,19 +142,19 @@ std::size_t GetMemTotal() } -void * operator new(std::size_t size) THROW_BAD_ALLOC() +void * operator new(std::size_t size) //throw(std::bad_alloc) { return GetMem( size ); } -void * operator new[](std::size_t size) THROW_BAD_ALLOC() +void * operator new[](std::size_t size) //throw(std::bad_alloc) { return GetMem( size ); } -void operator delete(void * p) THROW_NOTHING() +void operator delete(void * p) throw() { if (p) { @@ -173,7 +163,7 @@ void operator delete(void * p) THROW_NOTHING() } -void operator delete[](void * p) THROW_NOTHING() +void operator delete[](void * p) throw() { if (p) { diff --git a/indra/llcorehttp/tests/test_allocator.h b/indra/llcorehttp/tests/test_allocator.h index 3572bbc5c5..abd88f4c98 100644 --- a/indra/llcorehttp/tests/test_allocator.h +++ b/indra/llcorehttp/tests/test_allocator.h @@ -30,18 +30,13 @@ #include <cstdlib> #include <new> +#error 2019-06-27 Do not use test_allocator.h -- does not respect alignment. + size_t GetMemTotal(); -#if defined(WIN32) -void * operator new(std::size_t size) _THROW1(std::bad_alloc); -void * operator new[](std::size_t size) _THROW1(std::bad_alloc); -void operator delete(void * p) _THROW0(); -void operator delete[](void * p) _THROW0(); -#else -void * operator new(std::size_t size) throw (std::bad_alloc); -void * operator new[](std::size_t size) throw (std::bad_alloc); +void * operator new(std::size_t size); //throw (std::bad_alloc); +void * operator new[](std::size_t size); //throw (std::bad_alloc); void operator delete(void * p) throw (); void operator delete[](void * p) throw (); -#endif #endif // TEST_ALLOCATOR_H diff --git a/indra/llcorehttp/tests/test_bufferarray.hpp b/indra/llcorehttp/tests/test_bufferarray.hpp index 8a2a64d970..cc4ad2a906 100644 --- a/indra/llcorehttp/tests/test_bufferarray.hpp +++ b/indra/llcorehttp/tests/test_bufferarray.hpp @@ -30,8 +30,6 @@ #include <iostream> -#include "test_allocator.h" - using namespace LLCore; @@ -44,7 +42,6 @@ struct BufferArrayTestData { // the test objects inherit from this so the member functions and variables // can be referenced directly inside of the test functions. - size_t mMemTotal; }; typedef test_group<BufferArrayTestData> BufferArrayTestGroupType; @@ -56,13 +53,9 @@ void BufferArrayTestObjectType::test<1>() { set_test_name("BufferArray construction"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference BufferArray * ba = new BufferArray(); ensure("One ref on construction of BufferArray", ba->getRefCount() == 1); - ensure("Memory being used", mMemTotal < GetMemTotal()); ensure("Nothing in BA", 0 == ba->size()); // Try to read @@ -72,9 +65,6 @@ void BufferArrayTestObjectType::test<1>() // release the implicit reference, causing the object to be released ba->release(); - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } template <> template <> @@ -82,9 +72,6 @@ void BufferArrayTestObjectType::test<2>() { set_test_name("BufferArray single write"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference BufferArray * ba = new BufferArray(); @@ -105,9 +92,6 @@ void BufferArrayTestObjectType::test<2>() // release the implicit reference, causing the object to be released ba->release(); - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } @@ -116,9 +100,6 @@ void BufferArrayTestObjectType::test<3>() { set_test_name("BufferArray multiple writes"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference BufferArray * ba = new BufferArray(); @@ -154,9 +135,6 @@ void BufferArrayTestObjectType::test<3>() // release the implicit reference, causing the object to be released ba->release(); - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } template <> template <> @@ -164,9 +142,6 @@ void BufferArrayTestObjectType::test<4>() { set_test_name("BufferArray overwriting"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference BufferArray * ba = new BufferArray(); @@ -208,9 +183,6 @@ void BufferArrayTestObjectType::test<4>() // release the implicit reference, causing the object to be released ba->release(); - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } template <> template <> @@ -218,9 +190,6 @@ void BufferArrayTestObjectType::test<5>() { set_test_name("BufferArray multiple writes - sequential reads"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference BufferArray * ba = new BufferArray(); @@ -255,9 +224,6 @@ void BufferArrayTestObjectType::test<5>() // release the implicit reference, causing the object to be released ba->release(); - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } template <> template <> @@ -265,9 +231,6 @@ void BufferArrayTestObjectType::test<6>() { set_test_name("BufferArray overwrite spanning blocks and appending"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference BufferArray * ba = new BufferArray(); @@ -306,9 +269,6 @@ void BufferArrayTestObjectType::test<6>() // release the implicit reference, causing the object to be released ba->release(); - - // make sure we didn't leak any memory - ensure("All memory released", mMemTotal == GetMemTotal()); } template <> template <> @@ -316,9 +276,6 @@ void BufferArrayTestObjectType::test<7>() { set_test_name("BufferArray overwrite spanning blocks and sequential writes"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference BufferArray * ba = new BufferArray(); @@ -371,9 +328,6 @@ void BufferArrayTestObjectType::test<7>() // release the implicit reference, causing the object to be released ba->release(); - - // make sure we didn't leak any memory - ensure("All memory released", mMemTotal == GetMemTotal()); } template <> template <> @@ -381,9 +335,6 @@ void BufferArrayTestObjectType::test<8>() { set_test_name("BufferArray zero-length appendBufferAlloc"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference BufferArray * ba = new BufferArray(); @@ -421,9 +372,6 @@ void BufferArrayTestObjectType::test<8>() // release the implicit reference, causing the object to be released ba->release(); - - // make sure we didn't leak any memory - ensure("All memory released", mMemTotal == GetMemTotal()); } } // end namespace tut diff --git a/indra/llcorehttp/tests/test_bufferstream.hpp b/indra/llcorehttp/tests/test_bufferstream.hpp index 831c901b9d..2739a6e38e 100644 --- a/indra/llcorehttp/tests/test_bufferstream.hpp +++ b/indra/llcorehttp/tests/test_bufferstream.hpp @@ -30,7 +30,6 @@ #include <iostream> -#include "test_allocator.h" #include "llsd.h" #include "llsdserialize.h" @@ -45,7 +44,6 @@ struct BufferStreamTestData { // the test objects inherit from this so the member functions and variables // can be referenced directly inside of the test functions. - size_t mMemTotal; }; typedef test_group<BufferStreamTestData> BufferStreamTestGroupType; @@ -59,12 +57,8 @@ void BufferStreamTestObjectType::test<1>() { set_test_name("BufferArrayStreamBuf construction with NULL BufferArray"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference BufferArrayStreamBuf * bsb = new BufferArrayStreamBuf(NULL); - ensure("Memory being used", mMemTotal < GetMemTotal()); // Not much will work with a NULL ensure("underflow() on NULL fails", tst_traits_t::eof() == bsb->underflow()); @@ -78,9 +72,6 @@ void BufferStreamTestObjectType::test<1>() // release the implicit reference, causing the object to be released delete bsb; bsb = NULL; - - // make sure we didn't leak any memory - ensure("Allocated memory returned", mMemTotal == GetMemTotal()); } @@ -89,12 +80,8 @@ void BufferStreamTestObjectType::test<2>() { set_test_name("BufferArrayStream construction with NULL BufferArray"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference BufferArrayStream * bas = new BufferArrayStream(NULL); - ensure("Memory being used", mMemTotal < GetMemTotal()); // Not much will work with a NULL here ensure("eof() is false on NULL", ! bas->eof()); @@ -104,9 +91,6 @@ void BufferStreamTestObjectType::test<2>() // release the implicit reference, causing the object to be released delete bas; bas = NULL; - - // make sure we didn't leak any memory - ensure("Allocated memory returned", mMemTotal == GetMemTotal()); } @@ -115,13 +99,9 @@ void BufferStreamTestObjectType::test<3>() { set_test_name("BufferArrayStreamBuf construction with empty BufferArray"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted BufferArray with implicit reference BufferArray * ba = new BufferArray; BufferArrayStreamBuf * bsb = new BufferArrayStreamBuf(ba); - ensure("Memory being used", mMemTotal < GetMemTotal()); // I can release my ref on the BA ba->release(); @@ -130,9 +110,6 @@ void BufferStreamTestObjectType::test<3>() // release the implicit reference, causing the object to be released delete bsb; bsb = NULL; - - // make sure we didn't leak any memory - ensure("Allocated memory returned", mMemTotal == GetMemTotal()); } @@ -141,24 +118,17 @@ void BufferStreamTestObjectType::test<4>() { set_test_name("BufferArrayStream construction with empty BufferArray"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted BufferArray with implicit reference BufferArray * ba = new BufferArray; { // create a new ref counted object with an implicit reference BufferArrayStream bas(ba); - ensure("Memory being used", mMemTotal < GetMemTotal()); } // release the implicit reference, causing the object to be released ba->release(); ba = NULL; - - // make sure we didn't leak any memory - ensure("Allocated memory returned", mMemTotal == GetMemTotal()); } @@ -167,9 +137,6 @@ void BufferStreamTestObjectType::test<5>() { set_test_name("BufferArrayStreamBuf construction with real BufferArray"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted BufferArray with implicit reference BufferArray * ba = new BufferArray; const char * content("This is a string. A fragment."); @@ -178,7 +145,6 @@ void BufferStreamTestObjectType::test<5>() // Creat an adapter for the BufferArray BufferArrayStreamBuf * bsb = new BufferArrayStreamBuf(ba); - ensure("Memory being used", mMemTotal < GetMemTotal()); // I can release my ref on the BA ba->release(); @@ -206,9 +172,6 @@ void BufferStreamTestObjectType::test<5>() // release the implicit reference, causing the object to be released delete bsb; bsb = NULL; - - // make sure we didn't leak any memory - ensure("Allocated memory returned", mMemTotal == GetMemTotal()); } @@ -217,9 +180,6 @@ void BufferStreamTestObjectType::test<6>() { set_test_name("BufferArrayStream construction with real BufferArray"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted BufferArray with implicit reference BufferArray * ba = new BufferArray; //const char * content("This is a string. A fragment."); @@ -229,7 +189,6 @@ void BufferStreamTestObjectType::test<6>() { // Creat an adapter for the BufferArray BufferArrayStream bas(ba); - ensure("Memory being used", mMemTotal < GetMemTotal()); // Basic operations bas << "Hello" << 27 << "."; @@ -243,10 +202,6 @@ void BufferStreamTestObjectType::test<6>() // release the implicit reference, causing the object to be released ba->release(); ba = NULL; - - // make sure we didn't leak any memory - // ensure("Allocated memory returned", mMemTotal == GetMemTotal()); - // static U64 mem = GetMemTotal(); } @@ -255,16 +210,12 @@ void BufferStreamTestObjectType::test<7>() { set_test_name("BufferArrayStream with LLSD serialization"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted BufferArray with implicit reference BufferArray * ba = new BufferArray; { // Creat an adapter for the BufferArray BufferArrayStream bas(ba); - ensure("Memory being used", mMemTotal < GetMemTotal()); // LLSD LLSD llsd = LLSD::emptyMap(); @@ -292,9 +243,6 @@ void BufferStreamTestObjectType::test<7>() // release the implicit reference, causing the object to be released ba->release(); ba = NULL; - - // make sure we didn't leak any memory - // ensure("Allocated memory returned", mMemTotal == GetMemTotal()); } diff --git a/indra/llcorehttp/tests/test_httpheaders.hpp b/indra/llcorehttp/tests/test_httpheaders.hpp index c05f1d9429..6aefb5054b 100644 --- a/indra/llcorehttp/tests/test_httpheaders.hpp +++ b/indra/llcorehttp/tests/test_httpheaders.hpp @@ -30,8 +30,6 @@ #include <iostream> -#include "test_allocator.h" - using namespace LLCoreInt; @@ -43,7 +41,6 @@ struct HttpHeadersTestData { // the test objects inherit from this so the member functions and variables // can be referenced directly inside of the test functions. - size_t mMemTotal; }; typedef test_group<HttpHeadersTestData> HttpHeadersTestGroupType; @@ -55,19 +52,12 @@ void HttpHeadersTestObjectType::test<1>() { set_test_name("HttpHeaders construction"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); - ensure("Memory being used", mMemTotal < GetMemTotal()); ensure("Nothing in headers", 0 == headers->size()); // release the implicit reference, causing the object to be released headers.reset(); - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } template <> template <> @@ -75,9 +65,6 @@ void HttpHeadersTestObjectType::test<2>() { set_test_name("HttpHeaders construction"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); @@ -101,9 +88,6 @@ void HttpHeadersTestObjectType::test<2>() // release the implicit reference, causing the object to be released headers.reset(); - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } template <> template <> @@ -111,9 +95,6 @@ void HttpHeadersTestObjectType::test<3>() { set_test_name("HttpHeaders basic find"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); @@ -151,9 +132,6 @@ void HttpHeadersTestObjectType::test<3>() // release the implicit reference, causing the object to be released headers.reset(); - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } template <> template <> @@ -161,9 +139,6 @@ void HttpHeadersTestObjectType::test<4>() { set_test_name("HttpHeaders normalized header entry"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); @@ -251,9 +226,6 @@ void HttpHeadersTestObjectType::test<4>() // release the implicit reference, causing the object to be released headers.reset(); - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } // Verify forward iterator finds everything as expected @@ -262,9 +234,6 @@ void HttpHeadersTestObjectType::test<5>() { set_test_name("HttpHeaders iterator tests"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); @@ -337,9 +306,6 @@ void HttpHeadersTestObjectType::test<5>() // release the implicit reference, causing the object to be released headers.reset(); - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } // Reverse iterators find everything as expected @@ -348,9 +314,6 @@ void HttpHeadersTestObjectType::test<6>() { set_test_name("HttpHeaders reverse iterator tests"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); @@ -421,9 +384,6 @@ void HttpHeadersTestObjectType::test<6>() // release the implicit reference, causing the object to be released headers.reset(); - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } } // end namespace tut diff --git a/indra/llcorehttp/tests/test_httpoperation.hpp b/indra/llcorehttp/tests/test_httpoperation.hpp index e7df2337de..c6407e8d04 100644 --- a/indra/llcorehttp/tests/test_httpoperation.hpp +++ b/indra/llcorehttp/tests/test_httpoperation.hpp @@ -31,8 +31,6 @@ #include <iostream> -#include "test_allocator.h" - using namespace LLCoreInt; @@ -60,7 +58,6 @@ namespace tut { // the test objects inherit from this so the member functions and variables // can be referenced directly inside of the test functions. - size_t mMemTotal; }; typedef test_group<HttpOperationTestData> HttpOperationTestGroupType; @@ -72,19 +69,12 @@ namespace tut { set_test_name("HttpOpNull construction"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference HttpOperation::ptr_t op (new HttpOpNull()); ensure(op.use_count() == 1); - ensure(mMemTotal < GetMemTotal()); - - // release the implicit reference, causing the object to be released - op.reset(); - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); + // release the implicit reference, causing the object to be released + op.reset(); } template <> template <> @@ -92,9 +82,6 @@ namespace tut { set_test_name("HttpOpNull construction with handlers"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // Get some handlers LLCore::HttpHandler::ptr_t h1 (new TestHandler()); @@ -109,13 +96,10 @@ namespace tut // release the reference, releasing the operation but // not the handlers. - op.reset(); - ensure(mMemTotal != GetMemTotal()); - - // release the handlers - h1.reset(); + op.reset(); - ensure(mMemTotal == GetMemTotal()); + // release the handlers + h1.reset(); } } diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp index e65588e48f..3cdd17919d 100644 --- a/indra/llcorehttp/tests/test_httprequest.hpp +++ b/indra/llcorehttp/tests/test_httprequest.hpp @@ -39,7 +39,6 @@ #include <boost/regex.hpp> #include <sstream> -#include "test_allocator.h" #include "llcorehttp_test.h" @@ -75,7 +74,6 @@ struct HttpRequestTestData { // the test objects inherit from this so the member functions and variables // can be referenced directly inside of the test functions. - size_t mMemTotal; int mHandlerCalls; HttpStatus mStatus; }; @@ -196,27 +194,19 @@ void HttpRequestTestObjectType::test<1>() HttpRequest * req = NULL; - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - try { // Get singletons created HttpRequest::createService(); - + // create a new ref counted object with an implicit reference req = new HttpRequest(); - ensure("Memory being used", mMemTotal < GetMemTotal()); - + // release the request object delete req; req = NULL; HttpRequest::destroyService(); - - // make sure we didn't leak any memory - // nat 2017-08-15 don't: requires total stasis in every other subsystem -// ensure("Memory returned", mMemTotal == GetMemTotal()); } catch (...) { @@ -235,9 +225,6 @@ void HttpRequestTestObjectType::test<2>() HttpRequest * req = NULL; - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - try { // Get singletons created @@ -245,7 +232,6 @@ void HttpRequestTestObjectType::test<2>() // create a new ref counted object with an implicit reference req = new HttpRequest(); - ensure("Memory being used", mMemTotal < GetMemTotal()); // Issue a NoOp HttpHandle handle = req->requestNoOp(LLCore::HttpHandler::ptr_t()); @@ -255,17 +241,11 @@ void HttpRequestTestObjectType::test<2>() delete req; req = NULL; - // We're still holding onto the operation which is - // sitting, unserviced, on the request queue so... - ensure("Memory being used 2", mMemTotal < GetMemTotal()); - // Request queue should have two references: global singleton & service object ensure("Two references to request queue", 2 == HttpRequestQueue::instanceOf()->getRefCount()); // Okay, tear it down HttpRequest::destroyService(); - // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); - ensure("Memory returned", mMemTotal == GetMemTotal()); } catch (...) { @@ -293,9 +273,6 @@ void HttpRequestTestObjectType::test<3>() // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -311,7 +288,6 @@ void HttpRequestTestObjectType::test<3>() // create a new ref counted object with an implicit reference req = new HttpRequest(); - ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a NoOp HttpHandle handle = req->requestNoOp(handlerp); @@ -360,8 +336,6 @@ void HttpRequestTestObjectType::test<3>() HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); - // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); - ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); } catch (...) { @@ -386,9 +360,6 @@ void HttpRequestTestObjectType::test<4>() LLCore::HttpHandler::ptr_t handler1p(&handler1, NoOpDeletor); LLCore::HttpHandler::ptr_t handler2p(&handler2, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req1 = NULL; @@ -407,7 +378,6 @@ void HttpRequestTestObjectType::test<4>() // create a new ref counted object with an implicit reference req1 = new HttpRequest(); req2 = new HttpRequest(); - ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue some NoOps HttpHandle handle = req1->requestNoOp(handler1p); @@ -466,8 +436,6 @@ void HttpRequestTestObjectType::test<4>() HttpRequest::destroyService(); ensure("Two handler calls on the way out", 3 == mHandlerCalls); - // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); - ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); } catch (...) { @@ -491,9 +459,6 @@ void HttpRequestTestObjectType::test<5>() // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -509,7 +474,6 @@ void HttpRequestTestObjectType::test<5>() // create a new ref counted object with an implicit reference req = new HttpRequest(); - ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a Spin HttpHandle handle = req->requestSpin(1); @@ -535,15 +499,6 @@ void HttpRequestTestObjectType::test<5>() // Shut down service HttpRequest::destroyService(); - - // Check memory usage - // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); - ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); - // This memory test should work but could give problems as it - // relies on the worker thread picking up a friendly request - // to shutdown. Doing so, it drops references to things and - // we should go back to where we started. If it gives you - // problems, look into the code before commenting things out. } catch (...) { @@ -566,9 +521,6 @@ void HttpRequestTestObjectType::test<6>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -586,7 +538,6 @@ void HttpRequestTestObjectType::test<6>() // create a new ref counted object with an implicit reference req = new HttpRequest(); - ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a Spin HttpHandle handle = req->requestSpin(0); // Hard spin @@ -612,13 +563,6 @@ void HttpRequestTestObjectType::test<6>() // Shut down service HttpRequest::destroyService(); - - // Check memory usage - // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); - // ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); - // This memory test won't work because we're killing the thread - // hard with the hard spinner. There's no opportunity to join - // nicely so many things leak or get destroyed unilaterally. } catch (...) { @@ -643,9 +587,6 @@ void HttpRequestTestObjectType::test<7>() TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -662,7 +603,6 @@ void HttpRequestTestObjectType::test<7>() // create a new ref counted object with an implicit reference req = new HttpRequest(); - ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); opts = HttpOptions::ptr_t(new HttpOptions()); opts->setRetries(1); // Don't try for too long - default retries take about 18S @@ -726,14 +666,6 @@ void HttpRequestTestObjectType::test<7>() HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); - -#if 0 // defined(WIN32) - // Can't do this on any platform anymore, the LL logging system holds - // on to memory and produces what looks like memory leaks... - - // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); - ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); -#endif } catch (...) { @@ -761,9 +693,6 @@ void HttpRequestTestObjectType::test<8>() // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -779,7 +708,6 @@ void HttpRequestTestObjectType::test<8>() // create a new ref counted object with an implicit reference req = new HttpRequest(); - ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a GET that *can* connect mStatus = HttpStatus(200); @@ -835,15 +763,6 @@ void HttpRequestTestObjectType::test<8>() HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); - -#if 0 // defined(WIN32) - // Can only do this memory test on Windows. On other platforms, - // the LL logging system holds on to memory and produces what looks - // like memory leaks... - - // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); - ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); -#endif } catch (...) { @@ -870,9 +789,6 @@ void HttpRequestTestObjectType::test<9>() // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -888,7 +804,6 @@ void HttpRequestTestObjectType::test<9>() // create a new ref counted object with an implicit reference req = new HttpRequest(); - ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a GET that *can* connect mStatus = HttpStatus(200); @@ -946,15 +861,6 @@ void HttpRequestTestObjectType::test<9>() HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); - -#if 0 // defined(WIN32) - // Can only do this memory test on Windows. On other platforms, - // the LL logging system holds on to memory and produces what looks - // like memory leaks... - - // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); - ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); -#endif } catch (...) { @@ -981,9 +887,6 @@ void HttpRequestTestObjectType::test<10>() // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -1000,7 +903,6 @@ void HttpRequestTestObjectType::test<10>() // create a new ref counted object with an implicit reference req = new HttpRequest(); - ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a GET that *can* connect static const char * body_text("Now is the time for all good men..."); @@ -1063,14 +965,6 @@ void HttpRequestTestObjectType::test<10>() HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); - -#if 0 // defined(WIN32) - // Can't do this on any platform anymore, the LL logging system holds - // on to memory and produces what looks like memory leaks... - - // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); - ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); -#endif } catch (...) { @@ -1100,9 +994,6 @@ void HttpRequestTestObjectType::test<11>() // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -1119,7 +1010,6 @@ void HttpRequestTestObjectType::test<11>() // create a new ref counted object with an implicit reference req = new HttpRequest(); - ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a GET that *can* connect static const char * body_text("Now is the time for all good men..."); @@ -1182,15 +1072,6 @@ void HttpRequestTestObjectType::test<11>() HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); - -#if 0 // defined(WIN32) - // Can only do this memory test on Windows. On other platforms, - // the LL logging system holds on to memory and produces what looks - // like memory leaks... - - // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); - ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); -#endif } catch (...) { @@ -1220,9 +1101,6 @@ void HttpRequestTestObjectType::test<12>() // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -1241,7 +1119,6 @@ void HttpRequestTestObjectType::test<12>() // create a new ref counted object with an implicit reference req = new HttpRequest(); - ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a GET that *can* connect mStatus = HttpStatus(200); @@ -1299,14 +1176,6 @@ void HttpRequestTestObjectType::test<12>() HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); - -#if 0 // defined(WIN32) - // Can't do this on any platform anymore, the LL logging system holds - // on to memory and produces what looks like memory leaks... - - // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); - ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); -#endif } catch (...) { @@ -1338,9 +1207,6 @@ void HttpRequestTestObjectType::test<13>() TestHandler2 handler(this, "handler"); handler.mHeadersRequired.reserve(20); // Avoid memory leak test failure LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -1360,7 +1226,6 @@ void HttpRequestTestObjectType::test<13>() // create a new ref counted object with an implicit reference req = new HttpRequest(); - ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); opts = HttpOptions::ptr_t(new HttpOptions()); opts->setWantHeaders(true); @@ -1428,15 +1293,6 @@ void HttpRequestTestObjectType::test<13>() HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); - -#if 0 // defined(WIN32) - // Can only do this memory test on Windows. On other platforms, - // the LL logging system holds on to memory and produces what looks - // like memory leaks... - - // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); - ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); -#endif } catch (...) { @@ -1462,9 +1318,6 @@ void HttpRequestTestObjectType::test<14>() TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); std::string url_base(get_base_url() + "/sleep/"); // path to a 30-second sleep - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -1481,7 +1334,6 @@ void HttpRequestTestObjectType::test<14>() // create a new ref counted object with an implicit reference req = new HttpRequest(); - ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); opts = HttpOptions::ptr_t(new HttpOptions); opts->setRetries(0); // Don't retry @@ -1546,14 +1398,6 @@ void HttpRequestTestObjectType::test<14>() HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); - -#if 0 // defined(WIN32) - // Can't do this on any platform anymore, the LL logging system holds - // on to memory and produces what looks like memory leaks... - - // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); - ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); -#endif } catch (...) { @@ -1586,9 +1430,6 @@ void HttpRequestTestObjectType::test<15>() // for memory return tests. handler.mCheckContentType = "application/llsd+xml"; handler.mCheckContentType.clear(); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -1604,7 +1445,6 @@ void HttpRequestTestObjectType::test<15>() // create a new ref counted object with an implicit reference req = new HttpRequest(); - ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a GET that *can* connect mStatus = HttpStatus(200); @@ -1662,15 +1502,6 @@ void HttpRequestTestObjectType::test<15>() HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); - -#if 0 // defined(WIN32) - // Can only do this memory test on Windows. On other platforms, - // the LL logging system holds on to memory and produces what looks - // like memory leaks... - - // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); - ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); -#endif } catch (...) { @@ -1701,9 +1532,6 @@ void HttpRequestTestObjectType::test<16>() // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -1943,9 +1771,6 @@ void HttpRequestTestObjectType::test<17>() // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -2131,9 +1956,6 @@ void HttpRequestTestObjectType::test<18>() // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -2320,9 +2142,6 @@ void HttpRequestTestObjectType::test<19>() // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -2503,9 +2322,6 @@ void HttpRequestTestObjectType::test<20>() // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -2711,9 +2527,6 @@ void HttpRequestTestObjectType::test<21>() // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -2915,9 +2728,6 @@ void HttpRequestTestObjectType::test<22>() // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpOptions::ptr_t options; @@ -2939,7 +2749,6 @@ void HttpRequestTestObjectType::test<22>() // create a new ref counted object with an implicit reference req = new HttpRequest(); - ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // ====================================== // Issue bug2295 GETs that will get a 206 @@ -3073,14 +2882,6 @@ void HttpRequestTestObjectType::test<22>() // Shut down service HttpRequest::destroyService(); - -#if 0 // defined(WIN32) - // Can't do this on any platform anymore, the LL logging system holds - // on to memory and produces what looks like memory leaks... - - // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); - ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); -#endif } catch (...) { @@ -3117,9 +2918,6 @@ void HttpRequestTestObjectType::test<23>() TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); std::string url_base(get_base_url() + "/503/"); // path to 503 generators - - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; @@ -3136,7 +2934,6 @@ void HttpRequestTestObjectType::test<23>() // create a new ref counted object with an implicit reference req = new HttpRequest(); - ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); opts = HttpOptions::ptr_t(new HttpOptions()); opts->setRetries(1); // Retry once only @@ -3210,14 +3007,6 @@ void HttpRequestTestObjectType::test<23>() // Shut down service HttpRequest::destroyService(); - -#if 0 // defined(WIN32) - // Can't do this on any platform anymore, the LL logging system holds - // on to memory and produces what looks like memory leaks... - - // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); - ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); -#endif } catch (...) { diff --git a/indra/llcorehttp/tests/test_httprequestqueue.hpp b/indra/llcorehttp/tests/test_httprequestqueue.hpp index ef4ce0479b..dba9e0b250 100644 --- a/indra/llcorehttp/tests/test_httprequestqueue.hpp +++ b/indra/llcorehttp/tests/test_httprequestqueue.hpp @@ -30,7 +30,6 @@ #include <iostream> -#include "test_allocator.h" #include "_httpoperation.h" @@ -45,7 +44,6 @@ struct HttpRequestqueueTestData { // the test objects inherit from this so the member functions and variables // can be referenced directly inside of the test functions. - size_t mMemTotal; }; typedef test_group<HttpRequestqueueTestData> HttpRequestqueueTestGroupType; @@ -57,20 +55,13 @@ void HttpRequestqueueTestObjectType::test<1>() { set_test_name("HttpRequestQueue construction"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference HttpRequestQueue::init(); ensure("One ref on construction of HttpRequestQueue", HttpRequestQueue::instanceOf()->getRefCount() == 1); - ensure("Memory being used", mMemTotal < GetMemTotal()); // release the implicit reference, causing the object to be released HttpRequestQueue::term(); - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } template <> template <> @@ -78,9 +69,6 @@ void HttpRequestqueueTestObjectType::test<2>() { set_test_name("HttpRequestQueue refcount works"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference HttpRequestQueue::init(); @@ -91,13 +79,9 @@ void HttpRequestqueueTestObjectType::test<2>() HttpRequestQueue::term(); ensure("One ref after term() called", rq->getRefCount() == 1); - ensure("Memory being used", mMemTotal < GetMemTotal()); // Drop ref rq->release(); - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } template <> template <> @@ -105,9 +89,6 @@ void HttpRequestqueueTestObjectType::test<3>() { set_test_name("HttpRequestQueue addOp/fetchOp work"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference HttpRequestQueue::init(); @@ -126,9 +107,6 @@ void HttpRequestqueueTestObjectType::test<3>() // release the singleton, hold on to the object HttpRequestQueue::term(); - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } template <> template <> @@ -136,9 +114,6 @@ void HttpRequestqueueTestObjectType::test<4>() { set_test_name("HttpRequestQueue addOp/fetchAll work"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference HttpRequestQueue::init(); @@ -164,9 +139,6 @@ void HttpRequestqueueTestObjectType::test<4>() // release the singleton, hold on to the object HttpRequestQueue::term(); - - // We're still holding onto the ops. - ensure(mMemTotal < GetMemTotal()); // Release them ops.clear(); @@ -177,9 +149,6 @@ void HttpRequestqueueTestObjectType::test<4>() // op->release(); // } } - - // Should be clean - ensure("All memory returned", mMemTotal == GetMemTotal()); } } // end namespace tut diff --git a/indra/llcorehttp/tests/test_refcounted.hpp b/indra/llcorehttp/tests/test_refcounted.hpp index 5dff143e5d..2310812d5a 100644 --- a/indra/llcorehttp/tests/test_refcounted.hpp +++ b/indra/llcorehttp/tests/test_refcounted.hpp @@ -28,9 +28,8 @@ #include "_refcounted.h" -#include "test_allocator.h" - -#if 0 // disable all of this because it's hanging win64 builds? +// disable all of this because it's hanging win64 builds? +#if ! (LL_WINDOWS && ADDRESS_SIZE == 64) using namespace LLCoreInt; namespace tut @@ -39,7 +38,6 @@ namespace tut { // the test objects inherit from this so the member functions and variables // can be referenced directly inside of the test functions. - size_t mMemTotal; }; typedef test_group<RefCountedTestData> RefCountedTestGroupType; @@ -51,18 +49,12 @@ namespace tut { set_test_name("RefCounted construction with implicit count"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference RefCounted * rc = new RefCounted(true); ensure(rc->getRefCount() == 1); // release the implicit reference, causing the object to be released rc->release(); - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } template <> template <> @@ -70,9 +62,6 @@ namespace tut { set_test_name("RefCounted construction without implicit count"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - // create a new ref counted object with an implicit reference RefCounted * rc = new RefCounted(false); ensure(rc->getRefCount() == 0); @@ -83,8 +72,6 @@ namespace tut // release the implicit reference, causing the object to be released rc->release(); - - ensure(mMemTotal == GetMemTotal()); } template <> template <> @@ -92,9 +79,6 @@ namespace tut { set_test_name("RefCounted addRef and release"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - RefCounted * rc = new RefCounted(false); for (int i = 0; i < 1024; ++i) @@ -108,9 +92,6 @@ namespace tut { rc->release(); } - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } template <> template <> @@ -118,9 +99,6 @@ namespace tut { set_test_name("RefCounted isLastRef check"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - RefCounted * rc = new RefCounted(true); // with only one reference, isLastRef should be true @@ -128,9 +106,6 @@ namespace tut // release it to clean up memory rc->release(); - - // make sure we didn't leak any memory - ensure(mMemTotal == GetMemTotal()); } template <> template <> @@ -138,9 +113,6 @@ namespace tut { set_test_name("RefCounted noRef check"); - // record the total amount of dynamically allocated memory - mMemTotal = GetMemTotal(); - RefCounted * rc = new RefCounted(false); // set the noRef @@ -148,10 +120,7 @@ namespace tut // with only one reference, isLastRef should be true ensure(rc->getRefCount() == RefCounted::NOT_REF_COUNTED); - - // allow this memory leak, but check that we're leaking a known amount - ensure(mMemTotal == (GetMemTotal() - sizeof(RefCounted))); } } -#endif // if 0 +#endif // disabling on Win64 #endif // TEST_LLCOREINT_REF_COUNTED_H_ diff --git a/indra/llcrashlogger/README.txt b/indra/llcrashlogger/README.txt new file mode 100644 index 0000000000..6932a8d9c3 --- /dev/null +++ b/indra/llcrashlogger/README.txt @@ -0,0 +1,3 @@ +This component is no longer used in Linden Lab builds. +Change requests to support continued use by open source +builds are welcome. diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index 5e74715500..e02f3a6306 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -411,6 +411,7 @@ bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); httpOpts->setTimeout(timeout); + httpOpts->setSSLVerifyPeer(false); for(int i = 0; i < retries; ++i) { @@ -642,7 +643,7 @@ void LLCrashLogger::init_curl() } CRYPTO_set_locking_callback(ssl_locking_callback); - CRYPTO_set_id_callback(ssl_thread_id_callback); + CRYPTO_THREADID_set_callback(ssl_thread_id_callback); } } @@ -658,12 +659,12 @@ void LLCrashLogger::term_curl() } -unsigned long LLCrashLogger::ssl_thread_id_callback(void) +void LLCrashLogger::ssl_thread_id_callback(CRYPTO_THREADID* pthreadid) { #if LL_WINDOWS - return (unsigned long)GetCurrentThread(); + CRYPTO_THREADID_set_pointer(pthreadid, GetCurrentThread()); #else - return (unsigned long)pthread_self(); + CRYPTO_THREADID_set_pointer(pthreadid, reinterpret_cast<void*>(pthread_self())); #endif } diff --git a/indra/llcrashlogger/llcrashlogger.h b/indra/llcrashlogger/llcrashlogger.h index 56e26c23ba..e3e8110a47 100644 --- a/indra/llcrashlogger/llcrashlogger.h +++ b/indra/llcrashlogger/llcrashlogger.h @@ -36,6 +36,11 @@ #include "llcrashlock.h" #include "_mutex.h" +// We shouldn't have to know the exact declaration of CRYPTO_THREADID, but VS +// 2017 complains if we forward-declare it as simply 'struct CRYPTO_THREADID'. +struct crypto_threadid_st; +typedef crypto_threadid_st CRYPTO_THREADID; + // Crash reporter behavior const S32 CRASH_BEHAVIOR_ASK = 0; const S32 CRASH_BEHAVIOR_ALWAYS_SEND = 1; @@ -68,7 +73,7 @@ public: protected: static void init_curl(); static void term_curl(); - static unsigned long ssl_thread_id_callback(void); + static void ssl_thread_id_callback(CRYPTO_THREADID*); static void ssl_locking_callback(int mode, int type, const char * file, int line); S32 mCrashBehavior; diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt index 293ada7548..28b8e8c06d 100644 --- a/indra/llimage/CMakeLists.txt +++ b/indra/llimage/CMakeLists.txt @@ -11,6 +11,7 @@ include(LLKDU) include(LLImageJ2COJ) include(ZLIB) include(LLAddBuildTest) +include(bugsplat) include(Tut) include_directories( diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 680fbf548f..aed8943439 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -2178,19 +2178,27 @@ bool LLImageFormatted::load(const std::string &filename, int load_size) } bool res; U8 *data = allocateData(load_size); - apr_size_t bytes_read = load_size; - apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read - if (s != APR_SUCCESS || (S32) bytes_read != load_size) + if (data) { - deleteData(); - setLastError("Unable to read file",filename); - res = false; + apr_size_t bytes_read = load_size; + apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read + if (s != APR_SUCCESS || (S32) bytes_read != load_size) + { + deleteData(); + setLastError("Unable to read file",filename); + res = false; + } + else + { + res = updateData(); + } } else { - res = updateData(); + setLastError("Allocation failure", filename); + res = false; } - + return res; } diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 8ec49d3f0f..f66b1666d7 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -87,6 +87,7 @@ typedef enum e_image_codec //============================================================================ // library initialization class +// LLImage is frequently used in threads so do not convert it to LLSingleton class LLImage { @@ -98,7 +99,7 @@ public: static void setLastError(const std::string& message); static bool useNewByteRange() { return sUseNewByteRange; } - static S32 getReverseByteRangePercent() { return sMinimalReverseByteRangePercent; } + static S32 getReverseByteRangePercent() { return sMinimalReverseByteRangePercent; } protected: static LLMutex* sMutex; diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp index 3b1b060c02..62638fa16c 100644 --- a/indra/llimage/llimagejpeg.cpp +++ b/indra/llimage/llimagejpeg.cpp @@ -315,7 +315,7 @@ bool LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) jpeg_destroy_decompress(&cinfo); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { setLastError( "Out of memory"); jpeg_destroy_decompress(&cinfo); @@ -386,7 +386,6 @@ boolean LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo ) { self->setLastError("Out of memory in LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )"); LLTHROW(LLContinueError("Out of memory in LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )")); - return false; } memcpy( new_buffer, self->mOutputBuffer, self->mOutputBufferSize ); /* Flawfinder: ignore */ delete[] self->mOutputBuffer; diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp index f298764cc0..f7dc6272cf 100644 --- a/indra/llimage/llpngwrapper.cpp +++ b/indra/llimage/llpngwrapper.cpp @@ -210,7 +210,7 @@ BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInf releaseResources(); return (FALSE); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { mErrorMessage = "LLPngWrapper"; releaseResources(); diff --git a/indra/llinventory/CMakeLists.txt b/indra/llinventory/CMakeLists.txt index 68dd00d880..e829788c91 100644 --- a/indra/llinventory/CMakeLists.txt +++ b/indra/llinventory/CMakeLists.txt @@ -19,16 +19,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 ) @@ -37,11 +41,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 @@ -49,6 +54,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 diff --git a/indra/llinventory/lleconomy.cpp b/indra/llinventory/lleconomy.cpp deleted file mode 100644 index 2a023d8c24..0000000000 --- a/indra/llinventory/lleconomy.cpp +++ /dev/null @@ -1,287 +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" - - -LLBaseEconomy::LLBaseEconomy() -: mObjectCount( -1 ), - mObjectCapacity( -1 ), - mPriceObjectClaim( -1 ), - mPricePublicObjectDecay( -1 ), - mPricePublicObjectDelete( -1 ), - mPriceEnergyUnit( -1 ), - mPriceUpload( -1 ), - mPriceRentLight( -1 ), - mTeleportMinPrice( -1 ), - mTeleportPriceExponent( -1 ), - mPriceGroupCreate( -1 ) -{ } - -LLBaseEconomy::~LLBaseEconomy() -{ } - -void LLBaseEconomy::addObserver(LLEconomyObserver* observer) -{ - mObservers.push_back(observer); -} - -void LLBaseEconomy::removeObserver(LLEconomyObserver* observer) -{ - std::list<LLEconomyObserver*>::iterator it = - std::find(mObservers.begin(), mObservers.end(), observer); - if (it != mObservers.end()) - { - mObservers.erase(it); - } -} - -void LLBaseEconomy::notifyObservers() -{ - for (std::list<LLEconomyObserver*>::iterator it = mObservers.begin(); - it != mObservers.end(); - ++it) - { - (*it)->onEconomyDataChange(); - } -} - -// static -void LLBaseEconomy::processEconomyData(LLMessageSystem *msg, LLBaseEconomy* 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); - LL_WARNS() << "LL_FAKE_UPLOAD_PRICE: Faking upload price as L$" << fakeprice << LL_ENDL; - 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 LLBaseEconomy::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 LLBaseEconomy::calculateLightRent(const LLVector3& object_size) const -{ - F32 intensity_mod = llmax(object_size.magVec(), 1.f); - return (S32)(intensity_mod * getPriceRentLight()); -} - -void LLBaseEconomy::print() -{ - LL_INFOS() << "Global Economy Settings: " << LL_ENDL; - LL_INFOS() << "Object Capacity: " << mObjectCapacity << LL_ENDL; - LL_INFOS() << "Object Count: " << mObjectCount << LL_ENDL; - LL_INFOS() << "Claim Price Per Object: " << mPriceObjectClaim << LL_ENDL; - LL_INFOS() << "Claim Price Per Public Object: " << mPricePublicObjectDecay << LL_ENDL; - LL_INFOS() << "Delete Price Per Public Object: " << mPricePublicObjectDelete << LL_ENDL; - LL_INFOS() << "Release Price Per Public Object: " << getPricePublicObjectRelease() << LL_ENDL; - LL_INFOS() << "Price Per Energy Unit: " << mPriceEnergyUnit << LL_ENDL; - LL_INFOS() << "Price Per Upload: " << mPriceUpload << LL_ENDL; - LL_INFOS() << "Light Base Price: " << mPriceRentLight << LL_ENDL; - LL_INFOS() << "Teleport Min Price: " << mTeleportMinPrice << LL_ENDL; - LL_INFOS() << "Teleport Price Exponent: " << mTeleportPriceExponent << LL_ENDL; - LL_INFOS() << "Price for group creation: " << mPriceGroupCreate << LL_ENDL; -} - -LLRegionEconomy::LLRegionEconomy() -: 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; - - LLBaseEconomy::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()) - { - LL_WARNS() << "Dropping EconomyDataRequest, because EconomyData message " - << "has not been processed" << LL_ENDL; - } - - 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->LLBaseEconomy::print(); - - LL_INFOS() << "Region Economy Settings: " << LL_ENDL; - LL_INFOS() << "Land (square meters): " << mAreaTotal << LL_ENDL; - LL_INFOS() << "Owned Land (square meters): " << mAreaOwned << LL_ENDL; - LL_INFOS() << "Daily Object Rent: " << mPriceObjectRent << LL_ENDL; - LL_INFOS() << "Daily Land Rent (per meter): " << getPriceParcelRent() << LL_ENDL; - LL_INFOS() << "Energey Efficiency: " << mEnergyEfficiency << LL_ENDL; -} - - -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 cdfde171c1..0000000000 --- a/indra/llinventory/lleconomy.h +++ /dev/null @@ -1,157 +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" -#include <list> - -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 LLBaseEconomy -{ -public: - LLBaseEconomy(); - virtual ~LLBaseEconomy(); - - virtual void print(); - - void addObserver(LLEconomyObserver* observer); - void removeObserver(LLEconomyObserver* observer); - void notifyObservers(); - - static void processEconomyData(LLMessageSystem *msg, LLBaseEconomy* 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<LLEconomyObserver*> mObservers; -}; - -class LLGlobalEconomy: public LLSingleton<LLGlobalEconomy>, public LLBaseEconomy -{ - LLSINGLETON_EMPTY_CTOR(LLGlobalEconomy); -}; - -class LLRegionEconomy : public LLBaseEconomy -{ -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/llinventory/llfoldertype.cpp b/indra/llinventory/llfoldertype.cpp index b0daf639fa..7241b3c0c2 100644 --- a/indra/llinventory/llfoldertype.cpp +++ b/indra/llinventory/llfoldertype.cpp @@ -100,6 +100,8 @@ LLFolderDictionary::LLFolderDictionary() 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_NONE, new FolderEntry("-1", FALSE)); }; @@ -147,7 +149,7 @@ bool LLFolderType::lookupIsEnsembleType(EType folder_type) // static LLAssetType::EType LLFolderType::folderTypeToAssetType(LLFolderType::EType folder_type) { - if (LLAssetType::lookup(LLAssetType::EType(folder_type)) == LLAssetType::badLookup()) + if (LLAssetType::lookup(LLAssetType::EType(folder_type)) == LLAssetType::BADLOOKUP) { LL_WARNS() << "Converting to unknown asset type " << folder_type << LL_ENDL; } diff --git a/indra/llinventory/llfoldertype.h b/indra/llinventory/llfoldertype.h index 515bb05a3f..85b86f9ce5 100644 --- a/indra/llinventory/llfoldertype.h +++ b/indra/llinventory/llfoldertype.h @@ -91,6 +91,8 @@ public: 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_COUNT, FT_NONE = -1 diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 11647c5518..18bc1b5a91 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -41,7 +41,7 @@ /// Exported functions ///---------------------------------------------------------------------------- static const std::string INV_ITEM_ID_LABEL("item_id"); -static const std::string INV_FOLDER_ID_LABEL("folder_id"); +static const std::string INV_FOLDER_ID_LABEL("cat_id"); static const std::string INV_PARENT_ID_LABEL("parent_id"); static const std::string INV_ASSET_TYPE_LABEL("type"); static const std::string INV_PREFERRED_TYPE_LABEL("preferred_type"); @@ -228,22 +228,6 @@ BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream) return TRUE; } -// exportFile should be replaced with exportLegacyStream -// not sure whether exportLegacyStream(llofstream(fp)) would work, fp may need to get icramented... -BOOL LLInventoryObject::exportFile(LLFILE* fp, BOOL) const -{ - std::string uuid_str; - fprintf(fp, "\tinv_object\t0\n\t{\n"); - mUUID.toString(uuid_str); - fprintf(fp, "\t\tobj_id\t%s\n", uuid_str.c_str()); - mParentUUID.toString(uuid_str); - fprintf(fp, "\t\tparent_id\t%s\n", uuid_str.c_str()); - fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType)); - fprintf(fp, "\t\tname\t%s|\n", mName.c_str()); - fprintf(fp,"\t}\n"); - return TRUE; -} - BOOL LLInventoryObject::exportLegacyStream(std::ostream& output_stream, BOOL) const { std::string uuid_str; @@ -604,215 +588,6 @@ BOOL LLInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block, S32 } // virtual -BOOL LLInventoryItem::importFile(LLFILE* fp) -{ - // *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 */ - char junk[MAX_STRING]; /* Flawfinder: ignore */ - BOOL success = TRUE; - - keyword[0] = '\0'; - valuestr[0] = '\0'; - - mInventoryType = LLInventoryType::IT_NONE; - mAssetUUID.setNull(); - while(success && (!feof(fp))) - { - if (fgets(buffer, MAX_STRING, fp) == NULL) - { - buffer[0] = '\0'; - } - - sscanf(buffer, " %254s %254s", keyword, valuestr); /* Flawfinder: ignore */ - if(0 == strcmp("{",keyword)) - { - continue; - } - if(0 == strcmp("}", keyword)) - { - break; - } - else if(0 == strcmp("item_id", keyword)) - { - mUUID.set(valuestr); - } - else if(0 == strcmp("parent_id", keyword)) - { - mParentUUID.set(valuestr); - } - else if(0 == strcmp("permissions", keyword)) - { - success = mPermissions.importFile(fp); - } - else if(0 == strcmp("sale_info", keyword)) - { - // Sale info used to contain next owner perm. It is now in - // the permissions. Thus, we read that out, and fix legacy - // objects. It's possible this op would fail, but it - // should pick up the vast majority of the tasks. - BOOL has_perm_mask = FALSE; - U32 perm_mask = 0; - success = mSaleInfo.importFile(fp, has_perm_mask, perm_mask); - if(has_perm_mask) - { - if(perm_mask == PERM_NONE) - { - perm_mask = mPermissions.getMaskOwner(); - } - // fair use fix. - if(!(perm_mask & PERM_COPY)) - { - perm_mask |= PERM_TRANSFER; - } - mPermissions.setMaskNext(perm_mask); - } - } - else if(0 == strcmp("shadow_id", keyword)) - { - mAssetUUID.set(valuestr); - LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES); - cipher.decrypt(mAssetUUID.mData, UUID_BYTES); - } - else if(0 == strcmp("asset_id", keyword)) - { - mAssetUUID.set(valuestr); - } - else if(0 == strcmp("type", keyword)) - { - mType = LLAssetType::lookup(valuestr); - } - else if(0 == strcmp("inv_type", keyword)) - { - mInventoryType = LLInventoryType::lookup(std::string(valuestr)); - } - else if(0 == strcmp("flags", keyword)) - { - sscanf(valuestr, "%x", &mFlags); - } - else if(0 == strcmp("name", keyword)) - { - //strcpy(valuestr, buffer + strlen(keyword) + 3); - // *NOTE: Not ANSI C, but widely supported. - sscanf( /* Flawfinder: ignore */ - buffer, - " %254s%254[\t]%254[^|]", - keyword, junk, valuestr); - - // IW: sscanf chokes and puts | in valuestr if there's no name - if (valuestr[0] == '|') - { - valuestr[0] = '\000'; - } - - mName.assign(valuestr); - LLStringUtil::replaceNonstandardASCII(mName, ' '); - LLStringUtil::replaceChar(mName, '|', ' '); - } - else if(0 == strcmp("desc", keyword)) - { - //strcpy(valuestr, buffer + strlen(keyword) + 3); - // *NOTE: Not ANSI C, but widely supported. - sscanf( /* Flawfinder: ignore */ - buffer, - " %254s%254[\t]%254[^|]", - keyword, junk, valuestr); - - if (valuestr[0] == '|') - { - valuestr[0] = '\000'; - } - - disclaimMem(mDescription); - mDescription.assign(valuestr); - claimMem(mDescription); - LLStringUtil::replaceNonstandardASCII(mDescription, ' '); - /* TODO -- ask Ian about this code - const char *donkey = mDescription.c_str(); - if (donkey[0] == '|') - { - LL_ERRS() << "Donkey" << LL_ENDL; - } - */ - } - else if(0 == strcmp("creation_date", keyword)) - { - S32 date; - sscanf(valuestr, "%d", &date); - mCreationDate = date; - } - else - { - LL_WARNS() << "unknown keyword '" << keyword - << "' in inventory import of item " << mUUID << LL_ENDL; - } - } - - // Need to convert 1.0 simstate files to a useful inventory type - // and potentially deal with bad inventory tyes eg, a landmark - // marked as a texture. - if((LLInventoryType::IT_NONE == mInventoryType) - || !inventory_and_asset_types_match(mInventoryType, mType)) - { - LL_DEBUGS() << "Resetting inventory type for " << mUUID << LL_ENDL; - mInventoryType = LLInventoryType::defaultForAssetType(mType); - } - - mPermissions.initMasks(mInventoryType); - - return success; -} - -BOOL LLInventoryItem::exportFile(LLFILE* fp, BOOL include_asset_key) const -{ - std::string uuid_str; - fprintf(fp, "\tinv_item\t0\n\t{\n"); - mUUID.toString(uuid_str); - fprintf(fp, "\t\titem_id\t%s\n", uuid_str.c_str()); - mParentUUID.toString(uuid_str); - fprintf(fp, "\t\tparent_id\t%s\n", uuid_str.c_str()); - mPermissions.exportFile(fp); - - // Check for permissions to see the asset id, and if so write it - // out as an asset id. Otherwise, apply our cheesy encryption. - if(include_asset_key) - { - U32 mask = mPermissions.getMaskBase(); - if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) - || (mAssetUUID.isNull())) - { - mAssetUUID.toString(uuid_str); - fprintf(fp, "\t\tasset_id\t%s\n", uuid_str.c_str()); - } - else - { - LLUUID shadow_id(mAssetUUID); - LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES); - cipher.encrypt(shadow_id.mData, UUID_BYTES); - shadow_id.toString(uuid_str); - fprintf(fp, "\t\tshadow_id\t%s\n", uuid_str.c_str()); - } - } - else - { - LLUUID::null.toString(uuid_str); - fprintf(fp, "\t\tasset_id\t%s\n", uuid_str.c_str()); - } - fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType)); - const std::string inv_type_str = LLInventoryType::lookup(mInventoryType); - if(!inv_type_str.empty()) fprintf(fp, "\t\tinv_type\t%s\n", inv_type_str.c_str()); - fprintf(fp, "\t\tflags\t%08x\n", mFlags); - mSaleInfo.exportFile(fp); - fprintf(fp, "\t\tname\t%s|\n", mName.c_str()); - fprintf(fp, "\t\tdesc\t%s|\n", mDescription.c_str()); - fprintf(fp, "\t\tcreation_date\t%d\n", (S32) mCreationDate); - fprintf(fp,"\t}\n"); - return TRUE; -} - -// virtual BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream) { // *NOTE: Changing the buffer size will require changing the scanf @@ -1463,90 +1238,7 @@ void LLInventoryCategory::unpackMessage(LLMessageSystem* msg, msg->getStringFast(block, _PREHASH_Name, mName, block_num); LLStringUtil::replaceNonstandardASCII(mName, ' '); } - -// virtual -BOOL LLInventoryCategory::importFile(LLFILE* fp) -{ - // *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 */ - keyword[0] = '\0'; - valuestr[0] = '\0'; - while(!feof(fp)) - { - if (fgets(buffer, MAX_STRING, fp) == NULL) - { - buffer[0] = '\0'; - } - - sscanf( /* Flawfinder: ignore */ - buffer, - " %254s %254s", - keyword, valuestr); - if(0 == strcmp("{",keyword)) - { - continue; - } - if(0 == strcmp("}", keyword)) - { - break; - } - else if(0 == strcmp("cat_id", keyword)) - { - mUUID.set(valuestr); - } - else if(0 == strcmp("parent_id", keyword)) - { - mParentUUID.set(valuestr); - } - else if(0 == strcmp("type", keyword)) - { - mType = LLAssetType::lookup(valuestr); - } - else if(0 == strcmp("pref_type", keyword)) - { - mPreferredType = LLFolderType::lookup(valuestr); - } - else if(0 == strcmp("name", keyword)) - { - //strcpy(valuestr, buffer + strlen(keyword) + 3); - // *NOTE: Not ANSI C, but widely supported. - sscanf( /* Flawfinder: ignore */ - buffer, - " %254s %254[^|]", - keyword, valuestr); - mName.assign(valuestr); - LLStringUtil::replaceNonstandardASCII(mName, ' '); - LLStringUtil::replaceChar(mName, '|', ' '); - } - else - { - LL_WARNS() << "unknown keyword '" << keyword - << "' in inventory import category " << mUUID << LL_ENDL; - } - } - return TRUE; -} - -BOOL LLInventoryCategory::exportFile(LLFILE* fp, BOOL) const -{ - std::string uuid_str; - fprintf(fp, "\tinv_category\t0\n\t{\n"); - mUUID.toString(uuid_str); - fprintf(fp, "\t\tcat_id\t%s\n", uuid_str.c_str()); - mParentUUID.toString(uuid_str); - fprintf(fp, "\t\tparent_id\t%s\n", uuid_str.c_str()); - fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType)); - fprintf(fp, "\t\tpref_type\t%s\n", LLFolderType::lookup(mPreferredType).c_str()); - fprintf(fp, "\t\tname\t%s|\n", mName.c_str()); - fprintf(fp,"\t}\n"); - return TRUE; -} - - // virtual BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream) { @@ -1625,6 +1317,45 @@ BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL) return TRUE; } +LLSD LLInventoryCategory::exportLLSD() const +{ + LLSD cat_data; + cat_data[INV_FOLDER_ID_LABEL] = mUUID; + cat_data[INV_PARENT_ID_LABEL] = mParentUUID; + cat_data[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(mType); + cat_data[INV_PREFERRED_TYPE_LABEL] = LLFolderType::lookup(mPreferredType); + cat_data[INV_NAME_LABEL] = mName; + + return cat_data; +} + +bool LLInventoryCategory::importLLSD(const LLSD& cat_data) +{ + if (cat_data.has(INV_FOLDER_ID_LABEL)) + { + setUUID(cat_data[INV_FOLDER_ID_LABEL].asUUID()); + } + if (cat_data.has(INV_PARENT_ID_LABEL)) + { + setParent(cat_data[INV_PARENT_ID_LABEL].asUUID()); + } + if (cat_data.has(INV_ASSET_TYPE_LABEL)) + { + setType(LLAssetType::lookup(cat_data[INV_ASSET_TYPE_LABEL].asString())); + } + if (cat_data.has(INV_PREFERRED_TYPE_LABEL)) + { + setPreferredType(LLFolderType::lookup(cat_data[INV_PREFERRED_TYPE_LABEL].asString())); + } + if (cat_data.has(INV_NAME_LABEL)) + { + mName = cat_data[INV_NAME_LABEL].asString(); + LLStringUtil::replaceNonstandardASCII(mName, ' '); + LLStringUtil::replaceChar(mName, '|', ' '); + } + + return true; +} ///---------------------------------------------------------------------------- /// Local function definitions ///---------------------------------------------------------------------------- diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 70b200e139..0f336a072f 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -95,8 +95,7 @@ public: // Implemented here so that a minimal information set can be transmitted // between simulator and viewer. //-------------------------------------------------------------------- - // 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; @@ -197,8 +196,6 @@ public: // File Support //-------------------------------------------------------------------- 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; @@ -247,7 +244,7 @@ public: LLInventoryCategory(const LLInventoryCategory* other); void copyCategory(const LLInventoryCategory* other); // LLRefCount requires custom copy protected: - ~LLInventoryCategory(); + virtual ~LLInventoryCategory(); //-------------------------------------------------------------------- // Accessors And Mutators @@ -269,11 +266,11 @@ public: // File Support //-------------------------------------------------------------------- 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; + LLSD exportLLSD() const; + bool importLLSD(const LLSD& cat_data); //-------------------------------------------------------------------- // Member Variables //-------------------------------------------------------------------- diff --git a/indra/llinventory/llinventorydefines.h b/indra/llinventory/llinventorydefines.h index 3881fb1fd7..54562673f3 100644 --- a/indra/llinventory/llinventorydefines.h +++ b/indra/llinventory/llinventorydefines.h @@ -81,9 +81,10 @@ public: 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..81485b3a97 --- /dev/null +++ b/indra/llinventory/llinventorysettings.cpp @@ -0,0 +1,112 @@ +/** +* @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" + + +//========================================================================= +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 = LLSettingsType::getInstance()->mTranslator->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<LLSettingsDictionary>, + public LLDictionary<LLSettingsType::type_e, SettingsEntry> +{ + 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::LLSettingsType(LLTranslationBridge::ptr_t &trans) +{ + mTranslator = trans; +} + +LLSettingsType::~LLSettingsType() +{ + mTranslator.reset(); +} + +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; +} diff --git a/indra/llinventory/llinventorysettings.h b/indra/llinventory/llinventorysettings.h new file mode 100644 index 0000000000..6b6685d088 --- /dev/null +++ b/indra/llinventory/llinventorysettings.h @@ -0,0 +1,63 @@ +/** +* @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" +#include "llsingleton.h" + +class LLSettingsType : public LLParamSingleton<LLSettingsType> +{ + LLSINGLETON(LLSettingsType, LLTranslationBridge::ptr_t &trans); + ~LLSettingsType(); + + friend struct SettingsEntry; + +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); + +protected: + + LLTranslationBridge::ptr_t mTranslator; +}; + + +#endif diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp index 7399e1bca4..853ed655f5 100644 --- a/indra/llinventory/llinventorytype.cpp +++ b/indra/llinventory/llinventorytype.cpp @@ -85,6 +85,7 @@ LLInventoryDictionary::LLInventoryDictionary() addEntry(LLInventoryType::IT_MESH, new InventoryEntry("mesh", "mesh", 1, LLAssetType::AT_MESH)); addEntry(LLInventoryType::IT_WIDGET, new InventoryEntry("widget", "widget", 1, LLAssetType::AT_WIDGET)); addEntry(LLInventoryType::IT_PERSON, new InventoryEntry("person", "person", 1, LLAssetType::AT_PERSON)); + addEntry(LLInventoryType::IT_SETTINGS, new InventoryEntry("settings", "settings", 1, LLAssetType::AT_SETTINGS)); } @@ -145,6 +146,14 @@ 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, // 51 AT_RESERVED_2 + LLInventoryType::IT_NONE, // 52 AT_RESERVED_3 + LLInventoryType::IT_NONE, // 53 AT_RESERVED_4 + LLInventoryType::IT_NONE, // 54 AT_RESERVED_5 + + LLInventoryType::IT_SETTINGS, // 55 AT_SETTINGS }; // static @@ -200,6 +209,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 034cee5f45..b6e7fb047f 100644 --- a/indra/llinventory/llinventorytype.h +++ b/indra/llinventory/llinventorytype.h @@ -64,7 +64,8 @@ public: IT_MESH = 22, IT_WIDGET = 23, IT_PERSON = 24, - IT_COUNT = 25, + IT_SETTINGS = 25, + IT_COUNT = 26, IT_UNKNOWN = 255, IT_NONE = -1 @@ -112,6 +113,11 @@ public: ICONNAME_LINKFOLDER, ICONNAME_MESH, + ICONNAME_SETTINGS, + ICONNAME_SETTINGS_SKY, + ICONNAME_SETTINGS_WATER, + ICONNAME_SETTINGS_DAY, + ICONNAME_INVALID, ICONNAME_UNKNOWN, ICONNAME_COUNT, @@ -131,6 +137,8 @@ public: // 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..fbd887030a --- /dev/null +++ b/indra/llinventory/llinvtranslationbrdg.h @@ -0,0 +1,41 @@ +/** +* @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 + +class LLTranslationBridge +{ +public: + typedef std::shared_ptr<LLTranslationBridge> 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 4c6075d6b5..bd7ab3c2c8 100644 --- a/indra/llinventory/lllandmark.cpp +++ b/indra/llinventory/lllandmark.cpp @@ -103,60 +103,104 @@ LLVector3 LLLandmark::getRegionPos() const // static -LLLandmark* LLLandmark::constructFromString(const char *buffer) +LLLandmark* LLLandmark::constructFromString(const char *buffer, const S32 buffer_size) { - const char* cur = buffer; S32 chars_read = 0; + S32 chars_read_total = 0; S32 count = 0; U32 version = 0; + bool bad_block = false; + LLLandmark* result = NULL; + // read version - count = sscanf( cur, "Landmark version %u\n%n", &version, &chars_read ); - if(count != 1) - { - goto error; - } + count = sscanf( buffer, "Landmark version %u\n%n", &version, &chars_read ); + chars_read_total += chars_read; - if(version == 1) - { - LLVector3d pos; - cur += chars_read; - // read position - count = sscanf( cur, "position %lf %lf %lf\n%n", pos.mdV+VX, pos.mdV+VY, pos.mdV+VZ, &chars_read ); - if( count != 3 ) - { - goto error; - } - cur += chars_read; - // LL_INFOS() << "Landmark read: " << pos << LL_ENDL; - - return new LLLandmark(pos); - } - else if(version == 2) - { - // *NOTE: Changing the buffer size will require changing the - // scanf call below. - char region_id_str[MAX_STRING]; /* Flawfinder: ignore */ - LLVector3 pos; - cur += chars_read; - count = sscanf( /* Flawfinder: ignore */ - cur, - "region_id %254s\n%n", - region_id_str, &chars_read); - if(count != 1) goto error; - cur += chars_read; - count = sscanf(cur, "local_pos %f %f %f\n%n", pos.mV+VX, pos.mV+VY, pos.mV+VZ, &chars_read); - if(count != 3) goto error; - cur += chars_read; - LLLandmark* lm = new LLLandmark; - lm->mRegionID.set(region_id_str); - lm->mRegionPos = pos; - return lm; - } + if (count != 1 + || chars_read_total >= buffer_size) + { + bad_block = true; + } + + if (!bad_block) + { + switch (version) + { + case 1: + { + LLVector3d pos; + // read position + count = sscanf(buffer + chars_read_total, "position %lf %lf %lf\n%n", pos.mdV + VX, pos.mdV + VY, pos.mdV + VZ, &chars_read); + if (count != 3) + { + bad_block = true; + } + else + { + LL_DEBUGS("Landmark") << "Landmark read: " << pos << LL_ENDL; + result = new LLLandmark(pos); + } + break; + } + case 2: + { + // *NOTE: Changing the buffer size will require changing the + // scanf call below. + char region_id_str[MAX_STRING]; + LLVector3 pos; + LLUUID region_id; + count = sscanf( buffer + chars_read_total, + "region_id %254s\n%n", + region_id_str, + &chars_read); + chars_read_total += chars_read; + + if (count != 1 + || chars_read_total >= buffer_size + || !LLUUID::validate(region_id_str)) + { + bad_block = true; + } + + if (!bad_block) + { + region_id.set(region_id_str); + if (region_id.isNull()) + { + bad_block = true; + } + } + + if (!bad_block) + { + count = sscanf(buffer + chars_read_total, "local_pos %f %f %f\n%n", pos.mV + VX, pos.mV + VY, pos.mV + VZ, &chars_read); + if (count != 3) + { + bad_block = true; + } + else + { + result = new LLLandmark; + result->mRegionID = region_id; + result->mRegionPos = pos; + } + } + break; + } + default: + { + LL_INFOS("Landmark") << "Encountered Unknown landmark version " << version << LL_ENDL; + break; + } + } + } - error: - LL_INFOS() << "Bad Landmark Asset: bad _DATA_ block." << LL_ENDL; - return NULL; + if (bad_block) + { + LL_INFOS("Landmark") << "Bad Landmark Asset: bad _DATA_ block." << LL_ENDL; + } + return result; } @@ -176,7 +220,7 @@ void LLLandmark::requestRegionHandle( if(region_id.isNull()) { // don't bother with checking - it's 0. - LL_DEBUGS() << "requestRegionHandle: null" << LL_ENDL; + LL_DEBUGS("Landmark") << "requestRegionHandle: null" << LL_ENDL; if(callback) { const U64 U64_ZERO = 0; @@ -187,7 +231,7 @@ void LLLandmark::requestRegionHandle( { if(region_id == mLocalRegion.first) { - LL_DEBUGS() << "requestRegionHandle: local" << LL_ENDL; + LL_DEBUGS("Landmark") << "requestRegionHandle: local" << LL_ENDL; if(callback) { callback(region_id, mLocalRegion.second); @@ -198,13 +242,13 @@ void LLLandmark::requestRegionHandle( region_map_t::iterator it = mRegions.find(region_id); if(it == mRegions.end()) { - LL_DEBUGS() << "requestRegionHandle: upstream" << LL_ENDL; + LL_DEBUGS("Landmark") << "requestRegionHandle: upstream" << LL_ENDL; if(callback) { region_callback_map_t::value_type vt(region_id, callback); sRegionCallbackMap.insert(vt); } - LL_DEBUGS() << "Landmark requesting information about: " + LL_DEBUGS("Landmark") << "Landmark requesting information about: " << region_id << LL_ENDL; msg->newMessage("RegionHandleRequest"); msg->nextBlock("RequestBlock"); @@ -214,7 +258,7 @@ void LLLandmark::requestRegionHandle( else if(callback) { // we have the answer locally - just call the callack. - LL_DEBUGS() << "requestRegionHandle: ready" << LL_ENDL; + LL_DEBUGS("Landmark") << "requestRegionHandle: ready" << LL_ENDL; callback(region_id, (*it).second.mRegionHandle); } } diff --git a/indra/llinventory/lllandmark.h b/indra/llinventory/lllandmark.h index 92923ea6fb..be34113a90 100644 --- a/indra/llinventory/lllandmark.h +++ b/indra/llinventory/lllandmark.h @@ -60,7 +60,7 @@ public: // constructs a new LLLandmark from a string // return NULL if there's an error - static LLLandmark* constructFromString(const char *buffer); + static LLLandmark* constructFromString(const char *buffer, const S32 buffer_size); // register callbacks that this class handles static void registerCallbacks(LLMessageSystem* msg); diff --git a/indra/llinventory/llparcel.cpp b/indra/llinventory/llparcel.cpp index 0908613c10..e2469f3c7e 100644 --- a/indra/llinventory/llparcel.cpp +++ b/indra/llinventory/llparcel.cpp @@ -231,6 +231,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) diff --git a/indra/llinventory/llparcel.h b/indra/llinventory/llparcel.h index 135d0ca7b9..5d08c1f4c6 100644 --- a/indra/llinventory/llparcel.h +++ b/indra/llinventory/llparcel.h @@ -34,6 +34,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; @@ -102,6 +103,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); @@ -290,7 +295,6 @@ public: void setAllowTerraform(BOOL b){setParcelFlag(PF_ALLOW_TERRAFORM, b); } void setAllowDamage(BOOL b) { setParcelFlag(PF_ALLOW_DAMAGE, b); } void setAllowFly(BOOL b) { setParcelFlag(PF_ALLOW_FLY, b); } - void setAllowLandmark(BOOL b){ setParcelFlag(PF_ALLOW_LANDMARK, b); } void setAllowGroupScripts(BOOL b) { setParcelFlag(PF_ALLOW_GROUP_SCRIPTS, b); } void setAllowOtherScripts(BOOL b) { setParcelFlag(PF_ALLOW_OTHER_SCRIPTS, b); } void setAllowDeedToGroup(BOOL b) { setParcelFlag(PF_ALLOW_DEED_TO_GROUP, b); } @@ -471,11 +475,6 @@ public: BOOL getAllowFly() const { return (mParcelFlags & PF_ALLOW_FLY) ? TRUE : FALSE; } - // Remove permission restrictions for creating landmarks. - // We should eventually remove this flag completely. - BOOL getAllowLandmark() const - { return TRUE; } - BOOL getAllowGroupScripts() const { return (mParcelFlags & PF_ALLOW_GROUP_SCRIPTS) ? TRUE : FALSE; } @@ -510,6 +509,10 @@ public: { return mRegionDenyAgeUnverifiedOverride; } BOOL getRegionAllowAccessOverride() const { return mRegionAllowAccessoverride; } + BOOL getRegionAllowEnvironmentOverride() const + { return mRegionAllowEnvironmentOverride; } + S32 getParcelEnvironmentVersion() const + { return mCurrentEnvironmentVersion; } BOOL getAllowGroupAVSounds() const { return mAllowGroupAVSounds; } @@ -580,6 +583,9 @@ public: 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; } @@ -589,8 +595,7 @@ public: LLUUID getPreviousOwnerID() const { return mPreviousOwnerID; } BOOL getPreviouslyGroupOwned() const { return mPreviouslyGroupOwned; } BOOL getSellWithObjects() const { return (mParcelFlags & PF_SELL_PARCEL_OBJECTS) ? TRUE : FALSE; } - - + protected: LLUUID mID; LLUUID mOwnerID; @@ -662,10 +667,13 @@ protected: BOOL mRegionDenyAnonymousOverride; BOOL mRegionDenyAgeUnverifiedOverride; BOOL mRegionAllowAccessoverride; + BOOL mRegionAllowEnvironmentOverride; BOOL mAllowGroupAVSounds; BOOL mAllowAnyAVSounds; + S32 mCurrentEnvironmentVersion; - + bool mIsDefaultDayCycle; + public: // HACK, make private S32 mLocalID; diff --git a/indra/llinventory/llparcelflags.h b/indra/llinventory/llparcelflags.h index 25b27a281a..4cffa83cc1 100644 --- a/indra/llinventory/llparcelflags.h +++ b/indra/llinventory/llparcelflags.h @@ -33,7 +33,7 @@ const U32 PF_ALLOW_FLY = 1 << 0;// Can start flying const U32 PF_ALLOW_OTHER_SCRIPTS= 1 << 1;// Scripts by others can run. const U32 PF_FOR_SALE = 1 << 2;// Can buy this land const U32 PF_FOR_SALE_OBJECTS = 1 << 7;// Can buy all objects on this land -const U32 PF_ALLOW_LANDMARK = 1 << 3; +const U32 PF_ALLOW_LANDMARK = 1 << 3;// Always true/deprecated const U32 PF_ALLOW_TERRAFORM = 1 << 4; const U32 PF_ALLOW_DAMAGE = 1 << 5; const U32 PF_CREATE_OBJECTS = 1 << 6; diff --git a/indra/llinventory/llpermissions.cpp b/indra/llinventory/llpermissions.cpp index e79b753514..0359d2f554 100644 --- a/indra/llinventory/llpermissions.cpp +++ b/indra/llinventory/llpermissions.cpp @@ -565,148 +565,6 @@ void LLPermissions::unpackMessage(LLMessageSystem* msg, const char* block, S32 b } -// -// File support -// - -BOOL LLPermissions::importFile(LLFILE* fp) -{ - 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 -{ - 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::importLegacyStream(std::istream& input_stream) { init(LLUUID::null, LLUUID::null, LLUUID::null, LLUUID::null); diff --git a/indra/llinventory/llpermissions.h b/indra/llinventory/llpermissions.h index 89c66f6ebd..27252f7b97 100644 --- a/indra/llinventory/llpermissions.h +++ b/indra/llinventory/llpermissions.h @@ -311,10 +311,6 @@ public: void packMessage(LLMessageSystem* msg) const; void unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0); - // Load/save support - BOOL importFile(LLFILE* fp); - BOOL exportFile(LLFILE* fp) const; - BOOL importLegacyStream(std::istream& input_stream); BOOL exportLegacyStream(std::ostream& output_stream) const; diff --git a/indra/llinventory/llsaleinfo.cpp b/indra/llinventory/llsaleinfo.cpp index 63e34d188e..b7231ee239 100644 --- a/indra/llinventory/llsaleinfo.cpp +++ b/indra/llinventory/llsaleinfo.cpp @@ -78,16 +78,6 @@ U32 LLSaleInfo::getCRC32() const return rv; } - -BOOL LLSaleInfo::exportFile(LLFILE* fp) const -{ - 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::exportLegacyStream(std::ostream& output_stream) const { output_stream << "\tsale_info\t0\n\t{\n"; @@ -129,69 +119,6 @@ bool LLSaleInfo::fromLLSD(const LLSD& sd, BOOL& has_perm_mask, U32& perm_mask) return true; } -// Deleted LLSaleInfo::exportFileXML() and LLSaleInfo::importXML() -// 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) -{ - 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 && (!feof(fp))) - { - 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)) - { - mSaleType = lookup(valuestr); - } - else if(0 == strcmp("sale_price", keyword)) - { - 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; diff --git a/indra/llinventory/llsaleinfo.h b/indra/llinventory/llsaleinfo.h index 4e98ccf6ff..3c8952838b 100644 --- a/indra/llinventory/llsaleinfo.h +++ b/indra/llinventory/llsaleinfo.h @@ -84,11 +84,6 @@ public: void setSalePrice(S32 price); //void setNextOwnerPermMask(U32 mask) { mNextOwnerPermMask = mask; } - - // file serialization - BOOL exportFile(LLFILE* fp) const; - BOOL importFile(LLFILE* fp, BOOL& has_perm_mask, U32& perm_mask); - BOOL exportLegacyStream(std::ostream& output_stream) const; LLSD asLLSD() const; operator LLSD() const { return asLLSD(); } diff --git a/indra/llinventory/llsettingsbase.cpp b/indra/llinventory/llsettingsbase.cpp new file mode 100644 index 0000000000..61b59e35aa --- /dev/null +++ b/indra/llinventory/llsettingsbase.cpp @@ -0,0 +1,751 @@ +/** +* @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 <algorithm> + +#include "llsdserialize.h" + +//========================================================================= +namespace +{ + const LLSettingsBase::TrackPosition BREAK_POINT = 0.5; +} + +const LLSettingsBase::TrackPosition LLSettingsBase::INVALID_TRACKPOS(-1.0); +const std::string LLSettingsBase::DEFAULT_SETTINGS_NAME("_default_"); + +//========================================================================= +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::FLAG_NOSAVE(0x01 << 3); + +const U32 LLSettingsBase::Validator::VALIDATION_PARTIAL(0x01 << 0); + +//========================================================================= +LLSettingsBase::LLSettingsBase(): + mSettings(LLSD::emptyMap()), + mDirty(true), + mBlendedFactor(0.0) +{ +} + +LLSettingsBase::LLSettingsBase(const LLSD setting) : + mSettings(setting), + mDirty(true), + 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 (LLSD::array_const_iterator ita = value.beginArray(); ita != value.endArray(); ++ita) + { + newSettings[key_name].append(*ita); + } + 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 (LLSD::array_const_iterator ita = value.beginArray(); ita != value.endArray(); ++ita) + { + newSettings[key_name].append(*ita); + } + 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(); + + llassert(mix >= 0.0f && mix <= 1.0f); + + 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 +{ + U32 flags = getFlags(); + LLSD settings (combineSDMaps(getSettings(), LLSD())); + if (flags) + settings[SETTING_FLAGS] = LLSD::Integer(flags); + return settings; +} + +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<LLSD> 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, 63)); + 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); + llassert(res >= 0.0 && res <= 1.0); + (void)res; + mTarget->update(); +} + +F64 LLSettingsBlender::setBlendFactor(const LLSettingsBase::BlendFactor& blendf_in) +{ + LLSettingsBase::TrackPosition blendf = blendf_in; + if (blendf >= 1.0) + { + triggerComplete(); + } + blendf = llclamp(blendf, 0.0f, 1.0f); + + if (mTarget) + { + mTarget->replaceSettings(mInitial->getSettings()); + 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(FLT_EPSILON); + +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; + + if (mTimeSpent > mBlendSpan) + { + triggerComplete(); + return false; + } + + LLSettingsBase::BlendFactor blendf = calculateBlend(mTimeSpent, mBlendSpan); + + 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..f7a9d5b7cd --- /dev/null +++ b/indra/llinventory/llsettingsbase.h @@ -0,0 +1,517 @@ +/** +* @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 <string> +#include <map> +#include <vector> +#include <boost/signals2.hpp> + +#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<LLSettingsBase>, + 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 DEFAULT_SETTINGS_NAME; + + 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; + static const U32 FLAG_NOSAVE; + + 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<std::string, DefaultParam> parammapping_t; + + typedef PTR_NAMESPACE::shared_ptr<LLSettingsBase> 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<U32>(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<LLSettingsBase *>(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<bool(LLSD &)> 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<Validator> 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<std::string> 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 *, bool force = false) { }; + + virtual parammapping_t getParameterMap() const { return parammapping_t(); } + + LLSD mSettings; + + 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<LLSettingsBlender> +{ + LOG_CLASS(LLSettingsBlender); +public: + typedef PTR_NAMESPACE::shared_ptr<LLSettingsBlender> ptr_t; + typedef boost::signals2::signal<void(const ptr_t )> 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), + 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); + mLastBlendF = LLSettingsBase::BlendFactor(-1.0f); + } + + virtual bool applyTimeDelta(const LLSettingsBase::Seconds& timedelta) SETTINGS_OVERRIDE; + + 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::BlendFactor mBlendFMinDelta; + LLSettingsBase::BlendFactor mLastBlendF; +}; + + +#endif diff --git a/indra/llinventory/llsettingsdaycycle.cpp b/indra/llinventory/llsettingsdaycycle.cpp new file mode 100644 index 0000000000..a687fd840d --- /dev/null +++ b/indra/llinventory/llsettingsdaycycle.cpp @@ -0,0 +1,896 @@ +/** +* @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 <algorithm> +#include <boost/make_shared.hpp> +#include "lltrace.h" +#include "llfasttimer.h" +#include "v3colorutil.h" + +#include "llsettingssky.h" +#include "llsettingswater.h" + +#include "llframetimer.h" + +//========================================================================= +namespace +{ + LLTrace::BlockTimerStatHandle FTM_BLEND_WATERVALUES("Blending Water Environment Day"); + LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERVALUES("Update Water Environment Day"); + + template<typename T> + 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("5646d39e-d3d7-6aff-ed71-30fc87d64a91"); + +// 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<std::string, LLSettingsBase::ptr_t> 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<std::string, LLSettingsBase::ptr_t>::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<std::string, LLSettingsBase::ptr_t> 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 (LLSD::array_const_iterator it = curtrack.beginArray(); it != curtrack.endArray(); ++it) + { + LLSettingsBase::TrackPosition keyframe = LLSettingsBase::TrackPosition((*it)[SETTING_KEYKFRAME].asReal()); + keyframe = llclamp(keyframe, 0.0f, 1.0f); + LLSettingsBase::ptr_t setting; + + + if ((*it).has(SETTING_KEYNAME)) + { + std::string key_name = (*it)[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_SETTINGS_NAME; + 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_SETTINGS_NAME); + 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 (LLSD::array_iterator track = value.beginArray(); track != value.endArray(); ++track) + { + S32 index = 0; + while (index < (*track).size()) + { + LLSD& elem = (*track)[index]; + + ++framecount; + if (index >= LLSettingsDay::FRAME_MAX) + { + (*track).erase(index); + continue; + } + + if (!elem.has(LLSettingsDay::SETTING_KEYKFRAME)) + { + (*track).erase(index); + continue; + } + + if (!elem[LLSettingsDay::SETTING_KEYKFRAME].isReal()) + { + (*track).erase(index); + continue; + } + + if (!elem.has(LLSettingsDay::SETTING_KEYNAME) && + !elem.has(LLSettingsDay::SETTING_KEYID)) + { + (*track).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(S32 track) +{ + static CycleTrack_t emptyTrack; + if (mDayTracks.size() <= track) + return emptyTrack; + + return mDayTracks[track]; +} + +const LLSettingsDay::CycleTrack_t& LLSettingsDay::getCycleTrackConst(S32 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 (llabs(old_frame - new_frame) < F_APPROXIMATELY_ZERO) + { + 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<LLSettingsSky>(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; + + LLSettingsDay::CycleTrack_t collection = const_cast<CycleTrack_t &>(mDayTracks[track]); + CycleTrack_t::iterator it = get_wrapping_atafter(collection, startframe); + + F32 dist = get_wrapping_distance(startframe, (*it).first); + + CycleTrack_t::iterator next_it = std::next(it); + if ((dist <= DEFAULT_MULTISLIDER_INCREMENT) && next_it != collection.end()) + return (*next_it); + else 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..f7f5bb63b6 --- /dev/null +++ b/indra/llinventory/llsettingsdaycycle.h @@ -0,0 +1,154 @@ +/** +* @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<LLSettingsWater> LLSettingsWaterPtr_t; +typedef PTR_NAMESPACE::shared_ptr<LLSettingsSky> 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<LLSettingsBase::TrackPosition, LLSettingsBase::ptr_t> CycleTrack_t; + typedef std::vector<CycleTrack_t> CycleList_t; + typedef PTR_NAMESPACE::shared_ptr<LLSettingsDay> ptr_t; + typedef PTR_NAMESPACE::weak_ptr<LLSettingsDay> wptr_t; + typedef std::vector<LLSettingsBase::TrackPosition> KeyframeList_t; + typedef std::pair<CycleTrack_t::iterator, CycleTrack_t::iterator> 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(S32 track); + const CycleTrack_t & getCycleTrackConst(S32 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; + + 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..81937dbda5 --- /dev/null +++ b/indra/llinventory/llsettingssky.cpp @@ -0,0 +1,1760 @@ +/** +* @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 <algorithm> +#include "lltrace.h" +#include "llfasttimer.h" +#include "v3colorutil.h" + +//========================================================================= +namespace +{ + 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("3ae23978-ac82-bcf3-a9cb-ba6e52dcb9ad"); + +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<LLSettingsSky>(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.4099, 0.4099, 0.4099, 0.0).getValue(); + dfltsetting[SETTING_CLOUD_POS_DENSITY1] = LLColor4(1.0000, 0.5260, 1.0000, 0.0).getValue(); + dfltsetting[SETTING_CLOUD_POS_DENSITY2] = LLColor4(1.0000, 0.5260, 1.0000, 0.0).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.000, 0.0010, -0.4799, 1.0).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(250.0000); + dfltsetting[SETTING_SUNLIGHT_COLOR] = LLColor4(0.7342, 0.7815, 0.8999, 0.0).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 +{ + return getIsSunUp() ? 1.0f : + getIsMoonUp() ? getMoonBrightness() * 0.25 : 0.0f; +} + +bool LLSettingsSky::getIsSunUp() const +{ + LLVector3 sunDir = getSunDirection(); + return sunDir.mV[2] >= 0.0f; +} + +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_neg; +} + +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::getColor(const std::string& key, const LLColor3& default_value) const +{ + if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(key)) + { + return LLColor3(mSettings[SETTING_LEGACY_HAZE][key]); + } + if (mSettings.has(key)) + { + return LLColor3(mSettings[key]); + } + return default_value; +} + +F32 LLSettingsSky::getFloat(const std::string& key, F32 default_value) const +{ + if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(key)) + { + return mSettings[SETTING_LEGACY_HAZE][key].asReal(); + } + if (mSettings.has(key)) + { + return mSettings[key].asReal(); + } + return default_value; +} + +LLColor3 LLSettingsSky::getAmbientColor() const +{ + return getColor(SETTING_AMBIENT, LLColor3(0.25f, 0.25f, 0.25f)); +} + +LLColor3 LLSettingsSky::getAmbientColorClamped() const +{ + LLColor3 ambient = getAmbientColor(); + + F32 max_color = llmax(ambient.mV[0], ambient.mV[1], ambient.mV[2]); + if (max_color > 1.0f) + { + ambient *= 1.0f/max_color; + } + + return ambient; +} + +LLColor3 LLSettingsSky::getBlueDensity() const +{ + return getColor(SETTING_BLUE_DENSITY, LLColor3(0.2447f, 0.4487f, 0.7599f)); +} + +LLColor3 LLSettingsSky::getBlueHorizon() const +{ + return getColor(SETTING_BLUE_HORIZON, LLColor3(0.4954f, 0.4954f, 0.6399f)); +} + +F32 LLSettingsSky::getHazeDensity() const +{ + return getFloat(SETTING_HAZE_DENSITY, 0.7f); +} + +F32 LLSettingsSky::getHazeHorizon() const +{ + return getFloat(SETTING_HAZE_HORIZON, 0.19f); +} + +F32 LLSettingsSky::getDensityMultiplier() const +{ + return getFloat(SETTING_DENSITY_MULTIPLIER, 0.0001f); +} + +F32 LLSettingsSky::getDistanceMultiplier() const +{ + return getFloat(SETTING_DISTANCE_MULTIPLIER, 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); +} + +// Get total from rayleigh and mie density values for normalization +LLColor3 LLSettingsSky::getTotalDensity() const +{ + LLColor3 blue_density = getBlueDensity(); + F32 haze_density = getHazeDensity(); + LLColor3 total_density = blue_density + smear(haze_density); + return total_density; +} + +// 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 +{ + F32 density_multiplier = getDensityMultiplier(); + LLColor3 blue_density = getBlueDensity(); + F32 haze_density = getHazeDensity(); + // Approximate line integral over requested distance + LLColor3 light_atten = (blue_density * 1.0 + smear(haze_density * 0.25f)) * density_multiplier * distance; + return light_atten; +} + +LLColor3 LLSettingsSky::getLightTransmittance(F32 distance) const +{ + LLColor3 total_density = getTotalDensity(); + F32 density_multiplier = getDensityMultiplier(); + // Transparency (-> density) from Beer's law + LLColor3 transmittance = componentExp(total_density * -(density_multiplier * distance)); + return transmittance; +} + +// performs soft scale clip and gamma correction ala the shader implementation +// scales colors down to 0 - 1 range preserving relative ratios +LLColor3 LLSettingsSky::gammaCorrect(const LLColor3& in) const +{ + F32 gamma = getGamma(); + + LLColor3 v(in); + // scale down to 0 to 1 range preserving relative ratio (aka homegenize) + F32 max_color = llmax(llmax(in.mV[0], in.mV[1]), in.mV[2]); + if (max_color > 1.0f) + { + v *= 1.0f / max_color; + } + + LLColor3 color = in * 2.0f; + color = smear(1.f) - componentSaturate(color); // clamping after mul seems wrong, but prevents negative colors... + componentPow(color, gamma); + color = smear(1.f) - color; + return color; +} + +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::getHazeColor() const +{ + update(); + return mHazeColor; +} + +LLColor4 LLSettingsSky::getTotalAmbient() const +{ + update(); + return mTotalAmbient; +} + +LLColor3 LLSettingsSky::getMoonlightColor() const +{ + return getSunlightColor(); //moon and sun share light color +} + +void LLSettingsSky::clampColor(LLColor3& color, F32 gamma, F32 scale) const +{ + F32 max_color = llmax(color.mV[0], color.mV[1], color.mV[2]); + if (max_color > scale) + { + color *= scale/max_color; + } + LLColor3 linear(color); + linear *= 1.0 / scale; + linear = smear(1.0f) - linear; + linear = componentPow(linear, gamma); + linear *= scale; + color = linear; +} + +// Similar/Shared Algorithms: +// indra\llinventory\llsettingssky.cpp -- LLSettingsSky::calculateLightSettings() +// indra\newview\app_settings\shaders\class1\windlight\atmosphericsFuncs.glsl -- calcAtmosphericVars() +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(max_y); + + // and vary_sunlight will work properly with moon light + const F32 LIMIT = FLT_EPSILON * 8.0f; + + F32 lighty = fabs(lightnorm[2]); + if(lighty >= LIMIT) + { + lighty = 1.f / lighty; + } + lighty = llmax(LIMIT, lighty); + componentMultBy(sunlight, componentExp((light_atten * -1.f) * lighty)); + componentMultBy(sunlight, light_transmittance); + + //increase ambient when there are more clouds + LLColor3 tmpAmbient = ambient + (smear(1.f) - ambient) * cloud_shadow * 0.5; + + //brightness of surface both sunlight and ambient + mSunDiffuse = sunlight; + mSunAmbient = tmpAmbient; + + F32 haze_horizon = getHazeHorizon(); + + sunlight *= 1.0 - cloud_shadow; + sunlight += tmpAmbient; + + mHazeColor = getBlueHorizon() * getBlueDensity() * sunlight; + mHazeColor += LLColor4(haze_horizon, haze_horizon, haze_horizon, haze_horizon) * getHazeDensity() * sunlight; + + F32 moon_brightness = getIsMoonUp() ? getMoonBrightness() : 0.001f; + + LLColor3 moonlight = getMoonlightColor(); + LLColor3 moonlight_b(0.66, 0.66, 1.2); // scotopic ambient value + + componentMultBy(moonlight, componentExp((light_atten * -1.f) * lighty)); + + mMoonDiffuse = componentMult(moonlight, light_transmittance) * moon_brightness; + mMoonAmbient = moonlight_b * 0.0125f; + + mTotalAmbient = ambient; +} + +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]); +} + +LLColor3 LLSettingsSky::getSunlightColorClamped() const +{ + LLColor3 sunlight = getSunlightColor(); + //clampColor(sunlight, getGamma(), 3.0f); + + F32 max_color = llmax(sunlight.mV[0], sunlight.mV[1], sunlight.mV[2]); + if (max_color > 1.0f) + { + sunlight *= 1.0f/max_color; + } + + return sunlight; +} + +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..4127911643 --- /dev/null +++ b/indra/llinventory/llsettingssky.h @@ -0,0 +1,374 @@ +/** +* @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<LLSettingsSky> 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(F32 distance) const; + LLColor3 getTotalDensity() 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; + + // color based on brightness + LLColor3 getMoonlightColor() const; + + LLColor4 getMoonAmbient() const; + LLColor3 getMoonDiffuse() const; + LLColor4 getSunAmbient() const; + LLColor3 getSunDiffuse() const; + LLColor4 getTotalAmbient() const; + LLColor4 getHazeColor() const; + + LLColor3 getSunlightColorClamped() const; + LLColor3 getAmbientColorClamped() 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(); + + LLColor3 getColor(const std::string& key, const LLColor3& default_value) const; + F32 getFloat(const std::string& key, F32 default_value) const; + + void calculateHeavenlyBodyPositions() const; + void calculateLightSettings() const; + void clampColor(LLColor3& color, F32 gamma, const F32 scale = 1.0f) 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; + mutable LLColor4 mHazeColor; + + typedef std::map<std::string, S32> 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..0eb95dcd89 --- /dev/null +++ b/indra/llinventory/llsettingswater.cpp @@ -0,0 +1,304 @@ +/** +* @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 <algorithm> +#include <boost/make_shared.hpp> +#include "lltrace.h" +#include "llfasttimer.h" +#include "v3colorutil.h" +#include "indra_constants.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<LLSettingsWater>(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<LLSettingsWater> 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/tests/inventorymisc_test.cpp b/indra/llinventory/tests/inventorymisc_test.cpp index 7b15552f24..e8b063bffe 100644 --- a/indra/llinventory/tests/inventorymisc_test.cpp +++ b/indra/llinventory/tests/inventorymisc_test.cpp @@ -28,9 +28,9 @@ #include "linden_common.h" #include "llsd.h" +#include "llsdserialize.h" #include "../llinventory.h" - #include "../test/lltut.h" @@ -320,27 +320,39 @@ namespace tut template<> template<> void inventory_object::test<7>() { - LLFILE* fp = LLFile::fopen("linden_file.dat","w+"); - if(!fp) + std::string filename("linden_file.dat"); + llofstream fileXML(filename.c_str()); + if (!fileXML.is_open()) { LL_ERRS() << "file could not be opened\n" << LL_ENDL; return; } LLPointer<LLInventoryItem> src1 = create_random_inventory_item(); - src1->exportFile(fp, TRUE); - fclose(fp); + fileXML << LLSDOStreamer<LLSDNotationFormatter>(src1->asLLSD()) << std::endl; + fileXML.close(); - LLPointer<LLInventoryItem> src2 = new LLInventoryItem(); - fp = LLFile::fopen("linden_file.dat","r+"); - if(!fp) + + LLPointer<LLInventoryItem> src2 = new LLInventoryItem(); + llifstream file(filename.c_str()); + if (!file.is_open()) { LL_ERRS() << "file could not be opened\n" << LL_ENDL; return; } - - src2->importFile(fp); - fclose(fp); + std::string line; + LLPointer<LLSDParser> parser = new LLSDNotationParser(); + std::getline(file, line); + LLSD s_item; + std::istringstream iss(line); + if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) + { + LL_ERRS()<< "Parsing cache failed" << LL_ENDL; + return; + } + src2->fromLLSD(s_item); + + file.close(); ensure_equals("1.item id::getUUID() failed", src1->getUUID(), src2->getUUID()); ensure_equals("2.parent::getParentUUID() failed", src1->getParentUUID(), src2->getParentUUID()); @@ -457,27 +469,39 @@ namespace tut template<> template<> void inventory_object::test<13>() { - LLFILE* fp = LLFile::fopen("linden_file.dat","w"); - if(!fp) + std::string filename("linden_file.dat"); + llofstream fileXML(filename.c_str()); + if (!fileXML.is_open()) { - LL_ERRS() << "file coudnt be opened\n" << LL_ENDL; + LL_ERRS() << "file could not be opened\n" << LL_ENDL; return; } - + LLPointer<LLInventoryCategory> src1 = create_random_inventory_cat(); - src1->exportFile(fp, TRUE); - fclose(fp); + fileXML << LLSDOStreamer<LLSDNotationFormatter>(src1->exportLLSD()) << std::endl; + fileXML.close(); - LLPointer<LLInventoryCategory> src2 = new LLInventoryCategory(); - fp = LLFile::fopen("linden_file.dat","r"); - if(!fp) + llifstream file(filename.c_str()); + if (!file.is_open()) { - LL_ERRS() << "file coudnt be opened\n" << LL_ENDL; + LL_ERRS() << "file could not be opened\n" << LL_ENDL; return; } - - src2->importFile(fp); - fclose(fp); + std::string line; + LLPointer<LLSDParser> parser = new LLSDNotationParser(); + std::getline(file, line); + LLSD s_item; + std::istringstream iss(line); + if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) + { + LL_ERRS()<< "Parsing cache failed" << LL_ENDL; + return; + } + + file.close(); + + LLPointer<LLInventoryCategory> src2 = new LLInventoryCategory(); + src2->importLLSD(s_item); ensure_equals("1.item id::getUUID() failed", src1->getUUID(), src2->getUUID()); ensure_equals("2.parent::getParentUUID() failed", src1->getParentUUID(), src2->getParentUUID()); diff --git a/indra/llkdu/include_kdu_xxxx.h b/indra/llkdu/include_kdu_xxxx.h index a1dbced60b..61204b5689 100644 --- a/indra/llkdu/include_kdu_xxxx.h +++ b/indra/llkdu/include_kdu_xxxx.h @@ -16,7 +16,7 @@ // #include "include_kdu_xxxx.h" // // kdu_xxxx #undef'ed by include_kdu_xxxx.h -#if LL_DARWIN +#if __clang__ // don't *really* want to rebuild KDU so turn off specific warnings for this header #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wself-assign-field" diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index 4048b9a43d..dac5349f57 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -44,16 +44,19 @@ using namespace kdu_core; #include <sstream> #include <iomanip> -// stream kdu_dims to std::ostream // Turns out this must NOT be in the anonymous namespace! -// It must also precede #include "stringize.h". +namespace kdu_core +{ +// stream kdu_dims to std::ostream inline std::ostream& operator<<(std::ostream& out, const kdu_dims& dims) { return out << "(" << dims.pos.x << "," << dims.pos.y << ")," "[" << dims.size.x << "x" << dims.size.y << "]"; } +} // namespace kdu_core +// operator<<(std::ostream&, const kdu_dims&) must precede #include "stringize.h" #include "stringize.h" namespace { diff --git a/indra/llkdu/tests/llimagej2ckdu_test.cpp b/indra/llkdu/tests/llimagej2ckdu_test.cpp index 79ed566d00..ee7b14be85 100644 --- a/indra/llkdu/tests/llimagej2ckdu_test.cpp +++ b/indra/llkdu/tests/llimagej2ckdu_test.cpp @@ -29,7 +29,7 @@ // Class to test #include "llimagej2ckdu.h" -#if LL_DARWIN +#if __clang__ // For this source, it's true that private fields in llkdumem.h are unused. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-private-field" diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt index 379c3ee9ea..552e820127 100644 --- a/indra/llmath/CMakeLists.txt +++ b/indra/llmath/CMakeLists.txt @@ -4,6 +4,7 @@ project(llmath) include(00-Common) include(LLCommon) +include(bugsplat) include(Boost) include_directories( @@ -90,6 +91,7 @@ set(llmath_HEADER_FILES raytrace.h v2math.h v3color.h + v3colorutil.h v3dmath.h v3math.h v4color.h diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp index ff90532f75..9034182072 100644 --- a/indra/llmath/llcamera.cpp +++ b/indra/llmath/llcamera.cpp @@ -93,6 +93,11 @@ F32 LLCamera::getMaxView() const : MAX_FIELD_OF_VIEW; // narrow views } +LLPlane LLCamera::getUserClipPlane() +{ + return mAgentPlanes[AGENT_PLANE_USER_CLIP]; +} + // ---------------- LLCamera::setFoo() member functions ---------------- void LLCamera::setUserClipPlane(LLPlane& plane) diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h index 321b8ddcc4..d0afa0e88f 100644 --- a/indra/llmath/llcamera.h +++ b/indra/llmath/llcamera.h @@ -154,6 +154,7 @@ public: bool isChanged(); //check if mAgentPlanes changed since last frame. + LLPlane getUserClipPlane(); void setUserClipPlane(LLPlane& plane); void disableUserClipPlane(); virtual void setView(F32 vertical_fov_rads); diff --git a/indra/llmath/llcoordframe.cpp b/indra/llmath/llcoordframe.cpp index 1bf51ca0eb..b25fd948f5 100644 --- a/indra/llmath/llcoordframe.cpp +++ b/indra/llmath/llcoordframe.cpp @@ -34,6 +34,20 @@ #include "llquaternion.h" #include "llcoordframe.h" +#define CHECK_FINITE(var) \ + if (!var.isFinite()) \ + { \ + LL_WARNS() << "Non Finite " << std::string(#var) << LL_ENDL; \ + reset(); \ + } + +#define CHECK_FINITE_OBJ() \ + if (!isFinite()) \ + { \ + LL_WARNS() << "Non Finite in LLCoordFrame " << LL_ENDL; \ + reset(); \ + } + #ifndef X_AXIS #define X_AXIS 1.0f,0.0f,0.0f #define Y_AXIS 0.0f,1.0f,0.0f @@ -56,11 +70,7 @@ LLCoordFrame::LLCoordFrame(const LLVector3 &origin) : mYAxis(Y_AXIS), mZAxis(Z_AXIS) { - if( !mOrigin.isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL; - } + CHECK_FINITE(mOrigin); } LLCoordFrame::LLCoordFrame(const LLVector3 &origin, const LLVector3 &direction) : @@ -68,11 +78,7 @@ LLCoordFrame::LLCoordFrame(const LLVector3 &origin, const LLVector3 &direction) { lookDir(direction); - if( !isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } LLCoordFrame::LLCoordFrame(const LLVector3 &x_axis, @@ -83,11 +89,7 @@ LLCoordFrame::LLCoordFrame(const LLVector3 &x_axis, mYAxis(y_axis), mZAxis(z_axis) { - if( !isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } LLCoordFrame::LLCoordFrame(const LLVector3 &origin, @@ -99,11 +101,7 @@ LLCoordFrame::LLCoordFrame(const LLVector3 &origin, mYAxis(y_axis), mZAxis(z_axis) { - if( !isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } @@ -114,11 +112,7 @@ LLCoordFrame::LLCoordFrame(const LLVector3 &origin, mYAxis(rotation.mMatrix[VY]), mZAxis(rotation.mMatrix[VZ]) { - if( !isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } LLCoordFrame::LLCoordFrame(const LLQuaternion &q) : @@ -129,11 +123,7 @@ LLCoordFrame::LLCoordFrame(const LLQuaternion &q) : mYAxis.setVec(rotation_matrix.mMatrix[VY]); mZAxis.setVec(rotation_matrix.mMatrix[VZ]); - if( !isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } LLCoordFrame::LLCoordFrame(const LLVector3 &origin, const LLQuaternion &q) : @@ -144,11 +134,7 @@ LLCoordFrame::LLCoordFrame(const LLVector3 &origin, const LLQuaternion &q) : mYAxis.setVec(rotation_matrix.mMatrix[VY]); mZAxis.setVec(rotation_matrix.mMatrix[VZ]); - if( !isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } LLCoordFrame::LLCoordFrame(const LLMatrix4 &mat) : @@ -157,11 +143,7 @@ LLCoordFrame::LLCoordFrame(const LLMatrix4 &mat) : mYAxis(mat.mMatrix[VY]), mZAxis(mat.mMatrix[VZ]) { - if( !isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } @@ -173,11 +155,7 @@ LLCoordFrame::LLCoordFrame(const F32 *origin, const F32 *rotation) : mYAxis(rotation+3*VY), mZAxis(rotation+3*VZ) { - if( !isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } */ @@ -188,11 +166,7 @@ LLCoordFrame::LLCoordFrame(const F32 *origin_and_rotation) : mYAxis(origin_and_rotation + 3*(VY+1)), mZAxis(origin_and_rotation + 3*(VZ+1)) { - if( !isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } */ @@ -217,21 +191,13 @@ void LLCoordFrame::setOrigin(F32 x, F32 y, F32 z) { mOrigin.setVec(x, y, z); - if( !mOrigin.isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::setOrigin()" << LL_ENDL; - } + CHECK_FINITE(mOrigin); } void LLCoordFrame::setOrigin(const LLVector3 &new_origin) { mOrigin = new_origin; - if( !mOrigin.isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::setOrigin()" << LL_ENDL; - } + CHECK_FINITE(mOrigin); } void LLCoordFrame::setOrigin(const F32 *origin) @@ -239,23 +205,13 @@ void LLCoordFrame::setOrigin(const F32 *origin) mOrigin.mV[VX] = *(origin + VX); mOrigin.mV[VY] = *(origin + VY); mOrigin.mV[VZ] = *(origin + VZ); - - if( !mOrigin.isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::setOrigin()" << LL_ENDL; - } + CHECK_FINITE(mOrigin); } void LLCoordFrame::setOrigin(const LLCoordFrame &frame) { mOrigin = frame.getOrigin(); - - if( !mOrigin.isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::setOrigin()" << LL_ENDL; - } + CHECK_FINITE(mOrigin); } // setAxes() member functions set the axes, and assume that @@ -268,11 +224,7 @@ void LLCoordFrame::setAxes(const LLVector3 &x_axis, mXAxis = x_axis; mYAxis = y_axis; mZAxis = z_axis; - if( !isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::setAxes()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } @@ -281,11 +233,7 @@ void LLCoordFrame::setAxes(const LLMatrix3 &rotation_matrix) mXAxis.setVec(rotation_matrix.mMatrix[VX]); mYAxis.setVec(rotation_matrix.mMatrix[VY]); mZAxis.setVec(rotation_matrix.mMatrix[VZ]); - if( !isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::setAxes()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } @@ -293,11 +241,7 @@ void LLCoordFrame::setAxes(const LLQuaternion &q ) { LLMatrix3 rotation_matrix(q); setAxes(rotation_matrix); - if( !isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::setAxes()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } @@ -313,11 +257,7 @@ void LLCoordFrame::setAxes( const F32 *rotation_matrix ) mZAxis.mV[VY] = *(rotation_matrix + 3*VZ + VY); mZAxis.mV[VZ] = *(rotation_matrix + 3*VZ + VZ); - if( !isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::setAxes()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } @@ -326,40 +266,22 @@ void LLCoordFrame::setAxes(const LLCoordFrame &frame) mXAxis = frame.getXAxis(); mYAxis = frame.getYAxis(); mZAxis = frame.getZAxis(); - - if( !isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::setAxes()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } - // translate() member functions move mOrigin to a relative position - void LLCoordFrame::translate(F32 x, F32 y, F32 z) { mOrigin.mV[VX] += x; mOrigin.mV[VY] += y; mOrigin.mV[VZ] += z; - - if( !mOrigin.isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::translate()" << LL_ENDL; - } + CHECK_FINITE(mOrigin); } - void LLCoordFrame::translate(const LLVector3 &v) { mOrigin += v; - - if( !mOrigin.isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::translate()" << LL_ENDL; - } + CHECK_FINITE(mOrigin); } @@ -368,12 +290,7 @@ void LLCoordFrame::translate(const F32 *origin) mOrigin.mV[VX] += *(origin + VX); mOrigin.mV[VY] += *(origin + VY); mOrigin.mV[VZ] += *(origin + VZ); - - if( !mOrigin.isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::translate()" << LL_ENDL; - } + CHECK_FINITE(mOrigin); } @@ -383,6 +300,7 @@ void LLCoordFrame::rotate(F32 angle, F32 x, F32 y, F32 z) { LLQuaternion q(angle, LLVector3(x,y,z)); rotate(q); + CHECK_FINITE_OBJ(); } @@ -390,6 +308,7 @@ void LLCoordFrame::rotate(F32 angle, const LLVector3 &rotation_axis) { LLQuaternion q(angle, rotation_axis); rotate(q); + CHECK_FINITE_OBJ(); } @@ -397,6 +316,7 @@ void LLCoordFrame::rotate(const LLQuaternion &q) { LLMatrix3 rotation_matrix(q); rotate(rotation_matrix); + CHECK_FINITE_OBJ(); } @@ -405,12 +325,7 @@ void LLCoordFrame::rotate(const LLMatrix3 &rotation_matrix) mXAxis.rotVec(rotation_matrix); mYAxis.rotVec(rotation_matrix); orthonormalize(); - - if( !isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::rotate()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } @@ -419,12 +334,7 @@ void LLCoordFrame::roll(F32 angle) LLQuaternion q(angle, mXAxis); LLMatrix3 rotation_matrix(q); rotate(rotation_matrix); - - if( !mYAxis.isFinite() || !mZAxis.isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::roll()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } void LLCoordFrame::pitch(F32 angle) @@ -432,12 +342,7 @@ void LLCoordFrame::pitch(F32 angle) LLQuaternion q(angle, mYAxis); LLMatrix3 rotation_matrix(q); rotate(rotation_matrix); - - if( !mXAxis.isFinite() || !mZAxis.isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::pitch()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } void LLCoordFrame::yaw(F32 angle) @@ -445,12 +350,7 @@ void LLCoordFrame::yaw(F32 angle) LLQuaternion q(angle, mZAxis); LLMatrix3 rotation_matrix(q); rotate(rotation_matrix); - - if( !mXAxis.isFinite() || !mYAxis.isFinite() ) - { - reset(); - LL_WARNS() << "Non Finite in LLCoordFrame::yaw()" << LL_ENDL; - } + CHECK_FINITE_OBJ(); } // get*() routines diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h index e508c9a199..e4ccd81faf 100644 --- a/indra/llmath/llmath.h +++ b/indra/llmath/llmath.h @@ -47,9 +47,6 @@ #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<double>::max()) #else #define llisnan(val) std::isnan(val) #define llfinite(val) std::isfinite(val) @@ -537,6 +534,35 @@ inline void ll_remove_outliers(std::vector<VEC_TYPE>& data, F32 k) } } +// Converts given value from a linear RGB floating point value (0..1) to a gamma corrected (sRGB) value. +// Some shaders require color values in linear space, while others require color values in gamma corrected (sRGB) space. +// Note: in our code, values labeled as sRGB are ALWAYS gamma corrected linear values, NOT linear values with monitor gamma applied +// Note: stored color values should always be gamma corrected linear (i.e. the values returned from an on-screen color swatch) +// Note: DO NOT cache the conversion. This leads to error prone synchronization and is actually slower in the typical case due to cache misses +inline float linearTosRGB(const float val) { + if (val < 0.0031308f) { + return val * 12.92f; + } + else { + return 1.055f * pow(val, 1.0f / 2.4f) - 0.055f; + } +} + +// Converts given value from a gamma corrected (sRGB) floating point value (0..1) to a linear color value. +// Some shaders require color values in linear space, while others require color values in gamma corrected (sRGB) space. +// Note: In our code, values labeled as sRGB are gamma corrected linear values, NOT linear values with monitor gamma applied +// Note: Stored color values should generally be gamma corrected sRGB. +// If you're serializing the return value of this function, you're probably doing it wrong. +// Note: DO NOT cache the conversion. This leads to error prone synchronization and is actually slower in the typical case due to cache misses. +inline float sRGBtoLinear(const float val) { + if (val < 0.04045f) { + return val / 12.92f; + } + else { + return pow((val + 0.055f) / 1.055f, 2.4f); + } +} + // Include simd math header #include "llsimdmath.h" diff --git a/indra/llmath/llquaternion.cpp b/indra/llmath/llquaternion.cpp index 47374c287f..57a976b57a 100644 --- a/indra/llmath/llquaternion.cpp +++ b/indra/llmath/llquaternion.cpp @@ -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) { @@ -860,6 +865,26 @@ void LLQuaternion::getAngleAxis(F32* angle, LLVector3 &vec) const } } +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 { diff --git a/indra/llmath/llquaternion.h b/indra/llmath/llquaternion.h index aa0b1752f4..51ce163b4e 100644 --- a/indra/llmath/llquaternion.h +++ b/indra/llmath/llquaternion.h @@ -28,6 +28,7 @@ #define LLQUATERNION_H #include <iostream> +#include "llsd.h" #ifndef LLMATH_H //enforce specific include order to avoid tangling inline dependencies #error "Please include llmath.h first." @@ -63,6 +64,10 @@ public: 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; @@ -79,7 +84,8 @@ public: 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) const LLQuaternion& setAngleAxis(F32 angle, const LLVector4 &vec); // Sets Quaternion to axis_angle2quat(angle, vec) @@ -100,6 +106,7 @@ public: 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 @@ -166,6 +173,24 @@ public: //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(); +} + // checker inline BOOL LLQuaternion::isFinite() const { diff --git a/indra/llmath/llsdutil_math.cpp b/indra/llmath/llsdutil_math.cpp index 591f7fde36..51e5e3764f 100644 --- a/indra/llmath/llsdutil_math.cpp +++ b/indra/llmath/llsdutil_math.cpp @@ -40,7 +40,7 @@ #if LL_WINDOWS # define WIN32_LEAN_AND_MEAN # include <winsock2.h> // for htonl -#elif LL_LINUX || LL_SOLARIS +#elif LL_LINUX # include <netinet/in.h> #elif LL_DARWIN # include <arpa/inet.h> diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h index 222f3cf235..27abf39537 100644 --- a/indra/llmath/llvector4a.h +++ b/indra/llmath/llvector4a.h @@ -46,10 +46,10 @@ class LLRotation; // of this writing, July 08, 2010) about getting it implemented before you resort to // LLVector3/LLVector4. ///////////////////////////////// -class LLVector4a; +struct LLVector4a; LL_ALIGN_PREFIX(16) -class LLVector4a +struct LLVector4a { public: @@ -92,6 +92,7 @@ public: // CONSTRUCTORS //////////////////////////////////// + //LLVector4a is plain data which should never have a default constructor or destructor(malloc&free won't trigger it) LLVector4a() { //DO NOT INITIALIZE -- The overhead is completely unnecessary ll_assert_aligned(this,16); diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index e7a8ca2f9d..e085fa6ada 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2205,7 +2205,6 @@ BOOL LLVolume::generate() { rot_mat.rotate(*profile++, tmp); dst->setAdd(tmp,offset); - llassert(dst->isFinite3()); // MAINT-5660; don't know why this happens, does not affect Release builds ++dst; } } @@ -2400,9 +2399,9 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) { //face has no geometry, continue face.resizeIndices(3); face.resizeVertices(1); - memset(face.mPositions, 0, sizeof(LLVector4a)); - memset(face.mNormals, 0, sizeof(LLVector4a)); - memset(face.mTexCoords, 0, sizeof(LLVector2)); + face.mPositions->clear(); + face.mNormals->clear(); + face.mTexCoords->setZero(); memset(face.mIndices, 0, sizeof(U16)*3); continue; } @@ -2419,7 +2418,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) if (idx.empty() || face.mNumIndices < 3) { //why is there an empty index list? - LL_WARNS() <<"Empty face present!" << LL_ENDL; + LL_WARNS() << "Empty face present! Face index: " << i << " Total: " << face_count << LL_ENDL; continue; } @@ -2490,7 +2489,11 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) } else { - memset(norm_out, 0, sizeof(LLVector4a)*num_verts); + for (U32 j = 0; j < num_verts; ++j) + { + norm_out->clear(); + norm_out++; // or just norm_out[j].clear(); + } } } @@ -2520,7 +2523,11 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) } else { - memset(tc_out, 0, sizeof(LLVector2)*num_verts); + for (U32 j = 0; j < num_verts; j += 2) + { + tc_out->clear(); + tc_out++; + } } } @@ -4657,6 +4664,10 @@ LLVolumeFace::LLVolumeFace() : mTexCoords(NULL), mIndices(NULL), mWeights(NULL), +#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS + mJustWeights(NULL), + mJointIndices(NULL), +#endif mWeightsScrubbed(FALSE), mOctree(NULL), mOptimized(FALSE) @@ -4683,6 +4694,10 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src) mTexCoords(NULL), mIndices(NULL), mWeights(NULL), +#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS + mJustWeights(NULL), + mJointIndices(NULL), +#endif mWeightsScrubbed(FALSE), mOctree(NULL) { @@ -4747,24 +4762,46 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src) if (src.mWeights) { + llassert(!mWeights); // don't orphan an old alloc here accidentally allocateWeights(src.mNumVertices); - LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size); + LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size); + mWeightsScrubbed = src.mWeightsScrubbed; } else { - ll_aligned_free_16(mWeights); - mWeights = NULL; - } - mWeightsScrubbed = src.mWeightsScrubbed; - } + ll_aligned_free_16(mWeights); + mWeights = NULL; + mWeightsScrubbed = FALSE; + } + + #if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS + if (src.mJointIndices) + { + llassert(!mJointIndices); // don't orphan an old alloc here accidentally + allocateJointIndices(src.mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mJointIndices, (F32*) src.mJointIndices, src.mNumVertices * sizeof(U8) * 4); + } + else*/ + { + ll_aligned_free_16(mJointIndices); + mJointIndices = NULL; + } + #endif + } + if (mNumIndices) { S32 idx_size = (mNumIndices*sizeof(U16)+0xF) & ~0xF; LLVector4a::memcpyNonAliased16((F32*) mIndices, (F32*) src.mIndices, idx_size); } - + else + { + ll_aligned_free_16(mIndices); + mIndices = NULL; + } + mOptimized = src.mOptimized; //delete @@ -4796,6 +4833,13 @@ void LLVolumeFace::freeData() ll_aligned_free_16(mWeights); mWeights = NULL; +#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS + ll_aligned_free_16(mJointIndices); + mJointIndices = NULL; + ll_aligned_free_16(mJustWeights); + mJustWeights = NULL; +#endif + delete mOctree; mOctree = NULL; } @@ -5197,9 +5241,9 @@ public: LLVCacheTriangleData* tri = *iter; if (tri->mActive) { - tri->mScore = tri->mVertex[0]->mScore; - tri->mScore += tri->mVertex[1]->mScore; - tri->mScore += tri->mVertex[2]->mScore; + tri->mScore = tri->mVertex[0] ? tri->mVertex[0]->mScore : 0; + tri->mScore += tri->mVertex[1] ? tri->mVertex[1]->mScore : 0; + tri->mScore += tri->mVertex[2] ? tri->mVertex[2]->mScore : 0; if (!mBestTriangle || mBestTriangle->mScore < tri->mScore) { @@ -5236,7 +5280,7 @@ bool LLVolumeFace::cacheOptimize() LLVCacheLRU cache; - if (mNumVertices < 3) + if (mNumVertices < 3 || mNumIndices < 3) { //nothing to do return true; } @@ -5252,7 +5296,7 @@ bool LLVolumeFace::cacheOptimize() triangle_data.resize(mNumIndices / 3); vertex_data.resize(mNumVertices); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { LL_WARNS("LLVOLUME") << "Resize failed" << LL_ENDL; return false; @@ -5406,7 +5450,7 @@ bool LLVolumeFace::cacheOptimize() { new_idx.resize(mNumVertices, -1); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { ll_aligned_free<64>(pos); ll_aligned_free_16(wght); @@ -5449,11 +5493,17 @@ bool LLVolumeFace::cacheOptimize() // DO NOT free mNormals and mTexCoords as they are part of mPositions buffer ll_aligned_free_16(mWeights); ll_aligned_free_16(mTangents); +#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS + ll_aligned_free_16(mJointIndices); + ll_aligned_free_16(mJustWeights); + mJustWeights = NULL; + mJointIndices = NULL; // filled in later as necessary by skinning code for acceleration +#endif mPositions = pos; mNormals = norm; mTexCoords = tc; - mWeights = wght; + mWeights = wght; mTangents = binorm; //std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks); @@ -6363,7 +6413,19 @@ void LLVolumeFace::allocateTangents(S32 num_verts) void LLVolumeFace::allocateWeights(S32 num_verts) { ll_aligned_free_16(mWeights); - mWeights = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); + mWeights = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); + +} + +void LLVolumeFace::allocateJointIndices(S32 num_verts) +{ +#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS + ll_aligned_free_16(mJointIndices); + ll_aligned_free_16(mJustWeights); + + mJointIndices = (U8*)ll_aligned_malloc_16(sizeof(U8) * 4 * num_verts); + mJustWeights = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a) * num_verts); +#endif } void LLVolumeFace::resizeIndices(S32 num_indices) @@ -6914,11 +6976,16 @@ void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVe { //LLVector4a *tan1 = new LLVector4a[vertexCount * 2]; LLVector4a* tan1 = (LLVector4a*) ll_aligned_malloc_16(vertexCount*2*sizeof(LLVector4a)); + // new(tan1) LLVector4a; LLVector4a* tan2 = tan1 + vertexCount; - memset(tan1, 0, vertexCount*2*sizeof(LLVector4a)); - + U32 count = vertexCount * 2; + for (U32 i = 0; i < count; i++) + { + tan1[i].clear(); + } + for (U32 a = 0; a < triangleCount; a++) { U32 i1 = *index_array++; diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 1d6d35c432..a77e8c08c6 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -875,6 +875,7 @@ public: void resizeVertices(S32 num_verts); void allocateTangents(S32 num_verts); void allocateWeights(S32 num_verts); + void allocateJointIndices(S32 num_verts); void resizeIndices(S32 num_indices); void fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx); @@ -956,6 +957,11 @@ public: // mWeights.size() should be empty or match mVertices.size() LLVector4a* mWeights; +#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS + LLVector4a* mJustWeights; + U8* mJointIndices; +#endif + mutable BOOL mWeightsScrubbed; // Which joints are rigged to, and the bounding box of any rigged diff --git a/indra/llmath/m3math.cpp b/indra/llmath/m3math.cpp index 802ddb9e57..65eb3348de 100644 --- a/indra/llmath/m3math.cpp +++ b/indra/llmath/m3math.cpp @@ -75,13 +75,6 @@ LLMatrix3::LLMatrix3(const F32 angle, const LLVector4 &vec) setRot(quat); } -LLMatrix3::LLMatrix3(const F32 angle, const F32 x, const F32 y, const F32 z) -{ - LLVector3 vec(x, y, z); - LLQuaternion quat(angle, vec); - setRot(quat); -} - LLMatrix3::LLMatrix3(const F32 roll, const F32 pitch, const F32 yaw) { setRot(roll,pitch,yaw); @@ -294,14 +287,6 @@ LLQuaternion LLMatrix3::quaternion() const return quat; } - -// These functions take Rotation arguments -const LLMatrix3& LLMatrix3::setRot(const F32 angle, const F32 x, const F32 y, const F32 z) -{ - setRot(LLQuaternion(angle,x,y,z)); - return *this; -} - const LLMatrix3& LLMatrix3::setRot(const F32 angle, const LLVector3 &vec) { setRot(LLQuaternion(angle, vec)); @@ -394,15 +379,6 @@ const LLMatrix3& LLMatrix3::setCol( U32 colIndex, const LLVector3& col ) return *this; } - -// Rotate exisitng mMatrix -const LLMatrix3& LLMatrix3::rotate(const F32 angle, const F32 x, const F32 y, const F32 z) -{ - LLMatrix3 mat(angle, x, y, z); - *this *= mat; - return *this; -} - const LLMatrix3& LLMatrix3::rotate(const F32 angle, const LLVector3 &vec) { diff --git a/indra/llmath/m3math.h b/indra/llmath/m3math.h index 2be5452f8d..bf38895855 100644 --- a/indra/llmath/m3math.h +++ b/indra/llmath/m3math.h @@ -60,7 +60,6 @@ class LLMatrix3 explicit LLMatrix3(const F32 *mat); // Initializes Matrix to values in mat explicit LLMatrix3(const LLQuaternion &q); // Initializes Matrix with rotation q - LLMatrix3(const F32 angle, const F32 x, const F32 y, const F32 z); // Initializes Matrix with axis angle LLMatrix3(const F32 angle, const LLVector3 &vec); // Initializes Matrix with axis angle LLMatrix3(const F32 angle, const LLVector3d &vec); // Initializes Matrix with axis angle LLMatrix3(const F32 angle, const LLVector4 &vec); // Initializes Matrix with axis angle @@ -81,8 +80,7 @@ class LLMatrix3 // Matrix setters - set some properties without modifying others // - // These functions take Rotation arguments - const LLMatrix3& setRot(const F32 angle, const F32 x, const F32 y, const F32 z); // Calculate rotation matrix for rotating angle radians about (x, y, z) + // These functions take Rotation arguments const LLMatrix3& setRot(const F32 angle, const LLVector3 &vec); // Calculate rotation matrix for rotating angle radians about vec const LLMatrix3& setRot(const F32 roll, const F32 pitch, const F32 yaw); // Calculate rotation matrix from Euler angles const LLMatrix3& setRot(const LLQuaternion &q); // Transform matrix by Euler angles and translating by pos diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp index d89c482804..3baf1bad18 100644 --- a/indra/llmath/m4math.cpp +++ b/indra/llmath/m4math.cpp @@ -384,13 +384,6 @@ void LLMatrix4::initRows(const LLVector4 &row0, } -const LLMatrix4& LLMatrix4::initRotation(const F32 angle, const F32 x, const F32 y, const F32 z) -{ - LLMatrix3 mat(angle, x, y, z); - return initMatrix(mat); -} - - const LLMatrix4& LLMatrix4::initRotation(F32 angle, const LLVector4 &vec) { LLMatrix3 mat(angle, vec); @@ -412,17 +405,6 @@ const LLMatrix4& LLMatrix4::initRotation(const LLQuaternion &q) } -// Position and Rotation -const LLMatrix4& LLMatrix4::initRotTrans(const F32 angle, const F32 rx, const F32 ry, const F32 rz, - const F32 tx, const F32 ty, const F32 tz) -{ - LLMatrix3 mat(angle, rx, ry, rz); - LLVector3 translation(tx, ty, tz); - initMatrix(mat); - setTranslation(translation); - return (*this); -} - const LLMatrix4& LLMatrix4::initRotTrans(const F32 angle, const LLVector3 &axis, const LLVector3&translation) { LLMatrix3 mat(angle, axis); @@ -513,15 +495,6 @@ const LLMatrix4& LLMatrix4::initAll(const LLVector3 &scale, const LLQuaternion & return (*this); } -// Rotate exisitng mMatrix -const LLMatrix4& LLMatrix4::rotate(const F32 angle, const F32 x, const F32 y, const F32 z) -{ - LLVector4 vec4(x, y, z); - LLMatrix4 mat(angle, vec4); - *this *= mat; - return *this; -} - const LLMatrix4& LLMatrix4::rotate(const F32 angle, const LLVector4 &vec) { LLMatrix4 mat(angle, vec); diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h index a77c5bc76d..bf60adb9b6 100644 --- a/indra/llmath/m4math.h +++ b/indra/llmath/m4math.h @@ -137,7 +137,6 @@ public: bool isIdentity() const; const LLMatrix4& setZero(); // Clears matrix to all zeros. - const LLMatrix4& initRotation(const F32 angle, const F32 x, const F32 y, const F32 z); // Calculate rotation matrix by rotating angle radians about (x, y, z) const LLMatrix4& initRotation(const F32 angle, const LLVector4 &axis); // Calculate rotation matrix for rotating angle radians about vec const LLMatrix4& initRotation(const F32 roll, const F32 pitch, const F32 yaw); // Calculate rotation matrix from Euler angles const LLMatrix4& initRotation(const LLQuaternion &q); // Set with Quaternion and position @@ -148,10 +147,6 @@ public: // These operation create a matrix that will rotate and translate by the // specified amounts. - const LLMatrix4& initRotTrans(const F32 angle, - const F32 rx, const F32 ry, const F32 rz, - const F32 px, const F32 py, const F32 pz); - const LLMatrix4& initRotTrans(const F32 angle, const LLVector3 &axis, const LLVector3 &translation); // Rotation from axis angle + translation const LLMatrix4& initRotTrans(const F32 roll, const F32 pitch, const F32 yaw, const LLVector4 &pos); // Rotation from Euler + translation const LLMatrix4& initRotTrans(const LLQuaternion &q, const LLVector4 &pos); // Set with Quaternion and position @@ -211,7 +206,6 @@ public: // Rotate existing matrix // These are really, really, inefficient as implemented! - djs - const LLMatrix4& rotate(const F32 angle, const F32 x, const F32 y, const F32 z); // Rotate matrix by rotating angle radians about (x, y, z) const LLMatrix4& rotate(const F32 angle, const LLVector4 &vec); // Rotate matrix by rotating angle radians about vec const LLMatrix4& rotate(const F32 roll, const F32 pitch, const F32 yaw); // Rotate matrix by Euler angles const LLMatrix4& rotate(const LLQuaternion &q); // Rotate matrix by Quaternion diff --git a/indra/llmath/tests/m3math_test.cpp b/indra/llmath/tests/m3math_test.cpp index 1ca2b005d9..2a0fe76aa7 100644 --- a/indra/llmath/tests/m3math_test.cpp +++ b/indra/llmath/tests/m3math_test.cpp @@ -77,7 +77,7 @@ namespace tut template<> template<> void m3math_test_object_t::test<2>() { - LLMatrix3 llmat3_obj(30, 1, 2, 3); + LLMatrix3 llmat3_obj; llmat3_obj.setZero(); ensure("LLMatrix3::setZero failed", 0.f == llmat3_obj.setZero().mMatrix[0][0] && diff --git a/indra/llmath/tests/v3dmath_test.cpp b/indra/llmath/tests/v3dmath_test.cpp index 20b26faa12..c4744e1b25 100644 --- a/indra/llmath/tests/v3dmath_test.cpp +++ b/indra/llmath/tests/v3dmath_test.cpp @@ -520,7 +520,12 @@ namespace tut vec3Da.normVec(); F64 angle = vec3Db*vec3Da; angle = acos(angle); +#if LL_WINDOWS && _MSC_VER > 1900 + skip("This fails on VS2017!"); +#else ensure("2:angle_between: Fail ", (angle == angle2)); #endif + +#endif } } diff --git a/indra/llmath/v2math.cpp b/indra/llmath/v2math.cpp index a0cd642853..a24571f2c8 100644 --- a/indra/llmath/v2math.cpp +++ b/indra/llmath/v2math.cpp @@ -118,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 8d5db96f5e..2335a2e327 100644 --- a/indra/llmath/v2math.h +++ b/indra/llmath/v2math.h @@ -49,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(); @@ -61,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 @@ -145,6 +146,10 @@ inline LLVector2::LLVector2(const LLVector3 &vec) mV[VY] = vec.mV[VY]; } +inline LLVector2::LLVector2(const LLSD &sd) +{ + setValue(sd); +} // Clear and Assignment Functions diff --git a/indra/llmath/v3color.h b/indra/llmath/v3color.h index daf3a6857b..43a632408c 100644 --- a/indra/llmath/v3color.h +++ b/indra/llmath/v3color.h @@ -100,6 +100,23 @@ public: 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() + { + 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 @@ -458,5 +475,22 @@ inline LLColor3 lerp(const LLColor3 &a, const LLColor3 &b, F32 u) a.mV[VZ] + (b.mV[VZ] - a.mV[VZ]) * u); } +inline const LLColor3 srgbColor3(const LLColor3 &a) { + LLColor3 srgbColor; + srgbColor.mV[0] = linearTosRGB(a.mV[0]); + srgbColor.mV[1] = linearTosRGB(a.mV[1]); + srgbColor.mV[2] = linearTosRGB(a.mV[2]); + + return srgbColor; +} + +inline const LLColor3 linearColor3(const LLColor3 &a) { + LLColor3 linearColor; + linearColor.mV[0] = sRGBtoLinear(a.mV[0]); + linearColor.mV[1] = sRGBtoLinear(a.mV[1]); + linearColor.mV[2] = sRGBtoLinear(a.mV[2]); + + return linearColor; +} #endif 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/v4color.h b/indra/llmath/v4color.h index 8f353ead5a..175edf1471 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 @@ -477,6 +479,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!) @@ -645,5 +656,29 @@ void LLColor4::clamp() } } +// Return the given linear space color value in gamma corrected (sRGB) space +inline const LLColor4 srgbColor4(const LLColor4 &a) { + LLColor4 srgbColor; + + srgbColor.mV[0] = linearTosRGB(a.mV[0]); + srgbColor.mV[1] = linearTosRGB(a.mV[1]); + srgbColor.mV[2] = linearTosRGB(a.mV[2]); + srgbColor.mV[3] = a.mV[3]; + + return srgbColor; +} + +// Return the given gamma corrected (sRGB) color in linear space +inline const LLColor4 linearColor4(const LLColor4 &a) +{ + LLColor4 linearColor; + linearColor.mV[0] = sRGBtoLinear(a.mV[0]); + linearColor.mV[1] = sRGBtoLinear(a.mV[1]); + linearColor.mV[2] = sRGBtoLinear(a.mV[2]); + linearColor.mV[3] = a.mV[3]; + + return linearColor; +} + #endif diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h index 623c8b2003..b8835ba2e4 100644 --- a/indra/llmath/v4math.h +++ b/indra/llmath/v4math.h @@ -30,6 +30,7 @@ #include "llerror.h" #include "llmath.h" #include "v3math.h" +#include "v2math.h" class LLMatrix3; class LLMatrix4; @@ -46,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); @@ -61,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) @@ -175,6 +188,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]; @@ -191,6 +220,11 @@ inline LLVector4::LLVector4(const LLVector3 &vec, F32 w) mV[VW] = w; } +inline LLVector4::LLVector4(const LLSD &sd) +{ + setValue(sd); +} + inline BOOL LLVector4::isFinite() const { @@ -500,6 +534,18 @@ inline F32 LLVector4::normVec(void) return (mag); } +// Because apparently some parts of the viewer use this for color info. +inline const LLVector4 srgbVector4(const LLVector4 &a) { + LLVector4 srgbColor; + + srgbColor.mV[0] = linearTosRGB(a.mV[0]); + srgbColor.mV[1] = linearTosRGB(a.mV[1]); + srgbColor.mV[2] = linearTosRGB(a.mV[2]); + srgbColor.mV[3] = a.mV[3]; + + return srgbColor; +} + #endif diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index e0922c0667..2f99ca069e 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -217,7 +217,7 @@ target_link_libraries( ${NGHTTP2_LIBRARIES} ${XMLRPCEPI_LIBRARIES} ${LLCOREHTTP_LIBRARIES} - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY} rt @@ -235,7 +235,7 @@ target_link_libraries( ${NGHTTP2_LIBRARIES} ${XMLRPCEPI_LIBRARIES} ${LLCOREHTTP_LIBRARIES} - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY} ) @@ -244,6 +244,7 @@ endif(LINUX) # tests if (LL_TESTS) SET(llmessage_TEST_SOURCE_FILES + llcoproceduremanager.cpp llnamevalue.cpp lltrustedmessageservice.cpp lltemplatemessagedispatcher.cpp @@ -264,7 +265,7 @@ if (LINUX) ${LLMESSAGE_LIBRARIES} ${LLCOREHTTP_LIBRARIES} ${JSONCPP_LIBRARIES} - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} rt ${GOOGLEMOCK_LIBRARIES} @@ -280,7 +281,7 @@ else (LINUX) ${LLMESSAGE_LIBRARIES} ${LLCOREHTTP_LIBRARIES} ${JSONCPP_LIBRARIES} - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${GOOGLEMOCK_LIBRARIES} ) diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index 596d57c7b7..d7801b6ddc 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -62,6 +62,42 @@ const LLUUID CATEGORIZE_LOST_AND_FOUND_ID(std::string("00000000-0000-0000-0000-0 const U64 TOXIC_ASSET_LIFETIME = (120 * 1000000); // microseconds +namespace +{ + bool operator == (const LLAssetStorage::LLGetAssetCallback &lhs, const LLAssetStorage::LLGetAssetCallback &rhs) + { + auto fnPtrLhs = lhs.target<LLAssetStorage::LLGetAssetCallback>(); + auto fnPtrRhs = rhs.target<LLAssetStorage::LLGetAssetCallback>(); + 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<typename T, typename... U> +// bool operator == (const std::function<T(U...)> &a, const std::function <T(U...)> &b) +// { +// typedef T(fnType)(U...); +// +// auto fnPtrA = a.target<T(*)(U...)>(); +// auto fnPtrB = b.target<T(*)(U...)>(); +// if (fnPtrA && fnPtrB) +// return (*fnPtrA == *fnPtrB); +// else if (!fnPtrA && !fnPtrB) +// return true; +// return false; +// } + +} + ///---------------------------------------------------------------------------- /// LLAssetInfo ///---------------------------------------------------------------------------- @@ -160,7 +196,7 @@ void LLAssetInfo::setFromNameValue( const LLNameValue& nv ) LLBaseDownloadRequest::LLBaseDownloadRequest(const LLUUID &uuid, const LLAssetType::EType type) : mUUID(uuid), mType(type), - mDownCallback(NULL), + mDownCallback(), mUserData(NULL), mHost(), mIsTemp(FALSE), @@ -191,7 +227,7 @@ LLBaseDownloadRequest* LLBaseDownloadRequest::getCopy() LLAssetRequest::LLAssetRequest(const LLUUID &uuid, const LLAssetType::EType type) : LLBaseDownloadRequest(uuid, type), - mUpCallback( NULL ), + mUpCallback(), mInfoCallback( NULL ), mIsLocal(FALSE), mIsUserWaiting(FALSE), @@ -390,11 +426,11 @@ void LLAssetStorage::_cleanupRequests(BOOL all, S32 error) LLAssetRequest* tmp = *curiter; if (tmp->mUpCallback) { - tmp->mUpCallback(tmp->getUUID(), tmp->mUserData, error, LL_EXSTAT_NONE); + tmp->mUpCallback(tmp->getUUID(), tmp->mUserData, error, LLExtStat::NONE); } if (tmp->mDownCallback) { - tmp->mDownCallback(mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, error, LL_EXSTAT_NONE); + tmp->mDownCallback(mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, error, LLExtStat::NONE); } if (tmp->mInfoCallback) { @@ -429,7 +465,7 @@ bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAsse // we've already got the file if (callback) { - callback(mStaticVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); + callback(mStaticVFS, uuid, type, user_data, LL_ERR_NOERR, LLExtStat::VFS_CACHED); } return true; } @@ -449,7 +485,7 @@ 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, + LLAssetStorage::LLGetAssetCallback callback, void *user_data, BOOL is_priority) { @@ -470,7 +506,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, if (callback) { add(sFailedDownloadCount, 1); - callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_NONE); + callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LLExtStat::NONE); } return; } @@ -481,7 +517,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, if (callback) { add(sFailedDownloadCount, 1); - callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID); + callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LLExtStat::NULL_UUID); } return; } @@ -496,7 +532,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, BOOL exists = mVFS->getExists(uuid, type); LLVFile file(mVFS, uuid, type); U32 size = exists ? file.getSize() : 0; - + if (size > 0) { // we've already got the file @@ -504,7 +540,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, // unless there's a weird error if (callback) { - callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); + callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LLExtStat::VFS_CACHED); } LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in VFS" << LL_ENDL; @@ -658,7 +694,7 @@ void LLAssetStorage::downloadCompleteCallback( } } - removeAndCallbackPendingDownloads(file_id, file_type, callback_id, callback_type, ext_status, result); + removeAndCallbackPendingDownloads(file_id, file_type, callback_id, callback_type, result, ext_status); } void LLAssetStorage::getEstateAsset( @@ -683,7 +719,7 @@ void LLAssetStorage::getEstateAsset( if (callback) { add(sFailedDownloadCount, 1); - callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID); + callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LLExtStat::NULL_UUID); } return; } @@ -705,7 +741,7 @@ void LLAssetStorage::getEstateAsset( // unless there's a weird error if (callback) { - callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); + callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LLExtStat::VFS_CACHED); } } else @@ -756,7 +792,7 @@ void LLAssetStorage::getEstateAsset( if (callback) { add(sFailedDownloadCount, 1); - callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); + callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LLExtStat::NO_UPSTREAM); } } } @@ -849,7 +885,7 @@ void LLAssetStorage::getInvItemAsset( // unless there's a weird error if (callback) { - callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); + callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LLExtStat::VFS_CACHED); } } else @@ -900,7 +936,7 @@ void LLAssetStorage::getInvItemAsset( if (callback) { add(sFailedDownloadCount, 1); - callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); + callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LLExtStat::NO_UPSTREAM); } } } @@ -998,7 +1034,7 @@ void LLAssetStorage::processUploadComplete(LLMessageSystem *msg, void **user_dat msg->getBOOLFast(_PREHASH_AssetBlock, _PREHASH_Success, success); asset_type = (LLAssetType::EType)asset_type_s8; - this_ptr->_callUploadCallbacks(uuid, asset_type, success, LL_EXSTAT_NONE); + this_ptr->_callUploadCallbacks(uuid, asset_type, success, LLExtStat::NONE); } void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType asset_type, BOOL success, LLExtStat ext_status ) @@ -1252,12 +1288,12 @@ bool LLAssetStorage::deletePendingRequestImpl(LLAssetStorage::request_list_t* re // Run callbacks. if (req->mUpCallback) { - req->mUpCallback(req->getUUID(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED); + req->mUpCallback(req->getUUID(), req->mUserData, error, LLExtStat::REQUEST_DROPPED); } if (req->mDownCallback) { add(sFailedDownloadCount, 1); - req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED); + req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error, LLExtStat::REQUEST_DROPPED); } if (req->mInfoCallback) { @@ -1326,9 +1362,13 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, iter != mPendingDownloads.end(); ) { LLAssetRequest* tmp = *iter++; + + //void(*const* cbptr)(LLVFS *, const LLUUID &, LLAssetType::EType, void *, S32, LLExtStat) + auto cbptr = tmp->mDownCallback.target<void(*)(LLVFS *, const LLUUID &, LLAssetType::EType, void *, S32, LLExtStat)>(); + if (type == tmp->getType() && uuid == tmp->getUUID() && - legacyGetDataCallback == tmp->mDownCallback && + (cbptr && (*cbptr == legacyGetDataCallback)) && callback == ((LLLegacyAssetRequest *)tmp->mUserData)->mDownCallback && user_data == ((LLLegacyAssetRequest *)tmp->mUserData)->mUserData) { diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h index 33b88473b9..7e4572f50f 100644 --- a/indra/llmessage/llassetstorage.h +++ b/indra/llmessage/llassetstorage.h @@ -28,6 +28,7 @@ #ifndef LL_LLASSETSTORAGE_H #define LL_LLASSETSTORAGE_H #include <string> +#include <functional> #include "lluuid.h" #include "lltimer.h" @@ -59,6 +60,14 @@ 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<void(LLVFS *vfs, const LLUUID &asset_id, LLAssetType::EType asset_type, void *user_data, S32 status, LLExtStat ext_status)> LLGetAssetCallback; +typedef std::function<void(const LLUUID &asset_id, void *user_data, S32 status, LLExtStat ext_status)> LLStoreAssetCallback; + + class LLAssetInfo { protected: @@ -110,7 +119,8 @@ protected: LLAssetType::EType mType; public: - void(*mDownCallback)(LLVFS*, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat); + LLGetAssetCallback mDownCallback; +// void(*mDownCallback)(LLVFS*, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat); void *mUserData; LLHost mHost; @@ -131,7 +141,8 @@ public: virtual LLBaseDownloadRequest* getCopy(); - void (*mUpCallback)(const LLUUID&, void *, S32, LLExtStat); + LLStoreAssetCallback mUpCallback; +// void (*mUpCallback)(const LLUUID&, void *, S32, LLExtStat); void (*mInfoCallback)(LLAssetInfo *, void *, S32); BOOL mIsLocal; @@ -182,12 +193,7 @@ protected: // Map of known bad assets typedef std::map<LLUUID,U64,lluuid_less> toxic_asset_map_t; -// *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 void (*LLGetAssetCallback)(LLVFS *vfs, const LLUUID &asset_id, - LLAssetType::EType asset_type, void *user_data, S32 status, LLExtStat ext_status); + class LLAssetStorage { @@ -195,7 +201,8 @@ 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 { @@ -255,7 +262,7 @@ public: virtual void logAssetStorageInfo() = 0; - void checkForTimeouts(); + virtual 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, @@ -377,8 +384,8 @@ 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) = 0; @@ -424,7 +431,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/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index ba1a2a035e..c67f59bc0c 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -49,101 +49,22 @@ #include <map> #include <set> -namespace LLAvatarNameCache -{ - use_display_name_signal_t mUseDisplayNamesSignal; - // Cache starts in a paused state until we can determine if the - // 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<LLUUID> 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. - typedef std::map<LLUUID, F64> pending_queue_t; - pending_queue_t sPendingQueue; - - // Callbacks to fire when we received a name. - // May have multiple callbacks for a single ID, which are - // represented as multiple slots bound to the signal. - // Avoid copying signals via pointers. - typedef std::map<LLUUID, callback_signal_t*> signal_map_t; - signal_map_t sSignalMap; - - // The cache at last, i.e. avatar names we know about. - typedef std::map<LLUUID, LLAvatarName> cache_t; - cache_t sCache; - - // 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. - const F64 MAX_UNREFRESHED_TIME = 20.0 * 60.0; - - // Time when unrefreshed cached names were checked last. - static F64 sLastExpireCheck; - - // Time-to-live for a temp cache entry. - const F64 TEMP_CACHE_ENTRY_LIFETIME = 60.0; - - LLCore::HttpRequest::ptr_t sHttpRequest; - LLCore::HttpHeaders::ptr_t sHttpHeaders; - LLCore::HttpOptions::ptr_t sHttpOptions; - LLCore::HttpRequest::policy_t sHttpPolicy; - LLCore::HttpRequest::priority_t sHttpPriority; - - //----------------------------------------------------------------------- - // Internal methods - //----------------------------------------------------------------------- - - // Handle name response off network. - void processName(const LLUUID& agent_id, - const LLAvatarName& av_name); - - void requestNamesViaCapability(); - - // Legacy name system callbacks - void legacyNameCallback(const LLUUID& agent_id, - const std::string& full_name, - bool is_group); - void legacyNameFetch(const LLUUID& agent_id, - const std::string& full_name, - bool is_group); - - void requestNamesViaLegacy(); +// Time-to-live for a temp cache entry. +const F64 TEMP_CACHE_ENTRY_LIFETIME = 60.0; +// Maximum time an unrefreshed cache entry is allowed. +const F64 MAX_UNREFRESHED_TIME = 20.0 * 60.0; - // Do a single callback to a given slot - void fireSignal(const LLUUID& agent_id, - const callback_slot_t& slot, - const LLAvatarName& av_name); - - // Is a request in-flight over the network? - bool isRequestPending(const LLUUID& agent_id); +// Send bulk lookup requests a few times a second at most. +// Only need per-frame timing resolution. +static LLFrameTimer sRequestTimer; - // Erase expired names from cache - void eraseUnrefreshed(); - - bool expirationFromCacheControl(const LLSD& headers, F64 *expires); - - // This is a coroutine. - void requestAvatarNameCache_(std::string url, std::vector<LLUUID> agentIds); - - void handleAvNameCacheSuccess(const LLSD &data, const LLSD &httpResult); -} +// static to avoid unnessesary dependencies +LLCore::HttpRequest::ptr_t sHttpRequest; +LLCore::HttpHeaders::ptr_t sHttpHeaders; +LLCore::HttpOptions::ptr_t sHttpOptions; +LLCore::HttpRequest::policy_t sHttpPolicy; +LLCore::HttpRequest::priority_t sHttpPriority; /* Sample response: <?xml version="1.0"?> @@ -187,9 +108,33 @@ namespace LLAvatarNameCache // Coroutine for sending and processing avatar name cache requests. // Do not call directly. See documentation in lleventcoro.h and llcoro.h for // further explanation. + +LLAvatarNameCache::LLAvatarNameCache() +{ + // Will be set to running later + // For now fail immediate lookups and query async ones. + mRunning = false; + + mUsePeopleAPI = true; + + sHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest()); + sHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()); + sHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()); + sHttpPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID; + sHttpPriority = 0; +} + +LLAvatarNameCache::~LLAvatarNameCache() +{ + sHttpRequest.reset(); + sHttpHeaders.reset(); + sHttpOptions.reset(); + mCache.clear(); +} + void LLAvatarNameCache::requestAvatarNameCache_(std::string url, std::vector<LLUUID> agentIds) { - LL_DEBUGS("AvNameCache") << "Entering coroutine " << LLCoros::instance().getName() + LL_DEBUGS("AvNameCache") << "Entering coroutine " << LLCoros::getName() << " with url '" << url << "', requesting " << agentIds.size() << " Agent Ids" << LL_ENDL; // Check pointer that can be cleaned up by cleanupClass() @@ -200,12 +145,12 @@ void LLAvatarNameCache::requestAvatarNameCache_(std::string url, std::vector<LLU } LLSD httpResults; + bool success = true; try { - bool success = true; - LLCoreHttpUtil::HttpCoroutineAdapter httpAdapter("NameCache", LLAvatarNameCache::sHttpPolicy); + LLCoreHttpUtil::HttpCoroutineAdapter httpAdapter("NameCache", sHttpPolicy); LLSD results = httpAdapter.getAndSuspend(sHttpRequest, url); LL_DEBUGS() << results << LL_ENDL; @@ -218,35 +163,47 @@ void LLAvatarNameCache::requestAvatarNameCache_(std::string url, std::vector<LLU else { httpResults = results["http_result"]; - success = httpResults["success"].asBoolean(); - if (!success) + if (!httpResults.isMap()) { - LL_WARNS("AvNameCache") << "Error result from LLCoreHttpUtil::HttpCoroHandler. Code " - << httpResults["status"] << ": '" << httpResults["message"] << "'" << LL_ENDL; + success = false; + LL_WARNS("AvNameCache") << " Invalid http_result returned from LLCoreHttpUtil::HttpCoroHandler." << LL_ENDL; } - } - - if (!success) - { // on any sort of failure add dummy records for any agent IDs - // in this request that we do not have cached already - std::vector<LLUUID>::const_iterator it = agentIds.begin(); - for ( ; it != agentIds.end(); ++it) + else { - const LLUUID& agent_id = *it; - LLAvatarNameCache::handleAgentError(agent_id); + success = httpResults["success"].asBoolean(); + if (!success) + { + LL_WARNS("AvNameCache") << "Error result from LLCoreHttpUtil::HttpCoroHandler. Code " + << httpResults["status"] << ": '" << httpResults["message"] << "'" << LL_ENDL; + } } - return; } - LLAvatarNameCache::handleAvNameCacheSuccess(results, httpResults); + if (LLAvatarNameCache::instanceExists()) + { + if (!success) + { // on any sort of failure add dummy records for any agent IDs + // in this request that we do not have cached already + std::vector<LLUUID>::const_iterator it = agentIds.begin(); + for (; it != agentIds.end(); ++it) + { + const LLUUID& agent_id = *it; + LLAvatarNameCache::getInstance()->handleAgentError(agent_id); + } + return; + } + LLAvatarNameCache::getInstance()->handleAvNameCacheSuccess(results, httpResults); + } } catch (...) { - LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::instance().getName() - << "('" << url << "', " << agentIds.size() - << " http result: " << httpResults.asString() - << " Agent Ids)")); + LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::getName() + << "('" << url << "', " + << agentIds.size() << "Agent Ids," + << " http result: " << S32(success) + << " has response: " << S32(httpResults.size()) + << ")")); throw; } } @@ -300,15 +257,15 @@ void LLAvatarNameCache::handleAvNameCacheSuccess(const LLSD &data, const LLSD &h } } LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result " - << LLAvatarNameCache::sCache.size() << " cached names" + << LLAvatarNameCache::mCache.size() << " cached names" << LL_ENDL; } // Provide some fallback for agents that return errors void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id) { - std::map<LLUUID,LLAvatarName>::iterator existing = sCache.find(agent_id); - if (existing == sCache.end()) + std::map<LLUUID,LLAvatarName>::iterator existing = mCache.find(agent_id); + if (existing == mCache.end()) { // there is no existing cache entry, so make a temporary name from legacy LL_WARNS("AvNameCache") << "LLAvatarNameCache get legacy for agent " @@ -322,7 +279,7 @@ void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id) // 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); + LLAvatarNameCache::mPendingQueue.erase(agent_id); LLAvatarName& av_name = existing->second; LL_DEBUGS("AvNameCache") << "LLAvatarNameCache use cache for agent " << agent_id << LL_ENDL; @@ -340,24 +297,41 @@ void LLAvatarNameCache::processName(const LLUUID& agent_id, const LLAvatarName& return; } + bool updated_account = true; // assume obsolete value for new arrivals by default + + std::map<LLUUID, LLAvatarName>::iterator it = mCache.find(agent_id); + if (it != mCache.end() + && (*it).second.getAccountName() == av_name.getAccountName()) + { + updated_account = false; + } + // Add to the cache - sCache[agent_id] = av_name; + mCache[agent_id] = av_name; // Suppress request from the queue - sPendingQueue.erase(agent_id); + mPendingQueue.erase(agent_id); + + // notify mute list about changes + if (updated_account && mAccountNameChangedCallback) + { + mAccountNameChangedCallback(agent_id, av_name); + } // Signal everyone waiting on this name - signal_map_t::iterator sig_it = sSignalMap.find(agent_id); - if (sig_it != sSignalMap.end()) + signal_map_t::iterator sig_it = mSignalMap.find(agent_id); + if (sig_it != mSignalMap.end()) { callback_signal_t* signal = sig_it->second; (*signal)(agent_id, av_name); - sSignalMap.erase(agent_id); + mSignalMap.erase(agent_id); delete signal; signal = NULL; } + + } void LLAvatarNameCache::requestNamesViaCapability() @@ -379,16 +353,16 @@ void LLAvatarNameCache::requestNamesViaCapability() U32 ids = 0; ask_queue_t::const_iterator it; - while(!sAskQueue.empty()) + while(!mAskQueue.empty()) { - it = sAskQueue.begin(); + it = mAskQueue.begin(); LLUUID agent_id = *it; - sAskQueue.erase(it); + mAskQueue.erase(it); if (url.empty()) { // ...starting new request - url += sNameLookupURL; + url += mNameLookupURL; url += "?ids="; ids = 1; } @@ -402,7 +376,7 @@ void LLAvatarNameCache::requestNamesViaCapability() agent_ids.push_back(agent_id); // mark request as pending - sPendingQueue[agent_id] = now; + mPendingQueue[agent_id] = now; if (url.size() > NAME_URL_SEND_THRESHOLD) { @@ -432,7 +406,7 @@ void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id, // Retrieve the name and set it to never (or almost never...) expire: when we are using the legacy // protocol, we do not get an expiration date for each name and there's no reason to ask the // data again and again so we set the expiration time to the largest value admissible. - std::map<LLUUID,LLAvatarName>::iterator av_record = sCache.find(agent_id); + std::map<LLUUID,LLAvatarName>::iterator av_record = LLAvatarNameCache::getInstance()->mCache.find(agent_id); LLAvatarName& av_name = av_record->second; av_name.setExpires(MAX_UNREFRESHED_TIME); } @@ -451,7 +425,7 @@ void LLAvatarNameCache::legacyNameFetch(const LLUUID& agent_id, 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); + LLAvatarNameCache::getInstance()->processName(agent_id, av_name); } void LLAvatarNameCache::requestNamesViaLegacy() @@ -460,15 +434,15 @@ void LLAvatarNameCache::requestNamesViaLegacy() F64 now = LLFrameTimer::getTotalSeconds(); std::string full_name; ask_queue_t::const_iterator it; - for (S32 requests = 0; !sAskQueue.empty() && requests < MAX_REQUESTS; ++requests) + for (S32 requests = 0; !mAskQueue.empty() && requests < MAX_REQUESTS; ++requests) { - it = sAskQueue.begin(); + it = mAskQueue.begin(); LLUUID agent_id = *it; - sAskQueue.erase(it); + mAskQueue.erase(it); // Mark as pending first, just in case the callback is immediately // invoked below. This should never happen in practice. - sPendingQueue[agent_id] = now; + mPendingQueue[agent_id] = now; LL_DEBUGS("AvNameCache") << "agent " << agent_id << LL_ENDL; @@ -477,26 +451,6 @@ void LLAvatarNameCache::requestNamesViaLegacy() } } -void LLAvatarNameCache::initClass(bool running, bool usePeopleAPI) -{ - sRunning = running; - sUsePeopleAPI = usePeopleAPI; - - sHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest()); - sHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()); - sHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()); - sHttpPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID; - sHttpPriority = 0; -} - -void LLAvatarNameCache::cleanupClass() -{ - sHttpRequest.reset(); - sHttpHeaders.reset(); - sHttpOptions.reset(); - sCache.clear(); -} - bool LLAvatarNameCache::importFile(std::istream& istr) { LLSD data; @@ -517,9 +471,9 @@ bool LLAvatarNameCache::importFile(std::istream& istr) { agent_id.set(it->first); av_name.fromLLSD( it->second ); - sCache[agent_id] = av_name; + mCache[agent_id] = av_name; } - LL_INFOS("AvNameCache") << "LLAvatarNameCache loaded " << sCache.size() << LL_ENDL; + LL_INFOS("AvNameCache") << "LLAvatarNameCache loaded " << mCache.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 @@ -531,9 +485,9 @@ 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) + LL_INFOS("AvNameCache") << "LLAvatarNameCache at exit cache has " << mCache.size() << LL_ENDL; + cache_t::const_iterator it = mCache.begin(); + for ( ; it != mCache.end(); ++it) { const LLUUID& agent_id = it->first; const LLAvatarName& av_name = it->second; @@ -552,23 +506,28 @@ void LLAvatarNameCache::exportFile(std::ostream& ostr) void LLAvatarNameCache::setNameLookupURL(const std::string& name_lookup_url) { - sNameLookupURL = name_lookup_url; + mNameLookupURL = name_lookup_url; } bool LLAvatarNameCache::hasNameLookupURL() { - return !sNameLookupURL.empty(); + return !mNameLookupURL.empty(); +} + +void LLAvatarNameCache::setUsePeopleAPI(bool use_api) +{ + mUsePeopleAPI = use_api; } bool LLAvatarNameCache::usePeopleAPI() { - return hasNameLookupURL() && sUsePeopleAPI; + return hasNameLookupURL() && mUsePeopleAPI; } void LLAvatarNameCache::idle() { // By convention, start running at first idle() call - sRunning = true; + mRunning = true; // *TODO: Possibly re-enabled this based on People API load measurements // 100 ms is the threshold for "user speed" operations, so we can @@ -579,7 +538,7 @@ void LLAvatarNameCache::idle() return; } - if (!sAskQueue.empty()) + if (!mAskQueue.empty()) { if (usePeopleAPI()) { @@ -592,7 +551,7 @@ void LLAvatarNameCache::idle() } } - if (sAskQueue.empty()) + if (mAskQueue.empty()) { // cleared the list, reset the request timer. sRequestTimer.resetWithExpiry(SECS_BETWEEN_REQUESTS); @@ -607,8 +566,8 @@ bool LLAvatarNameCache::isRequestPending(const LLUUID& agent_id) bool isPending = false; const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0; - pending_queue_t::const_iterator it = sPendingQueue.find(agent_id); - if (it != sPendingQueue.end()) + pending_queue_t::const_iterator it = mPendingQueue.find(agent_id); + if (it != mPendingQueue.end()) { // in the list of requests in flight, retry if too old F64 expire_time = LLFrameTimer::getTotalSeconds() - PENDING_TIMEOUT_SECS; @@ -622,11 +581,11 @@ void LLAvatarNameCache::eraseUnrefreshed() F64 now = LLFrameTimer::getTotalSeconds(); F64 max_unrefreshed = now - MAX_UNREFRESHED_TIME; - if (!sLastExpireCheck || sLastExpireCheck < max_unrefreshed) + if (!mLastExpireCheck || mLastExpireCheck < max_unrefreshed) { - sLastExpireCheck = now; + mLastExpireCheck = now; S32 expired = 0; - for (cache_t::iterator it = sCache.begin(); it != sCache.end();) + for (cache_t::iterator it = mCache.begin(); it != mCache.end();) { const LLAvatarName& av_name = it->second; if (av_name.mExpires < max_unrefreshed) @@ -635,7 +594,7 @@ void LLAvatarNameCache::eraseUnrefreshed() << " user '" << av_name.getAccountName() << "' " << "expired " << now - av_name.mExpires << " secs ago" << LL_ENDL; - sCache.erase(it++); + mCache.erase(it++); expired++; } else @@ -644,19 +603,24 @@ void LLAvatarNameCache::eraseUnrefreshed() } } LL_INFOS("AvNameCache") << "LLAvatarNameCache expired " << expired << " cached avatar names, " - << sCache.size() << " remaining" << LL_ENDL; + << mCache.size() << " remaining" << LL_ENDL; } } +//static, wrapper +bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) +{ + return LLAvatarNameCache::getInstance()->getName(agent_id, av_name); +} // 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) +bool LLAvatarNameCache::getName(const LLUUID& agent_id, LLAvatarName *av_name) { - if (sRunning) + if (mRunning) { // ...only do immediate lookups when cache is running - std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id); - if (it != sCache.end()) + std::map<LLUUID,LLAvatarName>::iterator it = mCache.find(agent_id); + if (it != mCache.end()) { *av_name = it->second; @@ -667,7 +631,7 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) { LL_DEBUGS("AvNameCache") << "LLAvatarNameCache refresh agent " << agent_id << LL_ENDL; - sAskQueue.insert(agent_id); + mAskQueue.insert(agent_id); } } @@ -678,7 +642,7 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) if (!isRequestPending(agent_id)) { LL_DEBUGS("AvNameCache") << "LLAvatarNameCache queue request for agent " << agent_id << LL_ENDL; - sAskQueue.insert(agent_id); + mAskQueue.insert(agent_id); } return false; @@ -693,15 +657,21 @@ void LLAvatarNameCache::fireSignal(const LLUUID& agent_id, signal(agent_id, av_name); } +// static, wrapper LLAvatarNameCache::callback_connection_t LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot) { + return LLAvatarNameCache::getInstance()->getNameCallback(agent_id, slot); +} + +LLAvatarNameCache::callback_connection_t LLAvatarNameCache::getNameCallback(const LLUUID& agent_id, callback_slot_t slot) +{ callback_connection_t connection; - if (sRunning) + if (mRunning) { // ...only do immediate lookups when cache is running - std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id); - if (it != sCache.end()) + std::map<LLUUID,LLAvatarName>::iterator it = mCache.find(agent_id); + if (it != mCache.end()) { const LLAvatarName& av_name = it->second; @@ -717,17 +687,17 @@ LLAvatarNameCache::callback_connection_t LLAvatarNameCache::get(const LLUUID& ag // schedule a request if (!isRequestPending(agent_id)) { - sAskQueue.insert(agent_id); + mAskQueue.insert(agent_id); } // always store additional callback, even if request is pending - signal_map_t::iterator sig_it = sSignalMap.find(agent_id); - if (sig_it == sSignalMap.end()) + signal_map_t::iterator sig_it = mSignalMap.find(agent_id); + if (sig_it == mSignalMap.end()) { // ...new callback for this id callback_signal_t* signal = new callback_signal_t(); connection = signal->connect(slot); - sSignalMap[agent_id] = signal; + mSignalMap[agent_id] = signal; } else { @@ -760,20 +730,20 @@ void LLAvatarNameCache::setUseUsernames(bool use) void LLAvatarNameCache::erase(const LLUUID& agent_id) { - sCache.erase(agent_id); + mCache.erase(agent_id); } void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_name) { // *TODO: update timestamp if zero? - sCache[agent_id] = av_name; + mCache[agent_id] = av_name; } LLUUID LLAvatarNameCache::findIdByName(const std::string& name) { std::map<LLUUID, LLAvatarName>::iterator it; - std::map<LLUUID, LLAvatarName>::iterator end = sCache.end(); - for (it = sCache.begin(); it != end; ++it) + std::map<LLUUID, LLAvatarName>::iterator end = mCache.end(); + for (it = mCache.begin(); it != end; ++it) { if (it->second.getUserName() == name) { diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index 63e067c939..549d1703fa 100644 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -29,20 +29,20 @@ #define LLAVATARNAMECACHE_H #include "llavatarname.h" // for convenience +#include "llsingleton.h" #include <boost/signals2.hpp> +#include <set> class LLSD; class LLUUID; -namespace LLAvatarNameCache +class LLAvatarNameCache : public LLSingleton<LLAvatarNameCache> { + LLSINGLETON(LLAvatarNameCache); + ~LLAvatarNameCache(); +public: typedef boost::signals2::signal<void (void)> 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, bool usePeopleAPI); - void cleanupClass(); + typedef boost::function<void (const LLUUID id, const LLAvatarName& av_name)> account_name_changed_callback_t; // Import/export the name cache to file. bool importFile(std::istream& istr); @@ -55,6 +55,7 @@ namespace LLAvatarNameCache // Do we have a valid lookup URL, i.e. are we trying to use the // more recent display name lookup system? bool hasNameLookupURL(); + void setUsePeopleAPI(bool use_api); bool usePeopleAPI(); // Periodically makes a batch request for display names not already in @@ -63,7 +64,8 @@ namespace LLAvatarNameCache // If name is in cache, returns true and fills in provided LLAvatarName // otherwise returns false. - bool get(const LLUUID& agent_id, LLAvatarName *av_name); + static bool get(const LLUUID& agent_id, LLAvatarName *av_name); + bool getName(const LLUUID& agent_id, LLAvatarName *av_name); // Callback types for get() below typedef boost::signals2::signal< @@ -74,7 +76,8 @@ namespace LLAvatarNameCache // 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); + static callback_connection_t get(const LLUUID& agent_id, callback_slot_t slot); + callback_connection_t getNameCallback(const LLUUID& agent_id, callback_slot_t slot); // Set display name: flips the switch and triggers the callbacks. void setUseDisplayNames(bool use); @@ -100,7 +103,86 @@ namespace LLAvatarNameCache F64 nameExpirationFromHeaders(const LLSD& headers); void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb); -} + + void setAccountNameChangedCallback(const account_name_changed_callback_t& cb) { mAccountNameChangedCallback = cb; } + +private: + // Handle name response off network. + void processName(const LLUUID& agent_id, + const LLAvatarName& av_name); + + void requestNamesViaCapability(); + + // Legacy name system callbacks + static void legacyNameCallback(const LLUUID& agent_id, + const std::string& full_name, + bool is_group); + static void legacyNameFetch(const LLUUID& agent_id, + const std::string& full_name, + bool is_group); + + void requestNamesViaLegacy(); + + // Do a single callback to a given slot + void fireSignal(const LLUUID& agent_id, + const callback_slot_t& slot, + const LLAvatarName& av_name); + + // Is a request in-flight over the network? + bool isRequestPending(const LLUUID& agent_id); + + // Erase expired names from cache + void eraseUnrefreshed(); + + bool expirationFromCacheControl(const LLSD& headers, F64 *expires); + + // This is a coroutine. + static void requestAvatarNameCache_(std::string url, std::vector<LLUUID> agentIds); + + void handleAvNameCacheSuccess(const LLSD &data, const LLSD &httpResult); + +private: + + use_display_name_signal_t mUseDisplayNamesSignal; + account_name_changed_callback_t mAccountNameChangedCallback; + + // Cache starts in a paused state until we can determine if the + // current region supports display names. + bool mRunning; + + // 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 mUsePeopleAPI; + + // 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 mNameLookupURL; + + // Accumulated agent IDs for next query against service + typedef std::set<LLUUID> ask_queue_t; + ask_queue_t mAskQueue; + + // Agent IDs that have been requested, but with no reply. + // Maps agent ID to frame time request was made. + typedef std::map<LLUUID, F64> pending_queue_t; + pending_queue_t mPendingQueue; + + // Callbacks to fire when we received a name. + // May have multiple callbacks for a single ID, which are + // represented as multiple slots bound to the signal. + // Avoid copying signals via pointers. + typedef std::map<LLUUID, callback_signal_t*> signal_map_t; + signal_map_t mSignalMap; + + // The cache at last, i.e. avatar names we know about. + typedef std::map<LLUUID, LLAvatarName> cache_t; + cache_t mCache; + + // Time when unrefreshed cached names were checked last. + F64 mLastExpireCheck; +}; // Parse a cache-control header to get the max-age delta-seconds. // Returns true if header has max-age param and it parses correctly. diff --git a/indra/llmessage/llblowfishcipher.cpp b/indra/llmessage/llblowfishcipher.cpp index 0b5025a422..949d4cc0c7 100644 --- a/indra/llmessage/llblowfishcipher.cpp +++ b/indra/llmessage/llblowfishcipher.cpp @@ -52,24 +52,28 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) if (src_len > dst_len) return 0; // OpenSSL uses "cipher contexts" to hold encryption parameters. - EVP_CIPHER_CTX context; - EVP_CIPHER_CTX_init(&context); + EVP_CIPHER_CTX *context = EVP_CIPHER_CTX_new(); + if (!context) + { + LL_WARNS() << "LLBlowfishCipher::encrypt EVP_CIPHER_CTX initiation failure" << LL_ENDL; + return 0; + } // We want a blowfish cyclic block chain cipher, but need to set // the key length before we pass in a key, so call EncryptInit // first with NULLs. - EVP_EncryptInit_ex(&context, EVP_bf_cbc(), NULL, NULL, NULL); - EVP_CIPHER_CTX_set_key_length(&context, (int)mSecretSize); + EVP_EncryptInit_ex(context, EVP_bf_cbc(), NULL, NULL, NULL); + EVP_CIPHER_CTX_set_key_length(context, (int)mSecretSize); // Complete initialization. Per EVP_EncryptInit man page, the // cipher pointer must be NULL. Apparently initial_vector must // be 8 bytes for blowfish, as this is the block size. unsigned char initial_vector[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - EVP_EncryptInit_ex(&context, NULL, NULL, mSecret, initial_vector); + EVP_EncryptInit_ex(context, NULL, NULL, mSecret, initial_vector); - 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); + 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); LL_DEBUGS() << "LLBlowfishCipher blocksize " << blocksize << " keylen " << keylen << " iv_len " << iv_length @@ -77,7 +81,7 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) int output_len = 0; int temp_len = 0; - if (!EVP_EncryptUpdate(&context, + if (!EVP_EncryptUpdate(context, dst, &output_len, src, @@ -89,18 +93,18 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) // There may be some final data left to encrypt if the input is // not an exact multiple of the block size. - if (!EVP_EncryptFinal_ex(&context, (unsigned char*)(dst + output_len), &temp_len)) + if (!EVP_EncryptFinal_ex(context, (unsigned char*)(dst + output_len), &temp_len)) { LL_WARNS() << "LLBlowfishCipher::encrypt EVP_EncryptFinal failure" << LL_ENDL; goto ERROR; } output_len += temp_len; - EVP_CIPHER_CTX_cleanup(&context); + EVP_CIPHER_CTX_free(context); return output_len; ERROR: - EVP_CIPHER_CTX_cleanup(&context); + EVP_CIPHER_CTX_free(context); return 0; } diff --git a/indra/llmessage/llbuffer.cpp b/indra/llmessage/llbuffer.cpp index 1a0eceba0f..cfe38605ad 100644 --- a/indra/llmessage/llbuffer.cpp +++ b/indra/llmessage/llbuffer.cpp @@ -32,6 +32,7 @@ #include "llmath.h" #include "llstl.h" #include "llthread.h" +#include "llmutex.h" #include <iterator> #define ASSERT_LLBUFFERARRAY_MUTEX_LOCKED() llassert(!mMutexp || mMutexp->isSelfLocked()) diff --git a/indra/llmessage/llbufferstream.cpp b/indra/llmessage/llbufferstream.cpp index ff1c9993cc..39508c1c52 100644 --- a/indra/llmessage/llbufferstream.cpp +++ b/indra/llmessage/llbufferstream.cpp @@ -31,6 +31,7 @@ #include "llbuffer.h" #include "llthread.h" +#include "llmutex.h" static const S32 DEFAULT_OUTPUT_SEGMENT_SIZE = 1024 * 4; diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index 8dbe2f8411..8baa2e328b 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -543,7 +543,7 @@ void LLCircuitData::checkPeriodTime() mBytesOutLastPeriod = mBytesOutThisPeriod; mBytesInThisPeriod = S32Bytes(0); mBytesOutThisPeriod = S32Bytes(0); - mLastPeriodLength = period_length; + mLastPeriodLength = F32Seconds::convert(period_length); mPeriodTime = mt_sec; } @@ -1378,8 +1378,8 @@ F32Milliseconds LLCircuitData::getPingInTransitTime() if (mPingsInTransit) { - time_since_ping_was_sent = ((mPingsInTransit*mHeartbeatInterval - F32Seconds(1)) - + (LLMessageSystem::getMessageTimeSeconds() - mPingTime)); + time_since_ping_was_sent = F32Milliseconds::convert(((mPingsInTransit*mHeartbeatInterval - F32Seconds(1)) + + (LLMessageSystem::getMessageTimeSeconds() - mPingTime))); } return time_since_ping_was_sent; diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp index 74cdff2b00..be014e7b1e 100644 --- a/indra/llmessage/llcoproceduremanager.cpp +++ b/indra/llmessage/llcoproceduremanager.cpp @@ -25,23 +25,29 @@ * $/LicenseInfo$ */ -#include "linden_common.h" +#include "llwin32headers.h" + +#include "linden_common.h" + #include "llcoproceduremanager.h" + +#include <chrono> + +#include <boost/fiber/buffered_channel.hpp> + #include "llexception.h" #include "stringize.h" -#include <boost/assign.hpp> //========================================================================= // Map of pool sizes for known pools -// *TODO$: When C++11 this can be initialized here as follows: -// = {{"AIS", 25}, {"Upload", 1}} -static std::map<std::string, U32> DefaultPoolSizes = - boost::assign::map_list_of - (std::string("Upload"), 1) - (std::string("AIS"), 1); - // *TODO: Rider for the moment keep AIS calls serialized otherwise the COF will tend to get out of sync. +static const std::map<std::string, U32> DefaultPoolSizes{ + {std::string("Upload"), 1}, + {std::string("AIS"), 1}, + // *TODO: Rider for the moment keep AIS calls serialized otherwise the COF will tend to get out of sync. +}; -#define DEFAULT_POOL_SIZE 5 +static const U32 DEFAULT_POOL_SIZE = 5; +const U32 LLCoprocedureManager::DEFAULT_QUEUE_SIZE = 4096; //========================================================================= class LLCoprocedurePool: private boost::noncopyable @@ -50,7 +56,7 @@ public: typedef LLCoprocedureManager::CoProcedure_t CoProcedure_t; LLCoprocedurePool(const std::string &name, size_t size); - virtual ~LLCoprocedurePool(); + ~LLCoprocedurePool(); /// Places the coprocedure on the queue for processing. /// @@ -60,36 +66,29 @@ public: /// @return This method returns a UUID that can be used later to cancel execution. LLUUID enqueueCoprocedure(const std::string &name, CoProcedure_t proc); - /// Cancel a coprocedure. If the coprocedure is already being actively executed - /// this method calls cancelSuspendedOperation() on the associated HttpAdapter - /// If it has not yet been dequeued it is simply removed from the queue. - bool cancelCoprocedure(const LLUUID &id); - - /// Requests a shutdown of the upload manager. Passing 'true' will perform - /// an immediate kill on the upload coroutine. - void shutdown(bool hardShutdown = false); - /// Returns the number of coprocedures in the queue awaiting processing. /// inline size_t countPending() const { - return mPendingCoprocs.size(); + return mPending; } /// Returns the number of coprocedures actively being processed. /// inline size_t countActive() const { - return mActiveCoprocs.size(); + return mActiveCoprocsCount; } /// Returns the total number of coprocedures either queued or in active processing. /// - inline size_t count() const + inline S32 count() const { return countPending() + countActive(); } + void close(); + private: struct QueuedCoproc { @@ -106,25 +105,27 @@ private: CoProcedure_t mProc; }; - // we use a deque here rather than std::queue since we want to be able to - // iterate through the queue and potentially erase an entry from the middle. - typedef std::deque<QueuedCoproc::ptr_t> CoprocQueue_t; - typedef std::map<LLUUID, LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t> ActiveCoproc_t; + // we use a buffered_channel here rather than unbuffered_channel since we want to be able to + // push values without blocking,even if there's currently no one calling a pop operation (due to + // fiber running right now) + typedef boost::fibers::buffered_channel<QueuedCoproc::ptr_t> CoprocQueue_t; + // Use shared_ptr to control the lifespan of our CoprocQueue_t instance + // because the consuming coroutine might outlive this LLCoprocedurePool + // instance. + typedef boost::shared_ptr<CoprocQueue_t> CoprocQueuePtr; std::string mPoolName; - size_t mPoolSize; - CoprocQueue_t mPendingCoprocs; - ActiveCoproc_t mActiveCoprocs; - bool mShutdown; - LLEventStream mWakeupTrigger; + size_t mPoolSize, mActiveCoprocsCount, mPending; + CoprocQueuePtr mPendingCoprocs; + LLTempBoundListener mStatusListener; typedef std::map<std::string, LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t> CoroAdapterMap_t; LLCore::HttpRequest::policy_t mHTTPPolicy; CoroAdapterMap_t mCoroMapping; - void coprocedureInvokerCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter); - + void coprocedureInvokerCoro(CoprocQueuePtr pendingCoprocs, + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter); }; //========================================================================= @@ -134,43 +135,53 @@ LLCoprocedureManager::LLCoprocedureManager() LLCoprocedureManager::~LLCoprocedureManager() { - + close(); } -LLCoprocedureManager::poolPtr_t LLCoprocedureManager::initializePool(const std::string &poolName) +void LLCoprocedureManager::initializePool(const std::string &poolName) { + poolMap_t::iterator it = mPoolMap.find(poolName); + + if (it != mPoolMap.end()) + { + // Pools are not supposed to be initialized twice + // Todo: ideally restrict init to STATE_FIRST + LL_ERRS() << "Pool is already present " << poolName << LL_ENDL; + return; + } + // Attempt to look up a pool size in the configuration. If found use that std::string keyName = "PoolSize" + poolName; int size = 0; - if (poolName.empty()) - LL_ERRS("CoprocedureManager") << "Poolname must not be empty" << LL_ENDL; + LL_ERRS_IF(poolName.empty(), "CoprocedureManager") << "Poolname must not be empty" << LL_ENDL; + LL_INFOS("CoprocedureManager") << "Initializing pool " << poolName << LL_ENDL; - if (mPropertyQueryFn && !mPropertyQueryFn.empty()) + if (mPropertyQueryFn) { size = mPropertyQueryFn(keyName); } if (size == 0) - { // if not found grab the know default... if there is no known + { + // if not found grab the know default... if there is no known // default use a reasonable number like 5. - std::map<std::string, U32>::iterator it = DefaultPoolSizes.find(poolName); - if (it == DefaultPoolSizes.end()) - size = DEFAULT_POOL_SIZE; - else - size = (*it).second; + auto it = DefaultPoolSizes.find(poolName); + size = (it != DefaultPoolSizes.end()) ? it->second : DEFAULT_POOL_SIZE; - if (mPropertyDefineFn && !mPropertyDefineFn.empty()) + if (mPropertyDefineFn) + { mPropertyDefineFn(keyName, size, "Coroutine Pool size for " + poolName); - LL_WARNS() << "LLCoprocedureManager: No setting for \"" << keyName << "\" setting pool size to default of " << size << LL_ENDL; + } + + LL_WARNS("CoProcMgr") << "LLCoprocedureManager: No setting for \"" << keyName << "\" setting pool size to default of " << size << LL_ENDL; } poolPtr_t pool(new LLCoprocedurePool(poolName, size)); - mPoolMap.insert(poolMap_t::value_type(poolName, pool)); + LL_ERRS_IF(!pool, "CoprocedureManager") << "Unable to create pool named \"" << poolName << "\" FATAL!" << LL_ENDL; - if (!pool) - LL_ERRS("CoprocedureManager") << "Unable to create pool named \"" << poolName << "\" FATAL!" << LL_ENDL; - return pool; + bool inserted = mPoolMap.emplace(poolName, pool).second; + LL_ERRS_IF(!inserted, "CoprocedureManager") << "Unable to add pool named \"" << poolName << "\" to map. FATAL!" << LL_ENDL; } //------------------------------------------------------------------------- @@ -178,53 +189,39 @@ LLUUID LLCoprocedureManager::enqueueCoprocedure(const std::string &pool, const s { // Attempt to find the pool and enqueue the procedure. If the pool does // not exist, create it. - poolPtr_t targetPool; poolMap_t::iterator it = mPoolMap.find(pool); if (it == mPoolMap.end()) { - targetPool = initializePool(pool); - } - else - { - targetPool = (*it).second; + // initializing pools in enqueueCoprocedure is not thread safe, + // at the moment pools need to be initialized manually + LL_ERRS() << "Uninitialized pool " << pool << LL_ENDL; } + poolPtr_t targetPool = it->second; return targetPool->enqueueCoprocedure(name, proc); } -void LLCoprocedureManager::cancelCoprocedure(const LLUUID &id) -{ - for (poolMap_t::const_iterator it = mPoolMap.begin(); it != mPoolMap.end(); ++it) - { - if ((*it).second->cancelCoprocedure(id)) - return; - } - LL_INFOS() << "Coprocedure not found." << LL_ENDL; -} - -void LLCoprocedureManager::shutdown(bool hardShutdown) -{ - for (poolMap_t::const_iterator it = mPoolMap.begin(); it != mPoolMap.end(); ++it) - { - (*it).second->shutdown(hardShutdown); - } - mPoolMap.clear(); -} - void LLCoprocedureManager::setPropertyMethods(SettingQuery_t queryfn, SettingUpdate_t updatefn) { + // functions to discover and store the pool sizes + // Might be a better idea to make an initializePool(name, size) to init everything externally mPropertyQueryFn = queryfn; mPropertyDefineFn = updatefn; + + initializePool("Upload"); + initializePool("AIS"); // it might be better to have some kind of on-demand initialization for AIS + // "ExpCache" pool gets initialized in LLExperienceCache + // asset storage pool gets initialized in LLViewerAssetStorage } //------------------------------------------------------------------------- size_t LLCoprocedureManager::countPending() const { size_t count = 0; - for (poolMap_t::const_iterator it = mPoolMap.begin(); it != mPoolMap.end(); ++it) + for (const auto& pair : mPoolMap) { - count += (*it).second->countPending(); + count += pair.second->countPending(); } return count; } @@ -235,7 +232,7 @@ size_t LLCoprocedureManager::countPending(const std::string &pool) const if (it == mPoolMap.end()) return 0; - return (*it).second->countPending(); + return it->second->countPending(); } size_t LLCoprocedureManager::countActive() const @@ -243,7 +240,7 @@ size_t LLCoprocedureManager::countActive() const size_t count = 0; for (poolMap_t::const_iterator it = mPoolMap.begin(); it != mPoolMap.end(); ++it) { - count += (*it).second->countActive(); + count += it->second->countActive(); } return count; } @@ -253,16 +250,18 @@ size_t LLCoprocedureManager::countActive(const std::string &pool) const poolMap_t::const_iterator it = mPoolMap.find(pool); if (it == mPoolMap.end()) + { return 0; - return (*it).second->countActive(); + } + return it->second->countActive(); } size_t LLCoprocedureManager::count() const { size_t count = 0; - for (poolMap_t::const_iterator it = mPoolMap.begin(); it != mPoolMap.end(); ++it) + for (const auto& pair : mPoolMap) { - count += (*it).second->count(); + count += pair.second->count(); } return count; } @@ -273,59 +272,88 @@ size_t LLCoprocedureManager::count(const std::string &pool) const if (it == mPoolMap.end()) return 0; - return (*it).second->count(); + return it->second->count(); +} + +void LLCoprocedureManager::close() +{ + for(auto & poolEntry : mPoolMap) + { + poolEntry.second->close(); + } +} + +void LLCoprocedureManager::close(const std::string &pool) +{ + poolMap_t::iterator it = mPoolMap.find(pool); + if (it != mPoolMap.end()) + { + it->second->close(); + } } //========================================================================= LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): mPoolName(poolName), mPoolSize(size), - mPendingCoprocs(), - mShutdown(false), - mWakeupTrigger("CoprocedurePool" + poolName, true), - mCoroMapping(), - mHTTPPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID) + mActiveCoprocsCount(0), + mPending(0), + mPendingCoprocs(boost::make_shared<CoprocQueue_t>(LLCoprocedureManager::DEFAULT_QUEUE_SIZE)), + mHTTPPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), + mCoroMapping() { + try + { + // store in our LLTempBoundListener so that when the LLCoprocedurePool is + // destroyed, we implicitly disconnect from this LLEventPump + // Monitores application status + mStatusListener = LLEventPumps::instance().obtain("LLApp").listen( + poolName + "_pool", // Make sure it won't repeat names from lleventcoro + [pendingCoprocs = mPendingCoprocs, poolName](const LLSD& status) + { + auto& statsd = status["status"]; + if (statsd.asString() != "running") + { + LL_INFOS("CoProcMgr") << "Pool " << poolName + << " closing queue because status " << statsd + << LL_ENDL; + // This should ensure that all waiting coprocedures in this + // pool will wake up and terminate. + pendingCoprocs->close(); + } + return false; + }); + } + catch (const LLEventPump::DupListenerName &) + { + // This shounldn't be possible since LLCoprocedurePool is supposed to have unique names, + // yet it somehow did happen, as result pools got '_pool' suffix and this catch. + // + // If this somehow happens again it is better to crash later on shutdown due to pump + // not stopping coroutine and see warning in logs than on startup or during login. + LL_WARNS("CoProcMgr") << "Attempted to register dupplicate listener name: " << poolName + << "_pool. Failed to start listener." << LL_ENDL; + + llassert(0); // Fix Me! Ignoring missing listener! + } + for (size_t count = 0; count < mPoolSize; ++count) { LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter( mPoolName + "Adapter", mHTTPPolicy)); - std::string pooledCoro = LLCoros::instance().launch("LLCoprocedurePool("+mPoolName+")::coprocedureInvokerCoro", - boost::bind(&LLCoprocedurePool::coprocedureInvokerCoro, this, httpAdapter)); + std::string pooledCoro = LLCoros::instance().launch( + "LLCoprocedurePool("+mPoolName+")::coprocedureInvokerCoro", + boost::bind(&LLCoprocedurePool::coprocedureInvokerCoro, this, + mPendingCoprocs, httpAdapter)); mCoroMapping.insert(CoroAdapterMap_t::value_type(pooledCoro, httpAdapter)); } - LL_INFOS() << "Created coprocedure pool named \"" << mPoolName << "\" with " << size << " items." << LL_ENDL; - - mWakeupTrigger.post(LLSD()); + LL_INFOS("CoProcMgr") << "Created coprocedure pool named \"" << mPoolName << "\" with " << size << " items, queue max " << LLCoprocedureManager::DEFAULT_QUEUE_SIZE << LL_ENDL; } LLCoprocedurePool::~LLCoprocedurePool() { - shutdown(); -} - -//------------------------------------------------------------------------- -void LLCoprocedurePool::shutdown(bool hardShutdown) -{ - CoroAdapterMap_t::iterator it; - - for (it = mCoroMapping.begin(); it != mCoroMapping.end(); ++it) - { - if (hardShutdown) - { - LLCoros::instance().kill((*it).first); - } - if ((*it).second) - { - (*it).second->cancelSuspendedOperation(); - } - } - - mShutdown = true; - mCoroMapping.clear(); - mPendingCoprocs.clear(); } //------------------------------------------------------------------------- @@ -333,76 +361,99 @@ LLUUID LLCoprocedurePool::enqueueCoprocedure(const std::string &name, LLCoproced { LLUUID id(LLUUID::generateNewID()); - mPendingCoprocs.push_back(QueuedCoproc::ptr_t(new QueuedCoproc(name, id, proc))); - LL_INFOS() << "Coprocedure(" << name << ") enqueued with id=" << id.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL; - - mWakeupTrigger.post(LLSD()); - - return id; -} - -bool LLCoprocedurePool::cancelCoprocedure(const LLUUID &id) -{ - // first check the active coroutines. If there, remove it and return. - ActiveCoproc_t::iterator itActive = mActiveCoprocs.find(id); - if (itActive != mActiveCoprocs.end()) + LL_INFOS("CoProcMgr") << "Coprocedure(" << name << ") enqueuing with id=" << id.asString() << " in pool \"" << mPoolName << "\" at " << mPending << LL_ENDL; + auto pushed = mPendingCoprocs->try_push(boost::make_shared<QueuedCoproc>(name, id, proc)); + if (pushed == boost::fibers::channel_op_status::success) { - LL_INFOS() << "Found and canceling active coprocedure with id=" << id.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL; - (*itActive).second->cancelSuspendedOperation(); - mActiveCoprocs.erase(itActive); - return true; + ++mPending; + return id; } - for (CoprocQueue_t::iterator it = mPendingCoprocs.begin(); it != mPendingCoprocs.end(); ++it) + // Here we didn't succeed in pushing. Shutdown could be the reason. + if (pushed == boost::fibers::channel_op_status::closed) { - if ((*it)->mId == id) - { - LL_INFOS() << "Found and removing queued coroutine(" << (*it)->mName << ") with Id=" << id.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL; - mPendingCoprocs.erase(it); - return true; - } + LL_WARNS("CoProcMgr") << "Discarding coprocedure '" << name << "' because shutdown" << LL_ENDL; + return {}; } - LL_INFOS() << "Coprocedure with Id=" << id.asString() << " was not found in pool \"" << mPoolName << "\"" << LL_ENDL; - return false; + // The queue should never fill up. + LL_ERRS("CoProcMgr") << "Enqueue into '" << name << "' failed (" << unsigned(pushed) << ")" << LL_ENDL; + return {}; // never executed, pacify the compiler } //------------------------------------------------------------------------- -void LLCoprocedurePool::coprocedureInvokerCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter) +void LLCoprocedurePool::coprocedureInvokerCoro( + CoprocQueuePtr pendingCoprocs, + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter) { - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - - while (!mShutdown) + for (;;) { - llcoro::suspendUntilEventOn(mWakeupTrigger); - if (mShutdown) + // It is VERY IMPORTANT that we instantiate a new ptr_t just before + // the pop_wait_for() call below. When this ptr_t was declared at + // function scope (outside the for loop), NickyD correctly diagnosed a + // mysterious hang condition due to: + // - the second time through the loop, the ptr_t held the last pointer + // to the previous QueuedCoproc, which indirectly held the last + // LLPointer to an LLInventoryCallback instance + // - while holding the lock on pendingCoprocs, pop_wait_for() assigned + // the popped value to the ptr_t variable + // - assignment destroyed the previous value of that variable, which + // indirectly destroyed the LLInventoryCallback + // - whose destructor called ~LLRequestServerAppearanceUpdateOnDestroy() + // - which called LLAppearanceMgr::requestServerAppearanceUpdate() + // - which called enqueueCoprocedure() + // - which tried to acquire the lock on pendingCoprocs... alas. + // Using a fresh, clean ptr_t ensures that no previous value is + // destroyed during pop_wait_for(). + QueuedCoproc::ptr_t coproc; + boost::fibers::channel_op_status status; + { + LLCoros::TempStatus st("waiting for work for 10s"); + status = pendingCoprocs->pop_wait_for(coproc, std::chrono::seconds(10)); + } + if (status == boost::fibers::channel_op_status::closed) + { break; - - while (!mPendingCoprocs.empty()) + } + + if(status == boost::fibers::channel_op_status::timeout) { - QueuedCoproc::ptr_t coproc = mPendingCoprocs.front(); - mPendingCoprocs.pop_front(); - ActiveCoproc_t::iterator itActive = mActiveCoprocs.insert(ActiveCoproc_t::value_type(coproc->mId, httpAdapter)).first; + LL_DEBUGS_ONCE("CoProcMgr") << "pool '" << mPoolName << "' waiting." << LL_ENDL; + continue; + } + // we actually popped an item + --mPending; + mActiveCoprocsCount++; - LL_INFOS() << "Dequeued and invoking coprocedure(" << coproc->mName << ") with id=" << coproc->mId.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL; + LL_DEBUGS("CoProcMgr") << "Dequeued and invoking coprocedure(" << coproc->mName << ") with id=" << coproc->mId.asString() << " in pool \"" << mPoolName << "\" (" << mPending << " left)" << LL_ENDL; - try - { - coproc->mProc(httpAdapter, coproc->mId); - } - catch (...) - { - LOG_UNHANDLED_EXCEPTION(STRINGIZE("Coprocedure('" << coproc->mName - << "', id=" << coproc->mId.asString() - << ") in pool '" << mPoolName << "'")); - // must NOT omit this or we deplete the pool - mActiveCoprocs.erase(itActive); - throw; - } + try + { + coproc->mProc(httpAdapter, coproc->mId); + } + catch (const LLCoros::Stop &e) + { + LL_INFOS("LLCoros") << "coprocedureInvokerCoro terminating because " + << e.what() << LL_ENDL; + throw; // let toplevel handle this as LLContinueError + } + catch (...) + { + LOG_UNHANDLED_EXCEPTION(STRINGIZE("Coprocedure('" << coproc->mName + << "', id=" << coproc->mId.asString() + << ") in pool '" << mPoolName << "'")); + // must NOT omit this or we deplete the pool + mActiveCoprocsCount--; + continue; + } - LL_INFOS() << "Finished coprocedure(" << coproc->mName << ")" << " in pool \"" << mPoolName << "\"" << LL_ENDL; + LL_DEBUGS("CoProcMgr") << "Finished coprocedure(" << coproc->mName << ")" << " in pool \"" << mPoolName << "\"" << LL_ENDL; - mActiveCoprocs.erase(itActive); - } + mActiveCoprocsCount--; } } + +void LLCoprocedurePool::close() +{ + mPendingCoprocs->close(); +} diff --git a/indra/llmessage/llcoproceduremanager.h b/indra/llmessage/llcoproceduremanager.h index 7d0e83180c..2d460826ff 100644 --- a/indra/llmessage/llcoproceduremanager.h +++ b/indra/llmessage/llcoproceduremanager.h @@ -32,6 +32,7 @@ #include "llcoros.h" #include "llcorehttputil.h" #include "lluuid.h" +#include <boost/smart_ptr/shared_ptr.hpp> class LLCoprocedurePool; @@ -57,11 +58,7 @@ public: /// Cancel a coprocedure. If the coprocedure is already being actively executed /// this method calls cancelYieldingOperation() on the associated HttpAdapter /// If it has not yet been dequeued it is simply removed from the queue. - void cancelCoprocedure(const LLUUID &id); - - /// Requests a shutdown of the upload manager. Passing 'true' will perform - /// an immediate kill on the upload coroutine. - void shutdown(bool hardShutdown = false); + //void cancelCoprocedure(const LLUUID &id); void setPropertyMethods(SettingQuery_t queryfn, SettingUpdate_t updatefn); @@ -80,6 +77,11 @@ public: size_t count() const; size_t count(const std::string &pool) const; + void close(); + void close(const std::string &pool); + + void initializePool(const std::string &poolName); + private: typedef boost::shared_ptr<LLCoprocedurePool> poolPtr_t; @@ -87,10 +89,11 @@ private: poolMap_t mPoolMap; - poolPtr_t initializePool(const std::string &poolName); - SettingQuery_t mPropertyQueryFn; SettingUpdate_t mPropertyDefineFn; + +public: + static const U32 DEFAULT_QUEUE_SIZE; }; #endif diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index 24387fbffd..0eae6d9826 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -597,7 +597,7 @@ LLSD HttpCoroJSONHandler::handleSuccess(LLCore::HttpResponse * response, LLCore: { bas >> jsonRoot; } - catch (std::runtime_error e) + catch (std::runtime_error& e) { // deserialization failed. Record the reason and pass back an empty map for markup. status = LLCore::HttpStatus(499, std::string(e.what())); return result; @@ -625,7 +625,7 @@ LLSD HttpCoroJSONHandler::parseBody(LLCore::HttpResponse *response, bool &succes { bas >> jsonRoot; } - catch (std::runtime_error e) + catch (std::runtime_error&) { success = false; return LLSD(); diff --git a/indra/llmessage/lldatapacker.cpp b/indra/llmessage/lldatapacker.cpp index 3510f93805..6cf6af6437 100644 --- a/indra/llmessage/lldatapacker.cpp +++ b/indra/llmessage/lldatapacker.cpp @@ -186,7 +186,7 @@ BOOL LLDataPackerBinaryBuffer::packString(const std::string& value, const char * if (mWriteEnabled) { - htonmemcpy(mCurBufferp, value.c_str(), MVT_VARIABLE, length); + htolememcpy(mCurBufferp, value.c_str(), MVT_VARIABLE, length); } mCurBufferp += length; return success; @@ -213,12 +213,12 @@ BOOL LLDataPackerBinaryBuffer::packBinaryData(const U8 *value, S32 size, const c if (mWriteEnabled) { - htonmemcpy(mCurBufferp, &size, MVT_S32, 4); + htolememcpy(mCurBufferp, &size, MVT_S32, 4); } mCurBufferp += 4; if (mWriteEnabled) { - htonmemcpy(mCurBufferp, value, MVT_VARIABLE, size); + htolememcpy(mCurBufferp, value, MVT_VARIABLE, size); } mCurBufferp += size; return success; @@ -229,12 +229,12 @@ BOOL LLDataPackerBinaryBuffer::unpackBinaryData(U8 *value, S32 &size, const char { BOOL success = TRUE; success &= verifyLength(4, name); - htonmemcpy(&size, mCurBufferp, MVT_S32, 4); + htolememcpy(&size, mCurBufferp, MVT_S32, 4); mCurBufferp += 4; success &= verifyLength(size, name); if (success) { - htonmemcpy(value, mCurBufferp, MVT_VARIABLE, size); + htolememcpy(value, mCurBufferp, MVT_VARIABLE, size); mCurBufferp += size; } else @@ -253,7 +253,7 @@ BOOL LLDataPackerBinaryBuffer::packBinaryDataFixed(const U8 *value, S32 size, co if (mWriteEnabled) { - htonmemcpy(mCurBufferp, value, MVT_VARIABLE, size); + htolememcpy(mCurBufferp, value, MVT_VARIABLE, size); } mCurBufferp += size; return success; @@ -264,7 +264,7 @@ BOOL LLDataPackerBinaryBuffer::unpackBinaryDataFixed(U8 *value, S32 size, const { BOOL success = TRUE; success &= verifyLength(size, name); - htonmemcpy(value, mCurBufferp, MVT_VARIABLE, size); + htolememcpy(value, mCurBufferp, MVT_VARIABLE, size); mCurBufferp += size; return success; } @@ -302,7 +302,7 @@ BOOL LLDataPackerBinaryBuffer::packU16(const U16 value, const char *name) if (mWriteEnabled) { - htonmemcpy(mCurBufferp, &value, MVT_U16, 2); + htolememcpy(mCurBufferp, &value, MVT_U16, 2); } mCurBufferp += 2; return success; @@ -314,7 +314,7 @@ BOOL LLDataPackerBinaryBuffer::unpackU16(U16 &value, const char *name) BOOL success = TRUE; success &= verifyLength(sizeof(U16), name); - htonmemcpy(&value, mCurBufferp, MVT_U16, 2); + htolememcpy(&value, mCurBufferp, MVT_U16, 2); mCurBufferp += 2; return success; } @@ -327,7 +327,7 @@ BOOL LLDataPackerBinaryBuffer::packU32(const U32 value, const char *name) if (mWriteEnabled) { - htonmemcpy(mCurBufferp, &value, MVT_U32, 4); + htolememcpy(mCurBufferp, &value, MVT_U32, 4); } mCurBufferp += 4; return success; @@ -339,7 +339,7 @@ BOOL LLDataPackerBinaryBuffer::unpackU32(U32 &value, const char *name) BOOL success = TRUE; success &= verifyLength(sizeof(U32), name); - htonmemcpy(&value, mCurBufferp, MVT_U32, 4); + htolememcpy(&value, mCurBufferp, MVT_U32, 4); mCurBufferp += 4; return success; } @@ -352,7 +352,7 @@ BOOL LLDataPackerBinaryBuffer::packS32(const S32 value, const char *name) if (mWriteEnabled) { - htonmemcpy(mCurBufferp, &value, MVT_S32, 4); + htolememcpy(mCurBufferp, &value, MVT_S32, 4); } mCurBufferp += 4; return success; @@ -364,7 +364,7 @@ BOOL LLDataPackerBinaryBuffer::unpackS32(S32 &value, const char *name) BOOL success = TRUE; success &= verifyLength(sizeof(S32), name); - htonmemcpy(&value, mCurBufferp, MVT_S32, 4); + htolememcpy(&value, mCurBufferp, MVT_S32, 4); mCurBufferp += 4; return success; } @@ -377,7 +377,7 @@ BOOL LLDataPackerBinaryBuffer::packF32(const F32 value, const char *name) if (mWriteEnabled) { - htonmemcpy(mCurBufferp, &value, MVT_F32, 4); + htolememcpy(mCurBufferp, &value, MVT_F32, 4); } mCurBufferp += 4; return success; @@ -389,7 +389,7 @@ BOOL LLDataPackerBinaryBuffer::unpackF32(F32 &value, const char *name) BOOL success = TRUE; success &= verifyLength(sizeof(F32), name); - htonmemcpy(&value, mCurBufferp, MVT_F32, 4); + htolememcpy(&value, mCurBufferp, MVT_F32, 4); mCurBufferp += 4; return success; } @@ -402,7 +402,7 @@ BOOL LLDataPackerBinaryBuffer::packColor4(const LLColor4 &value, const char *nam if (mWriteEnabled) { - htonmemcpy(mCurBufferp, value.mV, MVT_LLVector4, 16); + htolememcpy(mCurBufferp, value.mV, MVT_LLVector4, 16); } mCurBufferp += 16; return success; @@ -414,7 +414,7 @@ BOOL LLDataPackerBinaryBuffer::unpackColor4(LLColor4 &value, const char *name) BOOL success = TRUE; success &= verifyLength(16, name); - htonmemcpy(value.mV, mCurBufferp, MVT_LLVector4, 16); + htolememcpy(value.mV, mCurBufferp, MVT_LLVector4, 16); mCurBufferp += 16; return success; } @@ -427,7 +427,7 @@ BOOL LLDataPackerBinaryBuffer::packColor4U(const LLColor4U &value, const char *n if (mWriteEnabled) { - htonmemcpy(mCurBufferp, value.mV, MVT_VARIABLE, 4); + htolememcpy(mCurBufferp, value.mV, MVT_VARIABLE, 4); } mCurBufferp += 4; return success; @@ -439,7 +439,7 @@ BOOL LLDataPackerBinaryBuffer::unpackColor4U(LLColor4U &value, const char *name) BOOL success = TRUE; success &= verifyLength(4, name); - htonmemcpy(value.mV, mCurBufferp, MVT_VARIABLE, 4); + htolememcpy(value.mV, mCurBufferp, MVT_VARIABLE, 4); mCurBufferp += 4; return success; } @@ -453,8 +453,8 @@ BOOL LLDataPackerBinaryBuffer::packVector2(const LLVector2 &value, const char *n if (mWriteEnabled) { - htonmemcpy(mCurBufferp, &value.mV[0], MVT_F32, 4); - htonmemcpy(mCurBufferp+4, &value.mV[1], MVT_F32, 4); + htolememcpy(mCurBufferp, &value.mV[0], MVT_F32, 4); + htolememcpy(mCurBufferp+4, &value.mV[1], MVT_F32, 4); } mCurBufferp += 8; return success; @@ -466,8 +466,8 @@ BOOL LLDataPackerBinaryBuffer::unpackVector2(LLVector2 &value, const char *name) BOOL success = TRUE; success &= verifyLength(8, name); - htonmemcpy(&value.mV[0], mCurBufferp, MVT_F32, 4); - htonmemcpy(&value.mV[1], mCurBufferp+4, MVT_F32, 4); + htolememcpy(&value.mV[0], mCurBufferp, MVT_F32, 4); + htolememcpy(&value.mV[1], mCurBufferp+4, MVT_F32, 4); mCurBufferp += 8; return success; } @@ -480,7 +480,7 @@ BOOL LLDataPackerBinaryBuffer::packVector3(const LLVector3 &value, const char *n if (mWriteEnabled) { - htonmemcpy(mCurBufferp, value.mV, MVT_LLVector3, 12); + htolememcpy(mCurBufferp, value.mV, MVT_LLVector3, 12); } mCurBufferp += 12; return success; @@ -492,7 +492,7 @@ BOOL LLDataPackerBinaryBuffer::unpackVector3(LLVector3 &value, const char *name) BOOL success = TRUE; success &= verifyLength(12, name); - htonmemcpy(value.mV, mCurBufferp, MVT_LLVector3, 12); + htolememcpy(value.mV, mCurBufferp, MVT_LLVector3, 12); mCurBufferp += 12; return success; } @@ -504,7 +504,7 @@ BOOL LLDataPackerBinaryBuffer::packVector4(const LLVector4 &value, const char *n if (mWriteEnabled) { - htonmemcpy(mCurBufferp, value.mV, MVT_LLVector4, 16); + htolememcpy(mCurBufferp, value.mV, MVT_LLVector4, 16); } mCurBufferp += 16; return success; @@ -516,7 +516,7 @@ BOOL LLDataPackerBinaryBuffer::unpackVector4(LLVector4 &value, const char *name) BOOL success = TRUE; success &= verifyLength(16, name); - htonmemcpy(value.mV, mCurBufferp, MVT_LLVector4, 16); + htolememcpy(value.mV, mCurBufferp, MVT_LLVector4, 16); mCurBufferp += 16; return success; } @@ -528,7 +528,7 @@ BOOL LLDataPackerBinaryBuffer::packUUID(const LLUUID &value, const char *name) if (mWriteEnabled) { - htonmemcpy(mCurBufferp, value.mData, MVT_LLUUID, 16); + htolememcpy(mCurBufferp, value.mData, MVT_LLUUID, 16); } mCurBufferp += 16; return success; @@ -540,7 +540,7 @@ BOOL LLDataPackerBinaryBuffer::unpackUUID(LLUUID &value, const char *name) BOOL success = TRUE; success &= verifyLength(16, name); - htonmemcpy(value.mData, mCurBufferp, MVT_LLUUID, 16); + htolememcpy(value.mData, mCurBufferp, MVT_LLUUID, 16); mCurBufferp += 16; return success; } diff --git a/indra/llmessage/lldispatcher.cpp b/indra/llmessage/lldispatcher.cpp index c40fe0d389..717ef10f70 100644 --- a/indra/llmessage/lldispatcher.cpp +++ b/indra/llmessage/lldispatcher.cpp @@ -101,48 +101,70 @@ LLDispatchHandler* LLDispatcher::addHandler( // static bool LLDispatcher::unpackMessage( - LLMessageSystem* msg, - LLDispatcher::key_t& method, - LLUUID& invoice, - LLDispatcher::sparam_t& parameters) + LLMessageSystem* msg, + LLDispatcher::key_t& method, + LLUUID& invoice, + LLDispatcher::sparam_t& parameters) { - char buf[MAX_STRING]; /*Flawfinder: ignore*/ - msg->getStringFast(_PREHASH_MethodData, _PREHASH_Method, method); - msg->getUUIDFast(_PREHASH_MethodData, _PREHASH_Invoice, invoice); - S32 size; - S32 count = msg->getNumberOfBlocksFast(_PREHASH_ParamList); - for (S32 i = 0; i < count; ++i) - { - // we treat the SParam as binary data (since it might be an - // LLUUID in compressed form which may have embedded \0's,) - size = msg->getSizeFast(_PREHASH_ParamList, i, _PREHASH_Parameter); - if (size >= 0) - { - msg->getBinaryDataFast( - _PREHASH_ParamList, _PREHASH_Parameter, - buf, size, i, MAX_STRING-1); + char buf[MAX_STRING]; /*Flawfinder: ignore*/ + msg->getStringFast(_PREHASH_MethodData, _PREHASH_Method, method); + msg->getUUIDFast(_PREHASH_MethodData, _PREHASH_Invoice, invoice); + S32 size; + S32 count = msg->getNumberOfBlocksFast(_PREHASH_ParamList); + for (S32 i = 0; i < count; ++i) + { + // we treat the SParam as binary data (since it might be an + // LLUUID in compressed form which may have embedded \0's,) + size = msg->getSizeFast(_PREHASH_ParamList, i, _PREHASH_Parameter); + if (size >= 0) + { + msg->getBinaryDataFast( + _PREHASH_ParamList, _PREHASH_Parameter, + buf, size, i, MAX_STRING - 1); - // If the last byte of the data is 0x0, this is either a normally - // packed string, or a binary packed UUID (which for these messages - // are packed with a 17th byte 0x0). Unpack into a std::string - // without the trailing \0, so "abc\0" becomes std::string("abc", 3) - // which matches const char* "abc". - if (size > 0 - && buf[size-1] == 0x0) - { - // special char*/size constructor because UUIDs may have embedded - // 0x0 bytes. - std::string binary_data(buf, size-1); - parameters.push_back(binary_data); - } - else - { - // This is either a NULL string, or a string that was packed - // incorrectly as binary data, without the usual trailing '\0'. - std::string string_data(buf, size); - parameters.push_back(string_data); - } - } - } - return true; + // If the last byte of the data is 0x0, this is either a normally + // packed string, or a binary packed UUID (which for these messages + // are packed with a 17th byte 0x0). Unpack into a std::string + // without the trailing \0, so "abc\0" becomes std::string("abc", 3) + // which matches const char* "abc". + if (size > 0 + && buf[size - 1] == 0x0) + { + // special char*/size constructor because UUIDs may have embedded + // 0x0 bytes. + std::string binary_data(buf, size - 1); + parameters.push_back(binary_data); + } + else + { + // This is either a NULL string, or a string that was packed + // incorrectly as binary data, without the usual trailing '\0'. + std::string string_data(buf, size); + parameters.push_back(string_data); + } + } + } + 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 @@ public: LLUUID& invoice, sparam_t& parameters); + static bool unpackLargeMessage( + LLMessageSystem* msg, + key_t& method, + LLUUID& invoice, + sparam_t& parameters); + protected: typedef std::map<key_t, LLDispatchHandler*> dispatch_map_t; dispatch_map_t mHandlers; diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index aa7b3c1260..db22ad2ea3 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -85,15 +85,15 @@ const F64 LLExperienceCache::DEFAULT_EXPIRATION = 600.0; const S32 LLExperienceCache::DEFAULT_QUOTA = 128; // this is megabytes const int LLExperienceCache::SEARCH_PAGE_SIZE = 30; +bool LLExperienceCache::sShutdown = false; + //========================================================================= -LLExperienceCache::LLExperienceCache(): - mShutdown(false) +LLExperienceCache::LLExperienceCache() { } LLExperienceCache::~LLExperienceCache() { - } void LLExperienceCache::initSingleton() @@ -108,6 +108,8 @@ void LLExperienceCache::initSingleton() cache_stream >> (*this); } + LLCoprocedureManager::instance().initializePool("ExpCache"); + LLCoros::instance().launch("LLExperienceCache::idleCoro", boost::bind(&LLExperienceCache::idleCoro, this)); @@ -122,7 +124,7 @@ void LLExperienceCache::cleanup() { cache_stream << (*this); } - mShutdown = true; + sShutdown = true; } //------------------------------------------------------------------------- @@ -338,13 +340,13 @@ void LLExperienceCache::requestExperiences() F64 now = LLFrameTimer::getTotalSeconds(); const U32 EXP_URL_SEND_THRESHOLD = 3000; - const U32 PAGE_SIZE = EXP_URL_SEND_THRESHOLD / UUID_STR_LENGTH; + const U32 PAGE_SIZE1 = EXP_URL_SEND_THRESHOLD / UUID_STR_LENGTH; std::ostringstream ostr; - ostr << urlBase << "?page_size=" << PAGE_SIZE; + ostr << urlBase << "?page_size=" << PAGE_SIZE1; RequestQueue_t requests; - while (!mRequestQueue.empty()) + while (!mRequestQueue.empty() && !sShutdown) { RequestQueue_t::iterator it = mRequestQueue.begin(); LLUUID key = (*it); @@ -360,7 +362,7 @@ void LLExperienceCache::requestExperiences() boost::bind(&LLExperienceCache::requestExperiencesCoro, this, _1, ostr.str(), requests) ); ostr.str(std::string()); - ostr << urlBase << "?page_size=" << PAGE_SIZE; + ostr << urlBase << "?page_size=" << PAGE_SIZE1; requests.clear(); } } @@ -398,8 +400,6 @@ void LLExperienceCache::idleCoro() LL_INFOS("ExperienceCache") << "Launching Experience cache idle coro." << LL_ENDL; do { - llcoro::suspendUntilTimeout(SECS_BETWEEN_REQUESTS); - if (mEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT)) { eraseExpired(); @@ -410,7 +410,9 @@ void LLExperienceCache::idleCoro() requestExperiences(); } - } while (!mShutdown); + llcoro::suspendUntilTimeout(SECS_BETWEEN_REQUESTS); + + } while (!sShutdown); // 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.) diff --git a/indra/llmessage/llexperiencecache.h b/indra/llmessage/llexperiencecache.h index f9ff69c2b6..1c97133723 100644 --- a/indra/llmessage/llexperiencecache.h +++ b/indra/llmessage/llexperiencecache.h @@ -142,7 +142,7 @@ private: LLFrameTimer mEraseExpiredTimer; // Periodically clean out expired entries from the cache CapabilityQuery_t mCapability; std::string mCacheFileName; - bool mShutdown; + static bool sShutdown; // control for coroutines, they exist out of LLExperienceCache's scope, so they need a static control void idleCoro(); void eraseExpired(); diff --git a/indra/llmessage/llextendedstatus.h b/indra/llmessage/llextendedstatus.h index 8ce173d1ff..9923d73c1a 100644 --- a/indra/llmessage/llextendedstatus.h +++ b/indra/llmessage/llextendedstatus.h @@ -28,40 +28,36 @@ #ifndef LL_LLEXTENDEDSTATUS_H #define LL_LLEXTENDEDSTATUS_H - -typedef S32 LLExtStat; - - -// Status provider groups - Top bits indicate which status type it is -// Zero is common status code (next section) -const LLExtStat LL_EXSTAT_CURL_RESULT = 1L<<30; // serviced by curl - use 1L if we really implement the below -const LLExtStat LL_EXSTAT_RES_RESULT = 2L<<30; // serviced by resident copy -const LLExtStat LL_EXSTAT_VFS_RESULT = 3L<<30; // serviced by vfs - - -// Common Status Codes -// -const LLExtStat LL_EXSTAT_NONE = 0x00000; // No extra info here - sorry! -const LLExtStat LL_EXSTAT_NULL_UUID = 0x10001; // null asset ID -const LLExtStat LL_EXSTAT_NO_UPSTREAM = 0x10002; // attempt to upload without a valid upstream method/provider -const LLExtStat LL_EXSTAT_REQUEST_DROPPED = 0x10003; // request was dropped unserviced -const LLExtStat LL_EXSTAT_NONEXISTENT_FILE = 0x10004; // trying to upload a file that doesn't exist -const LLExtStat LL_EXSTAT_BLOCKED_FILE = 0x10005; // trying to upload a file that we can't open - - -// curl status codes: -// -// Mask off LL_EXSTAT_CURL_RESULT for original result and -// see: libraries/include/curl/curl.h - - -// Memory-Resident status codes: -// None at present - - -// VFS status codes: -const LLExtStat LL_EXSTAT_VFS_CACHED = LL_EXSTAT_VFS_RESULT | 0x0001; -const LLExtStat LL_EXSTAT_VFS_CORRUPT = LL_EXSTAT_VFS_RESULT | 0x0002; +enum class LLExtStat: uint32_t +{ + // Status provider groups - Top bits indicate which status type it is + // Zero is common status code (next section) + CURL_RESULT = 1UL<<30, // serviced by curl - use 1L if we really implement the below + RES_RESULT = 2UL<<30, // serviced by resident copy + VFS_RESULT = 3UL<<30, // serviced by vfs + + + // Common Status Codes + // + NONE = 0x00000, // No extra info here - sorry! + NULL_UUID = 0x10001, // null asset ID + NO_UPSTREAM = 0x10002, // attempt to upload without a valid upstream method/provider + REQUEST_DROPPED = 0x10003, // request was dropped unserviced + NONEXISTENT_FILE= 0x10004, // trying to upload a file that doesn't exist + BLOCKED_FILE = 0x10005, // trying to upload a file that we can't open + + // curl status codes: + // + // Mask off CURL_RESULT for original result and + // see: libraries/include/curl/curl.h + + // Memory-Resident status codes: + // None at present + + // VFS status codes: + VFS_CACHED = VFS_RESULT | 0x0001, + VFS_CORRUPT = VFS_RESULT | 0x0002, +}; #endif // LL_LLEXTENDEDSTATUS_H diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp index 04b34a296c..6fd17c9154 100644 --- a/indra/llmessage/llhttpnode.cpp +++ b/indra/llmessage/llhttpnode.cpp @@ -125,7 +125,7 @@ void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) cons { response->result(simpleGet()); } - catch (NotImplemented) + catch (NotImplemented&) { response->methodNotAllowed(); } @@ -138,7 +138,7 @@ void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, cons { response->result(simplePut(input)); } - catch (NotImplemented) + catch (NotImplemented&) { response->methodNotAllowed(); } @@ -151,7 +151,7 @@ void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, con { response->result(simplePost(input)); } - catch (NotImplemented) + catch (NotImplemented&) { response->methodNotAllowed(); } @@ -164,7 +164,7 @@ void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) cons { response->result(simpleDel(context)); } - catch (NotImplemented) + catch (NotImplemented&) { response->methodNotAllowed(); } diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp index 7caf0766b7..a9cc71c365 100644 --- a/indra/llmessage/lliosocket.cpp +++ b/indra/llmessage/lliosocket.cpp @@ -62,9 +62,9 @@ bool is_addr_in_use(apr_status_t status) #endif } -#if LL_LINUX +#if ! LL_WINDOWS // Define this to see the actual file descriptors being tossed around. -//#define LL_DEBUG_SOCKET_FILE_DESCRIPTORS 1 +#define LL_DEBUG_SOCKET_FILE_DESCRIPTORS 1 #if LL_DEBUG_SOCKET_FILE_DESCRIPTORS #include "apr_portable.h" #endif @@ -77,7 +77,7 @@ void ll_debug_socket(const char* msg, apr_socket_t* apr_sock) #if LL_DEBUG_SOCKET_FILE_DESCRIPTORS if(!apr_sock) { - LL_DEBUGS() << "Socket -- " << (msg?msg:"") << ": no socket." << LL_ENDL; + LL_DEBUGS("Socket") << "Socket -- " << (msg?msg:"") << ": no socket." << LL_ENDL; return; } // *TODO: Why doesn't this work? @@ -85,12 +85,12 @@ 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)) { - LL_DEBUGS() << "Socket -- " << (msg?msg:"") << " on fd " << os_sock + LL_DEBUGS("Socket") << "Socket -- " << (msg?msg:"") << " on fd " << os_sock << " at " << apr_sock << LL_ENDL; } else { - LL_DEBUGS() << "Socket -- " << (msg?msg:"") << " no fd " + LL_DEBUGS("Socket") << "Socket -- " << (msg?msg:"") << " no fd " << " at " << apr_sock << LL_ENDL; } #endif @@ -144,6 +144,9 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port, const c if(new_pool) apr_pool_destroy(new_pool); return rv; } + // At this point, the new LLSocket instance takes ownership of new_pool, + // which is why no early return below this call explicitly destroys it: it + // is instead cleaned up by ~LLSocket(). rv = ptr_t(new LLSocket(socket, new_pool)); if(port > 0) { @@ -186,7 +189,7 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port, const c } } } - else + else // port <= 0 { // we need to indicate that we have an ephemeral port if the // previous calls were successful. It will diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp index 134154aa6c..fcda2a85f6 100644 --- a/indra/llmessage/llmail.cpp +++ b/indra/llmessage/llmail.cpp @@ -373,7 +373,7 @@ std::string LLMail::encryptIMEmailAddress(const LLUUID& from_agent_id, // Convert input data into a binary blob std::vector<U8> data; data.resize(data_size); - // *NOTE: This may suffer from endian issues. Could be htonmemcpy. + // *NOTE: This may suffer from endian issues. Could be htolememcpy. memcpy(&data[0], &time, 4); memcpy(&data[4], &from_agent_id.mData[0], UUID_BYTES); memcpy(&data[4 + UUID_BYTES], &to_agent_id.mData[0], UUID_BYTES); diff --git a/indra/llmessage/llmessagetemplate.cpp b/indra/llmessage/llmessagetemplate.cpp index c4c7e66703..e70e259436 100644 --- a/indra/llmessage/llmessagetemplate.cpp +++ b/indra/llmessage/llmessagetemplate.cpp @@ -47,7 +47,7 @@ void LLMsgVarData::addData(const void *data, S32 size, EMsgVariableType type, S3 { delete[] mData; // Delete it if it already exists mData = new U8[size]; - htonmemcpy(mData, data, mType, size); + htolememcpy(mData, data, mType, size); } } diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp index dea03aab85..749e599c66 100644 --- a/indra/llmessage/llproxy.cpp +++ b/indra/llmessage/llproxy.cpp @@ -40,6 +40,7 @@ // incoming packet just to do a simple bool test. The getter for this // member is also static bool LLProxy::sUDPProxyEnabled = false; +LLProxy* LLProxy::sProxyInstance = NULL; // Some helpful TCP static functions. static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen); // Do a TCP data handshake @@ -60,11 +61,21 @@ LLProxy::LLProxy(): LLProxy::~LLProxy() { - if (ll_apr_is_initialized()) - { - stopSOCKSProxy(); - disableHTTPProxy(); - } + if (ll_apr_is_initialized()) + { + // locks mutex + stopSOCKSProxy(); + disableHTTPProxy(); + } + // The primary safety of sProxyInstance is the fact that by the + // point SUBSYSTEM_CLEANUP(LLProxy) gets called, nothing should + // be capable of using proxy + sProxyInstance = NULL; +} + +void LLProxy::initSingleton() +{ + sProxyInstance = this; } /** @@ -115,9 +126,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] = (char)(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] = (char)(socks_password.size()); memcpy(&password_auth[socks_username.size() + 3], socks_password.c_str(), socks_password.size()); authmethod_password_reply_t password_reply; @@ -403,8 +414,11 @@ LLSocks5AuthType LLProxy::getSelectedAuthMethod() const //static void LLProxy::cleanupClass() { - getInstance()->stopSOCKSProxy(); - deleteSingleton(); + if (instanceExists()) + { + getInstance()->stopSOCKSProxy(); + deleteSingleton(); + } } /** @@ -421,28 +435,28 @@ void LLProxy::cleanupClass() void LLProxy::applyProxySettings(CURL* handle) { // Do a faster unlocked check to see if we are supposed to proxy. - if (mHTTPProxyEnabled) + if (sProxyInstance && sProxyInstance->mHTTPProxyEnabled) { - // We think we should proxy, lock the proxy mutex. - LLMutexLock lock(&mProxyMutex); + // We think we should proxy, lock the proxy mutex. sProxyInstance is not protected by mutex + LLMutexLock lock(&sProxyInstance->mProxyMutex); // Now test again to verify that the proxy wasn't disabled between the first check and the lock. - if (mHTTPProxyEnabled) + if (sProxyInstance->mHTTPProxyEnabled) { - LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str()), CURLOPT_PROXY); - LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort()), CURLOPT_PROXYPORT); + LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXY, sProxyInstance->mHTTPProxy.getIPString().c_str()), CURLOPT_PROXY); + LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, sProxyInstance->mHTTPProxy.getPort()), CURLOPT_PROXYPORT); - if (mProxyType == LLPROXY_SOCKS) + if (sProxyInstance->mProxyType == LLPROXY_SOCKS) { - LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5), CURLOPT_PROXYTYPE); - if (mAuthMethodSelected == METHOD_PASSWORD) + LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5), CURLOPT_PROXYTYPE); + if (sProxyInstance->mAuthMethodSelected == METHOD_PASSWORD) { - std::string auth_string = mSocksUsername + ":" + mSocksPassword; - LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()), CURLOPT_PROXYUSERPWD); + std::string auth_string = sProxyInstance->mSocksUsername + ":" + sProxyInstance->mSocksPassword; + LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()), CURLOPT_PROXYUSERPWD); } } else { - LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP), CURLOPT_PROXYTYPE); + LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP), CURLOPT_PROXYTYPE); } } } diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h index 87891901ad..25f6977e14 100644 --- a/indra/llmessage/llproxy.h +++ b/indra/llmessage/llproxy.h @@ -32,6 +32,7 @@ #include "llmemory.h" #include "llsingleton.h" #include "llthread.h" +#include "llmutex.h" #include <curl/curl.h> #include <string> @@ -225,6 +226,8 @@ class LLProxy: public LLSingleton<LLProxy> LLSINGLETON(LLProxy); LOG_CLASS(LLProxy); + /*virtual*/ void initSingleton(); + public: // Static check for enabled status for UDP packets. Call from main thread only. static bool isSOCKSProxyEnabled() { return sUDPProxyEnabled; } @@ -250,7 +253,7 @@ public: // Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false. // Safe to call from any thread. - void applyProxySettings(CURL* handle); + static void applyProxySettings(CURL* handle); // Start a connection to the SOCKS 5 proxy. Call from main thread only. S32 startSOCKSProxy(LLHost host); @@ -343,6 +346,10 @@ private: /*########################################################################################### END OF SHARED MEMBERS ###########################################################################################*/ + + // A hack to get arround getInstance() and capture_dependency() which are unsafe to use inside threads + // set/reset on init/cleanup, strictly for use in applyProxySettings + static LLProxy* sProxyInstance; }; #endif diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h index e1ccd333f1..c13f39df9b 100644 --- a/indra/llmessage/llregionflags.h +++ b/indra/llmessage/llregionflags.h @@ -54,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_SKIP_COLLISIONS = (1 << 12); // Pin all non agent rigid bodies const U64 REGION_FLAGS_SKIP_SCRIPTS = (1 << 13); const U64 REGION_FLAGS_SKIP_PHYSICS = (1 << 14); // Skip all physics diff --git a/indra/llmessage/llteleportflags.h b/indra/llmessage/llteleportflags.h index b3fcad036e..fd1e702832 100644 --- a/indra/llmessage/llteleportflags.h +++ b/indra/llmessage/llteleportflags.h @@ -44,6 +44,8 @@ const U32 TELEPORT_FLAGS_VIA_REGION_ID = 1 << 12; const U32 TELEPORT_FLAGS_IS_FLYING = 1 << 13; const U32 TELEPORT_FLAGS_SHOW_RESET_HOME = 1 << 14; const U32 TELEPORT_FLAGS_FORCE_REDIRECT = 1 << 15; // used to force a redirect to some random location - used when kicking someone from land. +const U32 TELEPORT_FLAGS_VIA_GLOBAL_COORDS = 1 << 16; +const U32 TELEPORT_FLAGS_WITHIN_REGION = 1 << 17; const U32 TELEPORT_FLAGS_MASK_VIA = TELEPORT_FLAGS_VIA_LURE | TELEPORT_FLAGS_VIA_LANDMARK diff --git a/indra/llmessage/lltemplatemessagebuilder.cpp b/indra/llmessage/lltemplatemessagebuilder.cpp index 8d7c4c0282..5ac5f6c580 100644 --- a/indra/llmessage/lltemplatemessagebuilder.cpp +++ b/indra/llmessage/lltemplatemessagebuilder.cpp @@ -689,14 +689,14 @@ static S32 buildBlock(U8* buffer, S32 buffer_size, const LLMessageBlock* templat { case 1: sizeb = size; - htonmemcpy(&buffer[result], &sizeb, MVT_U8, 1); + htolememcpy(&buffer[result], &sizeb, MVT_U8, 1); break; case 2: sizeh = size; - htonmemcpy(&buffer[result], &sizeh, MVT_U16, 2); + htolememcpy(&buffer[result], &sizeh, MVT_U16, 2); break; case 4: - htonmemcpy(&buffer[result], &size, MVT_S32, 4); + htolememcpy(&buffer[result], &size, MVT_S32, 4); break; default: LL_ERRS() << "Attempting to build variable field with unknown size of " << size << LL_ENDL; diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index 4e0c53c37e..6d5ad0ba08 100644 --- a/indra/llmessage/lltemplatemessagereader.cpp +++ b/indra/llmessage/lltemplatemessagereader.cpp @@ -645,15 +645,15 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender switch(data_size) { case 1: - htonmemcpy(&tsizeb, &buffer[decode_pos], MVT_U8, 1); + htolememcpy(&tsizeb, &buffer[decode_pos], MVT_U8, 1); tsize = tsizeb; break; case 2: - htonmemcpy(&tsizeh, &buffer[decode_pos], MVT_U16, 2); + htolememcpy(&tsizeh, &buffer[decode_pos], MVT_U16, 2); tsize = tsizeh; break; case 4: - htonmemcpy(&tsize, &buffer[decode_pos], MVT_U32, 4); + htolememcpy(&tsize, &buffer[decode_pos], MVT_U32, 4); break; default: LL_ERRS() << "Attempting to read variable field with unknown size of " << data_size << LL_ENDL; diff --git a/indra/llmessage/lltransfertargetvfile.cpp b/indra/llmessage/lltransfertargetvfile.cpp index a572c68a7f..b27f0881e0 100644 --- a/indra/llmessage/lltransfertargetvfile.cpp +++ b/indra/llmessage/lltransfertargetvfile.cpp @@ -227,7 +227,7 @@ void LLTransferTargetVFile::completionCallback(const LLTSCode status) mParams.getAssetID(), mParams.getAssetType(), mParams.mRequestDatap, - LL_EXSTAT_NONE); + LLExtStat::NONE); } delete mParams.mRequestDatap; mParams.mRequestDatap = NULL; diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp index c8b9d5d19f..93d5cfc131 100644 --- a/indra/llmessage/llxfer.cpp +++ b/indra/llmessage/llxfer.cpp @@ -245,7 +245,7 @@ void LLXfer::sendPacket(S32 packet_num) num_copy); } fdata_size += sizeof(S32); - htonmemcpy(fdata_buf,&mXferSize, MVT_S32, sizeof(S32)); + htolememcpy(fdata_buf,&mXferSize, MVT_S32, sizeof(S32)); } S32 encoded_packetnum = encodePacketNum(packet_num,last_packet); @@ -319,7 +319,7 @@ S32 LLXfer::processEOF() if (mCallback) { - mCallback(mCallbackDataHandle,mCallbackResult,LL_EXSTAT_NONE); + mCallback(mCallbackDataHandle,mCallbackResult, LLExtStat::NONE); } return(retval); diff --git a/indra/llmessage/llxfer_mem.cpp b/indra/llmessage/llxfer_mem.cpp index 78a3e4f558..da8534ecdc 100644 --- a/indra/llmessage/llxfer_mem.cpp +++ b/indra/llmessage/llxfer_mem.cpp @@ -112,7 +112,7 @@ S32 LLXfer_Mem::processEOF() if (mCallback) { - mCallback((void *)mBuffer,mBufferLength,mCallbackDataHandle,mCallbackResult,LL_EXSTAT_NONE); + mCallback((void *)mBuffer,mBufferLength,mCallbackDataHandle,mCallbackResult, LLExtStat::NONE); } return(retval); diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 6ef4025ab1..da62bb12e8 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -117,8 +117,8 @@ void LLMessageHandlerBridge::post(LLHTTPNode::ResponsePtr response, gMessageSystem->mLastSender = LLHost(input["sender"].asString()); gMessageSystem->mPacketsIn += 1; gMessageSystem->mLLSDMessageReader->setMessage(namePtr, input["body"]); - gMessageSystem->mMessageReader = gMessageSystem->mLLSDMessageReader; - + LockMessageReader rdr(gMessageSystem->mMessageReader, gMessageSystem->mLLSDMessageReader); + if(gMessageSystem->callHandler(namePtr, false, gMessageSystem)) { response->result(LLSD()); @@ -189,7 +189,7 @@ void LLMessageSystem::init() mTimingCallbackData = NULL; mMessageBuilder = NULL; - mMessageReader = NULL; + LockMessageReader(mMessageReader, NULL); } // Read file and build message templates @@ -230,7 +230,6 @@ LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port, mTemplateMessageReader = new LLTemplateMessageReader(mMessageNumbers); mLLSDMessageReader = new LLSDMessageReader(); - mMessageReader = NULL; // initialize various bits of net info mSocket = 0; @@ -330,7 +329,6 @@ LLMessageSystem::~LLMessageSystem() delete mTemplateMessageReader; mTemplateMessageReader = NULL; - mMessageReader = NULL; delete mTemplateMessageBuilder; mTemplateMessageBuilder = NULL; @@ -480,11 +478,12 @@ LLCircuitData* LLMessageSystem::findCircuit(const LLHost& host, } // Returns TRUE if a valid, on-circuit message has been received. -BOOL LLMessageSystem::checkMessages( S64 frame_count ) +// Requiring a non-const LockMessageChecker reference ensures that +// mMessageReader has been set to mTemplateMessageReader. +BOOL LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) { // Pump BOOL valid_packet = FALSE; - mMessageReader = mTemplateMessageReader; LLTransferTargetVFile::updateQueue(); @@ -748,7 +747,7 @@ S32 LLMessageSystem::getReceiveBytes() const } -void LLMessageSystem::processAcks(F32 collect_time) +void LLMessageSystem::processAcks(LockMessageChecker&, F32 collect_time) { F64Seconds mt_sec = getMessageTimeSeconds(); { @@ -2062,8 +2061,9 @@ void LLMessageSystem::dispatch( return; } // enable this for output of message names - //LL_INFOS("Messaging") << "< \"" << msg_name << "\"" << LL_ENDL; - //LL_DEBUGS() << "data: " << LLSDNotationStreamer(message) << LL_ENDL; + LL_DEBUGS("Messaging") << "< \"" << msg_name << "\"" << LL_ENDL; + LL_DEBUGS("Messaging") << "context: " << context << LL_ENDL; + LL_DEBUGS("Messaging") << "message: " << message << LL_ENDL; handler->post(responsep, context, message); } @@ -3268,6 +3268,8 @@ void null_message_callback(LLMessageSystem *msg, void **data) // up, and then sending auth messages. void LLMessageSystem::establishBidirectionalTrust(const LLHost &host, S64 frame_count ) { + LockMessageChecker lmc(this); + std::string shared_secret = get_shared_secret(); if(shared_secret.empty()) { @@ -3287,7 +3289,7 @@ void LLMessageSystem::establishBidirectionalTrust(const LLHost &host, S64 frame_ addU8Fast(_PREHASH_PingID, 0); addU32Fast(_PREHASH_OldestUnacked, 0); sendMessage(host); - if (checkMessages( frame_count )) + if (lmc.checkMessages( frame_count )) { if (isMessageFast(_PREHASH_CompletePingCheck) && (getSender() == host)) @@ -3295,7 +3297,7 @@ void LLMessageSystem::establishBidirectionalTrust(const LLHost &host, S64 frame_ break; } } - processAcks(); + lmc.processAcks(); ms_sleep(1); } @@ -3314,8 +3316,8 @@ void LLMessageSystem::establishBidirectionalTrust(const LLHost &host, S64 frame_ cdp = mCircuitInfo.findCircuit(host); if(!cdp) break; // no circuit anymore, no point continuing. if(cdp->getTrusted()) break; // circuit is trusted. - checkMessages(frame_count); - processAcks(); + lmc.checkMessages(frame_count); + lmc.processAcks(); ms_sleep(1); } } @@ -3973,11 +3975,18 @@ void LLMessageSystem::setTimeDecodesSpamThreshold( F32 seconds ) LLMessageReader::setTimeDecodesSpamThreshold(seconds); } +LockMessageChecker::LockMessageChecker(LLMessageSystem* msgsystem): + // for the lifespan of this LockMessageChecker instance, use + // LLTemplateMessageReader as msgsystem's mMessageReader + LockMessageReader(msgsystem->mMessageReader, msgsystem->mTemplateMessageReader), + mMessageSystem(msgsystem) +{} + // HACK! babbage: return true if message rxed via either UDP or HTTP // TODO: babbage: move gServicePump in to LLMessageSystem? -bool LLMessageSystem::checkAllMessages(S64 frame_count, LLPumpIO* http_pump) +bool LLMessageSystem::checkAllMessages(LockMessageChecker& lmc, S64 frame_count, LLPumpIO* http_pump) { - if(checkMessages(frame_count)) + if(lmc.checkMessages(frame_count)) { return true; } diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index f6c5d9e228..e25a9ea7ef 100644 --- a/indra/llmessage/message.h +++ b/indra/llmessage/message.h @@ -35,10 +35,6 @@ #include <netinet/in.h> #endif -#if LL_SOLARIS -#include <netinet/in.h> -#endif - #if LL_WINDOWS #include "winsock2.h" // htons etc. #endif @@ -61,6 +57,8 @@ #include "llstoredmessage.h" #include "boost/function.hpp" #include "llpounceable.h" +#include "llcoros.h" +#include LLCOROS_MUTEX_HEADER const U32 MESSAGE_MAX_STRINGS_LENGTH = 64; const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192; @@ -199,6 +197,91 @@ public: virtual void complete(const LLHost& host, const LLUUID& agent) const = 0; }; +/** + * SL-12204: We've observed crashes when consumer code sets + * LLMessageSystem::mMessageReader, assuming that all subsequent processing of + * the current message will use the same mMessageReader value -- only to have + * a different coroutine sneak in and replace mMessageReader before + * completion. This is a limitation of sharing a stateful global resource for + * message parsing; instead code receiving a new message should instantiate a + * (trivially constructed) local message parser and use that. + * + * Until then, when one coroutine sets a particular LLMessageReader subclass + * as the current message reader, ensure that no other coroutine can replace + * it until the first coroutine has finished with its message. + * + * This is achieved with two helper classes. LLMessageSystem::mMessageReader + * is now an LLMessageReaderPointer instance, which can efficiently compare or + * dereference its contained LLMessageReader* but which cannot be directly + * assigned. To change the value of LLMessageReaderPointer, you must + * instantiate LockMessageReader with the LLMessageReader* you wish to make + * current. mMessageReader will have that value for the lifetime of the + * LockMessageReader instance, then revert to nullptr. Moreover, as its name + * implies, LockMessageReader locks the mutex in LLMessageReaderPointer so + * that any other coroutine instantiating LockMessageReader will block until + * the first coroutine has destroyed its instance. + */ +class LLMessageReaderPointer +{ +public: + LLMessageReaderPointer(): mPtr(nullptr) {} + // It is essential that comparison and dereferencing must be fast, which + // is why we don't check for nullptr when dereferencing. + LLMessageReader* operator->() const { return mPtr; } + bool operator==(const LLMessageReader* other) const { return mPtr == other; } + bool operator!=(const LLMessageReader* other) const { return ! (*this == other); } +private: + // Only LockMessageReader can set mPtr. + friend class LockMessageReader; + LLMessageReader* mPtr; + LLCoros::Mutex mMutex; +}; + +/** + * To set mMessageReader to nullptr: + * + * @code + * // use an anonymous instance that is destroyed immediately + * LockMessageReader(gMessageSystem->mMessageReader, nullptr); + * @endcode + * + * Why do we still require going through LockMessageReader at all? Because it + * would be Bad if any coroutine set mMessageReader to nullptr while another + * coroutine was still parsing a message. + */ +class LockMessageReader +{ +public: + LockMessageReader(LLMessageReaderPointer& var, LLMessageReader* instance): + mVar(var.mPtr), + mLock(var.mMutex) + { + mVar = instance; + } + // Some compilers reportedly fail to suppress generating implicit copy + // operations even though we have a move-only LockType data member. + LockMessageReader(const LockMessageReader&) = delete; + LockMessageReader& operator=(const LockMessageReader&) = delete; + ~LockMessageReader() + { + mVar = nullptr; + } +private: + // capture a reference to LLMessageReaderPointer::mPtr + decltype(LLMessageReaderPointer::mPtr)& mVar; + // while holding a lock on LLMessageReaderPointer::mMutex + LLCoros::LockType mLock; +}; + +/** + * LockMessageReader is great as long as you only need mMessageReader locked + * during a single LLMessageSystem function call. However, empirically the + * sequence from checkAllMessages() through processAcks() need mMessageReader + * locked to LLTemplateMessageReader. Enforce that by making them require an + * instance of LockMessageChecker. + */ +class LockMessageChecker; + class LLMessageSystem : public LLMessageSenderInterface { private: @@ -331,8 +414,8 @@ public: bool addCircuitCode(U32 code, const LLUUID& session_id); 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(F32 collect_time = 0.f); + BOOL checkMessages(LockMessageChecker&, S64 frame_count = 0 ); + void processAcks(LockMessageChecker&, F32 collect_time = 0.f); BOOL isMessageFast(const char *msg); BOOL isMessage(const char *msg) @@ -730,7 +813,7 @@ public: const LLSD& data); // Check UDP messages and pump http_pump to receive HTTP messages. - bool checkAllMessages(S64 frame_count, LLPumpIO* http_pump); + bool checkAllMessages(LockMessageChecker&, S64 frame_count, LLPumpIO* http_pump); // Moved to allow access from LLTemplateMessageDispatcher void clearReceiveState(); @@ -817,12 +900,13 @@ private: LLMessageBuilder* mMessageBuilder; LLTemplateMessageBuilder* mTemplateMessageBuilder; LLSDMessageBuilder* mLLSDMessageBuilder; - LLMessageReader* mMessageReader; + LLMessageReaderPointer mMessageReader; LLTemplateMessageReader* mTemplateMessageReader; LLSDMessageReader* mLLSDMessageReader; friend class LLMessageHandlerBridge; - + friend class LockMessageChecker; + bool callHandler(const char *name, bool trustedSource, LLMessageSystem* msg); @@ -835,6 +919,40 @@ private: // external hook into messaging system extern LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem; +// Implementation of LockMessageChecker depends on definition of +// LLMessageSystem, hence must follow it. +class LockMessageChecker: public LockMessageReader +{ +public: + LockMessageChecker(LLMessageSystem* msgsystem); + + // For convenience, provide forwarding wrappers so you can call (e.g.) + // checkAllMessages() on your LockMessageChecker instance instead of + // passing the instance to LLMessageSystem::checkAllMessages(). Use + // perfect forwarding to avoid having to maintain these wrappers in sync + // with the target methods. + template <typename... ARGS> + bool checkAllMessages(ARGS&&... args) + { + return mMessageSystem->checkAllMessages(*this, std::forward<ARGS>(args)...); + } + + template <typename... ARGS> + bool checkMessages(ARGS&&... args) + { + return mMessageSystem->checkMessages(*this, std::forward<ARGS>(args)...); + } + + template <typename... ARGS> + void processAcks(ARGS&&... args) + { + return mMessageSystem->processAcks(*this, std::forward<ARGS>(args)...); + } + +private: + LLMessageSystem* mMessageSystem; +}; + // Must specific overall system version, which is used to determine // if a patch is available in the message template checksum verification. // Return true if able to initialize system. @@ -860,10 +978,10 @@ void null_message_callback(LLMessageSystem *msg, void **data); // #if !defined( LL_BIG_ENDIAN ) && !defined( LL_LITTLE_ENDIAN ) -#error Unknown endianness for htonmemcpy. Did you miss a common include? +#error Unknown endianness for htolememcpy. Did you miss a common include? #endif -static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, size_t n) +static inline void *htolememcpy(void *vs, const void *vct, EMsgVariableType type, size_t n) { char *s = (char *)vs; const char *ct = (const char *)vct; @@ -886,7 +1004,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_S16: if (n != 2) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN *(s + 1) = *(ct); @@ -901,7 +1019,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_F32: if (n != 4) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN *(s + 3) = *(ct); @@ -918,7 +1036,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_F64: if (n != 8) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN *(s + 7) = *(ct); @@ -938,12 +1056,12 @@ 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) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN - htonmemcpy(s + 8, ct + 8, MVT_F32, 4); - htonmemcpy(s + 4, ct + 4, MVT_F32, 4); - return(htonmemcpy(s, ct, MVT_F32, 4)); + htolememcpy(s + 8, ct + 8, MVT_F32, 4); + htolememcpy(s + 4, ct + 4, MVT_F32, 4); + return(htolememcpy(s, ct, MVT_F32, 4)); #else return(memcpy(s,ct,n)); /* Flawfinder: ignore */ #endif @@ -951,12 +1069,12 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_LLVector3d: if (n != 24) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN - htonmemcpy(s + 16, ct + 16, MVT_F64, 8); - htonmemcpy(s + 8, ct + 8, MVT_F64, 8); - return(htonmemcpy(s, ct, MVT_F64, 8)); + htolememcpy(s + 16, ct + 16, MVT_F64, 8); + htolememcpy(s + 8, ct + 8, MVT_F64, 8); + return(htolememcpy(s, ct, MVT_F64, 8)); #else return(memcpy(s,ct,n)); /* Flawfinder: ignore */ #endif @@ -964,13 +1082,13 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_LLVector4: if (n != 16) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN - htonmemcpy(s + 12, ct + 12, MVT_F32, 4); - htonmemcpy(s + 8, ct + 8, MVT_F32, 4); - htonmemcpy(s + 4, ct + 4, MVT_F32, 4); - return(htonmemcpy(s, ct, MVT_F32, 4)); + htolememcpy(s + 12, ct + 12, MVT_F32, 4); + htolememcpy(s + 8, ct + 8, MVT_F32, 4); + htolememcpy(s + 4, ct + 4, MVT_F32, 4); + return(htolememcpy(s, ct, MVT_F32, 4)); #else return(memcpy(s,ct,n)); /* Flawfinder: ignore */ #endif @@ -978,12 +1096,12 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_U16Vec3: if (n != 6) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN - htonmemcpy(s + 4, ct + 4, MVT_U16, 2); - htonmemcpy(s + 2, ct + 2, MVT_U16, 2); - return(htonmemcpy(s, ct, MVT_U16, 2)); + htolememcpy(s + 4, ct + 4, MVT_U16, 2); + htolememcpy(s + 2, ct + 2, MVT_U16, 2); + return(htolememcpy(s, ct, MVT_U16, 2)); #else return(memcpy(s,ct,n)); /* Flawfinder: ignore */ #endif @@ -991,13 +1109,13 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_U16Quat: if (n != 8) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN - htonmemcpy(s + 6, ct + 6, MVT_U16, 2); - htonmemcpy(s + 4, ct + 4, MVT_U16, 2); - htonmemcpy(s + 2, ct + 2, MVT_U16, 2); - return(htonmemcpy(s, ct, MVT_U16, 2)); + htolememcpy(s + 6, ct + 6, MVT_U16, 2); + htolememcpy(s + 4, ct + 4, MVT_U16, 2); + htolememcpy(s + 2, ct + 2, MVT_U16, 2); + return(htolememcpy(s, ct, MVT_U16, 2)); #else return(memcpy(s,ct,n)); /* Flawfinder: ignore */ #endif @@ -1005,15 +1123,15 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_S16Array: if (n % 2) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN length = n % 2; for (i = 1; i < length; i++) { - htonmemcpy(s + i*2, ct + i*2, MVT_S16, 2); + htolememcpy(s + i*2, ct + i*2, MVT_S16, 2); } - return(htonmemcpy(s, ct, MVT_S16, 2)); + return(htolememcpy(s, ct, MVT_S16, 2)); #else return(memcpy(s,ct,n)); #endif @@ -1025,7 +1143,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, inline void *ntohmemcpy(void *s, const void *ct, EMsgVariableType type, size_t n) { - return(htonmemcpy(s,ct,type, n)); + return(htolememcpy(s,ct,type, n)); } inline const LLHost& LLMessageSystem::getReceivingInterface() const {return mLastReceivingIF;} diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index f8e11e324e..fba5b7453d 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -1376,7 +1376,9 @@ char const* const _PREHASH_RegionDenyAgeUnverified = LLMessageStringTable::getIn 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"); @@ -1392,3 +1394,4 @@ char const* const _PREHASH_AppearanceHover = LLMessageStringTable::getInstance() 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"); +char const* const _PREHASH_LargeGenericMessage = LLMessageStringTable::getInstance()->getString("LargeGenericMessage"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index 334236fb25..4f72c01ddf 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -1376,6 +1376,9 @@ 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; @@ -1391,4 +1394,6 @@ extern char const* const _PREHASH_AppearanceHover; extern char const* const _PREHASH_HoverHeight; extern char const* const _PREHASH_Experience; extern char const* const _PREHASH_ExperienceID; +extern char const* const _PREHASH_LargeGenericMessage; + #endif diff --git a/indra/llmessage/tests/llareslistener_test.cpp b/indra/llmessage/tests/llareslistener_test.cpp index c04696c86b..254185cbd0 100644 --- a/indra/llmessage/tests/llareslistener_test.cpp +++ b/indra/llmessage/tests/llareslistener_test.cpp @@ -138,15 +138,9 @@ namespace tut WrapLLErrs capture; LLSD request; request["op"] = "foo"; - std::string threw; - try - { - LLEventPumps::instance().obtain("LLAres").post(request); - } - catch (const WrapLLErrs::FatalException& e) - { - threw = e.what(); - } + std::string threw = capture.catch_llerrs([&request](){ + LLEventPumps::instance().obtain("LLAres").post(request); + }); ensure_contains("LLAresListener bad op", threw, "bad"); } @@ -157,15 +151,9 @@ namespace tut WrapLLErrs capture; LLSD request; request["op"] = "rewriteURI"; - std::string threw; - try - { - LLEventPumps::instance().obtain("LLAres").post(request); - } - catch (const WrapLLErrs::FatalException& e) - { - threw = e.what(); - } + std::string threw = capture.catch_llerrs([&request](){ + LLEventPumps::instance().obtain("LLAres").post(request); + }); ensure_contains("LLAresListener bad req", threw, "missing"); ensure_contains("LLAresListener bad req", threw, "reply"); ensure_contains("LLAresListener bad req", threw, "uri"); @@ -179,15 +167,9 @@ namespace tut LLSD request; request["op"] = "rewriteURI"; request["reply"] = "nonexistent"; - std::string threw; - try - { - LLEventPumps::instance().obtain("LLAres").post(request); - } - catch (const WrapLLErrs::FatalException& e) - { - threw = e.what(); - } + std::string threw = capture.catch_llerrs([&request](){ + LLEventPumps::instance().obtain("LLAres").post(request); + }); ensure_contains("LLAresListener bad req", threw, "missing"); ensure_contains("LLAresListener bad req", threw, "uri"); ensure_does_not_contain("LLAresListener bad req", threw, "reply"); @@ -201,15 +183,9 @@ namespace tut LLSD request; request["op"] = "rewriteURI"; request["uri"] = "foo.bar.com"; - std::string threw; - try - { - LLEventPumps::instance().obtain("LLAres").post(request); - } - catch (const WrapLLErrs::FatalException& e) - { - threw = e.what(); - } + std::string threw = capture.catch_llerrs([&request](){ + LLEventPumps::instance().obtain("LLAres").post(request); + }); ensure_contains("LLAresListener bad req", threw, "missing"); ensure_contains("LLAresListener bad req", threw, "reply"); ensure_does_not_contain("LLAresListener bad req", threw, "uri"); diff --git a/indra/llmessage/tests/llcoproceduremanager_test.cpp b/indra/llmessage/tests/llcoproceduremanager_test.cpp new file mode 100644 index 0000000000..6424117ef3 --- /dev/null +++ b/indra/llmessage/tests/llcoproceduremanager_test.cpp @@ -0,0 +1,179 @@ +/** + * @file llcoproceduremanager_test.cpp + * @author Brad + * @date 2019-02 + * @brief LLCoprocedureManager unit test + * + * $LicenseInfo:firstyear=2019&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 "llwin32headers.h" + +#include "linden_common.h" +#include "llsdserialize.h" + +#include "../llcoproceduremanager.h" + +#include <functional> + +#include <boost/fiber/fiber.hpp> +#include <boost/fiber/buffered_channel.hpp> +#include <boost/fiber/unbuffered_channel.hpp> + +#include "../test/lltut.h" +#include "../test/sync.h" + + +#if LL_WINDOWS +// disable unreachable code warnings +#pragma warning(disable: 4702) +#endif + +LLCoreHttpUtil::HttpCoroutineAdapter::HttpCoroutineAdapter(std::string const&, unsigned int, unsigned int) +{ +} + +void LLCoreHttpUtil::HttpCoroutineAdapter::cancelSuspendedOperation() +{ +} + +LLCoreHttpUtil::HttpCoroutineAdapter::~HttpCoroutineAdapter() +{ +} + +LLCore::HttpRequest::HttpRequest() +{ +} + +LLCore::HttpRequest::~HttpRequest() +{ +} + +namespace tut +{ + struct coproceduremanager_test + { + coproceduremanager_test() + { + } + + ~coproceduremanager_test() + { + LLCoprocedureManager::instance().close(); + } + }; + typedef test_group<coproceduremanager_test> coproceduremanager_t; + typedef coproceduremanager_t::object coproceduremanager_object_t; + tut::coproceduremanager_t tut_coproceduremanager("LLCoprocedureManager"); + + + template<> template<> + void coproceduremanager_object_t::test<1>() + { + Sync sync; + int foo = 0; + LLCoprocedureManager::instance().initializePool("PoolName"); + LLUUID queueId = LLCoprocedureManager::instance().enqueueCoprocedure("PoolName", "ProcName", + [&foo, &sync] (LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t & ptr, const LLUUID & id) { + sync.bump(); + foo = 1; + }); + + sync.yield(); + ensure_equals("coprocedure failed to update foo", foo, 1); + + LLCoprocedureManager::instance().close("PoolName"); + } + + template<> template<> + void coproceduremanager_object_t::test<2>() + { + const size_t capacity = 2; + boost::fibers::buffered_channel<std::function<void(void)>> chan(capacity); + + boost::fibers::fiber worker([&chan]() { + chan.value_pop()(); + }); + + chan.push([]() { + LL_INFOS("Test") << "test 1" << LL_ENDL; + }); + + worker.join(); + } + + template<> template<> + void coproceduremanager_object_t::test<3>() + { + boost::fibers::unbuffered_channel<std::function<void(void)>> chan; + + boost::fibers::fiber worker([&chan]() { + chan.value_pop()(); + }); + + chan.push([]() { + LL_INFOS("Test") << "test 1" << LL_ENDL; + }); + + worker.join(); + } + + template<> template<> + void coproceduremanager_object_t::test<4>() + { + boost::fibers::buffered_channel<std::function<void(void)>> chan(4); + + boost::fibers::fiber worker([&chan]() { + std::function<void(void)> f; + + // using namespace std::chrono_literals; + // const auto timeout = 5s; + // boost::fibers::channel_op_status status; + while (chan.pop(f) != boost::fibers::channel_op_status::closed) + { + LL_INFOS("CoWorker") << "got coproc" << LL_ENDL; + f(); + } + LL_INFOS("CoWorker") << "got closed" << LL_ENDL; + }); + + int counter = 0; + + for (int i = 0; i < 5; ++i) + { + LL_INFOS("CoMain") << "pushing coproc " << i << LL_ENDL; + chan.push([&counter]() { + LL_INFOS("CoProc") << "in coproc" << LL_ENDL; + ++counter; + }); + } + + LL_INFOS("CoMain") << "closing channel" << LL_ENDL; + chan.close(); + + LL_INFOS("CoMain") << "joining worker" << LL_ENDL; + worker.join(); + + LL_INFOS("CoMain") << "checking count" << LL_ENDL; + ensure_equals("coprocedure failed to update counter", counter, 5); + } +} // namespace tut diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 78b1483810..6d51adc685 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -664,12 +664,14 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie 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); @@ -855,12 +857,12 @@ void LLPluginClassMedia::paste() } void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path_cache, - const std::string &user_data_path_cookies, + const std::string &username, const std::string &user_data_path_cef_log) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path"); - message.setValue("cache_path", user_data_path_cache); - message.setValue("cookies_path", user_data_path_cookies); + message.setValue("cache_path", user_data_path_cache); + message.setValue("username", username); // cef shares cache between users but creates user-based contexts message.setValue("cef_log_file", user_data_path_cef_log); bool cef_verbose_log = gSavedSettings.getBOOL("CefVerboseLog"); @@ -1136,6 +1138,10 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) mDebugMessageLevel = message.getValue("message_level"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_DEBUG_MESSAGE); } + else if (message_name == "tooltip_text") + { + mHoverText = message.getValue("tooltip"); + } else { LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 4f52afb317..382f891e0c 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -118,7 +118,7 @@ public: 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 ); @@ -195,7 +195,7 @@ public: bool canPaste() const { return mCanPaste; }; // 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_cache, const std::string &user_data_path_cookies, const std::string &user_data_path_cef_log); + void setUserDataPath(const std::string &user_data_path_cache, const std::string &username, 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); diff --git a/indra/llplugin/llpluginmessagepipe.h b/indra/llplugin/llpluginmessagepipe.h index c3498beac0..9d5835eb82 100644 --- a/indra/llplugin/llpluginmessagepipe.h +++ b/indra/llplugin/llpluginmessagepipe.h @@ -31,6 +31,7 @@ #include "lliosocket.h" #include "llthread.h" +#include "llmutex.h" class LLPluginMessagePipe; diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp index e24d222cb6..d93ec8cf4b 100644 --- a/indra/llplugin/llpluginprocesschild.cpp +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -33,7 +33,7 @@ #include "llpluginmessagepipe.h" #include "llpluginmessageclasses.h" -static const F32 GOODBYE_SECONDS = 20.0f; +static const F32 GOODBYE_SECONDS = 12.0f; // Do not set it to be bigger than mPluginLockupTimeout or parent will kill LLPluginProcessChild static const F32 HEARTBEAT_SECONDS = 1.0f; static const F32 PLUGIN_IDLE_SECONDS = 1.0f / 100.0f; // Each call to idle will give the plugin this much time. @@ -218,8 +218,25 @@ void LLPluginProcessChild::idle(void) if (mWaitGoodbye.hasExpired()) { LL_WARNS() << "Wait for goodbye expired. Advancing to UNLOADED" << LL_ENDL; + if (mInstance != NULL) + { + // Something went wrong, at least make sure plugin will terminate + sendMessageToPlugin(LLPluginMessage("base", "force_exit")); + } setState(STATE_UNLOADED); } + + if (mInstance) + { + // Provide some time to the plugin + // example: CEF on "cleanup" sets shutdown request, but it still needs idle loop to actually shutdown + LLPluginMessage message("base", "idle"); + message.setValueReal("time", PLUGIN_IDLE_SECONDS); + sendMessageToPlugin(message); + + mInstance->idle(); + } + break; case STATE_UNLOADED: @@ -253,7 +270,7 @@ void LLPluginProcessChild::sleep(F64 seconds) } else { - ms_sleep((int)(seconds * 1000.0f)); + ms_sleep((int)(seconds * 1000.0f)); } } diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index eb6cb1b503..e5b4dec1bd 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -152,8 +152,18 @@ void LLPluginProcessParent::shutdown() mapInstances_t::iterator it; for (it = sInstances.begin(); it != sInstances.end(); ++it) { - (*it).second->setState(STATE_GOODBYE); - (*it).second->idle(); + EState state = (*it).second->mState; + if (state != STATE_CLEANUP + && state != STATE_EXITING + && state != STATE_DONE + && state != STATE_ERROR) + { + (*it).second->setState(STATE_GOODBYE); + } + if (state != STATE_DONE) + { + (*it).second->idle(); + } } sInstances.clear(); } diff --git a/indra/llplugin/slplugin/CMakeLists.txt b/indra/llplugin/slplugin/CMakeLists.txt index 33520ad64c..e4f64448c5 100644 --- a/indra/llplugin/slplugin/CMakeLists.txt +++ b/indra/llplugin/slplugin/CMakeLists.txt @@ -63,6 +63,7 @@ set_target_properties(SLPlugin endif () target_link_libraries(SLPlugin + ${LEGACY_STDIO_LIBS} ${LLPLUGIN_LIBRARIES} ${LLMESSAGE_LIBRARIES} ${LLCOMMON_LIBRARIES} diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt index dd2e806dda..7b6d04b096 100644 --- a/indra/llprimitive/CMakeLists.txt +++ b/indra/llprimitive/CMakeLists.txt @@ -80,7 +80,7 @@ target_link_libraries(llprimitive ${LLXML_LIBRARIES} ${LLPHYSICSEXTENSIONS_LIBRARIES} ${LLCHARACTER_LIBRARIES} - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ) diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index 8f75d89e5a..dfa29fb539 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -343,7 +343,7 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa return LLModel::NO_ERRORS ; } -LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly) +LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly, LLSD& log_msg) { domPRef p = poly->getP(); domListOfUInts& idx = p->getValue(); @@ -403,6 +403,7 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac LLVolumeFace::VertexMapData::PointMap point_map; U32 cur_idx = 0; + bool log_tc_msg = true; for (U32 i = 0; i < vcount.getCount(); ++i) { //for each polygon U32 first_index = 0; @@ -426,8 +427,21 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac if (tc_source) { - cv.mTexCoord.setVec(tc[idx[cur_idx+tc_offset]*2+0], - tc[idx[cur_idx+tc_offset]*2+1]); + U64 idx_x = idx[cur_idx + tc_offset] * 2 + 0; + U64 idx_y = idx[cur_idx + tc_offset] * 2 + 1; + + if (idx_y < tc.getCount()) + { + cv.mTexCoord.setVec(tc[idx_x], tc[idx_y]); + } + else if (log_tc_msg) + { + log_tc_msg = false; + LL_WARNS() << "Texture coordinates data is not complete." << LL_ENDL; + LLSD args; + args["Message"] = "IncompleteTC"; + log_msg.append(args); + } } if (norm_source) @@ -1215,7 +1229,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do for (S32 i = 0; i < childCount; ++i) { domNode* pNode = daeSafeCast<domNode>(children[i]); - if ( isNodeAJoint( pNode ) ) + if (pNode) { processJointNode( pNode, mJointList ); } @@ -1458,7 +1472,8 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do 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 ( mJointMap.find( lookingForJoint ) != mJointMap.end() ) + if (mJointMap.find(lookingForJoint) != mJointMap.end() + && model->mSkinInfo.mInvBindMatrix.size() > i) { LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i]; newInverse.setTranslation( mJointList[lookingForJoint].getTranslation() ); @@ -1470,6 +1485,12 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do } } + U32 bind_count = model->mSkinInfo.mAlternateBindMatrix.size(); + if (bind_count > 0 && bind_count != jointCnt) + { + LL_WARNS("Mesh") << "Model " << model->mLabel << " has invalid joint bind matrix list." << LL_ENDL; + } + //grab raw position array domVertices* verts = mesh->getVertices(); @@ -1784,7 +1805,7 @@ void LLDAELoader::extractTranslationViaElement( daeElement* pTranslateElement, L { if ( pTranslateElement ) { - domTranslate* pTranslateChild = dynamic_cast<domTranslate*>( pTranslateElement ); + domTranslate* pTranslateChild = static_cast<domTranslate*>( pTranslateElement ); domFloat3 translateChild = pTranslateChild->getValue(); LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); transform.setTranslation( singleJointTranslation ); @@ -1834,59 +1855,61 @@ void LLDAELoader::processJointNode( domNode* pNode, JointTransformMap& jointTran //LL_WARNS()<<"ProcessJointNode# Node:" <<pNode->getName()<<LL_ENDL; //1. handle the incoming node - extract out translation via SID or element + if (isNodeAJoint(pNode)) + { + LLMatrix4 workingTransform; - LLMatrix4 workingTransform; - - //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolverA( pNode, "./translate" ); - domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() ); - daeSIDResolver jointResolverB( pNode, "./location" ); - domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() ); + //Pull out the translate id and store it in the jointTranslations map + daeSIDResolver jointResolverA(pNode, "./translate"); + domTranslate* pTranslateA = daeSafeCast<domTranslate>(jointResolverA.getElement()); + daeSIDResolver jointResolverB(pNode, "./location"); + domTranslate* pTranslateB = daeSafeCast<domTranslate>(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() ) - { - //LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL; - daeSIDResolver jointResolver( pNode, "./matrix" ); - domMatrix* pMatrix = daeSafeCast<domMatrix>( jointResolver.getElement() ); - if ( pMatrix ) - { - //LL_INFOS()<<"A matrix SID was however found!"<<LL_ENDL; - 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]; - } - } - } - else - { - LL_WARNS()<< "The found element is not translate or matrix node - most likely a corrupt export!" <<LL_ENDL; - } - } - else - { - extractTranslationViaElement( pTranslateElement, workingTransform ); - } - } + //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()) + { + //LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL; + daeSIDResolver jointResolver(pNode, "./matrix"); + domMatrix* pMatrix = daeSafeCast<domMatrix>(jointResolver.getElement()); + if (pMatrix) + { + //LL_INFOS()<<"A matrix SID was however found!"<<LL_ENDL; + 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]; + } + } + } + else + { + LL_WARNS() << "The found element is not translate or matrix node - most likely a corrupt export!" << LL_ENDL; + } + } + else + { + extractTranslationViaElement(pTranslateElement, workingTransform); + } + } - //Store the working transform relative to the nodes name. - jointTransforms[ pNode->getName() ] = workingTransform; + //Store the working transform relative to the nodes name. + jointTransforms[pNode->getName()] = workingTransform; + } //2. handle the nodes children @@ -2356,7 +2379,7 @@ LLColor4 LLDAELoader::getDaeColor(daeElement* element) return value; } -bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh) +bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD& log_msg) { LLModel::EModelStatus status = LLModel::NO_ERRORS; domTriangles_Array& tris = mesh->getTriangles_array(); @@ -2378,7 +2401,7 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh) for (U32 i = 0; i < polys.getCount(); ++i) { domPolylistRef& poly = polys.get(i); - status = load_face_from_dom_polylist(pModel->getVolumeFaces(), pModel->getMaterialList(), poly); + status = load_face_from_dom_polylist(pModel->getVolumeFaces(), pModel->getMaterialList(), poly, log_msg); if(status != LLModel::NO_ERRORS) { @@ -2442,7 +2465,7 @@ bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& mo // Get the whole set of volume faces // - addVolumeFacesFromDomMesh(ret, mesh); + addVolumeFacesFromDomMesh(ret, mesh, mWarningsArray); U32 volume_faces = ret->getNumVolumeFaces(); @@ -2515,7 +2538,8 @@ bool LLDAELoader::createVolumeFacesFromDomMesh(LLModel* pModel, domMesh* mesh) { pModel->ClearFacesAndMaterials(); - addVolumeFacesFromDomMesh(pModel, mesh); + LLSD placeholder; + addVolumeFacesFromDomMesh(pModel, mesh, placeholder); if (pModel->getNumVolumeFaces() > 0) { diff --git a/indra/llprimitive/lldaeloader.h b/indra/llprimitive/lldaeloader.h index 4e990dbe5e..2b211343e1 100644 --- a/indra/llprimitive/lldaeloader.h +++ b/indra/llprimitive/lldaeloader.h @@ -89,7 +89,7 @@ protected: //Verify that a controller matches vertex counts bool verifyController( domController* pController ); - static bool addVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh); + static bool addVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh, LLSD& log_msg); static bool createVolumeFacesFromDomMesh(LLModel* model, domMesh *mesh); static LLModel* loadModelFromDomMesh(domMesh* mesh); diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 37548e3fe3..702a1b5238 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -434,7 +434,7 @@ void LLModel::generateNormals(F32 angle_cutoff) if (vol_face.mNumIndices > 65535) { - LL_WARNS() << "Too many vertices for normal generation to work." << LL_ENDL; + LL_WARNS("MESHSKININFO") << "Too many vertices for normal generation to work." << LL_ENDL; continue; } @@ -1100,7 +1100,7 @@ bool LLModel::loadModel(std::istream& is) { if (!LLSDSerialize::fromBinary(header, is, 1024*1024*1024)) { - LL_WARNS() << "Mesh header parse error. Not a valid mesh asset!" << LL_ENDL; + LL_WARNS("MESHSKININFO") << "Mesh header parse error. Not a valid mesh asset!" << LL_ENDL; return false; } } @@ -1132,7 +1132,7 @@ bool LLModel::loadModel(std::istream& is) if (header[lod_name[lod]]["offset"].asInteger() == -1 || header[lod_name[lod]]["size"].asInteger() == 0 ) { //cannot load requested LOD - LL_WARNS() << "LoD data is invalid!" << LL_ENDL; + LL_WARNS("MESHSKININFO") << "LoD data is invalid!" << LL_ENDL; return false; } @@ -1195,7 +1195,7 @@ bool LLModel::loadModel(std::istream& is) } else { - LL_WARNS() << "unpackVolumeFaces failed!" << LL_ENDL; + LL_WARNS("MESHSKININFO") << "unpackVolumeFaces failed!" << LL_ENDL; } return false; @@ -1223,7 +1223,7 @@ bool LLModel::isMaterialListSubset( LLModel* ref ) if (!foundRef) { - LL_INFOS() << "Could not find material " << mMaterialList[src] << " in reference model " << ref->mLabel << LL_ENDL; + LL_INFOS("MESHSKININFO") << "Could not find material " << mMaterialList[src] << " in reference model " << ref->mLabel << LL_ENDL; return false; } } @@ -1259,7 +1259,7 @@ bool LLModel::matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCn bool isASubset = isMaterialListSubset( ref ); if ( !isASubset ) { - LL_INFOS()<<"Material of model is not a subset of reference."<<LL_ENDL; + LL_INFOS("MESHSKININFO")<<"Material of model is not a subset of reference."<<LL_ENDL; return false; } @@ -1398,6 +1398,14 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) mInvBindMatrix.push_back(mat); } + + if (mJointNames.size() != mInvBindMatrix.size()) + { + LL_WARNS("MESHSKININFO") << "Joints vs bind matrix count mismatch. Dropping joint bindings." << LL_ENDL; + mJointNames.clear(); + mJointNums.clear(); + mInvBindMatrix.clear(); + } } if (skin.has("bind_shape_matrix")) @@ -1579,7 +1587,7 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp) range = max-min; - U16 count = position.size()/6; + U16 count = (U16)(position.size()/6); for (U32 j = 0; j < count; ++j) { @@ -1842,14 +1850,14 @@ bool validate_face(const LLVolumeFace& face) { if (face.mIndices[i] >= face.mNumVertices) { - LL_WARNS() << "Face has invalid index." << LL_ENDL; + LL_WARNS("MESHSKININFO") << "Face has invalid index." << LL_ENDL; return false; } } if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0) { - LL_WARNS() << "Face has invalid number of indices." << LL_ENDL; + LL_WARNS("MESHSKININFO") << "Face has invalid number of indices." << LL_ENDL; return false; } @@ -1879,7 +1887,7 @@ bool validate_model(const LLModel* mdl) { if (mdl->getNumVolumeFaces() == 0) { - LL_WARNS() << "Model has no faces!" << LL_ENDL; + LL_WARNS("MESHSKININFO") << "Model has no faces!" << LL_ENDL; return false; } @@ -1887,13 +1895,13 @@ bool validate_model(const LLModel* mdl) { if (mdl->getVolumeFace(i).mNumVertices == 0) { - LL_WARNS() << "Face has no vertices." << LL_ENDL; + LL_WARNS("MESHSKININFO") << "Face has no vertices." << LL_ENDL; return false; } if (mdl->getVolumeFace(i).mNumIndices == 0) { - LL_WARNS() << "Face has no indices." << LL_ENDL; + LL_WARNS("MESHSKININFO") << "Face has no indices." << LL_ENDL; return false; } diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp index 4e468ff45f..5171621007 100644 --- a/indra/llprimitive/llmodelloader.cpp +++ b/indra/llprimitive/llmodelloader.cpp @@ -127,7 +127,7 @@ LLModelLoader::LLModelLoader( , mStateCallback(state_cb) , mOpaqueData(opaque_userdata) , mRigValidJointUpload(true) -, mLegacyRigValid(true) +, mLegacyRigFlags(0) , mNoNormalize(false) , mNoOptimize(false) , mCacheOnlyHitIfRigged(false) @@ -136,6 +136,7 @@ LLModelLoader::LLModelLoader( { assert_main_thread(); sActiveLoaderList.push_back(this) ; + mWarningsArray = LLSD::emptyArray(); } LLModelLoader::~LLModelLoader() @@ -146,6 +147,7 @@ LLModelLoader::~LLModelLoader() void LLModelLoader::run() { + mWarningsArray.clear(); doLoadModel(); doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this)); } @@ -387,7 +389,7 @@ void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::st //2. It is suitable for upload as standard av with just skin weights bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset ); - bool isRigLegacyOK = isRigLegacy( jointListFromAsset ); + U32 legacy_rig_flags = determineRigLegacyFlags( jointListFromAsset ); // It's OK that both could end up being true. @@ -401,19 +403,16 @@ void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::st setRigValidForJointPositionUpload( false ); } - if ( !isRigLegacyOK) - { - // This starts out true, becomes false if false for any loaded - // mesh. - setLegacyRigValid( false ); - } + legacy_rig_flags |= getLegacyRigFlags(); + // This starts as 0, changes if any loaded mesh has issues + setLegacyRigFlags(legacy_rig_flags); } //----------------------------------------------------------------------------- -// isRigLegacy() +// determineRigLegacyFlags() //----------------------------------------------------------------------------- -bool LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAsset ) +U32 LLModelLoader::determineRigLegacyFlags( const std::vector<std::string> &jointListFromAsset ) { //No joints in asset if ( jointListFromAsset.size() == 0 ) @@ -426,7 +425,12 @@ bool LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAs { 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; + LLSD args; + args["Message"] = "TooManyJoint"; + args["[JOINTS]"] = LLSD::Integer(jointListFromAsset.size()); + args["[MAX]"] = LLSD::Integer(mMaxJointsPerMesh); + mWarningsArray.append(args); + return LEGACY_RIG_FLAG_TOO_MANY_JOINTS; } // Unknown joints in asset @@ -437,16 +441,24 @@ bool LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAs if (mJointMap.find(*it)==mJointMap.end()) { LL_WARNS() << "Rigged to unrecognized joint name " << *it << LL_ENDL; + LLSD args; + args["Message"] = "UnrecognizedJoint"; + args["[NAME]"] = *it; + mWarningsArray.append(args); unknown_joint_count++; } } if (unknown_joint_count>0) { LL_WARNS() << "Skinning disabled due to unknown joints" << LL_ENDL; - return false; + LLSD args; + args["Message"] = "UnknownJoints"; + args["[COUNT]"] = LLSD::Integer(unknown_joint_count); + mWarningsArray.append(args); + return LEGACY_RIG_FLAG_UNKNOWN_JOINT; } - return true; + return LEGACY_RIG_OK; } //----------------------------------------------------------------------------- // isRigSuitableForJointPositionUpload() diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h index 643c45a6d8..fbc74554a0 100644 --- a/indra/llprimitive/llmodelloader.h +++ b/indra/llprimitive/llmodelloader.h @@ -42,6 +42,10 @@ typedef std::deque<std::string> JointNameSet; const S32 SLM_SUPPORTED_VERSION = 3; const S32 NUM_LOD = 4; +const U32 LEGACY_RIG_OK = 0; +const U32 LEGACY_RIG_FLAG_TOO_MANY_JOINTS = 1; +const U32 LEGACY_RIG_FLAG_UNKNOWN_JOINT = 2; + class LLModelLoader : public LLThread { public: @@ -166,7 +170,7 @@ public: void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset ); //Determines if a rig is a legacy from the joint list - bool isRigLegacy( const std::vector<std::string> &jointListFromAsset ); + U32 determineRigLegacyFlags( const std::vector<std::string> &jointListFromAsset ); //Determines if a rig is suitable for upload bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset ); @@ -174,8 +178,9 @@ public: 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; } + const bool isLegacyRigValid(void) const { return mLegacyRigFlags == 0; } + U32 getLegacyRigFlags() const { return mLegacyRigFlags; } + void setLegacyRigFlags( U32 rigFlags ) { mLegacyRigFlags = rigFlags; } //----------------------------------------------------------------------------- // isNodeAJoint() @@ -185,6 +190,9 @@ public: return name != NULL && mJointMap.find(name) != mJointMap.end(); } + const LLSD logOut() const { return mWarningsArray; } + void clearLog() { mWarningsArray.clear(); } + protected: LLModelLoader::load_callback_t mLoadCallback; @@ -194,13 +202,15 @@ protected: void* mOpaqueData; bool mRigValidJointUpload; - bool mLegacyRigValid; + U32 mLegacyRigFlags; bool mNoNormalize; bool mNoOptimize; JointTransformMap mJointTransformMap; + LLSD mWarningsArray; // preview floater will pull logs from here + static std::list<LLModelLoader*> sActiveLoaderList; static bool isAlive(LLModelLoader* loader) ; }; diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index a0987b35d8..53b83a40d7 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -1013,7 +1013,7 @@ S32 LLPrimitive::packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_fa U64 exception_faces; U8 *start_loc = cur_ptr; - htonmemcpy(cur_ptr,data_ptr + (last_face_index * data_size), type, data_size); + htolememcpy(cur_ptr,data_ptr + (last_face_index * data_size), type, data_size); cur_ptr += data_size; for (face_index = last_face_index-1; face_index >= 0; face_index--) @@ -1072,7 +1072,7 @@ S32 LLPrimitive::packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_fa *cur_ptr++ = (U8)(exception_faces & 0x7F); - htonmemcpy(cur_ptr,data_ptr + (face_index * data_size), type, data_size); + htolememcpy(cur_ptr,data_ptr + (face_index * data_size), type, data_size); cur_ptr += data_size; } } @@ -1083,7 +1083,7 @@ S32 LLPrimitive::unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 dat { U8 *start_loc = cur_ptr; U64 i; - htonmemcpy(data_ptr,cur_ptr, type,data_size); + htolememcpy(data_ptr,cur_ptr, type,data_size); cur_ptr += data_size; for (i = 1; i < face_count; i++) @@ -1108,7 +1108,7 @@ 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); + htolememcpy(data_ptr+(j*data_size),cur_ptr,type,data_size); LL_DEBUGS("TEFieldDecode") << "Assigning " ; char foo[64]; sprintf(foo,"%x %x",*(data_ptr+(j*data_size)), *(data_ptr+(j*data_size)+1)); @@ -1659,7 +1659,7 @@ BOOL LLLightParams::unpack(LLDataPacker &dp) { LLColor4U color; dp.unpackColor4U(color, "color"); - setColor(LLColor4(color)); + setLinearColor(LLColor4(color)); F32 radius; dp.unpackF32(radius, "radius"); @@ -1707,7 +1707,7 @@ LLSD LLLightParams::asLLSD() const { LLSD sd; - sd["color"] = ll_sd_from_color4(getColor()); + sd["color"] = ll_sd_from_color4(getLinearColor()); sd["radius"] = getRadius(); sd["falloff"] = getFalloff(); sd["cutoff"] = getCutoff(); @@ -1721,7 +1721,7 @@ bool LLLightParams::fromLLSD(LLSD& sd) w = "color"; if (sd.has(w)) { - setColor( ll_color4_from_sd(sd["color"]) ); + setLinearColor( ll_color4_from_sd(sd["color"]) ); } else goto fail; w = "radius"; if (sd.has(w)) diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 6fd433c337..b1f8112223 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -131,8 +131,8 @@ extern const F32 LIGHT_MAX_CUTOFF; class LLLightParams : public LLNetworkData { -protected: - LLColor4 mColor; // alpha = intensity +private: + LLColor4 mColor; // linear color (not gamma corrected), alpha = intensity F32 mRadius; F32 mFalloff; F32 mCutoff; @@ -149,13 +149,22 @@ public: operator LLSD() const { return asLLSD(); } bool fromLLSD(LLSD& sd); - - void setColor(const LLColor4& color) { mColor = color; mColor.clamp(); } + // set the color by gamma corrected color value + // color - gamma corrected color value (directly taken from an on-screen color swatch) + void setSRGBColor(const LLColor4& color) { setLinearColor(linearColor4(color)); } + + // set the color by linear color value + // color - linear color value (value as it appears in shaders) + void setLinearColor(const LLColor4& color) { mColor = color; mColor.clamp(); } void setRadius(F32 radius) { mRadius = llclamp(radius, LIGHT_MIN_RADIUS, LIGHT_MAX_RADIUS); } void setFalloff(F32 falloff) { mFalloff = llclamp(falloff, LIGHT_MIN_FALLOFF, LIGHT_MAX_FALLOFF); } void setCutoff(F32 cutoff) { mCutoff = llclamp(cutoff, LIGHT_MIN_CUTOFF, LIGHT_MAX_CUTOFF); } - LLColor4 getColor() const { return mColor; } + // get the linear space color of this light. This value can be fed directly to shaders + LLColor4 getLinearColor() const { return mColor; } + // get the sRGB (gamma corrected) color of this light, this is the value that should be displayed in the UI + LLColor4 getSRGBColor() const { return srgbColor4(mColor); } + F32 getRadius() const { return mRadius; } F32 getFalloff() const { return mFalloff; } F32 getCutoff() const { return mCutoff; } diff --git a/indra/llprimitive/lltextureanim.cpp b/indra/llprimitive/lltextureanim.cpp index 031a315d62..7c48e57a1a 100644 --- a/indra/llprimitive/lltextureanim.cpp +++ b/indra/llprimitive/lltextureanim.cpp @@ -94,9 +94,9 @@ void LLTextureAnim::packTAMessage(LLMessageSystem *mesgsys) const data[1] = mFace; data[2] = mSizeX; data[3] = mSizeY; - htonmemcpy(data + 4, &mStart, MVT_F32, sizeof(F32)); - htonmemcpy(data + 8, &mLength, MVT_F32, sizeof(F32)); - htonmemcpy(data + 12, &mRate, MVT_F32, sizeof(F32)); + htolememcpy(data + 4, &mStart, MVT_F32, sizeof(F32)); + htolememcpy(data + 8, &mLength, MVT_F32, sizeof(F32)); + htolememcpy(data + 12, &mRate, MVT_F32, sizeof(F32)); mesgsys->addBinaryDataFast(_PREHASH_TextureAnim, data, TA_BLOCK_SIZE); } @@ -109,9 +109,9 @@ void LLTextureAnim::packTAMessage(LLDataPacker &dp) const data[1] = mFace; data[2] = mSizeX; data[3] = mSizeY; - htonmemcpy(data + 4, &mStart, MVT_F32, sizeof(F32)); - htonmemcpy(data + 8, &mLength, MVT_F32, sizeof(F32)); - htonmemcpy(data + 12, &mRate, MVT_F32, sizeof(F32)); + htolememcpy(data + 4, &mStart, MVT_F32, sizeof(F32)); + htolememcpy(data + 8, &mLength, MVT_F32, sizeof(F32)); + htolememcpy(data + 12, &mRate, MVT_F32, sizeof(F32)); dp.packBinaryData(data, TA_BLOCK_SIZE, "TextureAnimation"); } @@ -146,9 +146,9 @@ void LLTextureAnim::unpackTAMessage(LLMessageSystem *mesgsys, const S32 block_nu mSizeX = llmax((U8)1, data[2]); mSizeY = llmax((U8)1, data[3]); } - htonmemcpy(&mStart, data + 4, MVT_F32, sizeof(F32)); - htonmemcpy(&mLength, data + 8, MVT_F32, sizeof(F32)); - htonmemcpy(&mRate, data + 12, MVT_F32, sizeof(F32)); + htolememcpy(&mStart, data + 4, MVT_F32, sizeof(F32)); + htolememcpy(&mLength, data + 8, MVT_F32, sizeof(F32)); + htolememcpy(&mRate, data + 12, MVT_F32, sizeof(F32)); } void LLTextureAnim::unpackTAMessage(LLDataPacker &dp) @@ -170,9 +170,9 @@ void LLTextureAnim::unpackTAMessage(LLDataPacker &dp) mFace = data[1]; mSizeX = data[2]; mSizeY = data[3]; - htonmemcpy(&mStart, data + 4, MVT_F32, sizeof(F32)); - htonmemcpy(&mLength, data + 8, MVT_F32, sizeof(F32)); - htonmemcpy(&mRate, data + 12, MVT_F32, sizeof(F32)); + htolememcpy(&mStart, data + 4, MVT_F32, sizeof(F32)); + htolememcpy(&mLength, data + 8, MVT_F32, sizeof(F32)); + htolememcpy(&mRate, data + 12, MVT_F32, sizeof(F32)); } LLSD LLTextureAnim::asLLSD() const diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index 07a0d8c402..47e7ad915b 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -31,6 +31,7 @@ include_directories(SYSTEM ) set(llrender_SOURCE_FILES + llatmosphere.cpp llcubemap.cpp llfontbitmapcache.cpp llfontfreetype.cpp @@ -57,6 +58,7 @@ set(llrender_SOURCE_FILES set(llrender_HEADER_FILES CMakeLists.txt + llatmosphere.h llcubemap.h llfontgl.h llfontfreetype.h @@ -78,6 +80,7 @@ set(llrender_HEADER_FILES llshadermgr.h lltexture.h lluiimage.h + lluiimage.inl llvertexbuffer.h llglcommonfunc.h ) diff --git a/indra/llrender/llatmosphere.cpp b/indra/llrender/llatmosphere.cpp new file mode 100644 index 0000000000..ffc17c89f8 --- /dev/null +++ b/indra/llrender/llatmosphere.cpp @@ -0,0 +1,290 @@ +/** + * @file llatmosphere.cpp + * @brief LLAtmosphere integration impl + * + * $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 "linden_common.h" + +#include "llatmosphere.h" +#include "llfasttimer.h" +#include "llsys.h" +#include "llglheaders.h" +#include "llrender.h" +#include "llshadermgr.h" +#include "llglslshader.h" + +LLAtmosphere* gAtmosphere = nullptr; + +// Values from "Reference Solar Spectral Irradiance: ASTM G-173", ETR column +// (see http://rredc.nrel.gov/solar/spectra/am1.5/ASTMG173/ASTMG173.html), +// summed and averaged in each bin (e.g. the value for 360nm is the average +// of the ASTM G-173 values for all wavelengths between 360 and 370nm). +// Values in W.m^-2. +const int kLambdaMin = 360; +const int kLambdaMax = 830; +const double kSolarIrradiance[48] = { + 1.11776, 1.14259, 1.01249, 1.14716, 1.72765, 1.73054, 1.6887, 1.61253, + 1.91198, 2.03474, 2.02042, 2.02212, 1.93377, 1.95809, 1.91686, 1.8298, + 1.8685, 1.8931, 1.85149, 1.8504, 1.8341, 1.8345, 1.8147, 1.78158, 1.7533, + 1.6965, 1.68194, 1.64654, 1.6048, 1.52143, 1.55622, 1.5113, 1.474, 1.4482, + 1.41018, 1.36775, 1.34188, 1.31429, 1.28303, 1.26758, 1.2367, 1.2082, + 1.18737, 1.14683, 1.12362, 1.1058, 1.07124, 1.04992 +}; + +// Values from http://www.iup.uni-bremen.de/gruppen/molspec/databases/ +// referencespectra/o3spectra2011/index.html for 233K, summed and averaged in +// each bin (e.g. the value for 360nm is the average of the original values +// for all wavelengths between 360 and 370nm). Values in m^2. +const double kOzoneCrossSection[48] = { + 1.18e-27, 2.182e-28, 2.818e-28, 6.636e-28, 1.527e-27, 2.763e-27, 5.52e-27, + 8.451e-27, 1.582e-26, 2.316e-26, 3.669e-26, 4.924e-26, 7.752e-26, 9.016e-26, + 1.48e-25, 1.602e-25, 2.139e-25, 2.755e-25, 3.091e-25, 3.5e-25, 4.266e-25, + 4.672e-25, 4.398e-25, 4.701e-25, 5.019e-25, 4.305e-25, 3.74e-25, 3.215e-25, + 2.662e-25, 2.238e-25, 1.852e-25, 1.473e-25, 1.209e-25, 9.423e-26, 7.455e-26, + 6.566e-26, 5.105e-26, 4.15e-26, 4.228e-26, 3.237e-26, 2.451e-26, 2.801e-26, + 2.534e-26, 1.624e-26, 1.465e-26, 2.078e-26, 1.383e-26, 7.105e-27 +}; + +// From https://en.wikipedia.org/wiki/Dobson_unit, in molecules.m^-2. +const double kDobsonUnit = 2.687e20; +// Maximum number density of ozone molecules, in m^-3 (computed so at to get +// 300 Dobson units of ozone - for this we divide 300 DU by the integral of +// the ozone density profile defined below, which is equal to 15km). +const double kMaxOzoneNumberDensity = 300.0 * kDobsonUnit / 15000.0; +const double kRayleigh = 1.24062e-6; +const double kRayleighScaleHeight = 8000.0; +const double kMieScaleHeight = 1200.0; +const double kMieAngstromAlpha = 0.0; +const double kMieAngstromBeta = 5.328e-3; +const double kMieSingleScatteringAlbedo = 0.9; +const double kGroundAlbedo = 0.1; + +AtmosphericModelSettings::AtmosphericModelSettings() + : m_skyBottomRadius(6360.0f) + , m_skyTopRadius(6420.0f) + , m_sunArcRadians(0.00045f) + , m_mieAnisotropy(0.8f) +{ + DensityLayer rayleigh_density(0.0, 1.0, -1.0 / kRayleighScaleHeight, 0.0, 0.0); + DensityLayer mie_density(0.0, 1.0, -1.0 / kMieScaleHeight, 0.0, 0.0); + + m_rayleighProfile.push_back(rayleigh_density); + m_mieProfile.push_back(mie_density); + + // Density profile increasing linearly from 0 to 1 between 10 and 25km, and + // decreasing linearly from 1 to 0 between 25 and 40km. This is an approximate + // profile from http://www.kln.ac.lk/science/Chemistry/Teaching_Resources/ + // Documents/Introduction%20to%20atmospheric%20chemistry.pdf (page 10). + m_absorptionProfile.push_back(DensityLayer(25000.0, 0.0, 0.0, 1.0 / 15000.0, -2.0 / 3.0)); + m_absorptionProfile.push_back(DensityLayer(0.0, 0.0, 0.0, -1.0 / 15000.0, 8.0 / 3.0)); +} + +AtmosphericModelSettings::AtmosphericModelSettings( + DensityProfile& rayleighProfile, + DensityProfile& mieProfile, + DensityProfile& absorptionProfile) +: m_skyBottomRadius(6360.0f) +, m_skyTopRadius(6420.0f) +, m_rayleighProfile(rayleighProfile) +, m_mieProfile(mieProfile) +, m_absorptionProfile(absorptionProfile) +, m_sunArcRadians(0.00045f) +, m_mieAnisotropy(0.8f) +{ +} + +AtmosphericModelSettings::AtmosphericModelSettings( + F32 skyBottomRadius, + F32 skyTopRadius, + DensityProfile& rayleighProfile, + DensityProfile& mieProfile, + DensityProfile& absorptionProfile, + F32 sunArcRadians, + F32 mieAniso) +: m_skyBottomRadius(skyBottomRadius) +, m_skyTopRadius(skyTopRadius) +, m_rayleighProfile(rayleighProfile) +, m_mieProfile(mieProfile) +, m_absorptionProfile(absorptionProfile) +, m_sunArcRadians(sunArcRadians) +, m_mieAnisotropy(mieAniso) +{ +} + +bool AtmosphericModelSettings::operator==(const AtmosphericModelSettings& rhs) const +{ + if (m_skyBottomRadius != rhs.m_skyBottomRadius) + { + return false; + } + + if (m_skyTopRadius != rhs.m_skyTopRadius) + { + return false; + } + + if (m_sunArcRadians != rhs.m_sunArcRadians) + { + return false; + } + + if (m_mieAnisotropy != rhs.m_mieAnisotropy) + { + return false; + } + + if (m_rayleighProfile != rhs.m_rayleighProfile) + { + return false; + } + + if (m_mieProfile != rhs.m_mieProfile) + { + return false; + } + + if (m_absorptionProfile != rhs.m_absorptionProfile) + { + return false; + } + + return true; +} + +void LLAtmosphere::initClass() +{ + if (!gAtmosphere) + { + gAtmosphere = new LLAtmosphere; + } +} + +void LLAtmosphere::cleanupClass() +{ + if(gAtmosphere) + { + delete gAtmosphere; + } + gAtmosphere = NULL; +} + +LLAtmosphere::LLAtmosphere() +{ + for (int l = kLambdaMin; l <= kLambdaMax; l += 10) + { + double lambda = static_cast<double>(l) * 1e-3; // micro-meters + double mie = kMieAngstromBeta / kMieScaleHeight * pow(lambda, -kMieAngstromAlpha); + m_wavelengths.push_back(l); + m_solar_irradiance.push_back(kSolarIrradiance[(l - kLambdaMin) / 10]); + m_rayleigh_scattering.push_back(kRayleigh * pow(lambda, -4)); + m_mie_scattering.push_back(mie * kMieSingleScatteringAlbedo); + m_mie_extinction.push_back(mie); + m_absorption_extinction.push_back(kMaxOzoneNumberDensity * kOzoneCrossSection[(l - kLambdaMin) / 10]); + m_ground_albedo.push_back(kGroundAlbedo); + } + + AtmosphericModelSettings defaults; + configureAtmosphericModel(defaults); +} + +LLAtmosphere::~LLAtmosphere() +{ + // Cease referencing textures from atmosphere::model from our LLGLTextures wrappers for same. + if (m_transmittance) + { + m_transmittance->setTexName(0); + } + + if (m_scattering) + { + m_scattering->setTexName(0); + } + + if (m_mie_scatter_texture) + { + m_mie_scatter_texture->setTexName(0); + } +} + +bool LLAtmosphere::configureAtmosphericModel(AtmosphericModelSettings& settings) +{ + // TBD + return true; +} + +LLGLTexture* LLAtmosphere::getTransmittance() +{ + if (!m_transmittance) + { + m_transmittance = new LLGLTexture; + m_transmittance->generateGLTexture(); + m_transmittance->setAddressMode(LLTexUnit::eTextureAddressMode::TAM_CLAMP); + m_transmittance->setFilteringOption(LLTexUnit::eTextureFilterOptions::TFO_BILINEAR); + m_transmittance->setExplicitFormat(GL_RGB32F_ARB, GL_RGB, GL_FLOAT); + m_transmittance->setTarget(GL_TEXTURE_2D, LLTexUnit::TT_TEXTURE); + } + return m_transmittance; +} + +LLGLTexture* LLAtmosphere::getScattering() +{ + if (!m_scattering) + { + m_scattering = new LLGLTexture; + m_scattering->generateGLTexture(); + m_scattering->setAddressMode(LLTexUnit::eTextureAddressMode::TAM_CLAMP); + m_scattering->setFilteringOption(LLTexUnit::eTextureFilterOptions::TFO_BILINEAR); + m_scattering->setExplicitFormat(GL_RGB16F_ARB, GL_RGB, GL_FLOAT); + m_scattering->setTarget(GL_TEXTURE_3D, LLTexUnit::TT_TEXTURE_3D); + } + return m_scattering; +} + +LLGLTexture* LLAtmosphere::getMieScattering() +{ + if (!m_mie_scatter_texture) + { + m_mie_scatter_texture = new LLGLTexture; + m_mie_scatter_texture->generateGLTexture(); + m_mie_scatter_texture->setAddressMode(LLTexUnit::eTextureAddressMode::TAM_CLAMP); + m_mie_scatter_texture->setFilteringOption(LLTexUnit::eTextureFilterOptions::TFO_BILINEAR); + m_mie_scatter_texture->setExplicitFormat(GL_RGB16F_ARB, GL_RGB, GL_FLOAT); + m_mie_scatter_texture->setTarget(GL_TEXTURE_3D, LLTexUnit::TT_TEXTURE_3D); + } + return m_mie_scatter_texture; +} + +LLGLTexture* LLAtmosphere::getIlluminance() +{ + if (!m_illuminance) + { + m_illuminance = new LLGLTexture; + m_illuminance->generateGLTexture(); + m_illuminance->setAddressMode(LLTexUnit::eTextureAddressMode::TAM_CLAMP); + m_illuminance->setFilteringOption(LLTexUnit::eTextureFilterOptions::TFO_BILINEAR); + m_illuminance->setExplicitFormat(GL_RGB32F_ARB, GL_RGB, GL_FLOAT); + m_illuminance->setTarget(GL_TEXTURE_2D, LLTexUnit::TT_TEXTURE); + } + return m_illuminance; +} diff --git a/indra/llrender/llatmosphere.h b/indra/llrender/llatmosphere.h new file mode 100644 index 0000000000..572365d864 --- /dev/null +++ b/indra/llrender/llatmosphere.h @@ -0,0 +1,173 @@ +/** + * @file llatmosphere.h + * @brief LLAtmosphere class + * + * $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$ + */ + +#ifndef LL_ATMOSPHERE_H +#define LL_ATMOSPHERE_H + +#include "llglheaders.h" +#include "llgltexture.h" + +// An atmosphere layer of width 'width' (in m), and whose density is defined as +// 'exp_term' * exp('exp_scale' * h) + 'linear_term' * h + 'constant_term', +// clamped to [0,1], and where h is the altitude (in m). 'exp_term' and +// 'constant_term' are unitless, while 'exp_scale' and 'linear_term' are in +// m^-1. +class DensityLayer { + public: + DensityLayer() + : width(0.0f) + , exp_term(0.0f) + , exp_scale(0.0f) + , linear_term(0.0f) + , constant_term(0.0f) + { + } + + DensityLayer(float width, float exp_term, float exp_scale, float linear_term, float constant_term) + : width(width) + , exp_term(exp_term) + , exp_scale(exp_scale) + , linear_term(linear_term) + , constant_term(constant_term) + { + } + + bool operator==(const DensityLayer& rhs) const + { + if (width != rhs.width) + { + return false; + } + + if (exp_term != rhs.exp_term) + { + return false; + } + + if (exp_scale != rhs.exp_scale) + { + return false; + } + + if (linear_term != rhs.linear_term) + { + return false; + } + + if (constant_term != rhs.constant_term) + { + return false; + } + + return true; + } + + float width = 1024.0f; + float exp_term = 1.0f; + float exp_scale = 1.0f; + float linear_term = 1.0f; + float constant_term = 0.0f; +}; + +typedef std::vector<DensityLayer> DensityProfile; + +class AtmosphericModelSettings +{ +public: + AtmosphericModelSettings(); + + AtmosphericModelSettings( + DensityProfile& rayleighProfile, + DensityProfile& mieProfile, + DensityProfile& absorptionProfile); + + AtmosphericModelSettings( + F32 skyBottomRadius, + F32 skyTopRadius, + DensityProfile& rayleighProfile, + DensityProfile& mieProfile, + DensityProfile& absorptionProfile, + F32 sunArcRadians, + F32 mieAniso); + + bool operator==(const AtmosphericModelSettings& rhs) const; + + F32 m_skyBottomRadius; + F32 m_skyTopRadius; + DensityProfile m_rayleighProfile; + DensityProfile m_mieProfile; + DensityProfile m_absorptionProfile; + F32 m_sunArcRadians; + F32 m_mieAnisotropy; +}; + +class LLAtmosphere +{ +public: + LLAtmosphere(); + ~LLAtmosphere(); + + static void initClass(); + static void cleanupClass(); + + const LLAtmosphere& operator=(const LLAtmosphere& rhs) + { + LL_ERRS() << "Illegal operation!" << LL_ENDL; + return *this; + } + + LLGLTexture* getTransmittance(); + LLGLTexture* getScattering(); + LLGLTexture* getMieScattering(); + LLGLTexture* getIlluminance(); + + bool configureAtmosphericModel(AtmosphericModelSettings& settings); + +protected: + LLAtmosphere(const LLAtmosphere& rhs) + { + *this = rhs; + } + + LLPointer<LLGLTexture> m_transmittance; + LLPointer<LLGLTexture> m_scattering; + LLPointer<LLGLTexture> m_mie_scatter_texture; + LLPointer<LLGLTexture> m_illuminance; + + std::vector<double> m_wavelengths; + std::vector<double> m_solar_irradiance; + std::vector<double> m_rayleigh_scattering; + std::vector<double> m_mie_scattering; + std::vector<double> m_mie_extinction; + std::vector<double> m_absorption_extinction; + std::vector<double> m_ground_albedo; + + AtmosphericModelSettings m_settings; +}; + +extern LLAtmosphere* gAtmosphere; + +#endif // LL_ATMOSPHERE_H diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index af4e3fdda0..5947bca670 100644 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp @@ -43,20 +43,13 @@ const F32 epsilon = 1e-7f; const U16 RESOLUTION = 64; -#if LL_DARWIN -// mipmap generation on cubemap textures seems to be broken on the Mac for at least some cards. -// Since the cubemap is small (64x64 per face) and doesn't have any fine detail, turning off mipmaps is a usable workaround. -const BOOL use_cube_mipmaps = FALSE; -#else -const BOOL use_cube_mipmaps = FALSE; //current build works best without cube mipmaps -#endif - bool LLCubeMap::sUseCubeMaps = true; -LLCubeMap::LLCubeMap() +LLCubeMap::LLCubeMap(bool init_as_srgb) : mTextureStage(0), mTextureCoordStage(0), - mMatrixStage(0) + mMatrixStage(0), + mIssRGB(init_as_srgb) { mTargets[0] = GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB; mTargets[1] = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB; @@ -82,12 +75,17 @@ void LLCubeMap::initGL() U32 texname = 0; LLImageGL::generateTextures(1, &texname); - + for (int i = 0; i < 6; i++) { - mImages[i] = new LLImageGL(64, 64, 4, (use_cube_mipmaps? TRUE : FALSE)); + mImages[i] = new LLImageGL(RESOLUTION, RESOLUTION, 4, FALSE); + #if USE_SRGB_DECODE + if (mIssRGB) { + mImages[i]->setExplicitFormat(GL_SRGB8_ALPHA8, GL_RGBA); + } + #endif mImages[i]->setTarget(mTargets[i], LLTexUnit::TT_CUBE_MAP); - mRawImages[i] = new LLImageRaw(64, 64, 4); + mRawImages[i] = new LLImageRaw(RESOLUTION, RESOLUTION, 4); mImages[i]->createGLTexture(0, mRawImages[i], texname); gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_CUBE_MAP, texname); @@ -154,7 +152,7 @@ void LLCubeMap::initGLData() { for (int i = 0; i < 6; i++) { - mImages[i]->setSubImage(mRawImages[i], 0, 0, 64, 64); + mImages[i]->setSubImage(mRawImages[i], 0, 0, RESOLUTION, RESOLUTION); } } @@ -484,7 +482,7 @@ void LLCubeMap::paintIn(LLVector3 dir[4], const LLColor4U& col) td[offset + cc] = U8((td[offset + cc] + col.mV[cc]) * 0.5); } } - mImages[side]->setSubImage(mRawImages[side], 0, 0, 64, 64); + mImages[side]->setSubImage(mRawImages[side], 0, 0, RESOLUTION, RESOLUTION); } } diff --git a/indra/llrender/llcubemap.h b/indra/llrender/llcubemap.h index ee2c41e026..95b6d12099 100644 --- a/indra/llrender/llcubemap.h +++ b/indra/llrender/llcubemap.h @@ -36,8 +36,9 @@ class LLVector3; // Environment map hack! class LLCubeMap : public LLRefCount { + bool mIssRGB; public: - LLCubeMap(); + LLCubeMap(bool init_as_srgb); void init(const std::vector<LLPointer<LLImageRaw> >& rawimages); void initGL(); void initRawData(const std::vector<LLPointer<LLImageRaw> >& rawimages); diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp index ac2b695a3e..f2dc5771e9 100644 --- a/indra/llrender/llfontregistry.cpp +++ b/indra/llrender/llfontregistry.cpp @@ -45,6 +45,7 @@ bool font_desc_init_from_xml(LLXMLNodePtr node, LLFontDescriptor& desc); bool init_from_xml(LLFontRegistry* registry, LLXMLNodePtr node); const std::string MACOSX_FONT_PATH_LIBRARY = "/Library/Fonts/"; +const std::string MACOSX_FONT_SUPPLEMENTAL = "Supplemental/"; LLFontDescriptor::char_functor_map_t LLFontDescriptor::mCharFunctors({ { "is_emoji", LLStringOps::isEmoji } @@ -490,6 +491,8 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) ++font_file_it) { LLFontGL *fontp = NULL; + font_paths.push_back(MACOSX_FONT_PATH_LIBRARY + MACOSX_FONT_SUPPLEMENTAL + *file_name_it); + font_paths.push_back(sys_path + MACOSX_FONT_SUPPLEMENTAL + *file_name_it); bool is_ft_collection = (std::find_if(font_collection_files.begin(), font_collection_files.end(), [&font_file_it](const LLFontFileInfo& ffi) { return font_file_it->FileName == ffi.FileName; }) != font_collection_files.end()); diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index c0f0cec80b..43fedeca64 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -36,6 +36,7 @@ #include "llsys.h" #include "llgl.h" +#include "llglstates.h" #include "llrender.h" #include "llerror.h" @@ -49,6 +50,10 @@ #include "llglheaders.h" #include "llglslshader.h" +#if LL_WINDOWS +#include "lldxhardware.h" +#endif + #ifdef _DEBUG //#define GL_STATE_VERIFY #endif @@ -146,7 +151,7 @@ LLMatrix4 gGLObliqueProjectionInverse; std::list<LLGLUpdate*> LLGLUpdate::sGLQ; -#if (LL_WINDOWS || LL_LINUX || LL_SOLARIS) && !LL_MESA_HEADLESS +#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS // ATI prototypes #if LL_WINDOWS @@ -323,7 +328,7 @@ PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; #endif // vertex shader prototypes -#if LL_LINUX || LL_SOLARIS +#if LL_LINUX PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB = NULL; PFNGLVERTEXATTRIB1DVARBPROC glVertexAttrib1dvARB = NULL; PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB = NULL; @@ -342,7 +347,7 @@ PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB = NULL; PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB = NULL; PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB = NULL; PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB = NULL; -#endif // LL_LINUX || LL_SOLARIS +#endif // LL_LINUX PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB = NULL; PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB = NULL; PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB = NULL; @@ -350,7 +355,7 @@ PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB = NULL; PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB = NULL; PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB = NULL; PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB = NULL; -#if LL_LINUX || LL_SOLARIS +#if LL_LINUX PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB = NULL; PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB = NULL; PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB = NULL; @@ -388,12 +393,14 @@ PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB = NULL; PFNGLGETVERTEXATTRIBIVARBPROC glGetVertexAttribivARB = NULL; PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB = NULL; PFNGLISPROGRAMARBPROC glIsProgramARB = NULL; -#endif // LL_LINUX || LL_SOLARIS +#endif // LL_LINUX PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB = NULL; PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB = NULL; PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB = NULL; #if LL_WINDOWS +PFNWGLGETGPUIDSAMDPROC wglGetGPUIDsAMD = NULL; +PFNWGLGETGPUINFOAMDPROC wglGetGPUInfoAMD = NULL; PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; #endif @@ -413,6 +420,7 @@ LLGLManager::LLGLManager() : mHasMultitexture(FALSE), mHasATIMemInfo(FALSE), + mHasAMDAssociations(FALSE), mHasNVXMemInfo(FALSE), mNumTextureUnits(1), mHasMipMapGeneration(FALSE), @@ -463,8 +471,6 @@ LLGLManager::LLGLManager() : mHasSeparateSpecularColor(FALSE), - mDebugGPU(FALSE), - mDriverVersionMajor(1), mDriverVersionMinor(0), mDriverVersionRelease(0), @@ -497,7 +503,16 @@ void LLGLManager::initWGL() { LL_WARNS("RenderInit") << "No ARB create context extensions" << LL_ENDL; } - + + // For retreiving information per AMD adapter, + // because we can't trust curently selected/default one when there are multiple + mHasAMDAssociations = ExtensionExists("WGL_AMD_gpu_association", gGLHExts.mSysExts); + if (mHasAMDAssociations) + { + GLH_EXT_NAME(wglGetGPUIDsAMD) = (PFNWGLGETGPUIDSAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUIDsAMD"); + GLH_EXT_NAME(wglGetGPUInfoAMD) = (PFNWGLGETGPUINFOAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUInfoAMD"); + } + if (ExtensionExists("WGL_EXT_swap_control", gGLHExts.mSysExts)) { GLH_EXT_NAME(wglSwapIntervalEXT) = (PFNWGLSWAPINTERVALEXTPROC)GLH_EXT_GET_PROC_ADDRESS("wglSwapIntervalEXT"); @@ -568,10 +583,10 @@ bool LLGLManager::initGL() // Extract video card strings and convert to upper case to // work around driver-to-driver variation in capitalization. - mGLVendor = std::string((const char *)glGetString(GL_VENDOR)); + mGLVendor = ll_safe_string((const char *)glGetString(GL_VENDOR)); LLStringUtil::toUpper(mGLVendor); - mGLRenderer = std::string((const char *)glGetString(GL_RENDERER)); + mGLRenderer = ll_safe_string((const char *)glGetString(GL_RENDERER)); LLStringUtil::toUpper(mGLRenderer); parse_gl_version( &mDriverVersionMajor, @@ -683,23 +698,78 @@ bool LLGLManager::initGL() stop_glerror(); S32 old_vram = mVRAM; + mVRAM = 0; - if (mHasATIMemInfo) +#if LL_WINDOWS + if (mHasAMDAssociations) + { + GLuint gl_gpus_count = wglGetGPUIDsAMD(0, 0); + if (gl_gpus_count > 0) + { + GLuint* ids = new GLuint[gl_gpus_count]; + wglGetGPUIDsAMD(gl_gpus_count, ids); + + GLuint mem_mb = 0; + for (U32 i = 0; i < gl_gpus_count; i++) + { + wglGetGPUInfoAMD(ids[i], + WGL_GPU_RAM_AMD, + GL_UNSIGNED_INT, + sizeof(GLuint), + &mem_mb); + if (mVRAM < mem_mb) + { + // basically pick the best AMD and trust driver/OS to know to switch + mVRAM = mem_mb; + } + } + } + if (mVRAM != 0) + { + LL_WARNS("RenderInit") << "VRAM Detected (AMDAssociations):" << mVRAM << LL_ENDL; + } + } +#endif + + if (mHasATIMemInfo && mVRAM == 0) { //ask the gl how much vram is free at startup and attempt to use no more than half of that S32 meminfo[4]; glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo); - mVRAM = meminfo[0]/1024; + mVRAM = meminfo[0] / 1024; + LL_WARNS("RenderInit") << "VRAM Detected (ATIMemInfo):" << mVRAM << LL_ENDL; } - else if (mHasNVXMemInfo) + + if (mHasNVXMemInfo && mVRAM == 0) { S32 dedicated_memory; glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &dedicated_memory); mVRAM = dedicated_memory/1024; + LL_WARNS("RenderInit") << "VRAM Detected (NVXMemInfo):" << mVRAM << LL_ENDL; } +#if LL_WINDOWS if (mVRAM < 256) - { //something likely went wrong using the above extensions, fall back to old method + { + // Something likely went wrong using the above extensions + // try WMI first and fall back to old method (from dxdiag) if all else fails + // Function will check all GPUs WMI knows of and will pick up the one with most + // memory. We need to check all GPUs because system can switch active GPU to + // weaker one, to preserve power when not under load. + S32 mem = LLDXHardware::getMBVideoMemoryViaWMI(); + if (mem != 0) + { + mVRAM = mem; + LL_WARNS("RenderInit") << "VRAM Detected (WMI):" << mVRAM<< LL_ENDL; + } + } +#endif + + if (mVRAM < 256 && old_vram > 0) + { + // fall back to old method + // Note: on Windows value will be from LLDXHardware. + // Either received via dxdiag or via WMI by id from dxdiag. mVRAM = old_vram; } @@ -782,10 +852,6 @@ bool LLGLManager::initGL() stop_glerror(); - setToDebugGPU(); - - stop_glerror(); - initGLStates(); stop_glerror(); @@ -793,17 +859,6 @@ bool LLGLManager::initGL() return true; } -void LLGLManager::setToDebugGPU() -{ - //"MOBILE INTEL(R) 965 EXPRESS CHIP", - if (mGLRenderer.find("INTEL") != std::string::npos && mGLRenderer.find("965") != std::string::npos) - { - mDebugGPU = TRUE ; - } - - return ; -} - void LLGLManager::getGLInfo(LLSD& info) { if (gHeadlessClient) @@ -815,9 +870,9 @@ void LLGLManager::getGLInfo(LLSD& info) } else { - info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR)); - info["GLInfo"]["GLRenderer"] = std::string((const char *)glGetString(GL_RENDERER)); - info["GLInfo"]["GLVersion"] = std::string((const char *)glGetString(GL_VERSION)); + info["GLInfo"]["GLVendor"] = ll_safe_string((const char *)glGetString(GL_VENDOR)); + info["GLInfo"]["GLRenderer"] = ll_safe_string((const char *)glGetString(GL_RENDERER)); + info["GLInfo"]["GLVersion"] = ll_safe_string((const char *)glGetString(GL_VERSION)); } #if !LL_MESA_HEADLESS @@ -867,9 +922,9 @@ void LLGLManager::printGLInfoString() } else { - LL_INFOS("RenderInit") << "GL_VENDOR: " << ((const char *)glGetString(GL_VENDOR)) << LL_ENDL; - LL_INFOS("RenderInit") << "GL_RENDERER: " << ((const char *)glGetString(GL_RENDERER)) << LL_ENDL; - LL_INFOS("RenderInit") << "GL_VERSION: " << ((const char *)glGetString(GL_VERSION)) << LL_ENDL; + LL_INFOS("RenderInit") << "GL_VENDOR: " << ll_safe_string((const char *)glGetString(GL_VENDOR)) << LL_ENDL; + LL_INFOS("RenderInit") << "GL_RENDERER: " << ll_safe_string((const char *)glGetString(GL_RENDERER)) << LL_ENDL; + LL_INFOS("RenderInit") << "GL_VERSION: " << ll_safe_string((const char *)glGetString(GL_VERSION)) << LL_ENDL; } #if !LL_MESA_HEADLESS @@ -893,6 +948,79 @@ std::string LLGLManager::getRawGLString() return gl_string; } +void LLGLManager::asLLSD(LLSD& info) +{ + // Currently these are duplicates of fields in "system". + info["gpu_vendor"] = mGLVendorShort; + info["gpu_version"] = mDriverVersionVendorString; + info["opengl_version"] = mGLVersionString; + + info["vram"] = mVRAM; + + // Extensions used by everyone + info["has_multitexture"] = mHasMultitexture; + info["has_ati_mem_info"] = mHasATIMemInfo; + info["has_nvx_mem_info"] = mHasNVXMemInfo; + info["num_texture_units"] = mNumTextureUnits; + info["has_mip_map_generation"] = mHasMipMapGeneration; + info["has_compressed_textures"] = mHasCompressedTextures; + info["has_framebuffer_object"] = mHasFramebufferObject; + info["max_samples"] = mMaxSamples; + info["has_blend_func_separate"] = mHasBlendFuncSeparate; + + // ARB Extensions + info["has_vertex_buffer_object"] = mHasVertexBufferObject; + info["has_vertex_array_object"] = mHasVertexArrayObject; + info["has_sync"] = mHasSync; + info["has_map_buffer_range"] = mHasMapBufferRange; + info["has_flush_buffer_range"] = mHasFlushBufferRange; + info["has_pbuffer"] = mHasPBuffer; + info["has_shader_objects"] = mHasShaderObjects; + info["has_vertex_shader"] = mHasVertexShader; + info["has_fragment_shader"] = mHasFragmentShader; + info["num_texture_image_units"] = mNumTextureImageUnits; + info["has_occlusion_query"] = mHasOcclusionQuery; + info["has_timer_query"] = mHasTimerQuery; + info["has_occlusion_query2"] = mHasOcclusionQuery2; + info["has_point_parameters"] = mHasPointParameters; + info["has_draw_buffers"] = mHasDrawBuffers; + info["has_depth_clamp"] = mHasDepthClamp; + info["has_texture_rectangle"] = mHasTextureRectangle; + info["has_texture_multisample"] = mHasTextureMultisample; + info["has_transform_feedback"] = mHasTransformFeedback; + info["max_sample_mask_words"] = mMaxSampleMaskWords; + info["max_color_texture_samples"] = mMaxColorTextureSamples; + info["max_depth_texture_samples"] = mMaxDepthTextureSamples; + info["max_integer_samples"] = mMaxIntegerSamples; + + // Other extensions. + info["has_anisotropic"] = mHasAnisotropic; + info["has_arb_env_combine"] = mHasARBEnvCombine; + info["has_cube_map"] = mHasCubeMap; + info["has_debug_output"] = mHasDebugOutput; + info["has_srgb_texture"] = mHassRGBTexture; + info["has_srgb_framebuffer"] = mHassRGBFramebuffer; + info["has_texture_srgb_decode"] = mHasTexturesRGBDecode; + + // Vendor-specific extensions + info["is_ati"] = mIsATI; + info["is_nvidia"] = mIsNVIDIA; + info["is_intel"] = mIsIntel; + info["is_gf2or4mx"] = mIsGF2or4MX; + info["is_gf3"] = mIsGF3; + info["is_gf_gfx"] = mIsGFFX; + info["ati_offset_vertical_lines"] = mATIOffsetVerticalLines; + info["ati_old_driver"] = mATIOldDriver; + + // Other fields + info["has_requirements"] = mHasRequirements; + info["has_separate_specular_color"] = mHasSeparateSpecularColor; + info["max_vertex_range"] = mGLMaxVertexRange; + info["max_index_range"] = mGLMaxIndexRange; + info["max_texture_size"] = mGLMaxTextureSize; + info["gl_renderer"] = mGLRenderer; +} + void LLGLManager::shutdownGL() { if (mInited) @@ -961,7 +1089,7 @@ void LLGLManager::initExtensions() 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); + mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts); //Basic AMD method, also see mHasAMDAssociations 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"); @@ -998,6 +1126,12 @@ void LLGLManager::initExtensions() mHassRGBFramebuffer = ExtensionExists("GL_EXT_framebuffer_sRGB", gGLHExts.mSysExts); #endif +#ifdef GL_EXT_texture_sRGB_decode + mHasTexturesRGBDecode = ExtensionExists("GL_EXT_texture_sRGB_decode", gGLHExts.mSysExts); +#else + mHasTexturesRGBDecode = ExtensionExists("GL_ARB_texture_sRGB_decode", gGLHExts.mSysExts); +#endif + mHasMipMapGeneration = mHasFramebufferObject || mGLVersion >= 1.4f; mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts); @@ -1015,7 +1149,7 @@ void LLGLManager::initExtensions() mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts)); #endif -#if LL_LINUX || LL_SOLARIS +#if LL_LINUX 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. @@ -1085,7 +1219,7 @@ void LLGLManager::initExtensions() if (strchr(blacklist,'u')) mHasDepthClamp = FALSE; } -#endif // LL_LINUX || LL_SOLARIS +#endif // LL_LINUX if (!mHasMultitexture) { @@ -1163,7 +1297,7 @@ void LLGLManager::initExtensions() glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*) &mGLMaxIndexRange); glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*) &mGLMaxTextureSize); -#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 (mHasVertexBufferObject) { @@ -1262,7 +1396,7 @@ void LLGLManager::initExtensions() glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageCallbackARB"); glGetDebugMessageLogARB = (PFNGLGETDEBUGMESSAGELOGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetDebugMessageLogARB"); } -#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) @@ -2044,7 +2178,8 @@ LLGLState::LLGLState(LLGLenum state, S32 enabled) : if (mState) { mWasEnabled = sStateMap[state]; - llassert(mWasEnabled == glIsEnabled(state)); + // we can't actually assert on this as queued changes to state are not reflected by glIsEnabled + //llassert(mWasEnabled == glIsEnabled(state)); setEnabled(enabled); stop_glerror(); } @@ -2267,6 +2402,17 @@ LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& mode } } +void LLGLUserClipPlane::disable() +{ + if (mApply) + { + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + } + mApply = false; +} + void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d) { glh::matrix4f& P = mProjection; @@ -2295,12 +2441,7 @@ void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d) LLGLUserClipPlane::~LLGLUserClipPlane() { - if (mApply) - { - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - } + disable(); } LLGLNamePool::LLGLNamePool() @@ -2376,9 +2517,8 @@ void LLGLNamePool::release(GLuint name) //static void LLGLNamePool::upkeepPools() { - for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter) + for (auto& pool : instance_snapshot()) { - LLGLNamePool & pool = *iter; pool.upkeep(); } } @@ -2386,9 +2526,8 @@ void LLGLNamePool::upkeepPools() //static void LLGLNamePool::cleanupPools() { - for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter) + for (auto& pool : instance_snapshot()) { - LLGLNamePool & pool = *iter; pool.cleanup(); } } @@ -2478,27 +2617,45 @@ void LLGLDepthTest::checkState() } } -LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f P, U32 layer) +LLGLSquashToFarClip::LLGLSquashToFarClip() +{ + glh::matrix4f proj = get_current_projection(); + setProjectionMatrix(proj, 0); +} + +LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f& P, U32 layer) +{ + setProjectionMatrix(P, layer); +} + + +void LLGLSquashToFarClip::setProjectionMatrix(glh::matrix4f& projection, U32 layer) { F32 depth = 0.99999f - 0.0001f * layer; for (U32 i = 0; i < 4; i++) { - P.element(2, i) = P.element(3, i) * depth; + projection.element(2, i) = projection.element(3, i) * depth; } + LLRender::eMatrixMode last_matrix_mode = gGL.getMatrixMode(); + gGL.matrixMode(LLRender::MM_PROJECTION); gGL.pushMatrix(); - gGL.loadMatrix(P.m); - gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.loadMatrix(projection.m); + + gGL.matrixMode(last_matrix_mode); } LLGLSquashToFarClip::~LLGLSquashToFarClip() { + LLRender::eMatrixMode last_matrix_mode = gGL.getMatrixMode(); + gGL.matrixMode(LLRender::MM_PROJECTION); gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); + + gGL.matrixMode(last_matrix_mode); } @@ -2561,11 +2718,50 @@ void LLGLSyncFence::wait() #endif } +LLGLSPipelineSkyBox::LLGLSPipelineSkyBox() +: mAlphaTest(GL_ALPHA_TEST) +, mCullFace(GL_CULL_FACE) +, mSquashClip() +{ + if (!LLGLSLShader::sNoFixedFunction) + { + glDisable(GL_LIGHTING); + glDisable(GL_FOG); + glDisable(GL_CLIP_PLANE0); + } +} + +LLGLSPipelineSkyBox::~LLGLSPipelineSkyBox() +{ + if (!LLGLSLShader::sNoFixedFunction) + { + glEnable(GL_LIGHTING); + glEnable(GL_FOG); + glEnable(GL_CLIP_PLANE0); + } +} + +LLGLSPipelineDepthTestSkyBox::LLGLSPipelineDepthTestSkyBox(bool depth_test, bool depth_write) +: LLGLSPipelineSkyBox() +, mDepth(depth_test ? GL_TRUE : GL_FALSE, depth_write ? GL_TRUE : GL_FALSE, GL_LEQUAL) +{ + +} + +LLGLSPipelineBlendSkyBox::LLGLSPipelineBlendSkyBox(bool depth_test, bool depth_write) +: LLGLSPipelineDepthTestSkyBox(depth_test, depth_write) +, mBlend(GL_BLEND) +{ + gGL.setSceneBlendType(LLRender::BT_ALPHA); +} + #if LL_WINDOWS -// Expose desired use of high-performance graphics processor to Optimus driver +// Expose desired use of high-performance graphics processor to Optimus driver and to AMD driver +// https://docs.nvidia.com/gameworks/content/technologies/desktop/optimus.htm extern "C" { - _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; + __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; + __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; } #endif diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 4c4302d05b..a07e2d9bb0 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -78,6 +78,7 @@ public: // Extensions used by everyone BOOL mHasMultitexture; BOOL mHasATIMemInfo; + BOOL mHasAMDAssociations; BOOL mHasNVXMemInfo; S32 mNumTextureUnits; BOOL mHasMipMapGeneration; @@ -118,6 +119,7 @@ public: BOOL mHasDebugOutput; BOOL mHassRGBTexture; BOOL mHassRGBFramebuffer; + BOOL mHasTexturesRGBDecode; // Vendor-specific extensions BOOL mIsATI; @@ -140,9 +142,6 @@ public: // Misc extensions BOOL mHasSeparateSpecularColor; - //whether this GPU is in the debug list. - BOOL mDebugGPU; - S32 mDriverVersionMajor; S32 mDriverVersionMinor; S32 mDriverVersionRelease; @@ -163,6 +162,8 @@ public: void printGLInfoString(); void getGLInfo(LLSD& info); + void asLLSD(LLSD& info); + // In ALL CAPS std::string mGLVendor; std::string mGLVendorShort; @@ -174,7 +175,6 @@ private: void initExtensions(); void initGLStates(); void initGLImages(); - void setToDebugGPU(); }; extern LLGLManager gGLManager; @@ -348,6 +348,7 @@ public: ~LLGLUserClipPlane(); void setPlane(F32 a, F32 b, F32 c, F32 d); + void disable(); private: bool mApply; @@ -360,14 +361,17 @@ private: Modify and load projection matrix to push depth values to far clip plane. Restores projection matrix on destruction. - GL_MODELVIEW_MATRIX is active whenever program execution - leaves this class. + Saves/restores matrix mode around projection manipulation. Does not stack. */ class LLGLSquashToFarClip { public: - LLGLSquashToFarClip(glh::matrix4f projection, U32 layer = 0); + LLGLSquashToFarClip(); + LLGLSquashToFarClip(glh::matrix4f& projection, U32 layer = 0); + + void setProjectionMatrix(glh::matrix4f& projection, U32 layer); + ~LLGLSquashToFarClip(); }; diff --git a/indra/llrender/llglcommonfunc.h b/indra/llrender/llglcommonfunc.h index f1f8ff7bc4..e6d3755755 100644 --- a/indra/llrender/llglcommonfunc.h +++ b/indra/llrender/llglcommonfunc.h @@ -1,5 +1,5 @@ /** -* @file llphoenixfunc.h +* @file llglcommonfunc.h * @brief File include common opengl code snippets * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index 722dd9050b..6bca3623e0 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -27,242 +27,7 @@ #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 __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_timer_query -extern PFNGLQUERYCOUNTERPROC glQueryCounter; -extern PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v; -extern PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v; - -// 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 PFNGLUNIFORMMATRIX3X4FVPROC glUniformMatrix3x4fv; -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 @@ -618,6 +383,8 @@ extern PFNGLVARIANTARRAYOBJECTATIPROC glVariantObjectArrayATI; extern PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI; extern PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI; +extern PFNWGLGETGPUIDSAMDPROC wglGetGPUIDsAMD; +extern PFNWGLGETGPUINFOAMDPROC wglGetGPUInfoAMD; extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; // GL_ARB_occlusion_query diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 141ed51260..4351f6e2c8 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -37,11 +37,9 @@ #include "OpenGL/OpenGL.h" #endif -#ifdef LL_RELEASE_FOR_DOWNLOAD -#define UNIFORM_ERRS LL_WARNS_ONCE("Shader") -#else -#define UNIFORM_ERRS LL_ERRS("Shader") -#endif +// Print-print list of shader included source files that are linked together via glAttachObjectARB() +// i.e. On macOS / OSX the AMD GLSL linker will display an error if a varying is left in an undefined state. +#define DEBUG_SHADER_INCLUDES 0 // Lots of STL stuff in here, using namespace std to keep things more readable using std::vector; @@ -84,6 +82,12 @@ LLShaderFeatures::LLShaderFeatures() , hasObjectSkinning(false) , hasAtmospherics(false) , hasGamma(false) + , hasSrgb(false) + , encodesNormal(false) + , isDeferred(false) + , hasIndirect(false) + , hasShadows(false) + , hasAmbientOcclusion(false) , mIndexedTextureChannels(0) , disableTextureIndex(false) , hasAlphaMask(false) @@ -344,13 +348,13 @@ void LLGLSLShader::unloadInternal() { GLhandleARB obj[1024]; GLsizei count; + glGetAttachedObjectsARB(mProgramObject, 1024, &count, obj); - glGetAttachedObjectsARB(mProgramObject, sizeof(obj)/sizeof(obj[0]), &count, obj); for (GLsizei i = 0; i < count; i++) { glDetachObjectARB(mProgramObject, obj[i]); - glDeleteObjectARB(obj[i]); - } + glDeleteObjectARB(obj[i]); + } glDeleteObjectARB(mProgramObject); @@ -392,16 +396,28 @@ BOOL LLGLSLShader::createShader(std::vector<LLStaticHashedString> * attributes, mLightHash = 0xFFFFFFFF; llassert_always(!mShaderFiles.empty()); - BOOL success = TRUE; // Create program mProgramObject = glCreateProgramObjectARB(); + if (mProgramObject == 0) + { + // Shouldn't happen if shader related extensions, like ARB_vertex_shader, exist. + LL_SHADER_LOADING_WARNS() << "Failed to create handle for shader: " << mName << LL_ENDL; + unloadInternal(); + return FALSE; + } + + BOOL success = TRUE; #if LL_DARWIN // work-around missing mix(vec3,vec3,bvec3) mDefines["OLD_SELECT"] = "1"; #endif +#if DEBUG_SHADER_INCLUDES + fprintf(stderr, "--- %s ---\n", mName.c_str()); +#endif // DEBUG_SHADER_INCLUDES + //compile new source vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin(); for ( ; fileIter != mShaderFiles.end(); fileIter++ ) @@ -448,12 +464,12 @@ BOOL LLGLSLShader::createShader(std::vector<LLStaticHashedString> * attributes, } if( !success ) { - LL_WARNS("ShaderLoading") << "Failed to link shader: " << mName << LL_ENDL; + LL_SHADER_LOADING_WARNS() << "Failed to link shader: " << mName << LL_ENDL; // Try again using a lower shader level; if (mShaderLevel > 0) { - LL_WARNS("ShaderLoading") << "Failed to link using shader level " << mShaderLevel << " trying again using shader level " << (mShaderLevel - 1) << LL_ENDL; + LL_SHADER_LOADING_WARNS() << "Failed to link using shader level " << mShaderLevel << " trying again using shader level " << (mShaderLevel - 1) << LL_ENDL; mShaderLevel--; return createShader(attributes,uniforms); } @@ -485,18 +501,61 @@ BOOL LLGLSLShader::createShader(std::vector<LLStaticHashedString> * attributes, return success; } -BOOL LLGLSLShader::attachObject(std::string object) +#if DEBUG_SHADER_INCLUDES +void dumpAttachObject( const char *func_name, GLhandleARB program_object, const std::string &object_path ) +{ + GLcharARB* info_log; + GLint info_len_expect = 0; + GLint info_len_actual = 0; + + glGetObjectParameterivARB(program_object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_len_expect); + fprintf(stderr, " * %-20s(), log size: %d, %s\n", func_name, info_len_expect, object_path.c_str()); + + if (info_len_expect > 0) + { + fprintf(stderr, " ========== %s() ========== \n", func_name); + info_log = new GLcharARB [ info_len_expect ]; + glGetInfoLogARB(program_object, info_len_expect, &info_len_actual, info_log); + fprintf(stderr, "%s\n", info_log); + delete [] info_log; + } +} +#endif // DEBUG_SHADER_INCLUDES + +BOOL LLGLSLShader::attachVertexObject(std::string object_path) +{ + if (LLShaderMgr::instance()->mVertexShaderObjects.count(object_path) > 0) + { + stop_glerror(); + glAttachObjectARB(mProgramObject, LLShaderMgr::instance()->mVertexShaderObjects[object_path]); +#if DEBUG_SHADER_INCLUDES + dumpAttachObject("attachVertexObject", mProgramObject, object_path); +#endif // DEBUG_SHADER_INCLUDES + stop_glerror(); + return TRUE; + } + else + { + LL_SHADER_LOADING_WARNS() << "Attempting to attach shader object: '" << object_path << "' that hasn't been compiled." << LL_ENDL; + return FALSE; + } +} + +BOOL LLGLSLShader::attachFragmentObject(std::string object_path) { - if (LLShaderMgr::instance()->mShaderObjects.count(object) > 0) + if (LLShaderMgr::instance()->mFragmentShaderObjects.count(object_path) > 0) { stop_glerror(); - glAttachObjectARB(mProgramObject, LLShaderMgr::instance()->mShaderObjects[object]); + glAttachObjectARB(mProgramObject, LLShaderMgr::instance()->mFragmentShaderObjects[object_path]); +#if DEBUG_SHADER_INCLUDES + dumpAttachObject("attachFragmentObject", mProgramObject, object_path); +#endif // DEBUG_SHADER_INCLUDES stop_glerror(); return TRUE; } else { - LL_WARNS("ShaderLoading") << "Attempting to attach shader object that hasn't been compiled: " << object << LL_ENDL; + LL_SHADER_LOADING_WARNS() << "Attempting to attach shader object: '" << object_path << "' that hasn't been compiled." << LL_ENDL; return FALSE; } } @@ -507,11 +566,15 @@ void LLGLSLShader::attachObject(GLhandleARB object) { stop_glerror(); glAttachObjectARB(mProgramObject, object); +#if DEBUG_SHADER_INCLUDES + std::string object_path("???"); + dumpAttachObject("attachObject", mProgramObject, object_path); +#endif // DEBUG_SHADER_INCLUDES stop_glerror(); } else { - LL_WARNS("ShaderLoading") << "Attempting to attach non existing shader object. " << LL_ENDL; + LL_SHADER_LOADING_WARNS() << "Attempting to attach non existing shader object. " << LL_ENDL; } } @@ -690,6 +753,11 @@ void LLGLSLShader::mapUniform(GLint index, const vector<LLStaticHashedString> * } } +void LLGLSLShader::clearPermutations() +{ + mDefines.clear(); +} + void LLGLSLShader::addPermutation(std::string name, std::string value) { mDefines[name] = value; @@ -759,18 +827,19 @@ BOOL LLGLSLShader::mapUniforms(const vector<LLStaticHashedString> * uniforms) S32 diffuseMap = glGetUniformLocationARB(mProgramObject, "diffuseMap"); S32 specularMap = glGetUniformLocationARB(mProgramObject, "specularMap"); S32 bumpMap = glGetUniformLocationARB(mProgramObject, "bumpMap"); + S32 altDiffuseMap = glGetUniformLocationARB(mProgramObject, "altDiffuseMap"); S32 environmentMap = glGetUniformLocationARB(mProgramObject, "environmentMap"); std::set<S32> skip_index; - if (-1 != diffuseMap && (-1 != specularMap || -1 != bumpMap || -1 != environmentMap)) + if (-1 != diffuseMap && (-1 != specularMap || -1 != bumpMap || -1 != environmentMap || -1 != altDiffuseMap)) { GLenum type; GLsizei length; GLint size = -1; char name[1024]; - diffuseMap = specularMap = bumpMap = environmentMap = -1; + diffuseMap = altDiffuseMap = specularMap = bumpMap = environmentMap = -1; for (S32 i = 0; i < activeCount; i++) { @@ -790,12 +859,6 @@ BOOL LLGLSLShader::mapUniforms(const vector<LLStaticHashedString> * uniforms) continue; } - if (-1 == specularMap && std::string(name) == "specularMap") - { - specularMap = i; - continue; - } - if (-1 == bumpMap && std::string(name) == "bumpMap") { bumpMap = i; @@ -807,6 +870,12 @@ BOOL LLGLSLShader::mapUniforms(const vector<LLStaticHashedString> * uniforms) environmentMap = i; continue; } + + if (-1 == altDiffuseMap && std::string(name) == "altDiffuseMap") + { + altDiffuseMap = i; + continue; + } } bool specularDiff = specularMap < diffuseMap && -1 != specularMap; @@ -858,7 +927,7 @@ BOOL LLGLSLShader::link(BOOL suppress_errors) { BOOL success = LLShaderMgr::instance()->linkProgramObject(mProgramObject, suppress_errors); - if (!suppress_errors) + if (!success && !suppress_errors) { LLShaderMgr::instance()->dumpObjectLog(mProgramObject, !success, mName); } @@ -916,19 +985,19 @@ void LLGLSLShader::bindNoShader(void) } } -S32 LLGLSLShader::bindTexture(const std::string &uniform, LLTexture *texture, LLTexUnit::eTextureType mode) +S32 LLGLSLShader::bindTexture(const std::string &uniform, LLTexture *texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace) { S32 channel = 0; channel = getUniformLocation(uniform); - return bindTexture(channel, texture, mode); + return bindTexture(channel, texture, mode, colorspace); } -S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextureType mode) +S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace) { if (uniform < 0 || uniform >= (S32)mTexture.size()) { - UNIFORM_ERRS << "Uniform out of range: " << uniform << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL; return -1; } @@ -937,6 +1006,7 @@ S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextu if (uniform > -1) { gGL.getTexUnit(uniform)->bind(texture, mode); + gGL.getTexUnit(uniform)->setTextureColorSpace(colorspace); } return uniform; @@ -954,7 +1024,7 @@ S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode) { if (uniform < 0 || uniform >= (S32)mTexture.size()) { - UNIFORM_ERRS << "Uniform out of range: " << uniform << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL; return -1; } @@ -968,11 +1038,11 @@ S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode) return uniform; } -S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode) +S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space) { if (uniform < 0 || uniform >= (S32)mTexture.size()) { - UNIFORM_ERRS << "Uniform out of range: " << uniform << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL; return -1; } S32 index = mTexture[uniform]; @@ -980,21 +1050,22 @@ S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode) { gGL.getTexUnit(index)->activate(); gGL.getTexUnit(index)->enable(mode); + gGL.getTexUnit(index)->setTextureColorSpace(space); } return index; } -S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode) +S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space) { if (uniform < 0 || uniform >= (S32)mTexture.size()) { - UNIFORM_ERRS << "Uniform out of range: " << uniform << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL; return -1; } S32 index = mTexture[uniform]; if (index != -1 && gGL.getTexUnit(index)->getCurrType() != LLTexUnit::TT_NONE) { - if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode) + if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode && gGL.getTexUnit(index)->getCurrColorSpace() != space) { if (gDebugSession) { @@ -1017,7 +1088,7 @@ void LLGLSLShader::uniform1i(U32 index, GLint x) { if (mUniform.size() <= index) { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; return; } @@ -1039,7 +1110,7 @@ void LLGLSLShader::uniform1f(U32 index, GLfloat x) { if (mUniform.size() <= index) { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; return; } @@ -1061,7 +1132,7 @@ void LLGLSLShader::uniform2f(U32 index, GLfloat x, GLfloat y) { if (mUniform.size() <= index) { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; return; } @@ -1084,7 +1155,7 @@ void LLGLSLShader::uniform3f(U32 index, GLfloat x, GLfloat y, GLfloat z) { if (mUniform.size() <= index) { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; return; } @@ -1107,7 +1178,7 @@ void LLGLSLShader::uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat { if (mUniform.size() <= index) { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; return; } @@ -1130,7 +1201,7 @@ void LLGLSLShader::uniform1iv(U32 index, U32 count, const GLint* v) { if (mUniform.size() <= index) { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; return; } @@ -1153,7 +1224,7 @@ void LLGLSLShader::uniform1fv(U32 index, U32 count, const GLfloat* v) { if (mUniform.size() <= index) { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; return; } @@ -1176,7 +1247,7 @@ void LLGLSLShader::uniform2fv(U32 index, U32 count, const GLfloat* v) { if (mUniform.size() <= index) { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; return; } @@ -1199,7 +1270,7 @@ void LLGLSLShader::uniform3fv(U32 index, U32 count, const GLfloat* v) { if (mUniform.size() <= index) { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; return; } @@ -1222,7 +1293,7 @@ void LLGLSLShader::uniform4fv(U32 index, U32 count, const GLfloat* v) { if (mUniform.size() <= index) { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; return; } @@ -1245,7 +1316,7 @@ void LLGLSLShader::uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, c { if (mUniform.size() <= index) { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; return; } @@ -1262,7 +1333,7 @@ void LLGLSLShader::uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, c { if (mUniform.size() <= index) { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; return; } @@ -1279,7 +1350,7 @@ void LLGLSLShader::uniformMatrix3x4fv(U32 index, U32 count, GLboolean transpose, { if (mUniform.size() <= index) { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; return; } @@ -1296,7 +1367,7 @@ void LLGLSLShader::uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, c { if (mUniform.size() <= index) { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; return; } diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index b56b914013..7cf6d3c941 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -48,6 +48,12 @@ public: bool hasObjectSkinning; bool hasAtmospherics; bool hasGamma; + bool hasShadows; + bool hasAmbientOcclusion; + bool hasSrgb; + bool encodesNormal; + bool isDeferred; + bool hasIndirect; S32 mIndexedTextureChannels; bool disableTextureIndex; bool hasAlphaMask; @@ -96,7 +102,8 @@ public: std::vector<LLStaticHashedString> * uniforms, U32 varying_count = 0, const char** varyings = NULL); - BOOL attachObject(std::string object); + BOOL attachFragmentObject(std::string object); + BOOL attachVertexObject(std::string object); void attachObject(GLhandleARB object); void attachObjects(GLhandleARB* objects = NULL, S32 count = 0); BOOL mapAttributes(const std::vector<LLStaticHashedString> * attributes); @@ -139,6 +146,7 @@ public: GLint getAttribLocation(U32 attrib); GLint mapUniformTextureChannel(GLint location, GLenum type); + void clearPermutations(); void addPermutation(std::string name, std::string value); void removePermutation(std::string name); @@ -146,13 +154,13 @@ public: //if given texture uniform is active in the shader, //the corresponding channel will be active upon return //returns channel texture is enabled in from [0-MAX) - S32 enableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); - S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); + S32 enableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR); + S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR); // 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 bindTexture(const std::string& uniform, LLTexture *texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR); + S32 bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR); S32 unbindTexture(const std::string& uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); S32 unbindTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); diff --git a/indra/llrender/llglstates.h b/indra/llrender/llglstates.h index 0e2c3bcb44..a4924eba14 100644 --- a/indra/llrender/llglstates.h +++ b/indra/llrender/llglstates.h @@ -208,11 +208,27 @@ public: class LLGLSPipelineSkyBox { protected: - LLGLDisable mAlphaTest, mCullFace, mFog; + LLGLDisable mAlphaTest; + LLGLDisable mCullFace; + LLGLSquashToFarClip mSquashClip; public: - LLGLSPipelineSkyBox() - : mAlphaTest(GL_ALPHA_TEST), mCullFace(GL_CULL_FACE), mFog(GL_FOG) - { } + LLGLSPipelineSkyBox(); + ~LLGLSPipelineSkyBox(); +}; + +class LLGLSPipelineDepthTestSkyBox : public LLGLSPipelineSkyBox +{ +public: + LLGLSPipelineDepthTestSkyBox(bool depth_test, bool depth_write); + + LLGLDepthTest mDepth; +}; + +class LLGLSPipelineBlendSkyBox : public LLGLSPipelineDepthTestSkyBox +{ +public: + LLGLSPipelineBlendSkyBox(bool depth_test, bool depth_write); + LLGLEnable mBlend; }; class LLGLSTracker diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp index 3a6eebebba..ad501687ed 100644 --- a/indra/llrender/llgltexture.cpp +++ b/indra/llrender/llgltexture.cpp @@ -288,6 +288,18 @@ void LLGLTexture::setCategory(S32 category) mGLTexturep->setCategory(category) ; } +void LLGLTexture::setTexName(LLGLuint texName) +{ + llassert(mGLTexturep.notNull()); + return mGLTexturep->setTexName(texName); +} + +void LLGLTexture::setTarget(const LLGLenum target, const LLTexUnit::eTextureType bind_target) +{ + llassert(mGLTexturep.notNull()); + return mGLTexturep->setTarget(target, bind_target); +} + LLTexUnit::eTextureAddressMode LLGLTexture::getAddressMode(void) const { llassert(mGLTexturep.notNull()) ; @@ -389,9 +401,11 @@ void LLGLTexture::destroyGLTexture() 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; + U32 fullwidth = llmin(mFullWidth,U32(MAX_IMAGE_SIZE_DEFAULT)); + U32 fullheight = llmin(mFullHeight,U32(MAX_IMAGE_SIZE_DEFAULT)); + mTexelsPerImage = (U32)fullwidth * fullheight; } +static LLUUID sStubUUID; +const LLUUID& LLGLTexture::getID() const { return sStubUUID; } diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h index 70610d9626..071912c2c2 100644 --- a/indra/llrender/llgltexture.h +++ b/indra/llrender/llgltexture.h @@ -1,5 +1,5 @@ /** - * @file llglviewertexture.h + * @file llgltexture.h * @brief Object for managing opengl textures * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ @@ -104,7 +104,7 @@ public: virtual void dump(); // debug info to LL_INFOS() - virtual const LLUUID& getID() const = 0; + virtual const LLUUID& getID() const; void setBoostLevel(S32 level); S32 getBoostLevel() { return mBoostLevel; } @@ -133,6 +133,8 @@ public: BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height); void setGLTextureCreated (bool initialized); void setCategory(S32 category) ; + void setTexName(LLGLuint); // for forcing w/ externally created textures only + void setTarget(const LLGLenum target, const LLTexUnit::eTextureType bind_target); LLTexUnit::eTextureAddressMode getAddressMode(void) const ; S32 getMaxDiscardLevel() const; @@ -179,11 +181,11 @@ protected: protected: S32 mBoostLevel; // enum describing priority level - S32 mFullWidth; - S32 mFullHeight; + U32 mFullWidth; + U32 mFullHeight; BOOL mUseMipMaps; S8 mComponents; - F32 mTexelsPerImage; // Texels per image. + U32 mTexelsPerImage; // Texels per image. mutable S8 mNeedsGLTexture; //GL texture diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 40217b2e80..0151d20128 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -184,34 +184,47 @@ void LLImageGL::cleanupClass() //static S32 LLImageGL::dataFormatBits(S32 dataformat) { - switch (dataformat) - { - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 4; - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 8; - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 8; - case GL_LUMINANCE: return 8; - case GL_ALPHA: return 8; - case GL_COLOR_INDEX: return 8; - case GL_LUMINANCE_ALPHA: 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: - LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL; - return 0; - } + switch (dataformat) + { + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 4; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: return 4; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 8; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: return 8; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 8; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return 8; + case GL_LUMINANCE: return 8; + case GL_ALPHA: return 8; + case GL_COLOR_INDEX: return 8; + case GL_LUMINANCE_ALPHA: return 16; + case GL_RGB: return 24; + case GL_SRGB: return 24; + case GL_RGB8: return 24; + case GL_RGBA: return 32; + case GL_SRGB_ALPHA: return 32; + case GL_BGRA: return 32; // Used for QuickTime media textures on the Mac + default: + LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL; + return 0; + } } //static S32 LLImageGL::dataFormatBytes(S32 dataformat, S32 width, S32 height) { - if (dataformat >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT && - dataformat <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) - { - if (width < 4) width = 4; - if (height < 4) height = 4; - } + switch (dataformat) + { + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + if (width < 4) width = 4; + if (height < 4) height = 4; + break; + default: + break; + } S32 bytes ((width*height*dataFormatBits(dataformat)+7)>>3); S32 aligned = (bytes+3)&~3; return aligned; @@ -223,14 +236,19 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat) switch (dataformat) { case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 3; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: return 3; case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 4; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: return 4; case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 4; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return 4; case GL_LUMINANCE: return 1; case GL_ALPHA: return 1; case GL_COLOR_INDEX: return 1; case GL_LUMINANCE_ALPHA: return 2; case GL_RGB: return 3; + case GL_SRGB: return 3; case GL_RGBA: return 4; + case GL_SRGB_ALPHA: return 4; case GL_BGRA: return 4; // Used for QuickTime media textures on the Mac default: LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL; @@ -355,7 +373,7 @@ BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, B LLImageGL::LLImageGL(BOOL usemipmaps) : LLTrace::MemTrackable<LLImageGL>("LLImageGL"), - mSaveData(0) + mSaveData(0), mExternalTexture(FALSE) { init(usemipmaps); setSize(0, 0, 0); @@ -365,7 +383,7 @@ LLImageGL::LLImageGL(BOOL usemipmaps) LLImageGL::LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps) : LLTrace::MemTrackable<LLImageGL>("LLImageGL"), - mSaveData(0) + mSaveData(0), mExternalTexture(FALSE) { llassert( components <= 4 ); init(usemipmaps); @@ -376,7 +394,7 @@ LLImageGL::LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps) LLImageGL::LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps) : LLTrace::MemTrackable<LLImageGL>("LLImageGL"), - mSaveData(0) + mSaveData(0), mExternalTexture(FALSE) { init(usemipmaps); setSize(0, 0, 0); @@ -386,12 +404,36 @@ LLImageGL::LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps) createGLTexture(0, imageraw); } +LLImageGL::LLImageGL( + LLGLuint texName, + U32 components, + LLGLenum target, + LLGLint formatInternal, + LLGLenum formatPrimary, + LLGLenum formatType, + LLTexUnit::eTextureAddressMode addressMode) + : LLTrace::MemTrackable<LLImageGL>("LLImageGL"), mSaveData(0), mExternalTexture(TRUE) +{ + init(false); + mTexName = texName; + mTarget = target; + mComponents = components; + mAddressMode = addressMode; + mFormatType = formatType; + mFormatInternal = formatInternal; + mFormatPrimary = formatPrimary; +} + + LLImageGL::~LLImageGL() { - LLImageGL::cleanup(); - sImageList.erase(this); - freePickMask(); - sCount--; + if (!mExternalTexture) + { + LLImageGL::cleanup(); + sImageList.erase(this); + freePickMask(); + sCount--; + } } void LLImageGL::init(BOOL usemipmaps) @@ -626,10 +668,20 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { 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) - { - is_compressed = true; - } + + switch (mFormatPrimary) + { + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + is_compressed = true; + break; + default: + break; + } @@ -933,38 +985,56 @@ BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image) return FALSE; } - if( !mHasExplicitFormat ) - { - switch (mComponents) - { - case 1: - // Use luminance alpha (for fonts) - mFormatInternal = GL_LUMINANCE8; - mFormatPrimary = GL_LUMINANCE; - mFormatType = GL_UNSIGNED_BYTE; - break; - case 2: - // Use luminance alpha (for fonts) - mFormatInternal = GL_LUMINANCE8_ALPHA8; - mFormatPrimary = GL_LUMINANCE_ALPHA; - mFormatType = GL_UNSIGNED_BYTE; - break; - case 3: - mFormatInternal = GL_RGB8; - mFormatPrimary = GL_RGB; - mFormatType = GL_UNSIGNED_BYTE; - break; - case 4: - mFormatInternal = GL_RGBA8; - mFormatPrimary = GL_RGBA; - mFormatType = GL_UNSIGNED_BYTE; - break; - default: - LL_ERRS() << "Bad number of components for texture: " << (U32)getComponents() << LL_ENDL; - } - } - - mCurrentDiscardLevel = discard_level; + if (!mHasExplicitFormat) + { + switch (mComponents) + { + case 1: + // Use luminance alpha (for fonts) + mFormatInternal = GL_LUMINANCE8; + mFormatPrimary = GL_LUMINANCE; + mFormatType = GL_UNSIGNED_BYTE; + break; + case 2: + // Use luminance alpha (for fonts) + mFormatInternal = GL_LUMINANCE8_ALPHA8; + mFormatPrimary = GL_LUMINANCE_ALPHA; + mFormatType = GL_UNSIGNED_BYTE; + break; + case 3: +#if USE_SRGB_DECODE + if (gGLManager.mHasTexturesRGBDecode) + { + mFormatInternal = GL_SRGB8; + } + else +#endif + { + mFormatInternal = GL_RGB8; + } + mFormatPrimary = GL_RGB; + mFormatType = GL_UNSIGNED_BYTE; + break; + case 4: +#if USE_SRGB_DECODE + if (gGLManager.mHasTexturesRGBDecode) + { + mFormatInternal = GL_SRGB8_ALPHA8; + } + else +#endif + { + mFormatInternal = GL_RGBA8; + } + mFormatPrimary = GL_RGBA; + mFormatType = GL_UNSIGNED_BYTE; + break; + default: + LL_ERRS() << "Bad number of components for texture: " << (U32) getComponents() << LL_ENDL; + } + } + + mCurrentDiscardLevel = discard_level; mDiscardLevelInAtlas = discard_level; mTexelsInAtlas = raw_image->getWidth() * raw_image->getHeight() ; mLastBindTime = sLastFrameTime; @@ -1203,10 +1273,18 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt case GL_RGB8: intformat = GL_COMPRESSED_RGB; break; + case GL_SRGB: + case GL_SRGB8: + intformat = GL_COMPRESSED_SRGB; + break; case GL_RGBA: case GL_RGBA8: intformat = GL_COMPRESSED_RGBA; break; + case GL_SRGB_ALPHA: + case GL_SRGB8_ALPHA8: + intformat = GL_COMPRESSED_SRGB_ALPHA; + break; case GL_LUMINANCE: case GL_LUMINANCE8: intformat = GL_COMPRESSED_LUMINANCE; @@ -1308,35 +1386,62 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S return FALSE; } + if (mHasExplicitFormat && + ((mFormatPrimary == GL_RGBA && mComponents < 4) || + (mFormatPrimary == GL_RGB && mComponents < 3))) + + { + LL_WARNS() << "Incorrect format: " << std::hex << mFormatPrimary << " components: " << (U32)mComponents << LL_ENDL; + mHasExplicitFormat = FALSE; + } + if( !mHasExplicitFormat ) { - switch (mComponents) - { - case 1: - // Use luminance alpha (for fonts) - mFormatInternal = GL_LUMINANCE8; - mFormatPrimary = GL_LUMINANCE; - mFormatType = GL_UNSIGNED_BYTE; - break; - case 2: - // Use luminance alpha (for fonts) - mFormatInternal = GL_LUMINANCE8_ALPHA8; - mFormatPrimary = GL_LUMINANCE_ALPHA; - mFormatType = GL_UNSIGNED_BYTE; - break; - case 3: - mFormatInternal = GL_RGB8; - mFormatPrimary = GL_RGB; - mFormatType = GL_UNSIGNED_BYTE; - break; - case 4: - mFormatInternal = GL_RGBA8; - mFormatPrimary = GL_RGBA; - mFormatType = GL_UNSIGNED_BYTE; - break; - default: - LL_ERRS() << "Bad number of components for texture: " << (U32)getComponents() << LL_ENDL; - } + switch (mComponents) + { + case 1: + // Use luminance alpha (for fonts) + mFormatInternal = GL_LUMINANCE8; + mFormatPrimary = GL_LUMINANCE; + mFormatType = GL_UNSIGNED_BYTE; + break; + case 2: + // Use luminance alpha (for fonts) + mFormatInternal = GL_LUMINANCE8_ALPHA8; + mFormatPrimary = GL_LUMINANCE_ALPHA; + mFormatType = GL_UNSIGNED_BYTE; + break; + case 3: + #if USE_SRGB_DECODE + if (gGLManager.mHasTexturesRGBDecode) + { + mFormatInternal = GL_SRGB8; + } + else + #endif + { + mFormatInternal = GL_RGB8; + } + mFormatPrimary = GL_RGB; + mFormatType = GL_UNSIGNED_BYTE; + break; + case 4: + #if USE_SRGB_DECODE + if (gGLManager.mHasTexturesRGBDecode) + { + mFormatInternal = GL_SRGB8_ALPHA8; + } + else + #endif + { + mFormatInternal = GL_RGBA8; + } + mFormatPrimary = GL_RGBA; + mFormatType = GL_UNSIGNED_BYTE; + break; + default: + LL_ERRS() << "Bad number of components for texture: " << (U32)getComponents() << LL_ENDL; + } calcAlphaChannelOffsetAndStride() ; } @@ -1764,28 +1869,30 @@ void LLImageGL::calcAlphaChannelOffsetAndStride() } mAlphaStride = -1 ; - switch (mFormatPrimary) - { - case GL_LUMINANCE: - case GL_ALPHA: - mAlphaStride = 1; - break; - case GL_LUMINANCE_ALPHA: - mAlphaStride = 2; - break; - case GL_RGB: - mNeedsAlphaAndPickMask = FALSE ; - mIsMask = FALSE; - return ; //no alpha channel. - case GL_RGBA: - mAlphaStride = 4; - break; - case GL_BGRA_EXT: - mAlphaStride = 4; - break; - default: - break; - } + switch (mFormatPrimary) + { + case GL_LUMINANCE: + case GL_ALPHA: + mAlphaStride = 1; + break; + case GL_LUMINANCE_ALPHA: + mAlphaStride = 2; + break; + case GL_RGB: + case GL_SRGB: + mNeedsAlphaAndPickMask = FALSE; + mIsMask = FALSE; + return; //no alpha channel. + case GL_RGBA: + case GL_SRGB_ALPHA: + mAlphaStride = 4; + break; + case GL_BGRA_EXT: + mAlphaStride = 4; + break; + default: + break; + } mAlphaOffset = -1 ; if (mFormatType == GL_UNSIGNED_BYTE) @@ -1968,12 +2075,13 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) freePickMask(); - if (mFormatType != GL_UNSIGNED_BYTE || - mFormatPrimary != GL_RGBA) - { - //cannot generate a pick mask for this texture - return; - } + if (mFormatType != GL_UNSIGNED_BYTE || + ((mFormatPrimary != GL_RGBA) + && (mFormatPrimary != GL_SRGB_ALPHA))) + { + //cannot generate a pick mask for this texture + return; + } #ifdef SHOW_ASSERT const U32 pickSize = createPickMask(width, height); diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 2be54be062..61ddc8d59b 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -84,7 +84,10 @@ public: LLImageGL(BOOL usemipmaps = TRUE); LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps = TRUE); LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps = TRUE); - + + // For wrapping textures created via GL elsewhere with our API only. Use with caution. + LLImageGL(LLGLuint mTexName, U32 components, LLGLenum target, LLGLint formatInternal, LLGLenum formatPrimary, LLGLenum formatType, LLTexUnit::eTextureAddressMode addressMode); + protected: virtual ~LLImageGL(); @@ -130,6 +133,7 @@ public: S32 getMipBytes(S32 discard_level = -1) const; BOOL getBoundRecently() const; BOOL isJustBound() const; + BOOL getHasExplicitFormat() const { return mHasExplicitFormat; } LLGLenum getPrimaryFormat() const { return mFormatPrimary; } LLGLenum getFormatType() const { return mFormatType; } @@ -194,7 +198,7 @@ private: U16 mPickMaskWidth; U16 mPickMaskHeight; S8 mUseMipMaps; - S8 mHasExplicitFormat; // If false (default), GL format is f(mComponents) + BOOL mHasExplicitFormat; // If false (default), GL format is f(mComponents) S8 mAutoGenMips; BOOL mIsMask; @@ -234,6 +238,8 @@ protected: LLGLenum mFormatType; BOOL mFormatSwapBytes;// if true, use glPixelStorei(GL_UNPACK_SWAP_BYTES, 1) + BOOL mExternalTexture; + // STATICS public: static std::set<LLImageGL*> sImageList; @@ -279,6 +285,8 @@ public: void setCategory(S32 category) {mCategory = category;} S32 getCategory()const {return mCategory;} + void setTexName(GLuint texName) { mTexName = texName; } + //for debug use: show texture size distribution //---------------------------------------- static S32 sCurTexSizeBar ; diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 65d6181920..03b6aac20c 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -50,6 +50,7 @@ U32 LLRender::sUIVerts = 0; U32 LLTexUnit::sWhiteTexture = 0; bool LLRender::sGLCoreProfile = false; bool LLRender::sNsightDebugSupport = false; +LLVector2 LLRender::sUIGLScaleFactor = LLVector2(1.f, 1.f); static const U32 LL_NUM_TEXTURE_LAYERS = 32; static const U32 LL_NUM_LIGHT_UNITS = 8; @@ -59,7 +60,8 @@ static const GLenum sGLTextureType[] = GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_CUBE_MAP_ARB, - GL_TEXTURE_2D_MULTISAMPLE + GL_TEXTURE_2D_MULTISAMPLE, + GL_TEXTURE_3D }; static const GLint sGLAddressMode[] = @@ -104,7 +106,7 @@ LLTexUnit::LLTexUnit(S32 index) 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), + mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0), mTexColorSpace(TCS_LINEAR), mHasMipMaps(false), mIndex(index) { @@ -161,6 +163,8 @@ void LLTexUnit::refreshState(void) setTextureCombiner(mCurrColorOp, mCurrColorSrc1, mCurrColorSrc2, false); setTextureCombiner(mCurrAlphaOp, mCurrAlphaSrc1, mCurrAlphaSrc2, true); } + + setTextureColorSpace(mTexColorSpace); } void LLTexUnit::activate(void) @@ -218,6 +222,8 @@ void LLTexUnit::disable(void) { glDisable(sGLTextureType[mCurrTexType]); } + + setTextureColorSpace(TCS_LINEAR); mCurrTexType = TT_NONE; } @@ -254,7 +260,8 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind) gl_tex->mTexOptionsDirty = false; setTextureAddressMode(gl_tex->mAddressMode); setTextureFilteringOption(gl_tex->mFilterOption); - } + } + setTextureColorSpace(mTexColorSpace); } } else @@ -329,6 +336,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind) setTextureFilteringOption(texture->mFilterOption); stop_glerror(); } + setTextureColorSpace(mTexColorSpace); } stop_glerror(); @@ -354,7 +362,7 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap) { activate(); enable(LLTexUnit::TT_CUBE_MAP); - mCurrTexture = cubeMap->mImages[0]->getTexName(); + mCurrTexture = cubeMap->mImages[0]->getTexName(); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mCurrTexture); mHasMipMaps = cubeMap->mImages[0]->mHasMipMaps; cubeMap->mImages[0]->updateBindStats(cubeMap->mImages[0]->mTextureMemory); @@ -363,7 +371,8 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap) cubeMap->mImages[0]->mTexOptionsDirty = false; setTextureAddressMode(cubeMap->mImages[0]->mAddressMode); setTextureFilteringOption(cubeMap->mImages[0]->mFilterOption); - } + } + setTextureColorSpace(mTexColorSpace); return true; } else @@ -414,7 +423,8 @@ bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips) enable(type); mCurrTexture = texture; glBindTexture(sGLTextureType[type], texture); - mHasMipMaps = hasMips; + mHasMipMaps = hasMips; + setTextureColorSpace(mTexColorSpace); } return true; } @@ -434,6 +444,9 @@ void LLTexUnit::unbind(eTextureType type) if (mCurrTexType == type) { mCurrTexture = 0; + + // Always make sure our texture color space is reset to linear. SRGB sampling should be opt-in in the vast majority of cases. Also prevents color space "popping". + mTexColorSpace = TCS_LINEAR; if (LLGLSLShader::sNoFixedFunction && type == LLTexUnit::TT_TEXTURE) { glBindTexture(sGLTextureType[type], sWhiteTexture); @@ -837,6 +850,34 @@ void LLTexUnit::debugTextureUnit(void) } } +void LLTexUnit::setTextureColorSpace(eTextureColorSpace space) +{ + mTexColorSpace = space; + +#if USE_SRGB_DECODE + if (gGLManager.mHasTexturesRGBDecode) + { + if (space == TCS_SRGB) + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT); + } + else + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); + } + + if (gDebugGL) + { + assert_glerror(); + } + } + else + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); + } +#endif +} + LLLightState::LLLightState(S32 index) : mIndex(index), mEnabled(false), @@ -849,9 +890,12 @@ LLLightState::LLLightState(S32 index) if (mIndex == 0) { mDiffuse.set(1,1,1,1); + mDiffuseB.set(0,0,0,0); mSpecular.set(1,1,1,1); } + mSunIsPrimary = true; + mAmbient.set(0,0,0,1); mPosition.set(0,0,1,0); mSpotDirection.set(0,0,-1); @@ -894,6 +938,24 @@ void LLLightState::setDiffuse(const LLColor4& diffuse) } } +void LLLightState::setDiffuseB(const LLColor4& diffuse) +{ + if (mDiffuseB != diffuse) + { + ++gGL.mLightHash; + mDiffuseB = diffuse; + } +} + +void LLLightState::setSunPrimary(bool v) +{ + if (mSunIsPrimary != v) + { + ++gGL.mLightHash; + mSunIsPrimary = v; + } +} + void LLLightState::setAmbient(const LLColor4& ambient) { if (mAmbient != ambient) @@ -1137,40 +1199,46 @@ void LLRender::refreshState(void) void LLRender::syncLightState() { - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - - if (!shader) - { - return; - } - - if (shader->mLightHash != mLightHash) - { - shader->mLightHash = mLightHash; - - LLVector4 position[8]; - LLVector3 direction[8]; - LLVector3 attenuation[8]; - LLVector3 diffuse[8]; - - for (U32 i = 0; i < 8; i++) - { - 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); - } - - 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); - } + LLGLSLShader *shader = LLGLSLShader::sCurBoundShaderPtr; + + if (!shader) + { + return; + } + + if (shader->mLightHash != mLightHash) + { + shader->mLightHash = mLightHash; + + LLVector4 position[LL_NUM_LIGHT_UNITS]; + LLVector3 direction[LL_NUM_LIGHT_UNITS]; + LLVector4 attenuation[LL_NUM_LIGHT_UNITS]; + LLVector3 diffuse[LL_NUM_LIGHT_UNITS]; + LLVector3 diffuse_b[LL_NUM_LIGHT_UNITS]; + bool sun_primary[LL_NUM_LIGHT_UNITS]; + + for (U32 i = 0; i < LL_NUM_LIGHT_UNITS; i++) + { + LLLightState *light = mLightState[i]; + + position[i] = light->mPosition; + direction[i] = light->mSpotDirection; + attenuation[i].set(light->mLinearAtten, light->mQuadraticAtten, light->mSpecular.mV[2], light->mSpecular.mV[3]); + diffuse[i].set(light->mDiffuse.mV); + diffuse_b[i].set(light->mDiffuseB.mV); + sun_primary[i] = light->mSunIsPrimary; + } + + shader->uniform4fv(LLShaderMgr::LIGHT_POSITION, LL_NUM_LIGHT_UNITS, position[0].mV); + shader->uniform3fv(LLShaderMgr::LIGHT_DIRECTION, LL_NUM_LIGHT_UNITS, direction[0].mV); + shader->uniform4fv(LLShaderMgr::LIGHT_ATTENUATION, LL_NUM_LIGHT_UNITS, attenuation[0].mV); + shader->uniform3fv(LLShaderMgr::LIGHT_DIFFUSE, LL_NUM_LIGHT_UNITS, diffuse[0].mV); + shader->uniform4fv(LLShaderMgr::LIGHT_AMBIENT, 1, mAmbientLightColor.mV); + shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_primary[0] ? 1 : 0); + shader->uniform4fv(LLShaderMgr::AMBIENT, 1, mAmbientLightColor.mV); + shader->uniform4fv(LLShaderMgr::SUNLIGHT_COLOR, 1, diffuse[0].mV); + shader->uniform4fv(LLShaderMgr::MOONLIGHT_COLOR, 1, diffuse_b[0].mV); + } } void LLRender::syncMatrices() @@ -1190,6 +1258,7 @@ void LLRender::syncMatrices() LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; static glh::matrix4f cached_mvp; + static glh::matrix4f cached_inv_mdv; static U32 cached_mvp_mdv_hash = 0xFFFFFFFF; static U32 cached_mvp_proj_hash = 0xFFFFFFFF; @@ -1203,12 +1272,18 @@ void LLRender::syncMatrices() bool mvp_done = false; U32 i = MM_MODELVIEW; - if (mMatHash[i] != shader->mMatHash[i]) + if (mMatHash[MM_MODELVIEW] != shader->mMatHash[MM_MODELVIEW]) { //update modelview, normal, and MVP - glh::matrix4f& mat = mMatrix[i][mMatIdx[i]]; + glh::matrix4f& mat = mMatrix[MM_MODELVIEW][mMatIdx[MM_MODELVIEW]]; - shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mat.m); - shader->mMatHash[i] = mMatHash[i]; + // if MDV has changed, update the cached inverse as well + if (cached_mvp_mdv_hash != mMatHash[MM_MODELVIEW]) + { + cached_inv_mdv = mat.inverse(); + } + + shader->uniformMatrix4fv(name[MM_MODELVIEW], 1, GL_FALSE, mat.m); + shader->mMatHash[MM_MODELVIEW] = mMatHash[MM_MODELVIEW]; //update normal matrix S32 loc = shader->getUniformLocation(LLShaderMgr::NORMAL_MATRIX); @@ -1216,7 +1291,7 @@ void LLRender::syncMatrices() { if (cached_normal_hash != mMatHash[i]) { - cached_normal = mat.inverse().transpose(); + cached_normal = cached_inv_mdv.transpose(); cached_normal_hash = mMatHash[i]; } @@ -1232,6 +1307,11 @@ void LLRender::syncMatrices() shader->uniformMatrix3fv(LLShaderMgr::NORMAL_MATRIX, 1, GL_FALSE, norm_mat); } + if (shader->getUniformLocation(LLShaderMgr::INVERSE_MODELVIEW_MATRIX)) + { + shader->uniformMatrix4fv(LLShaderMgr::INVERSE_MODELVIEW_MATRIX, 1, GL_FALSE, cached_inv_mdv.m); + } + //update MVP matrix mvp_done = true; loc = shader->getUniformLocation(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX); @@ -1251,14 +1331,21 @@ void LLRender::syncMatrices() } } - i = MM_PROJECTION; - if (mMatHash[i] != shader->mMatHash[i]) + if (mMatHash[MM_PROJECTION] != shader->mMatHash[MM_PROJECTION]) { //update projection matrix, normal, and MVP - glh::matrix4f& mat = mMatrix[i][mMatIdx[i]]; + glh::matrix4f& mat = mMatrix[MM_PROJECTION][mMatIdx[MM_PROJECTION]]; + + // it would be nice to have this automatically track the state of the proj matrix + // but certain render paths (deferred lighting) require it to be mismatched *sigh* + //if (shader->getUniformLocation(LLShaderMgr::INVERSE_PROJECTION_MATRIX)) + //{ + // glh::matrix4f inv_proj = mat.inverse(); + // shader->uniformMatrix4fv(LLShaderMgr::INVERSE_PROJECTION_MATRIX, 1, FALSE, inv_proj.m); + //} - shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mat.m); - shader->mMatHash[i] = mMatHash[i]; + shader->uniformMatrix4fv(name[MM_PROJECTION], 1, GL_FALSE, mat.m); + shader->mMatHash[MM_PROJECTION] = mMatHash[MM_PROJECTION]; if (!mvp_done) { @@ -1266,7 +1353,7 @@ void LLRender::syncMatrices() S32 loc = shader->getUniformLocation(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX); if (loc > -1) { - if (cached_mvp_mdv_hash != mMatHash[i] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION]) + if (cached_mvp_mdv_hash != mMatHash[MM_PROJECTION] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION]) { U32 mdv = MM_MODELVIEW; cached_mvp = mat; @@ -1290,7 +1377,7 @@ void LLRender::syncMatrices() } - if (shader->mFeatures.hasLighting || shader->mFeatures.calculatesLighting) + if (shader->mFeatures.hasLighting || shader->mFeatures.calculatesLighting || shader->mFeatures.calculatesAtmospherics) { //also sync light state syncLightState(); } @@ -1307,7 +1394,7 @@ void LLRender::syncMatrices() GL_TEXTURE, }; - for (U32 i = 0; i < 2; ++i) + for (U32 i = 0; i < MM_TEXTURE0; ++i) { if (mMatHash[i] != mCurMatHash[i]) { @@ -1317,11 +1404,11 @@ void LLRender::syncMatrices() } } - for (U32 i = 2; i < NUM_MATRIX_MODES; ++i) + for (U32 i = MM_TEXTURE0; i < NUM_MATRIX_MODES; ++i) { if (mMatHash[i] != mCurMatHash[i]) { - gGL.getTexUnit(i-2)->activate(); + gGL.getTexUnit(i-MM_TEXTURE0)->activate(); glMatrixMode(mode[i]); glLoadMatrixf(mMatrix[i][mMatIdx[i]].m); mCurMatHash[i] = mMatHash[i]; @@ -1453,18 +1540,27 @@ void LLRender::multMatrix(const GLfloat* m) } } -void LLRender::matrixMode(U32 mode) +void LLRender::matrixMode(eMatrixMode mode) { if (mode == MM_TEXTURE) { - mode = MM_TEXTURE0 + gGL.getCurrentTexUnitIndex(); + U32 tex_index = gGL.getCurrentTexUnitIndex(); + // the shaders don't actually reference anything beyond texture_matrix0/1 outside of terrain rendering + llassert(tex_index <= 3); + mode = eMatrixMode(MM_TEXTURE0 + tex_index); + if (mode > MM_TEXTURE3) + { + // getCurrentTexUnitIndex() can go as high as 32 (LL_NUM_TEXTURE_LAYERS) + // Large value will result in a crash at mMatrix + LL_WARNS_ONCE() << "Attempted to assign matrix mode out of bounds: " << mode << LL_ENDL; + mode = MM_TEXTURE0; + } } - llassert(mode < NUM_MATRIX_MODES); mMatrixMode = mode; } -U32 LLRender::getMatrixMode() +LLRender::eMatrixMode LLRender::getMatrixMode() { if (mMatrixMode >= MM_TEXTURE0 && mMatrixMode <= MM_TEXTURE3) { //always return MM_TEXTURE if current matrix mode points at any texture matrix @@ -2331,3 +2427,85 @@ void LLRender::debugTexUnits(void) LL_INFOS("TextureUnit") << "Active TexUnit Enabled : " << active_enabled << LL_ENDL; } + + +glh::matrix4f copy_matrix(F32* src) +{ + glh::matrix4f ret; + ret.set_value(src); + return ret; +} + +glh::matrix4f get_current_modelview() +{ + return copy_matrix(gGLModelView); +} + +glh::matrix4f get_current_projection() +{ + return copy_matrix(gGLProjection); +} + +glh::matrix4f get_last_modelview() +{ + return copy_matrix(gGLLastModelView); +} + +glh::matrix4f get_last_projection() +{ + return copy_matrix(gGLLastProjection); +} + +void copy_matrix(const glh::matrix4f& src, F32* dst) +{ + for (U32 i = 0; i < 16; i++) + { + dst[i] = src.m[i]; + } +} + +void set_current_modelview(const glh::matrix4f& mat) +{ + copy_matrix(mat, gGLModelView); +} + +void set_current_projection(glh::matrix4f& mat) +{ + copy_matrix(mat, gGLProjection); +} + +glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar) +{ + 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; +} + +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); + +} diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 32bb728d8a..af8568f8a3 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -61,10 +61,11 @@ public: 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_RECT_TEXTURE, // Non power of 2 texture + TT_CUBE_MAP, // 6-sided cube map texture TT_MULTISAMPLE_TEXTURE, // see GL_ARB_texture_multisample - TT_NONE // No texture type is currently enabled + TT_TEXTURE_3D, // standard 3D Texture + TT_NONE, // No texture type is currently enabled } eTextureType; typedef enum @@ -130,6 +131,12 @@ public: TBS_ONE_MINUS_CONST_ALPHA } eTextureBlendSrc; + typedef enum + { + TCS_LINEAR = 0, + TCS_SRGB + } eTextureColorSpace; + LLTexUnit(S32 index); // Refreshes renderer state of the texture unit to the cached values @@ -152,7 +159,7 @@ public: // Binds the LLImageGL to this texture unit // (automatically enables the unit for the LLImageGL's texture type) bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false); - bool bind(LLTexture* texture, bool for_rendering = false, bool forceBind = false); + bool bind(LLTexture* texture, bool for_rendering = false, bool forceBind = false); // Binds a cubemap to this texture unit // (automatically enables the texture unit for cubemaps) @@ -197,6 +204,10 @@ public: void setHasMipMaps(bool hasMips) { mHasMipMaps = hasMips; } + void setTextureColorSpace(eTextureColorSpace space); + + eTextureColorSpace getCurrColorSpace() { return mTexColorSpace; } + protected: const S32 mIndex; U32 mCurrTexture; @@ -208,6 +219,7 @@ protected: eTextureBlendOp mCurrAlphaOp; eTextureBlendSrc mCurrAlphaSrc1; eTextureBlendSrc mCurrAlphaSrc2; + eTextureColorSpace mTexColorSpace; S32 mCurrColorScale; S32 mCurrAlphaScale; bool mHasMipMaps; @@ -228,6 +240,7 @@ public: void enable(); void disable(); void setDiffuse(const LLColor4& diffuse); + void setDiffuseB(const LLColor4& diffuse); void setAmbient(const LLColor4& ambient); void setSpecular(const LLColor4& specular); void setPosition(const LLVector4& position); @@ -237,6 +250,7 @@ public: void setSpotExponent(const F32& exponent); void setSpotCutoff(const F32& cutoff); void setSpotDirection(const LLVector3& direction); + void setSunPrimary(bool v); protected: friend class LLRender; @@ -244,6 +258,8 @@ protected: S32 mIndex; bool mEnabled; LLColor4 mDiffuse; + LLColor4 mDiffuseB; + bool mSunIsPrimary; LLColor4 mAmbient; LLColor4 mSpecular; LLVector4 mPosition; @@ -264,10 +280,11 @@ public: enum eTexIndex { - DIFFUSE_MAP = 0, - NORMAL_MAP, - SPECULAR_MAP, - NUM_TEXTURE_CHANNELS, + DIFFUSE_MAP = 0, + ALTERNATE_DIFFUSE_MAP = 1, + NORMAL_MAP = 1, + SPECULAR_MAP = 2, + NUM_TEXTURE_CHANNELS = 3, }; enum eVolumeTexIndex @@ -360,8 +377,8 @@ public: void loadMatrix(const GLfloat* m); void loadIdentity(); void multMatrix(const GLfloat* m); - void matrixMode(U32 mode); - U32 getMatrixMode(); + void matrixMode(eMatrixMode mode); + eMatrixMode getMatrixMode(); const glh::matrix4f& getModelviewMatrix(); const glh::matrix4f& getProjectionMatrix(); @@ -446,11 +463,12 @@ public: static U32 sUIVerts; static bool sGLCoreProfile; static bool sNsightDebugSupport; + static LLVector2 sUIGLScaleFactor; private: friend class LLLightState; - U32 mMatrixMode; + eMatrixMode mMatrixMode; U32 mMatIdx[NUM_MATRIX_MODES]; U32 mMatHash[NUM_MATRIX_MODES]; glh::matrix4f mMatrix[NUM_MATRIX_MODES][LL_MATRIX_STACK_DEPTH]; @@ -495,4 +513,33 @@ extern S32 gGLViewport[4]; extern LLRender gGL; +// 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 }; + +glh::matrix4f copy_matrix(F32* src); +glh::matrix4f get_current_modelview(); +glh::matrix4f get_current_projection(); +glh::matrix4f get_last_modelview(); +glh::matrix4f get_last_projection(); + +void copy_matrix(const glh::matrix4f& src, F32* dst); +void set_current_modelview(const glh::matrix4f& mat); +void 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); + +#if LL_RELEASE_FOR_DOWNLOAD + #define LL_SHADER_LOADING_WARNS(...) LL_WARNS_ONCE("ShaderLoading") + #define LL_SHADER_UNIFORM_ERRS(...) LL_WARNS_ONCE("Shader") +#else + #define LL_SHADER_LOADING_WARNS(...) LL_WARNS() + #define LL_SHADER_UNIFORM_ERRS(...) LL_ERRS("Shader") +#endif + #endif diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp index 4e2ebfd51e..dd34f3e383 100644 --- a/indra/llrender/llrender2dutils.cpp +++ b/indra/llrender/llrender2dutils.cpp @@ -46,8 +46,6 @@ // Globals // const LLColor4 UI_VERTEX_COLOR(1.f, 1.f, 1.f, 1.f); -/*static*/ LLVector2 LLRender2D::sGLScaleFactor(1.f, 1.f); -/*static*/ LLImageProviderInterface* LLRender2D::sImageProvider = NULL; // // Functions @@ -108,10 +106,10 @@ void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, S32 pixe top += LLFontGL::sCurOrigin.mY; gGL.loadUIIdentity(); - gl_rect_2d(llfloor((F32)left * LLRender2D::sGLScaleFactor.mV[VX]) - pixel_offset, - llfloor((F32)top * LLRender2D::sGLScaleFactor.mV[VY]) + pixel_offset, - llfloor((F32)right * LLRender2D::sGLScaleFactor.mV[VX]) + pixel_offset, - llfloor((F32)bottom * LLRender2D::sGLScaleFactor.mV[VY]) - pixel_offset, + gl_rect_2d(llfloor((F32)left * LLRender::sUIGLScaleFactor.mV[VX]) - pixel_offset, + llfloor((F32)top * LLRender::sUIGLScaleFactor.mV[VY]) + pixel_offset, + llfloor((F32)right * LLRender::sUIGLScaleFactor.mV[VX]) + pixel_offset, + llfloor((F32)bottom * LLRender::sUIGLScaleFactor.mV[VY]) - pixel_offset, filled); gGL.popUIMatrix(); } @@ -800,7 +798,7 @@ void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LL } gGL.end(); - LLRender2D::setLineWidth(1.f); + LLRender2D::getInstance()->setLineWidth(1.f); } void gl_arc_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled, F32 start_angle, F32 end_angle) @@ -967,7 +965,7 @@ void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha) } else { //polygon stipple is deprecated, use "Checker" texture - LLPointer<LLUIImage> img = LLRender2D::getUIImage("Checker"); + LLPointer<LLUIImage> img = LLRender2D::getInstance()->getUIImage("Checker"); gGL.getTexUnit(0)->bind(img->getImage()); gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP); gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); @@ -1567,25 +1565,25 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv } -// static -void LLRender2D::initClass(LLImageProviderInterface* image_provider, - const LLVector2* scale_factor) +LLRender2D::LLRender2D(LLImageProviderInterface* image_provider) { - sGLScaleFactor = (scale_factor == NULL) ? LLVector2(1.f, 1.f) : *scale_factor; - sImageProvider = image_provider; + mImageProvider = image_provider; + if(mImageProvider) + { + mImageProvider->addOnRemovalCallback(resetProvider); + } } -// static -void LLRender2D::cleanupClass() +LLRender2D::~LLRender2D() { - if(sImageProvider) + if(mImageProvider) { - sImageProvider->cleanUp(); + mImageProvider->cleanUp(); + mImageProvider->deleteOnRemovalCallback(resetProvider); } } - -//static +// static void LLRender2D::translate(F32 x, F32 y, F32 z) { gGL.translateUI(x,y,z); @@ -1594,14 +1592,14 @@ void LLRender2D::translate(F32 x, F32 y, F32 z) LLFontGL::sCurDepth += z; } -//static +// static void LLRender2D::pushMatrix() { gGL.pushUIMatrix(); LLFontGL::sOriginStack.push_back(std::make_pair(LLFontGL::sCurOrigin, LLFontGL::sCurDepth)); } -//static +// static void LLRender2D::popMatrix() { gGL.popUIMatrix(); @@ -1610,7 +1608,7 @@ void LLRender2D::popMatrix() LLFontGL::sOriginStack.pop_back(); } -//static +// static void LLRender2D::loadIdentity() { gGL.loadUIIdentity(); @@ -1619,25 +1617,18 @@ void LLRender2D::loadIdentity() LLFontGL::sCurDepth = 0.f; } -//static -void LLRender2D::setScaleFactor(const LLVector2 &scale_factor) -{ - sGLScaleFactor = scale_factor; -} - -//static +// static void LLRender2D::setLineWidth(F32 width) { gGL.flush(); - glLineWidth(width * lerp(sGLScaleFactor.mV[VX], sGLScaleFactor.mV[VY], 0.5f)); + glLineWidth(width * lerp(LLRender::sUIGLScaleFactor.mV[VX], LLRender::sUIGLScaleFactor.mV[VY], 0.5f)); } -//static LLPointer<LLUIImage> LLRender2D::getUIImageByID(const LLUUID& image_id, S32 priority) { - if (sImageProvider) + if (mImageProvider) { - return sImageProvider->getUIImageByID(image_id, priority); + return mImageProvider->getUIImageByID(image_id, priority); } else { @@ -1645,12 +1636,49 @@ LLPointer<LLUIImage> LLRender2D::getUIImageByID(const LLUUID& image_id, S32 prio } } -//static LLPointer<LLUIImage> LLRender2D::getUIImage(const std::string& name, S32 priority) { - if (!name.empty() && sImageProvider) - return sImageProvider->getUIImage(name, priority); + if (!name.empty() && mImageProvider) + return mImageProvider->getUIImage(name, priority); else return NULL; } +// static +void LLRender2D::resetProvider() +{ + if (LLRender2D::instanceExists()) + { + LLRender2D::getInstance()->mImageProvider = NULL; + } +} + +// class LLImageProviderInterface + +LLImageProviderInterface::~LLImageProviderInterface() +{ + for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end();) + { + callback_list_t::iterator curiter = iter++; + (*curiter)(); + } +} + +void LLImageProviderInterface::addOnRemovalCallback(callback_t func) +{ + if (!func) + { + return; + } + mCallbackList.push_back(func); +} + +void LLImageProviderInterface::deleteOnRemovalCallback(callback_t func) +{ + callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), func); + if (iter != mCallbackList.end()) + { + mCallbackList.erase(iter); + } +} + diff --git a/indra/llrender/llrender2dutils.h b/indra/llrender/llrender2dutils.h index cce3b4ed51..206e68f084 100644 --- a/indra/llrender/llrender2dutils.h +++ b/indra/llrender/llrender2dutils.h @@ -32,6 +32,7 @@ #include "llpointer.h" // LLPointer<> #include "llrect.h" +#include "llsingleton.h" #include "llglslshader.h" class LLColor4; @@ -121,39 +122,51 @@ inline void gl_rect_2d_offset_local( const LLRect& rect, S32 pixel_offset, BOOL class LLImageProviderInterface; -class LLRender2D +class LLRender2D : public LLParamSingleton<LLRender2D> { + LLSINGLETON(LLRender2D, LLImageProviderInterface* image_provider); LOG_CLASS(LLRender2D); + ~LLRender2D(); public: - static void initClass(LLImageProviderInterface* image_provider, - const LLVector2* scale_factor); - static void cleanupClass(); - static void pushMatrix(); static void popMatrix(); static void loadIdentity(); static void translate(F32 x, F32 y, F32 z = 0.0f); static void setLineWidth(F32 width); - static void setScaleFactor(const LLVector2& scale_factor); - static LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id, S32 priority = 0); - static LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0); + LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id, S32 priority = 0); + LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0); + +protected: + // since LLRender2D has no control of image provider's lifecycle + // we need a way to tell LLRender2D that provider died and + // LLRender2D needs to be updated. + static void resetProvider(); - static LLVector2 sGLScaleFactor; private: - static LLImageProviderInterface* sImageProvider; + LLImageProviderInterface* mImageProvider; }; class LLImageProviderInterface { protected: LLImageProviderInterface() {}; - virtual ~LLImageProviderInterface() {}; + virtual ~LLImageProviderInterface(); public: virtual LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority) = 0; virtual LLPointer<LLUIImage> getUIImageByID(const LLUUID& id, S32 priority) = 0; virtual void cleanUp() = 0; + + // to notify holders when pointer gets deleted + typedef void(*callback_t)(); + void addOnRemovalCallback(callback_t func); + void deleteOnRemovalCallback(callback_t func); + +private: + + typedef std::list< callback_t > callback_list_t; + callback_list_t mCallbackList; }; diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index cd484b4fe9..e3c0255290 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -501,10 +501,27 @@ U32 LLRenderTarget::getNumTextures() const return mTex.size(); } - -void LLRenderTarget::bindTexture(U32 index, S32 channel) +void LLRenderTarget::bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilterOptions filter_options) { - gGL.getTexUnit(channel)->bindManual(mUsage, getTexture(index)); + gGL.getTexUnit(channel)->bindManual(mUsage, getTexture(index)); + + bool isSRGB = false; + llassert(mInternalFormat.size() > index); + switch (mInternalFormat[index]) + { + case GL_SRGB: + case GL_SRGB8: + case GL_SRGB_ALPHA: + case GL_SRGB8_ALPHA8: + isSRGB = true; + break; + + default: + break; + } + + gGL.getTexUnit(channel)->setTextureFilteringOption(filter_options); + gGL.getTexUnit(channel)->setTextureColorSpace(isSRGB ? LLTexUnit::TCS_SRGB : LLTexUnit::TCS_LINEAR); } void LLRenderTarget::flush(bool fetch_depth) diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index 6dc84d978d..6c07ac5b1c 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -120,7 +120,7 @@ public: U32 getDepth(void) const { return mDepth; } bool hasStencil() const { return mStencil; } - void bindTexture(U32 index, S32 channel); + void bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilterOptions filter_options = LLTexUnit::TFO_BILINEAR); //flush rendering operations //must be called when rendering is complete diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 643c368870..e8c6295930 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -25,22 +25,14 @@ */ #include "linden_common.h" - #include "llshadermgr.h" - -#include "llfile.h" #include "llrender.h" +#include "llfile.h" #if LL_DARWIN #include "OpenGL/OpenGL.h" #endif -#ifdef LL_RELEASE_FOR_DOWNLOAD -#define UNIFORM_ERRS LL_WARNS_ONCE("Shader") -#else -#define UNIFORM_ERRS LL_ERRS("Shader") -#endif - // Lots of STL stuff in here, using namespace std to keep things more readable using std::vector; using std::pair; @@ -87,20 +79,20 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { if (features->hasWaterFog) { - if (!shader->attachObject("windlight/atmosphericsVarsWaterV.glsl")) + if (!shader->attachVertexObject("windlight/atmosphericsVarsWaterV.glsl")) { return FALSE; } } - else if (!shader->attachObject("windlight/atmosphericsVarsV.glsl")) + else if (!shader->attachVertexObject("windlight/atmosphericsVarsV.glsl")) { return FALSE; } } - if (features->calculatesLighting || features->atmosphericHelpers) + if (features->calculatesLighting || features->calculatesAtmospherics) { - if (!shader->attachObject("windlight/atmosphericsHelpersV.glsl")) + if (!shader->attachVertexObject("windlight/atmosphericsHelpersV.glsl")) { return FALSE; } @@ -110,40 +102,40 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { if (features->isSpecular) { - if (!shader->attachObject("lighting/lightFuncSpecularV.glsl")) + if (!shader->attachVertexObject("lighting/lightFuncSpecularV.glsl")) { return FALSE; } if (!features->isAlphaLighting) { - if (!shader->attachObject("lighting/sumLightsSpecularV.glsl")) + if (!shader->attachVertexObject("lighting/sumLightsSpecularV.glsl")) { return FALSE; } } - if (!shader->attachObject("lighting/lightSpecularV.glsl")) + if (!shader->attachVertexObject("lighting/lightSpecularV.glsl")) { return FALSE; } } else { - if (!shader->attachObject("lighting/lightFuncV.glsl")) + if (!shader->attachVertexObject("lighting/lightFuncV.glsl")) { return FALSE; } if (!features->isAlphaLighting) { - if (!shader->attachObject("lighting/sumLightsV.glsl")) + if (!shader->attachVertexObject("lighting/sumLightsV.glsl")) { return FALSE; } } - if (!shader->attachObject("lighting/lightV.glsl")) + if (!shader->attachVertexObject("lighting/lightV.glsl")) { return FALSE; } @@ -152,8 +144,12 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) // NOTE order of shader object attaching is VERY IMPORTANT!!! if (features->calculatesAtmospherics) - { - if (!shader->attachObject("windlight/atmosphericsV.glsl")) + { + if (!shader->attachVertexObject("windlight/atmosphericsFuncs.glsl")) { + return FALSE; + } + + if (!shader->attachVertexObject("windlight/atmosphericsV.glsl")) { return FALSE; } @@ -161,7 +157,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) if (features->hasSkinning) { - if (!shader->attachObject("avatar/avatarSkinV.glsl")) + if (!shader->attachVertexObject("avatar/avatarSkinV.glsl")) { return FALSE; } @@ -169,7 +165,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) if (features->hasObjectSkinning) { - if (!shader->attachObject("avatar/objectSkinV.glsl")) + if (!shader->attachVertexObject("avatar/objectSkinV.glsl")) { return FALSE; } @@ -179,33 +175,95 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) // Attach Fragment Shader Features Next /////////////////////////////////////// +// NOTE order of shader object attaching is VERY IMPORTANT!!! + if(features->calculatesAtmospherics) { if (features->hasWaterFog) { - if (!shader->attachObject("windlight/atmosphericsVarsWaterF.glsl")) + if (!shader->attachFragmentObject("windlight/atmosphericsVarsWaterF.glsl")) { return FALSE; } } - else if (!shader->attachObject("windlight/atmosphericsVarsF.glsl")) + else if (!shader->attachFragmentObject("windlight/atmosphericsVarsF.glsl")) + { + return FALSE; + } + } + + if (features->calculatesLighting || features->calculatesAtmospherics) + { + if (!shader->attachFragmentObject("windlight/atmosphericsHelpersF.glsl")) + { + return FALSE; + } + } + + // we want this BEFORE shadows and AO because those facilities use pos/norm access + if (features->isDeferred) + { + if (!shader->attachFragmentObject("deferred/deferredUtil.glsl")) + { + return FALSE; + } + } + + if (features->hasShadows) + { + if (!shader->attachFragmentObject("deferred/shadowUtil.glsl")) + { + return FALSE; + } + } + + if (features->hasAmbientOcclusion) + { + if (!shader->attachFragmentObject("deferred/aoUtil.glsl")) + { + return FALSE; + } + } + + if (features->hasIndirect) + { + if (!shader->attachFragmentObject("deferred/indirect.glsl")) { return FALSE; } } - // NOTE order of shader object attaching is VERY IMPORTANT!!! if (features->hasGamma) { - if (!shader->attachObject("windlight/gammaF.glsl")) + if (!shader->attachFragmentObject("windlight/gammaF.glsl")) { return FALSE; } } - - if (features->hasAtmospherics) + + if (features->hasSrgb) { - if (!shader->attachObject("windlight/atmosphericsF.glsl")) + if (!shader->attachFragmentObject("environment/srgbF.glsl")) + { + return FALSE; + } + } + + if (features->encodesNormal) + { + if (!shader->attachFragmentObject("environment/encodeNormF.glsl")) + { + return FALSE; + } + } + + if (features->hasAtmospherics) + { + if (!shader->attachFragmentObject("windlight/atmosphericsFuncs.glsl")) { + return FALSE; + } + + if (!shader->attachFragmentObject("windlight/atmosphericsF.glsl")) { return FALSE; } @@ -213,7 +271,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) if (features->hasTransport) { - if (!shader->attachObject("windlight/transportF.glsl")) + if (!shader->attachFragmentObject("windlight/transportF.glsl")) { return FALSE; } @@ -225,7 +283,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) // NOTE order of shader object attaching is VERY IMPORTANT!!! if (features->hasWaterFog) { - if (!shader->attachObject("environment/waterFogF.glsl")) + if (!shader->attachFragmentObject("environment/waterFogF.glsl")) { return FALSE; } @@ -239,14 +297,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { if (features->hasAlphaMask) { - if (!shader->attachObject("lighting/lightWaterAlphaMaskNonIndexedF.glsl")) + if (!shader->attachFragmentObject("lighting/lightWaterAlphaMaskNonIndexedF.glsl")) { return FALSE; } } else { - if (!shader->attachObject("lighting/lightWaterNonIndexedF.glsl")) + if (!shader->attachFragmentObject("lighting/lightWaterNonIndexedF.glsl")) { return FALSE; } @@ -256,14 +314,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { if (features->hasAlphaMask) { - if (!shader->attachObject("lighting/lightWaterAlphaMaskF.glsl")) + if (!shader->attachFragmentObject("lighting/lightWaterAlphaMaskF.glsl")) { return FALSE; } } else { - if (!shader->attachObject("lighting/lightWaterF.glsl")) + if (!shader->attachFragmentObject("lighting/lightWaterF.glsl")) { return FALSE; } @@ -278,14 +336,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { if (features->hasAlphaMask) { - if (!shader->attachObject("lighting/lightAlphaMaskNonIndexedF.glsl")) + if (!shader->attachFragmentObject("lighting/lightAlphaMaskNonIndexedF.glsl")) { return FALSE; } } else { - if (!shader->attachObject("lighting/lightNonIndexedF.glsl")) + if (!shader->attachFragmentObject("lighting/lightNonIndexedF.glsl")) { return FALSE; } @@ -295,14 +353,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { if (features->hasAlphaMask) { - if (!shader->attachObject("lighting/lightAlphaMaskF.glsl")) + if (!shader->attachFragmentObject("lighting/lightAlphaMaskF.glsl")) { return FALSE; } } else { - if (!shader->attachObject("lighting/lightF.glsl")) + if (!shader->attachFragmentObject("lighting/lightF.glsl")) { return FALSE; } @@ -320,14 +378,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { if (features->disableTextureIndex) { - if (!shader->attachObject("lighting/lightFullbrightShinyWaterNonIndexedF.glsl")) + if (!shader->attachFragmentObject("lighting/lightFullbrightShinyWaterNonIndexedF.glsl")) { return FALSE; } } else { - if (!shader->attachObject("lighting/lightFullbrightShinyWaterF.glsl")) + if (!shader->attachFragmentObject("lighting/lightFullbrightShinyWaterF.glsl")) { return FALSE; } @@ -340,12 +398,12 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { if (features->hasAlphaMask) { - if (!shader->attachObject("lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl")) + if (!shader->attachFragmentObject("lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl")) { return FALSE; } } - else if (!shader->attachObject("lighting/lightFullbrightWaterNonIndexedF.glsl")) + else if (!shader->attachFragmentObject("lighting/lightFullbrightWaterNonIndexedF.glsl")) { return FALSE; } @@ -354,12 +412,12 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { if (features->hasAlphaMask) { - if (!shader->attachObject("lighting/lightFullbrightWaterAlphaMaskF.glsl")) + if (!shader->attachFragmentObject("lighting/lightFullbrightWaterAlphaMaskF.glsl")) { return FALSE; } } - else if (!shader->attachObject("lighting/lightFullbrightWaterF.glsl")) + else if (!shader->attachFragmentObject("lighting/lightFullbrightWaterF.glsl")) { return FALSE; } @@ -371,14 +429,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { if (features->disableTextureIndex) { - if (!shader->attachObject("lighting/lightFullbrightShinyNonIndexedF.glsl")) + if (!shader->attachFragmentObject("lighting/lightFullbrightShinyNonIndexedF.glsl")) { return FALSE; } } else { - if (!shader->attachObject("lighting/lightFullbrightShinyF.glsl")) + if (!shader->attachFragmentObject("lighting/lightFullbrightShinyF.glsl")) { return FALSE; } @@ -393,14 +451,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) if (features->hasAlphaMask) { - if (!shader->attachObject("lighting/lightFullbrightNonIndexedAlphaMaskF.glsl")) + if (!shader->attachFragmentObject("lighting/lightFullbrightNonIndexedAlphaMaskF.glsl")) { return FALSE; } } else { - if (!shader->attachObject("lighting/lightFullbrightNonIndexedF.glsl")) + if (!shader->attachFragmentObject("lighting/lightFullbrightNonIndexedF.glsl")) { return FALSE; } @@ -410,14 +468,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { if (features->hasAlphaMask) { - if (!shader->attachObject("lighting/lightFullbrightAlphaMaskF.glsl")) + if (!shader->attachFragmentObject("lighting/lightFullbrightAlphaMaskF.glsl")) { return FALSE; } } else { - if (!shader->attachObject("lighting/lightFullbrightF.glsl")) + if (!shader->attachFragmentObject("lighting/lightFullbrightF.glsl")) { return FALSE; } @@ -435,14 +493,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { if (features->disableTextureIndex) { - if (!shader->attachObject("lighting/lightShinyWaterNonIndexedF.glsl")) + if (!shader->attachFragmentObject("lighting/lightShinyWaterNonIndexedF.glsl")) { return FALSE; } } else { - if (!shader->attachObject("lighting/lightShinyWaterF.glsl")) + if (!shader->attachFragmentObject("lighting/lightShinyWaterF.glsl")) { return FALSE; } @@ -454,14 +512,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { if (features->disableTextureIndex) { - if (!shader->attachObject("lighting/lightShinyNonIndexedF.glsl")) + if (!shader->attachFragmentObject("lighting/lightShinyNonIndexedF.glsl")) { return FALSE; } } else { - if (!shader->attachObject("lighting/lightShinyF.glsl")) + if (!shader->attachFragmentObject("lighting/lightShinyF.glsl")) { return FALSE; } @@ -472,14 +530,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) if (features->mIndexedTextureChannels <= 1) { - if (!shader->attachObject("objects/nonindexedTextureV.glsl")) + if (!shader->attachVertexObject("objects/nonindexedTextureV.glsl")) { return FALSE; } } else { - if (!shader->attachObject("objects/indexedTextureV.glsl")) + if (!shader->attachVertexObject("objects/indexedTextureV.glsl")) { return FALSE; } @@ -509,32 +567,55 @@ static std::string get_object_log(GLhandleARB ret) return res; } +//dump shader source for debugging +void LLShaderMgr::dumpShaderSource(U32 shader_code_count, GLcharARB** shader_code_text) +{ + char num_str[16]; // U32 = max 10 digits + + LL_SHADER_LOADING_WARNS() << "\n"; + + for (U32 i = 0; i < shader_code_count; i++) + { + snprintf(num_str, sizeof(num_str), "%4d: ", i+1); + std::string line_number(num_str); + LL_CONT << line_number << shader_code_text[i]; + } + LL_CONT << LL_ENDL; +} + void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns, const std::string& filename) { std::string log = get_object_log(ret); + std::string fname = filename; + if (filename.empty()) + { + fname = "unknown shader file"; + } - if (log.length() > 0 || warns) + if (log.length() > 0) { - LL_DEBUGS("ShaderLoading") << "Shader loading "; - - if (!filename.empty()) - { - LL_CONT << "From " << filename << ":\n"; - } - LL_CONT << log << LL_ENDL; + LL_SHADER_LOADING_WARNS() << "Shader loading from " << fname << LL_ENDL; + LL_SHADER_LOADING_WARNS() << "\n" << log << LL_ENDL; } } GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, boost::unordered_map<std::string, std::string>* defines, S32 texture_index_channels) { + +// endsure work-around for missing GLSL funcs gets propogated to feature shader files (e.g. srgbF.glsl) +#if LL_DARWIN + if (defines) + { + (*defines)["OLD_SELECT"] = "1"; + } +#endif + GLenum error = GL_NO_ERROR; - if (gDebugGL) + + error = glGetError(); + if (error != GL_NO_ERROR) { - error = glGetError(); - if (error != GL_NO_ERROR) - { - LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL; - } + LL_SHADER_LOADING_WARNS() << "GL ERROR entering loadShaderFile(): " << error << " for file: " << filename << LL_ENDL; } if (filename.empty()) @@ -549,6 +630,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade S32 try_gpu_class = shader_level; S32 gpu_class; + std::string open_file_name; //find the most relevant file for (gpu_class = try_gpu_class; gpu_class > 0; gpu_class--) { //search from the current gpu class down to class 1 to find the most relevant shader @@ -556,18 +638,33 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade fname << getShaderDirPrefix(); fname << gpu_class << "/" << filename; - - file = LLFile::fopen(fname.str(), "r"); /* Flawfinder: ignore */ + open_file_name = fname.str(); + + /* + Would be awesome, if we didn't have shaders that re-use files + with different environments to say, add skinning, etc + can't depend on cached version to have evaluate ifdefs identically... + if we can define a deterministic hash for the shader based on + all the inputs, maybe we can save some time here. + if (mShaderObjects.count(filename) > 0) + { + return mShaderObjects[filename]; + } + + */ + + LL_DEBUGS("ShaderLoading") << "Looking in " << open_file_name << LL_ENDL; + file = LLFile::fopen(open_file_name, "r"); /* Flawfinder: ignore */ if (file) { - LL_DEBUGS("ShaderLoading") << "Loading file: shaders/class" << gpu_class << "/" << filename << " (Want class " << gpu_class << ")" << LL_ENDL; + LL_DEBUGS("ShaderLoading") << "Loading file: " << open_file_name << " (Want class " << gpu_class << ")" << LL_ENDL; break; // done } } if (file == NULL) { - LL_WARNS("ShaderLoading") << "GLSL Shader file not found: " << filename << LL_ENDL; + LL_SHADER_LOADING_WARNS() << "GLSL Shader file not found: " << open_file_name << LL_ENDL; return 0; } @@ -612,7 +709,31 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade } else { - if (major_version < 4) + if (major_version >= 4) + { + //set version to 400 + shader_code_text[shader_code_count++] = strdup("#version 400\n"); + } + else if (major_version == 3) + { + if (minor_version < 10) + { + shader_code_text[shader_code_count++] = strdup("#version 300\n"); + } + else if (minor_version <= 19) + { + shader_code_text[shader_code_count++] = strdup("#version 310\n"); + } + else if (minor_version <= 29) + { + shader_code_text[shader_code_count++] = strdup("#version 320\n"); + } + else + { + shader_code_text[shader_code_count++] = strdup("#version 330\n"); + } + } + else { //set version to 1.30 shader_code_text[shader_code_count++] = strdup("#version 130\n"); @@ -620,10 +741,6 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade extra_code_text[extra_code_count++] = strdup("precision mediump int;\n"); extra_code_text[extra_code_count++] = strdup("precision highp float;\n"); } - else - { //set version to 400 - shader_code_text[shader_code_count++] = strdup("#version 400\n"); - } extra_code_text[extra_code_count++] = strdup("#define DEFINE_GL_FRAGCOLOR 1\n"); extra_code_text[extra_code_count++] = strdup("#define FXAA_GLSL_130 1\n"); @@ -646,7 +763,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade extra_code_text[extra_code_count++] = strdup("#define texture2D texture\n"); extra_code_text[extra_code_count++] = strdup("#define textureCube texture\n"); extra_code_text[extra_code_count++] = strdup("#define texture2DLod textureLod\n"); - extra_code_text[extra_code_count++] = strdup("#define shadow2D(a,b) vec2(texture(a,b))\n"); + extra_code_text[extra_code_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 @@ -704,7 +821,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade } */ - extra_code_text[extra_code_count++] = strdup("#define HAS_DIFFUSE_LOOKUP 1\n"); + extra_code_text[extra_code_count++] = strdup("#define HAS_DIFFUSE_LOOKUP\n"); //uniform declartion for (S32 i = 0; i < texture_index_channels; ++i) @@ -763,11 +880,6 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade LL_ERRS() << "Indexed texture rendering requires GLSL 1.30 or later." << LL_ENDL; } } - else - { - extra_code_text[extra_code_count++] = strdup("#define HAS_DIFFUSE_LOOKUP 0\n"); - } - //copy file into memory enum { @@ -852,85 +964,45 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade //create shader object GLhandleARB ret = glCreateShaderObjectARB(type); - if (gDebugGL) + + error = glGetError(); + if (error != GL_NO_ERROR) { - error = glGetError(); - if (error != GL_NO_ERROR) - { - LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL; - } + LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << " for file: " << open_file_name << LL_ENDL; } - + //load source glShaderSourceARB(ret, shader_code_count, (const GLcharARB**) shader_code_text, NULL); - if (gDebugGL) + error = glGetError(); + if (error != GL_NO_ERROR) { - error = glGetError(); - if (error != GL_NO_ERROR) - { - LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSourceARB: " << error << LL_ENDL; - } + LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSourceARB: " << error << " for file: " << open_file_name << LL_ENDL; } //compile source glCompileShaderARB(ret); - if (gDebugGL) + error = glGetError(); + if (error != GL_NO_ERROR) { - error = glGetError(); - if (error != GL_NO_ERROR) - { - LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL; - } + LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << " for file: " << open_file_name << LL_ENDL; } - + if (error == GL_NO_ERROR) { //check for errors GLint success = GL_TRUE; glGetObjectParameterivARB(ret, GL_OBJECT_COMPILE_STATUS_ARB, &success); - if (gDebugGL || success == GL_FALSE) - { - error = glGetError(); - if (error != GL_NO_ERROR || success == GL_FALSE) - { - //an error occured, print log - LL_WARNS("ShaderLoading") << "GLSL Compilation Error:" << LL_ENDL; - dumpObjectLog(ret, TRUE, filename); -#if LL_WINDOWS - std::stringstream ostr; - //dump shader source for debugging - for (GLuint i = 0; i < shader_code_count; i++) - { - ostr << i << ": " << shader_code_text[i]; - if (i % 128 == 0) - { //dump every 128 lines - - LL_WARNS("ShaderLoading") << "\n" << ostr.str() << LL_ENDL; - ostr = std::stringstream(); - } - - } - - LL_WARNS("ShaderLoading") << "\n" << ostr.str() << LL_ENDL; -#else - std::string str; - - for (GLuint i = 0; i < shader_code_count; i++) { - str.append(shader_code_text[i]); - - if (i % 128 == 0) - { - LL_WARNS("ShaderLoading") << str << LL_ENDL; - str = ""; - } - } -#endif - - ret = 0; - } + error = glGetError(); + if (error != GL_NO_ERROR || success == GL_FALSE) + { + //an error occured, print log + LL_WARNS("ShaderLoading") << "GLSL Compilation Error:" << LL_ENDL; + dumpObjectLog(ret, TRUE, open_file_name); + dumpShaderSource(shader_code_count, shader_code_text); + ret = 0; } } else @@ -949,7 +1021,12 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade if (ret) { // Add shader file to map - mShaderObjects[filename] = ret; + if (type == GL_VERTEX_SHADER_ARB) { + mVertexShaderObjects[filename] = ret; + } + else if (type == GL_FRAGMENT_SHADER_ARB) { + mFragmentShaderObjects[filename] = ret; + } shader_level = try_gpu_class; } else @@ -957,7 +1034,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade if (shader_level > 1) { shader_level--; - return loadShaderFile(filename,shader_level,type, defines, texture_index_channels); + return loadShaderFile(filename, shader_level, type, defines, texture_index_channels); } LL_WARNS("ShaderLoading") << "Failed to load " << filename << LL_ENDL; } @@ -973,7 +1050,7 @@ BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors) if (!suppress_errors && success == GL_FALSE) { //an error occured, print log - LL_WARNS("ShaderLoading") << "GLSL Linker Error:" << LL_ENDL; + LL_SHADER_LOADING_WARNS() << "GLSL Linker Error:" << LL_ENDL; } #if LL_DARWIN @@ -1006,7 +1083,7 @@ BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors) CGLGetParameter(ctx, kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing); if (!fragmentGPUProcessing || !vertexGPUProcessing) { - LL_WARNS("ShaderLoading") << "GLSL Linker: Running in Software:" << LL_ENDL; + LL_SHADER_LOADING_WARNS() << "GLSL Linker: Running in Software:" << LL_ENDL; success = GL_FALSE; suppress_errors = FALSE; } @@ -1017,7 +1094,7 @@ BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors) LLStringUtil::toLower(log); if (log.find("software") != std::string::npos) { - LL_WARNS("ShaderLoading") << "GLSL Linker: Running in Software:" << LL_ENDL; + LL_SHADER_LOADING_WARNS() << "GLSL Linker: Running in Software:" << LL_ENDL; success = GL_FALSE; suppress_errors = FALSE; } @@ -1033,7 +1110,7 @@ BOOL LLShaderMgr::validateProgramObject(GLhandleARB obj) glGetObjectParameterivARB(obj, GL_OBJECT_VALIDATE_STATUS_ARB, &success); if (success == GL_FALSE) { - LL_WARNS("ShaderLoading") << "GLSL program not valid: " << LL_ENDL; + LL_SHADER_LOADING_WARNS() << "GLSL program not valid: " << LL_ENDL; dumpObjectLog(obj); } else @@ -1067,6 +1144,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("projection_matrix"); mReservedUniforms.push_back("inv_proj"); mReservedUniforms.push_back("modelview_projection_matrix"); + mReservedUniforms.push_back("inv_modelview"); mReservedUniforms.push_back("normal_matrix"); mReservedUniforms.push_back("texture_matrix0"); mReservedUniforms.push_back("texture_matrix1"); @@ -1090,7 +1168,7 @@ void LLShaderMgr::initAttribsAndUniforms() llassert(mReservedUniforms.size() == LLShaderMgr::MULTI_LIGHT_FAR_Z+1); - + //NOTE: MUST match order in eGLSLReservedUniforms mReservedUniforms.push_back("proj_mat"); mReservedUniforms.push_back("proj_near"); mReservedUniforms.push_back("proj_p"); @@ -1109,14 +1187,17 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("color"); mReservedUniforms.push_back("diffuseMap"); + mReservedUniforms.push_back("altDiffuseMap"); mReservedUniforms.push_back("specularMap"); mReservedUniforms.push_back("bumpMap"); + mReservedUniforms.push_back("bumpMap2"); mReservedUniforms.push_back("environmentMap"); - mReservedUniforms.push_back("cloude_noise_texture"); + mReservedUniforms.push_back("cloud_noise_texture"); + mReservedUniforms.push_back("cloud_noise_texture_next"); mReservedUniforms.push_back("fullbright"); mReservedUniforms.push_back("lightnorm"); - mReservedUniforms.push_back("sunlight_color_copy"); - mReservedUniforms.push_back("ambient"); + mReservedUniforms.push_back("sunlight_color"); + mReservedUniforms.push_back("ambient_color"); mReservedUniforms.push_back("blue_horizon"); mReservedUniforms.push_back("blue_density"); mReservedUniforms.push_back("haze_horizon"); @@ -1175,6 +1256,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("spot_shadow_bias"); mReservedUniforms.push_back("spot_shadow_offset"); mReservedUniforms.push_back("sun_dir"); + mReservedUniforms.push_back("moon_dir"); mReservedUniforms.push_back("shadow_res"); mReservedUniforms.push_back("proj_shadow_res"); mReservedUniforms.push_back("depth_cutoff"); @@ -1217,8 +1299,6 @@ void LLShaderMgr::initAttribsAndUniforms() 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"); @@ -1232,8 +1312,8 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("refTex"); mReservedUniforms.push_back("eyeVec"); mReservedUniforms.push_back("time"); - mReservedUniforms.push_back("d1"); - mReservedUniforms.push_back("d2"); + mReservedUniforms.push_back("waveDir1"); + mReservedUniforms.push_back("waveDir2"); mReservedUniforms.push_back("lightDir"); mReservedUniforms.push_back("specular"); mReservedUniforms.push_back("lightExp"); @@ -1265,6 +1345,34 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("origin"); mReservedUniforms.push_back("display_gamma"); + + mReservedUniforms.push_back("inscatter"); + mReservedUniforms.push_back("sun_size"); + mReservedUniforms.push_back("fog_color"); + + mReservedUniforms.push_back("transmittance_texture"); + mReservedUniforms.push_back("scattering_texture"); + mReservedUniforms.push_back("single_mie_scattering_texture"); + mReservedUniforms.push_back("irradiance_texture"); + mReservedUniforms.push_back("blend_factor"); + mReservedUniforms.push_back("no_atmo"); + mReservedUniforms.push_back("moisture_level"); + mReservedUniforms.push_back("droplet_radius"); + mReservedUniforms.push_back("ice_level"); + mReservedUniforms.push_back("rainbow_map"); + mReservedUniforms.push_back("halo_map"); + mReservedUniforms.push_back("moon_brightness"); + mReservedUniforms.push_back("cloud_variance"); + + mReservedUniforms.push_back("sh_input_r"); + mReservedUniforms.push_back("sh_input_g"); + mReservedUniforms.push_back("sh_input_b"); + + mReservedUniforms.push_back("sun_moon_glow_factor"); + mReservedUniforms.push_back("water_edge"); + mReservedUniforms.push_back("sun_up_factor"); + mReservedUniforms.push_back("moonlight_color"); + llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS); std::set<std::string> dupe_check; diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 394b38f832..3908efd4ec 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -36,188 +36,223 @@ public: LLShaderMgr(); virtual ~LLShaderMgr(); - typedef enum - { - MODELVIEW_MATRIX = 0, - PROJECTION_MATRIX, - INVERSE_PROJECTION_MATRIX, - MODELVIEW_PROJECTION_MATRIX, - NORMAL_MATRIX, - TEXTURE_MATRIX0, - TEXTURE_MATRIX1, - TEXTURE_MATRIX2, - TEXTURE_MATRIX3, - OBJECT_PLANE_S, - OBJECT_PLANE_T, - VIEWPORT, - LIGHT_POSITION, - LIGHT_DIRECTION, - LIGHT_ATTENUATION, - LIGHT_DIFFUSE, - LIGHT_AMBIENT, - MULTI_LIGHT_COUNT, - MULTI_LIGHT, - MULTI_LIGHT_COL, - MULTI_LIGHT_FAR_Z, - PROJECTOR_MATRIX, - PROJECTOR_NEAR, - PROJECTOR_P, - PROJECTOR_N, - PROJECTOR_ORIGIN, - PROJECTOR_RANGE, - PROJECTOR_AMBIANCE, - PROJECTOR_SHADOW_INDEX, - PROJECTOR_SHADOW_FADE, - PROJECTOR_FOCUS, - PROJECTOR_LOD, - PROJECTOR_AMBIENT_LOD, - DIFFUSE_COLOR, - DIFFUSE_MAP, - SPECULAR_MAP, - BUMP_MAP, - ENVIRONMENT_MAP, - CLOUD_NOISE_MAP, - FULLBRIGHT, - LIGHTNORM, - SUNLIGHT_COLOR, - AMBIENT, - BLUE_HORIZON, - BLUE_DENSITY, - HAZE_HORIZON, - HAZE_DENSITY, - CLOUD_SHADOW, - DENSITY_MULTIPLIER, - DISTANCE_MULTIPLIER, - MAX_Y, - GLOW, - CLOUD_COLOR, - CLOUD_POS_DENSITY1, - CLOUD_POS_DENSITY2, - CLOUD_SCALE, - GAMMA, - SCENE_LIGHT_STRENGTH, - LIGHT_CENTER, - LIGHT_SIZE, - LIGHT_FALLOFF, - BOX_CENTER, - BOX_SIZE, - - GLOW_MIN_LUMINANCE, - GLOW_MAX_EXTRACT_ALPHA, - GLOW_LUM_WEIGHTS, - GLOW_WARMTH_WEIGHTS, - GLOW_WARMTH_AMOUNT, - GLOW_STRENGTH, - GLOW_DELTA, - - MINIMUM_ALPHA, - EMISSIVE_BRIGHTNESS, - - DEFERRED_SHADOW_MATRIX, - DEFERRED_ENV_MAT, - DEFERRED_SHADOW_CLIP, - DEFERRED_SUN_WASH, - DEFERRED_SHADOW_NOISE, - DEFERRED_BLUR_SIZE, - DEFERRED_SSAO_RADIUS, - DEFERRED_SSAO_MAX_RADIUS, - DEFERRED_SSAO_FACTOR, - DEFERRED_SSAO_FACTOR_INV, - DEFERRED_SSAO_EFFECT_MAT, - DEFERRED_SCREEN_RES, - DEFERRED_NEAR_CLIP, - DEFERRED_SHADOW_OFFSET, - DEFERRED_SHADOW_BIAS, - DEFERRED_SPOT_SHADOW_BIAS, - DEFERRED_SPOT_SHADOW_OFFSET, - DEFERRED_SUN_DIR, - DEFERRED_SHADOW_RES, - DEFERRED_PROJ_SHADOW_RES, - DEFERRED_DEPTH_CUTOFF, - DEFERRED_NORM_CUTOFF, - DEFERRED_SHADOW_TARGET_WIDTH, - - FXAA_TC_SCALE, - FXAA_RCP_SCREEN_RES, - FXAA_RCP_FRAME_OPT, - FXAA_RCP_FRAME_OPT2, - - DOF_FOCAL_DISTANCE, - DOF_BLUR_CONSTANT, - DOF_TAN_PIXEL_ANGLE, - DOF_MAGNIFICATION, - DOF_MAX_COF, - DOF_RES_SCALE, - DOF_WIDTH, - DOF_HEIGHT, - - DEFERRED_DEPTH, - DEFERRED_SHADOW0, - DEFERRED_SHADOW1, - DEFERRED_SHADOW2, - DEFERRED_SHADOW3, - DEFERRED_SHADOW4, - DEFERRED_SHADOW5, - DEFERRED_NORMAL, - DEFERRED_POSITION, - DEFERRED_DIFFUSE, - DEFERRED_SPECULAR, - DEFERRED_NOISE, - DEFERRED_LIGHTFUNC, - DEFERRED_LIGHT, - DEFERRED_BLOOM, - DEFERRED_PROJECTION, - DEFERRED_NORM_MATRIX, - - GLOBAL_GAMMA, - TEXTURE_GAMMA, - - SPECULAR_COLOR, - ENVIRONMENT_INTENSITY, - - AVATAR_MATRIX, - AVATAR_TRANSLATION, - - 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; + // clang-format off + typedef enum + { // Shader uniform name, set in LLShaderMgr::initAttribsAndUniforms() + MODELVIEW_MATRIX = 0, // "modelview_matrix" + PROJECTION_MATRIX, // "projection_matrix" + INVERSE_PROJECTION_MATRIX, // "inv_proj" + MODELVIEW_PROJECTION_MATRIX, // "modelview_projection_matrix" + INVERSE_MODELVIEW_MATRIX, // "inv_modelview" + NORMAL_MATRIX, // "normal_matrix" + TEXTURE_MATRIX0, // "texture_matrix0" + TEXTURE_MATRIX1, // "texture_matrix1" + TEXTURE_MATRIX2, // "texture_matrix2" + TEXTURE_MATRIX3, // "texture_matrix3" + OBJECT_PLANE_S, // "object_plane_s" + OBJECT_PLANE_T, // "object_plane_t" + VIEWPORT, // "viewport" + LIGHT_POSITION, // "light_position" + LIGHT_DIRECTION, // "light_direction" + LIGHT_ATTENUATION, // "light_attenuation" + LIGHT_DIFFUSE, // "light_diffuse" + LIGHT_AMBIENT, // "light_ambient" + MULTI_LIGHT_COUNT, // "light_count" + MULTI_LIGHT, // "light" + MULTI_LIGHT_COL, // "light_col" + MULTI_LIGHT_FAR_Z, // "far_z" + PROJECTOR_MATRIX, // "proj_mat" + PROJECTOR_NEAR, // "proj_near" + PROJECTOR_P, // "proj_p" + PROJECTOR_N, // "proj_n" + PROJECTOR_ORIGIN, // "proj_origin" + PROJECTOR_RANGE, // "proj_range" + PROJECTOR_AMBIANCE, // "proj_ambiance" + PROJECTOR_SHADOW_INDEX, // "proj_shadow_idx" + PROJECTOR_SHADOW_FADE, // "shadow_fade" + PROJECTOR_FOCUS, // "proj_focus" + PROJECTOR_LOD, // "proj_lod" + PROJECTOR_AMBIENT_LOD, // "proj_ambient_lod" + DIFFUSE_COLOR, // "color" + DIFFUSE_MAP, // "diffuseMap" + ALTERNATE_DIFFUSE_MAP, // "altDiffuseMap" + SPECULAR_MAP, // "specularMap" + BUMP_MAP, // "bumpMap" + BUMP_MAP2, // "bumpMap2" + ENVIRONMENT_MAP, // "environmentMap" + CLOUD_NOISE_MAP, // "cloud_noise_texture" + CLOUD_NOISE_MAP_NEXT, // "cloud_noise_texture_next" + FULLBRIGHT, // "fullbright" + LIGHTNORM, // "lightnorm" + SUNLIGHT_COLOR, // "sunlight_color" + AMBIENT, // "ambient_color" + BLUE_HORIZON, // "blue_horizon" + BLUE_DENSITY, // "blue_density" + HAZE_HORIZON, // "haze_horizon" + HAZE_DENSITY, // "haze_density" + CLOUD_SHADOW, // "cloud_shadow" + DENSITY_MULTIPLIER, // "density_multiplier" + DISTANCE_MULTIPLIER, // "distance_multiplier" + MAX_Y, // "max_y" + GLOW, // "glow" + CLOUD_COLOR, // "cloud_color" + CLOUD_POS_DENSITY1, // "cloud_pos_density1" + CLOUD_POS_DENSITY2, // "cloud_pos_density2" + CLOUD_SCALE, // "cloud_scale" + GAMMA, // "gamma" + SCENE_LIGHT_STRENGTH, // "scene_light_strength" + LIGHT_CENTER, // "center" + LIGHT_SIZE, // "size" + LIGHT_FALLOFF, // "falloff" + BOX_CENTER, // "box_center" + BOX_SIZE, // "box_size" + + GLOW_MIN_LUMINANCE, // "minLuminance" + GLOW_MAX_EXTRACT_ALPHA, // "maxExtractAlpha" + GLOW_LUM_WEIGHTS, // "lumWeights" + GLOW_WARMTH_WEIGHTS, // "warmthWeights" + GLOW_WARMTH_AMOUNT, // "warmthAmount" + GLOW_STRENGTH, // "glowStrength" + GLOW_DELTA, // "glowDelta" + + MINIMUM_ALPHA, // "minimum_alpha" + EMISSIVE_BRIGHTNESS, // "emissive_brightness" + + DEFERRED_SHADOW_MATRIX, // "shadow_matrix" + DEFERRED_ENV_MAT, // "env_mat" + DEFERRED_SHADOW_CLIP, // "shadow_clip" + DEFERRED_SUN_WASH, // "sun_wash" + DEFERRED_SHADOW_NOISE, // "shadow_noise" + DEFERRED_BLUR_SIZE, // "blur_size" + DEFERRED_SSAO_RADIUS, // "ssao_radius" + DEFERRED_SSAO_MAX_RADIUS, // "ssao_max_radius" + DEFERRED_SSAO_FACTOR, // "ssao_factor" + DEFERRED_SSAO_FACTOR_INV, // "ssao_factor_inv" + DEFERRED_SSAO_EFFECT_MAT, // "ssao_effect_mat" + DEFERRED_SCREEN_RES, // "screen_res" + DEFERRED_NEAR_CLIP, // "near_clip" + DEFERRED_SHADOW_OFFSET, // "shadow_offset" + DEFERRED_SHADOW_BIAS, // "shadow_bias" + DEFERRED_SPOT_SHADOW_BIAS, // "spot_shadow_bias" + DEFERRED_SPOT_SHADOW_OFFSET, // "spot_shadow_offset" + DEFERRED_SUN_DIR, // "sun_dir" + DEFERRED_MOON_DIR, // "moon_dir" + DEFERRED_SHADOW_RES, // "shadow_res" + DEFERRED_PROJ_SHADOW_RES, // "proj_shadow_res" + DEFERRED_DEPTH_CUTOFF, // "depth_cutoff" + DEFERRED_NORM_CUTOFF, // "norm_cutoff" + DEFERRED_SHADOW_TARGET_WIDTH, // "shadow_target_width" + + FXAA_TC_SCALE, // "tc_scale" + FXAA_RCP_SCREEN_RES, // "rcp_screen_res" + FXAA_RCP_FRAME_OPT, // "rcp_frame_opt" + FXAA_RCP_FRAME_OPT2, // "rcp_frame_opt2" + + DOF_FOCAL_DISTANCE, // "focal_distance" + DOF_BLUR_CONSTANT, // "blur_constant" + DOF_TAN_PIXEL_ANGLE, // "tan_pixel_angle" + DOF_MAGNIFICATION, // "magnification" + DOF_MAX_COF, // "max_cof" + DOF_RES_SCALE, // "res_scale" + DOF_WIDTH, // "dof_width" + DOF_HEIGHT, // "dof_height" + + DEFERRED_DEPTH, // "depthMap" + DEFERRED_SHADOW0, // "shadowMap0" + DEFERRED_SHADOW1, // "shadowMap1" + DEFERRED_SHADOW2, // "shadowMap2" + DEFERRED_SHADOW3, // "shadowMap3" + DEFERRED_SHADOW4, // "shadowMap4" + DEFERRED_SHADOW5, // "shadowMap5" + DEFERRED_NORMAL, // "normalMap" + DEFERRED_POSITION, // "positionMap" + DEFERRED_DIFFUSE, // "diffuseRect" + DEFERRED_SPECULAR, // "specularRect" + DEFERRED_NOISE, // "noiseMap" + DEFERRED_LIGHTFUNC, // "lightFunc" + DEFERRED_LIGHT, // "lightMap" + DEFERRED_BLOOM, // "bloomMap" + DEFERRED_PROJECTION, // "projectionMap" + DEFERRED_NORM_MATRIX, // "norm_mat" + TEXTURE_GAMMA, // "texture_gamma" + SPECULAR_COLOR, // "specular_color" + ENVIRONMENT_INTENSITY, // "env_intensity" + + AVATAR_MATRIX, // "matrixPalette" + AVATAR_TRANSLATION, // "translationPalette" + + WATER_SCREENTEX, // "screenTex" + WATER_SCREENDEPTH, // "screenDepth" + WATER_REFTEX, // "refTex" + WATER_EYEVEC, // "eyeVec" + WATER_TIME, // "time" + WATER_WAVE_DIR1, // "waveDir1" + WATER_WAVE_DIR2, // "waveDir2" + WATER_LIGHT_DIR, // "lightDir" + WATER_SPECULAR, // "specular" + WATER_SPECULAR_EXP, // "lightExp" + WATER_FOGCOLOR, // "waterFogColor" + WATER_FOGDENSITY, // "waterFogDensity" + WATER_FOGKS, // "waterFogKS" + WATER_REFSCALE, // "refScale" + WATER_WATERHEIGHT, // "waterHeight" + WATER_WATERPLANE, // "waterPlane" + WATER_NORM_SCALE, // "normScale" + WATER_FRESNEL_SCALE, // "fresnelScale" + WATER_FRESNEL_OFFSET, // "fresnelOffset" + WATER_BLUR_MULTIPLIER, // "blurMultiplier" + WATER_SUN_ANGLE, // "sunAngle" + WATER_SCALED_ANGLE, // "scaledAngle" + WATER_SUN_ANGLE2, // "sunAngle2" + + WL_CAMPOSLOCAL, // "camPosLocal" + + AVATAR_WIND, // "gWindDir" + AVATAR_SINWAVE, // "gSinWaveParams" + AVATAR_GRAVITY, // "gGravity" + + TERRAIN_DETAIL0, // "detail_0" + TERRAIN_DETAIL1, // "detail_1" + TERRAIN_DETAIL2, // "detail_2" + TERRAIN_DETAIL3, // "detail_3" + TERRAIN_ALPHARAMP, // "alpha_ramp" + + SHINY_ORIGIN, // "origin" + DISPLAY_GAMMA, // "display_gamma" + + INSCATTER_RT, // "inscatter" + SUN_SIZE, // "sun_size" + FOG_COLOR, // "fog_color" + + // precomputed textures + TRANSMITTANCE_TEX, // "transmittance_texture" + SCATTER_TEX, // "scattering_texture" + SINGLE_MIE_SCATTER_TEX, // "single_mie_scattering_texture" + ILLUMINANCE_TEX, // "irradiance_texture" + BLEND_FACTOR, // "blend_factor" + + NO_ATMO, // "no_atmo" + MOISTURE_LEVEL, // "moisture_level" + DROPLET_RADIUS, // "droplet_radius" + ICE_LEVEL, // "ice_level" + RAINBOW_MAP, // "rainbow_map" + HALO_MAP, // "halo_map" + + MOON_BRIGHTNESS, // "moon_brightness" + + CLOUD_VARIANCE, // "cloud_variance" + + SH_INPUT_L1R, // "sh_input_r" + SH_INPUT_L1G, // "sh_input_g" + SH_INPUT_L1B, // "sh_input_b" + + SUN_MOON_GLOW_FACTOR, // "sun_moon_glow_factor" + WATER_EDGE_FACTOR, // "water_edge" + SUN_UP_FACTOR, // "sun_up_factor" + MOONLIGHT_COLOR, // "moonlight_color" + END_RESERVED_UNIFORMS + } eGLSLReservedUniforms; + // clang-format on // singleton pattern implementation static LLShaderMgr * instance(); @@ -226,6 +261,7 @@ DISPLAY_GAMMA, BOOL attachShaderFeatures(LLGLSLShader * shader); void dumpObjectLog(GLhandleARB ret, BOOL warns = TRUE, const std::string& filename = ""); + void dumpShaderSource(U32 shader_code_count, GLcharARB** shader_code_text); BOOL linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE); BOOL validateProgramObject(GLhandleARB obj); GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, boost::unordered_map<std::string, std::string>* defines = NULL, S32 texture_index_channels = -1); @@ -238,7 +274,8 @@ DISPLAY_GAMMA, public: // Map of shader names to compiled - std::map<std::string, GLhandleARB> mShaderObjects; + std::map<std::string, GLhandleARB> mVertexShaderObjects; + std::map<std::string, GLhandleARB> mFragmentShaderObjects; //global (reserved slot) shader parameters std::vector<std::string> mReservedAttribs; diff --git a/indra/llrender/lltexture.cpp b/indra/llrender/lltexture.cpp index 90fbcec2be..6eef36216c 100644 --- a/indra/llrender/lltexture.cpp +++ b/indra/llrender/lltexture.cpp @@ -29,3 +29,15 @@ LLTexture::~LLTexture() { } + +S8 LLTexture::getType() const { llassert(false); return 0; } +void LLTexture::setKnownDrawSize(S32 width, S32 height) { llassert(false); } +bool LLTexture::bindDefaultImage(const S32 stage) { llassert(false); return false; } +bool LLTexture::bindDebugImage(const S32 stage) { llassert(false); return false; } +void LLTexture::forceImmediateUpdate() { llassert(false); } +void LLTexture::setActive() { llassert(false); } +S32 LLTexture::getWidth(S32 discard_level) const { llassert(false); return 0; } +S32 LLTexture::getHeight(S32 discard_level) const { llassert(false); return 0; } +bool LLTexture::isActiveFetching() { llassert(false); return false; } +LLImageGL* LLTexture::getGLTexture() const { llassert(false); return nullptr; } +void LLTexture::updateBindStatsForTester() { } diff --git a/indra/llrender/lltexture.h b/indra/llrender/lltexture.h index 9fca8b8cd3..41481fb8a7 100644 --- a/indra/llrender/lltexture.h +++ b/indra/llrender/lltexture.h @@ -58,21 +58,21 @@ public: // //interfaces to access LLGLTexture // - virtual S8 getType() const = 0 ; - virtual void setKnownDrawSize(S32 width, S32 height) = 0 ; - virtual bool bindDefaultImage(const S32 stage = 0) = 0 ; - virtual bool bindDebugImage(const S32 stage = 0) = 0; - virtual void forceImmediateUpdate() = 0 ; - virtual void setActive() = 0 ; - virtual S32 getWidth(S32 discard_level = -1) const = 0 ; - virtual S32 getHeight(S32 discard_level = -1) const = 0 ; - virtual bool isActiveFetching() = 0; + virtual S8 getType() const; + virtual void setKnownDrawSize(S32 width, S32 height); + virtual bool bindDefaultImage(const S32 stage = 0); + virtual bool bindDebugImage(const S32 stage = 0); + virtual void forceImmediateUpdate(); + virtual void setActive(); + virtual S32 getWidth(S32 discard_level = -1) const; + virtual S32 getHeight(S32 discard_level = -1) const; + virtual bool isActiveFetching(); private: //note: do not make this function public. - virtual LLImageGL* getGLTexture() const = 0 ; + virtual LLImageGL* getGLTexture() const; - virtual void updateBindStatsForTester() = 0 ; + virtual void updateBindStatsForTester(); }; #endif diff --git a/indra/llrender/lluiimage.cpp b/indra/llrender/lluiimage.cpp index 5d8f92b2e6..424672fe8e 100644 --- a/indra/llrender/lluiimage.cpp +++ b/indra/llrender/lluiimage.cpp @@ -31,7 +31,6 @@ // Project includes #include "lluiimage.h" -#include "llrender2dutils.h" LLUIImage::LLUIImage(const std::string& name, LLPointer<LLTexture> image) : mName(name), @@ -39,67 +38,29 @@ LLUIImage::LLUIImage(const std::string& name, LLPointer<LLTexture> image) mScaleRegion(0.f, 1.f, 1.f, 0.f), mClipRegion(0.f, 1.f, 1.f, 0.f), mImageLoaded(NULL), - mScaleStyle(SCALE_INNER) -{} + mScaleStyle(SCALE_INNER), + mCachedW(-1), + mCachedH(-1) +{ + getTextureWidth(); + getTextureHeight(); +} LLUIImage::~LLUIImage() { delete mImageLoaded; } -void LLUIImage::setClipRegion(const LLRectf& region) +S32 LLUIImage::getWidth() const { - mClipRegion = region; + // return clipped dimensions of actual image area + return ll_round((F32)mImage->getWidth(0) * mClipRegion.getWidth()); } -void LLUIImage::setScaleRegion(const LLRectf& region) +S32 LLUIImage::getHeight() const { - mScaleRegion = region; -} - -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 -{ - draw(x, y, getWidth(), getHeight(), color); -} - -void LLUIImage::draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const -{ - 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 -{ - gl_draw_scaled_image_with_border( - x, y, - width, height, - mImage, - color, - TRUE, - mClipRegion, - mScaleRegion, - mScaleStyle == SCALE_INNER); -} - -void LLUIImage::drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const -{ - LLRect border_rect; - border_rect.setOriginAndSize(x, y, width, height); - border_rect.stretch(border_width, border_width); - drawSolid(border_rect, color); + // return clipped dimensions of actual image area + return ll_round((F32)mImage->getHeight(0) * mClipRegion.getHeight()); } void LLUIImage::draw3D(const LLVector3& origin_agent, const LLVector3& x_axis, const LLVector3& y_axis, @@ -120,12 +81,12 @@ void LLUIImage::draw3D(const LLVector3& origin_agent, const LLVector3& x_axis, c } } - LLRender2D::pushMatrix(); + LLRender2D::getInstance()->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]); + LLRender2D::getInstance()->translate(rect_origin.mV[VX], + rect_origin.mV[VY], + rect_origin.mV[VZ]); gGL.getTexUnit(0)->bind(getImage()); gGL.color4fv(color.mV); @@ -142,31 +103,10 @@ void LLUIImage::draw3D(const LLVector3& origin_agent, const LLVector3& x_axis, c rect.getWidth() * x_axis, rect.getHeight() * y_axis); - } LLRender2D::popMatrix(); + } LLRender2D::getInstance()->popMatrix(); } - -S32 LLUIImage::getWidth() const -{ - // return clipped dimensions of actual image area - return ll_round((F32)mImage->getWidth(0) * mClipRegion.getWidth()); -} - -S32 LLUIImage::getHeight() const -{ - // return clipped dimensions of actual image area - return ll_round((F32)mImage->getHeight(0) * mClipRegion.getHeight()); -} - -S32 LLUIImage::getTextureWidth() const -{ - return mImage->getWidth(0); -} - -S32 LLUIImage::getTextureHeight() const -{ - return mImage->getHeight(0); -} +//#include "lluiimage.inl" boost::signals2::connection LLUIImage::addLoadedCallback( const image_loaded_signal_t::slot_type& cb ) { @@ -186,7 +126,6 @@ void LLUIImage::onImageLoaded() } } - namespace LLInitParam { void ParamValue<LLUIImage*>::updateValueFromBlock() @@ -199,7 +138,7 @@ namespace LLInitParam return; } - LLUIImage* imagep = LLRender2D::getUIImage(name()); + LLUIImage* imagep = LLRender2D::getInstance()->getUIImage(name()); if (imagep) { updateValue(imagep); diff --git a/indra/llrender/lluiimage.h b/indra/llrender/lluiimage.h index 6f47385eb0..e462e19004 100644 --- a/indra/llrender/lluiimage.h +++ b/indra/llrender/lluiimage.h @@ -36,6 +36,7 @@ #include <boost/signals2.hpp> #include "llinitparam.h" #include "lltexture.h" +#include "llrender2dutils.h" extern const LLColor4 UI_VERTEX_COLOR; @@ -53,35 +54,46 @@ public: LLUIImage(const std::string& name, LLPointer<LLTexture> image); virtual ~LLUIImage(); - void setClipRegion(const LLRectf& region); - void setScaleRegion(const LLRectf& region); - void setScaleStyle(EScaleStyle style); + LL_FORCE_INLINE void setClipRegion(const LLRectf& region) + { + mClipRegion = region; + } - LLPointer<LLTexture> getImage() { return mImage; } - const LLPointer<LLTexture>& getImage() const { return mImage; } + LL_FORCE_INLINE void setScaleRegion(const LLRectf& region) + { + mScaleRegion = region; + } - void draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color = UI_VERTEX_COLOR) const; - void draw(S32 x, S32 y, const LLColor4& color = UI_VERTEX_COLOR) const; - void draw(const LLRect& rect, const LLColor4& color = UI_VERTEX_COLOR) const { draw(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); } + LL_FORCE_INLINE void setScaleStyle(EScaleStyle style) + { + mScaleStyle = style; + } + + LL_FORCE_INLINE LLPointer<LLTexture> getImage() { return mImage; } + LL_FORCE_INLINE const LLPointer<LLTexture>& getImage() const { return mImage; } + + LL_FORCE_INLINE void draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color = UI_VERTEX_COLOR) const; + LL_FORCE_INLINE void draw(S32 x, S32 y, const LLColor4& color = UI_VERTEX_COLOR) const; + LL_FORCE_INLINE void draw(const LLRect& rect, const LLColor4& color = UI_VERTEX_COLOR) const { draw(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); } - void drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const; - void drawSolid(const LLRect& rect, const LLColor4& color) const { drawSolid(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); } - void drawSolid(S32 x, S32 y, const LLColor4& color) const { drawSolid(x, y, getWidth(), getHeight(), color); } + LL_FORCE_INLINE void drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const; + LL_FORCE_INLINE void drawSolid(const LLRect& rect, const LLColor4& color) const { drawSolid(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); } + LL_FORCE_INLINE void drawSolid(S32 x, S32 y, const LLColor4& color) const { drawSolid(x, y, getWidth(), getHeight(), color); } - 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); } + LL_FORCE_INLINE void drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const; + LL_FORCE_INLINE void drawBorder(const LLRect& rect, const LLColor4& color, S32 border_width) const { drawBorder(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color, border_width); } + LL_FORCE_INLINE 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; } + LL_FORCE_INLINE const std::string& getName() const { return mName; } virtual S32 getWidth() const; virtual S32 getHeight() const; // returns dimensions of underlying textures, which might not be equal to ui image portion - S32 getTextureWidth() const; - S32 getTextureHeight() const; + LL_FORCE_INLINE S32 getTextureWidth() const; + LL_FORCE_INLINE S32 getTextureHeight() const; boost::signals2::connection addLoadedCallback( const image_loaded_signal_t::slot_type& cb ); @@ -95,8 +107,12 @@ protected: LLRectf mClipRegion; LLPointer<LLTexture> mImage; EScaleStyle mScaleStyle; + mutable S32 mCachedW; + mutable S32 mCachedH; }; +#include "lluiimage.inl" + namespace LLInitParam { template<> diff --git a/indra/llrender/lluiimage.inl b/indra/llrender/lluiimage.inl new file mode 100644 index 0000000000..f5227556f0 --- /dev/null +++ b/indra/llrender/lluiimage.inl @@ -0,0 +1,77 @@ +/** + * @file lluiimage.inl + * @brief UI inline func implementation + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +void LLUIImage::draw(S32 x, S32 y, const LLColor4& color) const +{ + draw(x, y, getWidth(), getHeight(), color); +} + +void LLUIImage::draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const +{ + 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 +{ + gl_draw_scaled_image_with_border( + x, y, + width, height, + mImage, + color, + TRUE, + mClipRegion, + mScaleRegion, + mScaleStyle == SCALE_INNER); +} + +void LLUIImage::drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const +{ + LLRect border_rect; + border_rect.setOriginAndSize(x, y, width, height); + border_rect.stretch(border_width, border_width); + drawSolid(border_rect, color); +} + +// returns dimensions of underlying textures, which might not be equal to ui image portion +S32 LLUIImage::getTextureWidth() const +{ + mCachedW = (mCachedW == -1) ? getWidth() : mCachedW; + return mCachedW; +} + +S32 LLUIImage::getTextureHeight() const +{ + mCachedH = (mCachedH == -1) ? getHeight() : mCachedH; + return mCachedH; +} diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 1312f6afda..7d2b09ca4a 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -660,6 +660,9 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const { + llassert(start < (U32)mNumVerts); + llassert(end < (U32)mNumVerts); + if (start >= (U32) mNumVerts || end >= (U32) mNumVerts) { @@ -679,6 +682,9 @@ void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of U16* idx = ((U16*) getIndicesPointer())+indices_offset; for (U32 i = 0; i < count; ++i) { + llassert(idx[i] >= start); + llassert(idx[i] <= end); + if (idx[i] < start || idx[i] > end) { LL_ERRS() << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << LL_ENDL; @@ -697,6 +703,7 @@ void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of for (U32 i = start; i < end; i++) { S32 idx = (S32) (v[i][3]+0.25f); + llassert(idx >= 0); if (idx < 0 || idx >= shader->mFeatures.mIndexedTextureChannels) { LL_ERRS() << "Bad texture index found in vertex data stream." << LL_ENDL; @@ -942,15 +949,15 @@ S32 LLVertexBuffer::determineUsage(S32 usage) { //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default if (ret_usage != GL_DYNAMIC_COPY_ARB) { - if (sDisableVBOMapping) - { //always use stream draw if VBO mapping is disabled - ret_usage = GL_STREAM_DRAW_ARB; - } - else - { - ret_usage = GL_DYNAMIC_DRAW_ARB; - } - } + if (sDisableVBOMapping) + { //always use stream draw if VBO mapping is disabled + ret_usage = GL_STREAM_DRAW_ARB; + } + else + { + ret_usage = GL_DYNAMIC_DRAW_ARB; + } + } } return ret_usage; @@ -1186,7 +1193,7 @@ bool LLVertexBuffer::createGLBuffer(U32 size) return true; } - bool sucsess = true; + bool success = true; mEmpty = true; @@ -1208,9 +1215,9 @@ bool LLVertexBuffer::createGLBuffer(U32 size) if (!mMappedData) { - sucsess = false; + success = false; } - return sucsess; + return success; } bool LLVertexBuffer::createGLIndices(U32 size) @@ -1225,7 +1232,7 @@ bool LLVertexBuffer::createGLIndices(U32 size) return true; } - bool sucsess = true; + bool success = true; mEmpty = true; @@ -1250,9 +1257,9 @@ bool LLVertexBuffer::createGLIndices(U32 size) if (!mMappedIndexData) { - sucsess = false; + success = false; } - return sucsess; + return success; } void LLVertexBuffer::destroyGLBuffer() @@ -1299,7 +1306,7 @@ bool LLVertexBuffer::updateNumVerts(S32 nverts) { llassert(nverts >= 0); - bool sucsess = true; + bool success = true; if (nverts > 65536) { @@ -1311,34 +1318,34 @@ bool LLVertexBuffer::updateNumVerts(S32 nverts) if (needed_size > mSize || needed_size <= mSize/2) { - sucsess &= createGLBuffer(needed_size); + success &= createGLBuffer(needed_size); } sVertexCount -= mNumVerts; mNumVerts = nverts; sVertexCount += mNumVerts; - return sucsess; + return success; } bool LLVertexBuffer::updateNumIndices(S32 nindices) { llassert(nindices >= 0); - bool sucsess = true; + bool success = true; U32 needed_size = sizeof(U16) * nindices; if (needed_size > mIndicesSize || needed_size <= mIndicesSize/2) { - sucsess &= createGLIndices(needed_size); + success &= createGLIndices(needed_size); } sIndexCount -= mNumIndices; mNumIndices = nindices; sIndexCount += mNumIndices; - return sucsess; + return success; } bool LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) @@ -1351,10 +1358,10 @@ bool LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) LL_ERRS() << "Bad vertex buffer allocation: " << nverts << " : " << nindices << LL_ENDL; } - bool sucsess = true; + bool success = true; - sucsess &= updateNumVerts(nverts); - sucsess &= updateNumIndices(nindices); + success &= updateNumVerts(nverts); + success &= updateNumIndices(nindices); if (create && (nverts || nindices)) { @@ -1370,7 +1377,7 @@ bool LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) } } - return sucsess; + return success; } static LLTrace::BlockTimerStatHandle FTM_SETUP_VERTEX_ARRAY("Setup VAO"); @@ -1471,7 +1478,12 @@ 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], (const GLvoid*) mOffsets[i]); + // nat 2018-10-24: VS 2017 also notices the issue + // described below, and warns even with reinterpret_cast. + // Cast via intptr_t to make it painfully obvious to the + // compiler that we're doing this intentionally. + glVertexAttribIPointer(i, attrib_size[i], attrib_type[i], sTypeSize[i], + reinterpret_cast<const GLvoid*>(intptr_t(mOffsets[i]))); } #endif } @@ -1486,7 +1498,7 @@ void LLVertexBuffer::setupVertexArray() // rather than as an actual pointer, so it's okay. glVertexAttribPointerARB(i, attrib_size[i], attrib_type[i], attrib_normalized[i], sTypeSize[i], - reinterpret_cast<GLvoid*>(mOffsets[i])); + reinterpret_cast<GLvoid*>(intptr_t(mOffsets[i]))); } } else @@ -1506,10 +1518,10 @@ bool LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) llassert(newnverts >= 0); llassert(newnindices >= 0); - bool sucsess = true; + bool success = true; - sucsess &= updateNumVerts(newnverts); - sucsess &= updateNumIndices(newnindices); + success &= updateNumVerts(newnverts); + success &= updateNumIndices(newnindices); if (useVBOs()) { @@ -1521,7 +1533,7 @@ bool LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) } } - return sucsess; + return success; } bool LLVertexBuffer::useVBOs() const @@ -2319,34 +2331,35 @@ void LLVertexBuffer::setBuffer(U32 data_mask) { U32 unsatisfied_mask = (required_mask & ~data_mask); - U32 i = 0; - while (i < TYPE_MAX) - { + for (U32 i = 0; i < TYPE_MAX; i++) + { U32 unsatisfied_flag = unsatisfied_mask & (1 << i); - switch (unsatisfied_flag) - { - case MAP_VERTEX: LL_INFOS() << "Missing vert pos" << LL_ENDL; break; - case MAP_NORMAL: LL_INFOS() << "Missing normals" << LL_ENDL; break; - case MAP_TEXCOORD0: LL_INFOS() << "Missing TC 0" << LL_ENDL; break; - case MAP_TEXCOORD1: LL_INFOS() << "Missing TC 1" << LL_ENDL; break; - case MAP_TEXCOORD2: LL_INFOS() << "Missing TC 2" << LL_ENDL; break; - case MAP_TEXCOORD3: LL_INFOS() << "Missing TC 3" << LL_ENDL; break; - case MAP_COLOR: LL_INFOS() << "Missing vert color" << LL_ENDL; break; - case MAP_EMISSIVE: LL_INFOS() << "Missing emissive" << LL_ENDL; break; - case MAP_TANGENT: LL_INFOS() << "Missing tangent" << LL_ENDL; break; - case MAP_WEIGHT: LL_INFOS() << "Missing weight" << LL_ENDL; break; - case MAP_WEIGHT4: LL_INFOS() << "Missing weightx4" << LL_ENDL; break; - case MAP_CLOTHWEIGHT: LL_INFOS() << "Missing clothweight" << LL_ENDL; break; - case MAP_TEXTURE_INDEX: LL_INFOS() << "Missing tex index" << LL_ENDL; break; - default: LL_INFOS() << "Missing who effin knows: " << unsatisfied_flag << LL_ENDL; - } - } - - if (unsatisfied_mask & (1 << TYPE_INDEX)) - { - LL_INFOS() << "Missing indices" << LL_ENDL; - } + switch (unsatisfied_flag) + { + case 0: break; + case MAP_VERTEX: LL_INFOS() << "Missing vert pos" << LL_ENDL; break; + case MAP_NORMAL: LL_INFOS() << "Missing normals" << LL_ENDL; break; + case MAP_TEXCOORD0: LL_INFOS() << "Missing TC 0" << LL_ENDL; break; + case MAP_TEXCOORD1: LL_INFOS() << "Missing TC 1" << LL_ENDL; break; + case MAP_TEXCOORD2: LL_INFOS() << "Missing TC 2" << LL_ENDL; break; + case MAP_TEXCOORD3: LL_INFOS() << "Missing TC 3" << LL_ENDL; break; + case MAP_COLOR: LL_INFOS() << "Missing vert color" << LL_ENDL; break; + case MAP_EMISSIVE: LL_INFOS() << "Missing emissive" << LL_ENDL; break; + case MAP_TANGENT: LL_INFOS() << "Missing tangent" << LL_ENDL; break; + case MAP_WEIGHT: LL_INFOS() << "Missing weight" << LL_ENDL; break; + case MAP_WEIGHT4: LL_INFOS() << "Missing weightx4" << LL_ENDL; break; + case MAP_CLOTHWEIGHT: LL_INFOS() << "Missing clothweight" << LL_ENDL; break; + case MAP_TEXTURE_INDEX: LL_INFOS() << "Missing tex index" << LL_ENDL; break; + default: LL_INFOS() << "Missing who effin knows: " << unsatisfied_flag << LL_ENDL; + } + } + + // TYPE_INDEX is beyond TYPE_MAX, so check for it individually + if (unsatisfied_mask & (1 << TYPE_INDEX)) + { + LL_INFOS() << "Missing indices" << LL_ENDL; + } LL_ERRS() << "Shader consumption mismatches data provision." << LL_ENDL; } diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index c89d7e3958..dbe1a3687f 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -155,9 +155,8 @@ public: //get the size of a buffer with the given typemask and vertex count //fill offsets with the offset of each vertex component array into the buffer // indexed by the following enum - static S32 calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices); + static S32 calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices); - //WARNING -- when updating these enums you MUST // 1 - update LLVertexBuffer::sTypeSize // 2 - add a strider accessor @@ -165,24 +164,28 @@ public: // 4 - modify LLVertexBuffer::setupClientArray // 5 - modify LLViewerShaderMgr::mReservedAttribs // 6 - update LLVertexBuffer::setupVertexArray - enum { - TYPE_VERTEX = 0, - 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, - }; - enum { + + // clang-format off + enum { // Shader attribute name, set in LLShaderMgr::initAttribsAndUniforms() + TYPE_VERTEX = 0, // "position" + TYPE_NORMAL, // "normal" + TYPE_TEXCOORD0, // "texcoord0" + TYPE_TEXCOORD1, // "texcoord1" + TYPE_TEXCOORD2, // "texcoord2" + TYPE_TEXCOORD3, // "texcoord3" + TYPE_COLOR, // "diffuse_color" + TYPE_EMISSIVE, // "emissive" + TYPE_TANGENT, // "tangent" + TYPE_WEIGHT, // "weight" + TYPE_WEIGHT4, // "weight4" + TYPE_CLOTHWEIGHT, // "clothing" + TYPE_TEXTURE_INDEX, // "texture_index" + TYPE_MAX, // TYPE_MAX is the size/boundary marker for attributes that go in the vertex buffer + TYPE_INDEX, // TYPE_INDEX is beyond _MAX because it lives in a separate (index) buffer + }; + // clang-format on + + enum { MAP_VERTEX = (1<<TYPE_VERTEX), MAP_NORMAL = (1<<TYPE_NORMAL), MAP_TEXCOORD0 = (1<<TYPE_TEXCOORD0), diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index e44f57fa9f..f781ff4110 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -122,6 +122,7 @@ set(llui_SOURCE_FILES lluictrl.cpp lluictrlfactory.cpp lluistring.cpp + lluiusage.cpp llundo.cpp llurlaction.cpp llurlentry.cpp @@ -133,8 +134,10 @@ set(llui_SOURCE_FILES llview.cpp llviewquery.cpp llviewereventrecorder.cpp + llvirtualtrackball.cpp llwindowshade.cpp llxuiparser.cpp + llxyvector.cpp ) set(llui_HEADER_FILES @@ -239,6 +242,7 @@ set(llui_HEADER_FILES llui.h lluicolor.h lluistring.h + lluiusage.h llundo.h llurlaction.h llurlentry.h @@ -250,8 +254,10 @@ set(llui_HEADER_FILES llview.h llviewereventrecorder.h llviewquery.h + llvirtualtrackball.h llwindowshade.h llxuiparser.h + llxyvector.h ) set_source_files_properties(${llui_HEADER_FILES} @@ -299,7 +305,7 @@ if(LL_TESTS) set(test_libs llui llmessage llcorehttp llcommon ${HUNSPELL_LIBRARY} ${LLCOMMON_LIBRARIES} - ${BOOST_COROUTINE_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY} ${WINDOWS_LIBRARIES}) if(NOT LINUX) LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}") diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp index 623f570cef..809d72208f 100644 --- a/indra/llui/llaccordionctrl.cpp +++ b/indra/llui/llaccordionctrl.cpp @@ -55,6 +55,7 @@ LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params) , mTabComparator( NULL ) , mNoVisibleTabsHelpText(NULL) , mNoVisibleTabsOrigString(params.no_visible_tabs_text.initial_value().asString()) + , mSkipScrollToChild(false) { initNoTabsWidget(params.no_matched_tabs_text); @@ -338,7 +339,7 @@ void LLAccordionCtrl::addCollapsibleCtrl(LLView* view) addChild(accordion_tab); mAccordionTabs.push_back(accordion_tab); - accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLAccordionCtrl::onCollapseCtrlCloseOpen, this, mAccordionTabs.size() - 1) ); + accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLAccordionCtrl::onCollapseCtrlCloseOpen, this, (S16)(mAccordionTabs.size() - 1)) ); arrange(); } @@ -655,6 +656,37 @@ void LLAccordionCtrl::onScrollPosChangeCallback(S32, LLScrollbar*) { updateLayout(getRect().getWidth(),getRect().getHeight()); } + +// virtual +void LLAccordionCtrl::onUpdateScrollToChild(const LLUICtrl *cntrl) +{ + if (mScrollbar && mScrollbar->getVisible() && !mSkipScrollToChild) + { + // same as scrollToShowRect + LLRect rect; + cntrl->localRectToOtherView(cntrl->getLocalRect(), &rect, this); + + // Translate to parent coordinatess to check if we are in visible rectangle + rect.translate(getRect().mLeft, getRect().mBottom); + + if (!getRect().contains(rect)) + { + // for accordition's scroll, height is in pixels + // Back to local coords and calculate position for scroller + S32 bottom = mScrollbar->getDocPos() - rect.mBottom + getRect().mBottom; + S32 top = mScrollbar->getDocPos() - rect.mTop + getRect().mTop; + + S32 scroll_pos = llclamp(mScrollbar->getDocPos(), + bottom, // min vertical scroll + top); // max vertical scroll + + mScrollbar->setDocPos(scroll_pos); + } + } + + LLUICtrl::onUpdateScrollToChild(cntrl); +} + void LLAccordionCtrl::onOpen (const LLSD& key) { for(size_t i=0;i<mAccordionTabs.size();++i) diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h index 1fe64c472e..2828254472 100644 --- a/indra/llui/llaccordionctrl.h +++ b/indra/llui/llaccordionctrl.h @@ -111,6 +111,7 @@ public: void draw(); void onScrollPosChangeCallback(S32, LLScrollbar*); + virtual void onUpdateScrollToChild(const LLUICtrl * cntrl); void onOpen (const LLSD& key); S32 notifyParent(const LLSD& info); @@ -137,6 +138,8 @@ public: bool getFitParent() const {return mFitParent;} + void setSkipScrollToChild(bool skip) { mSkipScrollToChild = skip; } + private: void initNoTabsWidget(const LLTextBox::Params& tb_params); void updateNoTabsHelpTextVisibility(); @@ -182,6 +185,8 @@ private: F32 mAutoScrollRate; LLTextBox* mNoVisibleTabsHelpText; + bool mSkipScrollToChild; + std::string mNoMatchedTabsOrigString; std::string mNoVisibleTabsOrigString; diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp index eaf1284237..04485c6262 100644 --- a/indra/llui/llaccordionctrltab.cpp +++ b/indra/llui/llaccordionctrltab.cpp @@ -452,6 +452,35 @@ void LLAccordionCtrlTab::onVisibilityChange(BOOL new_visibility) notifyParent(LLSD().with("child_visibility_change", new_visibility)); } +// virtual +void LLAccordionCtrlTab::onUpdateScrollToChild(const LLUICtrl *cntrl) +{ + if (mScrollbar && mScrollbar->getVisible()) + { + LLRect rect; + cntrl->localRectToOtherView(cntrl->getLocalRect(), &rect, this); + + // Translate to parent coordinatess to check if we are in visible rectangle + rect.translate(getRect().mLeft, getRect().mBottom); + + if (!getRect().contains(rect)) + { + // for accordition's scroll, height is in pixels + // Back to local coords and calculate position for scroller + S32 bottom = mScrollbar->getDocPos() - rect.mBottom + getRect().mBottom; + S32 top = mScrollbar->getDocPos() - rect.mTop + getRect().mTop; + + S32 scroll_pos = llclamp(mScrollbar->getDocPos(), + bottom, // min vertical scroll + top); // max vertical scroll + + mScrollbar->setDocPos(scroll_pos); + } + } + + LLUICtrl::onUpdateScrollToChild(cntrl); +} + BOOL LLAccordionCtrlTab::handleMouseDown(S32 x, S32 y, MASK mask) { if(mCollapsible && mHeaderVisible && mCanOpenClose) @@ -977,7 +1006,7 @@ void LLAccordionCtrlTab::drawChild(const LLRect& root_rect,LLView* child) LLRect screen_rect; localRectToScreen(child->getRect(),&screen_rect); - if ( root_rect.overlaps(screen_rect) && LLUI::sDirtyRect.overlaps(screen_rect)) + if ( root_rect.overlaps(screen_rect) && sDirtyRect.overlaps(screen_rect)) { gGL.matrixMode(LLRender::MM_MODELVIEW); LLUI::pushMatrix(); diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h index 0263bce4be..2c72e8c036 100644 --- a/indra/llui/llaccordionctrltab.h +++ b/indra/llui/llaccordionctrltab.h @@ -159,6 +159,7 @@ public: * Raises notifyParent event with "child_visibility_change" = new_visibility */ void onVisibilityChange(BOOL new_visibility); + virtual void onUpdateScrollToChild(const LLUICtrl * cntrl); // Changes expand/collapse state and triggers expand/collapse callbacks virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); diff --git a/indra/llui/llbadgeowner.cpp b/indra/llui/llbadgeowner.cpp index 0557cd4375..5f11c383ef 100644 --- a/indra/llui/llbadgeowner.cpp +++ b/indra/llui/llbadgeowner.cpp @@ -56,6 +56,14 @@ void LLBadgeOwner::initBadgeParams(const LLBadge::Params& p) } } +void LLBadgeOwner::reshapeBadge(const LLRect& new_rect) +{ + if (mBadge) + { + mBadge->setShape(new_rect); + } +} + void LLBadgeOwner::setBadgeVisibility(bool visible) { if (mBadge) diff --git a/indra/llui/llbadgeowner.h b/indra/llui/llbadgeowner.h index 01ed95f3a3..4ce208fa0d 100644 --- a/indra/llui/llbadgeowner.h +++ b/indra/llui/llbadgeowner.h @@ -46,6 +46,7 @@ public: bool hasBadgeHolderParent() const { return mHasBadgeHolderParent; }; void setBadgeVisibility(bool visible); void setDrawBadgeAtTop(bool draw_at_top); + void reshapeBadge(const LLRect& new_rect); private: diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 6b7a8a8b86..0e59fdf519 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -47,6 +47,7 @@ #include "llnotificationsutil.h" #include "llrender.h" #include "lluictrlfactory.h" +#include "lluiusage.h" #include "llhelp.h" #include "lldockablefloater.h" #include "llviewereventrecorder.h" @@ -90,8 +91,8 @@ LLButton::Params::Params() image_overlay_disabled_color("image_overlay_disabled_color", LLColor4::white % 0.3f), image_overlay_selected_color("image_overlay_selected_color", LLColor4::white), flash_color("flash_color"), - pad_right("pad_right", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")), - pad_left("pad_left", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")), + pad_right("pad_right", LLUI::getInstance()->mSettingGroups["config"]->getS32("ButtonHPad")), + pad_left("pad_left", LLUI::getInstance()->mSettingGroups["config"]->getS32("ButtonHPad")), pad_bottom("pad_bottom"), click_callback("click_callback"), mouse_down_callback("mouse_down_callback"), @@ -437,6 +438,13 @@ BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask) setFocus(TRUE); } + if (!mFunctionName.empty()) + { + LL_DEBUGS("UIUsage") << "calling mouse down function " << mFunctionName << LL_ENDL; + LLUIUsage::instance().logCommand(mFunctionName); + LLUIUsage::instance().logControl(getPathname()); + } + /* * ATTENTION! This call fires another mouse down callback. * If you wish to remove this call emit that signal directly @@ -614,7 +622,7 @@ void LLButton::getOverlayImageSize(S32& overlay_width, S32& overlay_height) // virtual void LLButton::draw() { - static LLCachedControl<bool> sEnableButtonFlashing(*LLUI::sSettingGroups["config"], "EnableButtonFlashing", true); + static LLCachedControl<bool> sEnableButtonFlashing(*LLUI::getInstance()->mSettingGroups["config"], "EnableButtonFlashing", true); F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency(); bool pressed_by_keyboard = FALSE; @@ -628,7 +636,7 @@ void LLButton::draw() { S32 local_mouse_x ; S32 local_mouse_y; - LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); + LLUI::getInstance()->getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); mouse_pressed_and_over = pointInView(local_mouse_x, local_mouse_y); } @@ -643,7 +651,8 @@ void LLButton::draw() LLColor4 highlighting_color = LLColor4::white; LLColor4 glow_color = LLColor4::white; LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA; - LLUIImage* imagep = NULL; + LLUIImage* imagep = NULL; + LLUIImage* image_glow = NULL; // Cancel sticking of color, if the button is pressed, // or when a flashing of the previously selected button is ended @@ -710,17 +719,18 @@ void LLButton::draw() imagep = mImageDisabled; } + image_glow = imagep; + if (mFlashing) { - // if button should flash and we have icon for flashing, use it as image for button - if(flash && mImageFlash) + if (flash && mImageFlash) { - // setting flash to false to avoid its further influence on glow - flash = false; - imagep = mImageFlash; + // if button should flash and we have icon for flashing, use it as image for button + image_glow = mImageFlash; } - // else use usual flashing via flash_color - else if (mFlashingTimer) + + // provide fade-in and fade-out via flash_color + if (mFlashingTimer) { LLColor4 flash_color = mFlashBgColor.get(); use_glow_effect = TRUE; @@ -734,6 +744,11 @@ void LLButton::draw() { glow_color = highlighting_color; } + else + { + // will fade from highlight color + glow_color = flash_color; + } } } @@ -806,7 +821,7 @@ void LLButton::draw() if (mCurGlowStrength > 0.01f) { gGL.setSceneBlendType(glow_type); - imagep->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha)); + image_glow->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha)); gGL.setSceneBlendType(LLRender::BT_ALPHA); } } @@ -817,7 +832,7 @@ void LLButton::draw() if (mCurGlowStrength > 0.01f) { gGL.setSceneBlendType(glow_type); - imagep->drawSolid(0, y, glow_color % (mCurGlowStrength * alpha)); + image_glow->drawSolid(0, y, glow_color % (mCurGlowStrength * alpha)); gGL.setSceneBlendType(LLRender::BT_ALPHA); } } @@ -1261,10 +1276,10 @@ void LLButton::showHelp(LLUICtrl* ctrl, const LLSD& sdname) // search back through the button's parents for a panel // with a help_topic string defined std::string help_topic; - if (LLUI::sHelpImpl && + if (LLUI::getInstance()->mHelpImpl && ctrl->findHelpTopic(help_topic)) { - LLUI::sHelpImpl->showTopic(help_topic); + LLUI::getInstance()->mHelpImpl->showTopic(help_topic); return; // success } diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 7629ed1fea..572d36996c 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -205,6 +205,7 @@ public: void setFlashing( bool b, bool force_flashing = false ); BOOL getFlashing() const { return mFlashing; } LLFlashTimer* getFlashTimer() {return mFlashingTimer;} + void setFlashColor(const LLUIColor &color) { mFlashBgColor = color; }; void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; } LLFontGL::HAlign getHAlign() const { return mHAlign; } diff --git a/indra/llui/llchat.h b/indra/llui/llchat.h index f5b242fdfc..c39e44200c 100644 --- a/indra/llui/llchat.h +++ b/indra/llui/llchat.h @@ -37,7 +37,8 @@ typedef enum e_chat_source_type CHAT_SOURCE_SYSTEM = 0, CHAT_SOURCE_AGENT = 1, CHAT_SOURCE_OBJECT = 2, - CHAT_SOURCE_UNKNOWN = 3 + CHAT_SOURCE_TELEPORT = 3, + CHAT_SOURCE_UNKNOWN = 4 } EChatSourceType; typedef enum e_chat_type @@ -64,7 +65,8 @@ typedef enum e_chat_style { CHAT_STYLE_NORMAL, CHAT_STYLE_IRC, - CHAT_STYLE_HISTORY + CHAT_STYLE_HISTORY, + CHAT_STYLE_TELEPORT_SEP }EChatStyle; // A piece of chat diff --git a/indra/llui/llchatentry.cpp b/indra/llui/llchatentry.cpp index dac001afab..c506576126 100644 --- a/indra/llui/llchatentry.cpp +++ b/indra/llui/llchatentry.cpp @@ -201,7 +201,7 @@ BOOL LLChatEntry::handleSpecialKey(const KEY key, const MASK mask) } else { - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } handled = TRUE; } @@ -225,7 +225,7 @@ BOOL LLChatEntry::handleSpecialKey(const KEY key, const MASK mask) } else { - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } handled = TRUE; } diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp index eee6339caf..08da599ef2 100644 --- a/indra/llui/llcheckboxctrl.cpp +++ b/indra/llui/llcheckboxctrl.cpp @@ -47,10 +47,18 @@ static LLDefaultChildRegistry::Register<LLCheckBoxCtrl> r("check_box"); template class LLCheckBoxCtrl* LLView::getChild<class LLCheckBoxCtrl>( const std::string& name, BOOL recurse) const; +void LLCheckBoxCtrl::WordWrap::declareValues() +{ + declare("none", EWordWrap::WRAP_NONE); + declare("down", EWordWrap::WRAP_DOWN); + declare("up", EWordWrap::WRAP_UP); +} + LLCheckBoxCtrl::Params::Params() : initial_value("initial_value", false), label_text("label_text"), check_button("check_button"), + word_wrap("word_wrap", EWordWrap::WRAP_NONE), radio_style("radio_style") {} @@ -59,14 +67,14 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) : LLUICtrl(p), mTextEnabledColor(p.label_text.text_color()), mTextDisabledColor(p.label_text.text_readonly_color()), - mFont(p.font()) + mFont(p.font()), + mWordWrap(p.word_wrap) { mViewModel->setValue(LLSD(p.initial_value)); mViewModel->resetDirty(); static LLUICachedControl<S32> llcheckboxctrl_spacing ("UICheckboxctrlSpacing", 0); static LLUICachedControl<S32> llcheckboxctrl_hpad ("UICheckboxctrlHPad", 0); static LLUICachedControl<S32> llcheckboxctrl_vpad ("UICheckboxctrlVPad", 0); - static LLUICachedControl<S32> llcheckboxctrl_btn_size ("UICheckboxctrlBtnSize", 0); // must be big enough to hold all children setUseBoundingRect(TRUE); @@ -85,20 +93,47 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) { tbparams.font(p.font); } - mLabel = LLUICtrlFactory::create<LLTextBox> (tbparams); + + mLabel = LLUICtrlFactory::create<LLTextBox>(tbparams); + if (mWordWrap != WRAP_NONE) + { + // Not setWordWrap(mWordWrap != WRAP_NONE) because there might be some old lurking code that sets it manually + mLabel->setWordWrap(true); + S32 new_width = getRect().getWidth() - p.check_button.rect().getWidth() - llcheckboxctrl_hpad; + LLRect label_rect = mLabel->getRect(); + label_rect.mRight = label_rect.mLeft + new_width; + mLabel->setRect(label_rect); + } mLabel->reshapeToFitText(); - addChild(mLabel); LLRect label_rect = mLabel->getRect(); + if (mLabel->getLineCount() > 1) + { + if (mWordWrap == WRAP_DOWN) + { + // reshapeToFitText uses LLView::reshape() which always reshapes + // from bottom to top, but we want to extend the bottom + // Note: might be better idea to use getRect().mTop of LLCheckBoxCtrl (+pad) as top point of new rect + S32 delta = ll_round((F32)mLabel->getFont()->getLineHeight() * mLabel->getLineSpacingMult()) - label_rect.getHeight(); + label_rect.translate(0, delta); + mLabel->setRect(label_rect); + } + // else + // WRAP_UP is essentially done by reshapeToFitText() (extends from bottom to top) + // howhever it doesn't respect rect of checkbox + // todo: this should be fixed, but there are at least couple checkboxes that use this feature as is. + } + + addChild(mLabel); // Button - // Note: button cover the label by extending all the way to the right. + // Note: button cover the label by extending all the way to the right and down. LLRect btn_rect = p.check_button.rect(); btn_rect.setOriginAndSize( btn_rect.mLeft, - btn_rect.mBottom, + llmin(btn_rect.mBottom, label_rect.mBottom), llmax(btn_rect.mRight, label_rect.mRight - btn_rect.mLeft), - llmax( label_rect.getHeight(), btn_rect.mTop)); + llmax(label_rect.getHeight(), btn_rect.mTop)); std::string active_true_id, active_false_id; std::string inactive_true_id, inactive_false_id; @@ -152,20 +187,53 @@ void LLCheckBoxCtrl::clear() void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) { - - mLabel->reshapeToFitText(); - - LLRect label_rect = mLabel->getRect(); + LLRect rect = getRect(); + S32 delta_width = width - rect.getWidth(); + S32 delta_height = height - rect.getHeight(); + + if (delta_width || delta_height) + { + // adjust our rectangle + rect.mRight = getRect().mLeft + width; + rect.mTop = getRect().mBottom + height; + setRect(rect); + } + + // reshapeToFitText reshapes label to minimal size according to last bounding box + // it will work fine in case of decrease of space, but if we get more space or text + // becomes longer, label will fail to grow so reinit label's dimentions. + + static LLUICachedControl<S32> llcheckboxctrl_hpad("UICheckboxctrlHPad", 0); + LLRect label_rect = mLabel->getRect(); + S32 new_width = getRect().getWidth() - label_rect.mLeft - llcheckboxctrl_hpad; + label_rect.mRight = label_rect.mLeft + new_width; + mLabel->setRect(label_rect); + + S32 label_top = label_rect.mTop; + mLabel->reshapeToFitText(TRUE); + + label_rect = mLabel->getRect(); + if (label_top != label_rect.mTop && mWordWrap == WRAP_DOWN) + { + // reshapeToFitText uses LLView::reshape() which always reshapes + // from bottom to top, but we want to extend the bottom so + // reposition control + S32 delta = label_top - label_rect.mTop; + label_rect.translate(0, delta); + mLabel->setRect(label_rect); + } // Button - // Note: button cover the label by extending all the way to the right. + // Note: button cover the label by extending all the way to the right and down. LLRect btn_rect = mButton->getRect(); btn_rect.setOriginAndSize( btn_rect.mLeft, - btn_rect.mBottom, + llmin(btn_rect.mBottom, label_rect.mBottom), llmax(btn_rect.getWidth(), label_rect.mRight - btn_rect.mLeft), llmax(label_rect.mTop - btn_rect.mBottom, btn_rect.getHeight())); mButton->setShape(btn_rect); + + updateBoundingRect(); } //virtual diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h index 07ae9c3b18..eb5bd5b6da 100644 --- a/indra/llui/llcheckboxctrl.h +++ b/indra/llui/llcheckboxctrl.h @@ -50,6 +50,19 @@ class LLCheckBoxCtrl , public ll::ui::SearchableControl { public: + + enum EWordWrap + { + WRAP_NONE, + WRAP_UP, + WRAP_DOWN + }; + + struct WordWrap : public LLInitParam::TypeValuesHelper<EWordWrap, WordWrap> + { + static void declareValues(); + }; + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> { @@ -58,6 +71,8 @@ public: Optional<LLTextBox::Params> label_text; Optional<LLButton::Params> check_button; + Optional<EWordWrap, WordWrap> word_wrap; + Ignored radio_style; Params(); @@ -129,6 +144,8 @@ protected: LLUIColor mTextEnabledColor; LLUIColor mTextDisabledColor; + + EWordWrap mWordWrap; // off, shifts text up, shifts text down }; // Build time optimization, generate once in .cpp file diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index b2ad38bddf..52dc908655 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -514,6 +514,14 @@ S32 LLComboBox::getCurrentIndex() const return -1; } +void LLComboBox::setEnabledByValue(const LLSD& value, BOOL enabled) +{ + LLScrollListItem *found = mList->getItem(value); + if (found) + { + found->setEnabled(enabled); + } +} void LLComboBox::createLineEditor(const LLComboBox::Params& p) { @@ -668,7 +676,7 @@ void LLComboBox::showList() mButton->setToggleState(TRUE); mList->setVisible(TRUE); - LLUI::addPopup(this); + LLUI::getInstance()->addPopup(this); setUseBoundingRect(TRUE); // updateBoundingRect(); @@ -694,7 +702,7 @@ void LLComboBox::hideList() mList->mouseOverHighlightNthItem(-1); setUseBoundingRect(FALSE); - LLUI::removePopup(this); + LLUI::getInstance()->removePopup(this); // updateBoundingRect(); } } diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index 7d38c051a5..4af3313162 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -158,6 +158,8 @@ public: BOOL setCurrentByIndex( S32 index ); S32 getCurrentIndex() const; + void setEnabledByValue(const LLSD& value, BOOL enabled); + void createLineEditor(const Params&); //======================================================================== diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp index 26ae31cac6..8fc2978bdd 100644 --- a/indra/llui/llconsole.cpp +++ b/indra/llui/llconsole.cpp @@ -68,7 +68,7 @@ LLConsole::LLConsole(const LLConsole::Params& p) setFontSize(p.font_size_index); } mFadeTime = mLinePersistTime - FADE_DURATION; - setMaxLines(LLUI::sSettingGroups["config"]->getS32("ConsoleMaxLines")); + setMaxLines(LLUI::getInstance()->mSettingGroups["config"]->getS32("ConsoleMaxLines")); } void LLConsole::setLinePersistTime(F32 seconds) @@ -180,7 +180,9 @@ void LLConsole::draw() LLUIImagePtr imagep = LLUI::getUIImage("transparent"); - F32 console_opacity = llclamp(LLUI::sSettingGroups["config"]->getF32("ConsoleBackgroundOpacity"), 0.f, 1.f); + static LLCachedControl<F32> console_bg_opacity(*LLUI::getInstance()->mSettingGroups["config"], "ConsoleBackgroundOpacity", 0.7f); + F32 console_opacity = llclamp(console_bg_opacity(), 0.f, 1.f); + LLColor4 color = LLUIColorTable::instance().getColor("ConsoleBackground"); color.mV[VALPHA] *= console_opacity; @@ -369,9 +371,9 @@ LLConsole::Paragraph::Paragraph (LLWString str, const LLColor4 &color, F32 add_t // static void LLConsole::updateClass() { - for (instance_iter it = beginInstances(); it != endInstances(); ++it) + for (auto& con : instance_snapshot()) { - it->update(); + con.update(); } } diff --git a/indra/llui/llconsole.h b/indra/llui/llconsole.h index 5ff05698b0..04f5e71609 100644 --- a/indra/llui/llconsole.h +++ b/indra/llui/llconsole.h @@ -51,7 +51,7 @@ public: Optional<F32> persist_time; Optional<S32> font_size_index; Params() - : max_lines("max_lines", LLUI::sSettingGroups["config"]->getS32("ConsoleMaxLines")), + : max_lines("max_lines", LLUI::getInstance()->mSettingGroups["config"]->getS32("ConsoleMaxLines")), persist_time("persist_time", 0.f), // forever font_size_index("font_size_index") { diff --git a/indra/llui/llflashtimer.cpp b/indra/llui/llflashtimer.cpp index 6d9c429b08..39793316f4 100644 --- a/indra/llui/llflashtimer.cpp +++ b/indra/llui/llflashtimer.cpp @@ -40,10 +40,10 @@ LLFlashTimer::LLFlashTimer(callback_t cb, S32 count, F32 period) // By default use settings from settings.xml to be able change them via Debug settings. See EXT-5973. // Due to Timer is implemented as derived class from EventTimer it is impossible to change period // in runtime. So, both settings are made as required restart. - mFlashCount = 2 * ((count > 0) ? count : LLUI::sSettingGroups["config"]->getS32("FlashCount")); + mFlashCount = 2 * ((count > 0) ? count : LLUI::getInstance()->mSettingGroups["config"]->getS32("FlashCount")); if (mPeriod <= 0) { - mPeriod = LLUI::sSettingGroups["config"]->getF32("FlashPeriod"); + mPeriod = LLUI::getInstance()->mSettingGroups["config"]->getF32("FlashPeriod"); } } diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index a245dd8f78..0e42922543 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -1,5 +1,4 @@ /** - * @file llfloater.cpp * @brief LLFloater base class * @@ -37,6 +36,7 @@ #include "lluictrlfactory.h" #include "llbutton.h" #include "llcheckboxctrl.h" +#include "llcriticaldamp.h" // LLSmoothInterpolation #include "lldir.h" #include "lldraghandle.h" #include "llfloaterreg.h" @@ -58,12 +58,17 @@ #include "llhelp.h" #include "llmultifloater.h" #include "llsdutil.h" +#include "lluiusage.h" #include <boost/foreach.hpp> // use this to control "jumping" behavior when Ctrl-Tabbing const S32 TABBED_FLOATER_OFFSET = 0; +const F32 LLFloater::CONTEXT_CONE_IN_ALPHA = 0.0f; +const F32 LLFloater::CONTEXT_CONE_OUT_ALPHA = 1.f; +const F32 LLFloater::CONTEXT_CONE_FADE_TIME = 0.08f; + namespace LLInitParam { void TypeValues<LLFloaterEnums::EOpenPositioning>::declareValues() @@ -194,7 +199,9 @@ LLFloater::Params::Params() help_pressed_image("help_pressed_image"), open_callback("open_callback"), close_callback("close_callback"), - follows("follows") + follows("follows"), + rel_x("rel_x", 0), + rel_y("rel_y", 0) { changeDefault(visible, false); } @@ -215,14 +222,14 @@ void LLFloater::initClass() sButtonToolTips[i] = LLTrans::getString( sButtonToolTipsIndex[i] ); } - LLControlVariable* ctrl = LLUI::sSettingGroups["config"]->getControl("ActiveFloaterTransparency").get(); + LLControlVariable* ctrl = LLUI::getInstance()->mSettingGroups["config"]->getControl("ActiveFloaterTransparency").get(); if (ctrl) { ctrl->getSignal()->connect(boost::bind(&LLFloater::updateActiveFloaterTransparency)); updateActiveFloaterTransparency(); } - ctrl = LLUI::sSettingGroups["config"]->getControl("InactiveFloaterTransparency").get(); + ctrl = LLUI::getInstance()->mSettingGroups["config"]->getControl("InactiveFloaterTransparency").get(); if (ctrl) { ctrl->getSignal()->connect(boost::bind(&LLFloater::updateInactiveFloaterTransparency)); @@ -263,6 +270,8 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p) mHasBeenDraggedWhileMinimized(FALSE), mPreviousMinimizedBottom(0), mPreviousMinimizedLeft(0), + mDefaultRelativeX(p.rel_x), + mDefaultRelativeY(p.rel_y), mMinimizeSignal(NULL) // mNotificationContext(NULL) { @@ -299,12 +308,10 @@ void LLFloater::initFloater(const Params& p) mButtonsEnabled[BUTTON_CLOSE] = TRUE; } - // Help button: '?' - if ( !mHelpTopic.empty() ) - { - mButtonsEnabled[BUTTON_HELP] = TRUE; - } - + // Help button: '?' + //SL-14050 Disable all Help question marks + mButtonsEnabled[BUTTON_HELP] = FALSE; + // Minimize button only for top draggers if ( !mDragOnLeft && mCanMinimize ) { @@ -374,13 +381,15 @@ void LLFloater::layoutDragHandle() // static void LLFloater::updateActiveFloaterTransparency() { - sActiveControlTransparency = LLUI::sSettingGroups["config"]->getF32("ActiveFloaterTransparency"); + static LLCachedControl<F32> active_transparency(*LLUI::getInstance()->mSettingGroups["config"], "ActiveFloaterTransparency", 1.f); + sActiveControlTransparency = active_transparency; } // static void LLFloater::updateInactiveFloaterTransparency() { - sInactiveControlTransparency = LLUI::sSettingGroups["config"]->getF32("InactiveFloaterTransparency"); + static LLCachedControl<F32> inactive_transparency(*LLUI::getInstance()->mSettingGroups["config"], "InactiveFloaterTransparency", 0.95f); + sInactiveControlTransparency = inactive_transparency; } void LLFloater::addResizeCtrls() @@ -503,7 +512,12 @@ void LLFloater::destroy() // virtual LLFloater::~LLFloater() { - LLFloaterReg::removeInstance(mInstanceName, mKey); + if (!isDead()) + { + // If it's dead, instance is supposed to be already removed, and + // in case of single instance we can remove new one by accident + LLFloaterReg::removeInstance(mInstanceName, mKey); + } if( gFocusMgr.childHasKeyboardFocus(this)) { @@ -579,7 +593,7 @@ std::string LLFloater::getControlName(const std::string& name, const LLSD& key) LLControlGroup* LLFloater::getControlGroup() { // Floater size, position, visibility, etc are saved in per-account settings. - return LLUI::sSettingGroups["account"]; + return LLUI::getInstance()->mSettingGroups["account"]; } void LLFloater::setVisible( BOOL visible ) @@ -592,7 +606,7 @@ void LLFloater::setVisible( BOOL visible ) if( !visible ) { - LLUI::removePopup(this); + LLUI::getInstance()->removePopup(this); if( gFocusMgr.childHasMouseCapture( this ) ) { @@ -818,7 +832,7 @@ void LLFloater::reshape(S32 width, S32 height, BOOL called_from_parent) void LLFloater::releaseFocus() { - LLUI::removePopup(this); + LLUI::getInstance()->removePopup(this); setFocus(FALSE); @@ -932,6 +946,15 @@ bool LLFloater::applyRectControl() saved_rect = true; } + else if ((mDefaultRelativeX != 0) && (mDefaultRelativeY != 0)) + { + mPosition.mX = mDefaultRelativeX; + mPosition.mY = mDefaultRelativeY; + mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; + applyRelativePosition(); + + saved_rect = true; + } // remember updated position if (rect_specified) @@ -1629,6 +1652,7 @@ void LLFloater::bringToFront( S32 x, S32 y ) // virtual void LLFloater::setVisibleAndFrontmost(BOOL take_focus,const LLSD& key) { + LLUIUsage::instance().logFloater(getInstanceName()); LLMultiFloater* hostp = getHost(); if (hostp) { @@ -1771,13 +1795,13 @@ void LLFloater::onClickDock(LLFloater* self) // static void LLFloater::onClickHelp( LLFloater* self ) { - if (self && LLUI::sHelpImpl) + if (self && LLUI::getInstance()->mHelpImpl) { // find the current help context for this floater std::string help_topic; if (self->findHelpTopic(help_topic)) { - LLUI::sHelpImpl->showTopic(help_topic); + LLUI::getInstance()->mHelpImpl->showTopic(help_topic); } } } @@ -2116,6 +2140,70 @@ void LLFloater::updateTitleButtons() } } +void LLFloater::drawConeToOwner(F32 &context_cone_opacity, + F32 max_cone_opacity, + LLView *owner_view, + F32 fade_time, + F32 contex_cone_in_alpha, + F32 contex_cone_out_alpha) +{ + if (owner_view + && owner_view->isInVisibleChain() + && hasFocus() + && context_cone_opacity > 0.001f + && gFocusMgr.childHasKeyboardFocus(this)) + { + // draw cone of context pointing back to owner (e.x. texture swatch) + LLRect owner_rect; + owner_view->localRectToOtherView(owner_view->getLocalRect(), &owner_rect, this); + LLRect local_rect = getLocalRect(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + LLGLEnable(GL_CULL_FACE); + gGL.begin(LLRender::QUADS); + { + gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); + gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); + gGL.vertex2i(owner_rect.mRight, owner_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); + gGL.vertex2i(local_rect.mRight, local_rect.mTop); + gGL.vertex2i(local_rect.mLeft, local_rect.mTop); + + gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mTop); + gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); + gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom); + gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); + + gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); + gGL.vertex2i(local_rect.mRight, local_rect.mBottom); + gGL.vertex2i(local_rect.mRight, local_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); + gGL.vertex2i(owner_rect.mRight, owner_rect.mTop); + gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom); + + + gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); + gGL.vertex2i(local_rect.mRight, local_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); + gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom); + gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom); + } + gGL.end(); + } + + if (gFocusMgr.childHasMouseCapture(getDragHandle())) + { + context_cone_opacity = lerp(context_cone_opacity, max_cone_opacity, LLSmoothInterpolation::getInterpolant(fade_time)); + } + else + { + context_cone_opacity = lerp(context_cone_opacity, 0.f, LLSmoothInterpolation::getInterpolant(fade_time)); + } +} + void LLFloater::buildButtons(const Params& floater_params) { static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0); @@ -2931,7 +3019,7 @@ void LLFloaterView::syncFloaterTabOrder() if (modal_dialog) { // If we have a visible modal dialog, make sure that it has focus - LLUI::addPopup(modal_dialog); + LLUI::getInstance()->addPopup(modal_dialog); if( !gFocusMgr.childHasKeyboardFocus( modal_dialog ) ) { @@ -3132,6 +3220,9 @@ void LLFloater::initFromParams(const LLFloater::Params& p) mSingleInstance = p.single_instance; mReuseInstance = p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance; + mDefaultRelativeX = p.rel_x; + mDefaultRelativeY = p.rel_y; + mPositioning = p.positioning; mSaveRect = p.save_rect; diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 165f67499b..2672d600c6 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -172,6 +172,9 @@ public: Optional<S32> header_height, legacy_header_height; // HACK see initFromXML() + Optional<F32> rel_x, + rel_y; + // Images for top-right controls Optional<LLUIImage*> close_image, restore_image, @@ -395,6 +398,15 @@ protected: virtual void updateTitleButtons(); + // Draws a cone from this floater to parent floater or view (owner) + // Modifies context_cone_opacity (interpolates according to fade time and returns new value) + void drawConeToOwner(F32 &context_cone_opacity, + F32 max_cone_opacity, + LLView *owner_view, + F32 context_fade_time = CONTEXT_CONE_FADE_TIME, + F32 contex_cone_in_alpha = CONTEXT_CONE_IN_ALPHA, + F32 contex_cone_out_alpha = CONTEXT_CONE_OUT_ALPHA); + private: void setForeground(BOOL b); // called only by floaterview void cleanupHandles(); // remove handles to dead floaters @@ -424,6 +436,10 @@ private: void updateTransparency(LLView* view, ETypeTransparency transparency_type); public: + static const F32 CONTEXT_CONE_IN_ALPHA; + static const F32 CONTEXT_CONE_OUT_ALPHA; + static const F32 CONTEXT_CONE_FADE_TIME; + // Called when floater is opened, passes mKey // Public so external views or floaters can watch for this floater opening commit_signal_t mOpenSignal; @@ -508,6 +524,9 @@ private: BOOL mHasBeenDraggedWhileMinimized; S32 mPreviousMinimizedBottom; S32 mPreviousMinimizedLeft; + + F32 mDefaultRelativeX; + F32 mDefaultRelativeY; }; diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index 9ef290abc0..36a0cb0fd0 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -32,6 +32,7 @@ #include "llfloater.h" #include "llmultifloater.h" #include "llfloaterreglistener.h" +#include "lluiusage.h" //******************************************************* @@ -57,6 +58,12 @@ void LLFloaterReg::add(const std::string& name, const std::string& filename, con } //static +bool LLFloaterReg::isRegistered(const std::string& name) +{ + return sBuildMap.find(name) != sBuildMap.end(); +} + +//static LLFloater* LLFloaterReg::getLastFloaterInGroup(const std::string& name) { const std::string& groupname = sGroupMap[name]; @@ -445,7 +452,7 @@ void LLFloaterReg::registerControlVariables() } } - const LLSD& exclude_list = LLUI::sSettingGroups["config"]->getLLSD("always_showable_floaters"); + const LLSD& exclude_list = LLUI::getInstance()->mSettingGroups["config"]->getLLSD("always_showable_floaters"); for (LLSD::array_const_iterator iter = exclude_list.beginArray(); iter != exclude_list.endArray(); iter++) @@ -472,7 +479,6 @@ void LLFloaterReg::toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& std::string name = sdname.asString(); LLFloater* instance = getInstance(name, key); - if (!instance) { LL_DEBUGS() << "Unable to get instance of floater '" << name << "'" << LL_ENDL; diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h index e3b17dcb4f..a457a15673 100644 --- a/indra/llui/llfloaterreg.h +++ b/indra/llui/llfloaterreg.h @@ -85,6 +85,7 @@ public: static void add(const std::string& name, const std::string& file, const LLFloaterBuildFunc& func, const std::string& groupname = LLStringUtil::null); + static bool isRegistered(const std::string& name); // Helpers static LLFloater* getLastFloaterInGroup(const std::string& name); diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp index 1b213c3418..7b0a6cbdae 100644 --- a/indra/llui/llfocusmgr.cpp +++ b/indra/llui/llfocusmgr.cpp @@ -183,7 +183,7 @@ void LLFocusMgr::releaseFocusIfNeeded( LLView* view ) } } - LLUI::removePopup(view); + LLUI::getInstance()->removePopup(view); } void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL keystrokes_only) @@ -481,7 +481,7 @@ void LLFocusMgr::setAppHasFocus(BOOL focus) // release focus from "top ctrl"s, which generally hides them if (!focus) { - LLUI::clearPopups(); + LLUI::getInstance()->clearPopups(); } mAppHasFocus = focus; } diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 895753aeae..622c9edba7 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -148,7 +148,9 @@ LLFolderView::Params::Params() : title("title"), use_label_suffix("use_label_suffix"), allow_multiselect("allow_multiselect", true), + allow_drag("allow_drag", true), show_empty_message("show_empty_message", true), + suppress_folder_menu("suppress_folder_menu", false), use_ellipses("use_ellipses", false), options_menu("options_menu", "") { @@ -162,11 +164,13 @@ LLFolderView::LLFolderView(const Params& p) mScrollContainer( NULL ), mPopupMenuHandle(), mAllowMultiSelect(p.allow_multiselect), + mAllowDrag(p.allow_drag), mShowEmptyMessage(p.show_empty_message), mShowFolderHierarchy(FALSE), mRenameItem( NULL ), mNeedsScroll( FALSE ), mUseLabelSuffix(p.use_label_suffix), + mSuppressFolderMenu(p.suppress_folder_menu), mPinningSelectedItem(FALSE), mNeedsAutoSelect( FALSE ), mAutoSelectOverride(FALSE), @@ -338,7 +342,9 @@ static LLTrace::BlockTimerStatHandle FTM_FILTER("Filter Folder View"); void LLFolderView::filter( LLFolderViewFilter& filter ) { LL_RECORD_BLOCK_TIME(FTM_FILTER); - filter.resetTime(llclamp(LLUI::sSettingGroups["config"]->getS32(mParentPanel.get()->getVisible() ? "FilterItemsMaxTimePerFrameVisible" : "FilterItemsMaxTimePerFrameUnvisible"), 1, 100)); + static LLCachedControl<S32> time_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10); + static LLCachedControl<S32> time_invisible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameUnvisible", 1); + filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? time_visible() : time_invisible()), 1, 100)); // Note: we filter the model, not the view getViewModelItem()->filter(filter); @@ -657,7 +663,8 @@ void LLFolderView::draw() closeAutoOpenedFolders(); } - if (mSearchTimer.getElapsedTimeF32() > LLUI::sSettingGroups["config"]->getF32("TypeAheadTimeout") || !mSearchString.size()) + static LLCachedControl<F32> type_ahead_timeout(*LLUI::getInstance()->mSettingGroups["config"], "TypeAheadTimeout", 1.5f); + if (mSearchTimer.getElapsedTimeF32() > type_ahead_timeout || !mSearchString.size()) { mSearchString.clear(); } @@ -733,7 +740,7 @@ void LLFolderView::closeRenamer( void ) if (mRenamer && mRenamer->getVisible()) { // Triggers onRenamerLost() that actually closes the renamer. - LLUI::removePopup(mRenamer); + LLUI::getInstance()->removePopup(mRenamer); } } @@ -1064,7 +1071,7 @@ void LLFolderView::startRenamingSelectedItem( void ) // set focus will fail unless item is visible mRenamer->setFocus( TRUE ); mRenamer->setTopLostCallback(boost::bind(&LLFolderView::onRenamerLost, this)); - LLUI::addPopup(mRenamer); + LLUI::getInstance()->addPopup(mRenamer); } } @@ -1321,7 +1328,7 @@ BOOL LLFolderView::handleUnicodeCharHere(llwchar uni_char) } //do text search - if (mSearchTimer.getElapsedTimeF32() > LLUI::sSettingGroups["config"]->getF32("TypeAheadTimeout")) + if (mSearchTimer.getElapsedTimeF32() > LLUI::getInstance()->mSettingGroups["config"]->getF32("TypeAheadTimeout")) { mSearchString.clear(); } @@ -1432,10 +1439,13 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask ) BOOL handled = childrenHandleRightMouseDown(x, y, mask) != NULL; S32 count = mSelectedItems.size(); + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); - if ( handled + bool hide_folder_menu = mSuppressFolderMenu && isFolderSelected(); + if ((handled && ( count > 0 && (hasVisibleChildren()) ) // show menu only if selected items are visible - && menu ) + && menu ) && + !hide_folder_menu) { if (mCallbackRegistrar) { @@ -1449,7 +1459,7 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask ) if (mCallbackRegistrar) { mCallbackRegistrar->popScope(); - } + } } else { @@ -1803,7 +1813,7 @@ void LLFolderView::updateRenamerPosition() screenPointToLocal( x, y, &x, &y ); mRenamer->setOrigin( x, y ); - LLRect scroller_rect(0, 0, (S32)LLUI::getWindowSize().mV[VX], 0); + LLRect scroller_rect(0, 0, (S32)LLUI::getInstance()->getWindowSize().mV[VX], 0); if (mScrollContainer) { scroller_rect = mScrollContainer->getContentWindowRect(); @@ -1862,6 +1872,20 @@ void LLFolderView::updateMenu() } } +bool LLFolderView::isFolderSelected() +{ + selected_items_t::iterator item_iter; + for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter) + { + LLFolderViewFolder* folder = dynamic_cast<LLFolderViewFolder*>(*item_iter); + if (folder != NULL) + { + return true; + } + } + return false; +} + bool LLFolderView::selectFirstItem() { for (folders_t::iterator iter = mFolders.begin(); diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 2926e160d0..6bb5e6c02e 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -90,9 +90,11 @@ public: Optional<std::string> title; Optional<bool> use_label_suffix, allow_multiselect, + allow_drag, show_empty_message, use_ellipses, - show_item_link_overlays; + show_item_link_overlays, + suppress_folder_menu; Mandatory<LLFolderViewModelInterface*> view_model; Optional<LLFolderViewGroupedItemModel*> grouped_item_model; Mandatory<std::string> options_menu; @@ -123,6 +125,7 @@ public: void setReshapeCallback(const signal_t::slot_type& cb) { mReshapeSignal.connect(cb); } bool getAllowMultiSelect() { return mAllowMultiSelect; } + bool getAllowDrag() { return mAllowDrag; } // Close all folders in the view void closeAllFolders(); @@ -259,6 +262,8 @@ protected: void closeRenamer( void ); + bool isFolderSelected(); + bool selectFirstItem(); bool selectLastItem(); @@ -271,6 +276,7 @@ protected: selected_items_t mSelectedItems; bool mKeyboardSelection, mAllowMultiSelect, + mAllowDrag, mShowEmptyMessage, mShowFolderHierarchy, mNeedsScroll, @@ -282,7 +288,8 @@ protected: mDragAndDropThisFrame, mShowItemLinkOverlays, mShowSelectionContext, - mShowSingleSelection; + mShowSingleSelection, + mSuppressFolderMenu; // Renaming variables and methods LLFolderViewItem* mRenameItem; // The item currently being renamed diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 0c1c3c40ec..835d3b781d 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -122,6 +122,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) : LLView(p), mLabelWidth(0), mLabelWidthDirty(false), + mSuffixNeedsRefresh(false), mLabelPaddingRight(DEFAULT_LABEL_PADDING_RIGHT), mParentFolder( NULL ), mIsSelected( FALSE ), @@ -181,11 +182,25 @@ LLFolderViewItem::~LLFolderViewItem() BOOL LLFolderViewItem::postBuild() { - refresh(); + LLFolderViewModelItem& vmi = *getViewModelItem(); + // getDisplayName() is expensive (due to internal getLabelSuffix() and name building) + // it also sets search strings so it requires a filter reset + mLabel = vmi.getDisplayName(); + setToolTip(vmi.getName()); + + // Dirty the filter flag of the model from the view (CHUI-849) + vmi.dirtyFilter(); + + // Don't do full refresh on constructor if it is possible to avoid + // it significantly slows down bulk view creation. + // Todo: Ideally we need to move getDisplayName() out of constructor as well. + // Like: make a logic that will let filter update search string, + // while LLFolderViewItem::arrange() updates visual part + mSuffixNeedsRefresh = true; + mLabelWidthDirty = true; return TRUE; } - LLFolderView* LLFolderViewItem::getRoot() { return mRoot; @@ -280,24 +295,51 @@ BOOL LLFolderViewItem::isPotentiallyVisible(S32 filter_generation) void LLFolderViewItem::refresh() { - LLFolderViewModelItem& vmi = *getViewModelItem(); + LLFolderViewModelItem& vmi = *getViewModelItem(); - mLabel = vmi.getDisplayName(); + mLabel = vmi.getDisplayName(); + setToolTip(vmi.getName()); + // icons are slightly expensive to get, can be optimized + // see LLInventoryIcon::getIcon() + mIcon = vmi.getIcon(); + mIconOpen = vmi.getIconOpen(); + mIconOverlay = vmi.getIconOverlay(); - setToolTip(vmi.getName()); - mIcon = vmi.getIcon(); - mIconOpen = vmi.getIconOpen(); - mIconOverlay = vmi.getIconOverlay(); + if (mRoot->useLabelSuffix()) + { + // Very Expensive! + // Can do a number of expensive checks, like checking active motions, wearables or friend list + mLabelStyle = vmi.getLabelStyle(); + mLabelSuffix = vmi.getLabelSuffix(); + } + + // Dirty the filter flag of the model from the view (CHUI-849) + vmi.dirtyFilter(); + + mLabelWidthDirty = true; + mSuffixNeedsRefresh = false; +} + +void LLFolderViewItem::refreshSuffix() +{ + LLFolderViewModelItem const* vmi = getViewModelItem(); + + // icons are slightly expensive to get, can be optimized + // see LLInventoryIcon::getIcon() + mIcon = vmi->getIcon(); + mIconOpen = vmi->getIconOpen(); + mIconOverlay = vmi->getIconOverlay(); if (mRoot->useLabelSuffix()) { - mLabelStyle = vmi.getLabelStyle(); - mLabelSuffix = vmi.getLabelSuffix(); + // Very Expensive! + // Can do a number of expensive checks, like checking active motions, wearables or friend list + mLabelStyle = vmi->getLabelStyle(); + mLabelSuffix = vmi->getLabelSuffix(); } - mLabelWidthDirty = true; - // Dirty the filter flag of the model from the view (CHUI-849) - vmi.dirtyFilter(); + mLabelWidthDirty = true; + mSuffixNeedsRefresh = false; } // Utility function for LLFolderView @@ -348,6 +390,12 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height ) : 0; if (mLabelWidthDirty) { + if (mSuffixNeedsRefresh) + { + // Expensive. But despite refreshing label, + // it is purely visual, so it is fine to do at our laisure + refreshSuffix(); + } mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(mLabelStyle)->getWidth(mLabelSuffix) + mLabelPaddingRight; mLabelWidthDirty = false; } @@ -548,7 +596,7 @@ BOOL LLFolderViewItem::handleMouseDown( S32 x, S32 y, MASK mask ) BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask ) { - static LLCachedControl<S32> drag_and_drop_threshold(*LLUI::sSettingGroups["config"],"DragAndDropDistanceThreshold", 3); + static LLCachedControl<S32> drag_and_drop_threshold(*LLUI::getInstance()->mSettingGroups["config"],"DragAndDropDistanceThreshold", 3); mIsMouseOverTitle = (y > (getRect().getHeight() - mItemHeight)); @@ -557,6 +605,7 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask ) LLFolderView* root = getRoot(); if( (x - mDragStartX) * (x - mDragStartX) + (y - mDragStartY) * (y - mDragStartY) > drag_and_drop_threshold() * drag_and_drop_threshold() + && root->getAllowDrag() && root->getCurSelectedItem() && root->startDrag()) { @@ -913,9 +962,10 @@ void LLFolderViewItem::draw() // if (filter_string_length > 0) { - F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, mViewModelItem->getFilterStringOffset()); + S32 filter_offset = mViewModelItem->getFilterStringOffset(); + F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string, filter_offset, filter_string_length); F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; - font->renderUTF8( combined_string, mViewModelItem->getFilterStringOffset(), match_string_left, yy, + font->renderUTF8( combined_string, filter_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, filter_string_length, S32_MAX, &right_x, /*use_ellipses*/FALSE, /*use_color*/FALSE ); } @@ -1558,7 +1608,7 @@ void LLFolderViewFolder::destroyView() // extractItem() removes the specified item from the folder, but // doesn't delete it. -void LLFolderViewFolder::extractItem( LLFolderViewItem* item ) +void LLFolderViewFolder::extractItem( LLFolderViewItem* item, bool deparent_model ) { if (item->isSelected()) getRoot()->clearSelection(); @@ -1581,7 +1631,11 @@ void LLFolderViewFolder::extractItem( LLFolderViewItem* item ) mItems.erase(it); } //item has been removed, need to update filter - getViewModelItem()->removeChild(item->getViewModelItem()); + if (deparent_model) + { + // in some cases model does not belong to parent view, is shared between views + getViewModelItem()->removeChild(item->getViewModelItem()); + } //because an item is going away regardless of filter status, force rearrange requestArrange(); removeChild(item); diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index 61c39e0175..616d2e7d86 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -95,6 +95,7 @@ protected: LLPointer<LLFolderViewModelItem> mViewModelItem; LLFontGL::StyleFlags mLabelStyle; std::string mLabelSuffix; + bool mSuffixNeedsRefresh; //suffix and icons LLUIImagePtr mIcon, mIconOpen, mIconOverlay; @@ -266,8 +267,13 @@ public: virtual BOOL passedFilter(S32 filter_generation = -1); virtual BOOL isPotentiallyVisible(S32 filter_generation = -1); - // refresh information from the object being viewed. - virtual void refresh(); + // refresh information from the object being viewed. + // refreshes label, suffixes and sets icons. Expensive! + // Causes filter update + virtual void refresh(); + // refreshes suffixes and sets icons. Expensive! + // Does not need filter update + virtual void refreshSuffix(); // LLView functionality virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); @@ -381,7 +387,7 @@ public: // extractItem() removes the specified item from the folder, but // doesn't delete it. - virtual void extractItem( LLFolderViewItem* item ); + virtual void extractItem( LLFolderViewItem* item, bool deparent_model = true); // This function is called by a child that needs to be resorted. void resort(LLFolderViewItem* item); diff --git a/indra/llui/llfolderviewmodel.cpp b/indra/llui/llfolderviewmodel.cpp index 3363dc5316..93122503d1 100644 --- a/indra/llui/llfolderviewmodel.cpp +++ b/indra/llui/llfolderviewmodel.cpp @@ -48,8 +48,9 @@ std::string LLFolderViewModelCommon::getStatusText() void LLFolderViewModelCommon::filter() { - getFilter().resetTime(llclamp(LLUI::sSettingGroups["config"]->getS32("FilterItemsMaxTimePerFrameVisible"), 1, 100)); - mFolderView->getViewModelItem()->filter(getFilter()); + static LLCachedControl<S32> max_time(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10); + getFilter().resetTime(llclamp(max_time(), 1, 100)); + mFolderView->getViewModelItem()->filter(getFilter()); } bool LLFolderViewModelItemCommon::hasFilterStringMatch() diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index f71a88c56e..e62b2779dd 100644 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -204,6 +204,7 @@ public: virtual bool hasChildren() const = 0; virtual void addChild(LLFolderViewModelItem* child) = 0; virtual void removeChild(LLFolderViewModelItem* child) = 0; + virtual void clearChildren() = 0; // This method will be called to determine if a drop can be // performed, and will set drop to TRUE if a drop is @@ -286,16 +287,6 @@ public: virtual void addChild(LLFolderViewModelItem* child) { - // Avoid duplicates: bail out if that child is already present in the list - // Note: this happens when models are created before views - child_list_t::const_iterator iter; - for (iter = mChildren.begin(); iter != mChildren.end(); iter++) - { - if (child == *iter) - { - return; - } - } mChildren.push_back(child); child->setParent(this); dirtyFilter(); @@ -311,9 +302,8 @@ public: virtual void clearChildren() { - // As this is cleaning the whole list of children wholesale, we do need to delete the pointed objects - // This is different and not equivalent to calling removeChild() on each child - std::for_each(mChildren.begin(), mChildren.end(), DeletePointer()); + // We are working with models that belong to views as LLPointers, clean the list, let poiters handle the rest + std::for_each(mChildren.begin(), mChildren.end(), [](LLFolderViewModelItem* c) {c->setParent(NULL); }); mChildren.clear(); dirtyDescendantsFilter(); dirtyFilter(); diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 955e7089f4..29a156e933 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -166,7 +166,7 @@ void LLLayoutPanel::setVisible( BOOL visible ) void LLLayoutPanel::reshape( S32 width, S32 height, BOOL called_from_parent /*= TRUE*/ ) { - if (width == getRect().getWidth() && height == getRect().getHeight()) return; + if (width == getRect().getWidth() && height == getRect().getHeight() && !LLView::sForceReshape) return; if (!mIgnoreReshape && mAutoResize == false) { @@ -209,7 +209,7 @@ LLLayoutStack::Params::Params() open_time_constant("open_time_constant", 0.02f), close_time_constant("close_time_constant", 0.03f), resize_bar_overlap("resize_bar_overlap", 1), - border_size("border_size", LLCachedControl<S32>(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0)), + border_size("border_size", LLCachedControl<S32>(*LLUI::getInstance()->mSettingGroups["config"], "UIResizeBarHeight", 0)), show_drag_handle("show_drag_handle", false), drag_handle_first_indent("drag_handle_first_indent", 0), drag_handle_second_indent("drag_handle_second_indent", 0), @@ -636,10 +636,10 @@ void LLLayoutStack::createResizeBar(LLLayoutPanel* panelp) //static void LLLayoutStack::updateClass() { - for (instance_iter it = beginInstances(); it != endInstances(); ++it) + for (auto& layout : instance_snapshot()) { - it->updateLayout(); - it->mAnimatedThisFrame = false; + layout.updateLayout(); + layout.mAnimatedThisFrame = false; } } diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index ff8bf30319..1badd54fca 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -96,6 +96,8 @@ LLLineEditor::Params::Params() ignore_tab("ignore_tab", true), is_password("is_password", false), cursor_color("cursor_color"), + use_bg_color("use_bg_color", false), + bg_color("bg_color"), text_color("text_color"), text_readonly_color("text_readonly_color"), text_tentative_color("text_tentative_color"), @@ -150,10 +152,12 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) mBgImageDisabled( p.background_image_disabled ), mBgImageFocused( p.background_image_focused ), mShowImageFocused( p.bg_image_always_focused ), + mUseBgColor(p.use_bg_color), mHaveHistory(FALSE), mReplaceNewlinesWithSpaces( TRUE ), mLabel(p.label), mCursorColor(p.cursor_color()), + mBgColor(p.bg_color()), mFgColor(p.text_color()), mReadOnlyFgColor(p.text_readonly_color()), mTentativeFgColor(p.text_tentative_color()), @@ -941,7 +945,7 @@ void LLLineEditor::removeChar() } else { - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } } @@ -992,7 +996,7 @@ void LLLineEditor::addChar(const llwchar uni_char) } else { - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } getWindow()->hideCursorUntilMouseMove(); @@ -1088,7 +1092,7 @@ BOOL LLLineEditor::handleSelectionKey(KEY key, MASK mask) } else { - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } break; @@ -1104,7 +1108,7 @@ BOOL LLLineEditor::handleSelectionKey(KEY key, MASK mask) } else { - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } break; @@ -1184,7 +1188,7 @@ void LLLineEditor::cut() if( need_to_rollback ) { rollback.doRollback( this ); - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } else { @@ -1288,7 +1292,7 @@ void LLLineEditor::pasteHelper(bool is_primary) } // Truncate the clean string at the limit of what will fit clean_string = clean_string.substr(0, wchars_that_fit); - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } if (mMaxLengthChars) @@ -1300,7 +1304,7 @@ void LLLineEditor::pasteHelper(bool is_primary) clean_string = clean_string.substr(0, available_chars); } - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } mText.insert(getCursor(), clean_string); @@ -1312,7 +1316,7 @@ void LLLineEditor::pasteHelper(bool is_primary) if( need_to_rollback ) { rollback.doRollback( this ); - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } else { @@ -1376,7 +1380,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) } else { - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } } handled = TRUE; @@ -1425,7 +1429,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) } else { - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } handled = TRUE; } @@ -1452,7 +1456,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) } else { - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } handled = TRUE; } @@ -1469,7 +1473,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) } else { - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } handled = TRUE; } @@ -1486,7 +1490,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) } else { - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } handled = TRUE; } @@ -1567,7 +1571,7 @@ BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask ) { rollback.doRollback(this); - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } // Notify owner if requested @@ -1623,7 +1627,7 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char) { rollback.doRollback( this ); - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } // Notify owner if requested @@ -1674,7 +1678,7 @@ void LLLineEditor::doDelete() if( need_to_rollback ) { rollback.doRollback( this ); - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } else { @@ -1688,37 +1692,42 @@ void LLLineEditor::doDelete() void LLLineEditor::drawBackground() { - bool has_focus = hasFocus(); - LLUIImage* image; - if ( mReadOnly ) - { - image = mBgImageDisabled; - } - else if ( has_focus || mShowImageFocused) + F32 alpha = getCurrentTransparency(); + if (mUseBgColor) { - image = mBgImageFocused; + gl_rect_2d(getLocalRect(), mBgColor % alpha, TRUE); } else { - image = mBgImage; - } - - if (!image) return; - - F32 alpha = getCurrentTransparency(); + bool has_focus = hasFocus(); + LLUIImage* image; + if (mReadOnly) + { + image = mBgImageDisabled; + } + else if (has_focus || mShowImageFocused) + { + image = mBgImageFocused; + } + else + { + image = mBgImage; + } - // optionally draw programmatic border - if (has_focus) - { - LLColor4 tmp_color = gFocusMgr.getFocusColor(); + if (!image) return; + // optionally draw programmatic border + if (has_focus) + { + LLColor4 tmp_color = gFocusMgr.getFocusColor(); + tmp_color.setAlpha(alpha); + image->drawBorder(0, 0, getRect().getWidth(), getRect().getHeight(), + tmp_color, + gFocusMgr.getFocusFlashWidth()); + } + LLColor4 tmp_color = UI_VERTEX_COLOR; tmp_color.setAlpha(alpha); - image->drawBorder(0, 0, getRect().getWidth(), getRect().getHeight(), - tmp_color, - gFocusMgr.getFocusFlashWidth()); + image->draw(getLocalRect(), tmp_color); } - LLColor4 tmp_color = UI_VERTEX_COLOR; - tmp_color.setAlpha(alpha); - image->draw(getLocalRect(), tmp_color); } void LLLineEditor::draw() @@ -2142,6 +2151,7 @@ void LLLineEditor::clear() void LLLineEditor::onTabInto() { selectAll(); + LLUICtrl::onTabInto(); } //virtual @@ -2478,7 +2488,7 @@ BOOL LLLineEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect { LLRect control_rect_screen; localRectToScreen(getRect(), &control_rect_screen); - LLUI::screenRectToGL(control_rect_screen, control); + LLUI::getInstance()->screenRectToGL(control_rect_screen, control); } S32 preedit_left_column, preedit_right_column; @@ -2508,7 +2518,7 @@ BOOL LLLineEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect S32 query_local = findPixelNearestPos(query - getCursor()); S32 query_screen_x, query_screen_y; localPointToScreen(query_local, getRect().getHeight() / 2, &query_screen_x, &query_screen_y); - LLUI::screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); + LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); } if (bounds) @@ -2524,7 +2534,7 @@ BOOL LLLineEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect LLRect preedit_rect_local(preedit_left_local, getRect().getHeight(), preedit_right_local, 0); LLRect preedit_rect_screen; localRectToScreen(preedit_rect_local, &preedit_rect_screen); - LLUI::screenRectToGL(preedit_rect_screen, bounds); + LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds); } return TRUE; diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index f775d53e63..f84625bea7 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -91,10 +91,12 @@ public: commit_on_focus_lost, ignore_tab, bg_image_always_focused, - is_password; + is_password, + use_bg_color; // colors Optional<LLUIColor> cursor_color, + bg_color, text_color, text_readonly_color, text_tentative_color, @@ -281,6 +283,9 @@ public: void resetContextMenu() { setContextMenu(NULL); }; + void setBgImage(LLPointer<LLUIImage> image) { mBgImage = image; } + void setBgImageFocused(LLPointer<LLUIImage> image) { mBgImageFocused = image; } + private: // private helper methods @@ -368,6 +373,7 @@ protected: LLTimer mTripleClickTimer; LLUIColor mCursorColor; + LLUIColor mBgColor; LLUIColor mFgColor; LLUIColor mReadOnlyFgColor; LLUIColor mTentativeFgColor; @@ -388,6 +394,8 @@ protected: BOOL mShowImageFocused; + bool mUseBgColor; + LLWString mPreeditWString; LLWString mPreeditOverwrittenWString; std::vector<S32> mPreeditPositions; diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 92543b952e..cdaf03ebde 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -79,7 +79,7 @@ const U32 LEFT_PAD_PIXELS = 3; const U32 LEFT_WIDTH_PIXELS = 15; const U32 LEFT_PLAIN_PIXELS = LEFT_PAD_PIXELS + LEFT_WIDTH_PIXELS; -const U32 RIGHT_PAD_PIXELS = 2; +const U32 RIGHT_PAD_PIXELS = 7; const U32 RIGHT_WIDTH_PIXELS = 15; const U32 RIGHT_PLAIN_PIXELS = RIGHT_PAD_PIXELS + RIGHT_WIDTH_PIXELS; @@ -95,7 +95,7 @@ const std::string SEPARATOR_NAME("separator"); const std::string VERTICAL_SEPARATOR_LABEL( "|" ); const std::string LLMenuGL::BOOLEAN_TRUE_PREFIX( "\xE2\x9C\x94" ); // U+2714 HEAVY CHECK MARK -const std::string LLMenuGL::BRANCH_SUFFIX( "\xE2\x96\xB6" ); // U+25B6 BLACK RIGHT-POINTING TRIANGLE +const std::string LLMenuGL::BRANCH_SUFFIX( "\xe2\x96\xb8" ); // U+25B6 BLACK RIGHT-POINTING TRIANGLE const std::string LLMenuGL::ARROW_UP ("^^^^^^^"); const std::string LLMenuGL::ARROW_DOWN("vvvvvvv"); @@ -213,6 +213,12 @@ LLSD LLMenuItemGL::getValue() const } //virtual +bool LLMenuItemGL::hasAccelerator(const KEY &key, const MASK &mask) const +{ + return (mAcceleratorKey == key) && (mAcceleratorMask == mask); +} + +//virtual BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask) { if( getEnabled() && (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) ) @@ -263,13 +269,13 @@ BOOL LLMenuItemGL::handleRightMouseUp(S32 x, S32 y, MASK mask) // This function checks to see if the accelerator key is already in use; // if not, it will be added to the list -BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLKeyBinding*> *listp) +BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp) { - LLKeyBinding *accelerator = NULL; + LLMenuKeyboardBinding *accelerator = NULL; if (mAcceleratorKey != KEY_NONE) { - std::list<LLKeyBinding*>::iterator list_it; + std::list<LLMenuKeyboardBinding*>::iterator list_it; for (list_it = listp->begin(); list_it != listp->end(); ++list_it) { accelerator = *list_it; @@ -293,7 +299,7 @@ BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLKeyBinding*> *listp) } if (!accelerator) { - accelerator = new LLKeyBinding; + accelerator = new LLMenuKeyboardBinding; if (accelerator) { accelerator->mKey = mAcceleratorKey; @@ -788,6 +794,12 @@ void LLMenuItemCallGL::initFromParams(const Params& p) { setEnabledControlVariable(control); } + else + { + LL_WARNS() << "Failed to assign 'enabled' control variable to menu " << getName() + << ": control " << p.on_enable.control_name() + << " does not exist." << LL_ENDL; + } } } if (p.on_click.isProvided()) @@ -1011,6 +1023,11 @@ BOOL LLMenuItemBranchGL::handleMouseUp(S32 x, S32 y, MASK mask) return TRUE; } +bool LLMenuItemBranchGL::hasAccelerator(const KEY &key, const MASK &mask) const +{ + return getBranch() && getBranch()->hasAccelerator(key, mask); +} + BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask) { return getBranch() && getBranch()->handleAcceleratorKey(key, mask); @@ -1018,7 +1035,7 @@ BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask) // This function checks to see if the accelerator key is already in use; // if not, it will be added to the list -BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list<LLKeyBinding*> *listp) +BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp) { LLMenuGL* branch = getBranch(); if (!branch) @@ -2717,6 +2734,15 @@ void LLMenuGL::setItemVisible( const std::string& name, BOOL visible ) } } + +void LLMenuGL::setItemLabel(const std::string &name, const std::string &label) +{ + LLMenuItemGL *item = getItem(name); + + if (item) + item->setLabel(label); +} + void LLMenuGL::setItemLastSelected(LLMenuItemGL* item) { if (getVisible()) @@ -2761,6 +2787,19 @@ LLMenuItemGL* LLMenuGL::getItem(S32 number) return NULL; } +LLMenuItemGL* LLMenuGL::getItem(std::string name) +{ + item_list_t::iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + if ((*item_iter)->getName() == name) + { + return (*item_iter); + } + } + return NULL; +} + LLMenuItemGL* LLMenuGL::getHighlightedItem() { item_list_t::iterator item_iter; @@ -2995,6 +3034,27 @@ void LLMenuGL::updateParent(LLView* parentp) } } +bool LLMenuGL::hasAccelerator(const KEY &key, const MASK &mask) const +{ + if (key == KEY_NONE) + { + return false; + } + // Note: checking this way because mAccelerators seems to be broken + // mAccelerators probably needs to be cleaned up or fixed + // It was used for dupplicate accelerator avoidance. + item_list_t::const_iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + LLMenuItemGL* itemp = *item_iter; + if (itemp->hasAccelerator(key, mask)) + { + return true; + } + } + return false; +} + BOOL LLMenuGL::handleAcceleratorKey(KEY key, MASK mask) { // don't handle if not enabled @@ -3216,7 +3276,7 @@ void hide_top_view( LLView* view ) // x and y are the desired location for the popup, in the spawning_view's // coordinate frame, NOT necessarily the mouse location // static -void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y) +void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x, S32 mouse_y) { const S32 CURSOR_HEIGHT = 22; // Approximate "normal" cursor size const S32 CURSOR_WIDTH = 12; @@ -3247,12 +3307,6 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y) } } - // 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 LLContextMenu::show() - S32 mouse_x, mouse_y; - // Resetting scrolling position if (menu->isScrollable() && menu->isScrollPositionOnShowReset()) { @@ -3263,7 +3317,18 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y) menu->needsArrange(); menu->arrangeAndClear(); - LLUI::getMousePositionLocal(menu->getParent(), &mouse_x, &mouse_y); + if ((mouse_x == 0) || (mouse_y == 0)) + + { + // 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 LLContextMenu::show() + + LLUI::getInstance()->getMousePositionLocal(menu->getParent(), &mouse_x, &mouse_y); + } + + LLMenuHolderGL::sContextMenuSpawnPos.set(mouse_x,mouse_y); const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getRect(); diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 78f688642e..273bd789c4 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -42,6 +42,13 @@ extern S32 MENU_BAR_HEIGHT; extern S32 MENU_BAR_WIDTH; +class LLMenuKeyboardBinding +{ +public: + KEY mKey; + MASK mMask; +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLMenuItemGL // @@ -91,6 +98,7 @@ public: /*virtual*/ void setValue(const LLSD& value); /*virtual*/ LLSD getValue() const; + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; virtual BOOL handleAcceleratorKey(KEY key, MASK mask); LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); } @@ -109,7 +117,7 @@ public: virtual void setBriefItem(BOOL brief); virtual BOOL isBriefItem() const; - virtual BOOL addToAcceleratorList(std::list<LLKeyBinding*> *listp); + virtual BOOL addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp); void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; } BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; } @@ -436,7 +444,8 @@ public: /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); /*virtual*/ void removeChild( LLView* ctrl); /*virtual*/ BOOL postBuild(); - + + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; virtual BOOL handleAcceleratorKey(KEY key, MASK mask); LLMenuGL* findChildMenuByName(const std::string& name, BOOL recurse) const; @@ -468,6 +477,8 @@ public: void setEnabledSubMenus(BOOL enable); void setItemVisible( const std::string& name, BOOL visible); + + void setItemLabel(const std::string &name, const std::string &label); // sets the left,bottom corner of menu, useful for popups void setLeftAndBottom(S32 left, S32 bottom); @@ -498,6 +509,7 @@ public: void setItemLastSelected(LLMenuItemGL* item); // must be in menu U32 getItemCount(); // number of menu items LLMenuItemGL* getItem(S32 number); // 0 = first item + LLMenuItemGL* getItem(std::string name); LLMenuItemGL* getHighlightedItem(); LLMenuItemGL* highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); @@ -507,7 +519,7 @@ public: void createJumpKeys(); // 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); + static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x = 0, S32 mouse_y = 0); // Whether to drop shadow menu bar void setDropShadowed( const BOOL shadowed ); @@ -625,10 +637,11 @@ public: virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; virtual BOOL handleAcceleratorKey(KEY key, MASK mask); // check if we've used these accelerators already - virtual BOOL addToAcceleratorList(std::list <LLKeyBinding*> *listp); + virtual BOOL addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp); // called to rebuild the draw label virtual void buildDrawLabel( void ); @@ -794,7 +807,7 @@ private: void checkMenuTrigger(); - std::list <LLKeyBinding*> mAccelerators; + std::list <LLMenuKeyboardBinding*> mAccelerators; BOOL mAltKeyTrigger; }; diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp index 8cf88ad5eb..5cfa8ea973 100644 --- a/indra/llui/llmodaldialog.cpp +++ b/indra/llui/llmodaldialog.cpp @@ -105,7 +105,7 @@ void LLModalDialog::onOpen(const LLSD& key) // This is a modal dialog. It sucks up all mouse and keyboard operations. gFocusMgr.setMouseCapture( this ); - LLUI::addPopup(this); + LLUI::getInstance()->addPopup(this); setFocus(TRUE); sModalStack.push_front( this ); @@ -147,7 +147,7 @@ void LLModalDialog::setVisible( BOOL visible ) gFocusMgr.setMouseCapture( this ); // The dialog view is a root view - LLUI::addPopup(this); + LLUI::getInstance()->addPopup(this); setFocus( TRUE ); } else @@ -165,7 +165,7 @@ BOOL LLModalDialog::handleMouseDown(S32 x, S32 y, MASK mask) if (popup_menu != NULL) { S32 mx, my; - LLUI::getMousePositionScreen(&mx, &my); + LLUI::getInstance()->getMousePositionScreen(&mx, &my); LLRect menu_screen_rc = popup_menu->calcScreenRect(); if(!menu_screen_rc.pointInRect(mx, my)) { @@ -202,7 +202,7 @@ BOOL LLModalDialog::handleHover(S32 x, S32 y, MASK mask) if (popup_menu != NULL) { S32 mx, my; - LLUI::getMousePositionScreen(&mx, &my); + LLUI::getInstance()->getMousePositionScreen(&mx, &my); LLRect menu_screen_rc = popup_menu->calcScreenRect(); if(menu_screen_rc.pointInRect(mx, my)) { @@ -286,7 +286,7 @@ void LLModalDialog::draw() void LLModalDialog::centerOnScreen() { - LLVector2 window_size = LLUI::getWindowSize(); + LLVector2 window_size = LLUI::getInstance()->getWindowSize(); centerWithin(LLRect(0, 0, ll_round(window_size.mV[VX]), ll_round(window_size.mV[VY]))); } @@ -316,7 +316,7 @@ void LLModalDialog::onAppFocusGained() // This is a modal dialog. It sucks up all mouse and keyboard operations. gFocusMgr.setMouseCapture( instance ); instance->setFocus(TRUE); - LLUI::addPopup(instance); + LLUI::getInstance()->addPopup(instance); instance->centerOnScreen(); } diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp index 0aa3e17075..f89064d59a 100644 --- a/indra/llui/llmultislider.cpp +++ b/indra/llui/llmultislider.cpp @@ -54,13 +54,18 @@ LLMultiSlider::SliderParams::SliderParams() LLMultiSlider::Params::Params() : max_sliders("max_sliders", 1), allow_overlap("allow_overlap", false), + loop_overlap("loop_overlap", false), + orientation("orientation"), + overlap_threshold("overlap_threshold", 0), draw_track("draw_track", true), use_triangle("use_triangle", false), track_color("track_color"), thumb_disabled_color("thumb_disabled_color"), + thumb_highlight_color("thumb_highlight_color"), thumb_outline_color("thumb_outline_color"), thumb_center_color("thumb_center_color"), thumb_center_selected_color("thumb_center_selected_color"), + thumb_image("thumb_image"), triangle_color("triangle_color"), mouse_down_callback("mouse_down_callback"), mouse_up_callback("mouse_up_callback"), @@ -71,9 +76,9 @@ LLMultiSlider::Params::Params() LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p) : LLF32UICtrl(p), mMouseOffset( 0 ), - mDragStartThumbRect( 0, getRect().getHeight(), p.thumb_width, 0 ), mMaxNumSliders(p.max_sliders), mAllowOverlap(p.allow_overlap), + mLoopOverlap(p.loop_overlap), mDrawTrack(p.draw_track), mUseTriangle(p.use_triangle), mTrackColor(p.track_color()), @@ -83,12 +88,22 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p) mDisabledThumbColor(p.thumb_disabled_color()), mTriangleColor(p.triangle_color()), mThumbWidth(p.thumb_width), + mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL), mMouseDownSignal(NULL), mMouseUpSignal(NULL) { mValue.emptyMap(); mCurSlider = LLStringUtil::null; - + + if (mOrientation == HORIZONTAL) + { + mDragStartThumbRect = LLRect(0, getRect().getHeight(), p.thumb_width, 0); + } + else + { + mDragStartThumbRect = LLRect(0, p.thumb_width, getRect().getWidth(), 0); + } + if (p.mouse_down_callback.isProvided()) { setMouseDownCallback(initCommitCallback(p.mouse_down_callback)); @@ -98,6 +113,15 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p) setMouseUpCallback(initCommitCallback(p.mouse_up_callback)); } + if (p.overlap_threshold.isProvided() && p.overlap_threshold > mIncrement) + { + mOverlapThreshold = p.overlap_threshold - mIncrement; + } + else + { + mOverlapThreshold = 0; + } + for (LLInitParam::ParamIterator<SliderParams>::const_iterator it = p.sliders.begin(); it != p.sliders.end(); ++it) @@ -111,6 +135,13 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p) addSlider(it->value); } } + + mRoundedSquareImgp = LLUI::getUIImage("Rounded_Square"); + if (p.thumb_image.isProvided()) + { + mThumbImagep = LLUI::getUIImage(p.thumb_image()); + } + mThumbHighlightColor = p.thumb_highlight_color.isProvided() ? p.thumb_highlight_color() : static_cast<LLUIColor>(gFocusMgr.getFocusColor()); } LLMultiSlider::~LLMultiSlider() @@ -119,6 +150,16 @@ LLMultiSlider::~LLMultiSlider() delete mMouseUpSignal; } +F32 LLMultiSlider::getNearestIncrement(F32 value) const +{ + value = llclamp(value, mMinValue, mMaxValue); + + // Round to nearest increment (bias towards rounding down) + value -= mMinValue; + value += mIncrement / 2.0001f; + value -= fmod(value, mIncrement); + return mMinValue + value; +} void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from_event) { @@ -127,13 +168,7 @@ void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from return; } - value = llclamp( value, mMinValue, mMaxValue ); - - // Round to nearest increment (bias towards rounding down) - value -= mMinValue; - value += mIncrement/2.0001f; - value -= fmod(value, mIncrement); - F32 newValue = mMinValue + value; + F32 newValue = getNearestIncrement(value); // now, make sure no overlap // if we want that @@ -143,14 +178,40 @@ void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from // look at the current spot // and see if anything is there LLSD::map_iterator mIt = mValue.beginMap(); - for(;mIt != mValue.endMap(); mIt++) { - - F32 testVal = (F32)mIt->second.asReal() - newValue; - if(testVal > -FLOAT_THRESHOLD && testVal < FLOAT_THRESHOLD && - mIt->first != name) { + + // increment is our distance between points, use to eliminate round error + F32 threshold = mOverlapThreshold + (mIncrement / 4); + // If loop overlap is enabled, check if we overlap with points 'after' max value (project to lower) + F32 loop_up_check = (mLoopOverlap && (value + threshold) > mMaxValue) ? (value + threshold - mMaxValue + mMinValue) : mMinValue - 1.0f; + // If loop overlap is enabled, check if we overlap with points 'before' min value (project to upper) + F32 loop_down_check = (mLoopOverlap && (value - threshold) < mMinValue) ? (value - threshold - mMinValue + mMaxValue) : mMaxValue + 1.0f; + + for(;mIt != mValue.endMap(); mIt++) + { + F32 locationVal = (F32)mIt->second.asReal(); + // Check nearby values + F32 testVal = locationVal - newValue; + if (testVal > -threshold + && testVal < threshold + && mIt->first != name) + { hit = true; break; } + if (mLoopOverlap) + { + // Check edge overlap values + if (locationVal < loop_up_check) + { + hit = true; + break; + } + if (locationVal > loop_down_check) + { + hit = true; + break; + } + } } // if none found, stop @@ -170,13 +231,26 @@ void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from } F32 t = (newValue - mMinValue) / (mMaxValue - mMinValue); + if (mOrientation == HORIZONTAL) + { + S32 left_edge = mThumbWidth/2; + S32 right_edge = getRect().getWidth() - (mThumbWidth/2); - S32 left_edge = mThumbWidth/2; - S32 right_edge = getRect().getWidth() - (mThumbWidth/2); + S32 x = left_edge + S32( t * (right_edge - left_edge) ); - S32 x = left_edge + S32( t * (right_edge - left_edge) ); - mThumbRects[name].mLeft = x - (mThumbWidth/2); - mThumbRects[name].mRight = x + (mThumbWidth/2); + mThumbRects[name].mLeft = x - (mThumbWidth / 2); + mThumbRects[name].mRight = x + (mThumbWidth / 2); + } + else + { + S32 bottom_edge = mThumbWidth/2; + S32 top_edge = getRect().getHeight() - (mThumbWidth/2); + + S32 x = bottom_edge + S32( t * (top_edge - bottom_edge) ); + + mThumbRects[name].mTop = x + (mThumbWidth / 2); + mThumbRects[name].mBottom = x - (mThumbWidth / 2); + } } void LLMultiSlider::setValue(const LLSD& value) @@ -196,7 +270,11 @@ void LLMultiSlider::setValue(const LLSD& value) F32 LLMultiSlider::getSliderValue(const std::string& name) const { - return (F32)mValue[name].asReal(); + if (mValue.has(name)) + { + return (F32)mValue[name].asReal(); + } + return 0; } void LLMultiSlider::setCurSlider(const std::string& name) @@ -206,6 +284,62 @@ void LLMultiSlider::setCurSlider(const std::string& name) } } +F32 LLMultiSlider::getSliderValueFromPos(S32 xpos, S32 ypos) const +{ + F32 t = 0; + if (mOrientation == HORIZONTAL) + { + S32 left_edge = mThumbWidth / 2; + S32 right_edge = getRect().getWidth() - (mThumbWidth / 2); + + xpos += mMouseOffset; + xpos = llclamp(xpos, left_edge, right_edge); + + t = F32(xpos - left_edge) / (right_edge - left_edge); + } + else + { + S32 bottom_edge = mThumbWidth / 2; + S32 top_edge = getRect().getHeight() - (mThumbWidth / 2); + + ypos += mMouseOffset; + ypos = llclamp(ypos, bottom_edge, top_edge); + + t = F32(ypos - bottom_edge) / (top_edge - bottom_edge); + } + + return((t * (mMaxValue - mMinValue)) + mMinValue); +} + + +LLRect LLMultiSlider::getSliderThumbRect(const std::string& name) const +{ + auto it = mThumbRects.find(name); + if (it != mThumbRects.end()) + return (*it).second; + return LLRect(); +} + +void LLMultiSlider::setSliderThumbImage(const std::string &name) +{ + if (!name.empty()) + { + mThumbImagep = LLUI::getUIImage(name); + } + else + clearSliderThumbImage(); +} + +void LLMultiSlider::clearSliderThumbImage() +{ + mThumbImagep = NULL; +} + +void LLMultiSlider::resetCurSlider() +{ + mCurSlider = LLStringUtil::null; +} + const std::string& LLMultiSlider::addSlider() { return addSlider(mInitialValue); @@ -230,7 +364,14 @@ const std::string& LLMultiSlider::addSlider(F32 val) } // add a new thumb rect - mThumbRects[newName.str()] = LLRect( 0, getRect().getHeight(), mThumbWidth, 0 ); + if (mOrientation == HORIZONTAL) + { + mThumbRects[newName.str()] = LLRect(0, getRect().getHeight(), mThumbWidth, 0); + } + else + { + mThumbRects[newName.str()] = LLRect(0, mThumbWidth, getRect().getWidth(), 0); + } // add the value and set the current slider to this one mValue.insert(newName.str(), initVal); @@ -242,21 +383,28 @@ const std::string& LLMultiSlider::addSlider(F32 val) return mCurSlider; } -void LLMultiSlider::addSlider(F32 val, const std::string& name) +bool LLMultiSlider::addSlider(F32 val, const std::string& name) { F32 initVal = val; if(mValue.size() >= mMaxNumSliders) { - return; + return false; } bool foundOne = findUnusedValue(initVal); if(!foundOne) { - return; + return false; } // add a new thumb rect - mThumbRects[name] = LLRect( 0, getRect().getHeight(), mThumbWidth, 0 ); + if (mOrientation == HORIZONTAL) + { + mThumbRects[name] = LLRect(0, getRect().getHeight(), mThumbWidth, 0); + } + else + { + mThumbRects[name] = LLRect(0, mThumbWidth, getRect().getWidth(), 0); + } // add the value and set the current slider to this one mValue.insert(name, initVal); @@ -264,6 +412,8 @@ void LLMultiSlider::addSlider(F32 val, const std::string& name) // move the slider setSliderValue(mCurSlider, initVal, TRUE); + + return true; } bool LLMultiSlider::findUnusedValue(F32& initVal) @@ -278,11 +428,13 @@ bool LLMultiSlider::findUnusedValue(F32& initVal) // look at the current spot // and see if anything is there + F32 threshold = mAllowOverlap ? FLOAT_THRESHOLD : mOverlapThreshold + (mIncrement / 4); LLSD::map_iterator mIt = mValue.beginMap(); for(;mIt != mValue.endMap(); mIt++) { F32 testVal = (F32)mIt->second.asReal() - initVal; - if(testVal > -FLOAT_THRESHOLD && testVal < FLOAT_THRESHOLD) { + if(testVal > -threshold && testVal < threshold) + { hit = true; break; } @@ -334,10 +486,15 @@ void LLMultiSlider::deleteSlider(const std::string& name) void LLMultiSlider::clear() { - while(mThumbRects.size() > 0) { + while(mThumbRects.size() > 0 && mValue.size() > 0) { deleteCurSlider(); } + if (mThumbRects.size() > 0 || mValue.size() > 0) + { + LL_WARNS() << "Failed to fully clear Multi slider" << LL_ENDL; + } + LLF32UICtrl::clear(); } @@ -345,14 +502,7 @@ BOOL LLMultiSlider::handleHover(S32 x, S32 y, MASK mask) { if( gFocusMgr.getMouseCapture() == this ) { - S32 left_edge = mThumbWidth/2; - S32 right_edge = getRect().getWidth() - (mThumbWidth/2); - - x += mMouseOffset; - x = llclamp( x, left_edge, right_edge ); - - F32 t = F32(x - left_edge) / (right_edge - left_edge); - setCurSliderValue(t * (mMaxValue - mMinValue) + mMinValue ); + setCurSliderValue(getSliderValueFromPos(x, y)); onCommit(); getWindow()->setCursor(UI_CURSOR_ARROW); @@ -360,6 +510,24 @@ BOOL LLMultiSlider::handleHover(S32 x, S32 y, MASK mask) } else { + if (getEnabled()) + { + mHoverSlider.clear(); + std::map<std::string, LLRect>::iterator mIt = mThumbRects.begin(); + for (; mIt != mThumbRects.end(); mIt++) + { + if (mIt->second.pointInRect(x, y)) + { + mHoverSlider = mIt->first; + break; + } + } + } + else + { + mHoverSlider.clear(); + } + getWindow()->setCursor(UI_CURSOR_ARROW); LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; } @@ -416,20 +584,30 @@ BOOL LLMultiSlider::handleMouseDown(S32 x, S32 y, MASK mask) } } - // Find the offset of the actual mouse location from the center of the thumb. - if (mThumbRects[mCurSlider].pointInRect(x,y)) - { - mMouseOffset = (mThumbRects[mCurSlider].mLeft + mThumbWidth/2) - x; - } - else + if (!mCurSlider.empty()) { - mMouseOffset = 0; - } + // Find the offset of the actual mouse location from the center of the thumb. + if (mThumbRects[mCurSlider].pointInRect(x,y)) + { + if (mOrientation == HORIZONTAL) + { + mMouseOffset = (mThumbRects[mCurSlider].mLeft + mThumbWidth / 2) - x; + } + else + { + mMouseOffset = (mThumbRects[mCurSlider].mBottom + mThumbWidth / 2) - y; + } + } + else + { + mMouseOffset = 0; + } - // Start dragging the thumb - // No handler needed for focus lost since this class has no state that depends on it. - gFocusMgr.setMouseCapture( this ); - mDragStartThumbRect = mThumbRects[mCurSlider]; + // Start dragging the thumb + // No handler needed for focus lost since this class has no state that depends on it. + gFocusMgr.setMouseCapture( this ); + mDragStartThumbRect = mThumbRects[mCurSlider]; + } } make_ui_sound("UISndClick"); @@ -462,6 +640,13 @@ BOOL LLMultiSlider::handleKeyHere(KEY key, MASK mask) return handled; } +/*virtual*/ +void LLMultiSlider::onMouseLeave(S32 x, S32 y, MASK mask) +{ + mHoverSlider.clear(); + LLF32UICtrl::onMouseLeave(x, y, mask); +} + void LLMultiSlider::draw() { static LLUICachedControl<S32> extra_triangle_height ("UIExtraTriangleHeight", 0); @@ -470,6 +655,7 @@ void LLMultiSlider::draw() std::map<std::string, LLRect>::iterator mIt; std::map<std::string, LLRect>::iterator curSldrIt; + std::map<std::string, LLRect>::iterator hoverSldrIt; // Draw background and thumb. @@ -481,17 +667,24 @@ void LLMultiSlider::draw() F32 opacity = getEnabled() ? 1.f : 0.3f; // Track - LLUIImagePtr thumb_imagep = LLUI::getUIImage("Rounded_Square"); - - static LLUICachedControl<S32> multi_track_height ("UIMultiTrackHeight", 0); - S32 height_offset = (getRect().getHeight() - multi_track_height) / 2; - LLRect track_rect(0, getRect().getHeight() - height_offset, getRect().getWidth(), height_offset ); + static LLUICachedControl<S32> multi_track_height_width ("UIMultiTrackHeight", 0); + S32 height_offset = 0; + S32 width_offset = 0; + if (mOrientation == HORIZONTAL) + { + height_offset = (getRect().getHeight() - multi_track_height_width) / 2; + } + else + { + width_offset = (getRect().getWidth() - multi_track_height_width) / 2; + } + LLRect track_rect(width_offset, getRect().getHeight() - height_offset, getRect().getWidth() - width_offset, height_offset); if(mDrawTrack) { track_rect.stretch(-1); - thumb_imagep->draw(track_rect, mTrackColor.get() % opacity); + mRoundedSquareImgp->draw(track_rect, mTrackColor.get() % opacity); } // if we're supposed to use a drawn triangle @@ -510,10 +703,11 @@ void LLMultiSlider::draw() mTriangleColor.get() % opacity, TRUE); } } - else if (!thumb_imagep) + else if (!mRoundedSquareImgp && !mThumbImagep) { // draw all the thumbs curSldrIt = mThumbRects.end(); + hoverSldrIt = mThumbRects.end(); for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) { // choose the color @@ -522,15 +716,21 @@ void LLMultiSlider::draw() curSldrIt = mIt; continue; - //curThumbColor = mThumbCenterSelectedColor; + } + if (mIt->first == mHoverSlider && getEnabled() && gFocusMgr.getMouseCapture() != this) + { + // draw last, after current one + hoverSldrIt = mIt; + continue; } // the draw command gl_rect_2d(mIt->second, curThumbColor, TRUE); } - // now draw the current slider - if(curSldrIt != mThumbRects.end()) { + // now draw the current and hover sliders + if(curSldrIt != mThumbRects.end()) + { gl_rect_2d(curSldrIt->second, mThumbCenterSelectedColor.get(), TRUE); } @@ -539,20 +739,57 @@ void LLMultiSlider::draw() { gl_rect_2d(mDragStartThumbRect, mThumbCenterColor.get() % opacity, FALSE); } + else if (hoverSldrIt != mThumbRects.end()) + { + gl_rect_2d(hoverSldrIt->second, mThumbCenterSelectedColor.get(), TRUE); + } } - else if( gFocusMgr.getMouseCapture() == this ) + else { - // draw drag start - thumb_imagep->drawSolid(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f); + LLMouseHandler* capture = gFocusMgr.getMouseCapture(); + if (capture == this) + { + // draw drag start (ghost) + if (mThumbImagep) + { + mThumbImagep->draw(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f); + } + else + { + mRoundedSquareImgp->drawSolid(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f); + } + } // draw the highlight if (hasFocus()) { - thumb_imagep->drawBorder(mThumbRects[mCurSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth()); + if (!mCurSlider.empty()) + { + if (mThumbImagep) + { + mThumbImagep->drawBorder(mThumbRects[mCurSlider], mThumbHighlightColor, gFocusMgr.getFocusFlashWidth()); + } + else + { + mRoundedSquareImgp->drawBorder(mThumbRects[mCurSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth()); + } + } } + if (!mHoverSlider.empty()) + { + if (mThumbImagep) + { + mThumbImagep->drawBorder(mThumbRects[mHoverSlider], mThumbHighlightColor, gFocusMgr.getFocusFlashWidth()); + } + else + { + mRoundedSquareImgp->drawBorder(mThumbRects[mHoverSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth()); + } + } // draw the thumbs curSldrIt = mThumbRects.end(); + hoverSldrIt = mThumbRects.end(); for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) { // choose the color @@ -563,46 +800,68 @@ void LLMultiSlider::draw() curSldrIt = mIt; continue; } + if (mIt->first == mHoverSlider && getEnabled() && gFocusMgr.getMouseCapture() != this) + { + // don't draw now, draw last, after current one + hoverSldrIt = mIt; + continue; + } // the draw command - thumb_imagep->drawSolid(mIt->second, curThumbColor); + if (mThumbImagep) + { + if (getEnabled()) + { + mThumbImagep->draw(mIt->second); + } + else + { + mThumbImagep->draw(mIt->second, LLColor4::grey % 0.8f); + } + } + else if (capture == this) + { + mRoundedSquareImgp->drawSolid(mIt->second, curThumbColor); + } + else + { + mRoundedSquareImgp->drawSolid(mIt->second, curThumbColor % opacity); + } } - // draw cur slider last + // draw cur and hover slider last if(curSldrIt != mThumbRects.end()) { - thumb_imagep->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get()); - } - - } - else - { - // draw highlight - if (hasFocus()) - { - thumb_imagep->drawBorder(mThumbRects[mCurSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth()); - } - - // draw thumbs - curSldrIt = mThumbRects.end(); - for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) - { - - // choose the color - curThumbColor = mThumbCenterColor.get(); - if(mIt->first == mCurSlider) + if (mThumbImagep) { - curSldrIt = mIt; - continue; - //curThumbColor = mThumbCenterSelectedColor; - } - - thumb_imagep->drawSolid(mIt->second, curThumbColor % opacity); + if (getEnabled()) + { + mThumbImagep->draw(curSldrIt->second); + } + else + { + mThumbImagep->draw(curSldrIt->second, LLColor4::grey % 0.8f); + } + } + else if (capture == this) + { + mRoundedSquareImgp->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get()); + } + else + { + mRoundedSquareImgp->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get() % opacity); + } } - - if(curSldrIt != mThumbRects.end()) + if(hoverSldrIt != mThumbRects.end()) { - thumb_imagep->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get() % opacity); + if (mThumbImagep) + { + mThumbImagep->draw(hoverSldrIt->second); + } + else + { + mRoundedSquareImgp->drawSolid(hoverSldrIt->second, mThumbCenterSelectedColor.get()); + } } } diff --git a/indra/llui/llmultislider.h b/indra/llui/llmultislider.h index 2b422e89c9..3cb4b760b0 100644 --- a/indra/llui/llmultislider.h +++ b/indra/llui/llmultislider.h @@ -47,16 +47,23 @@ public: Optional<S32> max_sliders; Optional<bool> allow_overlap, + loop_overlap, draw_track, use_triangle; + Optional<F32> overlap_threshold; + Optional<LLUIColor> track_color, thumb_disabled_color, + thumb_highlight_color, thumb_outline_color, thumb_center_color, thumb_center_selected_color, triangle_color; + Optional<std::string> orientation, + thumb_image; + Optional<CommitCallbackParam> mouse_down_callback, mouse_up_callback; Optional<S32> thumb_width; @@ -70,16 +77,27 @@ protected: friend class LLUICtrlFactory; public: virtual ~LLMultiSlider(); + + // Multi-slider rounds values to nearest increments (bias towards rounding down) + F32 getNearestIncrement(F32 value) const; + void setSliderValue(const std::string& name, F32 value, BOOL from_event = FALSE); F32 getSliderValue(const std::string& name) const; + F32 getSliderValueFromPos(S32 xpos, S32 ypos) const; + LLRect getSliderThumbRect(const std::string& name) const; + + void setSliderThumbImage(const std::string &name); + void clearSliderThumbImage(); + const std::string& getCurSlider() const { return mCurSlider; } F32 getCurSliderValue() const { return getSliderValue(mCurSlider); } void setCurSlider(const std::string& name); + void resetCurSlider(); void setCurSliderValue(F32 val, BOOL from_event = false) { setSliderValue(mCurSlider, val, from_event); } - /*virtual*/ void setValue(const LLSD& value); - /*virtual*/ LLSD getValue() const { return mValue; } + /*virtual*/ void setValue(const LLSD& value) override; + /*virtual*/ LLSD getValue() const override { return mValue; } boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ); boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); @@ -87,24 +105,34 @@ public: bool findUnusedValue(F32& initVal); const std::string& addSlider(); const std::string& addSlider(F32 val); - void addSlider(F32 val, const std::string& name); + bool addSlider(F32 val, const std::string& name); void deleteSlider(const std::string& name); void deleteCurSlider() { deleteSlider(mCurSlider); } - void clear(); + /*virtual*/ void clear() override; + + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask) override; + /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask) override; + /*virtual*/ void draw() override; + + S32 getMaxNumSliders() { return mMaxNumSliders; } + S32 getCurNumSliders() { return mValue.size(); } + F32 getOverlapThreshold() { return mOverlapThreshold; } + bool canAddSliders() { return mValue.size() < mMaxNumSliders; } - /*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(); protected: LLSD mValue; std::string mCurSlider; + std::string mHoverSlider; static S32 mNameCounter; S32 mMaxNumSliders; BOOL mAllowOverlap; + BOOL mLoopOverlap; + F32 mOverlapThreshold; BOOL mDrawTrack; BOOL mUseTriangle; /// hacked in toggle to use a triangle @@ -116,11 +144,16 @@ protected: mThumbRects; LLUIColor mTrackColor; LLUIColor mThumbOutlineColor; + LLUIColor mThumbHighlightColor; LLUIColor mThumbCenterColor; LLUIColor mThumbCenterSelectedColor; LLUIColor mDisabledThumbColor; LLUIColor mTriangleColor; - + LLUIImagePtr mThumbImagep; //blimps on the slider, for now no 'disabled' support + LLUIImagePtr mRoundedSquareImgp; //blimps on the slider, for now no 'disabled' support + + const EOrientation mOrientation; + commit_signal_t* mMouseDownSignal; commit_signal_t* mMouseUpSignal; }; diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp index c460a08afc..b3df7c154b 100644 --- a/indra/llui/llmultisliderctrl.cpp +++ b/indra/llui/llmultisliderctrl.cpp @@ -53,6 +53,12 @@ LLMultiSliderCtrl::Params::Params() can_edit_text("can_edit_text", false), max_sliders("max_sliders", 1), allow_overlap("allow_overlap", false), + loop_overlap("loop_overlap", false), + orientation("orientation"), + thumb_image("thumb_image"), + thumb_width("thumb_width"), + thumb_highlight_color("thumb_highlight_color"), + overlap_threshold("overlap_threshold", 0), draw_track("draw_track", true), use_triangle("use_triangle", false), decimal_digits("decimal_digits", 3), @@ -167,6 +173,19 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p) params.increment(p.increment); params.max_sliders(p.max_sliders); params.allow_overlap(p.allow_overlap); + params.loop_overlap(p.loop_overlap); + if (p.overlap_threshold.isProvided()) + { + params.overlap_threshold = p.overlap_threshold; + } + params.orientation(p.orientation); + params.thumb_image(p.thumb_image); + params.thumb_highlight_color(p.thumb_highlight_color); + if (p.thumb_width.isProvided()) + { + // otherwise should be provided by template + params.thumb_width(p.thumb_width); + } params.draw_track(p.draw_track); params.use_triangle(p.use_triangle); params.control_name(p.control_name); @@ -213,6 +232,11 @@ void LLMultiSliderCtrl::setCurSlider(const std::string& name) mCurValue = mMultiSlider->getCurSliderValue(); } +void LLMultiSliderCtrl::resetCurSlider() +{ + mMultiSlider->resetCurSlider(); +} + BOOL LLMultiSliderCtrl::setLabelArg( const std::string& key, const LLStringExplicit& text ) { BOOL res = FALSE; @@ -269,6 +293,17 @@ const std::string& LLMultiSliderCtrl::addSlider(F32 val) return name; } +bool LLMultiSliderCtrl::addSlider(F32 val, const std::string& name) +{ + bool res = mMultiSlider->addSlider(val, name); + if (res) + { + mCurValue = mMultiSlider->getCurSliderValue(); + updateText(); + } + return res; +} + void LLMultiSliderCtrl::deleteSlider(const std::string& name) { mMultiSlider->deleteSlider(name); @@ -474,6 +509,7 @@ void LLMultiSliderCtrl::onTabInto() { mEditor->onTabInto(); } + LLF32UICtrl::onTabInto(); } void LLMultiSliderCtrl::reportInvalidData() diff --git a/indra/llui/llmultisliderctrl.h b/indra/llui/llmultisliderctrl.h index b6a3542376..adb28676ec 100644 --- a/indra/llui/llmultisliderctrl.h +++ b/indra/llui/llmultisliderctrl.h @@ -51,14 +51,22 @@ public: text_width; Optional<bool> show_text, can_edit_text; - Optional<S32> decimal_digits; + Optional<S32> decimal_digits, + thumb_width; Optional<S32> max_sliders; Optional<bool> allow_overlap, + loop_overlap, draw_track, use_triangle; + Optional<std::string> orientation, + thumb_image; + + Optional<F32> overlap_threshold; + Optional<LLUIColor> text_color, - text_disabled_color; + text_disabled_color, + thumb_highlight_color; Optional<CommitCallbackParam> mouse_down_callback, mouse_up_callback; @@ -74,7 +82,7 @@ protected: public: virtual ~LLMultiSliderCtrl(); - F32 getSliderValue(const std::string& name) const; + F32 getSliderValue(const std::string& name) const { return mMultiSlider->getSliderValue(name); } void setSliderValue(const std::string& name, F32 v, BOOL from_event = FALSE); virtual void setValue(const LLSD& value ); @@ -84,6 +92,7 @@ public: const std::string& getCurSlider() const { return mMultiSlider->getCurSlider(); } F32 getCurSliderValue() const { return mCurValue; } void setCurSlider(const std::string& name); + void resetCurSlider(); void setCurSliderValue(F32 val, BOOL from_event = false) { setSliderValue(mMultiSlider->getCurSlider(), val, from_event); } virtual void setMinValue(const LLSD& min_value) { setMinValue((F32)min_value.asReal()); } @@ -98,15 +107,28 @@ public: void setMaxValue(F32 max_value) {mMultiSlider->setMaxValue(max_value);} void setIncrement(F32 increment) {mMultiSlider->setIncrement(increment);} + F32 getNearestIncrement(F32 value) const { return mMultiSlider->getNearestIncrement(value); } + F32 getSliderValueFromPos(S32 x, S32 y) const { return mMultiSlider->getSliderValueFromPos(x, y); } + LLRect getSliderThumbRect(const std::string &name) const { return mMultiSlider->getSliderThumbRect(name); } + + void setSliderThumbImage(const std::string &name) { mMultiSlider->setSliderThumbImage(name); } + void clearSliderThumbImage() { mMultiSlider->clearSliderThumbImage(); } + /// for adding and deleting sliders const std::string& addSlider(); const std::string& addSlider(F32 val); + bool addSlider(F32 val, const std::string& name); void deleteSlider(const std::string& name); void deleteCurSlider() { deleteSlider(mMultiSlider->getCurSlider()); } F32 getMinValue() const { return mMultiSlider->getMinValue(); } F32 getMaxValue() const { return mMultiSlider->getMaxValue(); } + S32 getMaxNumSliders() { return mMultiSlider->getMaxNumSliders(); } + S32 getCurNumSliders() { return mMultiSlider->getCurNumSliders(); } + F32 getOverlapThreshold() { return mMultiSlider->getOverlapThreshold(); } + bool canAddSliders() { return mMultiSlider->canAddSliders(); } + void setLabel(const std::string& label) { if (mLabelBox) mLabelBox->setText(label); } void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; } void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; } diff --git a/indra/llui/llnotificationptr.h b/indra/llui/llnotificationptr.h index acc047527f..580f353c7d 100644 --- a/indra/llui/llnotificationptr.h +++ b/indra/llui/llnotificationptr.h @@ -27,9 +27,8 @@ // Many classes just store a single LLNotificationPtr // and llnotifications.h is very large, so define this ligher header. -#include <boost/shared_ptr.hpp> class LLNotification; -typedef boost::shared_ptr<LLNotification> LLNotificationPtr; +typedef std::shared_ptr<LLNotification> LLNotificationPtr; #endif diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 7bafd711cb..b791a19c2b 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -68,7 +68,8 @@ LLNotificationForm::FormIgnore::FormIgnore() control("control"), invert_control("invert_control", false), save_option("save_option", false), - session_only("session_only", false) + session_only("session_only", false), + checkbox_only("checkbox_only", false) {} LLNotificationForm::FormButton::FormButton() @@ -76,6 +77,7 @@ LLNotificationForm::FormButton::FormButton() text("text"), ignore("ignore"), is_default("default"), + width("width", 0), type("type") { // set type here so it gets serialized @@ -130,7 +132,7 @@ bool handleIgnoredNotification(const LLSD& payload) response = pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON); break; case LLNotificationForm::IGNORE_WITH_LAST_RESPONSE: - response = LLUI::sSettingGroups["ignores"]->getLLSD("Default" + pNotif->getName()); + response = LLUI::getInstance()->mSettingGroups["ignores"]->getLLSD("Default" + pNotif->getName()); break; case LLNotificationForm::IGNORE_SHOW_AGAIN: break; @@ -195,9 +197,15 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotifica { if (p.ignore.isProvided()) { + // For all cases but IGNORE_CHECKBOX_ONLY this is name for use in preferences mIgnoreMsg = p.ignore.text; - if (!p.ignore.save_option) + LLUI *ui_inst = LLUI::getInstance(); + if (p.ignore.checkbox_only) + { + mIgnore = IGNORE_CHECKBOX_ONLY; + } + else if (!p.ignore.save_option) { mIgnore = p.ignore.session_only ? IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY : IGNORE_WITH_DEFAULT_RESPONSE; } @@ -205,19 +213,19 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotifica { // remember last option chosen by user and automatically respond with that in the future mIgnore = IGNORE_WITH_LAST_RESPONSE; - LLUI::sSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name)); + ui_inst->mSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name)); } BOOL show_notification = TRUE; if (p.ignore.control.isProvided()) { - mIgnoreSetting = LLUI::sSettingGroups["config"]->getControl(p.ignore.control); + mIgnoreSetting = ui_inst->mSettingGroups["config"]->getControl(p.ignore.control); mInvertSetting = p.ignore.invert_control; } - else + else if (mIgnore > IGNORE_NO) { - LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Show notification with this name", LLControlVariable::PERSIST_NONDFT); - mIgnoreSetting = LLUI::sSettingGroups["ignores"]->getControl(name); + ui_inst->mSettingGroups["ignores"]->declareBOOL(name, show_notification, "Show notification with this name", LLControlVariable::PERSIST_NONDFT); + mIgnoreSetting = ui_inst->mSettingGroups["ignores"]->getControl(name); } } @@ -248,7 +256,7 @@ LLNotificationForm::LLNotificationForm(const LLSD& sd) } else { - LL_WARNS() << "Invalid form data " << sd << LL_ENDL; + LL_WARNS("Notifications") << "Invalid form data " << sd << LL_ENDL; mFormData = LLSD::emptyArray(); } } @@ -388,13 +396,12 @@ LLControlVariablePtr LLNotificationForm::getIgnoreSetting() bool LLNotificationForm::getIgnored() { bool show = true; - if (mIgnore != LLNotificationForm::IGNORE_NO + if (mIgnore > LLNotificationForm::IGNORE_NO && mIgnoreSetting) { show = mIgnoreSetting->getValue().asBoolean(); if (mInvertSetting) show = !show; } - return !show; } @@ -432,7 +439,7 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par mSoundName("") { if (p.sound.isProvided() - && LLUI::sSettingGroups["config"]->controlExists(p.sound)) + && LLUI::getInstance()->mSettingGroups["config"]->controlExists(p.sound)) { mSoundName = p.sound; } @@ -442,11 +449,11 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par mUniqueContext.push_back(context.value); } - LL_DEBUGS() << "notification \"" << mName << "\": tag count is " << p.tags.size() << LL_ENDL; + LL_DEBUGS("Notifications") << "notification \"" << mName << "\": tag count is " << p.tags.size() << LL_ENDL; BOOST_FOREACH(const LLNotificationTemplate::Tag& tag, p.tags) { - LL_DEBUGS() << " tag \"" << std::string(tag.value) << "\"" << LL_ENDL; + LL_DEBUGS("Notifications") << " tag \"" << std::string(tag.value) << "\"" << LL_ENDL; mTags.push_back(tag.value); } @@ -695,12 +702,12 @@ void LLNotification::respond(const LLSD& response) mTemporaryResponder = false; } - if (mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) + if (mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) { mForm->setIgnored(mIgnored); if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) { - LLUI::sSettingGroups["ignores"]->setLLSD("Default" + getName(), response); + LLUI::getInstance()->mSettingGroups["ignores"]->setLLSD("Default" + getName(), response); } } @@ -1392,8 +1399,14 @@ void LLNotifications::initSingleton() createDefaultChannels(); } +void LLNotifications::cleanupSingleton() +{ + clear(); +} + void LLNotifications::createDefaultChannels() { + LL_INFOS("Notifications") << "Generating default notification channels" << LL_ENDL; // now construct the various channels AFTER loading the notifications, // because the history channel is going to rewrite the stored notifications file mDefaultChannels.push_back(new LLNotificationChannel("Enabled", "", @@ -1449,7 +1462,7 @@ void LLNotifications::forceResponse(const LLNotification::Params& params, S32 op if (selected_item.isUndefined()) { - LL_WARNS() << "Invalid option" << option << " for notification " << (std::string)params.name << LL_ENDL; + LL_WARNS("Notifications") << "Invalid option" << option << " for notification " << (std::string)params.name << LL_ENDL; return; } response[selected_item["name"].asString()] = true; @@ -1483,12 +1496,12 @@ void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements) if (found != replacements.end()) { replacement = found->second; - LL_DEBUGS() << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << LL_ENDL; + LL_DEBUGS("Notifications") << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << LL_ENDL; it->second->setValue(replacement); } else { - LL_WARNS() << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << LL_ENDL; + LL_WARNS("Notifications") << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << LL_ENDL; } } } @@ -1527,7 +1540,7 @@ void addPathIfExists(const std::string& new_path, std::vector<std::string>& path bool LLNotifications::loadTemplates() { - LL_INFOS() << "Reading notifications template" << LL_ENDL; + LL_INFOS("Notifications") << "Reading notifications template" << LL_ENDL; // Passing findSkinnedFilenames(constraint=LLDir::ALL_SKINS) makes it // output all relevant pathnames instead of just the ones from the most // specific skin. @@ -1598,7 +1611,7 @@ bool LLNotifications::loadTemplates() mTemplates[notification.name] = LLNotificationTemplatePtr(new LLNotificationTemplate(notification)); } - LL_INFOS() << "...done" << LL_ENDL; + LL_INFOS("Notifications") << "...done" << LL_ENDL; return true; } @@ -1826,7 +1839,7 @@ bool LLNotifications::isVisibleByRules(LLNotificationPtr n) for(it = mVisibilityRules.begin(); it != mVisibilityRules.end(); it++) { // An empty type/tag/name string will match any notification, so only do the comparison when the string is non-empty in the rule. - LL_DEBUGS() + LL_DEBUGS("Notifications") << "notification \"" << n->getName() << "\" " << "testing against " << ((*it)->mVisible?"show":"hide") << " rule, " << "name = \"" << (*it)->mName << "\" " @@ -1871,7 +1884,7 @@ bool LLNotifications::isVisibleByRules(LLNotificationPtr n) if((*it)->mResponse.empty()) { // Response property is empty. Cancel this notification. - LL_DEBUGS() << "cancelling notification " << n->getName() << LL_ENDL; + LL_DEBUGS("Notifications") << "cancelling notification " << n->getName() << LL_ENDL; cancel(n); } @@ -1882,7 +1895,7 @@ bool LLNotifications::isVisibleByRules(LLNotificationPtr n) // TODO: verify that the response template has an item with the correct name response[(*it)->mResponse] = true; - LL_DEBUGS() << "responding to notification " << n->getName() << " with response = " << response << LL_ENDL; + LL_DEBUGS("Notifications") << "responding to notification " << n->getName() << " with response = " << response << LL_ENDL; n->respond(response); } @@ -1894,7 +1907,7 @@ bool LLNotifications::isVisibleByRules(LLNotificationPtr n) break; } - LL_DEBUGS() << "allowing notification " << n->getName() << LL_ENDL; + LL_DEBUGS("Notifications") << "allowing notification " << n->getName() << LL_ENDL; return true; } @@ -1955,7 +1968,7 @@ void LLPostponedNotification::onAvatarNameCache(const LLUUID& agent_id, // from PE merge - we should figure out if this is the right thing to do if (name.empty()) { - LL_WARNS() << "Empty name received for Id: " << agent_id << LL_ENDL; + LL_WARNS("Notifications") << "Empty name received for Id: " << agent_id << LL_ENDL; name = SYSTEM_FROM; } diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 1509446920..b1123d27e5 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -85,7 +85,6 @@ #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> -#include <boost/enable_shared_from_this.hpp> #include <boost/type_traits.hpp> #include <boost/signals2.hpp> #include <boost/range.hpp> @@ -180,6 +179,7 @@ public: Optional<std::string> control; Optional<bool> invert_control; Optional<bool> session_only; + Optional<bool> checkbox_only; FormIgnore(); }; @@ -190,6 +190,7 @@ public: Mandatory<std::string> text; Optional<std::string> ignore; Optional<bool> is_default; + Optional<S32> width; Mandatory<std::string> type; @@ -232,7 +233,8 @@ public: typedef enum e_ignore_type { - IGNORE_NO, + IGNORE_CHECKBOX_ONLY = -1, // ignore won't be handled, will set value/checkbox only + IGNORE_NO = 0, IGNORE_WITH_DEFAULT_RESPONSE, IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY, IGNORE_WITH_LAST_RESPONSE, @@ -302,7 +304,7 @@ typedef boost::shared_ptr<LLNotificationVisibilityRule> LLNotificationVisibility */ class LLNotification : boost::noncopyable, - public boost::enable_shared_from_this<LLNotification> + public std::enable_shared_from_this<LLNotification> { LOG_CLASS(LLNotification); friend class LLNotifications; @@ -741,45 +743,30 @@ public: : mFilter(filter), mItems() {} - virtual ~LLNotificationChannelBase() {} + virtual ~LLNotificationChannelBase() + { + mItems.clear(); + } // you can also connect to a Channel, so you can be notified of // changes to this channel - template <typename LISTENER> - LLBoundListener connectChanged(const LISTENER& slot) + LLBoundListener connectChanged(const LLEventListener& slot) { - // Examine slot to see if it binds an LLEventTrackable subclass, or a - // boost::shared_ptr to something, or a boost::weak_ptr to something. // Call this->connectChangedImpl() to actually connect it. - return LLEventDetail::visit_and_connect(slot, - boost::bind(&LLNotificationChannelBase::connectChangedImpl, - this, - _1)); + return connectChangedImpl(slot); } - template <typename LISTENER> - LLBoundListener connectAtFrontChanged(const LISTENER& slot) + LLBoundListener connectAtFrontChanged(const LLEventListener& slot) { - return LLEventDetail::visit_and_connect(slot, - boost::bind(&LLNotificationChannelBase::connectAtFrontChangedImpl, - this, - _1)); + return connectAtFrontChangedImpl(slot); } - template <typename LISTENER> - LLBoundListener connectPassedFilter(const LISTENER& slot) + LLBoundListener connectPassedFilter(const LLEventListener& slot) { // see comments in connectChanged() - return LLEventDetail::visit_and_connect(slot, - boost::bind(&LLNotificationChannelBase::connectPassedFilterImpl, - this, - _1)); + return connectPassedFilterImpl(slot); } - template <typename LISTENER> - LLBoundListener connectFailedFilter(const LISTENER& slot) + LLBoundListener connectFailedFilter(const LLEventListener& slot) { // see comments in connectChanged() - return LLEventDetail::visit_and_connect(slot, - boost::bind(&LLNotificationChannelBase::connectFailedFilterImpl, - this, - _1)); + return connectFailedFilterImpl(slot); } // use this when items change or to add a new one @@ -889,6 +876,7 @@ class LLNotifications : { LLSINGLETON(LLNotifications); LOG_CLASS(LLNotifications); + virtual ~LLNotifications() {} public: @@ -973,6 +961,7 @@ public: private: /*virtual*/ void initSingleton(); + /*virtual*/ void cleanupSingleton(); void loadPersistentNotifications(); @@ -1086,6 +1075,11 @@ public: : LLNotificationChannel("Persistent", "Visible", ¬ificationFilter) {} + virtual ~LLPersistentNotificationChannel() + { + mHistory.clear(); + } + typedef std::vector<LLNotificationPtr> history_list_t; history_list_t::iterator beginHistory() { sortHistory(); return mHistory.begin(); } history_list_t::iterator endHistory() { return mHistory.end(); } diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp index be26416cbb..e73ba1fbe9 100644 --- a/indra/llui/llnotificationslistener.cpp +++ b/indra/llui/llnotificationslistener.cpp @@ -127,18 +127,16 @@ void LLNotificationsListener::listChannels(const LLSD& params) const { LLReqID reqID(params); LLSD response(reqID.makeResponse()); - for (LLNotificationChannel::instance_iter cmi(LLNotificationChannel::beginInstances()), - cmend(LLNotificationChannel::endInstances()); - cmi != cmend; ++cmi) + for (auto& cm : LLNotificationChannel::instance_snapshot()) { LLSD channelInfo, parents; - BOOST_FOREACH(const std::string& parent, cmi->getParents()) + for (const std::string& parent : cm.getParents()) { parents.append(parent); } channelInfo["parents"] = parents; channelInfo["parent"] = parents.size()? parents[0] : ""; - response[cmi->getName()] = channelInfo; + response[cm.getName()] = channelInfo; } LLEventPumps::instance().obtain(params["reply"]).post(response); } diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index ee90574161..00da0f5fec 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -609,7 +609,7 @@ std::string LLPanel::getString(const std::string& name, const LLStringUtil::form return formatted_string.getString(); } std::string err_str("Failed to find string " + name + " in panel " + getName()); //*TODO: Translate - if(LLUI::sSettingGroups["config"]->getBOOL("QAMode")) + if(LLUI::getInstance()->mSettingGroups["config"]->getBOOL("QAMode")) { LL_ERRS() << err_str << LL_ENDL; } @@ -628,7 +628,7 @@ std::string LLPanel::getString(const std::string& name) const return found_it->second; } std::string err_str("Failed to find string " + name + " in panel " + getName()); //*TODO: Translate - if(LLUI::sSettingGroups["config"]->getBOOL("QAMode")) + if(LLUI::getInstance()->mSettingGroups["config"]->getBOOL("QAMode")) { LL_ERRS() << err_str << LL_ENDL; } diff --git a/indra/llui/llresmgr.cpp b/indra/llui/llresmgr.cpp index 6e924c1f19..d65c220974 100644 --- a/indra/llui/llresmgr.cpp +++ b/indra/llui/llresmgr.cpp @@ -295,9 +295,6 @@ const std::string LLLocale::SYSTEM_LOCALE("English_United States.1252"); #elif LL_DARWIN const std::string LLLocale::USER_LOCALE("en_US.iso8859-1");// = LLStringUtil::null; const std::string LLLocale::SYSTEM_LOCALE("en_US.iso8859-1"); -#elif LL_SOLARIS -const std::string LLLocale::USER_LOCALE("en_US.ISO8859-1"); -const std::string LLLocale::SYSTEM_LOCALE("C"); #else // LL_LINUX likes this const std::string LLLocale::USER_LOCALE("en_US.utf8"); const std::string LLLocale::SYSTEM_LOCALE("C"); diff --git a/indra/llui/llrngwriter.cpp b/indra/llui/llrngwriter.cpp index e4a31d6a79..4bd1561425 100644 --- a/indra/llui/llrngwriter.cpp +++ b/indra/llui/llrngwriter.cpp @@ -29,14 +29,7 @@ #include "llrngwriter.h" #include "lluicolor.h" -#if LL_DARWIN -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdelete-incomplete" #include "lluictrlfactory.h" -#pragma clang diagnostic pop -#else -#include "lluictrlfactory.h" -#endif #include "boost/bind.hpp" diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp index 76134144a0..fde6de4921 100644 --- a/indra/llui/llscrollbar.cpp +++ b/indra/llui/llscrollbar.cpp @@ -84,7 +84,7 @@ LLScrollbar::LLScrollbar(const Params & p) mThumbImageH(p.thumb_image_horizontal), mTrackImageV(p.track_image_vertical), mTrackImageH(p.track_image_horizontal), - mThickness(p.thickness.isProvided() ? p.thickness : LLUI::sSettingGroups["config"]->getS32("UIScrollbarSize")), + mThickness(p.thickness.isProvided() ? p.thickness : LLUI::getInstance()->mSettingGroups["config"]->getS32("UIScrollbarSize")), mBGVisible(p.bg_visible), mBGColor(p.bg_color) { @@ -408,6 +408,16 @@ BOOL LLScrollbar::handleScrollWheel(S32 x, S32 y, S32 clicks) return handled; } +BOOL LLScrollbar::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + BOOL handled = FALSE; + if (LLScrollbar::HORIZONTAL == mOrientation) + { + handled = changeLine(clicks * mStepSize, TRUE); + } + return handled; +} + BOOL LLScrollbar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string &tooltip_msg) { @@ -488,7 +498,7 @@ void LLScrollbar::draw() S32 local_mouse_x; S32 local_mouse_y; - LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); + LLUI::getInstance()->getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); BOOL other_captor = gFocusMgr.getMouseCapture() && gFocusMgr.getMouseCapture() != this; BOOL hovered = getEnabled() && !other_captor && (hasMouseCapture() || mThumbRect.pointInRect(local_mouse_x, local_mouse_y)); if (hovered) @@ -645,5 +655,5 @@ void LLScrollbar::onLineDownBtnPressed( const LLSD& data ) void LLScrollbar::setThickness(S32 thickness) { - mThickness = thickness < 0 ? LLUI::sSettingGroups["config"]->getS32("UIScrollbarSize") : thickness; + mThickness = thickness < 0 ? LLUI::getInstance()->mSettingGroups["config"]->getS32("UIScrollbarSize") : thickness; } diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h index e2bf52c14b..5f2f490d81 100644 --- a/indra/llui/llscrollbar.h +++ b/indra/llui/llscrollbar.h @@ -88,6 +88,7 @@ public: 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 handleScrollHWheel(S32 x, S32 y, S32 clicks); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string &tooltip_msg); diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index 6135cc56ad..3db38bbfac 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -272,6 +272,25 @@ BOOL LLScrollContainer::handleScrollWheel( S32 x, S32 y, S32 clicks ) return FALSE; } +BOOL LLScrollContainer::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + if (LLUICtrl::handleScrollHWheel(x,y,clicks)) + { + return TRUE; + } + + LLScrollbar* horizontal = mScrollbar[HORIZONTAL]; + if (horizontal->getVisible() + && horizontal->getEnabled() + && horizontal->handleScrollHWheel( 0, 0, clicks ) ) + { + updateScroll(); + return TRUE; + } + + return FALSE; +} + BOOL LLScrollContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h index e6c7891397..c14099dbd5 100644 --- a/indra/llui/llscrollcontainer.h +++ b/indra/llui/llscrollcontainer.h @@ -107,6 +107,7 @@ public: virtual BOOL handleKeyHere(KEY key, MASK mask); virtual BOOL handleUnicodeCharHere(llwchar uni_char); virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + virtual BOOL handleScrollHWheel( S32 x, S32 y, S32 clicks ); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp index 8000efad0e..13839da400 100644 --- a/indra/llui/llscrolllistcell.cpp +++ b/indra/llui/llscrolllistcell.cpp @@ -50,6 +50,10 @@ LLScrollListCell* LLScrollListCell::create(const LLScrollListCell::Params& cell_ { cell = new LLScrollListDate(cell_p); } + else if (cell_p.type() == "icontext") + { + cell = new LLScrollListIconText(cell_p); + } else // default is "text" { cell = new LLScrollListText(cell_p); @@ -168,7 +172,7 @@ U32 LLScrollListText::sCount = 0; LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p) : LLScrollListCell(p), - mText(p.value().asString()), + mText(p.label.isProvided() ? p.label() : p.value().asString()), mFont(p.font), mColor(p.color), mUseColor(p.color.isProvided()), @@ -192,7 +196,7 @@ LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p) void LLScrollListText::highlightText(S32 offset, S32 num_chars) { mHighlightOffset = offset; - mHighlightCount = num_chars; + mHighlightCount = llmax(0, num_chars); } //virtual @@ -292,11 +296,12 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col if (mHighlightCount > 0) { + // Highlight text S32 left = 0; switch(mFontAlignment) { case LLFontGL::LEFT: - left = mFont->getWidth(mText.getString(), 0, mHighlightOffset); + left = mFont->getWidth(mText.getString(), 1, mHighlightOffset); break; case LLFontGL::RIGHT: left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX); @@ -319,7 +324,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col switch(mFontAlignment) { case LLFontGL::LEFT: - start_x = 0.f; + start_x = 1.f; break; case LLFontGL::RIGHT: start_x = (F32)getWidth(); @@ -435,3 +440,139 @@ const LLSD LLScrollListDate::getValue() const { return mDate; } + +// +// LLScrollListIconText +// +LLScrollListIconText::LLScrollListIconText(const LLScrollListCell::Params& p) + : LLScrollListText(p), + mIcon(p.value().isUUID() ? LLUI::getUIImageByID(p.value().asUUID()) : LLUI::getUIImage(p.value().asString())), + mPad(4) +{ + mTextWidth = getWidth() - mPad /*padding*/ - mFont->getLineHeight(); +} + +LLScrollListIconText::~LLScrollListIconText() +{ +} + +const LLSD LLScrollListIconText::getValue() const +{ + if (mIcon.isNull()) + { + return LLStringUtil::null; + } + return mIcon->getName(); +} + +void LLScrollListIconText::setValue(const LLSD& value) +{ + if (value.isUUID()) + { + // don't use default image specified by LLUUID::null, use no image in that case + LLUUID image_id = value.asUUID(); + mIcon = image_id.notNull() ? LLUI::getUIImageByID(image_id) : LLUIImagePtr(NULL); + } + else + { + std::string value_string = value.asString(); + if (LLUUID::validate(value_string)) + { + setValue(LLUUID(value_string)); + } + else if (!value_string.empty()) + { + mIcon = LLUI::getUIImage(value.asString()); + } + else + { + mIcon = NULL; + } + } +} + +void LLScrollListIconText::setWidth(S32 width) +{ + LLScrollListCell::setWidth(width); + // Assume that iamge height and width is identical to font height and width + mTextWidth = width - mPad /*padding*/ - mFont->getLineHeight(); +} + + +void LLScrollListIconText::draw(const LLColor4& color, const LLColor4& highlight_color) const +{ + LLColor4 display_color; + if (mUseColor) + { + display_color = mColor; + } + else + { + display_color = color; + } + + S32 icon_height = mFont->getLineHeight(); + S32 icon_space = mIcon ? (icon_height + mPad) : 0; + + if (mHighlightCount > 0) + { + S32 left = 0; + switch (mFontAlignment) + { + case LLFontGL::LEFT: + left = mFont->getWidth(mText.getString(), icon_space + 1, mHighlightOffset); + break; + case LLFontGL::RIGHT: + left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX) - icon_space; + break; + case LLFontGL::HCENTER: + left = (getWidth() - mFont->getWidth(mText.getString()) - icon_space) / 2; + break; + } + LLRect highlight_rect(left - 2, + mFont->getLineHeight() + 1, + left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1, + 1); + mRoundedRectImage->draw(highlight_rect, highlight_color); + } + + // Try to draw the entire string + F32 right_x; + U32 string_chars = mText.length(); + F32 start_text_x = 0.f; + S32 start_icon_x = 0; + switch (mFontAlignment) + { + case LLFontGL::LEFT: + start_text_x = icon_space + 1; + start_icon_x = 1; + break; + case LLFontGL::RIGHT: + start_text_x = (F32)getWidth(); + start_icon_x = getWidth() - mFont->getWidth(mText.getString()) - icon_space; + break; + case LLFontGL::HCENTER: + F32 center = (F32)getWidth()* 0.5f; + start_text_x = center + ((F32)icon_space * 0.5f); + start_icon_x = center - (((F32)icon_space + mFont->getWidth(mText.getString())) * 0.5f); + break; + } + mFont->render(mText.getWString(), 0, + start_text_x, 0.f, + display_color, + mFontAlignment, + LLFontGL::BOTTOM, + 0, + LLFontGL::NO_SHADOW, + string_chars, + getTextWidth(), + &right_x, + TRUE); + + if (mIcon) + { + mIcon->draw(start_icon_x, 0, icon_height, icon_height, mColor); + } +} + + diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h index d625ebddcc..19576fb247 100644 --- a/indra/llui/llscrolllistcell.h +++ b/indra/llui/llscrolllistcell.h @@ -59,7 +59,8 @@ public: visible; Optional<void*> userdata; - Optional<LLSD> value; + Optional<LLSD> value; // state of checkbox, icon id/name, date + Optional<std::string> label; // description or text Optional<std::string> tool_tip; Optional<const LLFontGL*> font; @@ -75,6 +76,7 @@ public: enabled("enabled", true), visible("visible", true), value("value"), + label("label"), tool_tip("tool_tip", ""), font("font", LLFontGL::getFontSansSerifSmall()), font_color("font_color", LLColor4::black), @@ -152,11 +154,12 @@ public: void setText(const LLStringExplicit& text); void setFontStyle(const U8 font_style); -private: +protected: LLUIString mText; S32 mTextWidth; const LLFontGL* mFont; LLColor4 mColor; + LLColor4 mHighlightColor; U8 mUseColor; LLFontGL::HAlign mFontAlignment; BOOL mVisible; @@ -169,7 +172,7 @@ private: }; /* - * Cell displaying an image. + * Cell displaying an image. AT the moment, this is specifically UI image */ class LLScrollListIcon : public LLScrollListCell { @@ -223,4 +226,26 @@ private: LLDate mDate; }; +/* +* Cell displaying icon and text. +*/ + +class LLScrollListIconText : public LLScrollListText +{ +public: + LLScrollListIconText(const LLScrollListCell::Params& p); + /*virtual*/ ~LLScrollListIconText(); + /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; + /*virtual*/ const LLSD getValue() const; + /*virtual*/ void setValue(const LLSD& value); + + + S32 getIconWidth() const; + /*virtual*/ void setWidth(S32 width);/* { LLScrollListCell::setWidth(width); mTextWidth = width - ; }*/ + +private: + LLPointer<LLUIImage> mIcon; + S32 mPad; +}; + #endif diff --git a/indra/llui/llscrolllistcolumn.cpp b/indra/llui/llscrolllistcolumn.cpp index cc9ff7a487..82b0415624 100644 --- a/indra/llui/llscrolllistcolumn.cpp +++ b/indra/llui/llscrolllistcolumn.cpp @@ -257,7 +257,7 @@ void LLScrollColumnHeader::updateResizeBars() for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++) { LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); - if (columnp->mHeader && columnp->mHeader->canResize()) + if (columnp && columnp->mHeader && columnp->mHeader->canResize()) { num_resizable_columns++; } @@ -269,7 +269,7 @@ void LLScrollColumnHeader::updateResizeBars() for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++) { LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); - if (!columnp->mHeader) continue; + if (!columnp || !columnp->mHeader) continue; BOOL enable = num_resizable_columns >= 2 && num_resizers_enabled < (num_resizable_columns - 1) && columnp->mHeader->canResize(); columnp->mHeader->enableResizeBar(enable); if (enable) diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index f4028057e8..de644185fd 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -115,6 +115,13 @@ struct SortScrollListItem // LLScrollListCtrl //--------------------------------------------------------------------------- +void LLScrollListCtrl::SelectionTypeNames::declareValues() +{ + declare("row", LLScrollListCtrl::ROW); + declare("cell", LLScrollListCtrl::CELL); + declare("header", LLScrollListCtrl::HEADER); +} + LLScrollListCtrl::Contents::Contents() : columns("column"), rows("row") @@ -128,15 +135,19 @@ LLScrollListCtrl::Params::Params() has_border("draw_border"), draw_heading("draw_heading"), search_column("search_column", 0), + selection_type("selection_type", ROW), sort_column("sort_column", -1), sort_ascending("sort_ascending", true), + can_sort("can_sort", true), mouse_wheel_opaque("mouse_wheel_opaque", false), commit_on_keyboard_movement("commit_on_keyboard_movement", true), + commit_on_selection_change("commit_on_selection_change", false), heading_height("heading_height"), page_lines("page_lines", 0), background_visible("background_visible"), draw_stripes("draw_stripes"), column_padding("column_padding"), + row_padding("row_padding", 2), fg_unselected_color("fg_unselected_color"), fg_selected_color("fg_selected_color"), bg_selected_color("bg_selected_color"), @@ -161,10 +172,12 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) mMaxSelectable(0), mAllowKeyboardMovement(true), mCommitOnKeyboardMovement(p.commit_on_keyboard_movement), - mCommitOnSelectionChange(false), + mCommitOnSelectionChange(p.commit_on_selection_change), mSelectionChanged(false), + mSelectionType(p.selection_type), mNeedsScroll(false), mCanSelect(true), + mCanSort(p.can_sort), mColumnsDirty(false), mMaxItemCount(INT_MAX), mBorderThickness( 2 ), @@ -199,6 +212,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) mHoveredColor(p.hovered_color()), mSearchColumn(p.search_column), mColumnPadding(p.column_padding), + mRowPadding(p.row_padding), mContextMenuType(MENU_NONE), mIsFriendSignal(NULL) { @@ -685,8 +699,6 @@ bool LLScrollListCtrl::updateColumnWidths() return width_changed; } -const S32 SCROLL_LIST_ROW_PAD = 2; - // Line height is the max height of all the cells in all the items. void LLScrollListCtrl::updateLineHeight() { @@ -699,7 +711,7 @@ void LLScrollListCtrl::updateLineHeight() S32 i = 0; for (const LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i)) { - mLineHeight = llmax( mLineHeight, cell->getHeight() + SCROLL_LIST_ROW_PAD ); + mLineHeight = llmax( mLineHeight, cell->getHeight() + mRowPadding ); } } } @@ -711,7 +723,7 @@ void LLScrollListCtrl::updateLineHeightInsert(LLScrollListItem* itemp) S32 i = 0; for (const LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i)) { - mLineHeight = llmax( mLineHeight, cell->getHeight() + SCROLL_LIST_ROW_PAD ); + mLineHeight = llmax( mLineHeight, cell->getHeight() + mRowPadding ); } } @@ -731,12 +743,12 @@ void LLScrollListCtrl::updateColumns(bool force_update) LLScrollColumnHeader* last_header = NULL; for (column_ordered_it = mColumnsIndexed.begin(); column_ordered_it != mColumnsIndexed.end(); ++column_ordered_it) { - if ((*column_ordered_it)->getWidth() < 0) + LLScrollListColumn* column = *column_ordered_it; + if (!column || column->getWidth() < 0) { // skip hidden columns continue; } - LLScrollListColumn* column = *column_ordered_it; if (column->mHeader) { @@ -762,14 +774,20 @@ void LLScrollListCtrl::updateColumns(bool force_update) } } + bool header_changed_width = false; // expand last column header we encountered to full list width if (last_header) { + S32 old_width = last_header->getColumn()->getWidth(); S32 new_width = llmax(0, mItemListRect.mRight - last_header->getRect().mLeft); last_header->reshape(new_width, last_header->getRect().getHeight()); last_header->setVisible(mDisplayColumnHeaders && new_width > 0); - last_header->getColumn()->setWidth(new_width); - } + if (old_width != new_width) + { + last_header->getColumn()->setWidth(new_width); + header_changed_width = true; + } + } // propagate column widths to individual cells if (columns_changed_width || force_update) @@ -788,6 +806,20 @@ void LLScrollListCtrl::updateColumns(bool force_update) } } } + else if (header_changed_width) + { + item_list::iterator iter; + S32 index = last_header->getColumn()->mIndex; // Not always identical to last column! + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem *itemp = *iter; + LLScrollListCell* cell = itemp->getColumn(index); + if (cell) + { + cell->setWidth(last_header->getColumn()->getWidth()); + } + } + } } void LLScrollListCtrl::setHeadingHeight(S32 heading_height) @@ -819,7 +851,15 @@ BOOL LLScrollListCtrl::selectFirstItem() { if (!itemp->getSelected()) { - selectItem(itemp); + switch (mSelectionType) + { + case CELL: + selectItem(itemp, 0); + break; + case HEADER: + case ROW: + selectItem(itemp, -1); + } } success = TRUE; mOriginalSelection = 0; @@ -878,7 +918,8 @@ BOOL LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index ) { if( itemp->getEnabled() ) { - selectItem(itemp, FALSE); + // TODO: support range selection for cells + selectItem(itemp, -1, FALSE); success = TRUE; } } @@ -1004,10 +1045,14 @@ void LLScrollListCtrl::clearHighlightedItems() void LLScrollListCtrl::mouseOverHighlightNthItem(S32 target_index) { - if (mHighlightedItem != target_index) - { - mHighlightedItem = target_index; - } + if (mHighlightedItem != target_index) + { + if (mHighlightedItem >= 0 && mHighlightedItem < mItemList.size()) + { + mItemList[mHighlightedItem]->setHoverCell(-1); + } + mHighlightedItem = target_index; + } } S32 LLScrollListCtrl::selectMultiple( uuid_vec_t ids ) @@ -1022,7 +1067,8 @@ S32 LLScrollListCtrl::selectMultiple( uuid_vec_t ids ) { if (item->getEnabled() && (item->getUUID() == (*iditr))) { - selectItem(item,FALSE); + // TODO: support multiple selection for cells + selectItem(item, -1, FALSE); ++count; break; } @@ -1095,7 +1141,7 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection) { if (prev_item) { - selectItem(prev_item, !extend_selection); + selectItem(prev_item, cur_item->getSelectedCell(), !extend_selection); } else { @@ -1139,7 +1185,7 @@ void LLScrollListCtrl::selectNextItem( BOOL extend_selection) { if (next_item) { - selectItem(next_item, !extend_selection); + selectItem(next_item, cur_item->getSelectedCell(), !extend_selection); } else { @@ -1210,7 +1256,7 @@ BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sen bool found = NULL != item; if(found) { - selectItem(item); + selectItem(item, -1); } if (mCommitOnSelectionChange) @@ -1278,7 +1324,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE; if (select) { - selectItem(item); + selectItem(item, -1); found = TRUE; break; } @@ -1318,7 +1364,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen // find offset of matching text (might have leading whitespace) S32 offset = item_label.find(target_trimmed); cellp->highlightText(offset, target_trimmed.size()); - selectItem(item); + selectItem(item, -1); found = TRUE; break; } @@ -1380,18 +1426,34 @@ BOOL LLScrollListCtrl::setSelectedByValue(const LLSD& value, BOOL selected) for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem* item = *iter; - if (item->getEnabled() && (item->getValue().asString() == value.asString())) - { - if (selected) - { - selectItem(item); - } - else - { - deselectItem(item); - } - found = TRUE; - break; + if (item->getEnabled()) + { + if (value.isBinary()) + { + if (item->getValue().isBinary()) + { + LLSD::Binary data1 = value.asBinary(); + LLSD::Binary data2 = item->getValue().asBinary(); + found = std::equal(data1.begin(), data1.end(), data2.begin()) ? TRUE : FALSE; + } + } + else + { + found = item->getValue().asString() == value.asString() ? TRUE : FALSE; + } + + if (found) + { + if (selected) + { + selectItem(item, -1); + } + else + { + deselectItem(item); + } + break; + } } } @@ -1464,7 +1526,7 @@ void LLScrollListCtrl::drawItems() S32 max_columns = 0; - LLColor4 highlight_color = LLColor4::white; + LLColor4 highlight_color = LLColor4::white; // ex: text inside cells static LLUICachedControl<F32> type_ahead_timeout ("TypeAheadTimeout", 0); highlight_color.mV[VALPHA] = clamp_rescale(mSearchTimer.getElapsedTimeF32(), type_ahead_timeout * 0.7f, type_ahead_timeout(), 0.4f, 0.f); @@ -1490,7 +1552,8 @@ void LLScrollListCtrl::drawItems() max_columns = llmax(max_columns, item->getNumColumns()); LLColor4 fg_color; - LLColor4 bg_color(LLColor4::transparent); + LLColor4 hover_color(LLColor4::transparent); + LLColor4 select_color(LLColor4::transparent); if( mScrollLines <= line && line < mScrollLines + num_page_lines ) { @@ -1499,44 +1562,44 @@ void LLScrollListCtrl::drawItems() { if(item->getHighlighted()) // if it's highlighted, average the colors { - bg_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f); + select_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f); } else // otherwise just select-highlight it { - bg_color = mBgSelectedColor.get(); + select_color = mBgSelectedColor.get(); } fg_color = (item->getEnabled() ? mFgSelectedColor.get() : mFgDisabledColor.get()); } - else if (mHighlightedItem == line && mCanSelect) + if (mHighlightedItem == line && mCanSelect) { if(item->getHighlighted()) // if it's highlighted, average the colors { - bg_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f); + hover_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f); } else // otherwise just hover-highlight it { - bg_color = mHoveredColor.get(); + hover_color = mHoveredColor.get(); } } else if (item->getHighlighted()) { - bg_color = mHighlightedColor.get(); + hover_color = mHighlightedColor.get(); } else { if (mDrawStripes && (line % 2 == 0) && (max_columns > 1)) { - bg_color = mBgStripeColor.get(); + hover_color = mBgStripeColor.get(); } } if (!item->getEnabled()) { - bg_color = mBgReadOnlyColor.get(); + hover_color = mBgReadOnlyColor.get(); } - item->draw(item_rect, fg_color % alpha, bg_color% alpha, highlight_color % alpha, mColumnPadding); + item->draw(item_rect, fg_color % alpha, hover_color% alpha, select_color% alpha, highlight_color % alpha, mColumnPadding); cur_y -= mLineHeight; } @@ -1601,6 +1664,20 @@ BOOL LLScrollListCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks) return handled; } +BOOL LLScrollListCtrl::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + BOOL handled = FALSE; + // Pretend the mouse is over the scrollbar + handled = mScrollbar->handleScrollHWheel( 0, 0, clicks ); + + if (mMouseWheelOpaque) + { + return TRUE; + } + + return handled; +} + // *NOTE: Requires a valid row_index and column_index LLRect LLScrollListCtrl::getCellRect(S32 row_index, S32 column_index) { @@ -1674,7 +1751,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) { if (mLastSelected == NULL) { - selectItem(hit_item); + selectItem(hit_item, getColumnIndexFromOffset(x)); } else { @@ -1698,7 +1775,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) LLScrollListItem *item = *itor; if (item == hit_item || item == lastSelected) { - selectItem(item, FALSE); + selectItem(item, getColumnIndexFromOffset(x), FALSE); selecting = !selecting; if (hit_item == lastSelected) { @@ -1708,7 +1785,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) } if (selecting) { - selectItem(item, FALSE); + selectItem(item, getColumnIndexFromOffset(x), FALSE); } } } @@ -1723,7 +1800,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) { if(!(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable)) { - selectItem(hit_item, FALSE); + selectItem(hit_item, getColumnIndexFromOffset(x), FALSE); } else { @@ -1737,12 +1814,12 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) else { deselectAllItems(TRUE); - selectItem(hit_item); + selectItem(hit_item, getColumnIndexFromOffset(x)); } } else { - selectItem(hit_item); + selectItem(hit_item, getColumnIndexFromOffset(x)); } selection_changed = mSelectionChanged; @@ -2110,8 +2187,29 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask) { LLScrollListItem* item = hitItem(x, y); if (item) - { - mouseOverHighlightNthItem(getItemIndex(item)); + { + mouseOverHighlightNthItem(getItemIndex(item)); + switch (mSelectionType) + { + case CELL: + item->setHoverCell(getColumnIndexFromOffset(x)); + break; + case HEADER: + { + S32 cell = getColumnIndexFromOffset(x); + if (cell > 0) + { + item->setHoverCell(cell); + } + else + { + item->setHoverCell(-1); + } + break; + } + case ROW: + break; + } } else { @@ -2159,6 +2257,58 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask ) handled = TRUE; } break; + case KEY_LEFT: + if (mAllowKeyboardMovement || hasFocus()) + { + // TODO: support multi-select + LLScrollListItem *item = getFirstSelected(); + if (item) + { + S32 cell = item->getSelectedCell(); + switch (mSelectionType) + { + case CELL: + if (cell < mColumns.size()) cell++; + break; + case HEADER: + if (cell == -1) cell = 1; + else if (cell > 1 && cell < mColumns.size()) cell++; // skip header + break; + case ROW: + cell = -1; + break; + } + item->setSelectedCell(cell); + handled = TRUE; + } + } + break; + case KEY_RIGHT: + if (mAllowKeyboardMovement || hasFocus()) + { + // TODO: support multi-select + LLScrollListItem *item = getFirstSelected(); + if (item) + { + S32 cell = item->getSelectedCell(); + switch (mSelectionType) + { + case CELL: + if (cell >= 0) cell--; + break; + case HEADER: + if (cell > 1) cell--; + else if (cell == 1) cell = -1; // skip header + break; + case ROW: + cell = -1; + break; + } + item->setSelectedCell(cell); + handled = TRUE; + } + } + break; case KEY_PAGE_UP: if (mAllowKeyboardMovement || hasFocus()) { @@ -2327,7 +2477,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char) LLWString item_label = utf8str_to_wstring(cellp->getValue().asString()); if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char) { - selectItem(item); + selectItem(item, -1); mNeedsScroll = true; cellp->highlightText(0, 1); mSearchTimer.reset(); @@ -2379,7 +2529,7 @@ BOOL LLScrollListCtrl::isRepeatedChars(const LLWString& string) const return TRUE; } -void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_item) +void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, S32 cell, BOOL select_single_item) { if (!itemp) return; @@ -2398,6 +2548,18 @@ void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_it deselectAllItems(TRUE); } itemp->setSelected(TRUE); + switch (mSelectionType) + { + case CELL: + itemp->setSelectedCell(cell); + break; + case HEADER: + itemp->setSelectedCell(cell <= 0 ? -1 : cell); + break; + case ROW: + itemp->setSelectedCell(-1); + break; + } mLastSelected = itemp; mSelectionChanged = true; } @@ -2658,7 +2820,7 @@ void LLScrollListCtrl::selectAll() LLScrollListItem *itemp = *iter; if( itemp->getEnabled() ) { - selectItem(itemp, FALSE); + selectItem(itemp, -1, FALSE); } } @@ -2787,6 +2949,8 @@ void LLScrollListCtrl::onClickColumn(void *userdata) LLScrollListCtrl *parent = info->mParentCtrl; if (!parent) return; + if (!parent->mCanSort) return; + S32 column_index = info->mIndex; LLScrollListColumn* column = parent->mColumnsIndexed[info->mIndex]; diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index b35a8608e7..0cc481b113 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -54,6 +54,18 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, public LLCtrlListInterface, public LLCtrlScrollInterface { public: + typedef enum e_selection_type + { + ROW, // default + CELL, // does not support multi-selection + HEADER, // when pointing to cells in column 0 will highlight whole row, otherwise cell, no multi-select + } ESelectionType; + + struct SelectionTypeNames : public LLInitParam::TypeValuesHelper<LLScrollListCtrl::ESelectionType, SelectionTypeNames> + { + static void declareValues(); + }; + struct Contents : public LLInitParam::Block<Contents> { Multiple<LLScrollListColumn::Params> columns; @@ -97,8 +109,11 @@ public: // behavioral flags Optional<bool> multi_select, commit_on_keyboard_movement, + commit_on_selection_change, mouse_wheel_opaque; + Optional<ESelectionType, SelectionTypeNames> selection_type; + // display flags Optional<bool> has_border, draw_heading, @@ -108,13 +123,15 @@ public: // layout Optional<S32> column_padding, - page_lines, + row_padding, + page_lines, heading_height; // sort and search behavior Optional<S32> search_column, sort_column; - Optional<bool> sort_ascending; + Optional<bool> sort_ascending, + can_sort; // whether user is allowed to sort // colors Optional<LLUIColor> fg_unselected_color, @@ -283,8 +300,10 @@ public: void setBackgroundVisible(BOOL b) { mBackgroundVisible = b; } void setDrawStripes(BOOL b) { mDrawStripes = b; } - void setColumnPadding(const S32 c) { mColumnPadding = c; } - S32 getColumnPadding() { return mColumnPadding; } + void setColumnPadding(const S32 c) { mColumnPadding = c; } + S32 getColumnPadding() const { return mColumnPadding; } + void setRowPadding(const S32 c) { mColumnPadding = c; } + S32 getRowPadding() const { return mColumnPadding; } void setCommitOnKeyboardMovement(BOOL b) { mCommitOnKeyboardMovement = b; } void setCommitOnSelectionChange(BOOL b) { mCommitOnSelectionChange = b; } void setAllowKeyboardMovement(BOOL b) { mAllowKeyboardMovement = b; } @@ -317,6 +336,7 @@ public: /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char); /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); /*virtual*/ void setEnabled(BOOL enabled); /*virtual*/ void setFocus( BOOL b ); @@ -428,7 +448,7 @@ private: void updateLineHeightInsert(LLScrollListItem* item); void reportInvalidInput(); BOOL isRepeatedChars(const LLWString& string) const; - void selectItem(LLScrollListItem* itemp, BOOL single_select = TRUE); + void selectItem(LLScrollListItem* itemp, S32 cell, BOOL single_select = TRUE); void deselectItem(LLScrollListItem* itemp); void commitIfChanged(); BOOL setSort(S32 column, BOOL ascending); @@ -453,9 +473,11 @@ private: bool mCommitOnKeyboardMovement; bool mCommitOnSelectionChange; bool mSelectionChanged; + ESelectionType mSelectionType; bool mNeedsScroll; bool mMouseWheelOpaque; bool mCanSelect; + bool mCanSort; // Whether user is allowed to sort bool mDisplayColumnHeaders; bool mColumnsDirty; bool mColumnWidthsDirty; @@ -468,6 +490,7 @@ private: LLRect mItemListRect; S32 mColumnPadding; + S32 mRowPadding; BOOL mBackgroundVisible; BOOL mDrawStripes; diff --git a/indra/llui/llscrolllistitem.cpp b/indra/llui/llscrolllistitem.cpp index df22c88afb..51c615dd00 100644 --- a/indra/llui/llscrolllistitem.cpp +++ b/indra/llui/llscrolllistitem.cpp @@ -40,6 +40,8 @@ LLScrollListItem::LLScrollListItem( const Params& p ) : mSelected(FALSE), mHighlighted(FALSE), + mHoverIndex(-1), + mSelectedIndex(-1), mEnabled(p.enabled), mUserdata(p.userdata), mItemValue(p.value) @@ -53,6 +55,28 @@ LLScrollListItem::~LLScrollListItem() mColumns.clear(); } +void LLScrollListItem::setSelected(BOOL b) +{ + mSelected = b; + mSelectedIndex = -1; +} + +void LLScrollListItem::setHighlighted(BOOL b) +{ + mHighlighted = b; + mHoverIndex = -1; +} + +void LLScrollListItem::setHoverCell(S32 cell) +{ + mHoverIndex = cell; +} + +void LLScrollListItem::setSelectedCell(S32 cell) +{ + mSelectedIndex = cell; +} + void LLScrollListItem::addColumn(const LLScrollListCell::Params& p) { mColumns.push_back(LLScrollListCell::create(p)); @@ -120,12 +144,21 @@ 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) +void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& hover_color, const LLColor4& select_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 ); + if (mSelectedIndex < 0 && getSelected()) + { + // Whole item is highlighted/selected + gl_rect_2d(bg_rect, select_color); + } + else if (mHoverIndex < 0) + { + // Whole item is highlighted/selected + gl_rect_2d(bg_rect, hover_color); + } S32 cur_x = rect.mLeft; S32 num_cols = getNumColumns(); @@ -141,6 +174,25 @@ void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const { LLUI::translate((F32) cur_x, (F32) rect.mBottom); + if (mSelectedIndex == cur_col) + { + // select specific cell + LLRect highlight_rect(0, + cell->getHeight(), + cell->getWidth(), + 0); + gl_rect_2d(highlight_rect, select_color); + } + else if (mHoverIndex == cur_col) + { + // highlight specific cell + LLRect highlight_rect(0, + cell->getHeight(), + cell->getWidth() , + 0); + gl_rect_2d(highlight_rect, hover_color); + } + cell->draw( fg_color, highlight_color ); } LLUI::popMatrix(); diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h index 13655b5873..d2c3dd7721 100644 --- a/indra/llui/llscrolllistitem.h +++ b/indra/llui/llscrolllistitem.h @@ -77,15 +77,21 @@ public: virtual ~LLScrollListItem(); - void setSelected( BOOL b ) { mSelected = b; } + void setSelected( BOOL b ); BOOL getSelected() const { return mSelected; } void setEnabled( BOOL b ) { mEnabled = b; } BOOL getEnabled() const { return mEnabled; } - void setHighlighted( BOOL b ) { mHighlighted = b; } + void setHighlighted( BOOL b ); BOOL getHighlighted() const { return mHighlighted; } + void setSelectedCell( S32 cell ); + S32 getSelectedCell() const { return mSelectedIndex; } + + void setHoverCell( S32 cell ); + S32 getHoverCell() const { return mHoverIndex; } + void setUserdata( void* userdata ) { mUserdata = userdata; } void* getUserdata() const { return mUserdata; } @@ -107,14 +113,21 @@ public: 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 void draw(const LLRect& rect, + const LLColor4& fg_color, + const LLColor4& hover_color, // highlight/hover selection of whole item or cell + const LLColor4& select_color, // highlight/hover selection of whole item or cell + const LLColor4& highlight_color, // highlights contents of cells (ex: text) + S32 column_padding); protected: LLScrollListItem( const Params& ); private: BOOL mSelected; - BOOL mHighlighted; + BOOL mHighlighted; + S32 mHoverIndex; + S32 mSelectedIndex; BOOL mEnabled; void* mUserdata; LLSD mItemValue; diff --git a/indra/llui/llsearcheditor.cpp b/indra/llui/llsearcheditor.cpp index 1fdd05a11c..bafeef41fb 100644 --- a/indra/llui/llsearcheditor.cpp +++ b/indra/llui/llsearcheditor.cpp @@ -34,7 +34,11 @@ LLSearchEditor::LLSearchEditor(const LLSearchEditor::Params& p) : LLUICtrl(p), mSearchButton(NULL), - mClearButton(NULL) + mClearButton(NULL), + mEditorImage(p.background_image), + mEditorImageFocused(p.background_image_focused), + mEditorSearchImage(p.background_image_highlight), + mHighlightTextField(p.highlight_text_field) { S32 srch_btn_top = p.search_button.top_pad + p.search_button.rect.height; S32 srch_btn_right = p.search_button.rect.width + p.search_button.left_pad; @@ -57,6 +61,8 @@ LLSearchEditor::LLSearchEditor(const LLSearchEditor::Params& p) // Set up line editor. LLLineEditor::Params line_editor_params(p); line_editor_params.name("filter edit box"); + line_editor_params.background_image(p.background_image); + line_editor_params.background_image_focused(p.background_image_focused); line_editor_params.rect(getLocalRect()); line_editor_params.follows.flags(FOLLOWS_ALL); line_editor_params.text_pad_left(text_pad_left); @@ -104,6 +110,20 @@ void LLSearchEditor::draw() if (mClearButton) mClearButton->setVisible(!mSearchEditor->getWText().empty()); + if (mHighlightTextField) + { + if (!mSearchEditor->getWText().empty()) + { + mSearchEditor->setBgImage(mEditorSearchImage); + mSearchEditor->setBgImageFocused(mEditorSearchImage); + } + else + { + mSearchEditor->setBgImage(mEditorImage); + mSearchEditor->setBgImageFocused(mEditorImageFocused); + } + } + LLUICtrl::draw(); } diff --git a/indra/llui/llsearcheditor.h b/indra/llui/llsearcheditor.h index 3b12868225..c0f3c1d60c 100644 --- a/indra/llui/llsearcheditor.h +++ b/indra/llui/llsearcheditor.h @@ -47,14 +47,23 @@ public: Optional<LLButton::Params> search_button, clear_button; Optional<bool> search_button_visible, - clear_button_visible; + clear_button_visible, + highlight_text_field; Optional<commit_callback_t> keystroke_callback; + Optional<LLUIImage*> background_image, + background_image_focused, + background_image_highlight; + Params() : search_button("search_button"), search_button_visible("search_button_visible"), clear_button("clear_button"), - clear_button_visible("clear_button_visible") + clear_button_visible("clear_button_visible"), + highlight_text_field("highlight_text_field"), + background_image("background_image"), + background_image_focused("background_image_focused"), + background_image_highlight("background_image_highlight") {} }; @@ -93,6 +102,13 @@ protected: LLLineEditor* mSearchEditor; LLButton* mSearchButton; LLButton* mClearButton; + + LLPointer<LLUIImage> mEditorImage; + LLPointer<LLUIImage> mEditorImageFocused; + LLPointer<LLUIImage> mEditorSearchImage; + LLPointer<LLUIImage> mEditorSearchImageFocused; + + bool mHighlightTextField; }; #endif // LL_SEARCHEDITOR_H diff --git a/indra/llui/llslider.cpp b/indra/llui/llslider.cpp index ebbb951ee6..62df5a2c38 100644 --- a/indra/llui/llslider.cpp +++ b/indra/llui/llslider.cpp @@ -42,7 +42,6 @@ static LLDefaultChildRegistry::Register<LLSlider> r1("slider_bar"); LLSlider::Params::Params() : orientation ("orientation", std::string ("horizontal")), - track_color("track_color"), thumb_outline_color("thumb_outline_color"), thumb_center_color("thumb_center_color"), thumb_image("thumb_image"), @@ -60,7 +59,6 @@ LLSlider::LLSlider(const LLSlider::Params& p) : LLF32UICtrl(p), mMouseOffset( 0 ), mOrientation ((p.orientation() == "horizontal") ? HORIZONTAL : VERTICAL), - mTrackColor(p.track_color()), mThumbOutlineColor(p.thumb_outline_color()), mThumbCenterColor(p.thumb_center_color()), mThumbImage(p.thumb_image), @@ -331,8 +329,9 @@ void LLSlider::draw() highlight_rect.set(track_rect.mLeft, track_rect.mTop, track_rect.mRight, track_rect.mBottom); } - trackImage->draw(track_rect, LLColor4::white % alpha); - trackHighlightImage->draw(highlight_rect, LLColor4::white % alpha); + LLColor4 color = isInEnabledChain() ? LLColor4::white % alpha : LLColor4::white % (0.6f * alpha); + trackImage->draw(track_rect, color); + trackHighlightImage->draw(highlight_rect, color); // Thumb if (hasFocus()) diff --git a/indra/llui/llslider.h b/indra/llui/llslider.h index 3b492d8182..484a5373b3 100644 --- a/indra/llui/llslider.h +++ b/indra/llui/llslider.h @@ -38,8 +38,7 @@ public: { Optional<std::string> orientation; - Optional<LLUIColor> track_color, - thumb_outline_color, + Optional<LLUIColor> thumb_outline_color, thumb_center_color; Optional<LLUIImage*> thumb_image, @@ -99,7 +98,6 @@ private: const EOrientation mOrientation; LLRect mThumbRect; - LLUIColor mTrackColor; LLUIColor mThumbOutlineColor; LLUIColor mThumbCenterColor; diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp index 0056cb6dc4..d80a434f22 100644 --- a/indra/llui/llsliderctrl.cpp +++ b/indra/llui/llsliderctrl.cpp @@ -283,6 +283,35 @@ void LLSliderCtrl::updateText() } } +void LLSliderCtrl::updateSliderRect() +{ + S32 right = getRect().getWidth(); + S32 top = getRect().getHeight(); + S32 bottom = 0; + S32 left = 0; + static LLUICachedControl<S32> sliderctrl_spacing("UISliderctrlSpacing", 0); + if (mEditor) + { + LLRect editor_rect = mEditor->getRect(); + S32 editor_width = editor_rect.getWidth(); + editor_rect.mRight = right; + editor_rect.mLeft = right - editor_width; + mEditor->setRect(editor_rect); + + right -= editor_width + sliderctrl_spacing; + } + if (mTextBox) + { + right -= mTextBox->getRect().getWidth() + sliderctrl_spacing; + } + if (mLabelBox) + { + left += mLabelBox->getRect().getWidth() + sliderctrl_spacing; + } + + mSlider->setRect(LLRect(left, top,right,bottom)); +} + // static void LLSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata ) { @@ -404,6 +433,18 @@ void LLSliderCtrl::onCommit() LLF32UICtrl::onCommit(); } +void LLSliderCtrl::setRect(const LLRect& rect) +{ + LLF32UICtrl::setRect(rect); + updateSliderRect(); +} + +//virtual +void LLSliderCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + LLF32UICtrl::reshape(width, height, called_from_parent); + updateSliderRect(); +} void LLSliderCtrl::setPrecision(S32 precision) { @@ -438,6 +479,7 @@ void LLSliderCtrl::onTabInto() { mEditor->onTabInto(); } + LLF32UICtrl::onTabInto(); } void LLSliderCtrl::reportInvalidData() diff --git a/indra/llui/llsliderctrl.h b/indra/llui/llsliderctrl.h index 2bb8668b90..541c167717 100644 --- a/indra/llui/llsliderctrl.h +++ b/indra/llui/llsliderctrl.h @@ -125,6 +125,9 @@ public: mSlider->setControlName(control_name, context); } + /*virtual*/ void setRect(const LLRect& rect); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + static void onSliderCommit(LLUICtrl* caller, const LLSD& userdata); static void onEditorCommit(LLUICtrl* ctrl, const LLSD& userdata); @@ -146,6 +149,7 @@ protected: } private: void updateText(); + void updateSliderRect(); void reportInvalidData(); const LLFontGL* mFont; diff --git a/indra/llui/llspellcheck.cpp b/indra/llui/llspellcheck.cpp index 7f64743e99..ebd8ca0923 100644 --- a/indra/llui/llspellcheck.cpp +++ b/indra/llui/llspellcheck.cpp @@ -44,14 +44,11 @@ static const std::string DICT_FILE_IGNORE = "user_ignore.dic"; static const std::string DICT_FILE_MAIN = "dictionaries.xml"; static const std::string DICT_FILE_USER = "user_dictionaries.xml"; -LLSD LLSpellChecker::sDictMap; LLSpellChecker::settings_change_signal_t LLSpellChecker::sSettingsChangeSignal; LLSpellChecker::LLSpellChecker() : mHunspell(NULL) { - // Load initial dictionary information - refreshDictionaryMap(); } LLSpellChecker::~LLSpellChecker() @@ -59,6 +56,12 @@ LLSpellChecker::~LLSpellChecker() delete mHunspell; } +void LLSpellChecker::initSingleton() +{ + // Load initial dictionary information + refreshDictionaryMap(); +} + bool LLSpellChecker::checkSpelling(const std::string& word) const { if ( (!mHunspell) || (word.length() < 3) || (0 != mHunspell->spell(word.c_str())) ) @@ -94,10 +97,9 @@ S32 LLSpellChecker::getSuggestions(const std::string& word, std::vector<std::str return suggestions.size(); } -// static const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_language) { - for (LLSD::array_const_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it) + for (LLSD::array_const_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it) { const LLSD& dict_entry = *it; if (dict_language == dict_entry["language"].asString()) @@ -108,14 +110,12 @@ const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_language) return LLSD(); } -// static bool LLSpellChecker::hasDictionary(const std::string& dict_language, bool check_installed) { const LLSD dict_info = getDictionaryData(dict_language); return dict_info.has("language") && ( (!check_installed) || (dict_info["installed"].asBoolean()) ); } -// static void LLSpellChecker::setDictionaryData(const LLSD& dict_info) { const std::string dict_language = dict_info["language"].asString(); @@ -124,7 +124,7 @@ void LLSpellChecker::setDictionaryData(const LLSD& dict_info) return; } - for (LLSD::array_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it) + for (LLSD::array_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it) { LLSD& dict_entry = *it; if (dict_language == dict_entry["language"].asString()) @@ -133,7 +133,7 @@ void LLSpellChecker::setDictionaryData(const LLSD& dict_info) return; } } - sDictMap.append(dict_info); + mDictMap.append(dict_info); return; } @@ -147,14 +147,14 @@ void LLSpellChecker::refreshDictionaryMap() std::string user_filename(user_path + DICT_FILE_MAIN); llifstream user_file(user_filename.c_str(), std::ios::binary); if ( (!user_file.is_open()) - || (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(sDictMap, user_file)) - || (0 == sDictMap.size()) ) + || (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(mDictMap, user_file)) + || (0 == mDictMap.size()) ) { std::string app_filename(app_path + DICT_FILE_MAIN); llifstream app_file(app_filename.c_str(), std::ios::binary); if ( (!app_file.is_open()) - || (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(sDictMap, app_file)) - || (0 == sDictMap.size()) ) + || (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(mDictMap, app_file)) + || (0 == mDictMap.size()) ) { return; } @@ -178,7 +178,7 @@ void LLSpellChecker::refreshDictionaryMap() // Look for installed dictionaries std::string tmp_app_path, tmp_user_path; - for (LLSD::array_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it) + for (LLSD::array_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it) { LLSD& sdDict = *it; tmp_app_path = (sdDict.has("name")) ? app_path + sdDict["name"].asString() : LLStringUtil::null; @@ -416,7 +416,6 @@ bool LLSpellChecker::getUseSpellCheck() return (LLSpellChecker::instanceExists()) && (LLSpellChecker::instance().mHunspell); } -// static bool LLSpellChecker::canRemoveDictionary(const std::string& dict_language) { // Only user-installed inactive dictionaries can be removed @@ -426,7 +425,6 @@ bool LLSpellChecker::canRemoveDictionary(const std::string& dict_language) ( (!getUseSpellCheck()) || (!LLSpellChecker::instance().isActiveDictionary(dict_language)) ); } -// static void LLSpellChecker::removeDictionary(const std::string& dict_language) { if (!canRemoveDictionary(dict_language)) @@ -499,12 +497,3 @@ void LLSpellChecker::setUseSpellCheck(const std::string& dict_language) LLSpellChecker::instance().initHunspell(dict_language); } } - -// static -void LLSpellChecker::initClass() -{ - if (sDictMap.isUndefined()) - { - refreshDictionaryMap(); - } -} diff --git a/indra/llui/llspellcheck.h b/indra/llui/llspellcheck.h index acac589e43..3da5e30955 100644 --- a/indra/llui/llspellcheck.h +++ b/indra/llui/llspellcheck.h @@ -34,10 +34,9 @@ class Hunspell; -class LLSpellChecker : public LLSingleton<LLSpellChecker>, public LLInitClass<LLSpellChecker> +class LLSpellChecker : public LLSingleton<LLSpellChecker> { LLSINGLETON(LLSpellChecker); - friend class LLInitClass<LLSpellChecker>; ~LLSpellChecker(); public: @@ -48,6 +47,7 @@ public: protected: void addToDictFile(const std::string& dict_path, const std::string& word); void initHunspell(const std::string& dict_language); + void initSingleton(); public: typedef std::list<std::string> dict_list_t; @@ -57,26 +57,24 @@ public: bool isActiveDictionary(const std::string& dict_language) const; void setSecondaryDictionaries(dict_list_t dict_list); - static bool canRemoveDictionary(const std::string& dict_language); + bool canRemoveDictionary(const std::string& dict_language); static const std::string getDictionaryAppPath(); static const std::string getDictionaryUserPath(); - static const LLSD getDictionaryData(const std::string& dict_language); - static const LLSD& getDictionaryMap() { return sDictMap; } + const LLSD getDictionaryData(const std::string& dict_language); + const LLSD& getDictionaryMap() { return mDictMap; } static bool getUseSpellCheck(); - static bool hasDictionary(const std::string& dict_language, bool check_installed = false); - static void refreshDictionaryMap(); - static void removeDictionary(const std::string& dict_language); + bool hasDictionary(const std::string& dict_language, bool check_installed = false); + void refreshDictionaryMap(); + void removeDictionary(const std::string& dict_language); static void setUseSpellCheck(const std::string& dict_language); protected: static LLSD loadUserDictionaryMap(); - static void setDictionaryData(const LLSD& dict_info); + void setDictionaryData(const LLSD& dict_info); static void saveUserDictionaryMap(const LLSD& dict_map); public: typedef boost::signals2::signal<void()> settings_change_signal_t; static boost::signals2::connection setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb); -protected: - static void initClass(); protected: Hunspell* mHunspell; @@ -84,8 +82,8 @@ protected: std::string mDictFile; dict_list_t mDictSecondary; std::vector<std::string> mIgnoreList; + LLSD mDictMap; - static LLSD sDictMap; static settings_change_signal_t sSettingsChangeSignal; }; diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp index ce3fc29d32..ee78b82429 100644 --- a/indra/llui/llspinctrl.cpp +++ b/indra/llui/llspinctrl.cpp @@ -442,7 +442,8 @@ void LLSpinCtrl::setAllowEdit(BOOL allow_edit) void LLSpinCtrl::onTabInto() { - mEditor->onTabInto(); + mEditor->onTabInto(); + LLF32UICtrl::onTabInto(); } diff --git a/indra/llui/llstatview.cpp b/indra/llui/llstatview.cpp index eda2d6047f..bb4969c81f 100644 --- a/indra/llui/llstatview.cpp +++ b/indra/llui/llstatview.cpp @@ -43,7 +43,7 @@ LLStatView::LLStatView(const LLStatView::Params& p) BOOL isopen = getDisplayChildren(); if (mSetting.length() > 0) { - isopen = LLUI::sSettingGroups["config"]->getBOOL(mSetting); + isopen = LLUI::getInstance()->mSettingGroups["config"]->getBOOL(mSetting); } setDisplayChildren(isopen); } @@ -54,7 +54,7 @@ LLStatView::~LLStatView() if (mSetting.length() > 0) { BOOL isopen = getDisplayChildren(); - LLUI::sSettingGroups["config"]->setBOOL(mSetting, isopen); + LLUI::getInstance()->mSettingGroups["config"]->setBOOL(mSetting, isopen); } } diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 6521b883f8..459fdcf2ae 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -38,6 +38,7 @@ #include "llrender.h" #include "llfloater.h" #include "lltrans.h" +#include "lluiusage.h" //---------------------------------------------------------------------------- @@ -220,6 +221,8 @@ LLTabContainer::Params::Params() last_tab("last_tab"), use_custom_icon_ctrl("use_custom_icon_ctrl", false), open_tabs_on_drag_and_drop("open_tabs_on_drag_and_drop", false), + enable_tabs_flashing("enable_tabs_flashing", false), + tabs_flashing_color("tabs_flashing_color"), tab_icon_ctrl_pad("tab_icon_ctrl_pad", 0), use_ellipses("use_ellipses"), font_halign("halign") @@ -259,6 +262,8 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p) mCustomIconCtrlUsed(p.use_custom_icon_ctrl), mOpenTabsOnDragAndDrop(p.open_tabs_on_drag_and_drop), mTabIconCtrlPad(p.tab_icon_ctrl_pad), + mEnableTabsFlashing(p.enable_tabs_flashing), + mTabsFlashingColor(p.tabs_flashing_color), mUseTabEllipses(p.use_ellipses) { static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0); @@ -280,6 +285,11 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p) mMinTabWidth = tabcntr_vert_tab_min_width; } + if (p.tabs_flashing_color.isProvided()) + { + mEnableTabsFlashing = true; + } + initButtons( ); } @@ -1102,6 +1112,10 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) p.pad_left( mLabelPadLeft ); p.pad_right(2); } + + // inits flash timer + p.button_flash_enable = mEnableTabsFlashing; + p.flash_color = mTabsFlashingColor; // *TODO : It seems wrong not to use p in both cases considering the way p is initialized if (mCustomIconCtrlUsed) @@ -1543,6 +1557,8 @@ BOOL LLTabContainer::setTab(S32 which) if (is_selected) { + LLUIUsage::instance().logPanel(tuple->mTabPanel->getName()); + // Make sure selected tab is within scroll region if (mIsVertical) { diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index 6bf963313c..8f8cedb1b9 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -109,6 +109,12 @@ public: * Open tabs on hover in drag and drop situations */ Optional<bool> open_tabs_on_drag_and_drop; + + /** + * Enable tab flashing + */ + Optional<bool> enable_tabs_flashing; + Optional<LLUIColor> tabs_flashing_color; /** * Paddings for LLIconCtrl in case of LLCustomButtonIconCtrl usage(use_custom_icon_ctrl = true) @@ -310,6 +316,8 @@ private: bool mCustomIconCtrlUsed; bool mOpenTabsOnDragAndDrop; + bool mEnableTabsFlashing; + LLUIColor mTabsFlashingColor; S32 mTabIconCtrlPad; bool mUseTabEllipses; }; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index cc44f46706..9005d70b2e 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -152,6 +152,7 @@ LLTextBase::Params::Params() plain_text("plain_text",false), track_end("track_end", false), read_only("read_only", false), + skip_link_underline("skip_link_underline", false), spellcheck("spellcheck", false), v_pad("v_pad", 0), h_pad("h_pad", 0), @@ -185,6 +186,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mFontShadow(p.font_shadow), mPopupMenuHandle(), mReadOnly(p.read_only), + mSkipLinkUnderline(p.skip_link_underline), mSpellCheck(p.spellcheck), mSpellCheckStart(-1), mSpellCheckEnd(-1), @@ -1019,7 +1021,38 @@ BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask) // handle triple click if (!mTripleClickTimer.hasExpired()) { - selectAll(); + S32 real_line = getLineNumFromDocIndex(mCursorPos, false); + S32 line_start = -1; + S32 line_end = -1; + for (line_list_t::const_iterator it = mLineInfoList.begin(), end_it = mLineInfoList.end(); + it != end_it; + ++it) + { + if (it->mLineNum < real_line) + { + continue; + } + if (it->mLineNum > real_line) + { + break; + } + if (line_start == -1) + { + line_start = it->mDocIndexStart; + } + line_end = it->mDocIndexEnd; + line_end = llclamp(line_end, 0, getLength()); + } + + if (line_start == -1) + { + return TRUE; + } + + mSelectionEnd = line_start; + mSelectionStart = line_end; + setCursorPos(line_start); + return TRUE; } @@ -1150,7 +1183,7 @@ BOOL LLTextBase::handleToolTip(S32 x, S32 y, MASK mask) void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent) { - if (width != getRect().getWidth() || height != getRect().getHeight()) + if (width != getRect().getWidth() || height != getRect().getHeight() || LLView::sForceReshape) { bool scrolled_to_bottom = mScroller ? mScroller->isAtBottom() : false; @@ -2226,6 +2259,18 @@ void LLTextBase::needsReflow(S32 index) mReflowIndex = llmin(mReflowIndex, index); } +S32 LLTextBase::removeFirstLine() +{ + if (!mLineInfoList.empty()) + { + S32 length = getLineEnd(0); + deselect(); + removeStringNoUndo(0, length); + return length; + } + return 0; +} + void LLTextBase::appendLineBreakSegment(const LLStyle::Params& style_params) { segment_vec_t segments; @@ -2289,7 +2334,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig S32 cur_length = getLength(); LLStyleConstSP sp(new LLStyle(highlight_params)); LLTextSegmentPtr segmentp; - if(underline_on_hover_only) + if (underline_on_hover_only || mSkipLinkUnderline) { highlight_params.font.style("NORMAL"); LLStyleConstSP normal_sp(new LLStyle(highlight_params)); @@ -2313,7 +2358,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig S32 segment_start = old_length; S32 segment_end = old_length + wide_text.size(); LLStyleConstSP sp(new LLStyle(style_params)); - if (underline_on_hover_only) + if (underline_on_hover_only || mSkipLinkUnderline) { LLStyle::Params normal_style_params(style_params); normal_style_params.font.style("NORMAL"); @@ -3113,6 +3158,7 @@ BOOL LLTextSegment::handleRightMouseUp(S32 x, S32 y, MASK mask) { return FALSE; BOOL LLTextSegment::handleDoubleClick(S32 x, S32 y, MASK mask) { return FALSE; } BOOL LLTextSegment::handleHover(S32 x, S32 y, MASK mask) { return FALSE; } BOOL LLTextSegment::handleScrollWheel(S32 x, S32 y, S32 clicks) { return FALSE; } +BOOL LLTextSegment::handleScrollHWheel(S32 x, S32 y, S32 clicks) { return FALSE; } BOOL LLTextSegment::handleToolTip(S32 x, S32 y, MASK mask) { return FALSE; } const std::string& LLTextSegment::getName() const { @@ -3249,7 +3295,7 @@ BOOL LLNormalTextSegment::handleHover(S32 x, S32 y, MASK mask) // Only process the click if it's actually in this segment, not to the right of the end-of-line. if(mEditor.getSegmentAtLocalPos(x, y, false) == this) { - LLUI::getWindow()->setCursor(UI_CURSOR_HAND); + LLUI::getInstance()->getWindow()->setCursor(UI_CURSOR_HAND); return TRUE; } } @@ -3491,7 +3537,7 @@ F32 LLOnHoverChangeableTextSegment::draw(S32 start, S32 end, S32 selection_start /*virtual*/ BOOL LLOnHoverChangeableTextSegment::handleHover(S32 x, S32 y, MASK mask) { - mStyle = mHoveredStyle; + mStyle = mEditor.getSkipLinkUnderline() ? mNormalStyle : mHoveredStyle; return LLNormalTextSegment::handleHover(x, y, mask); } diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 99c243a346..590e7c9dbb 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -103,6 +103,7 @@ public: /*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 handleScrollHWheel(S32 x, S32 y, S32 clicks); /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); /*virtual*/ const std::string& getName() const; /*virtual*/ void onMouseCaptureLost(); @@ -309,6 +310,7 @@ public: border_visible, track_end, read_only, + skip_link_underline, spellcheck, allow_scroll, plain_text, @@ -406,6 +408,7 @@ public: virtual void setText(const LLStringExplicit &utf8str , const LLStyle::Params& input_params = LLStyle::Params()); // uses default style virtual std::string getText() const; void setMaxTextLength(S32 length) { mMaxTextByteLength = length; } + S32 getMaxTextLength() { return mMaxTextByteLength; } // wide-char versions void setWText(const LLWString& text); @@ -434,6 +437,7 @@ public: S32 getLength() const { return getWText().length(); } S32 getLineCount() const { return mLineInfoList.size(); } + S32 removeFirstLine(); // returns removed length void addDocumentChild(LLView* view); void removeDocumentChild(LLView* view); @@ -444,6 +448,8 @@ public: S32 getVPad() { return mVPad; } S32 getHPad() { return mHPad; } + F32 getLineSpacingMult() { return mLineSpacingMult; } + S32 getLineSpacingPixels() { return mLineSpacingPixels; } // only for multiline S32 getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round, bool hit_past_end_of_line = true) const; LLRect getLocalRectFromDocIndex(S32 pos) const; @@ -452,6 +458,9 @@ public: void setReadOnly(bool read_only) { mReadOnly = read_only; } bool getReadOnly() { return mReadOnly; } + void setSkipLinkUnderline(bool skip_link_underline) { mSkipLinkUnderline = skip_link_underline; } + bool getSkipLinkUnderline() { return mSkipLinkUnderline; } + void setPlainText(bool value) { mPlainText = value;} bool getPlainText() const { return mPlainText; } @@ -697,6 +706,8 @@ protected: bool mAutoIndent; S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes + bool mSkipLinkUnderline; + // support widgets LLHandle<LLContextMenu> mPopupMenuHandle; LLView* mDocumentView; diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp index 9faff1278d..134afc005b 100644 --- a/indra/llui/lltextbox.cpp +++ b/indra/llui/lltextbox.cpp @@ -107,7 +107,7 @@ BOOL LLTextBox::handleHover(S32 x, S32 y, MASK mask) if (!handled && mClickedCallback && mShowCursorHand) { // Clickable text boxes change the cursor to a hand - LLUI::getWindow()->setCursor(UI_CURSOR_HAND); + LLUI::getInstance()->getWindow()->setCursor(UI_CURSOR_HAND); return TRUE; } return handled; @@ -163,13 +163,13 @@ BOOL LLTextBox::setTextArg( const std::string& key, const LLStringExplicit& text } -void LLTextBox::reshapeToFitText() +void LLTextBox::reshapeToFitText(BOOL called_from_parent) { reflow(); S32 width = getTextPixelWidth(); S32 height = getTextPixelHeight(); - reshape( width + 2 * mHPad, height + 2 * mVPad, FALSE ); + reshape( width + 2 * mHPad, height + 2 * mVPad, called_from_parent ); } diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h index 061d2dd23d..c3e3b61912 100644 --- a/indra/llui/lltextbox.h +++ b/indra/llui/lltextbox.h @@ -60,7 +60,7 @@ public: void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; } void setClickedCallback( boost::function<void (void*)> cb, void* userdata = NULL ); - void reshapeToFitText(); + void reshapeToFitText(BOOL called_from_parent = FALSE); S32 getTextPixelWidth(); S32 getTextPixelHeight(); diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 137167db2a..b1f8b00cab 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1045,7 +1045,7 @@ void LLTextEditor::removeCharOrTab() } else { - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } } @@ -1068,7 +1068,7 @@ void LLTextEditor::removeChar() } else { - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } } @@ -1315,7 +1315,7 @@ BOOL LLTextEditor::handleNavigationKey(const KEY key, const MASK mask) } else { - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } } break; @@ -1333,7 +1333,7 @@ BOOL LLTextEditor::handleNavigationKey(const KEY key, const MASK mask) } else { - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } } break; @@ -1665,7 +1665,7 @@ BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask) } else { - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } break; @@ -2750,7 +2750,7 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect { LLRect control_rect_screen; localRectToScreen(mVisibleTextRect, &control_rect_screen); - LLUI::screenRectToGL(control_rect_screen, control); + LLUI::getInstance()->screenRectToGL(control_rect_screen, control); } S32 preedit_left_position, preedit_right_position; @@ -2804,7 +2804,7 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2; S32 query_screen_x, query_screen_y; localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y); - LLUI::screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); + LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); } if (bounds) @@ -2831,7 +2831,7 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom); LLRect preedit_rect_screen; localRectToScreen(preedit_rect_local, &preedit_rect_screen); - LLUI::screenRectToGL(preedit_rect_screen, bounds); + LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds); } return TRUE; diff --git a/indra/llui/lltextutil.cpp b/indra/llui/lltextutil.cpp index f6b2ee1dc0..538508b856 100644 --- a/indra/llui/lltextutil.cpp +++ b/indra/llui/lltextutil.cpp @@ -78,7 +78,7 @@ void LLTextUtil::textboxSetGreyedVal(LLTextBox *txtbox, const LLStyle::Params& n const std::string& LLTextUtil::formatPhoneNumber(const std::string& phone_str) { - static const std::string PHONE_SEPARATOR = LLUI::sSettingGroups["config"]->getString("AvalinePhoneSeparator"); + static const std::string PHONE_SEPARATOR = LLUI::getInstance()->mSettingGroups["config"]->getString("AvalinePhoneSeparator"); static const S32 PHONE_PART_LEN = 2; static std::string formatted_phone_str; diff --git a/indra/llui/lltoggleablemenu.cpp b/indra/llui/lltoggleablemenu.cpp index ccb92ffbb2..3e56e0a589 100644 --- a/indra/llui/lltoggleablemenu.cpp +++ b/indra/llui/lltoggleablemenu.cpp @@ -55,7 +55,7 @@ boost::signals2::connection LLToggleableMenu::setVisibilityChangeCallback(const void LLToggleableMenu::onVisibilityChange (BOOL curVisibilityIn) { S32 x,y; - LLUI::getMousePositionLocal(LLUI::getRootView(), &x, &y); + LLUI::getInstance()->getMousePositionLocal(LLUI::getInstance()->getRootView(), &x, &y); // STORM-1879: also check MouseCapture to see if the button was really // clicked (otherwise the VisibilityChange was triggered via keyboard shortcut) diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index abc2b6e9ca..5150df25f2 100644 --- a/indra/llui/lltoolbar.cpp +++ b/indra/llui/lltoolbar.cpp @@ -967,6 +967,8 @@ LLToolBarButton* LLToolBar::createButton(const LLCommandId& id) executeStopParam.function_name = executeStopFunction; executeStopParam.parameter = commandp->executeStopParameters(); LLUICtrl::commit_callback_t execute_func = initCommitCallback(executeParam); + button->setFunctionName(commandp->executeFunctionName()); + LL_DEBUGS("UIUsage") << "button function name a -> " << commandp->executeFunctionName() << LL_ENDL; LLUICtrl::commit_callback_t stop_func = initCommitCallback(executeStopParam); button->setMouseDownCallback(boost::bind(&LLToolBarButton::callIfEnabled, button, execute_func, _1, _2)); @@ -974,6 +976,8 @@ LLToolBarButton* LLToolBar::createButton(const LLCommandId& id) } else { + button->setFunctionName(commandp->executeFunctionName()); + LL_DEBUGS("UIUsage") << "button function name b -> " << commandp->executeFunctionName() << LL_ENDL; button->setCommitCallback(executeParam); } @@ -1125,7 +1129,7 @@ BOOL LLToolBarButton::handleHover(S32 x, S32 y, MASK mask) BOOL handled = FALSE; S32 mouse_distance_squared = (x - mMouseDownX) * (x - mMouseDownX) + (y - mMouseDownY) * (y - mMouseDownY); - S32 drag_threshold = LLUI::sSettingGroups["config"]->getS32("DragAndDropDistanceThreshold"); + static LLCachedControl<S32> drag_threshold(*LLUI::getInstance()->mSettingGroups["config"], "DragAndDropDistanceThreshold", 3); if (mouse_distance_squared > drag_threshold * drag_threshold && hasMouseCapture() && mStartDragItemCallback && mHandleDragItemCallback) diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index 698b128d45..2f56a8b1d0 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -145,10 +145,10 @@ LLToolTip::Params::Params() wrap("wrap", true), pos("pos"), message("message"), - delay_time("delay_time", LLUI::sSettingGroups["config"]->getF32( "ToolTipDelay" )), - visible_time_over("visible_time_over", LLUI::sSettingGroups["config"]->getF32( "ToolTipVisibleTimeOver" )), - visible_time_near("visible_time_near", LLUI::sSettingGroups["config"]->getF32( "ToolTipVisibleTimeNear" )), - visible_time_far("visible_time_far", LLUI::sSettingGroups["config"]->getF32( "ToolTipVisibleTimeFar" )), + delay_time("delay_time", LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipDelay" )), + visible_time_over("visible_time_over", LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipVisibleTimeOver" )), + visible_time_near("visible_time_near", LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipVisibleTimeNear" )), + visible_time_far("visible_time_far", LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipVisibleTimeFar" )), sticky_rect("sticky_rect"), image("image"), text_color("text_color"), @@ -358,8 +358,8 @@ void LLToolTip::draw() if (mFadeTimer.getStarted()) { - F32 tool_tip_fade_time = LLUI::sSettingGroups["config"]->getF32("ToolTipFadeTime"); - alpha = clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, tool_tip_fade_time, 1.f, 0.f); + static LLCachedControl<F32> tool_tip_fade_time(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipFadeTime", 0.2f); + alpha = clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, tool_tip_fade_time(), 1.f, 0.f); if (alpha == 0.f) { // finished fading out, so hide ourselves @@ -436,12 +436,12 @@ void LLToolTipMgr::createToolTip(const LLToolTip::Params& params) { LLCoordGL pos = params.pos; // try to spawn at requested position - LLUI::positionViewNearMouse(mToolTip, pos.mX, pos.mY); + LLUI::getInstance()->positionViewNearMouse(mToolTip, pos.mX, pos.mY); } else { // just spawn at mouse location - LLUI::positionViewNearMouse(mToolTip); + LLUI::getInstance()->positionViewNearMouse(mToolTip); } //...update "sticky" rect and tooltip position @@ -453,7 +453,7 @@ void LLToolTipMgr::createToolTip(const LLToolTip::Params& params) { S32 mouse_x; S32 mouse_y; - LLUI::getMousePositionLocal(gToolTipView->getParent(), &mouse_x, &mouse_y); + LLUI::getInstance()->getMousePositionLocal(gToolTipView->getParent(), &mouse_x, &mouse_y); // allow mouse a little bit of slop before changing tooltips mMouseNearRect.setCenterAndSize(mouse_x, mouse_y, 3, 3); @@ -491,7 +491,7 @@ void LLToolTipMgr::show(const LLToolTip::Params& params) // are we ready to show the tooltip? if (!mToolTipsBlocked // we haven't hit a key, moved the mouse, etc. - && LLUI::getMouseIdleTime() > params_with_defaults.delay_time) // the mouse has been still long enough + && LLUI::getInstance()->getMouseIdleTime() > params_with_defaults.delay_time) // the mouse has been still long enough { bool tooltip_changed = mLastToolTipParams.message() != params_with_defaults.message() || mLastToolTipParams.pos() != params_with_defaults.pos() @@ -563,7 +563,7 @@ void LLToolTipMgr::updateToolTipVisibility() } // hide tooltips when mouse cursor is hidden - if (LLUI::getWindow()->isCursorHidden()) + if (LLUI::getInstance()->getWindow()->isCursorHidden()) { blockToolTips(); return; @@ -574,7 +574,7 @@ void LLToolTipMgr::updateToolTipVisibility() if (toolTipVisible()) { S32 mouse_x, mouse_y; - LLUI::getMousePositionLocal(gToolTipView, &mouse_x, &mouse_y); + LLUI::getInstance()->getMousePositionLocal(gToolTipView, &mouse_x, &mouse_y); // mouse far away from tooltip tooltip_timeout = mLastToolTipParams.visible_time_far; diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 52190a1473..6f16745bd3 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -75,19 +75,6 @@ // Language for UI construction std::map<std::string, std::string> gTranslation; std::list<std::string> gUntranslated; -/*static*/ LLUI::settings_map_t LLUI::sSettingGroups; -/*static*/ LLUIAudioCallback LLUI::sAudioCallback = NULL; -/*static*/ LLUIAudioCallback LLUI::sDeferredAudioCallback = NULL; -/*static*/ LLWindow* LLUI::sWindow = NULL; -/*static*/ LLView* LLUI::sRootView = NULL; -/*static*/ BOOL LLUI::sDirty = FALSE; -/*static*/ LLRect LLUI::sDirtyRect; -/*static*/ LLHelp* LLUI::sHelpImpl = NULL; -/*static*/ std::vector<std::string> LLUI::sXUIPaths; -/*static*/ LLFrameTimer LLUI::sMouseIdleTimer; -/*static*/ LLUI::add_popup_t LLUI::sAddPopupFunc; -/*static*/ LLUI::remove_popup_t LLUI::sRemovePopupFunc; -/*static*/ LLUI::clear_popups_t LLUI::sClearPopupsFunc; // register filter editor here static LLDefaultChildRegistry::Register<LLFilterEditor> register_filter_editor("filter_editor"); @@ -106,18 +93,19 @@ LLUUID find_ui_sound(const char * namep) { std::string name = ll_safe_string(namep); LLUUID uuid = LLUUID(NULL); - if (!LLUI::sSettingGroups["config"]->controlExists(name)) + LLUI *ui_inst = LLUI::getInstance(); + if (!ui_inst->mSettingGroups["config"]->controlExists(name)) { LL_WARNS() << "tried to make UI sound for unknown sound name: " << name << LL_ENDL; } else { - uuid = LLUUID(LLUI::sSettingGroups["config"]->getString(name)); + uuid = LLUUID(ui_inst->mSettingGroups["config"]->getString(name)); if (uuid.isNull()) { - if (LLUI::sSettingGroups["config"]->getString(name) == LLUUID::null.asString()) + if (ui_inst->mSettingGroups["config"]->getString(name) == LLUUID::null.asString()) { - if (LLUI::sSettingGroups["config"]->getBOOL("UISndDebugSpamToggle")) + if (ui_inst->mSettingGroups["config"]->getBOOL("UISndDebugSpamToggle")) { LL_INFOS() << "UI sound name: " << name << " triggered but silent (null uuid)" << LL_ENDL; } @@ -127,9 +115,9 @@ LLUUID find_ui_sound(const char * namep) LL_WARNS() << "UI sound named: " << name << " does not translate to a valid uuid" << LL_ENDL; } } - else if (LLUI::sAudioCallback != NULL) + else if (ui_inst->mAudioCallback != NULL) { - if (LLUI::sSettingGroups["config"]->getBOOL("UISndDebugSpamToggle")) + if (ui_inst->mSettingGroups["config"]->getBOOL("UISndDebugSpamToggle")) { LL_INFOS() << "UI sound name: " << name << LL_ENDL; } @@ -144,7 +132,7 @@ void make_ui_sound(const char* namep) LLUUID soundUUID = find_ui_sound(namep); if(soundUUID.notNull()) { - LLUI::sAudioCallback(soundUUID); + LLUI::getInstance()->mAudioCallback(soundUUID); } } @@ -153,30 +141,30 @@ void make_ui_sound_deferred(const char* namep) LLUUID soundUUID = find_ui_sound(namep); if(soundUUID.notNull()) { - LLUI::sDeferredAudioCallback(soundUUID); + LLUI::getInstance()->mDeferredAudioCallback(soundUUID); } } -void LLUI::initClass(const settings_map_t& settings, - LLImageProviderInterface* image_provider, - LLUIAudioCallback audio_callback, - LLUIAudioCallback deferred_audio_callback, - const LLVector2* scale_factor, - const std::string& language) +LLUI::LLUI(const settings_map_t& settings, + LLImageProviderInterface* image_provider, + LLUIAudioCallback audio_callback, + LLUIAudioCallback deferred_audio_callback) +: mSettingGroups(settings), +mAudioCallback(audio_callback), +mDeferredAudioCallback(deferred_audio_callback), +mWindow(NULL), // set later in startup +mRootView(NULL), +mHelpImpl(NULL) { - LLRender2D::initClass(image_provider,scale_factor); - sSettingGroups = settings; + LLRender2D::initParamSingleton(image_provider); - if ((get_ptr_in_map(sSettingGroups, std::string("config")) == NULL) || - (get_ptr_in_map(sSettingGroups, std::string("floater")) == NULL) || - (get_ptr_in_map(sSettingGroups, std::string("ignores")) == NULL)) + if ((get_ptr_in_map(mSettingGroups, std::string("config")) == NULL) || + (get_ptr_in_map(mSettingGroups, std::string("floater")) == NULL) || + (get_ptr_in_map(mSettingGroups, std::string("ignores")) == NULL)) { LL_ERRS() << "Failure to initialize configuration groups" << LL_ENDL; } - sAudioCallback = audio_callback; - sDeferredAudioCallback = deferred_audio_callback; - sWindow = NULL; // set later in startup LLFontGL::sShadowColor = LLUIColorTable::instance().getColor("ColorDropShadow"); LLUICtrl::CommitCallbackRegistry::Registrar& reg = LLUICtrl::CommitCallbackRegistry::defaultRegistrar(); @@ -207,33 +195,13 @@ void LLUI::initClass(const settings_map_t& settings, LLCommandManager::load(); } -void LLUI::cleanupClass() -{ - SUBSYSTEM_CLEANUP(LLRender2D); -} - void LLUI::setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t& remove_popup, const clear_popups_t& clear_popups) { - sAddPopupFunc = add_popup; - sRemovePopupFunc = remove_popup; - sClearPopupsFunc = clear_popups; + mAddPopupFunc = add_popup; + mRemovePopupFunc = remove_popup; + mClearPopupsFunc = clear_popups; } -//static -void LLUI::dirtyRect(LLRect rect) -{ - if (!sDirty) - { - sDirtyRect = rect; - sDirty = TRUE; - } - else - { - sDirtyRect.unionWith(rect); - } -} - -//static void LLUI::setMousePositionScreen(S32 x, S32 y) { #if defined(LL_DARWIN) @@ -247,7 +215,6 @@ void LLUI::setMousePositionScreen(S32 x, S32 y) LLView::getWindow()->setCursorPosition(LLCoordGL(screen_x, screen_y).convert()); } -//static void LLUI::getMousePositionScreen(S32 *x, S32 *y) { LLCoordWindow cursor_pos_window; @@ -257,7 +224,6 @@ void LLUI::getMousePositionScreen(S32 *x, S32 *y) *y = ll_round((F32)cursor_pos_gl.mY / getScaleFactor().mV[VY]); } -//static void LLUI::setMousePositionLocal(const LLView* viewp, S32 x, S32 y) { S32 screen_x, screen_y; @@ -266,7 +232,6 @@ void LLUI::setMousePositionLocal(const LLView* viewp, S32 x, S32 y) setMousePositionScreen(screen_x, screen_y); } -//static void LLUI::getMousePositionLocal(const LLView* viewp, S32 *x, S32 *y) { S32 screen_x, screen_y; @@ -280,20 +245,19 @@ void LLUI::getMousePositionLocal(const LLView* viewp, S32 *x, S32 *y) // or on Windows if the SecondLife.exe executable is run directly, the // language follows the OS language. In all cases the user can override // the language manually in preferences. JC -// static -std::string LLUI::getLanguage() +std::string LLUI::getUILanguage() { std::string language = "en"; - if (sSettingGroups["config"]) + if (mSettingGroups["config"]) { - language = sSettingGroups["config"]->getString("Language"); + language = mSettingGroups["config"]->getString("Language"); if (language.empty() || language == "default") { - language = sSettingGroups["config"]->getString("InstallLanguage"); + language = mSettingGroups["config"]->getString("InstallLanguage"); } if (language.empty() || language == "default") { - language = sSettingGroups["config"]->getString("SystemLanguage"); + language = mSettingGroups["config"]->getString("SystemLanguage"); } if (language.empty() || language == "default") { @@ -303,6 +267,13 @@ std::string LLUI::getLanguage() return language; } +// static +std::string LLUI::getLanguage() +{ + // Note: lldateutil_test redefines this function + return LLUI::getInstance()->getUILanguage(); +} + struct SubDir : public LLInitParam::Block<SubDir> { Mandatory<std::string> value; @@ -362,37 +333,32 @@ std::string LLUI::locateSkin(const std::string& filename) return ""; } -//static LLVector2 LLUI::getWindowSize() { LLCoordWindow window_rect; - sWindow->getSize(&window_rect); + mWindow->getSize(&window_rect); return LLVector2(window_rect.mX / getScaleFactor().mV[VX], window_rect.mY / getScaleFactor().mV[VY]); } -//static void LLUI::screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y) { *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 = ll_round((F32)gl_x / getScaleFactor().mV[VX]); *screen_y = ll_round((F32)gl_y / getScaleFactor().mV[VY]); } -//static void LLUI::screenRectToGL(const LLRect& screen, LLRect *gl) { screenPointToGL(screen.mLeft, screen.mTop, &gl->mLeft, &gl->mTop); screenPointToGL(screen.mRight, screen.mBottom, &gl->mRight, &gl->mBottom); } -//static void LLUI::glRectToScreen(const LLRect& gl, LLRect *screen) { glPointToScreen(gl.mLeft, gl.mTop, &screen->mLeft, &screen->mTop); @@ -402,8 +368,8 @@ void LLUI::glRectToScreen(const LLRect& gl, LLRect *screen) LLControlGroup& LLUI::getControlControlGroup (const std::string& controlname) { - for (settings_map_t::iterator itor = sSettingGroups.begin(); - itor != sSettingGroups.end(); ++itor) + for (settings_map_t::iterator itor = mSettingGroups.begin(); + itor != mSettingGroups.end(); ++itor) { LLControlGroup* control_group = itor->second; if(control_group != NULL) @@ -413,43 +379,38 @@ LLControlGroup& LLUI::getControlControlGroup (const std::string& controlname) } } - return *sSettingGroups["config"]; // default group + return *mSettingGroups["config"]; // default group } -//static void LLUI::addPopup(LLView* viewp) { - if (sAddPopupFunc) + if (mAddPopupFunc) { - sAddPopupFunc(viewp); + mAddPopupFunc(viewp); } } -//static void LLUI::removePopup(LLView* viewp) { - if (sRemovePopupFunc) + if (mRemovePopupFunc) { - sRemovePopupFunc(viewp); + mRemovePopupFunc(viewp); } } -//static void LLUI::clearPopups() { - if (sClearPopupsFunc) + if (mClearPopupsFunc) { - sClearPopupsFunc(); + mClearPopupsFunc(); } } -//static void LLUI::reportBadKeystroke() { make_ui_sound("UISndBadKeystroke"); } - -//static + // spawn_x and spawn_y are top left corner of view in screen GL coordinates void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y) { @@ -460,7 +421,7 @@ void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y) S32 mouse_x; S32 mouse_y; - LLUI::getMousePositionScreen(&mouse_x, &mouse_y); + getMousePositionScreen(&mouse_x, &mouse_y); // If no spawn location provided, use mouse position if (spawn_x == S32_MAX || spawn_y == S32_MAX) @@ -535,6 +496,18 @@ const LLView* LLUI::resolvePath(const LLView* context, const std::string& path) return context; } +//static +LLVector2& LLUI::getScaleFactor() +{ + return LLRender::sUIGLScaleFactor; +} + +//static +void LLUI::setScaleFactor(const LLVector2& scale_factor) +{ + LLRender::sUIGLScaleFactor = scale_factor; +} + // LLLocalClipRect and LLScreenClipRect moved to lllocalcliprect.h/cpp diff --git a/indra/llui/llui.h b/indra/llui/llui.h index d7151dbee9..30dbd7248f 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -33,7 +33,6 @@ #include "llcontrol.h" #include "llcoord.h" #include "llcontrol.h" -#include "llglslshader.h" #include "llinitparam.h" #include "llregistry.h" #include "llrender2dutils.h" @@ -49,7 +48,6 @@ // for initparam specialization #include "llfontgl.h" - class LLUUID; class LLWindow; class LLView; @@ -77,7 +75,8 @@ enum EDragAndDropType DAD_MESH = 15, DAD_WIDGET = 16, DAD_PERSON = 17, - DAD_COUNT = 18, // number of types in this enum + DAD_SETTINGS = 18, + DAD_COUNT = 19, // number of types in this enum }; // Reasons for drags to be denied. @@ -109,8 +108,16 @@ class LLImageProviderInterface; typedef void (*LLUIAudioCallback)(const LLUUID& uuid); -class LLUI +class LLUI : public LLParamSingleton<LLUI> { +public: + typedef std::map<std::string, LLControlGroup*> settings_map_t; + +private: + LLSINGLETON(LLUI , const settings_map_t &settings, + LLImageProviderInterface* image_provider, + LLUIAudioCallback audio_callback, + LLUIAudioCallback deferred_audio_callback); LOG_CLASS(LLUI); public: // @@ -232,36 +239,20 @@ public: // // Methods // - typedef std::map<std::string, LLControlGroup*> settings_map_t; typedef boost::function<void(LLView*)> add_popup_t; typedef boost::function<void(LLView*)> remove_popup_t; typedef boost::function<void(void)> clear_popups_t; - static void initClass(const settings_map_t& settings, - LLImageProviderInterface* image_provider, - LLUIAudioCallback audio_callback = NULL, - LLUIAudioCallback deferred_audio_callback = NULL, - const LLVector2 *scale_factor = NULL, - const std::string& language = LLStringUtil::null); - static void cleanupClass(); - static void setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t&, const clear_popups_t& ); - - static void pushMatrix() { LLRender2D::pushMatrix(); } - static void popMatrix() { LLRender2D::popMatrix(); } - static void loadIdentity() { LLRender2D::loadIdentity(); } - static void translate(F32 x, F32 y, F32 z = 0.0f) { LLRender2D::translate(x, y, z); } - - static LLRect sDirtyRect; - static BOOL sDirty; - static void dirtyRect(LLRect rect); + void setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t&, const clear_popups_t& ); // Return the ISO639 language name ("en", "ko", etc.) for the viewer UI. // http://www.loc.gov/standards/iso639-2/php/code_list.php - static std::string getLanguage(); + std::string getUILanguage(); + static std::string getLanguage(); // static for lldateutil_test compatibility //helper functions (should probably move free standing rendering helper functions here) - static LLView* getRootView() { return sRootView; } - static void setRootView(LLView* view) { sRootView = view; } + LLView* getRootView() { return mRootView; } + void setRootView(LLView* view) { mRootView = view; } /** * Walk the LLView tree to resolve a path * Paths can be discovered using Develop > XUI > Show XUI Paths @@ -287,58 +278,65 @@ public: * tree, the first "bar" anywhere under it, and "baz" * as a direct child of that */ - static const LLView* resolvePath(const LLView* context, const std::string& path); - static LLView* resolvePath(LLView* context, const std::string& path); + const LLView* resolvePath(const LLView* context, const std::string& path); + LLView* resolvePath(LLView* context, const std::string& path); static std::string locateSkin(const std::string& filename); - static void setMousePositionScreen(S32 x, S32 y); - static void getMousePositionScreen(S32 *x, S32 *y); - static void setMousePositionLocal(const LLView* viewp, S32 x, S32 y); - static void getMousePositionLocal(const LLView* viewp, S32 *x, S32 *y); - static LLVector2& getScaleFactor() { return LLRender2D::sGLScaleFactor; } - static void setScaleFactor(const LLVector2& scale_factor) { LLRender2D::setScaleFactor(scale_factor); } - static void setLineWidth(F32 width) { LLRender2D::setLineWidth(width); } - static LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id, S32 priority = 0) - { return LLRender2D::getUIImageByID(image_id, priority); } - static LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0) - { return LLRender2D::getUIImage(name, priority); } - static LLVector2 getWindowSize(); - static void screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y); - static void glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y); - static void screenRectToGL(const LLRect& screen, LLRect *gl); - static void glRectToScreen(const LLRect& gl, LLRect *screen); + void setMousePositionScreen(S32 x, S32 y); + void getMousePositionScreen(S32 *x, S32 *y); + void setMousePositionLocal(const LLView* viewp, S32 x, S32 y); + void getMousePositionLocal(const LLView* viewp, S32 *x, S32 *y); + LLVector2 getWindowSize(); + void screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y); + void glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y); + void screenRectToGL(const LLRect& screen, LLRect *gl); + void glRectToScreen(const LLRect& gl, LLRect *screen); // Returns the control group containing the control name, or the default group - static LLControlGroup& getControlControlGroup (const std::string& controlname); - static F32 getMouseIdleTime() { return sMouseIdleTimer.getElapsedTimeF32(); } - static void resetMouseIdleTimer() { sMouseIdleTimer.reset(); } - static LLWindow* getWindow() { return sWindow; } + LLControlGroup& getControlControlGroup (const std::string& controlname); + F32 getMouseIdleTime() { return mMouseIdleTimer.getElapsedTimeF32(); } + void resetMouseIdleTimer() { mMouseIdleTimer.reset(); } + LLWindow* getWindow() { return mWindow; } - static void addPopup(LLView*); - static void removePopup(LLView*); - static void clearPopups(); + void addPopup(LLView*); + void removePopup(LLView*); + void clearPopups(); - static void reportBadKeystroke(); + void reportBadKeystroke(); // Ensures view does not overlap mouse cursor, but is inside // the view's parent rectangle. Used for tooltips, inspectors. // Optionally override the view's default X/Y, which are relative to the // view's parent. - static void positionViewNearMouse(LLView* view, S32 spawn_x = S32_MAX, S32 spawn_y = S32_MAX); + void positionViewNearMouse(LLView* view, S32 spawn_x = S32_MAX, S32 spawn_y = S32_MAX); + + // LLRender2D wrappers + static void pushMatrix() { LLRender2D::pushMatrix(); } + static void popMatrix() { LLRender2D::popMatrix(); } + static void loadIdentity() { LLRender2D::loadIdentity(); } + static void translate(F32 x, F32 y, F32 z = 0.0f) { LLRender2D::translate(x, y, z); } + + static LLVector2& getScaleFactor(); + static void setScaleFactor(const LLVector2& scale_factor); + static void setLineWidth(F32 width) { LLRender2D::setLineWidth(width); } + static LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id, S32 priority = 0) + { return LLRender2D::getInstance()->getUIImageByID(image_id, priority); } + static LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0) + { return LLRender2D::getInstance()->getUIImage(name, priority); } // // Data // - static settings_map_t sSettingGroups; - static LLUIAudioCallback sAudioCallback; - static LLUIAudioCallback sDeferredAudioCallback; - static LLWindow* sWindow; - static LLView* sRootView; - static LLHelp* sHelpImpl; + settings_map_t mSettingGroups; + LLUIAudioCallback mAudioCallback; + LLUIAudioCallback mDeferredAudioCallback; + LLWindow* mWindow; + LLView* mRootView; + LLHelp* mHelpImpl; private: - static std::vector<std::string> sXUIPaths; - static LLFrameTimer sMouseIdleTimer; - static add_popup_t sAddPopupFunc; - static remove_popup_t sRemovePopupFunc; - static clear_popups_t sClearPopupsFunc; + std::vector<std::string> mXUIPaths; + LLFrameTimer mMouseIdleTimer; + add_popup_t mAddPopupFunc; + remove_popup_t mRemovePopupFunc; + clear_popups_t mClearPopupsFunc; }; @@ -363,7 +361,7 @@ public: LLUICachedControl(const std::string& name, const T& default_value, const std::string& comment = "Declared In Code") - : LLCachedControl<T>(LLUI::getControlControlGroup(name), name, default_value, comment) + : LLCachedControl<T>(LLUI::getInstance()->getControlControlGroup(name), name, default_value, comment) {} }; diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index df74e113e9..5924542a19 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -35,6 +35,7 @@ #include "lluictrlfactory.h" #include "lltabcontainer.h" #include "llaccordionctrltab.h" +#include "lluiusage.h" static LLDefaultChildRegistry::Register<LLUICtrl> r("ui_ctrl"); @@ -137,13 +138,29 @@ void LLUICtrl::initFromParams(const Params& p) { LLControlVariable* control = findControl(p.enabled_controls.enabled); if (control) + { setEnabledControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign 'enabled' control variable to " << getName() + << ": control " << p.enabled_controls.enabled() + << " does not exist." << LL_ENDL; + } } else if(p.enabled_controls.disabled.isChosen()) { LLControlVariable* control = findControl(p.enabled_controls.disabled); if (control) + { setDisabledControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign 'disabled' control variable to " << getName() + << ": control " << p.enabled_controls.disabled() + << " does not exist." << LL_ENDL; + } } } if(p.controls_visibility.isProvided()) @@ -152,13 +169,29 @@ void LLUICtrl::initFromParams(const Params& p) { LLControlVariable* control = findControl(p.controls_visibility.visible); if (control) + { setMakeVisibleControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign visibility control variable to " << getName() + << ": control " << p.controls_visibility.visible() + << " does not exist." << LL_ENDL; + } } else if (p.controls_visibility.invisible.isChosen()) { LLControlVariable* control = findControl(p.controls_visibility.invisible); if (control) + { setMakeInvisibleControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign invisibility control variable to " << getName() + << ": control " << p.controls_visibility.invisible() + << " does not exist." << LL_ENDL; + } } } @@ -250,6 +283,7 @@ LLUICtrl::commit_signal_t::slot_type LLUICtrl::initCommitCallback(const CommitCa else { std::string function_name = cb.function_name; + setFunctionName(function_name); commit_callback_t* func = (CommitCallbackRegistry::getValue(function_name)); if (func) { @@ -390,7 +424,19 @@ BOOL LLUICtrl::canFocusChildren() const void LLUICtrl::onCommit() { if (mCommitSignal) - (*mCommitSignal)(this, getValue()); + { + if (!mFunctionName.empty()) + { + LL_DEBUGS("UIUsage") << "calling commit function " << mFunctionName << LL_ENDL; + LLUIUsage::instance().logCommand(mFunctionName); + LLUIUsage::instance().logControl(getPathname()); + } + else + { + //LL_DEBUGS("UIUsage") << "calling commit function " << "UNKNOWN" << LL_ENDL; + } + (*mCommitSignal)(this, getValue()); + } } //virtual @@ -497,6 +543,11 @@ void LLUICtrl::setControlName(const std::string& control_name, LLView *context) if (!control_name.empty()) { LLControlVariable* control = context->findControl(control_name); + if (!control) + { + LL_WARNS() << "Failed to assign control variable to " << getName() + << ": control "<< control_name << " does not exist." << LL_ENDL; + } setControlVariable(control); } } @@ -560,6 +611,12 @@ void LLUICtrl::setMakeInvisibleControlVariable(LLControlVariable* control) setVisible(!(mMakeInvisibleControlVariable->getValue().asBoolean())); } } + +void LLUICtrl::setFunctionName(const std::string& function_name) +{ + mFunctionName = function_name; +} + // static bool LLUICtrl::controlListener(const LLSD& newvalue, LLHandle<LLUICtrl> handle, std::string type) { @@ -684,8 +741,9 @@ void LLUICtrl::resetDirty() } // virtual -void LLUICtrl::onTabInto() +void LLUICtrl::onTabInto() { + onUpdateScrollToChild(this); } // virtual diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 63baed6793..67dd24341c 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -183,6 +183,8 @@ public: void setMakeVisibleControlVariable(LLControlVariable* control); void setMakeInvisibleControlVariable(LLControlVariable* control); + void setFunctionName(const std::string& function_name); + virtual void setTentative(BOOL b); virtual BOOL getTentative() const; virtual void setValue(const LLSD& value); @@ -213,7 +215,8 @@ public: virtual void setColor(const LLColor4& color); - F32 getCurrentTransparency(); + // Ansariel: Changed to virtual. We might want to change the transparency ourself! + virtual F32 getCurrentTransparency(); void setTransparencyType(ETypeTransparency type); ETypeTransparency getTransparencyType() const {return mTransparencyType;} @@ -309,6 +312,8 @@ protected: LLControlVariable* mMakeInvisibleControlVariable; boost::signals2::connection mMakeInvisibleControlConnection; + std::string mFunctionName; + static F32 sActiveControlTransparency; static F32 sInactiveControlTransparency; diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 03d946f1b7..135ed57a4f 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -37,6 +37,7 @@ #include "llheteromap.h" class LLView; +void deleteView(LLView*); // Inside LLView.cpp, avoid having to potentially delete an incomplete type here. // lookup widget constructor funcs by widget name template <typename DERIVED_TYPE> @@ -160,8 +161,8 @@ public: LLXMLNodePtr root_node; if (!LLUICtrlFactory::getLayeredXMLNode(filename, root_node)) - { - LL_WARNS() << "Couldn't parse XUI file: " << instance().getCurFileName() << LL_ENDL; + { + LL_WARNS() << "Couldn't parse XUI from path: " << instance().getCurFileName() << ", from filename: " << filename << LL_ENDL; goto fail; } @@ -174,14 +175,7 @@ public: { LL_WARNS() << "Widget in " << filename << " was of type " << typeid(view).name() << " instead of expected type " << typeid(T).name() << LL_ENDL; -#if LL_DARWIN -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdelete-incomplete" - delete view; -#pragma clang diagnostic pop -#else - delete view; -#endif + deleteView(view); view = NULL; } } diff --git a/indra/llui/lluiusage.cpp b/indra/llui/lluiusage.cpp new file mode 100644 index 0000000000..ccae6643b9 --- /dev/null +++ b/indra/llui/lluiusage.cpp @@ -0,0 +1,146 @@ +/** +* @file lluiuisage.cpp +* @brief Source file for LLUIUsage +* +* $LicenseInfo:firstyear=2021&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2021, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* 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 "lluiusage.h" +#include <boost/algorithm/string.hpp> + +LLUIUsage::LLUIUsage() +{ +} + +LLUIUsage::~LLUIUsage() +{ +} + +// static +std::string LLUIUsage::sanitized(const std::string& s) +{ + // Remove characters that make the ViewerStats db unhappy + std::string result(s); + std::replace(result.begin(), result.end(), '.', '_'); + std::replace(result.begin(), result.end(), ' ', '_'); + return result; +} + +// static +void LLUIUsage::setLLSDPath(LLSD& sd, const std::string& path, S32 max_elts, const LLSD& val) +{ + // Keep the last max_elts components of the specified path + std::vector<std::string> fields; + boost::split(fields, path, boost::is_any_of("/")); + auto first_pos = std::max(fields.begin(), fields.end() - max_elts); + auto end_pos = fields.end(); + std::vector<std::string> last_fields(first_pos,end_pos); + + setLLSDNested(sd, last_fields, val); +} + +// setLLSDNested() +// Accomplish the equivalent of +// sd[fields[0]][fields[1]]... = val; +// for an arbitrary number of fields. +// This might be useful as an LLSD utility function; is not specific to LLUIUsage +// +// static +void LLUIUsage::setLLSDNested(LLSD& sd, const std::vector<std::string>& fields, const LLSD& val) +{ + LLSD* fsd = &sd; + for (auto it=fields.begin(); it!=fields.end(); ++it) + { + if (it == fields.end()-1) + { + (*fsd)[*it] = val; + } + else + { + if (!(*fsd)[*it].isMap()) + { + (*fsd)[*it] = LLSD::emptyMap(); + } + fsd = &(*fsd)[*it]; + } + } +} + +void LLUIUsage::logCommand(const std::string& command) +{ + mCommandCounts[sanitized(command)]++; + LL_DEBUGS("UIUsage") << "command " << command << LL_ENDL; +} + +void LLUIUsage::logControl(const std::string& control) +{ + mControlCounts[sanitized(control)]++; + LL_DEBUGS("UIUsage") << "control " << control << LL_ENDL; +} + + +void LLUIUsage::logFloater(const std::string& floater) +{ + mFloaterCounts[sanitized(floater)]++; + LL_DEBUGS("UIUsage") << "floater " << floater << LL_ENDL; +} + +void LLUIUsage::logPanel(const std::string& p) +{ + mPanelCounts[sanitized(p)]++; + LL_DEBUGS("UIUsage") << "panel " << p << LL_ENDL; +} + +LLSD LLUIUsage::asLLSD() const +{ + LLSD result; + for (auto const& it : mCommandCounts) + { + result["commands"][it.first] = LLSD::Integer(it.second); + } + for (auto const& it : mControlCounts) + { + setLLSDPath(result["controls"], it.first, 2, LLSD::Integer(it.second)); + } + for (auto const& it : mFloaterCounts) + { + result["floaters"][it.first] = LLSD::Integer(it.second); + } + for (auto const& it : mPanelCounts) + { + result["panels"][it.first] = LLSD::Integer(it.second); + } + return result; +} + +// Clear up some junk content generated during initial login/UI initialization +void LLUIUsage::clear() +{ + + LL_DEBUGS("UIUsage") << "clear" << LL_ENDL; + mCommandCounts.clear(); + mControlCounts.clear(); + mFloaterCounts.clear(); + mPanelCounts.clear(); +} + diff --git a/indra/llui/lluiusage.h b/indra/llui/lluiusage.h new file mode 100644 index 0000000000..a30cd80db3 --- /dev/null +++ b/indra/llui/lluiusage.h @@ -0,0 +1,57 @@ +/** +* @file lluiuisage.h +* @brief Header file for LLUIUsage +* +* $LicenseInfo:firstyear=2021&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2021, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* 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_LLUIUSAGE_H +#define LL_LLUIUSAGE_H + +#include <map> +#include "llsd.h" +#include "llsingleton.h" + +// UIUsage tracking to see which operations and UI elements are most popular in a session +class LLUIUsage : public LLSingleton<LLUIUsage> +{ +public: + LLSINGLETON(LLUIUsage); + ~LLUIUsage(); +public: + static std::string sanitized(const std::string& s); + static void setLLSDPath(LLSD& sd, const std::string& path, S32 max_elts, const LLSD& val); + static void setLLSDNested(LLSD& sd, const std::vector<std::string>& fields, const LLSD& val); + void logCommand(const std::string& command); + void logControl(const std::string& control); + void logFloater(const std::string& floater); + void logPanel(const std::string& p); + LLSD asLLSD() const; + void clear(); +private: + std::map<std::string,U32> mCommandCounts; + std::map<std::string,U32> mControlCounts; + std::map<std::string,U32> mFloaterCounts; + std::map<std::string,U32> mPanelCounts; +}; + +#endif // LLUIUIUSAGE.h diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index cd9b52d164..e43c52c0c2 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -176,7 +176,7 @@ void LLUrlEntryBase::callObservers(const std::string &id, bool LLUrlEntryBase::isLinkDisabled() const { // this allows us to have a global setting to turn off text hyperlink highlighting/action - bool globally_disabled = LLUI::sSettingGroups["config"]->getBOOL("DisableTextHyperlinkActions"); + static LLCachedControl<bool> globally_disabled(*LLUI::getInstance()->mSettingGroups["config"], "DisableTextHyperlinkActions", false); return globally_disabled; } @@ -454,13 +454,19 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const } // -// LLUrlEntrySeconlifeURL Describes *secondlife.com/ and *lindenlab.com/ urls to substitute icon 'hand.png' before link +// LLUrlEntrySeconlifeURL Describes *secondlife.com/ *lindenlab.com/ *secondlifegrid.net/ and *tilia-inc.com/ urls to substitute icon 'hand.png' before link // LLUrlEntrySecondlifeURL::LLUrlEntrySecondlifeURL() { - mPattern = boost::regex("((http://([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com)" + mPattern = boost::regex("((http://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com)" "|" - "(https://([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(:\\d{1,5})?))" + "(http://([-\\w\\.]*\\.)?secondlifegrid\\.net)" + "|" + "(https://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com(:\\d{1,5})?)" + "|" + "(https://([-\\w\\.]*\\.)?secondlifegrid\\.net(:\\d{1,5})?)" + "|" + "(https?://([-\\w\\.]*\\.)?secondlife\\.io(:\\d{1,5})?))" "\\/\\S*", boost::regex::perl|boost::regex::icase); @@ -495,12 +501,14 @@ std::string LLUrlEntrySecondlifeURL::getTooltip(const std::string &url) const } // -// LLUrlEntrySimpleSecondlifeURL Describes *secondlife.com and *lindenlab.com urls to substitute icon 'hand.png' before link +// LLUrlEntrySimpleSecondlifeURL Describes *secondlife.com *lindenlab.com *secondlifegrid.net and *tilia-inc.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); + mPattern = boost::regex("https?://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com(?!\\S)" + "|" + "https?://([-\\w\\.]*\\.)?secondlifegrid\\.net(?!\\S)", + boost::regex::perl|boost::regex::icase); mIcon = "Hand"; mMenuName = "menu_url_http.xml"; @@ -511,8 +519,7 @@ LLUrlEntrySimpleSecondlifeURL::LLUrlEntrySimpleSecondlifeURL() // secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about // x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about // -LLUrlEntryAgent::LLUrlEntryAgent() : - mAvatarNameCacheConnection() +LLUrlEntryAgent::LLUrlEntryAgent() { mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/\\w+", boost::regex::perl|boost::regex::icase); @@ -543,7 +550,15 @@ void LLUrlEntryAgent::callObservers(const std::string &id, void LLUrlEntryAgent::onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name) { - mAvatarNameCacheConnection.disconnect(); + 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); + } std::string label = av_name.getCompleteName(); @@ -630,11 +645,17 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa } else { - if (mAvatarNameCacheConnection.connected()) + avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(agent_id); + if (it != mAvatarNameCacheConnections.end()) { - mAvatarNameCacheConnection.disconnect(); + if (it->second.connected()) + { + it->second.disconnect(); + } + mAvatarNameCacheConnections.erase(it); } - mAvatarNameCacheConnection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2)); + mAvatarNameCacheConnections[agent_id] = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2)); + addObserver(agent_id_string, url, cb); return LLTrans::getString("LoadingData"); } @@ -695,14 +716,21 @@ std::string LLUrlEntryAgent::getIcon(const std::string &url) // 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) // -LLUrlEntryAgentName::LLUrlEntryAgentName() : - mAvatarNameCacheConnection() +LLUrlEntryAgentName::LLUrlEntryAgentName() {} void LLUrlEntryAgentName::onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name) { - mAvatarNameCacheConnection.disconnect(); + 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); + } std::string label = getName(av_name); // received the agent name from the server - tell our observers @@ -737,11 +765,17 @@ std::string LLUrlEntryAgentName::getLabel(const std::string &url, const LLUrlLab } else { - if (mAvatarNameCacheConnection.connected()) + avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(agent_id); + if (it != mAvatarNameCacheConnections.end()) { - mAvatarNameCacheConnection.disconnect(); + if (it->second.connected()) + { + it->second.disconnect(); + } + mAvatarNameCacheConnections.erase(it); } - mAvatarNameCacheConnection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2)); + mAvatarNameCacheConnections[agent_id] = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2)); + addObserver(agent_id_string, url, cb); return LLTrans::getString("LoadingData"); } @@ -1095,7 +1129,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("secondlife:///app/region/[A-Za-z0-9()_%]+(/\\d+)?(/\\d+)?(/\\d+)?/?", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_slurl.xml"; mTooltip = LLTrans::getString("TooltipSLURL"); @@ -1475,4 +1509,43 @@ void LLUrlEntryExperienceProfile::onExperienceDetails( const LLSD& experience_de callObservers(experience_details[LLExperienceCache::EXPERIENCE_ID].asString(), name, LLStringUtil::null); } +// +// LLUrlEntryEmail Describes an IPv6 address +// +LLUrlEntryIPv6::LLUrlEntryIPv6() + : LLUrlEntryBase() +{ + mHostPath = "https?://\\[([a-f0-9:]+:+)+[a-f0-9]+]"; + mPattern = boost::regex(mHostPath + "(:\\d{1,5})?(/\\S*)?", + boost::regex::perl | boost::regex::icase); + mMenuName = "menu_url_http.xml"; + mTooltip = LLTrans::getString("TooltipHttpUrl"); +} + +std::string LLUrlEntryIPv6::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + boost::regex regex = boost::regex(mHostPath, boost::regex::perl | boost::regex::icase); + boost::match_results<std::string::const_iterator> matches; + + if (boost::regex_search(url, matches, regex)) + { + return url.substr(0, matches[0].length()); + } + else + { + return url; + } +} +std::string LLUrlEntryIPv6::getQuery(const std::string &url) const +{ + boost::regex regex = boost::regex(mHostPath, boost::regex::perl | boost::regex::icase); + boost::match_results<std::string::const_iterator> matches; + + return boost::regex_replace(url, regex, ""); +} + +std::string LLUrlEntryIPv6::getUrl(const std::string &string) const +{ + return string; +} diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 78c149d9fd..4af1ab5096 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -212,10 +212,14 @@ public: LLUrlEntryAgent(); ~LLUrlEntryAgent() { - 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(); } /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); /*virtual*/ std::string getIcon(const std::string &url); @@ -227,7 +231,9 @@ protected: /*virtual*/ void callObservers(const std::string &id, const std::string &label, const std::string& icon); private: void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name); - boost::signals2::connection mAvatarNameCacheConnection; + + typedef std::map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t; + avatar_name_cache_connection_map_t mAvatarNameCacheConnections; }; /// @@ -241,10 +247,14 @@ public: LLUrlEntryAgentName(); ~LLUrlEntryAgentName() { - 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(); } /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); /*virtual*/ LLStyle::Params getStyle() const; @@ -253,7 +263,9 @@ protected: virtual std::string getName(const LLAvatarName& avatar_name) = 0; private: void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name); - boost::signals2::connection mAvatarNameCacheConnection; + + typedef std::map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t; + avatar_name_cache_connection_map_t mAvatarNameCacheConnections; }; @@ -513,5 +525,18 @@ public: /*virtual*/ std::string getUrl(const std::string &string) const; }; +/// +/// LLUrlEntryEmail Describes an IPv6 address +/// +class LLUrlEntryIPv6 : public LLUrlEntryBase +{ +public: + LLUrlEntryIPv6(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getUrl(const std::string &string) const; + /*virtual*/ std::string getQuery(const std::string &url) const; + + std::string mHostPath; +}; #endif diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index ba6fa1e2e9..321a0ec5b9 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -79,6 +79,7 @@ LLUrlRegistry::LLUrlRegistry() mUrlEntrySLLabel = new LLUrlEntrySLLabel(); registerUrl(mUrlEntrySLLabel); registerUrl(new LLUrlEntryEmail()); + registerUrl(new LLUrlEntryIPv6()); } LLUrlRegistry::~LLUrlRegistry() diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 40537e6c4a..2781c991a7 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -60,6 +60,8 @@ static const S32 LINE_HEIGHT = 15; S32 LLView::sDepth = 0; bool LLView::sDebugRects = false; +bool LLView::sIsRectDirty = false; +LLRect LLView::sDirtyRect; bool LLView::sDebugRectsShowNames = true; bool LLView::sDebugKeys = false; bool LLView::sDebugMouseHandling = false; @@ -86,6 +88,11 @@ template class LLView* LLView::getChild<class LLView>( static LLDefaultChildRegistry::Register<LLView> r("view"); +void deleteView(LLView *aView) +{ + delete aView; +} + namespace LLInitParam { void TypeValues<LLView::EOrientation>::declareValues() @@ -641,6 +648,16 @@ void LLView::onVisibilityChange ( BOOL new_visibility ) } // virtual +void LLView::onUpdateScrollToChild(const LLUICtrl * cntrl) +{ + LLView* parent_view = getParent(); + if (parent_view) + { + parent_view->onUpdateScrollToChild(cntrl); + } +} + +// virtual void LLView::translate(S32 x, S32 y) { mRect.translate(x, y); @@ -816,7 +833,7 @@ LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask) } // This call differentiates this method from childrenHandleMouseEvent(). - LLUI::sWindow->setCursor(viewp->getHoverCursor()); + LLUI::getInstance()->mWindow->setCursor(viewp->getHoverCursor()); if (viewp->handleHover(local_x, local_y, mask) || viewp->blockMouseEvent(local_x, local_y)) @@ -870,15 +887,23 @@ BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask) std::string tooltip = getToolTip(); if (!tooltip.empty()) { + static LLCachedControl<F32> tooltip_fast_delay(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipFastDelay", 0.1f); + static LLCachedControl<F32> tooltip_delay(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipDelay", 0.7f); + static LLCachedControl<bool> allow_ui_tooltips(*LLUI::getInstance()->mSettingGroups["config"], "BasicUITooltips", true); // allow "scrubbing" over ui by showing next tooltip immediately // if previous one was still visible F32 timeout = LLToolTipMgr::instance().toolTipVisible() - ? LLUI::sSettingGroups["config"]->getF32( "ToolTipFastDelay" ) - : LLUI::sSettingGroups["config"]->getF32( "ToolTipDelay" ); - LLToolTipMgr::instance().show(LLToolTip::Params() - .message(tooltip) - .sticky_rect(calcScreenRect()) - .delay_time(timeout)); + ? tooltip_fast_delay + : tooltip_delay; + + // Even if we don't show tooltips, consume the event, nothing below should show tooltip + if (allow_ui_tooltips) + { + LLToolTipMgr::instance().show(LLToolTip::Params() + .message(tooltip) + .sticky_rect(calcScreenRect()) + .delay_time(timeout)); + } handled = TRUE; } @@ -1054,6 +1079,11 @@ BOOL LLView::handleScrollWheel(S32 x, S32 y, S32 clicks) return childrenHandleScrollWheel( x, y, clicks ) != NULL; } +BOOL LLView::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + return childrenHandleScrollHWheel( x, y, clicks ) != NULL; +} + BOOL LLView::handleRightMouseDown(S32 x, S32 y, MASK mask) { return childrenHandleRightMouseDown( x, y, mask ) != NULL; @@ -1079,6 +1109,11 @@ LLView* LLView::childrenHandleScrollWheel(S32 x, S32 y, S32 clicks) return childrenHandleMouseEvent(&LLView::handleScrollWheel, x, y, clicks, false); } +LLView* LLView::childrenHandleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + return childrenHandleMouseEvent(&LLView::handleScrollHWheel, x, y, clicks, false); +} + // Called during downward traversal LLView* LLView::childrenHandleKey(KEY key, MASK mask) { @@ -1142,7 +1177,7 @@ void LLView::drawChildren() { if (!mChildList.empty()) { - LLView* rootp = LLUI::getRootView(); + LLView* rootp = LLUI::getInstance()->getRootView(); ++sDepth; for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend();) // ++child_iter) @@ -1158,7 +1193,7 @@ void LLView::drawChildren() if (viewp->getVisible() && viewp->getRect().isValid()) { LLRect screen_rect = viewp->calcScreenRect(); - if ( rootp->getLocalRect().overlaps(screen_rect) && LLUI::sDirtyRect.overlaps(screen_rect)) + if ( rootp->getLocalRect().overlaps(screen_rect) && sDirtyRect.overlaps(screen_rect)) { LLUI::pushMatrix(); { @@ -1200,7 +1235,15 @@ void LLView::dirtyRect() parent = parent->getParent(); } - LLUI::dirtyRect(cur->calcScreenRect()); + if (!sIsRectDirty) + { + sDirtyRect = cur->calcScreenRect(); + sIsRectDirty = true; + } + else + { + sDirtyRect.unionWith(cur->calcScreenRect()); + } } //Draw a box for debugging. @@ -1371,7 +1414,9 @@ 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 ); - if (child_rect.getWidth() != viewp->getRect().getWidth() || child_rect.getHeight() != viewp->getRect().getHeight()) + if (child_rect.getWidth() != viewp->getRect().getWidth() + || child_rect.getHeight() != viewp->getRect().getHeight() + || sForceReshape) { viewp->reshape(child_rect.getWidth(), child_rect.getHeight()); } @@ -2223,9 +2268,9 @@ LLControlVariable *LLView::findControl(const std::string& name) std::string control_group_key = name.substr(0, key_pos); LLControlVariable* control; // check if it's in the control group that name indicated - if(LLUI::sSettingGroups[control_group_key]) + if(LLUI::getInstance()->mSettingGroups[control_group_key]) { - control = LLUI::sSettingGroups[control_group_key]->getControl(name); + control = LLUI::getInstance()->mSettingGroups[control_group_key]->getControl(name); if (control) { return control; @@ -2233,7 +2278,7 @@ LLControlVariable *LLView::findControl(const std::string& name) } } - LLControlGroup& control_group = LLUI::getControlControlGroup(name); + LLControlGroup& control_group = LLUI::getInstance()->getControlControlGroup(name); return control_group.getControl(name); } diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 8494bb338a..c60dcf3344 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -301,6 +301,7 @@ public: virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); virtual void onVisibilityChange ( BOOL new_visibility ); + virtual void onUpdateScrollToChild(const LLUICtrl * cntrl); void pushVisible(BOOL visible) { mLastVisible = mVisible; setVisible(visible); } void popVisible() { setVisible(mLastVisible); } @@ -426,6 +427,7 @@ public: /*virtual*/ BOOL handleMiddleMouseDown(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 handleScrollHWheel(S32 x, S32 y, S32 clicks); /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); @@ -498,7 +500,7 @@ public: // return query for iterating over focus roots in tab order static const LLViewQuery & getFocusRootsQuery(); - static LLWindow* getWindow(void) { return LLUI::sWindow; } + static LLWindow* getWindow(void) { return LLUI::getInstance()->mWindow; } // Set up params after XML load before calling new(), // usually to adjust layout. @@ -556,6 +558,7 @@ protected: LLView* childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask); LLView* childrenHandleDoubleClick(S32 x, S32 y, MASK mask); LLView* childrenHandleScrollWheel(S32 x, S32 y, S32 clicks); + LLView* childrenHandleScrollHWheel(S32 x, S32 y, S32 clicks); LLView* childrenHandleRightMouseDown(S32 x, S32 y, MASK mask); LLView* childrenHandleRightMouseUp(S32 x, S32 y, MASK mask); LLView* childrenHandleToolTip(S32 x, S32 y, MASK mask); @@ -654,6 +657,9 @@ public: // Draw debug rectangles around widgets to help with alignment and spacing static bool sDebugRects; + static bool sIsRectDirty; + static LLRect sDirtyRect; + // Draw widget names and sizes when drawing debug rectangles, turning this // off is useful to make the rectangles themselves easier to see. static bool sDebugRectsShowNames; diff --git a/indra/llui/llviewereventrecorder.cpp b/indra/llui/llviewereventrecorder.cpp index 8754cfebbb..cb000aef74 100644 --- a/indra/llui/llviewereventrecorder.cpp +++ b/indra/llui/llviewereventrecorder.cpp @@ -44,7 +44,7 @@ LLViewerEventRecorder::LLViewerEventRecorder() { bool LLViewerEventRecorder::displayViewerEventRecorderMenuItems() { - return LLUI::sSettingGroups["config"]->getBOOL("ShowEventRecorderMenuItems"); + return LLUI::getInstance()->mSettingGroups["config"]->getBOOL("ShowEventRecorderMenuItems"); } @@ -99,7 +99,7 @@ void LLViewerEventRecorder::setMouseGlobalCoords(S32 x, S32 y) { void LLViewerEventRecorder::updateMouseEventInfo(S32 local_x, S32 local_y, S32 global_x, S32 global_y, std::string mName) { - LLView * target_view = LLUI::resolvePath(LLUI::getRootView(), xui); + LLView * target_view = LLUI::getInstance()->resolvePath(LLUI::getInstance()->getRootView(), xui); if (! target_view) { LL_DEBUGS() << "LLViewerEventRecorder::updateMouseEventInfo - xui path on file at moment is NOT valid - so DO NOT record these local coords" << LL_ENDL; return; @@ -216,7 +216,7 @@ void LLViewerEventRecorder::playbackRecording() { LLSD LeapCommand; // ivita sets this on startup, it also sends commands to the viewer to make start, stop, and playback menu items visible in viewer - LeapCommand =LLUI::sSettingGroups["config"]->getLLSD("LeapPlaybackEventsCommand"); + LeapCommand =LLUI::getInstance()->mSettingGroups["config"]->getLLSD("LeapPlaybackEventsCommand"); LL_DEBUGS() << "[VITA] launching playback - leap command is: " << LLSDXMLStreamer(LeapCommand) << LL_ENDL; LLLeap::create("", LeapCommand, false); // exception=false diff --git a/indra/llui/llviewinject.h b/indra/llui/llviewinject.h index 0de3d155c4..7f18ec6fbe 100644 --- a/indra/llui/llviewinject.h +++ b/indra/llui/llviewinject.h @@ -32,7 +32,7 @@ namespace llview public: /** * Construct TargetEvent with the desired target LLView*. (See - * LLUI::resolvePath() to obtain an LLView* given a string pathname.) + * LLUI::getInstance()->resolvePath() to obtain an LLView* given a string pathname.) * This sets up for operator(). */ TargetEvent(LLView* view); diff --git a/indra/llui/llvirtualtrackball.cpp b/indra/llui/llvirtualtrackball.cpp new file mode 100644 index 0000000000..6e0aef740d --- /dev/null +++ b/indra/llui/llvirtualtrackball.cpp @@ -0,0 +1,520 @@ +/** +* @file LLVirtualTrackball.cpp +* @author Andrey Lihatskiy +* @brief Implementation for LLVirtualTrackball +* +* $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$ +*/ + +// A control for positioning the sun and the moon in the celestial sphere. + +#include "linden_common.h" +#include "llvirtualtrackball.h" +#include "llstring.h" +#include "llrect.h" +#include "lluictrlfactory.h" +#include "llrender.h" + +// Globals +static LLDefaultChildRegistry::Register<LLVirtualTrackball> register_virtual_trackball("sun_moon_trackball"); + +const LLVector3 VectorZero(1.0f, 0.0f, 0.0f); + +LLVirtualTrackball::Params::Params() + : border("border"), + image_moon_back("image_moon_back"), + image_moon_front("image_moon_front"), + image_sphere("image_sphere"), + image_sun_back("image_sun_back"), + image_sun_front("image_sun_front"), + btn_rotate_top("button_rotate_top"), + btn_rotate_bottom("button_rotate_bottom"), + btn_rotate_left("button_rotate_left"), + btn_rotate_right("button_rotate_right"), + thumb_mode("thumb_mode"), + lbl_N("labelN"), + lbl_S("labelS"), + lbl_W("labelW"), + lbl_E("labelE"), + increment_angle_mouse("increment_angle_mouse", 0.5f), + increment_angle_btn("increment_angle_btn", 3.0f) +{ +} + +LLVirtualTrackball::LLVirtualTrackball(const LLVirtualTrackball::Params& p) + : LLUICtrl(p), + mImgMoonBack(p.image_moon_back), + mImgMoonFront(p.image_moon_front), + mImgSunBack(p.image_sun_back), + mImgSunFront(p.image_sun_front), + mImgSphere(p.image_sphere), + mThumbMode(p.thumb_mode() == "moon" ? ThumbMode::MOON : ThumbMode::SUN), + mIncrementMouse(DEG_TO_RAD * p.increment_angle_mouse()), + mIncrementBtn(DEG_TO_RAD * p.increment_angle_btn()) +{ + LLRect border_rect = getLocalRect(); + S32 centerX = border_rect.getCenterX(); + S32 centerY = border_rect.getCenterY(); + U32 btn_size = 32; // width & height + U32 axis_offset_lt = 16; // offset from the axis for left/top sides + U32 axis_offset_rb = btn_size - axis_offset_lt; // and for right/bottom + + LLViewBorder::Params border = p.border; + border.rect(border_rect); + mBorder = LLUICtrlFactory::create<LLViewBorder>(border); + addChild(mBorder); + + + LLButton::Params btn_rt = p.btn_rotate_top; + btn_rt.rect(LLRect(centerX - axis_offset_lt, border_rect.mTop, centerX + axis_offset_rb, border_rect.mTop - btn_size)); + btn_rt.click_callback.function(boost::bind(&LLVirtualTrackball::onRotateTopClick, this)); + btn_rt.mouse_held_callback.function(boost::bind(&LLVirtualTrackball::onRotateTopClick, this)); + btn_rt.mouseenter_callback.function(boost::bind(&LLVirtualTrackball::onRotateTopMouseEnter, this)); + mBtnRotateTop = LLUICtrlFactory::create<LLButton>(btn_rt); + addChild(mBtnRotateTop); + + LLTextBox::Params lbl_N = p.lbl_N; + LLRect rect_N = btn_rt.rect; + //rect_N.translate(btn_rt.rect().getWidth(), 0); + lbl_N.rect = rect_N; + lbl_N.initial_value(lbl_N.label()); + mLabelN = LLUICtrlFactory::create<LLTextBox>(lbl_N); + addChild(mLabelN); + + + LLButton::Params btn_rr = p.btn_rotate_right; + btn_rr.rect(LLRect(border_rect.mRight - btn_size, centerY + axis_offset_lt, border_rect.mRight, centerY - axis_offset_rb)); + btn_rr.click_callback.function(boost::bind(&LLVirtualTrackball::onRotateRightClick, this)); + btn_rr.mouse_held_callback.function(boost::bind(&LLVirtualTrackball::onRotateRightClick, this)); + btn_rr.mouseenter_callback.function(boost::bind(&LLVirtualTrackball::onRotateRightMouseEnter, this)); + mBtnRotateRight = LLUICtrlFactory::create<LLButton>(btn_rr); + addChild(mBtnRotateRight); + + LLTextBox::Params lbl_E = p.lbl_E; + LLRect rect_E = btn_rr.rect; + //rect_E.translate(0, -1 * btn_rr.rect().getHeight()); + lbl_E.rect = rect_E; + lbl_E.initial_value(lbl_E.label()); + mLabelE = LLUICtrlFactory::create<LLTextBox>(lbl_E); + addChild(mLabelE); + + + LLButton::Params btn_rb = p.btn_rotate_bottom; + btn_rb.rect(LLRect(centerX - axis_offset_lt, border_rect.mBottom + btn_size, centerX + axis_offset_rb, border_rect.mBottom)); + btn_rb.click_callback.function(boost::bind(&LLVirtualTrackball::onRotateBottomClick, this)); + btn_rb.mouse_held_callback.function(boost::bind(&LLVirtualTrackball::onRotateBottomClick, this)); + btn_rb.mouseenter_callback.function(boost::bind(&LLVirtualTrackball::onRotateBottomMouseEnter, this)); + mBtnRotateBottom = LLUICtrlFactory::create<LLButton>(btn_rb); + addChild(mBtnRotateBottom); + + LLTextBox::Params lbl_S = p.lbl_S; + LLRect rect_S = btn_rb.rect; + //rect_S.translate(btn_rb.rect().getWidth(), 0); + lbl_S.rect = rect_S; + lbl_S.initial_value(lbl_S.label()); + mLabelS = LLUICtrlFactory::create<LLTextBox>(lbl_S); + addChild(mLabelS); + + + LLButton::Params btn_rl = p.btn_rotate_left; + btn_rl.rect(LLRect(border_rect.mLeft, centerY + axis_offset_lt, border_rect.mLeft + btn_size, centerY - axis_offset_rb)); + btn_rl.click_callback.function(boost::bind(&LLVirtualTrackball::onRotateLeftClick, this)); + btn_rl.mouse_held_callback.function(boost::bind(&LLVirtualTrackball::onRotateLeftClick, this)); + btn_rl.mouseenter_callback.function(boost::bind(&LLVirtualTrackball::onRotateLeftMouseEnter, this)); + mBtnRotateLeft = LLUICtrlFactory::create<LLButton>(btn_rl); + addChild(mBtnRotateLeft); + + LLTextBox::Params lbl_W = p.lbl_W; + LLRect rect_W = btn_rl.rect; + //rect_W.translate(0, -1* btn_rl.rect().getHeight()); + lbl_W.rect = rect_W; + lbl_W.initial_value(lbl_W.label()); + mLabelW = LLUICtrlFactory::create<LLTextBox>(lbl_W); + addChild(mLabelW); + + + LLPanel::Params touch_area; + touch_area.rect = LLRect(centerX - mImgSphere->getWidth() / 2, + centerY + mImgSphere->getHeight() / 2, + centerX + mImgSphere->getWidth() / 2, + centerY - mImgSphere->getHeight() / 2); + mTouchArea = LLUICtrlFactory::create<LLPanel>(touch_area); + addChild(mTouchArea); +} + +LLVirtualTrackball::~LLVirtualTrackball() +{ +} + +BOOL LLVirtualTrackball::postBuild() +{ + return TRUE; +} + + +void LLVirtualTrackball::drawThumb(S32 x, S32 y, ThumbMode mode, bool upperHemi) +{ + LLUIImage* thumb; + if (mode == ThumbMode::SUN) + { + if (upperHemi) + { + thumb = mImgSunFront; + } + else + { + thumb = mImgSunBack; + } + } + else + { + if (upperHemi) + { + thumb = mImgMoonFront; + } + else + { + thumb = mImgMoonBack; + } + } + thumb->draw(LLRect(x - thumb->getWidth() / 2, + y + thumb->getHeight() / 2, + x + thumb->getWidth() / 2, + y - thumb->getHeight() / 2)); +} + +bool LLVirtualTrackball::pointInTouchCircle(S32 x, S32 y) const +{ + S32 centerX = mTouchArea->getRect().getCenterX(); + S32 centerY = mTouchArea->getRect().getCenterY(); + + bool in_circle = pow(x - centerX, 2) + pow(y - centerY, 2) <= pow(mTouchArea->getRect().getWidth() / 2, 2); + return in_circle; +} + +void LLVirtualTrackball::draw() +{ + LLVector3 draw_point = VectorZero * mValue; + + S32 halfwidth = mTouchArea->getRect().getWidth() / 2; + S32 halfheight = mTouchArea->getRect().getHeight() / 2; + draw_point.mV[VX] = (draw_point.mV[VX] + 1.0) * halfwidth + mTouchArea->getRect().mLeft; + draw_point.mV[VY] = (draw_point.mV[VY] + 1.0) * halfheight + mTouchArea->getRect().mBottom; + bool upper_hemisphere = (draw_point.mV[VZ] >= 0.f); + + mImgSphere->draw(mTouchArea->getRect(), upper_hemisphere ? UI_VERTEX_COLOR : UI_VERTEX_COLOR % 0.5f); + drawThumb(draw_point.mV[VX], draw_point.mV[VY], mThumbMode, upper_hemisphere); + + + if (LLView::sDebugRects) + { + gGL.color4fv(LLColor4::red.mV); + gl_circle_2d(mTouchArea->getRect().getCenterX(), mTouchArea->getRect().getCenterY(), mImgSphere->getWidth() / 2, 60, false); + gl_circle_2d(draw_point.mV[VX], draw_point.mV[VY], mImgSunFront->getWidth() / 2, 12, false); + } + + // hide the direction labels when disabled + BOOL enabled = isInEnabledChain(); + mLabelN->setVisible(enabled); + mLabelE->setVisible(enabled); + mLabelS->setVisible(enabled); + mLabelW->setVisible(enabled); + + LLView::draw(); +} + +void LLVirtualTrackball::onRotateTopClick() +{ + if (getEnabled()) + { + LLQuaternion delta; + delta.setAngleAxis(mIncrementBtn, 1, 0, 0); + mValue *= delta; + setValueAndCommit(mValue); + + make_ui_sound("UISndClick"); + } +} + +void LLVirtualTrackball::onRotateBottomClick() +{ + if (getEnabled()) + { + LLQuaternion delta; + delta.setAngleAxis(mIncrementBtn, -1, 0, 0); + mValue *= delta; + setValueAndCommit(mValue); + + make_ui_sound("UISndClick"); + } +} + +void LLVirtualTrackball::onRotateLeftClick() +{ + if (getEnabled()) + { + LLQuaternion delta; + delta.setAngleAxis(mIncrementBtn, 0, 1, 0); + mValue *= delta; + setValueAndCommit(mValue); + + make_ui_sound("UISndClick"); + } +} + +void LLVirtualTrackball::onRotateRightClick() +{ + if (getEnabled()) + { + LLQuaternion delta; + delta.setAngleAxis(mIncrementBtn, 0, -1, 0); + mValue *= delta; + setValueAndCommit(mValue); + + make_ui_sound("UISndClick"); + } +} + +void LLVirtualTrackball::onRotateTopMouseEnter() +{ + mBtnRotateTop->setHighlight(true); +} + +void LLVirtualTrackball::onRotateBottomMouseEnter() +{ + mBtnRotateBottom->setHighlight(true); +} + +void LLVirtualTrackball::onRotateLeftMouseEnter() +{ + mBtnRotateLeft->setHighlight(true); +} + +void LLVirtualTrackball::onRotateRightMouseEnter() +{ + mBtnRotateRight->setHighlight(true); +} + +void LLVirtualTrackball::setValue(const LLSD& value) +{ + if (value.isArray() && value.size() == 4) + { + mValue.setValue(value); + } +} + +void LLVirtualTrackball::setRotation(const LLQuaternion &value) +{ + mValue = value; +} + +void LLVirtualTrackball::setValue(F32 x, F32 y, F32 z, F32 w) +{ + mValue.set(x, y, z, w); +} + +void LLVirtualTrackball::setValueAndCommit(const LLQuaternion &value) +{ + mValue = value; + onCommit(); +} + +LLSD LLVirtualTrackball::getValue() const +{ + return mValue.getValue(); +} + +LLQuaternion LLVirtualTrackball::getRotation() const +{ + return mValue; +} + +// static +void LLVirtualTrackball::getAzimuthAndElevation(const LLQuaternion &quat, F32 &azimuth, F32 &elevation) +{ + // LLQuaternion has own function to get azimuth, but it doesn't appear to return correct values (meant for 2d?) + LLVector3 point = VectorZero * quat; + + if (!is_approx_zero(point.mV[VX]) || !is_approx_zero(point.mV[VY])) + { + azimuth = atan2f(point.mV[VX], point.mV[VY]); + } + else + { + azimuth = 0; + } + + azimuth -= F_PI_BY_TWO; + + if (azimuth < 0) + { + azimuth += F_PI * 2; + } + + // while vector is '1', F32 is not sufficiently precise and we can get + // values like 1.0000012 which will result in -90deg angle instead of 90deg + F32 z = llclamp(point.mV[VZ], -1.f, 1.f); + elevation = asin(z); // because VectorZero's length is '1' +} + +// static +void LLVirtualTrackball::getAzimuthAndElevationDeg(const LLQuaternion &quat, F32 &azimuth, F32 &elevation) +{ + getAzimuthAndElevation(quat, azimuth, elevation); + azimuth *= RAD_TO_DEG; + elevation *= RAD_TO_DEG; +} + +BOOL LLVirtualTrackball::handleHover(S32 x, S32 y, MASK mask) +{ + if (hasMouseCapture()) + { + if (mDragMode == DRAG_SCROLL) + { // trackball (move to roll) mode + LLQuaternion delta; + + F32 rotX = x - mPrevX; + F32 rotY = y - mPrevY; + + if (abs(rotX) > 1) + { + F32 direction = (rotX < 0) ? -1 : 1; + delta.setAngleAxis(mIncrementMouse * abs(rotX), 0, direction, 0); // changing X - rotate around Y axis + mValue *= delta; + } + + if (abs(rotY) > 1) + { + F32 direction = (rotY < 0) ? 1 : -1; // reverse for Y (value increases from bottom to top) + delta.setAngleAxis(mIncrementMouse * abs(rotY), direction, 0, 0); // changing Y - rotate around X axis + mValue *= delta; + } + } + else + { // set on click mode + if (!pointInTouchCircle(x, y)) + { + return TRUE; // don't drag outside the circle + } + + F32 radius = mTouchArea->getRect().getWidth() / 2; + F32 xx = x - mTouchArea->getRect().getCenterX(); + F32 yy = y - mTouchArea->getRect().getCenterY(); + F32 dist = sqrt(pow(xx, 2) + pow(yy, 2)); + + F32 azimuth = llclamp(acosf(xx / dist), 0.0f, F_PI); + F32 altitude = llclamp(acosf(dist / radius), 0.0f, F_PI_BY_TWO); + + if (yy < 0) + { + azimuth = F_TWO_PI - azimuth; + } + + LLVector3 draw_point = VectorZero * mValue; + if (draw_point.mV[VZ] >= 0.f) + { + if (is_approx_zero(altitude)) // don't change the hemisphere + { + altitude = F_APPROXIMATELY_ZERO; + } + altitude *= -1; + } + + mValue.setAngleAxis(altitude, 0, 1, 0); + LLQuaternion az_quat; + az_quat.setAngleAxis(azimuth, 0, 0, 1); + mValue *= az_quat; + } + + // we are doing a lot of F32 mathematical operations with loss of precision, + // re-normalize to compensate + mValue.normalize(); + + mPrevX = x; + mPrevY = y; + onCommit(); + } + return TRUE; +} + +BOOL LLVirtualTrackball::handleMouseUp(S32 x, S32 y, MASK mask) +{ + if (hasMouseCapture()) + { + mPrevX = 0; + mPrevY = 0; + gFocusMgr.setMouseCapture(NULL); + make_ui_sound("UISndClickRelease"); + } + return LLView::handleMouseUp(x, y, mask); +} + +BOOL LLVirtualTrackball::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if (pointInTouchCircle(x, y)) + { + mPrevX = x; + mPrevY = y; + gFocusMgr.setMouseCapture(this); + mDragMode = (mask == MASK_CONTROL) ? DRAG_SCROLL : DRAG_SET; + make_ui_sound("UISndClick"); + } + return LLView::handleMouseDown(x, y, mask); +} + +BOOL LLVirtualTrackball::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (pointInTouchCircle(x, y)) + { + + //make_ui_sound("UISndClick"); + } + return LLView::handleRightMouseDown(x, y, mask); +} + +BOOL LLVirtualTrackball::handleKeyHere(KEY key, MASK mask) +{ + BOOL handled = FALSE; + switch (key) + { + case KEY_DOWN: + onRotateTopClick(); + handled = TRUE; + break; + case KEY_LEFT: + onRotateRightClick(); + handled = TRUE; + break; + case KEY_UP: + onRotateBottomClick(); + handled = TRUE; + break; + case KEY_RIGHT: + onRotateLeftClick(); + handled = TRUE; + break; + default: + break; + } + return handled; +} + diff --git a/indra/llui/llvirtualtrackball.h b/indra/llui/llvirtualtrackball.h new file mode 100644 index 0000000000..c7a893877b --- /dev/null +++ b/indra/llui/llvirtualtrackball.h @@ -0,0 +1,163 @@ +/** +* @file virtualtrackball.h +* @author Andrey Lihatskiy +* @brief Header file for LLVirtualTrackball +* +* $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$ +*/ + +// A control for positioning the sun and the moon in the celestial sphere. + +#ifndef LL_LLVIRTUALTRACKBALL_H +#define LL_LLVIRTUALTRACKBALL_H + +#include "lluictrl.h" +#include "llpanel.h" +#include "lltextbox.h" +#include "llbutton.h" + +class LLVirtualTrackball + : public LLUICtrl +{ +public: + enum ThumbMode + { + SUN, + MOON + }; + enum DragMode + { + DRAG_SET, + DRAG_SCROLL + }; + + struct Params + : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<LLViewBorder::Params> border; + Optional<LLUIImage*> image_moon_back, + image_moon_front, + image_sphere, + image_sun_back, + image_sun_front; + + Optional<std::string> thumb_mode; + Optional<F32> increment_angle_mouse, + increment_angle_btn; + + Optional<LLTextBox::Params> lbl_N, + lbl_S, + lbl_W, + lbl_E; + + Optional<LLButton::Params> btn_rotate_top, + btn_rotate_bottom, + btn_rotate_left, + btn_rotate_right; + + Params(); + }; + + + virtual ~LLVirtualTrackball(); + /*virtual*/ BOOL postBuild(); + + 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 handleKeyHere(KEY key, MASK mask); + + virtual void draw(); + + virtual void setValue(const LLSD& value); + void setValue(F32 x, F32 y, F32 z, F32 w); + virtual LLSD getValue() const; + + void setRotation(const LLQuaternion &value); + LLQuaternion getRotation() const; + + static void getAzimuthAndElevation(const LLQuaternion &quat, F32 &azimuth, F32 &elevation); + static void getAzimuthAndElevationDeg(const LLQuaternion &quat, F32 &azimuth, F32 &elevation); + +protected: + friend class LLUICtrlFactory; + LLVirtualTrackball(const Params&); + void onEditChange(); + +protected: + LLTextBox* mNLabel; + LLTextBox* mELabel; + LLTextBox* mSLabel; + LLTextBox* mWLabel; + + LLButton* mBtnRotateTop; + LLButton* mBtnRotateBottom; + LLButton* mBtnRotateLeft; + LLButton* mBtnRotateRight; + + LLTextBox* mLabelN; + LLTextBox* mLabelS; + LLTextBox* mLabelW; + LLTextBox* mLabelE; + + LLPanel* mTouchArea; + LLViewBorder* mBorder; + +private: + void setValueAndCommit(const LLQuaternion &value); + void drawThumb(S32 x, S32 y, ThumbMode mode, bool upperHemi = true); + bool pointInTouchCircle(S32 x, S32 y) const; + + void onRotateTopClick(); + void onRotateBottomClick(); + void onRotateLeftClick(); + void onRotateRightClick(); + + void onRotateTopMouseEnter(); + void onRotateBottomMouseEnter(); + void onRotateLeftMouseEnter(); + void onRotateRightMouseEnter(); + + S32 mPrevX; + S32 mPrevY; + + LLUIImage* mImgMoonBack; + LLUIImage* mImgMoonFront; + LLUIImage* mImgSunBack; + LLUIImage* mImgSunFront; + LLUIImage* mImgBtnRotTop; + LLUIImage* mImgBtnRotLeft; + LLUIImage* mImgBtnRotRight; + LLUIImage* mImgBtnRotBottom; + LLUIImage* mImgSphere; + + LLQuaternion mValue; + ThumbMode mThumbMode; + DragMode mDragMode; + + F32 mIncrementMouse; + F32 mIncrementBtn; +}; + +#endif + diff --git a/indra/llui/llxyvector.cpp b/indra/llui/llxyvector.cpp new file mode 100644 index 0000000000..d7ba243e1d --- /dev/null +++ b/indra/llui/llxyvector.cpp @@ -0,0 +1,337 @@ +/** +* @file llxyvector.cpp +* @author Andrey Lihatskiy +* @brief Implementation for LLXYVector +* +* $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$ +*/ + +// A control that allows to set two related vector magnitudes by manipulating a single vector on a plane. + +#include "linden_common.h" + +#include "llxyvector.h" + +#include "llstring.h" +#include "llrect.h" + +#include "lluictrlfactory.h" +#include "llrender.h" + +#include "llmath.h" + +// Globals +static LLDefaultChildRegistry::Register<LLXYVector> register_xy_vector("xy_vector"); + + +const F32 CENTER_CIRCLE_RADIUS = 2; +const S32 ARROW_ANGLE = 30; +const S32 ARROW_LENGTH_LONG = 10; +const S32 ARROW_LENGTH_SHORT = 6; + +LLXYVector::Params::Params() + : x_entry("x_entry"), + y_entry("y_entry"), + touch_area("touch_area"), + border("border"), + edit_bar_height("edit_bar_height", 18), + padding("padding", 4), + min_val_x("min_val_x", -1.0f), + max_val_x("max_val_x", 1.0f), + increment_x("increment_x", 0.05f), + min_val_y("min_val_y", -1.0f), + max_val_y("max_val_y", 1.0f), + increment_y("increment_y", 0.05f), + label_width("label_width", 16), + arrow_color("arrow_color", LLColor4::white), + ghost_color("ghost_color"), + area_color("area_color", LLColor4::grey4), + grid_color("grid_color", LLColor4::grey % 0.25f), + logarithmic("logarithmic", FALSE) +{ +} + +LLXYVector::LLXYVector(const LLXYVector::Params& p) + : LLUICtrl(p), + mArrowColor(p.arrow_color()), + mAreaColor(p.area_color), + mGridColor(p.grid_color), + mMinValueX(p.min_val_x), + mMaxValueX(p.max_val_x), + mIncrementX(p.increment_x), + mMinValueY(p.min_val_y), + mMaxValueY(p.max_val_y), + mIncrementY(p.increment_y), + mLogarithmic(p.logarithmic), + mValueX(0), + mValueY(0) +{ + mGhostColor = p.ghost_color.isProvided() ? p.ghost_color() % 0.3f : p.arrow_color() % 0.3f; + + LLRect border_rect = getLocalRect(); + LLViewBorder::Params params = p.border; + params.rect(border_rect); + mBorder = LLUICtrlFactory::create<LLViewBorder>(params); + addChild(mBorder); + + LLTextBox::Params x_label_params; + x_label_params.initial_value(p.x_entry.label()); + x_label_params.rect = LLRect(p.padding, + border_rect.mTop - p.padding, + p.label_width, + border_rect.getHeight() - p.edit_bar_height); + mXLabel = LLUICtrlFactory::create<LLTextBox>(x_label_params); + addChild(mXLabel); + LLLineEditor::Params x_params = p.x_entry; + x_params.rect = LLRect(p.padding + p.label_width, + border_rect.mTop - p.padding, + border_rect.getCenterX(), + border_rect.getHeight() - p.edit_bar_height); + x_params.commit_callback.function(boost::bind(&LLXYVector::onEditChange, this)); + mXEntry = LLUICtrlFactory::create<LLLineEditor>(x_params); + mXEntry->setPrevalidateInput(LLTextValidate::validateFloat); + addChild(mXEntry); + + LLTextBox::Params y_label_params; + y_label_params.initial_value(p.y_entry.label()); + y_label_params.rect = LLRect(border_rect.getCenterX() + p.padding, + border_rect.mTop - p.padding, + border_rect.getCenterX() + p.label_width, + border_rect.getHeight() - p.edit_bar_height); + mYLabel = LLUICtrlFactory::create<LLTextBox>(y_label_params); + addChild(mYLabel); + LLLineEditor::Params y_params = p.y_entry; + y_params.rect = LLRect(border_rect.getCenterX() + p.padding + p.label_width, + border_rect.getHeight() - p.padding, + border_rect.getWidth() - p.padding, + border_rect.getHeight() - p.edit_bar_height); + y_params.commit_callback.function(boost::bind(&LLXYVector::onEditChange, this)); + mYEntry = LLUICtrlFactory::create<LLLineEditor>(y_params); + mYEntry->setPrevalidateInput(LLTextValidate::validateFloat); + addChild(mYEntry); + + LLPanel::Params touch_area = p.touch_area; + touch_area.rect = LLRect(p.padding, + border_rect.mTop - p.edit_bar_height - p.padding, + border_rect.getWidth() - p.padding, + p.padding); + mTouchArea = LLUICtrlFactory::create<LLPanel>(touch_area); + addChild(mTouchArea); +} + +LLXYVector::~LLXYVector() +{ +} + +BOOL LLXYVector::postBuild() +{ + mLogScaleX = (2 * log(mMaxValueX)) / mTouchArea->getRect().getWidth(); + mLogScaleY = (2 * log(mMaxValueY)) / mTouchArea->getRect().getHeight(); + + return TRUE; +} + +void drawArrow(S32 tailX, S32 tailY, S32 tipX, S32 tipY, LLColor4 color) +{ + gl_line_2d(tailX, tailY, tipX, tipY, color); + + S32 dx = tipX - tailX; + S32 dy = tipY - tailY; + + S32 arrowLength = (abs(dx) < ARROW_LENGTH_LONG && abs(dy) < ARROW_LENGTH_LONG) ? ARROW_LENGTH_SHORT : ARROW_LENGTH_LONG; + + F32 theta = std::atan2(dy, dx); + + F32 rad = ARROW_ANGLE * std::atan(1) * 4 / 180; + F32 x = tipX - arrowLength * cos(theta + rad); + F32 y = tipY - arrowLength * sin(theta + rad); + F32 rad2 = -1 * ARROW_ANGLE * std::atan(1) * 4 / 180; + F32 x2 = tipX - arrowLength * cos(theta + rad2); + F32 y2 = tipY - arrowLength * sin(theta + rad2); + gl_triangle_2d(tipX, tipY, x, y, x2, y2, color, true); +} + +void LLXYVector::draw() +{ + S32 centerX = mTouchArea->getRect().getCenterX(); + S32 centerY = mTouchArea->getRect().getCenterY(); + S32 pointX; + S32 pointY; + + if (mLogarithmic) + { + pointX = (log(llabs(mValueX) + 1)) / mLogScaleX; + pointX *= (mValueX < 0) ? -1 : 1; + pointX += centerX; + + pointY = (log(llabs(mValueY) + 1)) / mLogScaleY; + pointY *= (mValueY < 0) ? -1 : 1; + pointY += centerY; + } + else // linear + { + pointX = centerX + (mValueX * mTouchArea->getRect().getWidth() / (2 * mMaxValueX)); + pointY = centerY + (mValueY * mTouchArea->getRect().getHeight() / (2 * mMaxValueY)); + } + + // fill + gl_rect_2d(mTouchArea->getRect(), mAreaColor, true); + + // draw grid + gl_line_2d(centerX, mTouchArea->getRect().mTop, centerX, mTouchArea->getRect().mBottom, mGridColor); + gl_line_2d(mTouchArea->getRect().mLeft, centerY, mTouchArea->getRect().mRight, centerY, mGridColor); + + // draw ghost + if (hasMouseCapture()) + { + drawArrow(centerX, centerY, mGhostX, mGhostY, mGhostColor); + } + else + { + mGhostX = pointX; + mGhostY = pointY; + } + + if (abs(mValueX) >= mIncrementX || abs(mValueY) >= mIncrementY) + { + // draw the vector arrow + drawArrow(centerX, centerY, pointX, pointY, mArrowColor); + } + else + { + // skip the arrow, set color for center circle + gGL.color4fv(mArrowColor.get().mV); + } + + // draw center circle + gl_circle_2d(centerX, centerY, CENTER_CIRCLE_RADIUS, 12, true); + + LLView::draw(); +} + +void LLXYVector::onEditChange() +{ + if (getEnabled()) + { + setValueAndCommit(mXEntry->getValue().asReal(), mYEntry->getValue().asReal()); + } +} + +void LLXYVector::setValue(const LLSD& value) +{ + if (value.isArray()) + { + setValue(value[0].asReal(), value[1].asReal()); + } +} + +void LLXYVector::setValue(F32 x, F32 y) +{ + mValueX = ll_round(llclamp(x, mMinValueX, mMaxValueX), mIncrementX); + mValueY = ll_round(llclamp(y, mMinValueY, mMaxValueY), mIncrementY); + + update(); +} + +void LLXYVector::setValueAndCommit(F32 x, F32 y) +{ + if (mValueX != x || mValueY != y) + { + setValue(x, y); + onCommit(); + } +} + +LLSD LLXYVector::getValue() const +{ + LLSD value; + value.append(mValueX); + value.append(mValueY); + return value; +} + +void LLXYVector::update() +{ + mXEntry->setValue(mValueX); + mYEntry->setValue(mValueY); +} + +BOOL LLXYVector::handleHover(S32 x, S32 y, MASK mask) +{ + if (hasMouseCapture()) + { + if (mLogarithmic) + { + F32 valueX = llfastpow(F_E, mLogScaleX*(llabs(x - mTouchArea->getRect().getCenterX()))) - 1; + valueX *= (x < mTouchArea->getRect().getCenterX()) ? -1 : 1; + + F32 valueY = llfastpow(F_E, mLogScaleY*(llabs(y - mTouchArea->getRect().getCenterY()))) - 1; + valueY *= (y < mTouchArea->getRect().getCenterY()) ? -1 : 1; + + setValueAndCommit(valueX, valueY); + } + else //linear + { + F32 valueX = 2 * mMaxValueX * F32(x - mTouchArea->getRect().getCenterX()) / mTouchArea->getRect().getWidth(); + F32 valueY = 2 * mMaxValueY * F32(y - mTouchArea->getRect().getCenterY()) / mTouchArea->getRect().getHeight(); + + setValueAndCommit(valueX, valueY); + } + } + + return TRUE; +} + +BOOL LLXYVector::handleMouseUp(S32 x, S32 y, MASK mask) +{ + if (hasMouseCapture()) + { + gFocusMgr.setMouseCapture(NULL); + make_ui_sound("UISndClickRelease"); + } + + if (mTouchArea->getRect().pointInRect(x, y)) + { + return TRUE; + } + else + { + return LLUICtrl::handleMouseUp(x, y, mask); + } +} + +BOOL LLXYVector::handleMouseDown(S32 x, S32 y, MASK mask) +{ + + if (mTouchArea->getRect().pointInRect(x, y)) + { + gFocusMgr.setMouseCapture(this); + make_ui_sound("UISndClick"); + + return TRUE; + } + else + { + return LLUICtrl::handleMouseDown(x, y, mask); + } +} + diff --git a/indra/llui/llxyvector.h b/indra/llui/llxyvector.h new file mode 100644 index 0000000000..bb3822dd26 --- /dev/null +++ b/indra/llui/llxyvector.h @@ -0,0 +1,122 @@ +/** +* @file llxyvector.h +* @author Andrey Lihatskiy +* @brief Header file for LLXYVector +* +* $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$ +*/ + +// A control that allows to set two related vector magnitudes by manipulating a single vector on a plane. + +#ifndef LL_LLXYVECTOR_H +#define LL_LLXYVECTOR_H + +#include "lluictrl.h" +#include "llpanel.h" +#include "lltextbox.h" +#include "lllineeditor.h" + +class LLXYVector + : public LLUICtrl +{ +public: + struct Params + : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<LLLineEditor::Params> x_entry; + Optional<LLLineEditor::Params> y_entry; + Optional<LLPanel::Params> touch_area; + Optional<LLViewBorder::Params> border; + Optional<S32> edit_bar_height; + Optional<S32> padding; + Optional<S32> label_width; + Optional<F32> min_val_x; + Optional<F32> max_val_x; + Optional<F32> increment_x; + Optional<F32> min_val_y; + Optional<F32> max_val_y; + Optional<F32> increment_y; + Optional<LLUIColor> arrow_color; + Optional<LLUIColor> ghost_color; + Optional<LLUIColor> area_color; + Optional<LLUIColor> grid_color; + Optional<BOOL> logarithmic; + + Params(); + }; + + + virtual ~LLXYVector(); + /*virtual*/ BOOL postBuild(); + + 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 void draw(); + + virtual void setValue(const LLSD& value); + void setValue(F32 x, F32 y); + virtual LLSD getValue() const; + +protected: + friend class LLUICtrlFactory; + LLXYVector(const Params&); + void onEditChange(); + +protected: + LLTextBox* mXLabel; + LLTextBox* mYLabel; + LLLineEditor* mXEntry; + LLLineEditor* mYEntry; + LLPanel* mTouchArea; + LLViewBorder* mBorder; + +private: + void update(); + void setValueAndCommit(F32 x, F32 y); + + F32 mValueX; + F32 mValueY; + + F32 mMinValueX; + F32 mMaxValueX; + F32 mIncrementX; + F32 mMinValueY; + F32 mMaxValueY; + F32 mIncrementY; + + U32 mGhostX; + U32 mGhostY; + + LLUIColor mArrowColor; + LLUIColor mGhostColor; + LLUIColor mAreaColor; + LLUIColor mGridColor; + + BOOL mLogarithmic; + F32 mLogScaleX; + F32 mLogScaleY; +}; + +#endif + diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index 119cbebc81..1a474cca90 100644 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -36,6 +36,11 @@ #include <boost/regex.hpp> +#if LL_WINDOWS +// because something pulls in window and lldxdiag dependencies which in turn need wbemuuid.lib + #pragma comment(lib, "wbemuuid.lib") +#endif + // namespace LLExperienceCache // { @@ -734,11 +739,6 @@ namespace tut "XXX secondlife:///app/region/Burning%20Life%20(Hyper)/27/210/30 XXX", "secondlife:///app/region/Burning%20Life%20(Hyper)/27/210/30"); - // DEV-35459: SLURLs and teleport Links not parsed properly - testRegex("Region with quote", url, - "XXX secondlife:///app/region/A'ksha%20Oasis/41/166/701 XXX", - "secondlife:///app/region/A%27ksha%20Oasis/41/166/701"); - // Rendering tests. testLabel("Render /app/region/Ahern/50/50/50/", url, "secondlife:///app/region/Ahern/50/50/50/", @@ -898,4 +898,38 @@ namespace tut "and even no www something lindenlab.com", ""); } + + template<> template<> + void object::test<16>() + { + // + // test LLUrlEntryIPv6 + // + LLUrlEntryIPv6 url; + + // Regex tests. + testRegex("match urls with a protocol", url, + "this url should match http://[::1]", + "http://[::1]"); + + testRegex("match urls with a protocol and query", url, + "this url should match http://[::1]/file.mp3", + "http://[::1]/file.mp3"); + + testRegex("match urls with a protocol", url, + "this url should match http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]", + "http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]"); + + testRegex("match urls with port", url, + "let's specify some port http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]:8080", + "http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]:8080"); + + testRegex("don't match urls w/o protocol", url, + "looks like an url something [2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d] but no https prefix", + ""); + + testRegex("don't match incorrect urls", url, + "http://[ 2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d ]", + ""); + } } diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index 2076ce334e..9e9abbadff 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -61,9 +61,6 @@ LLDir_Win32 gDirUtil; #elif LL_DARWIN #include "lldir_mac.h" LLDir_Mac gDirUtil; -#elif LL_SOLARIS -#include "lldir_solaris.h" -LLDir_Solaris gDirUtil; #else #include "lldir_linux.h" LLDir_Linux gDirUtil; @@ -1090,7 +1087,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, (unsigned short)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: diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h index 38e204ef04..4988b9c6e3 100644 --- a/indra/llvfs/lldir.h +++ b/indra/llvfs/lldir.h @@ -27,11 +27,6 @@ #ifndef LL_LLDIR_H #define LL_LLDIR_H -#if LL_SOLARIS -#include <sys/param.h> -#define MAX_PATH MAXPATHLEN -#endif - // these numbers are read from settings_files.xml, so we need to be explicit typedef enum ELLPath { diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp deleted file mode 100644 index f18560ff20..0000000000 --- a/indra/llvfs/lldir_solaris.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/** - * @file fmodwrapper.cpp - * @brief dummy source file for building a shared library to wrap libfmod.a - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "lldir_solaris.h" -#include "llerror.h" -#include "llrand.h" -#include "llstring.h" -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <glob.h> -#include <pwd.h> -#include <sys/utsname.h> -#define _STRUCTURED_PROC 1 -#include <sys/procfs.h> -#include <fcntl.h> - -static std::string getCurrentUserHome(char* fallback) -{ - // fwiw this exactly duplicates getCurrentUserHome() in lldir_linux.cpp... - // we should either derive both from LLDir_Posix or just axe Solaris. - const uid_t uid = getuid(); - struct passwd *pw; - - pw = getpwuid(uid); - if ((pw != NULL) && (pw->pw_dir != NULL)) - { - return pw->pw_dir; - } - - LL_INFOS() << "Couldn't detect home directory from passwd - trying $HOME" << LL_ENDL; - auto home_env = LLStringUtil::getoptenv("HOME"); - if (home_env) - { - return *home_env; - } - else - { - LL_WARNS() << "Couldn't detect home directory! Falling back to " << fallback << LL_ENDL; - return fallback; - } -} - - -LLDir_Solaris::LLDir_Solaris() -{ - mDirDelimiter = "/"; - mCurrentDirIndex = -1; - mCurrentDirCount = -1; - mDirp = NULL; - - char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */ - if (getcwd(tmp_str, LL_MAX_PATH) == NULL) - { - strcpy(tmp_str, "/tmp"); - LL_WARNS() << "Could not get current directory; changing to " - << tmp_str << LL_ENDL; - if (chdir(tmp_str) == -1) - { - LL_ERRS() << "Could not change directory to " << tmp_str << LL_ENDL; - } - } - - mExecutableFilename = ""; - mExecutablePathAndName = ""; - mExecutableDir = strdup(tmp_str); - mWorkingDir = strdup(tmp_str); - mAppRODataDir = strdup(tmp_str); - mOSUserDir = getCurrentUserHome(tmp_str); - mOSUserAppDir = ""; - mLindenUserDir = ""; - - 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){ - 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)){ - LL_WARNS() << "Unable to read " << path << LL_ENDL; - close(proc_fd); - return; - } - - close(proc_fd); - - mExecutableFilename = strdup(proc_psinfo.pr_fname); - 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){ - LL_WARNS() << "Unable to read link from " << path << LL_ENDL; - return; - } - - char *p = execpath; // nuke trash in link, if any exists - int i = 0; - while(*p != NULL && ++i < LL_MAX_PATH && isprint((int)(*p++))); - *p = NULL; - - mExecutablePathAndName = strdup(execpath); - 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. - - auto SECONDLIFE(LLDirUtil::getoptenv("SECONDLIFE")); - if(SECONDLIFE){ - mExecutableDir = add(*SECONDLIFE, "bin"); //NOTE: make sure we point at the bin - }else{ - mExecutableDir = getDirName(execpath); - LL_INFOS() << "mExecutableDir = [" << mExecutableDir << "]" << LL_ENDL; - } - - mLLPluginDir = add(mExecutableDir, "llplugin"); - - // *TODO: don't use /tmp, use $HOME/.secondlife/tmp or something. - mTempDir = "/tmp"; -} - -LLDir_Solaris::~LLDir_Solaris() -{ -} - -// Implementation - - -void LLDir_Solaris::initAppDirs(const std::string &app_name, - const std::string& app_read_only_data_dir) -{ - // Allow override so test apps can read newview directory - if (!app_read_only_data_dir.empty()) - { - mAppRODataDir = app_read_only_data_dir; - mSkinBaseDir = add(mAppRODataDir, "skins"); - } - mAppName = app_name; - - std::string upper_app_name(app_name); - LLStringUtil::toUpper(upper_app_name); - - auto app_home_env(LLStringUtil::getoptenv(upper_app_name + "_USER_DIR")); - if (app_home_env) - { - // user has specified own userappdir i.e. $SECONDLIFE_USER_DIR - mOSUserAppDir = *app_home_env; - } - else - { - // traditionally on unixoids, MyApp gets ~/.myapp dir for data - mOSUserAppDir = mOSUserDir; - mOSUserAppDir += "/"; - mOSUserAppDir += "."; - std::string lower_app_name(app_name); - LLStringUtil::toLower(lower_app_name); - mOSUserAppDir += lower_app_name; - } - - // create any directories we expect to write to. - - int res = LLFile::mkdir(mOSUserAppDir); - if (res == -1) - { - LL_WARNS() << "Couldn't create app user dir " << mOSUserAppDir << LL_ENDL; - LL_WARNS() << "Default to base dir" << mOSUserDir << LL_ENDL; - mOSUserAppDir = mOSUserDir; - } - - res = LLFile::mkdir(getExpandedFilename(LL_PATH_LOGS,"")); - if (res == -1) - { - LL_WARNS() << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << LL_ENDL; - } - - res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SETTINGS,"")); - if (res == -1) - { - LL_WARNS() << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << LL_ENDL; - } - - res = LLFile::mkdir(getExpandedFilename(LL_PATH_CACHE,"")); - if (res == -1) - { - LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << LL_ENDL; - } - - mCAFile = getExpandedFilename(LL_PATH_EXECUTABLE, "ca-bundle.crt"); -} - -U32 LLDir_Solaris::countFilesInDir(const std::string &dirname, const std::string &mask) -{ - U32 file_count = 0; - glob_t g; - - std::string tmp_str; - tmp_str = dirname; - tmp_str += mask; - - if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) - { - file_count = g.gl_pathc; - - globfree(&g); - } - - return (file_count); -} - -std::string LLDir_Solaris::getCurPath() -{ - char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */ - if (getcwd(tmp_str, LL_MAX_PATH) == NULL) - { - 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 -{ - struct stat stat_data; - // Check the age of the file - // Now, we see if the files we've gathered are recent... - int res = stat(filename.c_str(), &stat_data); - if (!res) - { - return TRUE; - } - else - { - return FALSE; - } -} - diff --git a/indra/llvfs/lldir_solaris.h b/indra/llvfs/lldir_solaris.h deleted file mode 100644 index c6dac57e14..0000000000 --- a/indra/llvfs/lldir_solaris.h +++ /dev/null @@ -1,61 +0,0 @@ -/** - * @file fmodwrapper.cpp - * @brief dummy source file for building a shared library to wrap libfmod.a - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#if !LL_SOLARIS -#error This header must not be included when compiling for any target other than Solaris. Consider including lldir.h instead. -#endif // !LL_SOLARIS - -#ifndef LL_LLDIR_SOLARIS_H -#define LL_LLDIR_SOLARIS_H - -#include "lldir.h" - -#include <dirent.h> -#include <errno.h> - -class LLDir_Solaris : public LLDir -{ -public: - LLDir_Solaris(); - virtual ~LLDir_Solaris(); - - /*virtual*/ void initAppDirs(const std::string &app_name, - const std::string& app_read_only_data_dir); - - virtual std::string getCurPath(); - virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - /*virtual*/ bool fileExists(const std::string &filename) const; - -private: - DIR *mDirp; - int mCurrentDirIndex; - int mCurrentDirCount; - std::string mCurrentDir; -}; - -#endif // LL_LLDIR_SOLARIS_H - - diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp index 617056d94d..2c64bf563e 100644 --- a/indra/llvfs/llvfs.cpp +++ b/indra/llvfs/llvfs.cpp @@ -33,10 +33,6 @@ #include <map> #if LL_WINDOWS #include <share.h> -#elif LL_SOLARIS -#include <sys/types.h> -#include <unistd.h> -#include <fcntl.h> #else #include <sys/file.h> #endif @@ -2146,12 +2142,6 @@ LLFILE *LLVFS::openAndLock(const std::string& filename, const char* mode, BOOL r int fd; // first test the lock in a non-destructive way -#if LL_SOLARIS - struct flock fl; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 1; -#else // !LL_SOLARIS if (strchr(mode, 'w') != NULL) { fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ @@ -2167,19 +2157,13 @@ LLFILE *LLVFS::openAndLock(const std::string& filename, const char* mode, BOOL r fclose(fp); } } -#endif // !LL_SOLARIS // now actually open the file for use fp = LLFile::fopen(filename, mode); /* Flawfinder: ignore */ if (fp) { fd = fileno(fp); -#if LL_SOLARIS - fl.l_type = read_lock ? F_RDLCK : F_WRLCK; - if (fcntl(fd, F_SETLK, &fl) == -1) -#else if (flock(fd, (read_lock ? LOCK_SH : LOCK_EX) | LOCK_NB) == -1) -#endif { fclose(fp); fp = NULL; @@ -2207,14 +2191,6 @@ void LLVFS::unlockAndClose(LLFILE *fp) flock(fd, LOCK_UN); #endif */ -#if LL_SOLARIS - struct flock fl; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 1; - fl.l_type = F_UNLCK; - fcntl(fileno(fp), F_SETLK, &fl); -#endif fclose(fp); } } diff --git a/indra/llvfs/llvfs.h b/indra/llvfs/llvfs.h index dca5ff4ad5..42feafe20b 100644 --- a/indra/llvfs/llvfs.h +++ b/indra/llvfs/llvfs.h @@ -31,6 +31,7 @@ #include "lluuid.h" #include "llassettype.h" #include "llthread.h" +#include "llmutex.h" enum EVFSValid { diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index 0743fd899f..8bfb23ed64 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -11,7 +11,6 @@ project(llwindow) include(00-Common) -include(DirectX) include(DragDrop) include(LLCommon) include(LLImage) @@ -30,7 +29,6 @@ include_directories( ${LLVFS_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} - ${DIRECTX_INCLUDE_DIR} ) include_directories(SYSTEM ${LLCOMMON_SYSTEM_INCLUDE_DIRS} diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp index d4790f9f29..12a6baa3e6 100644 --- a/indra/llwindow/lldxhardware.cpp +++ b/indra/llwindow/lldxhardware.cpp @@ -61,7 +61,7 @@ typedef BOOL ( WINAPI* PfnCoSetProxyBlanket )( IUnknown* pProxy, DWORD dwAuthnSv OLECHAR* pServerPrincName, DWORD dwAuthnLevel, DWORD dwImpLevel, RPC_AUTH_IDENTITY_HANDLE pAuthInfo, DWORD dwCapabilities ); -HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam ) +HRESULT GetVideoMemoryViaWMI(WCHAR* strInputDeviceID, DWORD* pdwAdapterRam) { HRESULT hr; bool bGotMemory = false; @@ -149,21 +149,26 @@ HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam ) if ( !pVideoControllers[iController] ) continue; - pPropName = SysAllocString( L"PNPDeviceID" ); - hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr ); + // if strInputDeviceID is set find this specific device and return memory or specific device + // if strInputDeviceID is not set return the best device + if (strInputDeviceID) + { + 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 ); + 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; + if( SUCCEEDED( hr ) && strInputDeviceID) + { + if( wcsstr( var.bstrVal, strInputDeviceID ) != 0 ) + bFound = true; + } + VariantClear( &var ); + if( pPropName ) SysFreeString( pPropName ); } - VariantClear( &var ); - if( pPropName ) SysFreeString( pPropName ); - if( bFound ) + if( bFound || !strInputDeviceID ) { pPropName = SysAllocString( L"AdapterRAM" ); hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr ); @@ -175,13 +180,18 @@ HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam ) if( SUCCEEDED( hr ) ) { bGotMemory = true; - *pdwAdapterRam = var.ulVal; + *pdwAdapterRam = llmax(var.ulVal, *pdwAdapterRam); } VariantClear( &var ); if( pPropName ) SysFreeString( pPropName ); - break; } + SAFE_RELEASE( pVideoControllers[iController] ); + + if (bFound) + { + break; + } } } } @@ -207,6 +217,17 @@ HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam ) return E_FAIL; } +//static +S32 LLDXHardware::getMBVideoMemoryViaWMI() +{ + DWORD vram = 0; + if (SUCCEEDED(GetVideoMemoryViaWMI(NULL, &vram))) + { + return vram / (1024 * 1024);; + } + return 0; +} + //Getting the version of graphics controller driver via WMI std::string LLDXHardware::getDriverVersionWMI() { @@ -613,6 +634,9 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) IDxDiagContainer *device_containerp = NULL; IDxDiagContainer *file_containerp = NULL; IDxDiagContainer *driver_containerp = NULL; + DWORD dw_device_count; + + mVRAM = 0; // CoCreate a IDxDiagProvider* LL_DEBUGS("AppInit") << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL; @@ -663,10 +687,21 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp); if(FAILED(hr) || !devices_containerp) { + // do not release 'dirty' devices_containerp at this stage, only dx_diag_rootp + devices_containerp = NULL; goto LCleanup; } + // make sure there is something inside + hr = devices_containerp->GetNumberOfChildContainers(&dw_device_count); + if (FAILED(hr) || dw_device_count == 0) + { + goto LCleanup; + } + // Get device 0 + // By default 0 device is the primary one, howhever in case of various hybrid graphics + // like itegrated AMD and PCI AMD GPUs system might switch. LL_DEBUGS("AppInit") << "devices_containerp->GetChildContainer" << LL_ENDL; hr = devices_containerp->GetChildContainer(L"0", &device_containerp); if(FAILED(hr) || !device_containerp) @@ -679,12 +714,27 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) WCHAR deviceID[512]; get_wstring(device_containerp, L"szDeviceID", deviceID, 512); - + // Example: searches id like 1F06 in pnp string (aka VEN_10DE&DEV_1F06) + // doesn't seem to work on some systems since format is unrecognizable + // but in such case keyDeviceID works if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID, &vram))) { mVRAM = vram/(1024*1024); } else + { + get_wstring(device_containerp, L"szKeyDeviceID", deviceID, 512); + LL_WARNS() << "szDeviceID" << deviceID << LL_ENDL; + // '+9' to avoid ENUM\\PCI\\ prefix + // Returns string like Enum\\PCI\\VEN_10DE&DEV_1F06&SUBSYS... + // and since GetVideoMemoryViaWMI searches by PNPDeviceID it is sufficient + if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID + 9, &vram))) + { + mVRAM = vram / (1024 * 1024); + } + } + + if (mVRAM == 0) { // Get the English VRAM string std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish"); @@ -872,6 +922,7 @@ LLSD LLDXHardware::getDisplayInfo() IDxDiagContainer *device_containerp = NULL; IDxDiagContainer *file_containerp = NULL; IDxDiagContainer *driver_containerp = NULL; + DWORD dw_device_count; // CoCreate a IDxDiagProvider* LL_INFOS() << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL; @@ -922,9 +973,18 @@ LLSD LLDXHardware::getDisplayInfo() hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp); if(FAILED(hr) || !devices_containerp) { + // do not release 'dirty' devices_containerp at this stage, only dx_diag_rootp + devices_containerp = NULL; goto LCleanup; } + // make sure there is something inside + hr = devices_containerp->GetNumberOfChildContainers(&dw_device_count); + if (FAILED(hr) || dw_device_count == 0) + { + goto LCleanup; + } + // Get device 0 LL_INFOS() << "devices_containerp->GetChildContainer" << LL_ENDL; hr = devices_containerp->GetChildContainer(L"0", &device_containerp); @@ -976,6 +1036,10 @@ LLSD LLDXHardware::getDisplayInfo() } LCleanup: + if (ret.emptyMap()) + { + LL_INFOS() << "Failed to get data, cleaning up" << LL_ENDL; + } SAFE_RELEASE(file_containerp); SAFE_RELEASE(driver_containerp); SAFE_RELEASE(device_containerp); diff --git a/indra/llwindow/lldxhardware.h b/indra/llwindow/lldxhardware.h index cf33db8b37..1cb687e3b6 100644 --- a/indra/llwindow/lldxhardware.h +++ b/indra/llwindow/lldxhardware.h @@ -94,6 +94,10 @@ public: LLSD getDisplayInfo(); + // Will get memory of best GPU in MB, return memory on sucsess, 0 on failure + // Note: WMI is not accurate in some cases + static S32 getMBVideoMemoryViaWMI(); + // Find a particular device that matches the following specs. // Empty strings indicate that you don't care. // You can separate multiple devices with '|' chars to indicate you want diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp index f6f6c3931c..5404ac50e5 100644 --- a/indra/llwindow/llkeyboard.cpp +++ b/indra/llwindow/llkeyboard.cpp @@ -327,7 +327,7 @@ BOOL LLKeyboard::keyFromString(const std::string& str, KEY *key) // static -std::string LLKeyboard::stringFromKey(KEY key) +std::string LLKeyboard::stringFromKey(KEY key, bool translate) { std::string res = get_if_there(sKeysToNames, key, std::string()); if (res.empty()) @@ -338,16 +338,60 @@ std::string LLKeyboard::stringFromKey(KEY key) res = std::string(buffer); } - LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator; - if (trans != NULL) + if (translate) { - res = trans(res.c_str()); + LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator; + if (trans != NULL) + { + res = trans(res.c_str()); + } } return res; } +//static +std::string LLKeyboard::stringFromAccelerator(MASK accel_mask) +{ + std::string res; + + LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator; + + if (trans == NULL) + { + LL_ERRS() << "No mKeyStringTranslator" << LL_ENDL; + return res; + } + // Append any masks +#ifdef LL_DARWIN + // Standard Mac names for modifier keys in menu equivalents + // We could use the symbol characters, but they only exist in certain fonts. + if (accel_mask & MASK_CONTROL) + { + if (accel_mask & MASK_MAC_CONTROL) + { + res.append(trans("accel-mac-control")); + } + else + { + res.append(trans("accel-mac-command")); // Symbol would be "\xE2\x8C\x98" + } + } + if (accel_mask & MASK_ALT) + res.append(trans("accel-mac-option")); // Symbol would be "\xE2\x8C\xA5" + if (accel_mask & MASK_SHIFT) + res.append(trans("accel-mac-shift")); // Symbol would be "\xE2\x8C\xA7" +#else + if (accel_mask & MASK_CONTROL) + res.append(trans("accel-win-control")); + if (accel_mask & MASK_ALT) + res.append(trans("accel-win-alt")); + if (accel_mask & MASK_SHIFT) + res.append(trans("accel-win-shift")); +#endif + return res; +} //static std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key ) { @@ -359,41 +403,7 @@ std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key ) return res; } - LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator; - - if( trans == NULL ) - { - LL_ERRS() << "No mKeyStringTranslator" << LL_ENDL; - return res; - } - - // Append any masks -#ifdef LL_DARWIN - // Standard Mac names for modifier keys in menu equivalents - // We could use the symbol characters, but they only exist in certain fonts. - if( accel_mask & MASK_CONTROL ) - { - if ( accel_mask & MASK_MAC_CONTROL ) - { - res.append( trans("accel-mac-control") ); - } - else - { - res.append( trans("accel-mac-command") ); // Symbol would be "\xE2\x8C\x98" - } - } - if( accel_mask & MASK_ALT ) - res.append( trans("accel-mac-option") ); // Symbol would be "\xE2\x8C\xA5" - if( accel_mask & MASK_SHIFT ) - res.append( trans("accel-mac-shift") ); // Symbol would be "\xE2\x8C\xA7" -#else - if( accel_mask & MASK_CONTROL ) - res.append( trans("accel-win-control") ); - if( accel_mask & MASK_ALT ) - res.append( trans("accel-win-alt") ); - if( accel_mask & MASK_SHIFT ) - res.append( trans("accel-win-shift") ); -#endif + res.append(stringFromAccelerator(accel_mask)); std::string key_string = LLKeyboard::stringFromKey(key); if ((accel_mask & MASK_NORMALKEYS) && (key_string[0] == '-' || key_string[0] == '=' || key_string[0] == '+')) diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index 6f2dc87317..36bd8bcbed 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -38,10 +38,10 @@ enum EKeystate { KEYSTATE_DOWN, KEYSTATE_LEVEL, - KEYSTATE_UP + KEYSTATE_UP }; -typedef boost::function<void(EKeystate keystate)> LLKeyFunc; +typedef boost::function<bool(EKeystate keystate)> LLKeyFunc; typedef std::string (LLKeyStringTranslatorFunc)(const char *label); enum EKeyboardInsertMode @@ -50,15 +50,6 @@ enum EKeyboardInsertMode LL_KIM_OVERWRITE }; -class LLKeyBinding -{ -public: - KEY mKey; - MASK mMask; -// const char *mName; // unused - LLKeyFunc mFunction; -}; - class LLWindowCallbacks; class LLKeyboard @@ -103,7 +94,8 @@ public: static BOOL maskFromString(const std::string& str, MASK *mask); // False on failure static BOOL keyFromString(const std::string& str, KEY *key); // False on failure - static std::string stringFromKey(KEY key); + static std::string stringFromKey(KEY key, bool translate = true); + static std::string stringFromAccelerator( MASK accel_mask ); // separated for convinience, returns with "+": "Shift+" or "Shift+Alt+"... static std::string stringFromAccelerator( MASK accel_mask, KEY key ); void setCallbacks(LLWindowCallbacks *cbs) { mCallbacks = cbs; } diff --git a/indra/llwindow/llmousehandler.cpp b/indra/llwindow/llmousehandler.cpp index bea66e763c..e41ebd42f3 100644 --- a/indra/llwindow/llmousehandler.cpp +++ b/indra/llwindow/llmousehandler.cpp @@ -27,7 +27,7 @@ #include "llmousehandler.h" //virtual -BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down) +BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL handled = FALSE; if (down) @@ -38,6 +38,10 @@ BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType cli case CLICK_RIGHT: handled = handleRightMouseDown(x, y, mask); break; case CLICK_MIDDLE: handled = handleMiddleMouseDown(x, y, mask); break; case CLICK_DOUBLELEFT: handled = handleDoubleClick(x, y, mask); break; + case CLICK_BUTTON4: + case CLICK_BUTTON5: + LL_INFOS() << "Handle mouse button " << clicktype + 1 << " down." << LL_ENDL; + break; default: LL_WARNS() << "Unhandled enum." << LL_ENDL; } @@ -50,6 +54,10 @@ BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType cli case CLICK_RIGHT: handled = handleRightMouseUp(x, y, mask); break; case CLICK_MIDDLE: handled = handleMiddleMouseUp(x, y, mask); break; case CLICK_DOUBLELEFT: handled = handleDoubleClick(x, y, mask); break; + case CLICK_BUTTON4: + case CLICK_BUTTON5: + LL_INFOS() << "Handle mouse button " << clicktype + 1 << " up." << LL_ENDL; + break; default: LL_WARNS() << "Unhandled enum." << LL_ENDL; } diff --git a/indra/llwindow/llmousehandler.h b/indra/llwindow/llmousehandler.h index d825a3424c..d221dd117c 100644 --- a/indra/llwindow/llmousehandler.h +++ b/indra/llwindow/llmousehandler.h @@ -29,6 +29,7 @@ #include "linden_common.h" #include "llrect.h" +#include "indra_constants.h" // Mostly-abstract interface. // Intended for use via multiple inheritance. @@ -46,14 +47,7 @@ public: SHOW_ALWAYS, } EShowToolTip; - typedef enum { - CLICK_LEFT, - CLICK_MIDDLE, - CLICK_RIGHT, - CLICK_DOUBLELEFT - } EClickType; - - virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down); + virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) = 0; virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) = 0; virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask) = 0; @@ -64,6 +58,7 @@ public: virtual BOOL handleHover(S32 x, S32 y, MASK mask) = 0; virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) = 0; + virtual BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks) = 0; virtual BOOL handleToolTip(S32 x, S32 y, MASK mask) = 0; virtual const std::string& getName() const = 0; diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index 1990499459..d2c5b11c3d 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -359,10 +359,10 @@ attributedStringInfo getSegments(NSAttributedString *str) callRightMouseDown(mMousePos, [theEvent modifierFlags]); mSimulatedRightClick = true; } else { - if ([theEvent clickCount] >= 2) + if ([theEvent clickCount] == 2) { callDoubleClick(mMousePos, [theEvent modifierFlags]); - } else if ([theEvent clickCount] == 1) { + } else if ([theEvent clickCount] >= 1) { callLeftMouseDown(mMousePos, [theEvent modifierFlags]); } } @@ -444,7 +444,7 @@ attributedStringInfo getSegments(NSAttributedString *str) NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; mMousePos[0] = mPoint.x; mMousePos[1] = mPoint.y; - callMiddleMouseDown(mMousePos, [theEvent modifierFlags]); + callOtherMouseDown(mMousePos, [theEvent modifierFlags], [theEvent buttonNumber]); } - (void) otherMouseUp:(NSEvent *)theEvent @@ -452,7 +452,7 @@ attributedStringInfo getSegments(NSAttributedString *str) NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; mMousePos[0] = mPoint.x; mMousePos[1] = mPoint.y; - callMiddleMouseUp(mMousePos, [theEvent modifierFlags]); + callOtherMouseUp(mMousePos, [theEvent modifierFlags], [theEvent buttonNumber]); } - (void) rightMouseDragged:(NSEvent *)theEvent @@ -467,7 +467,7 @@ attributedStringInfo getSegments(NSAttributedString *str) - (void) scrollWheel:(NSEvent *)theEvent { - callScrollMoved(-[theEvent deltaY]); + callScrollMoved(-[theEvent deltaX], -[theEvent deltaY]); } - (void) mouseExited:(NSEvent *)theEvent @@ -816,7 +816,7 @@ attributedStringInfo getSegments(NSAttributedString *str) [super setMarkedText:aString selectedRange:selectedRange replacementRange:replacementRange]; if ([aString length] == 0) // this means Input Widow becomes empty { - [_window orderOut:_window]; // Close this to avoid empty Input Window + [self.window orderOut:self.window]; // Close this to avoid empty Input Window } } @@ -840,7 +840,7 @@ attributedStringInfo getSegments(NSAttributedString *str) (mKeyPressed >= 0xF700 && mKeyPressed <= 0xF8FF)) { // this is case a) of above comment - [_window orderOut:_window]; // to avoid empty Input Window + [self.window orderOut:self.window]; // to avoid empty Input Window } } diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index 1b24250618..30bc743e72 100644 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -263,6 +263,18 @@ std::vector<std::string> LLWindow::getDynamicFallbackFontList() #endif } +// static +std::vector<std::string> LLWindow::getDisplaysResolutionList() +{ +#if LL_WINDOWS + return LLWindowWin32::getDisplaysResolutionList(); +#elif LL_DARWIN + return LLWindowMacOSX::getDisplaysResolutionList(); +#else + return std::vector<std::string>(); +#endif +} + #define UTF16_IS_HIGH_SURROGATE(U) ((U16)((U) - 0xD800) < 0x0400) #define UTF16_IS_LOW_SURROGATE(U) ((U16)((U) - 0xDC00) < 0x0400) #define UTF16_SURROGATE_PAIR_TO_UTF32(H,L) (((H) << 10) + (L) - (0xD800 << 10) - 0xDC00 + 0x00010000) @@ -457,9 +469,8 @@ LLCoordCommon LL_COORD_TYPE_WINDOW::convertToCommon() const { const LLCoordWindow& self = LLCoordWindow::getTypedCoords(*this); - LLWindow* windowp = &(*LLWindow::beginInstances()); LLCoordGL out; - windowp->convertCoords(self, &out); + LLWindow::instance_snapshot().begin()->convertCoords(self, &out); return out.convert(); } @@ -467,18 +478,16 @@ void LL_COORD_TYPE_WINDOW::convertFromCommon(const LLCoordCommon& from) { LLCoordWindow& self = LLCoordWindow::getTypedCoords(*this); - LLWindow* windowp = &(*LLWindow::beginInstances()); LLCoordGL from_gl(from); - windowp->convertCoords(from_gl, &self); + LLWindow::instance_snapshot().begin()->convertCoords(from_gl, &self); } LLCoordCommon LL_COORD_TYPE_SCREEN::convertToCommon() const { const LLCoordScreen& self = LLCoordScreen::getTypedCoords(*this); - LLWindow* windowp = &(*LLWindow::beginInstances()); LLCoordGL out; - windowp->convertCoords(self, &out); + LLWindow::instance_snapshot().begin()->convertCoords(self, &out); return out.convert(); } @@ -486,7 +495,6 @@ void LL_COORD_TYPE_SCREEN::convertFromCommon(const LLCoordCommon& from) { LLCoordScreen& self = LLCoordScreen::getTypedCoords(*this); - LLWindow* windowp = &(*LLWindow::beginInstances()); LLCoordGL from_gl(from); - windowp->convertCoords(from_gl, &self); + LLWindow::instance_snapshot().begin()->convertCoords(from_gl, &self); } diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index a05ba8cbba..d4d5b76937 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -168,6 +168,12 @@ public: // Get system UI size based on DPI (for 96 DPI UI size should be 1.0) virtual F32 getSystemUISize() { return 1.0; } + + static std::vector<std::string> getDisplaysResolutionList(); + + // windows only DirectInput8 for joysticks + virtual void* getDirectInput8() { return NULL; }; + virtual bool getInputDevices(U32 device_type_filter, void * devices_callback, void* userdata) { return false; }; protected: LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags); virtual ~LLWindow(); diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index 94c725fc7e..be61e1e16c 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -98,6 +98,16 @@ BOOL LLWindowCallbacks::handleMiddleMouseUp(LLWindow *window, const LLCoordGL po return FALSE; } +BOOL LLWindowCallbacks::handleOtherMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask, S32 button) +{ + return FALSE; +} + +BOOL LLWindowCallbacks::handleOtherMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask, S32 button) +{ + return FALSE; +} + BOOL LLWindowCallbacks::handleActivate(LLWindow *window, BOOL activated) { return FALSE; @@ -120,6 +130,10 @@ void LLWindowCallbacks::handleScrollWheel(LLWindow *window, S32 clicks) { } +void LLWindowCallbacks::handleScrollHWheel(LLWindow *window, S32 clicks) +{ +} + void LLWindowCallbacks::handleResize(LLWindow *window, const S32 width, const S32 height) { } diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 4d753024fe..3b18648138 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -49,11 +49,14 @@ public: virtual BOOL handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); virtual BOOL handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); virtual BOOL handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); + virtual BOOL handleOtherMouseDown(LLWindow *window, LLCoordGL pos, MASK mask, S32 button); + virtual BOOL handleOtherMouseUp(LLWindow *window, LLCoordGL pos, MASK mask, S32 button); virtual BOOL handleActivate(LLWindow *window, BOOL activated); virtual BOOL handleActivateApp(LLWindow *window, BOOL activating); virtual void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); virtual void handleMouseDragged(LLWindow *window, LLCoordGL pos, MASK mask); virtual void handleScrollWheel(LLWindow *window, S32 clicks); + virtual void handleScrollHWheel(LLWindow *window, S32 clicks); virtual void handleResize(LLWindow *window, S32 width, S32 height); virtual void handleFocus(LLWindow *window); virtual void handleFocusLost(LLWindow *window); diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index 99af161102..44fd4127ce 100644 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -142,7 +142,7 @@ void callDoubleClick(float *pos, unsigned int mask); void callResize(unsigned int width, unsigned int height); void callMouseMoved(float *pos, unsigned int mask); void callMouseDragged(float *pos, unsigned int mask); -void callScrollMoved(float delta); +void callScrollMoved(float deltaX, float deltaY); void callMouseExit(); void callWindowFocus(); void callWindowUnfocus(); @@ -150,8 +150,8 @@ void callWindowHide(); void callWindowUnhide(); void callWindowDidChangeScreen(); void callDeltaUpdate(float *delta, unsigned int mask); -void callMiddleMouseDown(float *pos, unsigned int mask); -void callMiddleMouseUp(float *pos, unsigned int mask); +void callOtherMouseDown(float *pos, unsigned int mask, int button); +void callOtherMouseUp(float *pos, unsigned int mask, int button); void callFocus(); void callFocusLost(); void callModifier(unsigned int mask); diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 3554f90be8..0d0607a0bb 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -41,6 +41,7 @@ #include <OpenGL/OpenGL.h> #include <Carbon/Carbon.h> #include <CoreServices/CoreServices.h> +#include <CoreGraphics/CGDisplayConfiguration.h> extern BOOL gDebugWindowProc; BOOL gHiDPISupport = TRUE; @@ -356,9 +357,13 @@ void callMouseDragged(float *pos, MASK mask) gWindowImplementation->getCallbacks()->handleMouseDragged(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); } -void callScrollMoved(float delta) +void callScrollMoved(float deltaX, float deltaY) { - gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, delta); + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleScrollHWheel(gWindowImplementation, deltaX); + gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, deltaY); + } } void callMouseExit() @@ -417,7 +422,7 @@ void callDeltaUpdate(float *delta, MASK mask) gWindowImplementation->updateMouseDeltas(delta); } -void callMiddleMouseDown(float *pos, MASK mask) +void callOtherMouseDown(float *pos, MASK mask, int button) { LLCoordGL outCoords; outCoords.mX = ll_round(pos[0]); @@ -426,10 +431,18 @@ void callMiddleMouseDown(float *pos, MASK mask) gWindowImplementation->getMouseDeltas(deltas); outCoords.mX += deltas[0]; outCoords.mY += deltas[1]; - gWindowImplementation->getCallbacks()->handleMiddleMouseDown(gWindowImplementation, outCoords, mask); + + if (button == 2) + { + gWindowImplementation->getCallbacks()->handleMiddleMouseDown(gWindowImplementation, outCoords, mask); + } + else + { + gWindowImplementation->getCallbacks()->handleOtherMouseDown(gWindowImplementation, outCoords, mask, button + 1); + } } -void callMiddleMouseUp(float *pos, MASK mask) +void callOtherMouseUp(float *pos, MASK mask, int button) { LLCoordGL outCoords; outCoords.mX = ll_round(pos[0]); @@ -437,8 +450,15 @@ void callMiddleMouseUp(float *pos, MASK mask) float deltas[2]; gWindowImplementation->getMouseDeltas(deltas); outCoords.mX += deltas[0]; - outCoords.mY += deltas[1]; - gWindowImplementation->getCallbacks()->handleMiddleMouseUp(gWindowImplementation, outCoords, mask); + outCoords.mY += deltas[1]; + if (button == 2) + { + gWindowImplementation->getCallbacks()->handleMiddleMouseUp(gWindowImplementation, outCoords, mask); + } + else + { + gWindowImplementation->getCallbacks()->handleOtherMouseUp(gWindowImplementation, outCoords, mask, button + 1); + } } void callModifier(MASK mask) @@ -1892,6 +1912,35 @@ void LLWindowMacOSX::interruptLanguageTextInput() commitCurrentPreedit(mGLView); } +std::vector<std::string> LLWindowMacOSX::getDisplaysResolutionList() +{ + std::vector<std::string> resolution_list; + + CGDirectDisplayID display_ids[10]; + uint32_t found_displays = 0; + CGError err = CGGetActiveDisplayList(10, display_ids, &found_displays); + + if (kCGErrorSuccess != err) + { + LL_WARNS() << "Couldn't get a list of active displays" << LL_ENDL; + return std::vector<std::string>(); + } + + for (uint32_t i = 0; i < found_displays; i++) + { + S32 monitor_width = CGDisplayPixelsWide(display_ids[i]); + S32 monitor_height = CGDisplayPixelsHigh(display_ids[i]); + + std::ostringstream sstream; + sstream << monitor_width << "x" << monitor_height;; + std::string res = sstream.str(); + + resolution_list.push_back(res); + } + + return resolution_list; +} + //static std::vector<std::string> LLWindowMacOSX::getDynamicFallbackFontList() { diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 24651027e8..bf45238c8d 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -114,6 +114,8 @@ public: /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); /*virtual*/ F32 getSystemUISize(); + static std::vector<std::string> getDisplaysResolutionList(); + static std::vector<std::string> getDynamicFallbackFontList(); // Provide native key event data diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index c20e639fc7..85eb9d6d1b 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -51,13 +51,13 @@ extern "C" { # include "fontconfig/fontconfig.h" } -#if LL_LINUX || LL_SOLARIS +#if LL_LINUX // not necessarily available on random SDL platforms, so #if LL_LINUX // for execv(), waitpid(), fork() # include <unistd.h> # include <sys/types.h> # include <sys/wait.h> -#endif // LL_LINUX || LL_SOLARIS +#endif // LL_LINUX extern BOOL gDebugWindowProc; @@ -323,12 +323,6 @@ static int x11_detect_VRAM_kb_fp(FILE *fp, const char *prefix_str) 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); -#else - std::string x_log_location("/var/log/"); std::string fname; int rtn = 0; // 'could not detect' @@ -409,7 +403,6 @@ static int x11_detect_VRAM_kb() } } return rtn; -#endif // LL_SOLARIS } #endif // LL_X11 @@ -484,27 +477,10 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); -#if !LL_SOLARIS - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, (bits <= 16) ? 16 : 24); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, (bits <= 16) ? 16 : 24); // We need stencil support for a few (minor) things. if (!getenv("LL_GL_NO_STENCIL")) SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); -#else - // NOTE- use smaller Z-buffer to enable more graphics cards - // - This should not affect better GPUs and has been proven - // to provide 24-bit z-buffers when available. - // - // As the API states: - // - // GLX_DEPTH_SIZE Must be followed by a nonnegative - // minimum size specification. If this - // value is zero, visuals with no depth - // buffer are preferred. Otherwise, the - // largest available depth buffer of at - // least the minimum size is preferred. - - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); -#endif SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, (bits <= 16) ? 1 : 8); // *FIX: try to toggle vsync here? @@ -682,25 +658,13 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B // fixme: actually, it's REALLY important for picking that we get at // least 8 bits each of red,green,blue. Alpha we can be a bit more // relaxed about if we have to. -#if LL_SOLARIS && defined(__sparc) -// again the __sparc required because Xsun support, 32bit are very pricey on SPARC - if(colorBits < 24) //HACK: on SPARC allow 24-bit color -#else if (colorBits < 32) -#endif { close(); setupFailure( -#if LL_SOLARIS && defined(__sparc) - "Second Life requires at least 24-bit color on SPARC to run in a window.\n" - "Please use fbconfig to set your default color depth to 24 bits.\n" - "You may also need to adjust the X11 setting in SMF. To do so use\n" - " 'svccfg -s svc:/application/x11/x11-server setprop options/default_depth=24'\n" -#else "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" -#endif "Alternately, if you choose to run fullscreen, Second Life\n" "will automatically adjust the screen each time it runs.", "Error", @@ -2503,7 +2467,7 @@ BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) } #endif // LL_GTK -#if LL_LINUX || LL_SOLARIS +#if LL_LINUX // extracted from spawnWebBrowser for clarity and to eliminate // compiler confusion regarding close(int fd) vs. LLWindow::close() void exec_cmd(const std::string& cmd, const std::string& arg) @@ -2559,7 +2523,7 @@ void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async) LL_INFOS() << "spawn_web_browser: " << escaped_url << LL_ENDL; -#if LL_LINUX || LL_SOLARIS +#if LL_LINUX # if LL_X11 if (mSDL_Display) { @@ -2578,7 +2542,7 @@ void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async) cmd += "launch_url.sh"; arg = escaped_url; exec_cmd(cmd, arg); -#endif // LL_LINUX || LL_SOLARIS +#endif // LL_LINUX LL_INFOS() << "spawn_web_browser returning." << LL_ENDL; } diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index e05f507506..b2b123f0da 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -38,6 +38,7 @@ // Linden library includes #include "llerror.h" +#include "llexception.h" #include "llfasttimer.h" #include "llgl.h" #include "llstring.h" @@ -59,6 +60,9 @@ #include <dinput.h> #include <Dbt.h.> +#include <InitGuid.h> // needed for llurlentry test to build on some systems +#pragma comment(lib, "dxguid.lib") // needed for llurlentry test to build on some systems +#pragma comment(lib, "dinput8") const S32 MAX_MESSAGE_PER_UPDATE = 20; const S32 BITS_PER_PIXEL = 32; @@ -76,6 +80,7 @@ const F32 ICON_FLASH_TIME = 0.5f; extern BOOL gDebugWindowProc; LPWSTR gIconResource = IDI_APPLICATION; +LPDIRECTINPUT8 gDirectInput8; LLW32MsgCallback gAsyncMsgCallback = NULL; @@ -117,7 +122,7 @@ void show_window_creation_error(const std::string& title) LL_WARNS("Window") << title << LL_ENDL; } -HGLRC SafeCreateContext(HDC hdc) +HGLRC SafeCreateContext(HDC &hdc) { __try { @@ -129,6 +134,22 @@ HGLRC SafeCreateContext(HDC hdc) } } +GLuint SafeChoosePixelFormat(HDC &hdc, const PIXELFORMATDESCRIPTOR *ppfd) +{ + __try + { + return ChoosePixelFormat(hdc, ppfd); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + // convert to C++ styled exception + // C exception don't allow classes, so it's a regular char array + char integer_string[32]; + sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); + throw std::exception(integer_string); + } +} + //static BOOL LLWindowWin32::sIsClassRegistered = FALSE; @@ -400,6 +421,39 @@ LLWinImm::~LLWinImm() } +class LLMonitorInfo +{ +public: + + std::vector<std::string> getResolutionsList() { return mResList; } + + LLMonitorInfo() + { + EnumDisplayMonitors(0, 0, MonitorEnum, (LPARAM)this); + } + +private: + + static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData) + { + int monitor_width = lprcMonitor->right - lprcMonitor->left; + int monitor_height = lprcMonitor->bottom - lprcMonitor->top; + + std::ostringstream sstream; + sstream << monitor_width << "x" << monitor_height;; + std::string res = sstream.str(); + + LLMonitorInfo* pThis = reinterpret_cast<LLMonitorInfo*>(pData); + pThis->mResList.push_back(res); + + return TRUE; + } + + std::vector<std::string> mResList; +}; + +static LLMonitorInfo sMonitorInfo; + LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, @@ -428,6 +482,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, memset(mCurrentGammaRamp, 0, sizeof(mCurrentGammaRamp)); memset(mPrevGammaRamp, 0, sizeof(mPrevGammaRamp)); mCustomGammaSet = FALSE; + mWindowHandle = NULL; if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &mMouseVanish, 0)) { @@ -482,6 +537,21 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, mhInstance = GetModuleHandle(NULL); mWndProc = NULL; + // Init Direct Input - needed for joystick / Spacemouse + + LPDIRECTINPUT8 di8_interface; + HRESULT status = DirectInput8Create( + mhInstance, // HINSTANCE hinst, + DIRECTINPUT_VERSION, // DWORD dwVersion, + IID_IDirectInput8, // REFIID riidltf, + (LPVOID*)&di8_interface, // LPVOID * ppvOut, + NULL // LPUNKNOWN punkOuter + ); + if (status == DI_OK) + { + gDirectInput8 = di8_interface; + } + mSwapMethod = SWAP_METHOD_UNDEFINED; // No WPARAM yet. @@ -676,6 +746,37 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, // TrackMouseEvent( &track_mouse_event ); // } + // SL-12971 dual GPU display + DISPLAY_DEVICEA display_device; + int display_index = -1; + DWORD display_flags = 0; // EDD_GET_DEVICE_INTERFACE_NAME ? + const size_t display_bytes = sizeof(display_device); + + do + { + if (display_index >= 0) + { + // CHAR DeviceName [ 32] Adapter name + // CHAR DeviceString[128] + CHAR text[256]; + + size_t name_len = strlen(display_device.DeviceName ); + size_t desc_len = strlen(display_device.DeviceString); + + CHAR *name = name_len ? display_device.DeviceName : "???"; + CHAR *desc = desc_len ? display_device.DeviceString : "???"; + + sprintf(text, "Display Device %d: %s, %s", display_index, name, desc); + LL_INFOS("Window") << text << LL_ENDL; + } + + ::ZeroMemory(&display_device,display_bytes); + display_device.cb = display_bytes; + + display_index++; + } while( EnumDisplayDevicesA(NULL, display_index, &display_device, display_flags )); + + LL_INFOS("Window") << "Total Display Devices: " << display_index << LL_ENDL; //----------------------------------------------------------------------- // Create GL drawing context @@ -714,6 +815,7 @@ LLWindowWin32::~LLWindowWin32() void LLWindowWin32::show() { + LL_DEBUGS("Window") << "Setting window to show" << LL_ENDL; ShowWindow(mWindowHandle, SW_SHOW); SetForegroundWindow(mWindowHandle); SetFocus(mWindowHandle); @@ -741,17 +843,27 @@ void LLWindowWin32::restore() SetFocus(mWindowHandle); } +// See SL-12170 +// According to callstack "c0000005 Access violation" happened inside __try block, +// deep in DestroyWindow and crashed viewer, which shouldn't be possible. +// I tried manually causing this exception and it was caught without issues, so +// I'm turning off optimizations for this part to be sure code executes as intended +// (it is a straw, but I have no idea why else __try can get overruled) +#pragma optimize("", off) bool destroy_window_handler(HWND &hWnd) { + bool res; __try { - return DestroyWindow(hWnd); + res = DestroyWindow(hWnd); } __except (EXCEPTION_EXECUTE_HANDLER) { - return false; + res = false; } + return res; } +#pragma optimize("", on) // close() destroys all OS-specific code associated with a window. // Usually called from LLWindowManager::destroyWindow() @@ -773,9 +885,6 @@ void LLWindowWin32::close() resetDisplayResolution(); } - // Don't process events in our mainWindowProc any longer. - SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, NULL); - // Make sure cursor is visible and we haven't mangled the clipping state. showCursor(); setMouseClipping(FALSE); @@ -821,16 +930,24 @@ void LLWindowWin32::close() LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; - // Make sure we don't leave a blank toolbar button. - ShowWindow(mWindowHandle, SW_HIDE); + if (IsWindow(mWindowHandle)) + { + // Make sure we don't leave a blank toolbar button. + ShowWindow(mWindowHandle, SW_HIDE); - // This causes WM_DESTROY to be sent *immediately* - if (!destroy_window_handler(mWindowHandle)) - { - OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"), - mCallbacks->translateString("MBShutdownErr"), - OSMB_OK); - } + // This causes WM_DESTROY to be sent *immediately* + if (!destroy_window_handler(mWindowHandle)) + { + OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"), + mCallbacks->translateString("MBShutdownErr"), + OSMB_OK); + } + } + else + { + // Something killed the window while we were busy destroying gl or handle somehow got broken + LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL; + } mWindowHandle = NULL; } @@ -1116,7 +1233,16 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO mPostQuit = FALSE; // create window - DestroyWindow(mWindowHandle); + LL_DEBUGS("Window") << "Creating window with X: " << window_rect.left + << " Y: " << window_rect.top + << " Width: " << (window_rect.right - window_rect.left) + << " Height: " << (window_rect.bottom - window_rect.top) + << " Fullscreen: " << mFullscreen + << LL_ENDL; + if (mWindowHandle && !destroy_window_handler(mWindowHandle)) + { + LL_WARNS("Window") << "Failed to properly close window before recreating it!" << LL_ENDL; + } mWindowHandle = CreateWindowEx(dw_ex_style, mWindowClassName, mWindowTitle, @@ -1172,11 +1298,24 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO LL_INFOS("Window") << "Device context retrieved." << LL_ENDL ; - if (!(pixel_format = ChoosePixelFormat(mhDC, &pfd))) + try + { + // Looks like ChoosePixelFormat can crash in case of faulty driver + if (!(pixel_format = SafeChoosePixelFormat(mhDC, &pfd))) { + LL_WARNS("Window") << "ChoosePixelFormat failed, code: " << GetLastError() << LL_ENDL; + OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), + mCallbacks->translateString("MBError"), OSMB_OK); close(); + return FALSE; + } + } + catch (...) + { + LOG_UNHANDLED_EXCEPTION("ChoosePixelFormat"); OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), mCallbacks->translateString("MBError"), OSMB_OK); + close(); return FALSE; } @@ -1405,21 +1544,27 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO LL_INFOS("Window") << "pixel formats done." << LL_ENDL ; S32 swap_method = 0; - S32 cur_format = num_formats-1; + S32 cur_format = 0; +const S32 max_format = (S32)num_formats - 1; GLint swap_query = WGL_SWAP_METHOD_ARB; - BOOL found_format = FALSE; - - while (!found_format && wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) + // SL-14705 Fix name tags showing in front of objects with AMD GPUs. + // On AMD hardware we need to iterate from the first pixel format to the end. + // Spec: + // https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_pixel_format.txt + while (wglGetPixelFormatAttribivARB(mhDC, pixel_formats[cur_format], 0, 1, &swap_query, &swap_method)) { - if (swap_method == WGL_SWAP_UNDEFINED_ARB || cur_format <= 0) + if (swap_method == WGL_SWAP_UNDEFINED_ARB) { - found_format = TRUE; + break; } - else + else if (cur_format >= max_format) { - --cur_format; + cur_format = 0; + break; } + + ++cur_format; } pixel_format = pixel_formats[cur_format]; @@ -1436,8 +1581,12 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO ReleaseDC (mWindowHandle, mhDC); // Release The Device Context mhDC = 0; // Zero The Device Context } - DestroyWindow (mWindowHandle); // Destroy The Window - + + // Destroy The Window + if (mWindowHandle && !destroy_window_handler(mWindowHandle)) + { + LL_WARNS("Window") << "Failed to properly close window!" << LL_ENDL; + } mWindowHandle = CreateWindowEx(dw_ex_style, mWindowClassName, @@ -1931,6 +2080,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr( h_wnd, GWLP_USERDATA ); + bool debug_window_proc = gDebugWindowProc || debugLoggingEnabled("Window"); + if (NULL != window_imp) { @@ -1973,9 +2124,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_DEVICECHANGE: window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DEVICECHANGE"); - if (gDebugWindowProc) + if (debug_window_proc) { - LL_INFOS() << " WM_DEVICECHANGE: wParam=" << w_param + LL_INFOS("Window") << " WM_DEVICECHANGE: wParam=" << w_param << "; lParam=" << l_param << LL_ENDL; } if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL) @@ -2031,7 +2182,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ BOOL activating = (BOOL) w_param; BOOL minimized = window_imp->getMinimized(); - if (gDebugWindowProc) + if (debug_window_proc) { LL_INFOS("Window") << "WINDOWPROC ActivateApp " << " activating " << S32(activating) @@ -2082,7 +2233,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // JC - I'm not sure why, but if we don't report that we handled the // WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work // properly when we run fullscreen. - if (gDebugWindowProc) + if (debug_window_proc) { LL_INFOS("Window") << "WINDOWPROC Activate " << " activating " << S32(activating) @@ -2154,7 +2305,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYDOWN"); { - if (gDebugWindowProc) + if (debug_window_proc) { LL_INFOS("Window") << "Debug WindowProc WM_KEYDOWN " << " key " << S32(w_param) @@ -2180,7 +2331,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYUP"); LL_RECORD_BLOCK_TIME(FTM_KEYHANDLER); - if (gDebugWindowProc) + if (debug_window_proc) { LL_INFOS("Window") << "Debug WindowProc WM_KEYUP " << " key " << S32(w_param) @@ -2196,9 +2347,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ } case WM_IME_SETCONTEXT: window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_SETCONTEXT"); - if (gDebugWindowProc) + if (debug_window_proc) { - LL_INFOS() << "WM_IME_SETCONTEXT" << LL_ENDL; + LL_INFOS("Window") << "WM_IME_SETCONTEXT" << LL_ENDL; } if (LLWinImm::isAvailable() && window_imp->mPreeditor) { @@ -2209,7 +2360,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_IME_STARTCOMPOSITION: window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_STARTCOMPOSITION"); - if (gDebugWindowProc) + if (debug_window_proc) { LL_INFOS() << "WM_IME_STARTCOMPOSITION" << LL_ENDL; } @@ -2222,7 +2373,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_IME_ENDCOMPOSITION: window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_ENDCOMPOSITION"); - if (gDebugWindowProc) + if (debug_window_proc) { LL_INFOS() << "WM_IME_ENDCOMPOSITION" << LL_ENDL; } @@ -2234,7 +2385,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_IME_COMPOSITION: window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_COMPOSITION"); - if (gDebugWindowProc) + if (debug_window_proc) { LL_INFOS() << "WM_IME_COMPOSITION" << LL_ENDL; } @@ -2247,7 +2398,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_IME_REQUEST: window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_REQUEST"); - if (gDebugWindowProc) + if (debug_window_proc) { LL_INFOS() << "WM_IME_REQUEST" << LL_ENDL; } @@ -2278,7 +2429,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // characters. We just need to take care of surrogate pairs sent as two WM_CHAR's // by ourselves. It is not that tough. -- Alissa Sabre @ SL window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CHAR"); - if (gDebugWindowProc) + if (debug_window_proc) { LL_INFOS("Window") << "Debug WindowProc WM_CHAR " << " key " << S32(w_param) @@ -2539,6 +2690,72 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ } } break; + case WM_XBUTTONDOWN: + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONDOWN"); + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + S32 button = GET_XBUTTON_WPARAM(w_param); + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + window_imp->interruptLanguageTextInput(); + } + + // Because we move the cursor position in tllviewerhe 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 + // first click changes the cursor position, all subsequent clicks + // will occur at the wrong location. JC + if (window_imp->mMousePositionModified) + { + LLCoordWindow cursor_coord_window; + window_imp->getCursorPosition(&cursor_coord_window); + gl_coord = cursor_coord_window.convert(); + } + else + { + gl_coord = window_coord.convert(); + } + MASK mask = gKeyboard->currentMask(TRUE); + // generate move event to update mouse coordinates + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); + // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 + if (window_imp->mCallbacks->handleOtherMouseDown(window_imp, gl_coord, mask, button + 3)) + { + return 0; + } + } + break; + + case WM_XBUTTONUP: + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONUP"); + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + S32 button = GET_XBUTTON_WPARAM(w_param); + // 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 + // first click changes the cursor position, all subsequent clicks + // will occur at the wrong location. JC + if (window_imp->mMousePositionModified) + { + LLCoordWindow cursor_coord_window; + window_imp->getCursorPosition(&cursor_coord_window); + gl_coord = cursor_coord_window.convert(); + } + else + { + gl_coord = window_coord.convert(); + } + MASK mask = gKeyboard->currentMask(TRUE); + // generate move event to update mouse coordinates + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); + // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 + if (window_imp->mCallbacks->handleOtherMouseUp(window_imp, gl_coord, mask, button + 3)) + { + return 0; + } + } + break; case WM_MOUSEWHEEL: { @@ -2596,6 +2813,42 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ return 0; } */ + case WM_MOUSEHWHEEL: + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEHWHEEL"); + static short h_delta = 0; + + RECT client_rect; + + // eat scroll events that occur outside our window, since we use mouse position to direct scroll + // instead of keyboard focus + // NOTE: mouse_coord is in *window* coordinates for scroll events + POINT mouse_coord = {(S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)}; + + if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord) + && GetClientRect(window_imp->mWindowHandle, &client_rect)) + { + // we have a valid mouse point and client rect + if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x + || mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y) + { + // mouse is outside of client rect, so don't do anything + return 0; + } + } + + S16 incoming_h_delta = HIWORD(w_param); + h_delta += incoming_h_delta; + + // If the user rapidly spins the wheel, we can get messages with + // large deltas, like 480 or so. Thus we need to scroll more quickly. + if (h_delta <= -WHEEL_DELTA || WHEEL_DELTA <= h_delta) + { + window_imp->mCallbacks->handleScrollHWheel(window_imp, h_delta / WHEEL_DELTA); + h_delta = 0; + } + return 0; + } // Handle mouse movement within the window case WM_MOUSEMOVE: { @@ -2619,7 +2872,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ S32 width = S32( LOWORD(l_param) ); S32 height = S32( HIWORD(l_param) ); - if (gDebugWindowProc) + if (debug_window_proc) { BOOL maximized = ( w_param == SIZE_MAXIMIZED ); BOOL restored = ( w_param == SIZE_RESTORED ); @@ -2694,7 +2947,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ } case WM_SETFOCUS: - if (gDebugWindowProc) + if (debug_window_proc) { LL_INFOS("Window") << "WINDOWPROC SetFocus" << LL_ENDL; } @@ -2703,7 +2956,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ return 0; case WM_KILLFOCUS: - if (gDebugWindowProc) + if (debug_window_proc) { LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL; } @@ -2735,7 +2988,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; default: { - if (gDebugWindowProc) + if (debug_window_proc) { LL_INFOS("Window") << "Unhandled windows message code: " << U32(u_msg) << LL_ENDL; } @@ -2745,7 +2998,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->mCallbacks->handlePauseWatchdog(window_imp); } - + else + { + // (NULL == window_imp) + LL_DEBUGS("Window") << "No window implementation to handle message with, message code: " << U32(u_msg) << LL_ENDL; + } // pass unhandled messages down to Windows return DefWindowProc(h_wnd, u_msg, w_param, l_param); @@ -3272,7 +3529,10 @@ void LLSplashScreenWin32::hideImpl() { if (mWindow) { - DestroyWindow(mWindow); + if (!destroy_window_handler(mWindow)) + { + LL_WARNS("Window") << "Failed to properly close splash screen window!" << LL_ENDL; + } mWindow = NULL; } } @@ -4045,6 +4305,28 @@ void LLWindowWin32::setDPIAwareness() } } +void* LLWindowWin32::getDirectInput8() +{ + return &gDirectInput8; +} + +bool LLWindowWin32::getInputDevices(U32 device_type_filter, void * di8_devices_callback, void* userdata) +{ + if (gDirectInput8 != NULL) + { + // Enumerate devices + HRESULT status = gDirectInput8->EnumDevices( + (DWORD) device_type_filter, // DWORD dwDevType, + (LPDIENUMDEVICESCALLBACK)di8_devices_callback, // LPDIENUMDEVICESCALLBACK lpCallback, // BOOL DIEnumDevicesCallback( LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef ) // BOOL CALLBACK DinputDevice::DevicesCallback + (LPVOID*)userdata, // LPVOID pvRef + DIEDFL_ATTACHEDONLY // DWORD dwFlags + ); + + return status == DI_OK; + } + return false; +} + F32 LLWindowWin32::getSystemUISize() { F32 scale_value = 1.f; @@ -4107,6 +4389,12 @@ F32 LLWindowWin32::getSystemUISize() } //static +std::vector<std::string> LLWindowWin32::getDisplaysResolutionList() +{ + return sMonitorInfo.getResolutionsList(); +} + +//static std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList() { // Fonts previously in getFontListSans() have moved to fonts.xml. diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 9cd16eb993..0b3d14fb16 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -114,8 +114,12 @@ public: LLWindowCallbacks::DragNDropResult completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ); + static std::vector<std::string> getDisplaysResolutionList(); static std::vector<std::string> getDynamicFallbackFontList(); static void setDPIAwareness(); + + /*virtual*/ void* getDirectInput8(); + /*virtual*/ bool getInputDevices(U32 device_type_filter, void * di8_devices_callback, void* userdata); protected: LLWindowWin32(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, diff --git a/indra/llxml/CMakeLists.txt b/indra/llxml/CMakeLists.txt index 17400a203e..013a422d35 100644 --- a/indra/llxml/CMakeLists.txt +++ b/indra/llxml/CMakeLists.txt @@ -28,7 +28,6 @@ set(llxml_HEADER_FILES CMakeLists.txt llcontrol.h - llcontrolgroupreader.h llxmlnode.h llxmlparser.h llxmltree.h diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index ccf4f3ddf5..ead8634df4 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -40,6 +40,7 @@ #include "v4coloru.h" #include "v4color.h" #include "v3color.h" +#include "llquaternion.h" #include "llrect.h" #include "llxmltree.h" #include "llsdserialize.h" @@ -125,6 +126,9 @@ bool LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b) case TYPE_VEC3D: result = LLVector3d(a) == LLVector3d(b); break; + case TYPE_QUAT: + result = LLQuaternion(a) == LLQuaternion(b); + break; case TYPE_RECT: result = LLRect(a) == LLRect(b); break; @@ -361,6 +365,7 @@ const std::string LLControlGroup::mTypeString[TYPE_COUNT] = { "U32" ,"String" ,"Vector3" ,"Vector3D" + ,"Quaternion" ,"Rect" ,"Color4" ,"Color3" @@ -523,6 +528,11 @@ LLControlVariable* LLControlGroup::declareVec3d(const std::string& name, const L return declareControl(name, TYPE_VEC3D, initial_val.getValue(), comment, persist); } +LLControlVariable* LLControlGroup::declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist) +{ + return declareControl(name, TYPE_QUAT, initial_val.getValue(), comment, persist); +} + LLControlVariable* LLControlGroup::declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist) { return declareControl(name, TYPE_RECT, initial_val.getValue(), comment, persist); @@ -600,6 +610,11 @@ LLVector3d LLControlGroup::getVector3d(const std::string& name) return get<LLVector3d>(name); } +LLQuaternion LLControlGroup::getQuaternion(const std::string& name) +{ + return get<LLQuaternion>(name); +} + LLRect LLControlGroup::getRect(const std::string& name) { return get<LLRect>(name); @@ -626,6 +641,24 @@ LLSD LLControlGroup::getLLSD(const std::string& name) return get<LLSD>(name); } +LLSD LLControlGroup::asLLSD(bool diffs_only) +{ + // Dump all stored values as LLSD + LLSD result = LLSD::emptyArray(); + for (ctrl_name_table_t::iterator iter = mNameTable.begin(); + iter != mNameTable.end(); iter++) + { + LLControlVariable *control = iter->second; + if (!control || control->isType(TYPE_STRING) || (diffs_only && control->isDefault())) + { + continue; + } + const std::string& name = iter->first; + result[name] = getLLSD(name); + } + return result; +} + BOOL LLControlGroup::controlExists(const std::string& name) { ctrl_name_table_t::iterator iter = mNameTable.find(name); @@ -677,6 +710,11 @@ void LLControlGroup::setVector3d(const std::string& name, const LLVector3d &val) set(name, val); } +void LLControlGroup::setQuaternion(const std::string& name, const LLQuaternion &val) +{ + set(name, val); +} + void LLControlGroup::setRect(const std::string& name, const LLRect &val) { set(name, val); @@ -859,6 +897,16 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require validitems++; } break; + case TYPE_QUAT: + { + LLQuaternion quat; + + child_nodep->getAttributeQuat("value", quat); + + control->set(quat.getValue()); + validitems++; + } + break; case TYPE_RECT: { //RN: hack to support reading rectangles from a string @@ -1201,6 +1249,11 @@ template <> eControlType get_control_type<LLVector3d>() return TYPE_VEC3D; } +template <> eControlType get_control_type<LLQuaternion>() +{ + return TYPE_QUAT; +} + template <> eControlType get_control_type<LLRect>() { return TYPE_RECT; @@ -1236,6 +1289,10 @@ template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in) { return in.getValue(); } +template <> LLSD convert_to_llsd<LLQuaternion>(const LLQuaternion& in) +{ + return in.getValue(); +} template <> LLSD convert_to_llsd<LLRect>(const LLRect& in) { @@ -1349,6 +1406,18 @@ LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, cons } template<> +LLQuaternion convert_from_llsd<LLQuaternion>(const LLSD& sd, eControlType type, const std::string& control_name) +{ + if (type == TYPE_QUAT) + return (LLQuaternion)sd; + else + { + CONTROL_ERRS << "Invalid LLQuaternion value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return LLQuaternion(); + } +} + +template<> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, const std::string& control_name) { if (type == TYPE_RECT) diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index de0d366492..19508becc3 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -34,8 +34,6 @@ #include "llrefcount.h" #include "llinstancetracker.h" -#include "llcontrolgroupreader.h" - #include <vector> // *NOTE: boost::visit_each<> generates warning 4675 on .net 2003 @@ -67,6 +65,7 @@ class LLVector3; class LLVector3d; +class LLQuaternion; class LLColor4; class LLColor3; @@ -80,6 +79,7 @@ typedef enum e_control_type TYPE_STRING, TYPE_VEC3, TYPE_VEC3D, + TYPE_QUAT, TYPE_RECT, TYPE_COL4, TYPE_COL3, @@ -200,8 +200,6 @@ public: LLControlGroup(const std::string& name); ~LLControlGroup(); void cleanup(); - - typedef LLInstanceTracker<LLControlGroup, std::string>::instance_iter instance_iter; LLControlVariablePtr getControl(const std::string& name); @@ -220,6 +218,7 @@ public: LLControlVariable* declareString(const std::string& name, const std::string &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); LLControlVariable* declareVec3(const std::string& name, const LLVector3 &initial_val,const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); LLControlVariable* declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); LLControlVariable* declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); LLControlVariable* declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); LLControlVariable* declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); @@ -234,15 +233,17 @@ public: LLWString getWString(const std::string& name); LLVector3 getVector3(const std::string& name); - LLVector3d getVector3d(const std::string& name); + LLVector3d getVector3d(const std::string& name); LLRect getRect(const std::string& name); LLSD getLLSD(const std::string& name); - + LLQuaternion getQuaternion(const std::string& name); LLColor4 getColor(const std::string& name); LLColor4 getColor4(const std::string& name); LLColor3 getColor3(const std::string& name); + LLSD asLLSD(bool diffs_only); + // generic getter template<typename T> T get(const std::string& name) { @@ -270,6 +271,7 @@ public: void setString(const std::string& name, const std::string& val); void setVector3(const std::string& name, const LLVector3 &val); void setVector3d(const std::string& name, const LLVector3d &val); + void setQuaternion(const std::string& name, const LLQuaternion &val); void setRect(const std::string& name, const LLRect &val); void setColor4(const std::string& name, const LLColor4 &val); void setLLSD(const std::string& name, const LLSD& val); @@ -436,7 +438,8 @@ template <> eControlType get_control_type<bool>(); //template <> eControlType get_control_type<BOOL> () template <> eControlType get_control_type<std::string>(); template <> eControlType get_control_type<LLVector3>(); -template <> eControlType get_control_type<LLVector3d>(); +template <> eControlType get_control_type<LLVector3d>(); +template <> eControlType get_control_type<LLQuaternion>(); template <> eControlType get_control_type<LLRect>(); template <> eControlType get_control_type<LLColor4>(); template <> eControlType get_control_type<LLColor3>(); @@ -444,7 +447,8 @@ template <> eControlType get_control_type<LLSD>(); template <> LLSD convert_to_llsd<U32>(const U32& in); template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in); -template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in); +template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in); +template <> LLSD convert_to_llsd<LLQuaternion>(const LLQuaternion& in); template <> LLSD convert_to_llsd<LLRect>(const LLRect& in); template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in); template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in); @@ -453,6 +457,7 @@ template<> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlTy template<> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, const std::string& control_name); template<> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, const std::string& control_name); template<> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, const std::string& control_name); +template<> LLQuaternion convert_from_llsd<LLQuaternion>(const LLSD& sd, eControlType type, const std::string& control_name); template<> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, const std::string& control_name); template<> bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, const std::string& control_name); template<> S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, const std::string& control_name); diff --git a/indra/llxml/llcontrolgroupreader.h b/indra/llxml/llcontrolgroupreader.h deleted file mode 100644 index 6a27a65499..0000000000 --- a/indra/llxml/llcontrolgroupreader.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @file llcontrolgroupreader.h - * @brief Interface providing readonly access to LLControlGroup (intended for unit testing) - * - * $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_LLCONTROLGROUPREADER_H -#define LL_LLCONTROLGROUPREADER_H - -#include "stdtypes.h" -#include <string> - -#include "v3math.h" -#include "v3dmath.h" -#include "v3color.h" -#include "v4color.h" -#include "llrect.h" - -class LLControlGroupReader -{ -public: - LLControlGroupReader() {} - virtual ~LLControlGroupReader() {} - - virtual std::string getString(const std::string& name) { return ""; } - virtual LLWString getWString(const std::string& name) { return LLWString(); } - virtual std::string getText(const std::string& name) { return ""; } - virtual LLVector3 getVector3(const std::string& name) { return LLVector3(); } - virtual LLVector3d getVector3d(const std::string& name) { return LLVector3d(); } - virtual LLRect getRect(const std::string& name) { return LLRect(); } - virtual BOOL getBOOL(const std::string& name) { return FALSE; } - virtual S32 getS32(const std::string& name) { return 0; } - virtual F32 getF32(const std::string& name) {return 0.0f; } - virtual U32 getU32(const std::string& name) {return 0; } - virtual LLSD getLLSD(const std::string& name) { return LLSD(); } - - virtual LLColor4 getColor(const std::string& name) { return LLColor4(); } - virtual LLColor4 getColor4(const std::string& name) { return LLColor4(); } - virtual LLColor3 getColor3(const std::string& name) { return LLColor3(); } - - virtual void setBOOL(const std::string& name, BOOL val) {} - virtual void setS32(const std::string& name, S32 val) {} - virtual void setF32(const std::string& name, F32 val) {} - virtual void setU32(const std::string& name, U32 val) {} - virtual void setString(const std::string& name, const std::string& val) {} - virtual void setVector3(const std::string& name, const LLVector3 &val) {} - virtual void setVector3d(const std::string& name, const LLVector3d &val) {} - virtual void setRect(const std::string& name, const LLRect &val) {} - virtual void setColor4(const std::string& name, const LLColor4 &val) {} - virtual void setLLSD(const std::string& name, const LLSD& val) {} -}; - -#endif /* LL_LLCONTROLGROUPREADER_H */ - - - - - - - diff --git a/indra/llxml/llxmltree.cpp b/indra/llxml/llxmltree.cpp index ca98953f92..ed9c07e1db 100644 --- a/indra/llxml/llxmltree.cpp +++ b/indra/llxml/llxmltree.cpp @@ -111,9 +111,11 @@ LLXmlTreeNode::~LLXmlTreeNode() attribute_map_t::iterator iter; for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++) delete iter->second; - child_list_t::iterator child_iter; - for (child_iter=mChildList.begin(); child_iter != mChildList.end(); child_iter++) - delete *child_iter; + for(LLXmlTreeNode* node : mChildren) + { + delete node; + } + mChildren.clear(); } void LLXmlTreeNode::dump( const std::string& prefix ) @@ -149,15 +151,15 @@ void LLXmlTreeNode::addAttribute(const std::string& name, const std::string& val LLXmlTreeNode* LLXmlTreeNode::getFirstChild() { - mChildListIter = mChildList.begin(); + mChildrenIter = mChildren.begin(); return getNextChild(); } LLXmlTreeNode* LLXmlTreeNode::getNextChild() { - if (mChildListIter == mChildList.end()) + if (mChildrenIter == mChildren.end()) return 0; else - return *mChildListIter++; + return *mChildrenIter++; } LLXmlTreeNode* LLXmlTreeNode::getChildByName(const std::string& name) @@ -184,7 +186,7 @@ void LLXmlTreeNode::appendContents(const std::string& str) void LLXmlTreeNode::addChild(LLXmlTreeNode* child) { llassert( child ); - mChildList.push_back( child ); + mChildren.push_back( child ); // Add a name mapping to this node LLStdStringHandle tableptr = mTree->mNodeNames.insert(child->mName); diff --git a/indra/llxml/llxmltree.h b/indra/llxml/llxmltree.h index a82fee0416..3e425c3870 100644 --- a/indra/llxml/llxmltree.h +++ b/indra/llxml/llxmltree.h @@ -151,7 +151,7 @@ public: LLXmlTreeNode* getParent() { return mParent; } LLXmlTreeNode* getFirstChild(); LLXmlTreeNode* getNextChild(); - S32 getChildCount() { return (S32)mChildList.size(); } + S32 getChildCount() { return (S32)mChildren.size(); } LLXmlTreeNode* getChildByName( const std::string& name ); // returns first child with name, NULL if none LLXmlTreeNode* getNextNamedChild(); // returns next child with name, NULL if none @@ -177,9 +177,9 @@ private: std::string mName; std::string mContents; - typedef std::list<class LLXmlTreeNode *> child_list_t; - child_list_t mChildList; - child_list_t::iterator mChildListIter; + typedef std::vector<class LLXmlTreeNode *> children_t; + children_t mChildren; + children_t::iterator mChildrenIter; typedef std::multimap<LLStdStringHandle, LLXmlTreeNode *> child_map_t; child_map_t mChildMap; // for fast name lookups diff --git a/indra/mac_crash_logger/CMakeLists.txt b/indra/mac_crash_logger/CMakeLists.txt deleted file mode 100644 index f6c4dfb59d..0000000000 --- a/indra/mac_crash_logger/CMakeLists.txt +++ /dev/null @@ -1,95 +0,0 @@ -# -*- cmake -*- - -project(mac_crash_logger) - -include(00-Common) -include(LLCommon) -include(LLCoreHttp) -include(LLCrashLogger) -include(LLMath) -include(LLMessage) -include(LLVFS) -include(LLXML) -include(Linking) -include(LLSharedLibs) -include(Boost) - -include_directories( - ${LLCOREHTTP_INCLUDE_DIRS} - ${LLCOMMON_INCLUDE_DIRS} - ${LLCRASHLOGGER_INCLUDE_DIRS} - ${LLMATH_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} - ${LLXML_INCLUDE_DIRS} - ) -include_directories(SYSTEM - ${LLCOMMON_SYSTEM_INCLUDE_DIRS} - ${LLXML_SYSTEM_INCLUDE_DIRS} - ) - -set(mac_crash_logger_SOURCE_FILES - mac_crash_logger.cpp - llcrashloggermac.cpp - llcrashloggermacdelegate.mm - ) - -set(mac_crash_logger_HEADER_FILES - CMakeLists.txt - - llcrashloggermac.h - llcrashloggermacdelegate.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 - ) - -find_library(COCOA_LIBRARY Cocoa) - -target_link_libraries(mac-crash-logger - ${LLCRASHLOGGER_LIBRARIES} - ${LLVFS_LIBRARIES} - ${COCOA_LIBRARIES} - ${LLXML_LIBRARIES} - ${LLMESSAGE_LIBRARIES} - ${LLVFS_LIBRARIES} - ${LLMATH_LIBRARIES} - ${LLCOREHTTP_LIBRARIES} - ${LLCOMMON_LIBRARIES} - ${BOOST_CONTEXT_LIBRARY} - ${BOOST_COROUTINE_LIBRARY} - ) - -add_custom_command( - TARGET mac-crash-logger POST_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS - -E - copy_if_different - ${CMAKE_CURRENT_SOURCE_DIR}/CrashReporter.nib - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/mac-crash-logger.app/Contents/Resources/CrashReporter.nib - ) - -ll_deploy_sharedlibs_command(mac-crash-logger) - - diff --git a/indra/mac_crash_logger/CrashReporter.nib b/indra/mac_crash_logger/CrashReporter.nib Binary files differdeleted file mode 100755 index e9d9e05985..0000000000 --- a/indra/mac_crash_logger/CrashReporter.nib +++ /dev/null diff --git a/indra/mac_crash_logger/CrashReporter.xib b/indra/mac_crash_logger/CrashReporter.xib deleted file mode 100755 index f6d4776d51..0000000000 --- a/indra/mac_crash_logger/CrashReporter.xib +++ /dev/null @@ -1,3895 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00"> - <data> - <int key="IBDocument.SystemTarget">1070</int> - <string key="IBDocument.SystemVersion">11G63</string> - <string key="IBDocument.InterfaceBuilderVersion">2182</string> - <string key="IBDocument.AppKitVersion">1138.51</string> - <string key="IBDocument.HIToolboxVersion">569.00</string> - <object class="NSMutableDictionary" key="IBDocument.PluginVersions"> - <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="NS.object.0">2182</string> - </object> - <array key="IBDocument.IntegratedClassDependencies"> - <string>NSTextField</string> - <string>NSView</string> - <string>NSWindowTemplate</string> - <string>NSMenu</string> - <string>NSMenuItem</string> - <string>NSTextFieldCell</string> - <string>NSButtonCell</string> - <string>IBNSLayoutConstraint</string> - <string>NSButton</string> - <string>NSCustomObject</string> - </array> - <array key="IBDocument.PluginDependencies"> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - </array> - <object class="NSMutableDictionary" key="IBDocument.Metadata"> - <string key="NS.key.0">PluginDependencyRecalculationVersion</string> - <integer value="1" key="NS.object.0"/> - </object> - <array class="NSMutableArray" key="IBDocument.RootObjects" id="1048"> - <object class="NSCustomObject" id="1021"> - <string key="NSClassName">NSApplication</string> - </object> - <object class="NSCustomObject" id="1014"> - <string key="NSClassName">FirstResponder</string> - </object> - <object class="NSCustomObject" id="1050"> - <string key="NSClassName">NSApplication</string> - </object> - <object class="NSMenu" id="649796088"> - <string key="NSTitle">AMainMenu</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="694149608"> - <reference key="NSMenu" ref="649796088"/> - <string key="NSTitle">Second Life Crash Logger</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <object class="NSCustomResource" key="NSOnImage" id="35465992"> - <string key="NSClassName">NSImage</string> - <string key="NSResourceName">NSMenuCheckmark</string> - </object> - <object class="NSCustomResource" key="NSMixedImage" id="502551668"> - <string key="NSClassName">NSImage</string> - <string key="NSResourceName">NSMenuMixedState</string> - </object> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="110575045"> - <string key="NSTitle">Second Life Crash Logger</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="238522557"> - <reference key="NSMenu" ref="110575045"/> - <string key="NSTitle">About Second Life Crash Logger</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="304266470"> - <reference key="NSMenu" ref="110575045"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="609285721"> - <reference key="NSMenu" ref="110575045"/> - <string key="NSTitle">Preferences…</string> - <string key="NSKeyEquiv">,</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="481834944"> - <reference key="NSMenu" ref="110575045"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="1046388886"> - <reference key="NSMenu" ref="110575045"/> - <string key="NSTitle">Services</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="752062318"> - <string key="NSTitle">Services</string> - <array class="NSMutableArray" key="NSMenuItems"/> - <string key="NSName">_NSServicesMenu</string> - </object> - </object> - <object class="NSMenuItem" id="646227648"> - <reference key="NSMenu" ref="110575045"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="755159360"> - <reference key="NSMenu" ref="110575045"/> - <string key="NSTitle">Hide Second Life Crash Logger</string> - <string key="NSKeyEquiv">h</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="342932134"> - <reference key="NSMenu" ref="110575045"/> - <string key="NSTitle">Hide Others</string> - <string key="NSKeyEquiv">h</string> - <int key="NSKeyEquivModMask">1572864</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="908899353"> - <reference key="NSMenu" ref="110575045"/> - <string key="NSTitle">Show All</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="1056857174"> - <reference key="NSMenu" ref="110575045"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="632727374"> - <reference key="NSMenu" ref="110575045"/> - <string key="NSTitle">Quit Second Life Crash Logger</string> - <string key="NSKeyEquiv">q</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - <string key="NSName">_NSAppleMenu</string> - </object> - </object> - <object class="NSMenuItem" id="379814623"> - <reference key="NSMenu" ref="649796088"/> - <string key="NSTitle">File</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="720053764"> - <string key="NSTitle">File</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="705341025"> - <reference key="NSMenu" ref="720053764"/> - <string key="NSTitle">New</string> - <string key="NSKeyEquiv">n</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="722745758"> - <reference key="NSMenu" ref="720053764"/> - <string key="NSTitle">Open…</string> - <string key="NSKeyEquiv">o</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="1025936716"> - <reference key="NSMenu" ref="720053764"/> - <string key="NSTitle">Open Recent</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="1065607017"> - <string key="NSTitle">Open Recent</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="759406840"> - <reference key="NSMenu" ref="1065607017"/> - <string key="NSTitle">Clear Menu</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - <string key="NSName">_NSRecentDocumentsMenu</string> - </object> - </object> - <object class="NSMenuItem" id="425164168"> - <reference key="NSMenu" ref="720053764"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="776162233"> - <reference key="NSMenu" ref="720053764"/> - <string key="NSTitle">Close</string> - <string key="NSKeyEquiv">w</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="1023925487"> - <reference key="NSMenu" ref="720053764"/> - <string key="NSTitle">Save…</string> - <string key="NSKeyEquiv">s</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="579971712"> - <reference key="NSMenu" ref="720053764"/> - <string key="NSTitle">Revert to Saved</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="1010469920"> - <reference key="NSMenu" ref="720053764"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="294629803"> - <reference key="NSMenu" ref="720053764"/> - <string key="NSTitle">Page Setup...</string> - <string key="NSKeyEquiv">P</string> - <int key="NSKeyEquivModMask">1179648</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSToolTip"/> - </object> - <object class="NSMenuItem" id="49223823"> - <reference key="NSMenu" ref="720053764"/> - <string key="NSTitle">Print…</string> - <string key="NSKeyEquiv">p</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - </object> - </object> - <object class="NSMenuItem" id="952259628"> - <reference key="NSMenu" ref="649796088"/> - <string key="NSTitle">Edit</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="789758025"> - <string key="NSTitle">Edit</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="1058277027"> - <reference key="NSMenu" ref="789758025"/> - <string key="NSTitle">Undo</string> - <string key="NSKeyEquiv">z</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="790794224"> - <reference key="NSMenu" ref="789758025"/> - <string key="NSTitle">Redo</string> - <string key="NSKeyEquiv">Z</string> - <int key="NSKeyEquivModMask">1179648</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="1040322652"> - <reference key="NSMenu" ref="789758025"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="296257095"> - <reference key="NSMenu" ref="789758025"/> - <string key="NSTitle">Cut</string> - <string key="NSKeyEquiv">x</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="860595796"> - <reference key="NSMenu" ref="789758025"/> - <string key="NSTitle">Copy</string> - <string key="NSKeyEquiv">c</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="29853731"> - <reference key="NSMenu" ref="789758025"/> - <string key="NSTitle">Paste</string> - <string key="NSKeyEquiv">v</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="82994268"> - <reference key="NSMenu" ref="789758025"/> - <string key="NSTitle">Paste and Match Style</string> - <string key="NSKeyEquiv">V</string> - <int key="NSKeyEquivModMask">1572864</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="437104165"> - <reference key="NSMenu" ref="789758025"/> - <string key="NSTitle">Delete</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="583158037"> - <reference key="NSMenu" ref="789758025"/> - <string key="NSTitle">Select All</string> - <string key="NSKeyEquiv">a</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="212016141"> - <reference key="NSMenu" ref="789758025"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="892235320"> - <reference key="NSMenu" ref="789758025"/> - <string key="NSTitle">Find</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="963351320"> - <string key="NSTitle">Find</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="447796847"> - <reference key="NSMenu" ref="963351320"/> - <string key="NSTitle">Find…</string> - <string key="NSKeyEquiv">f</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <int key="NSTag">1</int> - </object> - <object class="NSMenuItem" id="738670835"> - <reference key="NSMenu" ref="963351320"/> - <string key="NSTitle">Find and Replace…</string> - <string key="NSKeyEquiv">f</string> - <int key="NSKeyEquivModMask">1572864</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <int key="NSTag">12</int> - </object> - <object class="NSMenuItem" id="326711663"> - <reference key="NSMenu" ref="963351320"/> - <string key="NSTitle">Find Next</string> - <string key="NSKeyEquiv">g</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <int key="NSTag">2</int> - </object> - <object class="NSMenuItem" id="270902937"> - <reference key="NSMenu" ref="963351320"/> - <string key="NSTitle">Find Previous</string> - <string key="NSKeyEquiv">G</string> - <int key="NSKeyEquivModMask">1179648</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <int key="NSTag">3</int> - </object> - <object class="NSMenuItem" id="159080638"> - <reference key="NSMenu" ref="963351320"/> - <string key="NSTitle">Use Selection for Find</string> - <string key="NSKeyEquiv">e</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <int key="NSTag">7</int> - </object> - <object class="NSMenuItem" id="88285865"> - <reference key="NSMenu" ref="963351320"/> - <string key="NSTitle">Jump to Selection</string> - <string key="NSKeyEquiv">j</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - </object> - </object> - <object class="NSMenuItem" id="972420730"> - <reference key="NSMenu" ref="789758025"/> - <string key="NSTitle">Spelling and Grammar</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="769623530"> - <string key="NSTitle">Spelling and Grammar</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="679648819"> - <reference key="NSMenu" ref="769623530"/> - <string key="NSTitle">Show Spelling and Grammar</string> - <string key="NSKeyEquiv">:</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="96193923"> - <reference key="NSMenu" ref="769623530"/> - <string key="NSTitle">Check Document Now</string> - <string key="NSKeyEquiv">;</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="859480356"> - <reference key="NSMenu" ref="769623530"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="948374510"> - <reference key="NSMenu" ref="769623530"/> - <string key="NSTitle">Check Spelling While Typing</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="967646866"> - <reference key="NSMenu" ref="769623530"/> - <string key="NSTitle">Check Grammar With Spelling</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="795346622"> - <reference key="NSMenu" ref="769623530"/> - <string key="NSTitle">Correct Spelling Automatically</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - </object> - </object> - <object class="NSMenuItem" id="507821607"> - <reference key="NSMenu" ref="789758025"/> - <string key="NSTitle">Substitutions</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="698887838"> - <string key="NSTitle">Substitutions</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="65139061"> - <reference key="NSMenu" ref="698887838"/> - <string key="NSTitle">Show Substitutions</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="19036812"> - <reference key="NSMenu" ref="698887838"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="605118523"> - <reference key="NSMenu" ref="698887838"/> - <string key="NSTitle">Smart Copy/Paste</string> - <string key="NSKeyEquiv">f</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <int key="NSTag">1</int> - </object> - <object class="NSMenuItem" id="197661976"> - <reference key="NSMenu" ref="698887838"/> - <string key="NSTitle">Smart Quotes</string> - <string key="NSKeyEquiv">g</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <int key="NSTag">2</int> - </object> - <object class="NSMenuItem" id="672708820"> - <reference key="NSMenu" ref="698887838"/> - <string key="NSTitle">Smart Dashes</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="708854459"> - <reference key="NSMenu" ref="698887838"/> - <string key="NSTitle">Smart Links</string> - <string key="NSKeyEquiv">G</string> - <int key="NSKeyEquivModMask">1179648</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <int key="NSTag">3</int> - </object> - <object class="NSMenuItem" id="537092702"> - <reference key="NSMenu" ref="698887838"/> - <string key="NSTitle">Text Replacement</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - </object> - </object> - <object class="NSMenuItem" id="288088188"> - <reference key="NSMenu" ref="789758025"/> - <string key="NSTitle">Transformations</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="579392910"> - <string key="NSTitle">Transformations</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="1060694897"> - <reference key="NSMenu" ref="579392910"/> - <string key="NSTitle">Make Upper Case</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="879586729"> - <reference key="NSMenu" ref="579392910"/> - <string key="NSTitle">Make Lower Case</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="56570060"> - <reference key="NSMenu" ref="579392910"/> - <string key="NSTitle">Capitalize</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - </object> - </object> - <object class="NSMenuItem" id="676164635"> - <reference key="NSMenu" ref="789758025"/> - <string key="NSTitle">Speech</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="785027613"> - <string key="NSTitle">Speech</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="731782645"> - <reference key="NSMenu" ref="785027613"/> - <string key="NSTitle">Start Speaking</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="680220178"> - <reference key="NSMenu" ref="785027613"/> - <string key="NSTitle">Stop Speaking</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - </object> - </object> - </array> - </object> - </object> - <object class="NSMenuItem" id="302598603"> - <reference key="NSMenu" ref="649796088"/> - <string key="NSTitle">Format</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="941447902"> - <string key="NSTitle">Format</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="792887677"> - <reference key="NSMenu" ref="941447902"/> - <string key="NSTitle">Font</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="786677654"> - <string key="NSTitle">Font</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="159677712"> - <reference key="NSMenu" ref="786677654"/> - <string key="NSTitle">Show Fonts</string> - <string key="NSKeyEquiv">t</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="305399458"> - <reference key="NSMenu" ref="786677654"/> - <string key="NSTitle">Bold</string> - <string key="NSKeyEquiv">b</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <int key="NSTag">2</int> - </object> - <object class="NSMenuItem" id="814362025"> - <reference key="NSMenu" ref="786677654"/> - <string key="NSTitle">Italic</string> - <string key="NSKeyEquiv">i</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <int key="NSTag">1</int> - </object> - <object class="NSMenuItem" id="330926929"> - <reference key="NSMenu" ref="786677654"/> - <string key="NSTitle">Underline</string> - <string key="NSKeyEquiv">u</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="533507878"> - <reference key="NSMenu" ref="786677654"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="158063935"> - <reference key="NSMenu" ref="786677654"/> - <string key="NSTitle">Bigger</string> - <string key="NSKeyEquiv">+</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <int key="NSTag">3</int> - </object> - <object class="NSMenuItem" id="885547335"> - <reference key="NSMenu" ref="786677654"/> - <string key="NSTitle">Smaller</string> - <string key="NSKeyEquiv">-</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <int key="NSTag">4</int> - </object> - <object class="NSMenuItem" id="901062459"> - <reference key="NSMenu" ref="786677654"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="767671776"> - <reference key="NSMenu" ref="786677654"/> - <string key="NSTitle">Kern</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="175441468"> - <string key="NSTitle">Kern</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="252969304"> - <reference key="NSMenu" ref="175441468"/> - <string key="NSTitle">Use Default</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="766922938"> - <reference key="NSMenu" ref="175441468"/> - <string key="NSTitle">Use None</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="677519740"> - <reference key="NSMenu" ref="175441468"/> - <string key="NSTitle">Tighten</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="238351151"> - <reference key="NSMenu" ref="175441468"/> - <string key="NSTitle">Loosen</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - </object> - </object> - <object class="NSMenuItem" id="691570813"> - <reference key="NSMenu" ref="786677654"/> - <string key="NSTitle">Ligature</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="1058217995"> - <string key="NSTitle">Ligature</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="706297211"> - <reference key="NSMenu" ref="1058217995"/> - <string key="NSTitle">Use Default</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="568384683"> - <reference key="NSMenu" ref="1058217995"/> - <string key="NSTitle">Use None</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="663508465"> - <reference key="NSMenu" ref="1058217995"/> - <string key="NSTitle">Use All</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - </object> - </object> - <object class="NSMenuItem" id="769124883"> - <reference key="NSMenu" ref="786677654"/> - <string key="NSTitle">Baseline</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="18263474"> - <string key="NSTitle">Baseline</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="257962622"> - <reference key="NSMenu" ref="18263474"/> - <string key="NSTitle">Use Default</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="644725453"> - <reference key="NSMenu" ref="18263474"/> - <string key="NSTitle">Superscript</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="1037576581"> - <reference key="NSMenu" ref="18263474"/> - <string key="NSTitle">Subscript</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="941806246"> - <reference key="NSMenu" ref="18263474"/> - <string key="NSTitle">Raise</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="1045724900"> - <reference key="NSMenu" ref="18263474"/> - <string key="NSTitle">Lower</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - </object> - </object> - <object class="NSMenuItem" id="739652853"> - <reference key="NSMenu" ref="786677654"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="1012600125"> - <reference key="NSMenu" ref="786677654"/> - <string key="NSTitle">Show Colors</string> - <string key="NSKeyEquiv">C</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="214559597"> - <reference key="NSMenu" ref="786677654"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="596732606"> - <reference key="NSMenu" ref="786677654"/> - <string key="NSTitle">Copy Style</string> - <string key="NSKeyEquiv">c</string> - <int key="NSKeyEquivModMask">1572864</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="393423671"> - <reference key="NSMenu" ref="786677654"/> - <string key="NSTitle">Paste Style</string> - <string key="NSKeyEquiv">v</string> - <int key="NSKeyEquivModMask">1572864</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - <string key="NSName">_NSFontMenu</string> - </object> - </object> - <object class="NSMenuItem" id="215659978"> - <reference key="NSMenu" ref="941447902"/> - <string key="NSTitle">Text</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="446991534"> - <string key="NSTitle">Text</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="875092757"> - <reference key="NSMenu" ref="446991534"/> - <string key="NSTitle">Align Left</string> - <string key="NSKeyEquiv">{</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="630155264"> - <reference key="NSMenu" ref="446991534"/> - <string key="NSTitle">Center</string> - <string key="NSKeyEquiv">|</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="945678886"> - <reference key="NSMenu" ref="446991534"/> - <string key="NSTitle">Justify</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="512868991"> - <reference key="NSMenu" ref="446991534"/> - <string key="NSTitle">Align Right</string> - <string key="NSKeyEquiv">}</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="163117631"> - <reference key="NSMenu" ref="446991534"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="31516759"> - <reference key="NSMenu" ref="446991534"/> - <string key="NSTitle">Writing Direction</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="956096989"> - <string key="NSTitle">Writing Direction</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="257099033"> - <reference key="NSMenu" ref="956096989"/> - <bool key="NSIsDisabled">YES</bool> - <string key="NSTitle">Paragraph</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="551969625"> - <reference key="NSMenu" ref="956096989"/> - <string type="base64-UTF8" key="NSTitle">CURlZmF1bHQ</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="249532473"> - <reference key="NSMenu" ref="956096989"/> - <string type="base64-UTF8" key="NSTitle">CUxlZnQgdG8gUmlnaHQ</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="607364498"> - <reference key="NSMenu" ref="956096989"/> - <string type="base64-UTF8" key="NSTitle">CVJpZ2h0IHRvIExlZnQ</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="508151438"> - <reference key="NSMenu" ref="956096989"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="981751889"> - <reference key="NSMenu" ref="956096989"/> - <bool key="NSIsDisabled">YES</bool> - <string key="NSTitle">Selection</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="380031999"> - <reference key="NSMenu" ref="956096989"/> - <string type="base64-UTF8" key="NSTitle">CURlZmF1bHQ</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="825984362"> - <reference key="NSMenu" ref="956096989"/> - <string type="base64-UTF8" key="NSTitle">CUxlZnQgdG8gUmlnaHQ</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="560145579"> - <reference key="NSMenu" ref="956096989"/> - <string type="base64-UTF8" key="NSTitle">CVJpZ2h0IHRvIExlZnQ</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - </object> - </object> - <object class="NSMenuItem" id="908105787"> - <reference key="NSMenu" ref="446991534"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="644046920"> - <reference key="NSMenu" ref="446991534"/> - <string key="NSTitle">Show Ruler</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="231811626"> - <reference key="NSMenu" ref="446991534"/> - <string key="NSTitle">Copy Ruler</string> - <string key="NSKeyEquiv">c</string> - <int key="NSKeyEquivModMask">1310720</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="883618387"> - <reference key="NSMenu" ref="446991534"/> - <string key="NSTitle">Paste Ruler</string> - <string key="NSKeyEquiv">v</string> - <int key="NSKeyEquivModMask">1310720</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - </object> - </object> - </array> - </object> - </object> - <object class="NSMenuItem" id="586577488"> - <reference key="NSMenu" ref="649796088"/> - <string key="NSTitle">View</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="466310130"> - <string key="NSTitle">View</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="102151532"> - <reference key="NSMenu" ref="466310130"/> - <string key="NSTitle">Show Toolbar</string> - <string key="NSKeyEquiv">t</string> - <int key="NSKeyEquivModMask">1572864</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="237841660"> - <reference key="NSMenu" ref="466310130"/> - <string key="NSTitle">Customize Toolbar…</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - </object> - </object> - <object class="NSMenuItem" id="713487014"> - <reference key="NSMenu" ref="649796088"/> - <string key="NSTitle">Window</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="835318025"> - <string key="NSTitle">Window</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="1011231497"> - <reference key="NSMenu" ref="835318025"/> - <string key="NSTitle">Minimize</string> - <string key="NSKeyEquiv">m</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="575023229"> - <reference key="NSMenu" ref="835318025"/> - <string key="NSTitle">Zoom</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="299356726"> - <reference key="NSMenu" ref="835318025"/> - <bool key="NSIsDisabled">YES</bool> - <bool key="NSIsSeparator">YES</bool> - <string key="NSTitle"/> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - <object class="NSMenuItem" id="625202149"> - <reference key="NSMenu" ref="835318025"/> - <string key="NSTitle">Bring All to Front</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - <string key="NSName">_NSWindowsMenu</string> - </object> - </object> - <object class="NSMenuItem" id="448692316"> - <reference key="NSMenu" ref="649796088"/> - <string key="NSTitle">Help</string> - <string key="NSKeyEquiv"/> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - <string key="NSAction">submenuAction:</string> - <object class="NSMenu" key="NSSubmenu" id="992780483"> - <string key="NSTitle">Help</string> - <array class="NSMutableArray" key="NSMenuItems"> - <object class="NSMenuItem" id="105068016"> - <reference key="NSMenu" ref="992780483"/> - <string key="NSTitle">Second Life Crash Logger Help</string> - <string key="NSKeyEquiv">?</string> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="35465992"/> - <reference key="NSMixedImage" ref="502551668"/> - </object> - </array> - <string key="NSName">_NSHelpMenu</string> - </object> - </object> - </array> - <string key="NSName">_NSMainMenu</string> - </object> - <object class="NSWindowTemplate" id="972006081"> - <int key="NSWindowStyleMask">15</int> - <int key="NSWindowBacking">2</int> - <string key="NSWindowRect">{{335, 390}, {508, 477}}</string> - <int key="NSWTFlags">1954021376</int> - <string key="NSWindowTitle">Second Life Crash Logger</string> - <string key="NSWindowClass">NSWindow</string> - <nil key="NSViewClass"/> - <nil key="NSUserInterfaceItemIdentifier"/> - <object class="NSView" key="NSWindowView" id="439893737"> - <reference key="NSNextResponder"/> - <int key="NSvFlags">256</int> - <array class="NSMutableArray" key="NSSubviews"> - <object class="NSTextField" id="242877095"> - <reference key="NSNextResponder" ref="439893737"/> - <int key="NSvFlags">268</int> - <string key="NSFrame">{{17, 228}, {474, 229}}</string> - <reference key="NSSuperview" ref="439893737"/> - <reference key="NSWindow"/> - <reference key="NSNextKeyView" ref="1018085422"/> - <string key="NSReuseIdentifierKey">_NS:9</string> - <string key="NSAntiCompressionPriority">{250, 750}</string> - <bool key="NSEnabled">YES</bool> - <object class="NSTextFieldCell" key="NSCell" id="502956757"> - <int key="NSCellFlags">67239424</int> - <int key="NSCellFlags2">272891904</int> - <object class="NSMutableString" key="NSContents"> - <bytes key="NS.bytes">U2Vjb25kIExpZmUgYXBwZWFycyB0byBoYXZlIGNyYXNoZWQgb3IgZnJvemVuIHRoZSBsYXN0IHRpbWUg -aXQgcmFuLgoKVGhpcyBjcmFzaCByZXBvcnRlciBjb2xsZWN0cyBpbmZvcm1hdGlvbiBhYm91dCB5b3Vy -IGNvbXB1dGVyJ3MgaGFyZHdhcmUgY29uZmlndXJhdGlvbiwgb3BlcmF0aW5nIHN5c3RlbSwgYW5kIHNv -bWUgU2Vjb25kIExpZmUgbG9ncywgYWxsIG9mIHdoaWNoIGFyZSB1c2VkIGZvciBkZWJ1Z2dpbmcgcHVy -cG9zZXMgb25seS4KCkluIHRoZSBzcGFjZSBiZWxvdywgcGxlYXNlIGJyaWVmbHkgZGVzY3JpYmUgd2hh -dCB5b3Ugd2VyZSBkb2luZyBvciB0cnlpbmcgdG8gZG8ganVzdCBwcmlvciB0byB0aGUgY3Jhc2guICBU -aGFuayB5b3UgZm9yIHlvdXIgaGVscCEKClRoaXMgcmVwb3J0IGlzIE5PVCByZWFkIGJ5IEN1c3RvbWVy -IFN1cHBvcnQuICBJZiB5b3UgaGF2ZSBiaWxsaW5nIG9yIG90aGVyIHF1ZXN0aW9ucywgcGxlYXNlIGdv -IHRvOiBodHRwOi8vd3d3LnNlY29uZGxpZmUuY29tL3N1cHBvcnQvCgpJZiB5b3UgZG9uJ3Qgd2lzaCB0 -byBzZW5kIExpbmRlbiBMYWIgYSBjcmFzaCByZXBvcnQsIHByZXNzIENhbmNlbC4</bytes> - </object> - <object class="NSFont" key="NSSupport" id="1010806345"> - <string key="NSName">LucidaGrande</string> - <double key="NSSize">13</double> - <int key="NSfFlags">16</int> - </object> - <string key="NSCellIdentifier">_NS:9</string> - <reference key="NSControlView" ref="242877095"/> - <object class="NSColor" key="NSBackgroundColor"> - <int key="NSColorSpace">6</int> - <string key="NSCatalogName">System</string> - <string key="NSColorName">controlColor</string> - <object class="NSColor" key="NSColor"> - <int key="NSColorSpace">3</int> - <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes> - </object> - </object> - <object class="NSColor" key="NSTextColor"> - <int key="NSColorSpace">6</int> - <string key="NSCatalogName">System</string> - <string key="NSColorName">controlTextColor</string> - <object class="NSColor" key="NSColor" id="355388215"> - <int key="NSColorSpace">3</int> - <bytes key="NSWhite">MAA</bytes> - </object> - </object> - </object> - </object> - <object class="NSTextField" id="1018085422"> - <reference key="NSNextResponder" ref="439893737"/> - <int key="NSvFlags">268</int> - <string key="NSFrame">{{20, 64}, {468, 163}}</string> - <reference key="NSSuperview" ref="439893737"/> - <reference key="NSWindow"/> - <reference key="NSNextKeyView" ref="688522420"/> - <string key="NSReuseIdentifierKey">_NS:9</string> - <string key="NSAntiCompressionPriority">{250, 750}</string> - <bool key="NSEnabled">YES</bool> - <object class="NSTextFieldCell" key="NSCell" id="867418359"> - <int key="NSCellFlags">-1805517311</int> - <int key="NSCellFlags2">272891904</int> - <string key="NSContents"/> - <object class="NSFont" key="NSSupport"> - <string key="NSName">LucidaGrande</string> - <double key="NSSize">9</double> - <int key="NSfFlags">3614</int> - </object> - <string key="NSCellIdentifier">_NS:9</string> - <reference key="NSControlView" ref="1018085422"/> - <bool key="NSDrawsBackground">YES</bool> - <object class="NSColor" key="NSBackgroundColor"> - <int key="NSColorSpace">6</int> - <string key="NSCatalogName">System</string> - <string key="NSColorName">textBackgroundColor</string> - <object class="NSColor" key="NSColor"> - <int key="NSColorSpace">3</int> - <bytes key="NSWhite">MQA</bytes> - </object> - </object> - <object class="NSColor" key="NSTextColor"> - <int key="NSColorSpace">6</int> - <string key="NSCatalogName">System</string> - <string key="NSColorName">textColor</string> - <reference key="NSColor" ref="355388215"/> - </object> - </object> - </object> - <object class="NSButton" id="688522420"> - <reference key="NSNextResponder" ref="439893737"/> - <int key="NSvFlags">268</int> - <string key="NSFrame">{{16, 18}, {189, 30}}</string> - <reference key="NSSuperview" ref="439893737"/> - <reference key="NSWindow"/> - <reference key="NSNextKeyView" ref="93467784"/> - <string key="NSReuseIdentifierKey">_NS:9</string> - <bool key="NSEnabled">YES</bool> - <object class="NSButtonCell" key="NSCell" id="445379790"> - <int key="NSCellFlags">-2080244224</int> - <int key="NSCellFlags2">262144</int> - <string key="NSContents">Remember This Choice</string> - <reference key="NSSupport" ref="1010806345"/> - <string key="NSCellIdentifier">_NS:9</string> - <reference key="NSControlView" ref="688522420"/> - <int key="NSButtonFlags">1211912703</int> - <int key="NSButtonFlags2">2</int> - <object class="NSCustomResource" key="NSNormalImage"> - <string key="NSClassName">NSImage</string> - <string key="NSResourceName">NSSwitch</string> - </object> - <object class="NSButtonImageSource" key="NSAlternateImage"> - <string key="NSImageName">NSSwitch</string> - </object> - <string key="NSAlternateContents"/> - <string key="NSKeyEquivalent"/> - <int key="NSPeriodicDelay">200</int> - <int key="NSPeriodicInterval">25</int> - </object> - </object> - <object class="NSButton" id="93467784"> - <reference key="NSNextResponder" ref="439893737"/> - <int key="NSvFlags">268</int> - <string key="NSFrame">{{285, 23}, {91, 17}}</string> - <reference key="NSSuperview" ref="439893737"/> - <reference key="NSWindow"/> - <reference key="NSNextKeyView" ref="46276252"/> - <string key="NSReuseIdentifierKey">_NS:9</string> - <bool key="NSEnabled">YES</bool> - <object class="NSButtonCell" key="NSCell" id="623922320"> - <int key="NSCellFlags">-2080244224</int> - <int key="NSCellFlags2">134479872</int> - <string key="NSContents">Send Report</string> - <reference key="NSSupport" ref="1010806345"/> - <string key="NSCellIdentifier">_NS:9</string> - <reference key="NSControlView" ref="93467784"/> - <int key="NSButtonFlags">-2038152961</int> - <int key="NSButtonFlags2">164</int> - <string key="NSAlternateContents"/> - <string key="NSKeyEquivalent"/> - <int key="NSPeriodicDelay">400</int> - <int key="NSPeriodicInterval">75</int> - </object> - </object> - <object class="NSButton" id="46276252"> - <reference key="NSNextResponder" ref="439893737"/> - <int key="NSvFlags">268</int> - <string key="NSFrame">{{388, 23}, {100, 17}}</string> - <reference key="NSSuperview" ref="439893737"/> - <reference key="NSWindow"/> - <reference key="NSNextKeyView"/> - <string key="NSReuseIdentifierKey">_NS:9</string> - <bool key="NSEnabled">YES</bool> - <object class="NSButtonCell" key="NSCell" id="398179500"> - <int key="NSCellFlags">-2080244224</int> - <int key="NSCellFlags2">134479872</int> - <string key="NSContents">Don't Send</string> - <reference key="NSSupport" ref="1010806345"/> - <string key="NSCellIdentifier">_NS:9</string> - <reference key="NSControlView" ref="46276252"/> - <int key="NSButtonFlags">-2038152961</int> - <int key="NSButtonFlags2">164</int> - <string key="NSAlternateContents"/> - <string key="NSKeyEquivalent"/> - <int key="NSPeriodicDelay">400</int> - <int key="NSPeriodicInterval">75</int> - </object> - </object> - </array> - <string key="NSFrameSize">{508, 477}</string> - <reference key="NSSuperview"/> - <reference key="NSWindow"/> - <reference key="NSNextKeyView" ref="242877095"/> - </object> - <string key="NSScreenRect">{{0, 0}, {1680, 1028}}</string> - <string key="NSMaxSize">{10000000000000, 10000000000000}</string> - <bool key="NSWindowIsRestorable">YES</bool> - </object> - <object class="NSCustomObject" id="976324537"> - <string key="NSClassName">LLCrashLoggerMacDelegate</string> - </object> - </array> - <object class="IBObjectContainer" key="IBDocument.Objects"> - <array class="NSMutableArray" key="connectionRecords"> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">terminate:</string> - <reference key="source" ref="1050"/> - <reference key="destination" ref="632727374"/> - </object> - <int key="connectionID">449</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">orderFrontStandardAboutPanel:</string> - <reference key="source" ref="1021"/> - <reference key="destination" ref="238522557"/> - </object> - <int key="connectionID">142</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBOutletConnection" key="connection"> - <string key="label">delegate</string> - <reference key="source" ref="1021"/> - <reference key="destination" ref="976324537"/> - </object> - <int key="connectionID">495</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">performMiniaturize:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="1011231497"/> - </object> - <int key="connectionID">37</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">arrangeInFront:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="625202149"/> - </object> - <int key="connectionID">39</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">print:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="49223823"/> - </object> - <int key="connectionID">86</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">runPageLayout:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="294629803"/> - </object> - <int key="connectionID">87</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">clearRecentDocuments:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="759406840"/> - </object> - <int key="connectionID">127</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">performClose:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="776162233"/> - </object> - <int key="connectionID">193</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">toggleContinuousSpellChecking:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="948374510"/> - </object> - <int key="connectionID">222</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">undo:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="1058277027"/> - </object> - <int key="connectionID">223</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">copy:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="860595796"/> - </object> - <int key="connectionID">224</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">checkSpelling:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="96193923"/> - </object> - <int key="connectionID">225</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">paste:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="29853731"/> - </object> - <int key="connectionID">226</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">stopSpeaking:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="680220178"/> - </object> - <int key="connectionID">227</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">cut:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="296257095"/> - </object> - <int key="connectionID">228</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">showGuessPanel:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="679648819"/> - </object> - <int key="connectionID">230</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">redo:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="790794224"/> - </object> - <int key="connectionID">231</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">selectAll:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="583158037"/> - </object> - <int key="connectionID">232</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">startSpeaking:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="731782645"/> - </object> - <int key="connectionID">233</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">delete:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="437104165"/> - </object> - <int key="connectionID">235</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">performZoom:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="575023229"/> - </object> - <int key="connectionID">240</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">performFindPanelAction:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="447796847"/> - </object> - <int key="connectionID">241</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">centerSelectionInVisibleArea:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="88285865"/> - </object> - <int key="connectionID">245</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">toggleGrammarChecking:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="967646866"/> - </object> - <int key="connectionID">347</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">toggleSmartInsertDelete:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="605118523"/> - </object> - <int key="connectionID">355</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">toggleAutomaticQuoteSubstitution:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="197661976"/> - </object> - <int key="connectionID">356</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">toggleAutomaticLinkDetection:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="708854459"/> - </object> - <int key="connectionID">357</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">saveDocument:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="1023925487"/> - </object> - <int key="connectionID">362</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">revertDocumentToSaved:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="579971712"/> - </object> - <int key="connectionID">364</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">runToolbarCustomizationPalette:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="237841660"/> - </object> - <int key="connectionID">365</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">toggleToolbarShown:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="102151532"/> - </object> - <int key="connectionID">366</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">hide:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="755159360"/> - </object> - <int key="connectionID">367</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">hideOtherApplications:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="342932134"/> - </object> - <int key="connectionID">368</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">unhideAllApplications:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="908899353"/> - </object> - <int key="connectionID">370</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">newDocument:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="705341025"/> - </object> - <int key="connectionID">373</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">openDocument:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="722745758"/> - </object> - <int key="connectionID">374</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">raiseBaseline:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="941806246"/> - </object> - <int key="connectionID">426</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">lowerBaseline:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="1045724900"/> - </object> - <int key="connectionID">427</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">copyFont:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="596732606"/> - </object> - <int key="connectionID">428</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">subscript:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="1037576581"/> - </object> - <int key="connectionID">429</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">superscript:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="644725453"/> - </object> - <int key="connectionID">430</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">tightenKerning:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="677519740"/> - </object> - <int key="connectionID">431</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">underline:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="330926929"/> - </object> - <int key="connectionID">432</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">orderFrontColorPanel:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="1012600125"/> - </object> - <int key="connectionID">433</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">useAllLigatures:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="663508465"/> - </object> - <int key="connectionID">434</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">loosenKerning:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="238351151"/> - </object> - <int key="connectionID">435</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">pasteFont:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="393423671"/> - </object> - <int key="connectionID">436</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">unscript:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="257962622"/> - </object> - <int key="connectionID">437</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">useStandardKerning:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="252969304"/> - </object> - <int key="connectionID">438</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">useStandardLigatures:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="706297211"/> - </object> - <int key="connectionID">439</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">turnOffLigatures:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="568384683"/> - </object> - <int key="connectionID">440</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">turnOffKerning:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="766922938"/> - </object> - <int key="connectionID">441</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">toggleAutomaticSpellingCorrection:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="795346622"/> - </object> - <int key="connectionID">456</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">orderFrontSubstitutionsPanel:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="65139061"/> - </object> - <int key="connectionID">458</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">toggleAutomaticDashSubstitution:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="672708820"/> - </object> - <int key="connectionID">461</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">toggleAutomaticTextReplacement:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="537092702"/> - </object> - <int key="connectionID">463</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">uppercaseWord:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="1060694897"/> - </object> - <int key="connectionID">464</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">capitalizeWord:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="56570060"/> - </object> - <int key="connectionID">467</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">lowercaseWord:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="879586729"/> - </object> - <int key="connectionID">468</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">pasteAsPlainText:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="82994268"/> - </object> - <int key="connectionID">486</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">performFindPanelAction:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="326711663"/> - </object> - <int key="connectionID">487</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">performFindPanelAction:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="270902937"/> - </object> - <int key="connectionID">488</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">performFindPanelAction:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="159080638"/> - </object> - <int key="connectionID">489</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">showHelp:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="105068016"/> - </object> - <int key="connectionID">493</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">alignCenter:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="630155264"/> - </object> - <int key="connectionID">518</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">pasteRuler:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="883618387"/> - </object> - <int key="connectionID">519</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">toggleRuler:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="644046920"/> - </object> - <int key="connectionID">520</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">alignRight:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="512868991"/> - </object> - <int key="connectionID">521</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">copyRuler:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="231811626"/> - </object> - <int key="connectionID">522</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">alignJustified:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="945678886"/> - </object> - <int key="connectionID">523</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">alignLeft:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="875092757"/> - </object> - <int key="connectionID">524</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">makeBaseWritingDirectionNatural:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="551969625"/> - </object> - <int key="connectionID">525</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">makeBaseWritingDirectionLeftToRight:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="249532473"/> - </object> - <int key="connectionID">526</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">makeBaseWritingDirectionRightToLeft:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="607364498"/> - </object> - <int key="connectionID">527</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">makeTextWritingDirectionNatural:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="380031999"/> - </object> - <int key="connectionID">528</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">makeTextWritingDirectionLeftToRight:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="825984362"/> - </object> - <int key="connectionID">529</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">makeTextWritingDirectionRightToLeft:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="560145579"/> - </object> - <int key="connectionID">530</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">performFindPanelAction:</string> - <reference key="source" ref="1014"/> - <reference key="destination" ref="738670835"/> - </object> - <int key="connectionID">535</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBOutletConnection" key="connection"> - <string key="label">window</string> - <reference key="source" ref="976324537"/> - <reference key="destination" ref="972006081"/> - </object> - <int key="connectionID">532</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">remember:</string> - <reference key="source" ref="976324537"/> - <reference key="destination" ref="688522420"/> - </object> - <int key="connectionID">1176</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">send:</string> - <reference key="source" ref="976324537"/> - <reference key="destination" ref="93467784"/> - </object> - <int key="connectionID">1177</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">cancel:</string> - <reference key="source" ref="976324537"/> - <reference key="destination" ref="46276252"/> - </object> - <int key="connectionID">1178</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBOutletConnection" key="connection"> - <string key="label">crashText</string> - <reference key="source" ref="976324537"/> - <reference key="destination" ref="1018085422"/> - </object> - <int key="connectionID">1179</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBOutletConnection" key="connection"> - <string key="label">rememberCheck</string> - <reference key="source" ref="976324537"/> - <reference key="destination" ref="688522420"/> - </object> - <int key="connectionID">1187</int> - </object> - </array> - <object class="IBMutableOrderedSet" key="objectRecords"> - <array key="orderedObjects"> - <object class="IBObjectRecord"> - <int key="objectID">0</int> - <array key="object" id="0"/> - <reference key="children" ref="1048"/> - <nil key="parent"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">-2</int> - <reference key="object" ref="1021"/> - <reference key="parent" ref="0"/> - <string key="objectName">File's Owner</string> - </object> - <object class="IBObjectRecord"> - <int key="objectID">-1</int> - <reference key="object" ref="1014"/> - <reference key="parent" ref="0"/> - <string key="objectName">First Responder</string> - </object> - <object class="IBObjectRecord"> - <int key="objectID">-3</int> - <reference key="object" ref="1050"/> - <reference key="parent" ref="0"/> - <string key="objectName">Application</string> - </object> - <object class="IBObjectRecord"> - <int key="objectID">29</int> - <reference key="object" ref="649796088"/> - <array class="NSMutableArray" key="children"> - <reference ref="713487014"/> - <reference ref="694149608"/> - <reference ref="952259628"/> - <reference ref="379814623"/> - <reference ref="586577488"/> - <reference ref="302598603"/> - <reference ref="448692316"/> - </array> - <reference key="parent" ref="0"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">19</int> - <reference key="object" ref="713487014"/> - <array class="NSMutableArray" key="children"> - <reference ref="835318025"/> - </array> - <reference key="parent" ref="649796088"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">56</int> - <reference key="object" ref="694149608"/> - <array class="NSMutableArray" key="children"> - <reference ref="110575045"/> - </array> - <reference key="parent" ref="649796088"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">217</int> - <reference key="object" ref="952259628"/> - <array class="NSMutableArray" key="children"> - <reference ref="789758025"/> - </array> - <reference key="parent" ref="649796088"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">83</int> - <reference key="object" ref="379814623"/> - <array class="NSMutableArray" key="children"> - <reference ref="720053764"/> - </array> - <reference key="parent" ref="649796088"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">81</int> - <reference key="object" ref="720053764"/> - <array class="NSMutableArray" key="children"> - <reference ref="1023925487"/> - <reference ref="49223823"/> - <reference ref="722745758"/> - <reference ref="705341025"/> - <reference ref="1025936716"/> - <reference ref="294629803"/> - <reference ref="776162233"/> - <reference ref="425164168"/> - <reference ref="579971712"/> - <reference ref="1010469920"/> - </array> - <reference key="parent" ref="379814623"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">75</int> - <reference key="object" ref="1023925487"/> - <reference key="parent" ref="720053764"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">78</int> - <reference key="object" ref="49223823"/> - <reference key="parent" ref="720053764"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">72</int> - <reference key="object" ref="722745758"/> - <reference key="parent" ref="720053764"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">82</int> - <reference key="object" ref="705341025"/> - <reference key="parent" ref="720053764"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">124</int> - <reference key="object" ref="1025936716"/> - <array class="NSMutableArray" key="children"> - <reference ref="1065607017"/> - </array> - <reference key="parent" ref="720053764"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">77</int> - <reference key="object" ref="294629803"/> - <reference key="parent" ref="720053764"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">73</int> - <reference key="object" ref="776162233"/> - <reference key="parent" ref="720053764"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">79</int> - <reference key="object" ref="425164168"/> - <reference key="parent" ref="720053764"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">112</int> - <reference key="object" ref="579971712"/> - <reference key="parent" ref="720053764"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">74</int> - <reference key="object" ref="1010469920"/> - <reference key="parent" ref="720053764"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">125</int> - <reference key="object" ref="1065607017"/> - <array class="NSMutableArray" key="children"> - <reference ref="759406840"/> - </array> - <reference key="parent" ref="1025936716"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">126</int> - <reference key="object" ref="759406840"/> - <reference key="parent" ref="1065607017"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">205</int> - <reference key="object" ref="789758025"/> - <array class="NSMutableArray" key="children"> - <reference ref="437104165"/> - <reference ref="583158037"/> - <reference ref="1058277027"/> - <reference ref="212016141"/> - <reference ref="296257095"/> - <reference ref="29853731"/> - <reference ref="860595796"/> - <reference ref="1040322652"/> - <reference ref="790794224"/> - <reference ref="892235320"/> - <reference ref="972420730"/> - <reference ref="676164635"/> - <reference ref="507821607"/> - <reference ref="288088188"/> - <reference ref="82994268"/> - </array> - <reference key="parent" ref="952259628"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">202</int> - <reference key="object" ref="437104165"/> - <reference key="parent" ref="789758025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">198</int> - <reference key="object" ref="583158037"/> - <reference key="parent" ref="789758025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">207</int> - <reference key="object" ref="1058277027"/> - <reference key="parent" ref="789758025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">214</int> - <reference key="object" ref="212016141"/> - <reference key="parent" ref="789758025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">199</int> - <reference key="object" ref="296257095"/> - <reference key="parent" ref="789758025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">203</int> - <reference key="object" ref="29853731"/> - <reference key="parent" ref="789758025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">197</int> - <reference key="object" ref="860595796"/> - <reference key="parent" ref="789758025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">206</int> - <reference key="object" ref="1040322652"/> - <reference key="parent" ref="789758025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">215</int> - <reference key="object" ref="790794224"/> - <reference key="parent" ref="789758025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">218</int> - <reference key="object" ref="892235320"/> - <array class="NSMutableArray" key="children"> - <reference ref="963351320"/> - </array> - <reference key="parent" ref="789758025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">216</int> - <reference key="object" ref="972420730"/> - <array class="NSMutableArray" key="children"> - <reference ref="769623530"/> - </array> - <reference key="parent" ref="789758025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">200</int> - <reference key="object" ref="769623530"/> - <array class="NSMutableArray" key="children"> - <reference ref="948374510"/> - <reference ref="96193923"/> - <reference ref="679648819"/> - <reference ref="967646866"/> - <reference ref="859480356"/> - <reference ref="795346622"/> - </array> - <reference key="parent" ref="972420730"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">219</int> - <reference key="object" ref="948374510"/> - <reference key="parent" ref="769623530"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">201</int> - <reference key="object" ref="96193923"/> - <reference key="parent" ref="769623530"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">204</int> - <reference key="object" ref="679648819"/> - <reference key="parent" ref="769623530"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">220</int> - <reference key="object" ref="963351320"/> - <array class="NSMutableArray" key="children"> - <reference ref="270902937"/> - <reference ref="88285865"/> - <reference ref="159080638"/> - <reference ref="326711663"/> - <reference ref="447796847"/> - <reference ref="738670835"/> - </array> - <reference key="parent" ref="892235320"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">213</int> - <reference key="object" ref="270902937"/> - <reference key="parent" ref="963351320"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">210</int> - <reference key="object" ref="88285865"/> - <reference key="parent" ref="963351320"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">221</int> - <reference key="object" ref="159080638"/> - <reference key="parent" ref="963351320"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">208</int> - <reference key="object" ref="326711663"/> - <reference key="parent" ref="963351320"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">209</int> - <reference key="object" ref="447796847"/> - <reference key="parent" ref="963351320"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">57</int> - <reference key="object" ref="110575045"/> - <array class="NSMutableArray" key="children"> - <reference ref="238522557"/> - <reference ref="755159360"/> - <reference ref="908899353"/> - <reference ref="632727374"/> - <reference ref="646227648"/> - <reference ref="609285721"/> - <reference ref="481834944"/> - <reference ref="304266470"/> - <reference ref="1046388886"/> - <reference ref="1056857174"/> - <reference ref="342932134"/> - </array> - <reference key="parent" ref="694149608"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">58</int> - <reference key="object" ref="238522557"/> - <reference key="parent" ref="110575045"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">134</int> - <reference key="object" ref="755159360"/> - <reference key="parent" ref="110575045"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">150</int> - <reference key="object" ref="908899353"/> - <reference key="parent" ref="110575045"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">136</int> - <reference key="object" ref="632727374"/> - <reference key="parent" ref="110575045"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">144</int> - <reference key="object" ref="646227648"/> - <reference key="parent" ref="110575045"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">129</int> - <reference key="object" ref="609285721"/> - <reference key="parent" ref="110575045"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">143</int> - <reference key="object" ref="481834944"/> - <reference key="parent" ref="110575045"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">236</int> - <reference key="object" ref="304266470"/> - <reference key="parent" ref="110575045"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">131</int> - <reference key="object" ref="1046388886"/> - <array class="NSMutableArray" key="children"> - <reference ref="752062318"/> - </array> - <reference key="parent" ref="110575045"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">149</int> - <reference key="object" ref="1056857174"/> - <reference key="parent" ref="110575045"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">145</int> - <reference key="object" ref="342932134"/> - <reference key="parent" ref="110575045"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">130</int> - <reference key="object" ref="752062318"/> - <reference key="parent" ref="1046388886"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">24</int> - <reference key="object" ref="835318025"/> - <array class="NSMutableArray" key="children"> - <reference ref="299356726"/> - <reference ref="625202149"/> - <reference ref="575023229"/> - <reference ref="1011231497"/> - </array> - <reference key="parent" ref="713487014"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">92</int> - <reference key="object" ref="299356726"/> - <reference key="parent" ref="835318025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">5</int> - <reference key="object" ref="625202149"/> - <reference key="parent" ref="835318025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">239</int> - <reference key="object" ref="575023229"/> - <reference key="parent" ref="835318025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">23</int> - <reference key="object" ref="1011231497"/> - <reference key="parent" ref="835318025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">295</int> - <reference key="object" ref="586577488"/> - <array class="NSMutableArray" key="children"> - <reference ref="466310130"/> - </array> - <reference key="parent" ref="649796088"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">296</int> - <reference key="object" ref="466310130"/> - <array class="NSMutableArray" key="children"> - <reference ref="102151532"/> - <reference ref="237841660"/> - </array> - <reference key="parent" ref="586577488"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">297</int> - <reference key="object" ref="102151532"/> - <reference key="parent" ref="466310130"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">298</int> - <reference key="object" ref="237841660"/> - <reference key="parent" ref="466310130"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">211</int> - <reference key="object" ref="676164635"/> - <array class="NSMutableArray" key="children"> - <reference ref="785027613"/> - </array> - <reference key="parent" ref="789758025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">212</int> - <reference key="object" ref="785027613"/> - <array class="NSMutableArray" key="children"> - <reference ref="680220178"/> - <reference ref="731782645"/> - </array> - <reference key="parent" ref="676164635"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">195</int> - <reference key="object" ref="680220178"/> - <reference key="parent" ref="785027613"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">196</int> - <reference key="object" ref="731782645"/> - <reference key="parent" ref="785027613"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">346</int> - <reference key="object" ref="967646866"/> - <reference key="parent" ref="769623530"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">348</int> - <reference key="object" ref="507821607"/> - <array class="NSMutableArray" key="children"> - <reference ref="698887838"/> - </array> - <reference key="parent" ref="789758025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">349</int> - <reference key="object" ref="698887838"/> - <array class="NSMutableArray" key="children"> - <reference ref="605118523"/> - <reference ref="197661976"/> - <reference ref="708854459"/> - <reference ref="65139061"/> - <reference ref="19036812"/> - <reference ref="672708820"/> - <reference ref="537092702"/> - </array> - <reference key="parent" ref="507821607"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">350</int> - <reference key="object" ref="605118523"/> - <reference key="parent" ref="698887838"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">351</int> - <reference key="object" ref="197661976"/> - <reference key="parent" ref="698887838"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">354</int> - <reference key="object" ref="708854459"/> - <reference key="parent" ref="698887838"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">371</int> - <reference key="object" ref="972006081"/> - <array class="NSMutableArray" key="children"> - <reference ref="439893737"/> - </array> - <reference key="parent" ref="0"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">372</int> - <reference key="object" ref="439893737"/> - <array class="NSMutableArray" key="children"> - <reference ref="242877095"/> - <reference ref="1018085422"/> - <reference ref="688522420"/> - <object class="IBNSLayoutConstraint" id="109434655"> - <reference key="firstItem" ref="242877095"/> - <int key="firstAttribute">3</int> - <int key="relation">0</int> - <reference key="secondItem" ref="439893737"/> - <int key="secondAttribute">3</int> - <float key="multiplier">1</float> - <object class="IBNSLayoutSymbolicConstant" key="constant"> - <double key="value">20</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">8</int> - <float key="scoringTypeFloat">29</float> - <int key="contentType">3</int> - <reference key="containingView" ref="439893737"/> - </object> - <reference ref="46276252"/> - <reference ref="93467784"/> - <object class="IBNSLayoutConstraint" id="166525974"> - <reference key="firstItem" ref="439893737"/> - <int key="firstAttribute">6</int> - <int key="relation">0</int> - <reference key="secondItem" ref="242877095"/> - <int key="secondAttribute">6</int> - <float key="multiplier">1</float> - <object class="IBNSLayoutSymbolicConstant" key="constant"> - <double key="value">20</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">8</int> - <float key="scoringTypeFloat">29</float> - <int key="contentType">3</int> - <reference key="containingView" ref="439893737"/> - </object> - <object class="IBNSLayoutConstraint" id="229833409"> - <reference key="firstItem" ref="242877095"/> - <int key="firstAttribute">5</int> - <int key="relation">0</int> - <reference key="secondItem" ref="439893737"/> - <int key="secondAttribute">5</int> - <float key="multiplier">1</float> - <object class="IBNSLayoutSymbolicConstant" key="constant"> - <double key="value">20</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">8</int> - <float key="scoringTypeFloat">29</float> - <int key="contentType">3</int> - <reference key="containingView" ref="439893737"/> - </object> - <object class="IBNSLayoutConstraint" id="992363278"> - <reference key="firstItem" ref="439893737"/> - <int key="firstAttribute">6</int> - <int key="relation">0</int> - <reference key="secondItem" ref="1018085422"/> - <int key="secondAttribute">6</int> - <float key="multiplier">1</float> - <object class="IBNSLayoutSymbolicConstant" key="constant"> - <double key="value">20</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">8</int> - <float key="scoringTypeFloat">29</float> - <int key="contentType">3</int> - <reference key="containingView" ref="439893737"/> - </object> - <object class="IBNSLayoutConstraint" id="646866003"> - <reference key="firstItem" ref="1018085422"/> - <int key="firstAttribute">5</int> - <int key="relation">0</int> - <reference key="secondItem" ref="439893737"/> - <int key="secondAttribute">5</int> - <float key="multiplier">1</float> - <object class="IBNSLayoutSymbolicConstant" key="constant"> - <double key="value">20</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">8</int> - <float key="scoringTypeFloat">29</float> - <int key="contentType">3</int> - <reference key="containingView" ref="439893737"/> - </object> - <object class="IBNSLayoutConstraint" id="98217052"> - <reference key="firstItem" ref="439893737"/> - <int key="firstAttribute">4</int> - <int key="relation">0</int> - <reference key="secondItem" ref="1018085422"/> - <int key="secondAttribute">4</int> - <float key="multiplier">1</float> - <object class="IBLayoutConstant" key="constant"> - <double key="value">64</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">3</int> - <float key="scoringTypeFloat">9</float> - <int key="contentType">3</int> - <reference key="containingView" ref="439893737"/> - </object> - <object class="IBNSLayoutConstraint" id="578918264"> - <reference key="firstItem" ref="439893737"/> - <int key="firstAttribute">6</int> - <int key="relation">0</int> - <reference key="secondItem" ref="46276252"/> - <int key="secondAttribute">6</int> - <float key="multiplier">1</float> - <object class="IBNSLayoutSymbolicConstant" key="constant"> - <double key="value">20</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">8</int> - <float key="scoringTypeFloat">29</float> - <int key="contentType">3</int> - <reference key="containingView" ref="439893737"/> - </object> - <object class="IBNSLayoutConstraint" id="591594339"> - <reference key="firstItem" ref="688522420"/> - <int key="firstAttribute">5</int> - <int key="relation">0</int> - <reference key="secondItem" ref="439893737"/> - <int key="secondAttribute">5</int> - <float key="multiplier">1</float> - <object class="IBNSLayoutSymbolicConstant" key="constant"> - <double key="value">20</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">8</int> - <float key="scoringTypeFloat">29</float> - <int key="contentType">3</int> - <reference key="containingView" ref="439893737"/> - </object> - <object class="IBNSLayoutConstraint" id="432526715"> - <reference key="firstItem" ref="439893737"/> - <int key="firstAttribute">4</int> - <int key="relation">0</int> - <reference key="secondItem" ref="688522420"/> - <int key="secondAttribute">4</int> - <float key="multiplier">1</float> - <object class="IBLayoutConstant" key="constant"> - <double key="value">21</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">3</int> - <float key="scoringTypeFloat">9</float> - <int key="contentType">3</int> - <reference key="containingView" ref="439893737"/> - </object> - <object class="IBNSLayoutConstraint" id="891430181"> - <reference key="firstItem" ref="439893737"/> - <int key="firstAttribute">6</int> - <int key="relation">0</int> - <reference key="secondItem" ref="93467784"/> - <int key="secondAttribute">6</int> - <float key="multiplier">1</float> - <object class="IBLayoutConstant" key="constant"> - <double key="value">132</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">3</int> - <float key="scoringTypeFloat">9</float> - <int key="contentType">3</int> - <reference key="containingView" ref="439893737"/> - </object> - <object class="IBNSLayoutConstraint" id="833183002"> - <reference key="firstItem" ref="93467784"/> - <int key="firstAttribute">11</int> - <int key="relation">0</int> - <reference key="secondItem" ref="46276252"/> - <int key="secondAttribute">11</int> - <float key="multiplier">1</float> - <object class="IBLayoutConstant" key="constant"> - <double key="value">0.0</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">6</int> - <float key="scoringTypeFloat">24</float> - <int key="contentType">2</int> - <reference key="containingView" ref="439893737"/> - </object> - <object class="IBNSLayoutConstraint" id="670714078"> - <reference key="firstItem" ref="93467784"/> - <int key="firstAttribute">10</int> - <int key="relation">0</int> - <reference key="secondItem" ref="688522420"/> - <int key="secondAttribute">10</int> - <float key="multiplier">1</float> - <object class="IBLayoutConstant" key="constant"> - <double key="value">0.0</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">6</int> - <float key="scoringTypeFloat">24</float> - <int key="contentType">2</int> - <reference key="containingView" ref="439893737"/> - </object> - </array> - <reference key="parent" ref="972006081"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">375</int> - <reference key="object" ref="302598603"/> - <array class="NSMutableArray" key="children"> - <reference ref="941447902"/> - </array> - <reference key="parent" ref="649796088"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">376</int> - <reference key="object" ref="941447902"/> - <array class="NSMutableArray" key="children"> - <reference ref="792887677"/> - <reference ref="215659978"/> - </array> - <reference key="parent" ref="302598603"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">377</int> - <reference key="object" ref="792887677"/> - <array class="NSMutableArray" key="children"> - <reference ref="786677654"/> - </array> - <reference key="parent" ref="941447902"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">388</int> - <reference key="object" ref="786677654"/> - <array class="NSMutableArray" key="children"> - <reference ref="159677712"/> - <reference ref="305399458"/> - <reference ref="814362025"/> - <reference ref="330926929"/> - <reference ref="533507878"/> - <reference ref="158063935"/> - <reference ref="885547335"/> - <reference ref="901062459"/> - <reference ref="767671776"/> - <reference ref="691570813"/> - <reference ref="769124883"/> - <reference ref="739652853"/> - <reference ref="1012600125"/> - <reference ref="214559597"/> - <reference ref="596732606"/> - <reference ref="393423671"/> - </array> - <reference key="parent" ref="792887677"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">389</int> - <reference key="object" ref="159677712"/> - <reference key="parent" ref="786677654"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">390</int> - <reference key="object" ref="305399458"/> - <reference key="parent" ref="786677654"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">391</int> - <reference key="object" ref="814362025"/> - <reference key="parent" ref="786677654"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">392</int> - <reference key="object" ref="330926929"/> - <reference key="parent" ref="786677654"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">393</int> - <reference key="object" ref="533507878"/> - <reference key="parent" ref="786677654"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">394</int> - <reference key="object" ref="158063935"/> - <reference key="parent" ref="786677654"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">395</int> - <reference key="object" ref="885547335"/> - <reference key="parent" ref="786677654"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">396</int> - <reference key="object" ref="901062459"/> - <reference key="parent" ref="786677654"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">397</int> - <reference key="object" ref="767671776"/> - <array class="NSMutableArray" key="children"> - <reference ref="175441468"/> - </array> - <reference key="parent" ref="786677654"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">398</int> - <reference key="object" ref="691570813"/> - <array class="NSMutableArray" key="children"> - <reference ref="1058217995"/> - </array> - <reference key="parent" ref="786677654"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">399</int> - <reference key="object" ref="769124883"/> - <array class="NSMutableArray" key="children"> - <reference ref="18263474"/> - </array> - <reference key="parent" ref="786677654"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">400</int> - <reference key="object" ref="739652853"/> - <reference key="parent" ref="786677654"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">401</int> - <reference key="object" ref="1012600125"/> - <reference key="parent" ref="786677654"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">402</int> - <reference key="object" ref="214559597"/> - <reference key="parent" ref="786677654"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">403</int> - <reference key="object" ref="596732606"/> - <reference key="parent" ref="786677654"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">404</int> - <reference key="object" ref="393423671"/> - <reference key="parent" ref="786677654"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">405</int> - <reference key="object" ref="18263474"/> - <array class="NSMutableArray" key="children"> - <reference ref="257962622"/> - <reference ref="644725453"/> - <reference ref="1037576581"/> - <reference ref="941806246"/> - <reference ref="1045724900"/> - </array> - <reference key="parent" ref="769124883"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">406</int> - <reference key="object" ref="257962622"/> - <reference key="parent" ref="18263474"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">407</int> - <reference key="object" ref="644725453"/> - <reference key="parent" ref="18263474"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">408</int> - <reference key="object" ref="1037576581"/> - <reference key="parent" ref="18263474"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">409</int> - <reference key="object" ref="941806246"/> - <reference key="parent" ref="18263474"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">410</int> - <reference key="object" ref="1045724900"/> - <reference key="parent" ref="18263474"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">411</int> - <reference key="object" ref="1058217995"/> - <array class="NSMutableArray" key="children"> - <reference ref="706297211"/> - <reference ref="568384683"/> - <reference ref="663508465"/> - </array> - <reference key="parent" ref="691570813"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">412</int> - <reference key="object" ref="706297211"/> - <reference key="parent" ref="1058217995"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">413</int> - <reference key="object" ref="568384683"/> - <reference key="parent" ref="1058217995"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">414</int> - <reference key="object" ref="663508465"/> - <reference key="parent" ref="1058217995"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">415</int> - <reference key="object" ref="175441468"/> - <array class="NSMutableArray" key="children"> - <reference ref="252969304"/> - <reference ref="766922938"/> - <reference ref="677519740"/> - <reference ref="238351151"/> - </array> - <reference key="parent" ref="767671776"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">416</int> - <reference key="object" ref="252969304"/> - <reference key="parent" ref="175441468"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">417</int> - <reference key="object" ref="766922938"/> - <reference key="parent" ref="175441468"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">418</int> - <reference key="object" ref="677519740"/> - <reference key="parent" ref="175441468"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">419</int> - <reference key="object" ref="238351151"/> - <reference key="parent" ref="175441468"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">450</int> - <reference key="object" ref="288088188"/> - <array class="NSMutableArray" key="children"> - <reference ref="579392910"/> - </array> - <reference key="parent" ref="789758025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">451</int> - <reference key="object" ref="579392910"/> - <array class="NSMutableArray" key="children"> - <reference ref="1060694897"/> - <reference ref="879586729"/> - <reference ref="56570060"/> - </array> - <reference key="parent" ref="288088188"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">452</int> - <reference key="object" ref="1060694897"/> - <reference key="parent" ref="579392910"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">453</int> - <reference key="object" ref="859480356"/> - <reference key="parent" ref="769623530"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">454</int> - <reference key="object" ref="795346622"/> - <reference key="parent" ref="769623530"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">457</int> - <reference key="object" ref="65139061"/> - <reference key="parent" ref="698887838"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">459</int> - <reference key="object" ref="19036812"/> - <reference key="parent" ref="698887838"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">460</int> - <reference key="object" ref="672708820"/> - <reference key="parent" ref="698887838"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">462</int> - <reference key="object" ref="537092702"/> - <reference key="parent" ref="698887838"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">465</int> - <reference key="object" ref="879586729"/> - <reference key="parent" ref="579392910"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">466</int> - <reference key="object" ref="56570060"/> - <reference key="parent" ref="579392910"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">485</int> - <reference key="object" ref="82994268"/> - <reference key="parent" ref="789758025"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">490</int> - <reference key="object" ref="448692316"/> - <array class="NSMutableArray" key="children"> - <reference ref="992780483"/> - </array> - <reference key="parent" ref="649796088"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">491</int> - <reference key="object" ref="992780483"/> - <array class="NSMutableArray" key="children"> - <reference ref="105068016"/> - </array> - <reference key="parent" ref="448692316"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">492</int> - <reference key="object" ref="105068016"/> - <reference key="parent" ref="992780483"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">494</int> - <reference key="object" ref="976324537"/> - <reference key="parent" ref="0"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">496</int> - <reference key="object" ref="215659978"/> - <array class="NSMutableArray" key="children"> - <reference ref="446991534"/> - </array> - <reference key="parent" ref="941447902"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">497</int> - <reference key="object" ref="446991534"/> - <array class="NSMutableArray" key="children"> - <reference ref="875092757"/> - <reference ref="630155264"/> - <reference ref="945678886"/> - <reference ref="512868991"/> - <reference ref="163117631"/> - <reference ref="31516759"/> - <reference ref="908105787"/> - <reference ref="644046920"/> - <reference ref="231811626"/> - <reference ref="883618387"/> - </array> - <reference key="parent" ref="215659978"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">498</int> - <reference key="object" ref="875092757"/> - <reference key="parent" ref="446991534"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">499</int> - <reference key="object" ref="630155264"/> - <reference key="parent" ref="446991534"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">500</int> - <reference key="object" ref="945678886"/> - <reference key="parent" ref="446991534"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">501</int> - <reference key="object" ref="512868991"/> - <reference key="parent" ref="446991534"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">502</int> - <reference key="object" ref="163117631"/> - <reference key="parent" ref="446991534"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">503</int> - <reference key="object" ref="31516759"/> - <array class="NSMutableArray" key="children"> - <reference ref="956096989"/> - </array> - <reference key="parent" ref="446991534"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">504</int> - <reference key="object" ref="908105787"/> - <reference key="parent" ref="446991534"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">505</int> - <reference key="object" ref="644046920"/> - <reference key="parent" ref="446991534"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">506</int> - <reference key="object" ref="231811626"/> - <reference key="parent" ref="446991534"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">507</int> - <reference key="object" ref="883618387"/> - <reference key="parent" ref="446991534"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">508</int> - <reference key="object" ref="956096989"/> - <array class="NSMutableArray" key="children"> - <reference ref="257099033"/> - <reference ref="551969625"/> - <reference ref="249532473"/> - <reference ref="607364498"/> - <reference ref="508151438"/> - <reference ref="981751889"/> - <reference ref="380031999"/> - <reference ref="825984362"/> - <reference ref="560145579"/> - </array> - <reference key="parent" ref="31516759"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">509</int> - <reference key="object" ref="257099033"/> - <reference key="parent" ref="956096989"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">510</int> - <reference key="object" ref="551969625"/> - <reference key="parent" ref="956096989"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">511</int> - <reference key="object" ref="249532473"/> - <reference key="parent" ref="956096989"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">512</int> - <reference key="object" ref="607364498"/> - <reference key="parent" ref="956096989"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">513</int> - <reference key="object" ref="508151438"/> - <reference key="parent" ref="956096989"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">514</int> - <reference key="object" ref="981751889"/> - <reference key="parent" ref="956096989"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">515</int> - <reference key="object" ref="380031999"/> - <reference key="parent" ref="956096989"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">516</int> - <reference key="object" ref="825984362"/> - <reference key="parent" ref="956096989"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">517</int> - <reference key="object" ref="560145579"/> - <reference key="parent" ref="956096989"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">534</int> - <reference key="object" ref="738670835"/> - <reference key="parent" ref="963351320"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">536</int> - <reference key="object" ref="242877095"/> - <array class="NSMutableArray" key="children"> - <reference ref="502956757"/> - <object class="IBNSLayoutConstraint" id="697106875"> - <reference key="firstItem" ref="242877095"/> - <int key="firstAttribute">8</int> - <int key="relation">0</int> - <nil key="secondItem"/> - <int key="secondAttribute">0</int> - <float key="multiplier">1</float> - <object class="IBLayoutConstant" key="constant"> - <double key="value">229</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">3</int> - <float key="scoringTypeFloat">9</float> - <int key="contentType">1</int> - <reference key="containingView" ref="242877095"/> - </object> - </array> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">537</int> - <reference key="object" ref="502956757"/> - <reference key="parent" ref="242877095"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">593</int> - <reference key="object" ref="1018085422"/> - <array class="NSMutableArray" key="children"> - <reference ref="867418359"/> - <object class="IBNSLayoutConstraint" id="276483890"> - <reference key="firstItem" ref="1018085422"/> - <int key="firstAttribute">8</int> - <int key="relation">0</int> - <nil key="secondItem"/> - <int key="secondAttribute">0</int> - <float key="multiplier">1</float> - <object class="IBLayoutConstant" key="constant"> - <double key="value">163</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">3</int> - <float key="scoringTypeFloat">9</float> - <int key="contentType">1</int> - <reference key="containingView" ref="1018085422"/> - </object> - </array> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">594</int> - <reference key="object" ref="867418359"/> - <reference key="parent" ref="1018085422"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">727</int> - <reference key="object" ref="688522420"/> - <array class="NSMutableArray" key="children"> - <reference ref="445379790"/> - <object class="IBNSLayoutConstraint" id="337680523"> - <reference key="firstItem" ref="688522420"/> - <int key="firstAttribute">7</int> - <int key="relation">0</int> - <nil key="secondItem"/> - <int key="secondAttribute">0</int> - <float key="multiplier">1</float> - <object class="IBLayoutConstant" key="constant"> - <double key="value">183</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">3</int> - <float key="scoringTypeFloat">9</float> - <int key="contentType">1</int> - <reference key="containingView" ref="688522420"/> - </object> - <object class="IBNSLayoutConstraint" id="73036966"> - <reference key="firstItem" ref="688522420"/> - <int key="firstAttribute">8</int> - <int key="relation">0</int> - <nil key="secondItem"/> - <int key="secondAttribute">0</int> - <float key="multiplier">1</float> - <object class="IBLayoutConstant" key="constant"> - <double key="value">22</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">3</int> - <float key="scoringTypeFloat">9</float> - <int key="contentType">1</int> - <reference key="containingView" ref="688522420"/> - </object> - </array> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">728</int> - <reference key="object" ref="445379790"/> - <reference key="parent" ref="688522420"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">775</int> - <reference key="object" ref="93467784"/> - <array class="NSMutableArray" key="children"> - <reference ref="623922320"/> - </array> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">776</int> - <reference key="object" ref="623922320"/> - <reference key="parent" ref="93467784"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">780</int> - <reference key="object" ref="46276252"/> - <array class="NSMutableArray" key="children"> - <reference ref="398179500"/> - <object class="IBNSLayoutConstraint" id="944606221"> - <reference key="firstItem" ref="46276252"/> - <int key="firstAttribute">7</int> - <int key="relation">0</int> - <nil key="secondItem"/> - <int key="secondAttribute">0</int> - <float key="multiplier">1</float> - <object class="IBLayoutConstant" key="constant"> - <double key="value">100</double> - </object> - <float key="priority">1000</float> - <int key="scoringType">3</int> - <float key="scoringTypeFloat">9</float> - <int key="contentType">1</int> - <reference key="containingView" ref="46276252"/> - </object> - </array> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">781</int> - <reference key="object" ref="398179500"/> - <reference key="parent" ref="46276252"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">884</int> - <reference key="object" ref="109434655"/> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">981</int> - <reference key="object" ref="229833409"/> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">982</int> - <reference key="object" ref="992363278"/> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">1022</int> - <reference key="object" ref="98217052"/> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">1026</int> - <reference key="object" ref="276483890"/> - <reference key="parent" ref="1018085422"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">979</int> - <reference key="object" ref="166525974"/> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">985</int> - <reference key="object" ref="646866003"/> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">977</int> - <reference key="object" ref="697106875"/> - <reference key="parent" ref="242877095"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">1099</int> - <reference key="object" ref="337680523"/> - <reference key="parent" ref="688522420"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">1093</int> - <reference key="object" ref="578918264"/> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">1100</int> - <reference key="object" ref="73036966"/> - <reference key="parent" ref="688522420"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">1098</int> - <reference key="object" ref="432526715"/> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">1168</int> - <reference key="object" ref="670714078"/> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">1167</int> - <reference key="object" ref="833183002"/> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">1095</int> - <reference key="object" ref="591594339"/> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">1166</int> - <reference key="object" ref="891430181"/> - <reference key="parent" ref="439893737"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">1076</int> - <reference key="object" ref="944606221"/> - <reference key="parent" ref="46276252"/> - </object> - </array> - </object> - <dictionary class="NSMutableDictionary" key="flattenedProperties"> - <string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="1022.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="1026.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="1076.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="1093.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="1095.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="1098.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="1099.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="1100.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="112.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="1166.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="1167.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="1168.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="124.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="125.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="126.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="129.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="130.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="131.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="134.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="136.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="143.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="144.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="145.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="149.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="150.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="19.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="195.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="196.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="197.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="198.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="199.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="200.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="201.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="202.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="203.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="204.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="205.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="206.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="207.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="208.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="209.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="210.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="211.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="212.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="213.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="214.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="215.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="216.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="217.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="218.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="219.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="220.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="221.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="23.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="236.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="239.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="24.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="29.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="295.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="296.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="297.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="298.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="346.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="348.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="349.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="350.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="351.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="354.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="371.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="371.IBWindowTemplateEditedContentRect">{{380, 496}, {480, 360}}</string> - <integer value="1" key="371.NSWindowTemplate.visibleAtLaunch"/> - <array class="NSMutableArray" key="372.IBNSViewMetadataConstraints"> - <reference ref="109434655"/> - <reference ref="166525974"/> - <reference ref="229833409"/> - <reference ref="992363278"/> - <reference ref="646866003"/> - <reference ref="98217052"/> - <reference ref="578918264"/> - <reference ref="591594339"/> - <reference ref="432526715"/> - <reference ref="891430181"/> - <reference ref="833183002"/> - <reference ref="670714078"/> - </array> - <string key="372.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <reference key="372.IBUserGuides" ref="0"/> - <string key="375.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="376.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="377.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="388.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="389.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="390.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="391.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="392.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="393.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="394.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="395.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="396.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="397.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="398.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="399.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="400.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="401.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="402.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="403.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="404.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="405.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="406.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="407.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="408.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="409.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="410.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="411.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="412.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="413.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="414.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="415.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="416.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="417.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="418.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="419.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="450.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="451.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="452.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="453.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="454.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="457.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="459.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="460.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="462.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="465.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="466.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="485.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="490.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="491.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="492.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="494.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="496.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="497.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="498.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="499.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="5.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="500.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="501.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="502.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="503.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="504.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="505.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="506.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="507.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="508.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="509.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="510.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="511.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="512.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="513.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="514.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="515.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="516.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="517.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="534.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <array class="NSMutableArray" key="536.IBNSViewMetadataConstraints"> - <reference ref="697106875"/> - </array> - <boolean value="NO" key="536.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/> - <string key="536.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="537.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="56.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="57.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="58.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <array class="NSMutableArray" key="593.IBNSViewMetadataConstraints"> - <reference ref="276483890"/> - </array> - <boolean value="NO" key="593.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/> - <string key="593.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="594.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="72.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <array class="NSMutableArray" key="727.IBNSViewMetadataConstraints"> - <reference ref="337680523"/> - <reference ref="73036966"/> - </array> - <boolean value="NO" key="727.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/> - <string key="727.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="728.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="73.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="74.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="75.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="77.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <boolean value="NO" key="775.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/> - <string key="775.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="776.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="78.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <array class="NSMutableArray" key="780.IBNSViewMetadataConstraints"> - <reference ref="944606221"/> - </array> - <boolean value="NO" key="780.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/> - <string key="780.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="781.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="79.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="81.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="82.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="83.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="884.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="92.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="977.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="979.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="981.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="982.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="985.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> - </dictionary> - <dictionary class="NSMutableDictionary" key="unlocalizedProperties"/> - <nil key="activeLocalization"/> - <dictionary class="NSMutableDictionary" key="localizations"/> - <nil key="sourceID"/> - <int key="maxID">1187</int> - </object> - <object class="IBClassDescriber" key="IBDocument.Classes"> - <array class="NSMutableArray" key="referencedPartialClassDescriptions"> - <object class="IBPartialClassDescription"> - <string key="className">LLCrashLoggerMacDelegate</string> - <string key="superclassName">NSObject</string> - <dictionary class="NSMutableDictionary" key="actions"> - <string key="cancel:">id</string> - <string key="remember:">id</string> - <string key="send:">id</string> - </dictionary> - <dictionary class="NSMutableDictionary" key="actionInfosByName"> - <object class="IBActionInfo" key="cancel:"> - <string key="name">cancel:</string> - <string key="candidateClassName">id</string> - </object> - <object class="IBActionInfo" key="remember:"> - <string key="name">remember:</string> - <string key="candidateClassName">id</string> - </object> - <object class="IBActionInfo" key="send:"> - <string key="name">send:</string> - <string key="candidateClassName">id</string> - </object> - </dictionary> - <dictionary class="NSMutableDictionary" key="outlets"> - <string key="crashText">NSTextField</string> - <string key="rememberCheck">NSButton</string> - <string key="window">NSWindow</string> - </dictionary> - <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName"> - <object class="IBToOneOutletInfo" key="crashText"> - <string key="name">crashText</string> - <string key="candidateClassName">NSTextField</string> - </object> - <object class="IBToOneOutletInfo" key="rememberCheck"> - <string key="name">rememberCheck</string> - <string key="candidateClassName">NSButton</string> - </object> - <object class="IBToOneOutletInfo" key="window"> - <string key="name">window</string> - <string key="candidateClassName">NSWindow</string> - </object> - </dictionary> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBProjectSource</string> - <string key="minorKey">./Classes/LLCrashLoggerMacDelegate.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSLayoutConstraint</string> - <string key="superclassName">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBProjectSource</string> - <string key="minorKey">./Classes/NSLayoutConstraint.h</string> - </object> - </object> - </array> - </object> - <int key="IBDocument.localizationMode">0</int> - <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string> - <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies"> - <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string> - <integer value="1070" key="NS.object.0"/> - </object> - <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool> - <int key="IBDocument.defaultPropertyAccessControl">3</int> - <dictionary class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes"> - <string key="NSMenuCheckmark">{11, 11}</string> - <string key="NSMenuMixedState">{10, 3}</string> - <string key="NSSwitch">{15, 15}</string> - </dictionary> - <bool key="IBDocument.UseAutolayout">YES</bool> - </data> -</archive> diff --git a/indra/mac_crash_logger/Info.plist b/indra/mac_crash_logger/Info.plist deleted file mode 100644 index 2ebed11c3f..0000000000 --- a/indra/mac_crash_logger/Info.plist +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>CFBundleDevelopmentRegion</key> - <string>English</string> - <key>CFBundleExecutable</key> - <string>mac-crash-logger</string> - <key>CFBundleGetInfoString</key> - <string></string> - <key>CFBundleIconFile</key> - <string></string> - <key>CFBundleInfoDictionaryVersion</key> - <string>6.0</string> - <key>CFBundlePackageType</key> - <string>APPL</string> - <key>CFBundleShortVersionString</key> - <string></string> - <key>CFBundleSignature</key> - <string>????</string> - <key>CFBundleVersion</key> - <string>1.0.0</string> - <key>NSMainNibFile</key> - <string>CrashReporter</string> - <key>NSPrincipalClass</key> - <string>NSApplication</string> -</dict> -</plist> diff --git a/indra/mac_crash_logger/README.txt b/indra/mac_crash_logger/README.txt new file mode 100644 index 0000000000..6932a8d9c3 --- /dev/null +++ b/indra/mac_crash_logger/README.txt @@ -0,0 +1,3 @@ +This component is no longer used in Linden Lab builds. +Change requests to support continued use by open source +builds are welcome. diff --git a/indra/mac_crash_logger/llcrashloggermac.cpp b/indra/mac_crash_logger/llcrashloggermac.cpp deleted file mode 100644 index ec3616e26a..0000000000 --- a/indra/mac_crash_logger/llcrashloggermac.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/** - * @file llcrashloggermac.cpp - * @brief Mac OSX crash logger implementation - * - * $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 "llcrashloggermac.h" - -#include <iostream> - -#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" - -// Windows Message Handlers - -BOOL gFirstDialog = TRUE; -LLFILE *gDebugFile = NULL; - -std::string gUserNotes = ""; -bool gSendReport = false; -bool gRememberChoice = false; - -LLCrashLoggerMac::LLCrashLoggerMac(void) -{ -} - -LLCrashLoggerMac::~LLCrashLoggerMac(void) -{ -} - -bool LLCrashLoggerMac::init(void) -{ - bool ok = LLCrashLogger::init(); - return ok; -} - -void LLCrashLoggerMac::gatherPlatformSpecificFiles() -{ -} - -bool LLCrashLoggerMac::frame() -{ - - if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND) - { - gSendReport = true; - } - - if(gSendReport) - { - setUserText(gUserNotes); - sendCrashLogs(); - } - - LL_INFOS() << "Sending of logs complete" << LL_ENDL; - - return true; -} - -bool LLCrashLoggerMac::cleanup() -{ - commonCleanup(); - mKeyMaster.releaseMaster(); - return true; -} diff --git a/indra/mac_crash_logger/llcrashloggermacdelegate.mm b/indra/mac_crash_logger/llcrashloggermacdelegate.mm deleted file mode 100644 index b2af76a47c..0000000000 --- a/indra/mac_crash_logger/llcrashloggermacdelegate.mm +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @file llcrashloggermacdelegate.mm - * @brief Mac OSX crash logger implementation - * - * $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$ - */ - - -/* -#import "llcrashloggermacdelegate.h" -#include <iostream> - -extern std::string gUserNotes; -extern bool gSendReport; -extern bool gRememberChoice; - -@implementation LLCrashLoggerMacDelegate - -- (void)setWindow:(NSWindow *)window -{ - _window = window; -} - -- (NSWindow *)window -{ - return _window; -} - -- (void)dealloc -{ - [super dealloc]; -} - -std::string* NSToString( NSString *ns_str ) -{ - return ( new std::string([ns_str UTF8String]) ); -} - -- (IBAction)remember:(id)sender -{ - gRememberChoice = [rememberCheck state]; -} - -- (IBAction)send:(id)sender -{ - std::string* user_input = NSToString([crashText stringValue]); - gUserNotes = *user_input; - gSendReport = true; -} - -- (IBAction)cancel:(id)sender -{ - [ _window close]; -} -@end -*/
\ No newline at end of file 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 54e41a1954..0000000000 --- a/indra/mac_crash_logger/mac_crash_logger.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/** - * @file mac_crash_logger.cpp - * @brief Mac OSX crash logger implementation - * - * $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 "linden_common.h" -#include "llcrashloggermac.h" -#include "indra_constants.h" -#include "llpidlock.h" - -#include <iostream> - -int main(int argc, char **argv) -{ - LLCrashLoggerMac app; - app.parseCommandOptions(argc, argv); - - LLSD options = LLApp::instance()->getOptionData( - LLApp::PRIORITY_COMMAND_LINE); - - if (! app.init()) - { - LL_WARNS() << "Unable to initialize application." << LL_ENDL; - return 1; - } - - if (app.getCrashBehavior() != CRASH_BEHAVIOR_ALWAYS_SEND) - { -// return NSApplicationMain(argc, (const char **)argv); - } - app.frame(); - app.cleanup(); - - LL_INFOS() << "Crash reporter finished normally." << LL_ENDL; - - return 0; -} diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index eead92fd8e..8465285d2b 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -62,6 +62,7 @@ private: void onConsoleMessageCallback(std::string message, std::string source, int line); void onStatusMessageCallback(std::string value); void onTitleChangeCallback(std::string title); + void onTooltipCallback(std::string text); void onLoadStartCallback(); void onRequestExitCallback(); void onLoadEndCallback(int httpStatusCode); @@ -71,6 +72,8 @@ private: bool onHTTPAuthCallback(const std::string host, const std::string realm, std::string& username, std::string& password); void onCursorChangedCallback(dullahan::ECursorType type); const std::vector<std::string> onFileDialog(dullahan::EFileDialogType dialog_type, const std::string dialog_title, const std::string default_file, const std::string dialog_accept_filter, bool& use_default); + bool onJSDialogCallback(const std::string origin_url, const std::string message_text, const std::string default_prompt_text); + bool onJSBeforeUnloadCallback(); void postDebugMessage(const std::string& msg); void authResponse(LLPluginMessage &message); @@ -87,6 +90,8 @@ private: bool mPluginsEnabled; bool mJavascriptEnabled; bool mDisableGPU; + bool mDisableNetworkService; + bool mUseMockKeyChain; std::string mUserAgentSubtring; std::string mAuthUsername; std::string mAuthPassword; @@ -94,8 +99,9 @@ private: bool mCanCut; bool mCanCopy; bool mCanPaste; + std::string mRootCachePath; std::string mCachePath; - std::string mCookiePath; + std::string mContextCachePath; std::string mCefLogFile; bool mCefLogVerbose; std::vector<std::string> mPickedFiles; @@ -119,6 +125,8 @@ MediaPluginBase(host_send_func, host_user_data) mPluginsEnabled = false; mJavascriptEnabled = true; mDisableGPU = false; + mDisableNetworkService = true; + mUseMockKeyChain = true; mUserAgentSubtring = ""; mAuthUsername = ""; mAuthPassword = ""; @@ -127,7 +135,6 @@ MediaPluginBase(host_send_func, host_user_data) mCanCopy = false; mCanPaste = false; mCachePath = ""; - mCookiePath = ""; mCefLogFile = ""; mCefLogVerbose = false; mPickedFiles.clear(); @@ -208,6 +215,12 @@ void MediaPluginCEF::onTitleChangeCallback(std::string title) sendMessage(message); } +void MediaPluginCEF::onTooltipCallback(std::string text) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "tooltip_text"); + message.setValue("tooltip", text); + sendMessage(message); +} //////////////////////////////////////////////////////////////////////////////// // void MediaPluginCEF::onLoadStartCallback() @@ -241,6 +254,7 @@ void MediaPluginCEF::onRequestExitCallback() LLPluginMessage message("base", "goodbye"); sendMessage(message); + // Will trigger delete on next staticReceiveMessage() mDeleteMe = true; } @@ -356,6 +370,22 @@ const std::vector<std::string> MediaPluginCEF::onFileDialog(dullahan::EFileDialo //////////////////////////////////////////////////////////////////////////////// // +bool MediaPluginCEF::onJSDialogCallback(const std::string origin_url, const std::string message_text, const std::string default_prompt_text) +{ + // return true indicates we suppress the JavaScript alert UI entirely + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool MediaPluginCEF::onJSBeforeUnloadCallback() +{ + // return true indicates we suppress the JavaScript UI entirely + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// void MediaPluginCEF::onCursorChangedCallback(dullahan::ECursorType type) { std::string name = ""; @@ -430,6 +460,8 @@ void MediaPluginCEF::receiveMessage(const char* message_string) { mCEFLib->update(); + mVolumeCatcher.pump(); + // this seems bad but unless the state changes (it won't until we figure out // how to get CEF to tell us if copy/cut/paste is available) then this function // will return immediately @@ -437,9 +469,12 @@ void MediaPluginCEF::receiveMessage(const char* message_string) } else if (message_name == "cleanup") { - mVolumeCatcher.setVolume(0); mCEFLib->requestExit(); } + else if (message_name == "force_exit") + { + mDeleteMe = true; + } else if (message_name == "shm_added") { SharedSegmentInfo info; @@ -486,6 +521,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string) mCEFLib->setOnConsoleMessageCallback(std::bind(&MediaPluginCEF::onConsoleMessageCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); mCEFLib->setOnStatusMessageCallback(std::bind(&MediaPluginCEF::onStatusMessageCallback, this, std::placeholders::_1)); mCEFLib->setOnTitleChangeCallback(std::bind(&MediaPluginCEF::onTitleChangeCallback, this, std::placeholders::_1)); + mCEFLib->setOnTooltipCallback(std::bind(&MediaPluginCEF::onTooltipCallback, this, std::placeholders::_1)); mCEFLib->setOnLoadStartCallback(std::bind(&MediaPluginCEF::onLoadStartCallback, this)); mCEFLib->setOnLoadEndCallback(std::bind(&MediaPluginCEF::onLoadEndCallback, this, std::placeholders::_1)); mCEFLib->setOnLoadErrorCallback(std::bind(&MediaPluginCEF::onLoadError, this, std::placeholders::_1, std::placeholders::_2)); @@ -495,16 +531,50 @@ void MediaPluginCEF::receiveMessage(const char* message_string) mCEFLib->setOnFileDialogCallback(std::bind(&MediaPluginCEF::onFileDialog, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); mCEFLib->setOnCursorChangedCallback(std::bind(&MediaPluginCEF::onCursorChangedCallback, this, std::placeholders::_1)); mCEFLib->setOnRequestExitCallback(std::bind(&MediaPluginCEF::onRequestExitCallback, this)); - + mCEFLib->setOnJSDialogCallback(std::bind(&MediaPluginCEF::onJSDialogCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + mCEFLib->setOnJSBeforeUnloadCallback(std::bind(&MediaPluginCEF::onJSBeforeUnloadCallback, this)); + dullahan::dullahan_settings settings; +#if LL_WINDOWS + // As of CEF version 83+, for Windows versions, we need to tell CEF + // where the host helper process is since this DLL is not in the same + // dir as the executable that loaded it (SLPlugin.exe). The code in + // Dullahan that tried to figure out the location automatically uses + // the location of the exe which isn't helpful so we tell it explicitly. + char cur_dir_str[MAX_PATH]; + GetCurrentDirectoryA(MAX_PATH, cur_dir_str); + settings.host_process_path = std::string(cur_dir_str); +#endif settings.accept_language_list = mHostLanguage; - settings.background_color = 0xffffffff; + + // SL-15560: Product team overruled my change to set the default + // embedded background color to match the floater background + // and set it to white + settings.background_color = 0xffffffff; // white + settings.cache_enabled = true; + settings.root_cache_path = mRootCachePath; settings.cache_path = mCachePath; - settings.cookie_store_path = mCookiePath; + settings.context_cache_path = mContextCachePath; settings.cookies_enabled = mCookiesEnabled; settings.disable_gpu = mDisableGPU; - settings.flash_enabled = mPluginsEnabled; +#if LL_DARWIN + settings.disable_network_service = mDisableNetworkService; + settings.use_mock_keychain = mUseMockKeyChain; +#endif + // This setting applies to all plugins, not just Flash + // Regarding, SL-15559 PDF files do not load in CEF v91, + // it turns out that on Windows, PDF support is treated + // as a plugin on Windows only so turning all plugins + // off, disabled built in PDF support. (Works okay in + // macOS surprisingly). To mitigrate this, we set the global + // media enabled flag to whatever the consumer wants and + // explicitly disable Flash with a different setting (below) + settings.plugins_enabled = mPluginsEnabled; + + // SL-14897 Disable Flash support in the embedded browser + settings.flash_enabled = false; + settings.flip_mouse_y = false; settings.flip_pixels_y = true; settings.frame_rate = 60; @@ -513,8 +583,8 @@ void MediaPluginCEF::receiveMessage(const char* message_string) settings.initial_width = 1024; settings.java_enabled = false; settings.javascript_enabled = mJavascriptEnabled; - settings.media_stream_enabled = false; // MAINT-6060 - WebRTC media removed until we can add granualrity/query UI - settings.plugins_enabled = mPluginsEnabled; + settings.media_stream_enabled = false; // MAINT-6060 - WebRTC media removed until we can add granularity/query UI + settings.user_agent_substring = mCEFLib->makeCompatibleUserAgentString(mUserAgentSubtring); settings.webgl_enabled = true; settings.log_file = mCefLogFile; @@ -525,10 +595,10 @@ void MediaPluginCEF::receiveMessage(const char* message_string) mCEFLib->setCustomSchemes(custom_schemes); bool result = mCEFLib->init(settings); - if (!result) - { - // if this fails, the media system in viewer will put up a message - } + if (!result) + { + // if this fails, the media system in viewer will put up a message + } // now we can set page zoom factor F32 factor = (F32)message_in.getValueReal("factor"); @@ -553,10 +623,25 @@ void MediaPluginCEF::receiveMessage(const char* message_string) else if (message_name == "set_user_data_path") { std::string user_data_path_cache = message_in.getValue("cache_path"); - std::string user_data_path_cookies = message_in.getValue("cookies_path"); + std::string subfolder = message_in.getValue("username"); - mCachePath = user_data_path_cache + "cef_cache"; - mCookiePath = user_data_path_cookies + "cef_cookies"; + mRootCachePath = user_data_path_cache + "cef_cache"; + if (!subfolder.empty()) + { + std::string delim; +#if LL_WINDOWS + // media plugin doesn't have access to gDirUtilp + delim = "\\"; +#else + delim = "/"; +#endif + mCachePath = mRootCachePath + delim + subfolder; + } + else + { + mCachePath = mRootCachePath; + } + mContextCachePath = ""; // disabled by "" mCefLogFile = message_in.getValue("cef_log_file"); mCefLogVerbose = message_in.getValueBoolean("cef_verbose_log"); } @@ -655,12 +740,18 @@ void MediaPluginCEF::receiveMessage(const char* message_string) } else if (message_name == "scroll_event") { + // Mouse coordinates for cef to be able to scroll 'containers' S32 x = message_in.getValueS32("x"); S32 y = message_in.getValueS32("y"); + + // Wheel's clicks + S32 delta_x = message_in.getValueS32("clicks_x"); + S32 delta_y = message_in.getValueS32("clicks_y"); const int scaling_factor = 40; - y *= -scaling_factor; + delta_x *= -scaling_factor; + delta_y *= -scaling_factor; - mCEFLib->mouseWheel(x, y); + mCEFLib->mouseWheel(x, y, delta_x, delta_y); } else if (message_name == "text_event") { diff --git a/indra/media_plugins/cef/windows_volume_catcher.cpp b/indra/media_plugins/cef/windows_volume_catcher.cpp index 6953ad3ab8..7a36123a11 100644 --- a/indra/media_plugins/cef/windows_volume_catcher.cpp +++ b/indra/media_plugins/cef/windows_volume_catcher.cpp @@ -27,8 +27,9 @@ */ #include "volume_catcher.h" -#include <windows.h> #include "llsingleton.h" +#include <windows.h> +#include <mmeapi.h> class VolumeCatcherImpl : public LLSingleton<VolumeCatcherImpl> { LLSINGLETON(VolumeCatcherImpl); diff --git a/indra/media_plugins/example/media_plugin_example.cpp b/indra/media_plugins/example/media_plugin_example.cpp index c296a0413d..650685fb94 100644 --- a/indra/media_plugins/example/media_plugin_example.cpp +++ b/indra/media_plugins/example/media_plugin_example.cpp @@ -128,6 +128,10 @@ void mediaPluginExample::receiveMessage(const char* message_string) mDeleteMe = true; } + else if (message_name == "force_exit") + { + mDeleteMe = true; + } else if (message_name == "shm_added") { SharedSegmentInfo info; diff --git a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp index 80702a1079..5d4a488e64 100644 --- a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp +++ b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp @@ -34,6 +34,11 @@ #include "llpluginmessageclasses.h" #include "media_plugin_base.h" +#if defined(_MSC_VER) +#include <basetsd.h> +typedef SSIZE_T ssize_t; +#endif + #include "vlc/vlc.h" #include "vlc/libvlc_version.h" @@ -495,6 +500,10 @@ void MediaPluginLibVLC::receiveMessage(const char* message_string) { resetVLC(); } + else if (message_name == "force_exit") + { + mDeleteMe = true; + } else if (message_name == "shm_added") { SharedSegmentInfo info; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index f03dcb4066..8d902ce618 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -8,17 +8,14 @@ include(00-Common) include(Linking) include(Boost) -if (BUGSPLAT_DB) - include(bugsplat) -endif (BUGSPLAT_DB) +include(bugsplat) include(BuildPackagesInfo) include(BuildVersion) include(CMakeCopyIfDifferent) include(DBusGlib) -include(DirectX) include(DragDrop) include(EXPAT) -include(FMODEX) +include(FMODSTUDIO) include(GLOD) include(Hunspell) include(ICU4C) @@ -64,9 +61,9 @@ if (NOT HAVOK_TPV) add_subdirectory(${LLPHYSICSEXTENSIONS_SRC_DIR} llphysicsextensions) endif (NOT HAVOK_TPV) -if(FMODEX) - include_directories(${FMODEX_INCLUDE_DIR}) -endif(FMODEX) +if(FMODSTUDIO) + include_directories(${FMODSTUDIO_INCLUDE_DIR}) +endif(FMODSTUDIO) include_directories( ${DBUSGLIB_INCLUDE_DIRS} @@ -98,24 +95,25 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ) -if (BUGSPLAT_DB) - include_directories( - ${BUGSPLAT_INCLUDE_DIR} - ) -endif (BUGSPLAT_DB) - include_directories(SYSTEM ${LLCOMMON_SYSTEM_INCLUDE_DIRS} ${LLXML_SYSTEM_INCLUDE_DIRS} ${LLPHYSICSEXTENSIONS_INCLUDE_DIRS} ) +if (USE_BUGSPLAT) + include_directories(AFTER + ${BUGSPLAT_INCLUDE_DIR} + ) +endif (USE_BUGSPLAT) + set(viewer_SOURCE_FILES groupchatlistener.cpp llaccountingcostmanager.cpp llaisapi.cpp llagent.cpp llagentaccess.cpp + llagentbenefits.cpp llagentcamera.cpp llagentdata.cpp llagentlanguage.cpp @@ -171,7 +169,6 @@ set(viewer_SOURCE_FILES llcurrencyuimanager.cpp llcylinder.cpp lldateutil.cpp - lldaycyclemanager.cpp lldebugmessagebox.cpp lldebugview.cpp lldeferredsounds.cpp @@ -194,7 +191,7 @@ set(viewer_SOURCE_FILES lldrawpoolwlsky.cpp lldynamictexture.cpp llemote.cpp - llenvmanager.cpp + llenvironment.cpp llestateinfomodel.cpp lleventnotifier.cpp lleventpoll.cpp @@ -209,9 +206,9 @@ set(viewer_SOURCE_FILES llfilteredwearablelist.cpp llfirstuse.cpp llflexibleobject.cpp - llflickrconnect.cpp llfloaterabout.cpp llfloaterbvhpreview.cpp + llfloateraddpaymentmethod.cpp llfloaterauction.cpp llfloaterautoreplacesettings.cpp llfloateravatar.cpp @@ -230,23 +227,24 @@ set(viewer_SOURCE_FILES llfloaterbuycurrencyhtml.cpp llfloaterbuyland.cpp llfloatercamera.cpp + llfloatercamerapresets.cpp llfloaterchatvoicevolume.cpp llfloatercolorpicker.cpp llfloaterconversationlog.cpp llfloaterconversationpreview.cpp - llfloaterdeleteenvpreset.cpp + llfloatercreatelandmark.cpp llfloaterdeleteprefpreset.cpp llfloaterdestinations.cpp - llfloatereditdaycycle.cpp - llfloatereditsky.cpp - llfloatereditwater.cpp - llfloaterenvironmentsettings.cpp + llfloatereditenvironmentbase.cpp + llfloatereditextdaycycle.cpp + llfloaterenvironmentadjust.cpp llfloaterevent.cpp llfloaterexperiencepicker.cpp llfloaterexperienceprofile.cpp llfloaterexperiences.cpp - llfloaterflickr.cpp + llfloaterfixedenvironment.cpp llfloaterfonttest.cpp + llfloaterforgetuser.cpp llfloatergesture.cpp llfloatergodtools.cpp llfloatergotoline.cpp @@ -257,6 +255,7 @@ set(viewer_SOURCE_FILES llfloaterhandler.cpp llfloaterhelpbrowser.cpp llfloaterhoverheight.cpp + llfloaterhowto.cpp llfloaterhud.cpp llfloaterimagepreview.cpp llfloaterimsessiontab.cpp @@ -276,6 +275,7 @@ set(viewer_SOURCE_FILES llfloatermodelpreview.cpp llfloatermodeluploadbase.cpp llfloatermyscripts.cpp + llfloatermyenvironment.cpp llfloaternamedesc.cpp llfloaternotificationsconsole.cpp llfloaternotificationstabbed.cpp @@ -291,12 +291,14 @@ set(viewer_SOURCE_FILES llfloaterperms.cpp llfloaterpostprocess.cpp llfloaterpreference.cpp + llfloaterpreferenceviewadvanced.cpp llfloaterpreviewtrash.cpp llfloaterproperties.cpp llfloaterregiondebugconsole.cpp llfloaterregioninfo.cpp llfloaterreporter.cpp llfloaterregionrestarting.cpp + llfloatersavecamerapreset.cpp llfloatersaveprefpreset.cpp llfloatersceneloadstats.cpp llfloaterscriptdebug.cpp @@ -318,7 +320,6 @@ set(viewer_SOURCE_FILES llfloatertos.cpp llfloatertoybox.cpp llfloatertranslationsettings.cpp - llfloatertwitter.cpp llfloateruipreview.cpp llfloaterurlentry.cpp llfloatervoiceeffect.cpp @@ -331,6 +332,7 @@ set(viewer_SOURCE_FILES llfolderviewmodelinventory.cpp llfollowcam.cpp llfriendcard.cpp + llflyoutcombobtn.cpp llgesturelistener.cpp llgesturemgr.cpp llgiveinventory.cpp @@ -376,8 +378,10 @@ set(viewer_SOURCE_FILES llinventoryobserver.cpp llinventorypanel.cpp lljoystickbutton.cpp + llkeyconflict.cpp lllandmarkactions.cpp lllandmarklist.cpp + lllegacyatmospherics.cpp lllistbrowser.cpp lllistcontextmenu.cpp lllistview.cpp @@ -401,6 +405,7 @@ set(viewer_SOURCE_FILES llmenuoptionpathfindingrebakenavmesh.cpp llmeshrepository.cpp llmimetypes.cpp + llmodelpreview.cpp llmorphview.cpp llmoveview.cpp llmutelist.cpp @@ -433,7 +438,10 @@ set(viewer_SOURCE_FILES llpanelblockedlist.cpp llpanelclassified.cpp llpanelcontents.cpp + llpaneleditsky.cpp + llpaneleditwater.cpp llpaneleditwearable.cpp + llpanelenvironment.cpp llpanelexperiencelisteditor.cpp llpanelexperiencelog.cpp llpanelexperiencepicker.cpp @@ -441,6 +449,7 @@ set(viewer_SOURCE_FILES llpanelface.cpp llpanelgenerictip.cpp llpanelgroup.cpp + llpanelgroupcreate.cpp llpanelgroupbulk.cpp llpanelgroupbulkban.cpp llpanelgroupexperiences.cpp @@ -479,6 +488,7 @@ set(viewer_SOURCE_FILES llpanelplaceprofile.cpp llpanelplaces.cpp llpanelplacestab.cpp + llpanelpresetscamerapulldown.cpp llpanelpresetspulldown.cpp llpanelprimmediacontrols.cpp llpanelprofile.cpp @@ -492,6 +502,7 @@ set(viewer_SOURCE_FILES llpaneltiptoast.cpp llpanelvoiceeffect.cpp llpaneltopinfobar.cpp + llpanelpulldown.cpp llpanelvoicedevicesettings.cpp llpanelvolume.cpp llpanelvolumepulldown.cpp @@ -549,6 +560,9 @@ set(viewer_SOURCE_FILES llsecapi.cpp llsechandler_basic.cpp llselectmgr.cpp + llsetkeybinddialog.cpp + llsettingspicker.cpp + llsettingsvo.cpp llshareavatarhandler.cpp llsidepanelappearance.cpp llsidepanelinventory.cpp @@ -574,6 +588,7 @@ set(viewer_SOURCE_FILES llsyntaxid.cpp llsyswellitem.cpp llsyswellwindow.cpp + lltelemetry.cpp llteleporthistory.cpp llteleporthistorystorage.cpp lltextureatlas.cpp @@ -613,16 +628,17 @@ set(viewer_SOURCE_FILES lltoolselectland.cpp lltoolselectrect.cpp lltracker.cpp + lltrackpicker.cpp lltransientdockablefloater.cpp lltransientfloatermgr.cpp lltranslate.cpp - lltwitterconnect.cpp lluiavatar.cpp lluilistener.cpp lluploaddialog.cpp llurl.cpp llurldispatcher.cpp llurldispatcherlistener.cpp + llurlfloaterdispatchhandler.cpp llurlhistory.cpp llurllineeditorctrl.cpp llurlwhitelist.cpp @@ -652,7 +668,7 @@ set(viewer_SOURCE_FILES llviewerjointattachment.cpp llviewerjointmesh.cpp llviewerjoystick.cpp - llviewerkeyboard.cpp + llviewerinput.cpp llviewerlayer.cpp llviewermedia.cpp llviewermedia_streamingaudio.cpp @@ -664,6 +680,7 @@ set(viewer_SOURCE_FILES llviewerobject.cpp llviewerobjectlist.cpp llvieweroctree.cpp + llviewerparcelaskplay.cpp llviewerparcelmedia.cpp llviewerparcelmediaautoplay.cpp llviewerparcelmgr.cpp @@ -704,19 +721,13 @@ set(viewer_SOURCE_FILES llvowater.cpp llvowlsky.cpp llwatchdog.cpp - llwaterparammanager.cpp - llwaterparamset.cpp llwearableitemslist.cpp llwearablelist.cpp llweb.cpp llwebprofile.cpp llwind.cpp llwindowlistener.cpp - llwlanimator.cpp - llwldaycycle.cpp llwlhandlers.cpp - llwlparammanager.cpp - llwlparamset.cpp llworld.cpp llworldmap.cpp llworldmapmessage.cpp @@ -740,6 +751,7 @@ set(viewer_HEADER_FILES llaisapi.h llagent.h llagentaccess.h + llagentbenefits.h llagentcamera.h llagentdata.h llagentlanguage.h @@ -796,7 +808,6 @@ set(viewer_HEADER_FILES llcurrencyuimanager.h llcylinder.h lldateutil.h - lldaycyclemanager.h lldebugmessagebox.h lldebugview.h lldeferredsounds.h @@ -819,7 +830,7 @@ set(viewer_HEADER_FILES lldrawpoolwlsky.h lldynamictexture.h llemote.h - llenvmanager.h + llenvironment.h llestateinfomodel.h lleventnotifier.h lleventpoll.h @@ -834,9 +845,9 @@ set(viewer_HEADER_FILES llfilteredwearablelist.h llfirstuse.h llflexibleobject.h - llflickrconnect.h llfloaterabout.h llfloaterbvhpreview.h + llfloateraddpaymentmethod.h llfloaterauction.h llfloaterautoreplacesettings.h llfloateravatar.h @@ -854,24 +865,25 @@ set(viewer_HEADER_FILES llfloaterbuycurrency.h llfloaterbuycurrencyhtml.h llfloaterbuyland.h + llfloatercamerapresets.h llfloatercamera.h llfloaterchatvoicevolume.h llfloatercolorpicker.h llfloaterconversationlog.h llfloaterconversationpreview.h + llfloatercreatelandmark.h llfloaterdeleteprefpreset.h - llfloaterdeleteenvpreset.h llfloaterdestinations.h - llfloatereditdaycycle.h - llfloatereditsky.h - llfloatereditwater.h - llfloaterenvironmentsettings.h + llfloatereditenvironmentbase.h + llfloatereditextdaycycle.h + llfloaterenvironmentadjust.h llfloaterevent.h llfloaterexperiencepicker.h llfloaterexperienceprofile.h llfloaterexperiences.h - llfloaterflickr.h + llfloaterfixedenvironment.h llfloaterfonttest.h + llfloaterforgetuser.h llfloatergesture.h llfloatergodtools.h llfloatergotoline.h @@ -882,6 +894,7 @@ set(viewer_HEADER_FILES llfloaterhandler.h llfloaterhelpbrowser.h llfloaterhoverheight.h + llfloaterhowto.h llfloaterhud.h llfloaterimagepreview.h llfloaterimnearbychat.h @@ -904,6 +917,7 @@ set(viewer_HEADER_FILES llfloatermodelpreview.h llfloatermodeluploadbase.h llfloatermyscripts.h + llfloatermyenvironment.h llfloaternamedesc.h llfloaternotificationsconsole.h llfloaternotificationstabbed.h @@ -919,12 +933,14 @@ set(viewer_HEADER_FILES llfloaterperms.h llfloaterpostprocess.h llfloaterpreference.h + llfloaterpreferenceviewadvanced.h llfloaterpreviewtrash.h llfloaterproperties.h llfloaterregiondebugconsole.h llfloaterregioninfo.h llfloaterreporter.h llfloaterregionrestarting.h + llfloatersavecamerapreset.h llfloatersaveprefpreset.h llfloatersceneloadstats.h llfloaterscriptdebug.h @@ -946,7 +962,6 @@ set(viewer_HEADER_FILES llfloatertos.h llfloatertoybox.h llfloatertranslationsettings.h - llfloatertwitter.h llfloateruipreview.h llfloaterurlentry.h llfloatervoiceeffect.h @@ -959,6 +974,7 @@ set(viewer_HEADER_FILES llfolderviewmodelinventory.h llfollowcam.h llfriendcard.h + llflyoutcombobtn.h llgesturelistener.h llgesturemgr.h llgiveinventory.h @@ -1002,6 +1018,7 @@ set(viewer_HEADER_FILES llinventoryobserver.h llinventorypanel.h lljoystickbutton.h + llkeyconflict.h lllandmarkactions.h lllandmarklist.h lllightconstants.h @@ -1028,6 +1045,7 @@ set(viewer_HEADER_FILES llmenuoptionpathfindingrebakenavmesh.h llmeshrepository.h llmimetypes.h + llmodelpreview.h llmorphview.h llmoveview.h llmutelist.h @@ -1051,7 +1069,10 @@ set(viewer_HEADER_FILES llpanelblockedlist.h llpanelclassified.h llpanelcontents.h + llpaneleditsky.h + llpaneleditwater.h llpaneleditwearable.h + llpanelenvironment.h llpanelexperiencelisteditor.h llpanelexperiencelog.h llpanelexperiencepicker.h @@ -1059,6 +1080,7 @@ set(viewer_HEADER_FILES llpanelface.h llpanelgenerictip.h llpanelgroup.h + llpanelgroupcreate.h llpanelgroupbulk.h llpanelgroupbulkimpl.h llpanelgroupbulkban.h @@ -1098,12 +1120,14 @@ set(viewer_HEADER_FILES llpanelplaceprofile.h llpanelplaces.h llpanelplacestab.h + llpanelpresetscamerapulldown.h llpanelpresetspulldown.h llpanelprimmediacontrols.h llpanelprofile.h llpanelsnapshot.h llpanelteleporthistory.h llpaneltiptoast.h + llpanelpulldown.h llpanelvoicedevicesettings.h llpanelvoiceeffect.h llpaneltopinfobar.h @@ -1166,6 +1190,9 @@ set(viewer_HEADER_FILES llsecapi.h llsechandler_basic.h llselectmgr.h + llsetkeybinddialog.h + llsettingspicker.h + llsettingsvo.h llsidepanelappearance.h llsidepanelinventory.h llsidepanelinventorysubpanel.h @@ -1231,10 +1258,10 @@ set(viewer_HEADER_FILES lltoolselectland.h lltoolselectrect.h lltracker.h + lltrackpicker.h lltransientdockablefloater.h lltransientfloatermgr.h lltranslate.h - lltwitterconnect.h lluiconstants.h lluiavatar.h lluilistener.h @@ -1243,6 +1270,7 @@ set(viewer_HEADER_FILES llurl.h llurldispatcher.h llurldispatcherlistener.h + llurlfloaterdispatchhandler.h llurlhistory.h llurllineeditorctrl.h llurlwhitelist.h @@ -1271,7 +1299,7 @@ set(viewer_HEADER_FILES llviewerjointattachment.h llviewerjointmesh.h llviewerjoystick.h - llviewerkeyboard.h + llviewerinput.h llviewerlayer.h llviewermedia.h llviewermediafocus.h @@ -1283,6 +1311,7 @@ set(viewer_HEADER_FILES llviewerobject.h llviewerobjectlist.h llvieweroctree.h + llviewerparcelaskplay.h llviewerparcelmedia.h llviewerparcelmediaautoplay.h llviewerparcelmgr.h @@ -1323,19 +1352,13 @@ set(viewer_HEADER_FILES llvowater.h llvowlsky.h llwatchdog.h - llwaterparammanager.h - llwaterparamset.h llwearableitemslist.h llwearablelist.h llweb.h llwebprofile.h llwind.h llwindowlistener.h - llwlanimator.h - llwldaycycle.h llwlhandlers.h - llwlparammanager.h - llwlparamset.h llworld.h llworldmap.h llworldmapmessage.h @@ -1378,8 +1401,12 @@ if (DARWIN) PROPERTIES COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}" # BugsplatMac is a module, imported with @import. That language feature - # demands these switches. - COMPILE_FLAGS "-fmodules -fcxx-modules" + # demands these -f switches. + # Xcode 10.2 requires that Objective-C++ headers declare nullability of + # pointer variables. As of 2019-06-26, the BugsplatMac version we're using + # does not yet do so in its own header files. This -W flag prevents fatal + # warnings. + COMPILE_FLAGS "-fmodules -fcxx-modules -Wno-nullability-completeness" ) find_library(AGL_LIBRARY AGL) @@ -1395,11 +1422,11 @@ if (DARWIN) ${COREAUDIO_LIBRARY} ) - if (BUGSPLAT_DB) + if (USE_BUGSPLAT) list(APPEND viewer_LIBRARIES ${BUGSPLAT_LIBRARIES} ) - endif (BUGSPLAT_DB) + endif (USE_BUGSPLAT) # Add resource files to the project. set(viewer_RESOURCE_FILES @@ -1577,20 +1604,12 @@ if (WINDOWS) list(APPEND viewer_SOURCE_FILES ${viewer_RESOURCE_FILES}) endif (NOT USESYSTEMLIBS) - 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 ${WINDOWS_LIBRARIES} comdlg32 - ${DINPUT_LIBRARY} - ${DXGUID_LIBRARY} + dxguid kernel32 odbc32 odbccp32 @@ -1621,6 +1640,10 @@ if (WINDOWS) # causes those systems to run in a Windows 8 compatibility mode, which works. LIST(APPEND viewer_SOURCE_FILES windows.manifest) endif (ADDRESS_SIZE EQUAL 64) + + if (OPENAL) + LIST(APPEND viewer_LIBRARIES ${OPENAL_LIBRARIES}) + endif (OPENAL) endif (WINDOWS) # Add the xui files. This is handy for searching for xui elements @@ -1659,7 +1682,7 @@ set(viewer_APPSETTINGS_FILES app_settings/grass.xml app_settings/high_graphics.xml app_settings/ignorable_dialogs.xml - app_settings/keys.xml + app_settings/key_bindings.xml app_settings/keywords_lsl_default.xml app_settings/logcontrol.xml app_settings/low_graphics.xml @@ -1716,13 +1739,20 @@ if (OPENAL) set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_OPENAL") endif (OPENAL) -if (FMODEX) - set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX") - set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY}) -endif (FMODEX) +if (FMODSTUDIO) + set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODSTUDIO") + set(FMODWRAPPER_LIBRARY ${FMODSTUDIO_LIBRARY}) +endif (FMODSTUDIO) set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") +if (HAVOK OR HAVOK_TPV) + set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_HAVOK") +endif (HAVOK OR HAVOK_TPV) + +# progress view disables/enables icons based on available packages +set_source_files_properties(llprogressview.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") + list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES}) set_source_files_properties(${viewer_HEADER_FILES} @@ -1740,10 +1770,10 @@ if (SDL_FOUND) ) endif (SDL_FOUND) -if (BUGSPLAT_DB) +if (USE_BUGSPLAT) set_property(TARGET ${VIEWER_BINARY_NAME} - PROPERTY COMPILE_DEFINITIONS "LL_BUGSPLAT") -endif (BUGSPLAT_DB) + PROPERTY COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}") +endif (USE_BUGSPLAT) # add package files file(GLOB EVENT_HOST_SCRIPT_GLOB_LIST @@ -1776,6 +1806,11 @@ if (WINDOWS) # 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. + # nat: https://cmake.org/cmake/help/v3.14/command/file.html + # "For example, the code + # file(STRINGS myfile.txt myfile) + # stores a list in the variable myfile in which each item is a line from the input file." + # And of course it's straightforward to read a text file in Python. set(COPY_INPUT_DEPENDENCIES # The following commented dependencies are determined at variably at build time. Can't do this here. @@ -1794,15 +1829,11 @@ if (WINDOWS) ${SHARED_LIB_STAGING_DIR}/Release/openjpeg.dll ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/openjpeg.dll ${SHARED_LIB_STAGING_DIR}/Debug/openjpegd.dll - ${SHARED_LIB_STAGING_DIR}/Release/msvcr100.dll - ${SHARED_LIB_STAGING_DIR}/Release/msvcp100.dll - ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/msvcr100.dll - ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/msvcp100.dll - ${SHARED_LIB_STAGING_DIR}/Debug/msvcr100d.dll - ${SHARED_LIB_STAGING_DIR}/Debug/msvcp100d.dll ${SHARED_LIB_STAGING_DIR}/Release/libhunspell.dll ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libhunspell.dll ${SHARED_LIB_STAGING_DIR}/Debug/libhunspell.dll + ${SHARED_LIB_STAGING_DIR}/Release/uriparser.dll + ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/uriparser.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/SLVoice.exe ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libsndfile-1.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxoal.dll @@ -1811,38 +1842,48 @@ if (WINDOWS) ${CMAKE_CURRENT_SOURCE_DIR}/licenses-win32.txt ${CMAKE_CURRENT_SOURCE_DIR}/featuretable.txt ${CMAKE_CURRENT_SOURCE_DIR}/featuretable_xp.txt - ${ARCH_PREBUILT_DIRS_RELEASE}/libeay32.dll - ${ARCH_PREBUILT_DIRS_RELEASE}/ssleay32.dll - ${ARCH_PREBUILT_DIRS_DEBUG}/libeay32.dll - ${ARCH_PREBUILT_DIRS_DEBUG}/ssleay32.dll ${viewer_APPSETTINGS_FILES} SLPlugin media_plugin_cef media_plugin_libvlc media_plugin_example winmm_shim - windows-crash-logger ) + if (NOT USE_BUGSPLAT) + LIST(APPEND COPY_INPUT_DEPENDENCIES windows-crash-logger) + endif (NOT USE_BUGSPLAT) + if (ADDRESS_SIZE EQUAL 64) list(APPEND COPY_INPUT_DEPENDENCIES ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk_x64.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/ortp_x64.dll + ${ARCH_PREBUILT_DIRS_RELEASE}/libcrypto-1_1-x64.dll + ${ARCH_PREBUILT_DIRS_RELEASE}/libssl-1_1-x64.dll ) else (ADDRESS_SIZE EQUAL 64) list(APPEND COPY_INPUT_DEPENDENCIES ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/ortp.dll + ${ARCH_PREBUILT_DIRS_RELEASE}/libcrypto-1_1.dll + ${ARCH_PREBUILT_DIRS_RELEASE}/libssl-1_1.dll ) endif (ADDRESS_SIZE EQUAL 64) - if (FMODEX) + if (FMODSTUDIO) + list(APPEND COPY_INPUT_DEPENDENCIES + ${SHARED_LIB_STAGING_DIR}/Release/fmod.dll + ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmod.dll + ${SHARED_LIB_STAGING_DIR}/Debug/fmodL.dll + ) + endif (FMODSTUDIO) + + if (OPENAL) list(APPEND COPY_INPUT_DEPENDENCIES - ${SHARED_LIB_STAGING_DIR}/Release/fmodex.dll - ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmodex.dll - ${SHARED_LIB_STAGING_DIR}/Debug/fmodexL.dll + ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/OpenAL32.dll + ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/alut.dll ) - endif (FMODEX) + endif (OPENAL) add_custom_command( OUTPUT ${CMAKE_CFG_INTDIR}/copy_touched.bat @@ -1853,6 +1894,8 @@ if (WINDOWS) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodstudio=${FMODSTUDIO}" + "--openal=${OPENAL}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" @@ -1879,7 +1922,6 @@ if (WINDOWS) add_dependencies(${VIEWER_BINARY_NAME} SLPlugin - windows-crash-logger ) # sets the 'working directory' for debugging from visual studio. @@ -1914,6 +1956,8 @@ if (WINDOWS) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodstudio=${FMODSTUDIO}" + "--openal=${OPENAL}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" @@ -1981,6 +2025,7 @@ endif (WINDOWS) # modern version. target_link_libraries(${VIEWER_BINARY_NAME} + ${LEGACY_STDIO_LIBS} ${PNG_PRELOAD_ARCHIVES} ${ZLIB_PRELOAD_ARCHIVES} ${URIPARSER_PRELOAD_ARCHIVES} @@ -2008,7 +2053,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${viewer_LIBRARIES} ${BOOST_PROGRAM_OPTIONS_LIBRARY} ${BOOST_REGEX_LIBRARY} - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${DBUSGLIB_LIBRARIES} ${OPENGL_LIBRARIES} @@ -2030,11 +2075,11 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLAPPEARANCE_LIBRARIES} ) -if (BUGSPLAT_DB) +if (USE_BUGSPLAT) target_link_libraries(${VIEWER_BINARY_NAME} ${BUGSPLAT_LIBRARIES} ) -endif (BUGSPLAT_DB) +endif (USE_BUGSPLAT) set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH "Path to artwork files.") @@ -2045,13 +2090,16 @@ if (LINUX) # These are the generated targets that are copied to package/ set(COPY_INPUT_DEPENDENCIES ${VIEWER_BINARY_NAME} - linux-crash-logger SLPlugin media_plugin_gstreamer010 media_plugin_libvlc llcommon ) + if (NOT USE_BUGSPLAT) + LIST(APPEND COPY_INPUT_DEPENDENCIES linux-crash-logger) + endif (NOT USE_BUGSPLAT) + add_custom_command( OUTPUT ${product}.tar.bz2 COMMAND ${PYTHON_EXECUTABLE} @@ -2060,6 +2108,8 @@ if (LINUX) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodstudio=${FMODSTUDIO}" + "--openal=${OPENAL}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" @@ -2086,6 +2136,8 @@ if (LINUX) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodstudio=${FMODSTUDIO}" + "--openal=${OPENAL}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" @@ -2123,7 +2175,7 @@ if (DARWIN) set(MACOSX_BUNDLE_BUNDLE_NAME "SecondLife") set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}") set(MACOSX_BUNDLE_BUNDLE_VERSION "${VIEWER_SHORT_VERSION}${VIEWER_MACOSX_PHASE}${VIEWER_REVISION}") - set(MACOSX_BUNDLE_COPYRIGHT "Copyright © Linden Research, Inc. 2018") + set(MACOSX_BUNDLE_COPYRIGHT "Copyright © Linden Research, Inc. 2020") set(MACOSX_BUNDLE_NSMAIN_NIB_FILE "SecondLife.nib") set(MACOSX_BUNDLE_NSPRINCIPAL_CLASS "LLApplication") @@ -2162,6 +2214,8 @@ if (DARWIN) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodstudio=${FMODSTUDIO}" + "--openal=${OPENAL}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} --bundleid=${MACOSX_BUNDLE_GUI_IDENTIFIER} @@ -2176,8 +2230,7 @@ if (DARWIN) ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) - add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_libvlc media_plugin_cef mac-crash-logger) - add_dependencies(${VIEWER_BINARY_NAME} mac-crash-logger) + add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_libvlc media_plugin_cef) if (ENABLE_SIGNING) set(SIGNING_SETTING "--signature=${SIGNING_IDENTITY}") @@ -2196,6 +2249,8 @@ if (DARWIN) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodstudio=${FMODSTUDIO}" + "--openal=${OPENAL}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" @@ -2218,62 +2273,7 @@ endif (INSTALL) # Note that the conventional VIEWER_SYMBOL_FILE is set by ../../build.sh if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIEWER_SYMBOL_FILE) - if (NOT BUGSPLAT_DB) - # Breakpad symbol-file generation - set(SYMBOL_SEARCH_DIRS "") - if (WINDOWS) - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") - # 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}/mac_crash_logger/${CMAKE_CFG_INTDIR}") - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/gstreamer010/${CMAKE_CFG_INTDIR}") - set(VIEWER_EXE_GLOBS "'${product}' SLPlugin mac-crash-logger") - set(VIEWER_EXE_GLOBS "'${product}' mac-crash-logger") - set(VIEWER_LIB_GLOB "*.dylib") - endif (DARWIN) - if (LINUX) - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/packaged") - set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin SLPlugin") - set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin") - set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}*") - set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest) - endif (LINUX) - - if(CMAKE_CFG_INTDIR STREQUAL ".") - set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE}) - else(CMAKE_CFG_INTDIR STREQUAL ".") - # 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(CMAKE_CFG_INTDIR STREQUAL ".") - 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) - - else (NOT BUGSPLAT_DB) + if (BUGSPLAT_DB) # BugSplat symbol-file generation if (WINDOWS) # Just pack up a tarball containing only the .pdb file for the @@ -2357,9 +2357,9 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE if (LINUX) # TBD endif (LINUX) - endif (NOT BUGSPLAT_DB) + endif (BUGSPLAT_DB) - # for both BUGSPLAT_DB and Breakpad + # for both Bugsplat and Breakpad add_dependencies(llpackage generate_symbols) endif () @@ -2438,6 +2438,7 @@ if (LL_TESTS) set_source_files_properties( lllogininstance.cpp PROPERTIES + LL_TEST_ADDITIONAL_SOURCE_FILES llversioninfo.cpp LL_TEST_ADDITIONAL_LIBRARIES "${BOOST_SYSTEM_LIBRARY}" ) @@ -2487,10 +2488,14 @@ if (LL_TESTS) ${OPENSSL_LIBRARIES} ${CRYPTO_LIBRARIES} ${LIBRT_LIBRARY} - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ) + LL_ADD_INTEGRATION_TEST(cppfeatures + "" + "${test_libs}" + ) LL_ADD_INTEGRATION_TEST(llsechandler_basic llsechandler_basic.cpp "${test_libs}" @@ -2532,7 +2537,6 @@ if (LL_TESTS) include(LLAddBuildTest) SET(viewer_TEST_SOURCE_FILES llagentaccess.cpp - llwlparammanager.cpp ) set_source_files_properties( ${viewer_TEST_SOURCE_FILES} diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 91e4a9f262..4c8366c864 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -6.3.2 +6.4.23 diff --git a/indra/newview/app_settings/camera/Front.xml b/indra/newview/app_settings/camera/Front.xml new file mode 100644 index 0000000000..39f44e11a8 --- /dev/null +++ b/indra/newview/app_settings/camera/Front.xml @@ -0,0 +1,142 @@ +<llsd> + <map> + <key>AppearanceCameraMovement</key> + <map> + <key>Comment</key> + <string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>AvatarSitRotation</key> + <map> + <key>Comment</key> + <string>Avatar real sitting rotation used in preset</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>LLSD</string> + <key>Value</key> + <array> + <real>0</real> + <real>0</real> + <real>0</real> + <real>1</real> + </array> + </map> + <key>CameraAngle</key> + <map> + <key>Comment</key> + <string>Camera field of view angle (Radians)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>1.047197551</real> + </map> + <key>CameraOffsetBuild</key> + <map> + <key>Comment</key> + <string>Default camera position relative to focus point when entering build mode</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Vector3</string> + <key>Value</key> + <array> + <real>-6</real> + <real>0</real> + <real>6</real> + </array> + </map> + <key>CameraOffsetRearView</key> + <map> + <key>Comment</key> + <string>Initial camera offset from avatar in Front View</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Vector3</string> + <key>Value</key> + <array> + <real>2.2</real> + <real>0.0</real> + <real>0.0</real> + </array> + </map> + <key>CameraOffsetScale</key> + <map> + <key>Comment</key> + <string>Scales the default offset</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>1</real> + </map> + <key>CameraZoomFraction</key> + <map> + <key>Comment</key> + <string>Mousewheel driven fraction of zoom</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>0.90322577953338623</real> + </map> + <key>EditCameraMovement</key> + <map> + <key>Comment</key> + <string>When entering build mode, camera moves up above avatar</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>FocusOffsetRearView</key> + <map> + <key>Comment</key> + <string>Initial focus point offset relative to avatar for the camera preset Front View (x-axis is forward)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Vector3D</string> + <key>Value</key> + <array> + <real>0.0</real> + <real>0.0</real> + <real>0.0</real> + </array> + </map> + <key>PresetCameraActive</key> + <map> + <key>Comment</key> + <string>Name of currently selected preference</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>Default</string> + </map> + <key>TrackFocusObject</key> + <map> + <key>Comment</key> + <string>Camera tracks last object zoomed on</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + </map> +</llsd> diff --git a/indra/newview/app_settings/camera/Rear.xml b/indra/newview/app_settings/camera/Rear.xml new file mode 100644 index 0000000000..8dc36353ce --- /dev/null +++ b/indra/newview/app_settings/camera/Rear.xml @@ -0,0 +1,142 @@ +<llsd> + <map> + <key>AppearanceCameraMovement</key> + <map> + <key>Comment</key> + <string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>AvatarSitRotation</key> + <map> + <key>Comment</key> + <string>Avatar real sitting rotation used in preset</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>LLSD</string> + <key>Value</key> + <array> + <real>0</real> + <real>0</real> + <real>0</real> + <real>1</real> + </array> + </map> + <key>CameraAngle</key> + <map> + <key>Comment</key> + <string>Camera field of view angle (Radians)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>1.047197551</real> + </map> + <key>CameraOffsetBuild</key> + <map> + <key>Comment</key> + <string>Default camera position relative to focus point when entering build mode</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Vector3</string> + <key>Value</key> + <array> + <real>-6</real> + <real>0</real> + <real>6</real> + </array> + </map> + <key>CameraOffsetRearView</key> + <map> + <key>Comment</key> + <string>Initial camera offset from avatar in Rear View</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Vector3</string> + <key>Value</key> + <array> + <real>-3</real> + <real>0</real> + <real>0.75</real> + </array> + </map> + <key>CameraOffsetScale</key> + <map> + <key>Comment</key> + <string>Scales the default offset</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>1</real> + </map> + <key>CameraZoomFraction</key> + <map> + <key>Comment</key> + <string>Mousewheel driven fraction of zoom</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>0.90322577953338623</real> + </map> + <key>EditCameraMovement</key> + <map> + <key>Comment</key> + <string>When entering build mode, camera moves up above avatar</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>FocusOffsetRearView</key> + <map> + <key>Comment</key> + <string>Initial focus point offset relative to avatar for the camera preset Rear View (x-axis is forward)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Vector3D</string> + <key>Value</key> + <array> + <real>1.0</real> + <real>0.0</real> + <real>1.0</real> + </array> + </map> + <key>PresetCameraActive</key> + <map> + <key>Comment</key> + <string>Name of currently selected preference</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>Default</string> + </map> + <key>TrackFocusObject</key> + <map> + <key>Comment</key> + <string>Camera tracks last object zoomed on</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + </map> +</llsd> diff --git a/indra/newview/app_settings/camera/Side.xml b/indra/newview/app_settings/camera/Side.xml new file mode 100644 index 0000000000..089ab93a8f --- /dev/null +++ b/indra/newview/app_settings/camera/Side.xml @@ -0,0 +1,142 @@ +<llsd> + <map> + <key>AppearanceCameraMovement</key> + <map> + <key>Comment</key> + <string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>AvatarSitRotation</key> + <map> + <key>Comment</key> + <string>Avatar real sitting rotation used in preset</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>LLSD</string> + <key>Value</key> + <array> + <real>0</real> + <real>0</real> + <real>0</real> + <real>1</real> + </array> + </map> + <key>CameraAngle</key> + <map> + <key>Comment</key> + <string>Camera field of view angle (Radians)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>1.047197551</real> + </map> + <key>CameraOffsetBuild</key> + <map> + <key>Comment</key> + <string>Default camera position relative to focus point when entering build mode</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Vector3</string> + <key>Value</key> + <array> + <real>-6</real> + <real>0</real> + <real>6</real> + </array> + </map> + <key>CameraOffsetRearView</key> + <map> + <key>Comment</key> + <string>Initial camera offset from avatar in Side View</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Vector3</string> + <key>Value</key> + <array> + <real>-1.0</real> + <real>0.7</real> + <real>0.5</real> + </array> + </map> + <key>CameraOffsetScale</key> + <map> + <key>Comment</key> + <string>Scales the default offset</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>1</real> + </map> + <key>CameraZoomFraction</key> + <map> + <key>Comment</key> + <string>Mousewheel driven fraction of zoom</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>0.90322577953338623</real> + </map> + <key>EditCameraMovement</key> + <map> + <key>Comment</key> + <string>When entering build mode, camera moves up above avatar</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>FocusOffsetRearView</key> + <map> + <key>Comment</key> + <string>Initial focus point offset relative to avatar for the camera preset Side View (x-axis is forward)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Vector3D</string> + <key>Value</key> + <array> + <real>1.5</real> + <real>0.7</real> + <real>1.0</real> + </array> + </map> + <key>PresetCameraActive</key> + <map> + <key>Comment</key> + <string>Name of currently selected preference</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>Default</string> + </map> + <key>TrackFocusObject</key> + <map> + <key>Comment</key> + <string>Camera tracks last object zoomed on</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + </map> +</llsd> diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml index e4e1cdcf44..4e186292f7 100644 --- a/indra/newview/app_settings/cmd_line.xml +++ b/indra/newview/app_settings/cmd_line.xml @@ -407,5 +407,14 @@ <integer>1</integer> <!-- Special case. Mapped to settings procedurally. --> </map> + + <key>skipupdatecheck</key> + <map> + <key>desc</key> + <string>Skips update check at startup.</string> + <key>map-to</key> + <string>CmdLineSkipUpdater</string> + </map> + </map> </llsd> diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index cab0c523b2..d0480ca47e 100644 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -88,8 +88,10 @@ icon="Command_HowTo_Icon" label_ref="Command_HowTo_Label" tooltip_ref="Command_HowTo_Tooltip" - execute_function="Help.ToggleHowTo" - is_running_function="Help.HowToVisible" + execute_function="Floater.ToggleOrBringToFront" + execute_parameters="guidebook" + is_running_function="Floater.IsOpen" + is_running_parameters="guidebook" /> <command name="inventory" available_in_toybox="true" @@ -150,16 +152,6 @@ is_running_function="Floater.IsOpen" is_running_parameters="moveview" /> - <command name="outbox" - available_in_toybox="false" - icon="Command_Outbox_Icon" - label_ref="Command_Outbox_Label" - tooltip_ref="Command_Outbox_Tooltip" - execute_function="Floater.ToggleOrBringToFront" - execute_parameters="outbox" - is_running_function="Floater.IsOpen" - is_running_parameters="outbox" - /> <command name="people" available_in_toybox="true" icon="Command_People_Icon" @@ -228,26 +220,6 @@ is_running_function="Floater.IsOpen" is_running_parameters="snapshot" /> - <command name="flickr" - available_in_toybox="true" - icon="Command_Flickr_Icon" - label_ref="Command_Flickr_Label" - tooltip_ref="Command_Flickr_Tooltip" - execute_function="Floater.ToggleOrBringToFront" - execute_parameters="flickr" - is_running_function="Floater.IsOpen" - is_running_parameters="flickr" - /> - <command name="twitter" - available_in_toybox="true" - icon="Command_Twitter_Icon" - label_ref="Command_Twitter_Label" - tooltip_ref="Command_Twitter_Tooltip" - execute_function="Floater.ToggleOrBringToFront" - execute_parameters="twitter" - is_running_function="Floater.IsOpen" - is_running_parameters="twitter" - /> <command name="speak" available_in_toybox="true" icon="Command_Speak_Icon" @@ -293,4 +265,15 @@ is_running_function="Floater.IsOpen" is_running_parameters="grid_status" /> + <command name="myenvironments" + available_in_toybox="true" + is_flashing_allowed="true" + icon="Command_Environments_Icon" + label_ref="Command_Environments_Label" + tooltip_ref="Command_Environments_Tooltip" + execute_function="Floater.ToggleOrBringToFront" + execute_parameters="my_environments" + is_running_function="Floater.IsOpen" + is_running_parameters="my_environments" + /> </commands> diff --git a/indra/newview/app_settings/high_graphics.xml b/indra/newview/app_settings/high_graphics.xml index c38b3fcda4..662f7e39dd 100644 --- a/indra/newview/app_settings/high_graphics.xml +++ b/indra/newview/app_settings/high_graphics.xml @@ -33,8 +33,6 @@ <!--Default for now--> <RenderVolumeLODFactor value="1.125"/> <!--NO SHADERS--> - <VertexShaderEnable value="TRUE"/> - <!--NO SHADERS--> <WindLightUseAtmosShaders value="TRUE"/> <!--Deferred Shading--> <RenderDeferred value="FALSE"/> diff --git a/indra/newview/app_settings/keys.xml b/indra/newview/app_settings/key_bindings.xml index a8037fec05..4f6deb1f98 100644 --- a/indra/newview/app_settings/keys.xml +++ b/indra/newview/app_settings/key_bindings.xml @@ -28,34 +28,11 @@ <binding key="PAD_ENTER" mask="NONE" command="start_chat"/> <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/> - <binding key="A" mask="SHIFT" command="slide_left"/> - <binding key="D" mask="SHIFT" command="slide_right"/> - <binding key="W" mask="SHIFT" command="push_forward"/> - <binding key="S" mask="SHIFT" command="push_backward"/> - <binding key="E" mask="SHIFT" command="jump"/> - <binding key="C" mask="SHIFT" command="push_down"/> - <binding key="F" mask="SHIFT" command="toggle_fly"/> - <binding key="SPACE" mask="NONE" command="stop_moving"/> <binding key="ENTER" mask="NONE" command="start_chat"/> <binding key="DIVIDE" mask="NONE" command="start_gesture"/> - <binding key="LEFT" mask="SHIFT" command="slide_left"/> - <binding key="RIGHT" mask="SHIFT" command="slide_right"/> - <binding key="UP" mask="SHIFT" command="push_forward"/> - <binding key="DOWN" mask="SHIFT" command="push_backward"/> - <binding key="PGUP" mask="SHIFT" command="jump"/> - <binding key="PGDN" mask="SHIFT" command="push_down"/> - - <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/> - <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/> - <binding key="PAD_UP" mask="SHIFT" command="push_forward"/> - <binding key="PAD_DOWN" mask="SHIFT" command="push_backward"/> - <binding key="PAD_PGUP" mask="SHIFT" command="jump"/> - <binding key="PAD_PGDN" mask="SHIFT" command="push_down"/> - <binding key="PAD_HOME" mask="SHIFT" command="toggle_fly"/> - <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/> - <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/> + <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/> </first_person> <third_person> <binding key="A" mask="NONE" command="turn_left"/> @@ -64,15 +41,10 @@ <binding key="D" mask="SHIFT" command="slide_right"/> <binding key="W" mask="NONE" command="push_forward"/> <binding key="S" mask="NONE" command="push_backward"/> - <binding key="W" mask="SHIFT" command="push_forward"/> - <binding key="S" mask="SHIFT" command="push_backward"/> <binding key="E" mask="NONE" command="jump"/> <binding key="C" mask="NONE" command="push_down"/> - <binding key="E" mask="SHIFT" command="jump"/> - <binding key="C" mask="SHIFT" command="push_down"/> <binding key="F" mask="NONE" command="toggle_fly"/> - <binding key="F" mask="SHIFT" command="toggle_fly"/> <binding key="SPACE" mask="NONE" command="stop_moving"/> <binding key="ENTER" mask="NONE" command="start_chat"/> @@ -84,13 +56,8 @@ <binding key="RIGHT" mask="SHIFT" command="slide_right"/> <binding key="UP" mask="NONE" command="push_forward"/> <binding key="DOWN" mask="NONE" command="push_backward"/> - <binding key="UP" mask="SHIFT" command="push_forward"/> - <binding key="DOWN" mask="SHIFT" command="push_backward"/> <binding key="PGUP" mask="NONE" command="jump"/> <binding key="PGDN" mask="NONE" command="push_down"/> - <binding key="PGUP" mask="SHIFT" command="jump"/> - <binding key="PGDN" mask="SHIFT" command="push_down"/> - <binding key="HOME" mask="SHIFT" command="toggle_fly"/> <binding key="HOME" mask="NONE" command="toggle_fly"/> <binding key="PAD_LEFT" mask="NONE" command="turn_left"/> @@ -99,20 +66,12 @@ <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/> <binding key="PAD_UP" mask="NONE" command="push_forward"/> <binding key="PAD_DOWN" mask="NONE" command="push_backward"/> - <binding key="PAD_UP" mask="SHIFT" command="push_forward"/> - <binding key="PAD_DOWN" mask="SHIFT" command="push_backward"/> <binding key="PAD_PGUP" mask="NONE" command="jump"/> <binding key="PAD_PGDN" mask="NONE" command="push_down"/> - <binding key="PAD_PGUP" mask="SHIFT" command="jump"/> - <binding key="PAD_PGDN" mask="SHIFT" command="push_down"/> <binding key="PAD_HOME" mask="NONE" command="toggle_fly"/> - <binding key="PAD_HOME" mask="SHIFT" command="toggle_fly"/> <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/> - <binding key="PAD_CENTER" mask="SHIFT" command="stop_moving"/> <binding key="PAD_ENTER" mask="NONE" command="start_chat"/> - <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/> <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/> - <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/> <!--Camera controls in third person on Alt--> <binding key="LEFT" mask="ALT" command="spin_around_cw"/> @@ -139,28 +98,14 @@ <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/> <!--mimic alt zoom behavior with keyboard only--> - <binding key="A" mask="CTL_ALT" command="spin_around_cw"/> - <binding key="D" mask="CTL_ALT" command="spin_around_ccw"/> <binding key="W" mask="CTL_ALT" command="spin_over"/> <binding key="S" mask="CTL_ALT" command="spin_under"/> - <binding key="E" mask="CTL_ALT" command="spin_over"/> - <binding key="C" mask="CTL_ALT" command="spin_under"/> - <binding key="LEFT" mask="CTL_ALT" command="spin_around_cw"/> - <binding key="RIGHT" mask="CTL_ALT" command="spin_around_ccw"/> <binding key="UP" mask="CTL_ALT" command="spin_over"/> <binding key="DOWN" mask="CTL_ALT" command="spin_under"/> - <binding key="PGUP" mask="CTL_ALT" command="spin_over"/> - <binding key="PGDN" mask="CTL_ALT" command="spin_under"/> - <binding key="PAD_LEFT" mask="CTL_ALT" command="spin_around_cw"/> - <binding key="PAD_RIGHT" mask="CTL_ALT" command="spin_around_ccw"/> <binding key="PAD_UP" mask="CTL_ALT" command="spin_over"/> <binding key="PAD_DOWN" mask="CTL_ALT" command="spin_under"/> - <binding key="PAD_PGUP" mask="CTL_ALT" command="spin_over"/> - <binding key="PAD_PGDN" mask="CTL_ALT" command="spin_under"/> - <binding key="PAD_ENTER" mask="CTL_ALT" command="start_chat"/> - <binding key="PAD_DIVIDE" mask="CTL_ALT" command="start_gesture"/> <!--Therefore pan on Alt-Shift--> <binding key="A" mask="CTL_ALT_SHIFT" command="pan_left"/> @@ -179,63 +124,10 @@ <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/> <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/> <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/> - </third_person> - <!-- Basic editing camera control --> - <edit> - <binding key="A" mask="NONE" command="spin_around_cw"/> - <binding key="D" mask="NONE" command="spin_around_ccw"/> - <binding key="W" mask="NONE" command="move_forward"/> - <binding key="S" mask="NONE" command="move_backward"/> - <binding key="E" mask="NONE" command="spin_over"/> - <binding key="C" mask="NONE" command="spin_under"/> - <binding key="ENTER" mask="NONE" command="start_chat"/> - <binding key="DIVIDE" mask="NONE" command="start_gesture"/> - <binding key="PAD_ENTER" mask="NONE" command="start_chat"/> - <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/> - - <binding key="LEFT" mask="NONE" command="spin_around_cw"/> - <binding key="RIGHT" mask="NONE" command="spin_around_ccw"/> - <binding key="UP" mask="NONE" command="move_forward"/> - <binding key="DOWN" mask="NONE" command="move_backward"/> - <binding key="PGUP" mask="NONE" command="spin_over"/> - <binding key="PGDN" mask="NONE" command="spin_under"/> - - <binding key="A" mask="SHIFT" command="pan_left"/> - <binding key="D" mask="SHIFT" command="pan_right"/> - <binding key="W" mask="SHIFT" command="pan_up"/> - <binding key="S" mask="SHIFT" command="pan_down"/> - - <binding key="LEFT" mask="SHIFT" command="pan_left"/> - <binding key="RIGHT" mask="SHIFT" command="pan_right"/> - <binding key="UP" mask="SHIFT" command="pan_up"/> - <binding key="DOWN" mask="SHIFT" command="pan_down"/> - - <!--Walking works with ALT held down.--> - <binding key="A" mask="ALT" command="slide_left"/> - <binding key="D" mask="ALT" command="slide_right"/> - <binding key="W" mask="ALT" command="push_forward"/> - <binding key="S" mask="ALT" command="push_backward"/> - <binding key="E" mask="ALT" command="jump"/> - <binding key="C" mask="ALT" command="push_down"/> - - <binding key="LEFT" mask="ALT" command="slide_left"/> - <binding key="RIGHT" mask="ALT" command="slide_right"/> - <binding key="UP" mask="ALT" command="push_forward"/> - <binding key="DOWN" mask="ALT" command="push_backward"/> - <binding key="PGUP" mask="ALT" command="jump"/> - <binding key="PGDN" mask="ALT" command="push_down"/> - <binding key="HOME" mask="ALT" command="toggle_fly"/> - - <binding key="PAD_LEFT" mask="ALT" command="slide_left"/> - <binding key="PAD_RIGHT" mask="ALT" command="slide_right"/> - <binding key="PAD_UP" mask="ALT" command="push_forward"/> - <binding key="PAD_DOWN" mask="ALT" command="push_backward"/> - <binding key="PAD_PGUP" mask="ALT" command="jump"/> - <binding key="PAD_PGDN" mask="ALT" command="push_down"/> - <binding key="PAD_ENTER" mask="ALT" command="start_chat"/> - <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/> - </edit> + <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/> + <binding key="" mask="NONE" mouse="LMB" command="walk_to"/> + </third_person> <sitting> <binding key="A" mask="ALT" command="spin_around_cw"/> <binding key="D" mask="ALT" command="spin_around_ccw"/> @@ -251,15 +143,11 @@ <binding key="PGUP" mask="ALT" command="spin_over"/> <binding key="PGDN" mask="ALT" command="spin_under"/> - <binding key="A" mask="CTL_ALT" command="spin_around_cw"/> - <binding key="D" mask="CTL_ALT" command="spin_around_ccw"/> <binding key="W" mask="CTL_ALT" command="spin_over"/> <binding key="S" mask="CTL_ALT" command="spin_under"/> <binding key="E" mask="CTL_ALT" command="spin_over"/> <binding key="C" mask="CTL_ALT" command="spin_under"/> - <binding key="LEFT" mask="CTL_ALT" command="spin_around_cw"/> - <binding key="RIGHT" mask="CTL_ALT" command="spin_around_ccw"/> <binding key="UP" mask="CTL_ALT" command="spin_over"/> <binding key="DOWN" mask="CTL_ALT" command="spin_under"/> <binding key="PGUP" mask="CTL_ALT" command="spin_over"/> @@ -294,23 +182,23 @@ <binding key="A" mask="SHIFT" command="slide_left"/> <binding key="D" mask="SHIFT" command="slide_right"/> <binding key="W" mask="SHIFT" command="move_forward_sitting"/> - <binding key="S" mask="SHIFT" command="move_backward_sitting"/> - <binding key="E" mask="SHIFT" command="spin_over_sitting"/> - <binding key="C" mask="SHIFT" command="spin_under_sitting"/> + <binding key="S" mask="SHIFT" command="move_backward_sitting"/> + <binding key="E" mask="SHIFT" command="spin_over_sitting"/> + <binding key="C" mask="SHIFT" command="spin_under_sitting"/> <binding key="LEFT" mask="SHIFT" command="slide_left"/> <binding key="RIGHT" mask="SHIFT" command="slide_right"/> <binding key="UP" mask="SHIFT" command="move_forward_sitting"/> - <binding key="DOWN" mask="SHIFT" command="move_backward_sitting"/> - <binding key="PGUP" mask="SHIFT" command="spin_over_sitting"/> - <binding key="PGDN" mask="SHIFT" command="spin_under_sitting"/> + <binding key="DOWN" mask="SHIFT" command="move_backward_sitting"/> + <binding key="PGUP" mask="SHIFT" command="spin_over_sitting"/> + <binding key="PGDN" mask="SHIFT" command="spin_under_sitting"/> <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/> <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/> <binding key="PAD_UP" mask="SHIFT" command="move_forward_sitting"/> - <binding key="PAD_DOWN" mask="SHIFT" command="move_backward_sitting"/> - <binding key="PAD_PGUP" mask="SHIFT" command="spin_over_sitting"/> - <binding key="PAD_PGDN" mask="SHIFT" command="spin_under_sitting"/> + <binding key="PAD_DOWN" mask="SHIFT" command="move_backward_sitting"/> + <binding key="PAD_PGUP" mask="SHIFT" command="spin_over_sitting"/> + <binding key="PAD_PGDN" mask="SHIFT" command="spin_under_sitting"/> <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/> <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/> @@ -334,6 +222,8 @@ <binding key="ENTER" mask="NONE" command="start_chat"/> <binding key="DIVIDE" mask="NONE" command="start_gesture"/> + + <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/> </sitting> <edit_avatar> <!--Avatar editing camera controls--> @@ -359,5 +249,7 @@ <binding key="PAD_PGDN" mask="NONE" command="edit_avatar_spin_under"/> <binding key="PAD_ENTER" mask="NONE" command="start_chat"/> <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/> + + <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/> </edit_avatar> -</keys>
\ No newline at end of file +</keys> diff --git a/indra/newview/app_settings/low_graphics.xml b/indra/newview/app_settings/low_graphics.xml index df3f67a5a1..0ee8e7a059 100644 --- a/indra/newview/app_settings/low_graphics.xml +++ b/indra/newview/app_settings/low_graphics.xml @@ -33,8 +33,6 @@ <!--Default for now--> <RenderVolumeLODFactor value="1.125"/> <!--NO SHADERS--> - <VertexShaderEnable value="FALSE"/> - <!--NO SHADERS--> <WindLightUseAtmosShaders value="FALSE"/> <!--No Deferred Shading--> <RenderDeferred value="FALSE"/> diff --git a/indra/newview/app_settings/mid_graphics.xml b/indra/newview/app_settings/mid_graphics.xml index a10c02b79f..c89e060307 100644 --- a/indra/newview/app_settings/mid_graphics.xml +++ b/indra/newview/app_settings/mid_graphics.xml @@ -33,8 +33,6 @@ <!--Default for now--> <RenderVolumeLODFactor value="1.125"/> <!--NO SHADERS--> - <VertexShaderEnable value="TRUE"/> - <!--NO SHADERS--> <WindLightUseAtmosShaders value="FALSE"/> <!--No Deferred Shading--> <RenderDeferred value="FALSE"/> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 49601ae98f..b1120c18b2 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1252,6 +1252,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>BulkChangeIncludeSettings</key> + <map> + <key>Comment</key> + <string>Bulk permission changes affect environment settings</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>BulkChangeEveryoneCopy</key> <map> <key>Comment</key> @@ -1499,6 +1510,21 @@ <real>0.5</real> </array> </map> + <key>CameraOffsetCustomPreset</key> + <map> + <key>Comment</key> + <string>Initial camera offset from avatar for the custom camera preset</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Vector3</string> + <key>Value</key> + <array> + <real>-3.0</real> + <real>0.0</real> + <real>0.75</real> + </array> + </map> <key>CameraOffsetScale</key> <map> <key>Comment</key> @@ -1510,6 +1536,17 @@ <key>Value</key> <real>1.0</real> </map> + <key>CameraZoomFraction</key> + <map> + <key>Comment</key> + <string>Mousewheel driven fraction of zoom</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>0.9</real> + </map> <key>CameraPosOnLogout</key> <map> <key>Comment</key> @@ -1547,7 +1584,7 @@ <key>Value</key> <real>1.0</real> </map> - <key>CameraPreset</key> + <key>CameraPreset</key> <!-- deprecated (see SL-12429) --> <map> <key>Comment</key> <string>Preset camera position - view (0 - rear, 1 - front, 2 - group)</string> @@ -1929,7 +1966,18 @@ <key>Value</key> <string/> </map> - <key>ConnectAsGod</key> + <key>CmdLineSkipUpdater</key> + <map> + <key>Comment</key> + <string>Command line skip updater check.</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>ConnectAsGod</key> <map> <key>Comment</key> <string>Log in a god if you have god access.</string> @@ -2028,17 +2076,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>BrowserPluginsEnabled</key> - <map> - <key>Comment</key> - <string>Enable Web plugins in the built-in Web browser?</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>ChatBarCustomWidth</key> <map> <key>Comment</key> @@ -3494,7 +3531,7 @@ <key>DoubleClickAutoPilot</key> <map> <key>Comment</key> - <string>Enable double-click auto pilot</string> + <string>(Obsolete)Enable double-click auto pilot</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -3502,10 +3539,10 @@ <key>Value</key> <integer>0</integer> </map> - <key>DoubleClickTeleport</key> + <key>DoubleClickTeleport</key> <map> <key>Comment</key> - <string>Enable double-click to teleport where allowed</string> + <string>Enable double-click to teleport where allowed (afects minimap and people panel)</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -4356,6 +4393,37 @@ <real>1.0</real> </array> </map> + <key>FocusOffsetCustomPreset</key> + <map> + <key>Comment</key> + <string>Initial focus point offset relative to avatar for the custom camera preset (x-axis is forward)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Vector3D</string> + <key>Value</key> + <array> + <real>1.0</real> + <real>0.0</real> + <real>1.0</real> + </array> + </map> + <key>AvatarSitRotation</key> + <map> + <key>Comment</key> + <string>Avatar real sitting rotation used in preset</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>LLSD</string> + <key>Value</key> + <array> + <real>0</real> + <real>0</real> + <real>0</real> + <real>1</real> + </array> + </map> <key>FocusPosOnLogout</key> <map> <key>Comment</key> @@ -4646,6 +4714,17 @@ <key>Value</key> <string>https://search.[GRID]/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]</string> </map> + <key>GuidebookURL</key> + <map> + <key>Comment</key> + <string>URL for Guidebook content</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>http://guidebooks.secondlife.io/welcome/index.html</string> + </map> <key>HighResSnapshot</key> <map> <key>Comment</key> @@ -4913,7 +4992,7 @@ <key>InventoryOutboxDisplayBoth</key> <map> <key>Comment</key> - <string>Show the legacy Merchant Outbox UI as well as the Marketplace Listings UI</string> + <string>(Deprecated) Show the legacy Merchant Outbox UI as well as the Marketplace Listings UI</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -5163,6 +5242,17 @@ <key>Value</key> <string /> </map> + <key>JoystickDeviceUUID</key> + <map> + <key>Comment</key> + <string>Preffered device ID.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string /> + </map> <key>JoystickMouselookYaw</key> <map> <key>Comment</key> @@ -5304,7 +5394,7 @@ <key>Type</key> <string>String</string> <key>Value</key> - <string>https://secondlife-status.statuspage.io/history.atom</string> + <string>https://status.secondlifegrid.net/history.atom</string> </map> <key>GridStatusUpdateDelay</key> <map> @@ -5845,7 +5935,7 @@ <key>Type</key> <string>String</string> <key>Value</key> - <string>http://map.secondlife.com.s3.amazonaws.com/</string> + <string>https://map.secondlife.com/</string> </map> <key>CurrentMapServerURL</key> <map> @@ -6496,7 +6586,7 @@ <key>Value</key> <integer>1</integer> </map> - <key>MemoryFailurePreventionEnabled</key> + <key>MemoryFailurePreventionEnabled</key> <!-- deprecated, only used for obsolete-in-2020 Intel 965 Express GPU --> <map> <key>Comment</key> <string>If set, the viewer will quit to avoid crash when memory failure happens</string> @@ -6640,7 +6730,7 @@ <integer>600</integer> </map> <key>MigrateCacheDirectory</key> - <map> + <map> <key>Comment</key> <string>Check for old version of disk cache to migrate to current location</string> <key>Persist</key> @@ -6716,6 +6806,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>MouseMoon</key> + <map> + <key>Comment</key> + <string /> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>MuteAmbient</key> <map> <key>Comment</key> @@ -7494,11 +7595,11 @@ <key>ParcelMediaAutoPlayEnable</key> <map> <key>Comment</key> - <string>Auto play parcel media when available</string> + <string>Auto play parcel media when available. 0 - Do not autoplay; 1- Autoplay; 2 - Ask</string> <key>Persist</key> <integer>1</integer> <key>Type</key> - <string>Boolean</string> + <string>S32</string> <key>Value</key> <integer>1</integer> </map> @@ -7879,7 +7980,6 @@ <key>Value</key> <integer>13</integer> </map> - <key>PreviewAmbientColor</key> <map> <key>Comment</key> @@ -7896,8 +7996,6 @@ <real>1.0</real> </array> </map> - - <key>PreviewDiffuse0</key> <map> <key>Comment</key> @@ -8184,7 +8282,7 @@ <key>PushToTalkButton</key> <map> <key>Comment</key> - <string>Which button or keyboard key is used for push-to-talk</string> + <string>(Obsolete)Which button or keyboard key is used for push-to-talk</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -8344,7 +8442,7 @@ <key>Type</key> <string>F32</string> <key>Value</key> - <real>0.125</real> + <real>0.02</real> </map> <key>MediaRollOffMin</key> <map> @@ -8355,7 +8453,7 @@ <key>Type</key> <string>F32</string> <key>Value</key> - <real>10.0</real> + <real>40.0</real> </map> <key>MediaRollOffMax</key> <map> @@ -8366,7 +8464,7 @@ <key>Type</key> <string>F32</string> <key>Value</key> - <real>30.0</real> + <real>80.0</real> </map> <key>RecentItemsSortOrder</key> <map> @@ -8434,6 +8532,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>RememberUser</key> + <map> + <key>Comment</key> + <string>Keep user name for next login</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>RememberPassword</key> <map> <key>Comment</key> @@ -8525,6 +8634,28 @@ </array> </map> + <key>RenderAlphaBatchFullbrights</key> + <map> + <key>Comment</key> + <string>Render fullbright alpha content more efficiently, but with possible visual differences from prev viewers.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>RenderAlphaBatchEmissives</key> + <map> + <key>Comment</key> + <string>Render emissive alpha content more efficiently, but with possible visual differences from prev viewers.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>RenderAnisotropic</key> <map> <key>Comment</key> @@ -8982,7 +9113,7 @@ <key>Type</key> <string>F32</string> <key>Value</key> - <real>0.03</real> + <real>0.1</real> </map> <key>RenderDebugPipeline</key> <map> @@ -9154,7 +9285,7 @@ <key>Type</key> <string>F32</string> <key>Value</key> - <real>-0.008</real> + <real>-0.004</real> </map> <key>RenderShadowOffset</key> <map> @@ -9276,7 +9407,7 @@ <key>RenderShadowResolutionScale</key> <map> <key>Comment</key> - <string>Scale of shadow map resolution vs. screen resolution</string> + <string>Scale of shadow map resolution vs. screen resolution (only positivie values are allowed)</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -10255,6 +10386,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>RenderUseAdvancedAtmospherics</key> + <map> + <key>Comment</key> + <string>Use fancy precomputed atmospherics and stuff.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>RenderUseTriStrips</key> <map> <key>Comment</key> @@ -11219,6 +11361,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>BasicUITooltips</key> + <map> + <key>Comment</key> + <string>Show tooltips for various 2D UI elements like buttons or checkboxes, won't supress tooltips like drag'n'drop, inworld, links or media</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>ShowHoverTips</key> <map> <key>Comment</key> @@ -11959,6 +12112,21 @@ <key>Value</key> <real>0.300000011921</real> </map> + <key>SkyMoonDefaultPosition</key> + <map> + <key>Comment</key> + <string>Default position of sun in sky (direction in world coordinates)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Vector3</string> + <key>Value</key> + <array> + <real>-1.0</real> + <real>0.0</real> + <real>-0.1</real> + </array> + </map> <key>SkyNightColorShift</key> <map> <key>Comment</key> @@ -12275,6 +12443,39 @@ <key>Value</key> <integer>0</integer> </map> + <key>AmbientDisable</key> + <map> + <key>Comment</key> + <string>If TRUE, ambient light has no effect</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>SunlightDisable</key> + <map> + <key>Comment</key> + <string>If TRUE, sunlight has no effect</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>LocalLightDisable</key> + <map> + <key>Comment</key> + <string>If TRUE, local lights have no effect</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>TextureDiscardLevel</key> <map> <key>Comment</key> @@ -13133,6 +13334,17 @@ <key>Value</key> <real>3</real> </map> + <key>HUDScaleFactor</key> + <map> + <key>Comment</key> + <string>Scale of HUD attachments</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>1.0</real> + </map> <key>UIScaleFactor</key> <map> <key>Comment</key> @@ -14112,17 +14324,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>VertexShaderEnable</key> - <map> - <key>Comment</key> - <string>Enable/disable all GLSL shaders (debug)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>VivoxAutoPostCrashDumps</key> <map> <key>Comment</key> @@ -14211,10 +14412,55 @@ <key>Value</key> <integer>44125</integer> </map> - <key>VoiceCallsFriendsOnly</key> + + <key>VivoxVadAuto</key> + <map> + <key>Comment</key> + <string>A flag indicating if the automatic VAD is enabled (1) or disabled (0). The individual settings are ignored if the auto-mode is enabled</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>VivoxVadHangover</key> + <map> + <key>Comment</key> + <string>The time (in milliseconds) that it takes or the VAD to switch back to silence from speech mode after the last speech frame has been detected</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>2000</integer> + </map> + <key>VivoxVadNoiseFloor</key> + <map> + <key>Comment</key> + <string>A dimensionless value between 0 and 20000 (default 576) that controls the maximum level at which the noise floor may be set at by the VAD's noise tracking</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>576</integer> + </map> + <key>VivoxVadSensitivity</key> + <map> + <key>Comment</key> + <string>A dimensionless value between 0 and 100, indicating the 'sensitivity of the VAD'. Increasing this value corresponds to decreasing the sensitivity of the VAD and 0 is turned off altogether</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>VoiceCallsFriendsOnly</key> <map> <key>Comment</key> - <string>Only accept voice calls from residents on your friends list</string> + <string>(Deprecated) Only accept voice calls from residents on your friends list</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -14805,6 +15051,28 @@ <key>Value</key> <integer>1</integer> </map> + <key>sunbeacon</key> + <map> + <key>Comment</key> + <string>Show direction to the Sun</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>moonbeacon</key> + <map> + <key>Comment</key> + <string>Show direction to the Moon</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>ShowDeviceSettings</key> <map> <key>Comment</key> @@ -15331,7 +15599,7 @@ <key>ClickToWalk</key> <map> <key>Comment</key> - <string>Click in world to walk to location</string> + <string>(obsolete)Click in world to walk to location</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -15767,6 +16035,28 @@ <key>Value</key> <integer>0</integer> </map> + <key>SettingsNextOwnerModify</key> + <map> + <key>Comment</key> + <string>Newly created Environment setting can be modified by next owner</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>SettingsNextOwnerTransfer</key> + <map> + <key>Comment</key> + <string>Newly created Environment setting can be resold or given away by next owner</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>DefaultUploadPermissionsConverted</key> <map> <key>Comment</key> @@ -16134,7 +16424,7 @@ <key>FMODExProfilerEnable</key> <map> <key>Comment</key> - <string>Enable profiler tool if using FMOD Ex</string> + <string>Enable profiler tool if using FMOD Ex or FMOD Studio</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -16145,7 +16435,7 @@ <key>FMODExDecodeBufferSize</key> <map> <key>Comment</key> - <string>Sets the streaming decode buffer size (in milliseconds)</string> + <string>Sets the streaming decode buffer size (in milliseconds) for FMOD Ex or FMOD Studio</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -16156,7 +16446,7 @@ <key>FMODExStreamBufferSize</key> <map> <key>Comment</key> - <string>Sets the streaming buffer size (in milliseconds)</string> + <string>Sets the streaming buffer size (in milliseconds) for FMOD Ex or FMOD Studio</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -16299,6 +16589,50 @@ <key>Value</key> <integer>0</integer> </map> + <key>CameraOpacity</key> + <map> + <key>Comment</key> + <string>Opacity of the Camera Controls floater</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>1.0</real> + </map> + <key>PresetCameraActive</key> + <map> + <key>Comment</key> + <string>Name of currently selected preference</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>Rear View</string> + </map> + <key>CameraPresetType</key> + <map> + <key>Comment</key> + <string>Preset camera position - view (0 - rear, 1 - front, 2 - group, 3 - custom)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>HoverHeightAffectsCamera</key> + <map> + <key>Comment</key> + <string>Camera view is affected by Hover Height setting</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>CefVerboseLog</key> <map> <key>Comment</key> @@ -16324,3 +16658,4 @@ </map> </llsd> + diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml index 8f4ca6c633..537744b44c 100644 --- a/indra/newview/app_settings/settings_per_account.xml +++ b/indra/newview/app_settings/settings_per_account.xml @@ -220,6 +220,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>VoiceCallsFriendsOnly</key> + <map> + <key>Comment</key> + <string>Only accept voice calls and receive IMs from residents on your friends list</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>VoiceEffectDefault</key> <map> <key>Comment</key> diff --git a/indra/newview/app_settings/shaders/class1/avatar/avatarV.glsl b/indra/newview/app_settings/shaders/class1/avatar/avatarV.glsl index 19203ab670..0543a26642 100644 --- a/indra/newview/app_settings/shaders/class1/avatar/avatarV.glsl +++ b/indra/newview/app_settings/shaders/class1/avatar/avatarV.glsl @@ -34,7 +34,7 @@ VARYING vec2 vary_texcoord0; uniform vec4 color; -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); +vec4 calcLighting(vec3 pos, vec3 norm, vec4 color); mat4 getSkinnedTransform(); void calcAtmospherics(vec3 inPositionEye); @@ -62,7 +62,7 @@ void main() calcAtmospherics(pos.xyz); - vec4 col = calcLighting(pos.xyz, norm, color, vec4(0,0,0,0)); + vec4 col = calcLighting(pos.xyz, norm, color); vertex_color = col; } diff --git a/indra/newview/app_settings/shaders/class1/avatar/eyeballV.glsl b/indra/newview/app_settings/shaders/class1/avatar/eyeballV.glsl index 82db15c3ae..fac1599c6b 100644 --- a/indra/newview/app_settings/shaders/class1/avatar/eyeballV.glsl +++ b/indra/newview/app_settings/shaders/class1/avatar/eyeballV.glsl @@ -36,7 +36,7 @@ ATTRIBUTE vec2 texcoord0; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol); +vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor); void calcAtmospherics(vec3 inPositionEye); void main() @@ -52,7 +52,7 @@ void main() calcAtmospherics(pos.xyz); vec4 specular = vec4(1.0); - vec4 color = calcLightingSpecular(pos, norm, diffuse_color, specular, vec4(0.0)); + vec4 color = calcLightingSpecular(pos, norm, diffuse_color, specular); vertex_color = color; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl index b9c8f34cb0..dc484317e9 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl @@ -22,7 +22,9 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + +//class1/deferred/alphaF.glsl + #extension GL_ARB_texture_rectangle : enable /*[EXTRA_CODE_HERE]*/ @@ -37,39 +39,9 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -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 mat3 ssao_effect_mat; - uniform vec3 sun_dir; - -#if HAS_SHADOW -uniform sampler2DShadow shadowMap0; -uniform sampler2DShadow shadowMap1; -uniform sampler2DShadow shadowMap2; -uniform sampler2DShadow shadowMap3; - -uniform vec2 shadow_res; - -uniform mat4 shadow_matrix[6]; -uniform vec4 shadow_clip; -uniform float shadow_bias; - -#endif +uniform vec3 moon_dir; #ifdef USE_DIFFUSE_TEX uniform sampler2D diffuseMap; @@ -81,551 +53,254 @@ VARYING vec2 vary_texcoord0; VARYING vec3 vary_norm; #ifdef USE_VERTEX_COLOR -VARYING vec4 vertex_color; +VARYING vec4 vertex_color; //vertex color should be treated as sRGB #endif -vec3 vary_PositionEye; -vec3 vary_SunlitColor; -vec3 vary_AmblitColor; -vec3 vary_AdditiveColor; -vec3 vary_AtmosAttenuation; - +uniform mat4 proj_mat; uniform mat4 inv_proj; uniform vec2 screen_res; - +uniform int sun_up_factor; uniform vec4 light_position[8]; uniform vec3 light_direction[8]; -uniform vec3 light_attenuation[8]; +uniform vec4 light_attenuation[8]; uniform vec3 light_diffuse[8]; -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)); - -#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); +#ifdef WATER_FOG +vec4 applyWaterFogView(vec3 pos, vec4 color); #endif -} +vec3 srgb_to_linear(vec3 c); +vec3 linear_to_srgb(vec3 c); -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 +vec2 encode_normal (vec3 n); +vec3 scaleSoftClipFrag(vec3 l); +vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten); -} +void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive, bool use_ao); -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} +#ifdef HAS_SHADOW +float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); +#endif -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; -} +float getAmbientClamp(); -vec3 calcDirectionalLight(vec3 n, vec3 l) +vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, float ambiance) { - float a = max(dot(n,l),0.0); - a = pow(a, 1.0/1.3); - return vec3(a,a,a); -} + vec3 col = vec3(0); -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 dist = length(lv); float da = 1.0; - vec3 col = vec3(0); - - if (d > 0.0 && la > 0.0 && fa > 0.0) + /*if (dist > la) + { + return col; + } + + clip to projector bounds + vec4 proj_tc = proj_mat * lp; + + if (proj_tc.z < 0 + || proj_tc.z > 1 + || proj_tc.x < 0 + || proj_tc.x > 1 + || proj_tc.y < 0 + || proj_tc.y > 1) + { + return col; + }*/ + + if (dist > 0.0 && la > 0.0) { + dist /= la; + //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; + dist_atten *= 2.0f; + + if (dist_atten <= 0.0) + { + return col; + } // 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)); + da *= dot(n, lv); + da = max(0.0, da); + + float lit = 0.0f; + + float amb_da = 0.0;//ambiance; + if (da > 0) + { + lit = max(da * dist_atten,0.0); + col = lit * light_col * diffuse; + amb_da += (da*0.5+0.5) * ambiance; + } + amb_da += (da*da*0.5 + 0.5) * ambiance; + amb_da *= dist_atten; + amb_da = min(amb_da, 1.0f - lit); + + // SL-10969 ... need to work out why this blows out in many setups... + //col.rgb += amb_da * light_col * diffuse; + + // no spec for alpha shader... + } + col = max(col, vec3(0)); + return col; } -#if HAS_SHADOW -float pcfShadow(sampler2DShadow shadowMap, vec4 stc) +void main() { - stc.xyz /= stc.w; - stc.z += shadow_bias; - - stc.x = floor(stc.x*shadow_res.x + fract(stc.y*shadow_res.y*12345))/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 + vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; + frag *= screen_res; + + vec4 pos = vec4(vary_position, 1.0); + vec3 norm = vary_norm; -#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)); + float shadow = 1.0f; - //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; -} +#ifdef HAS_SHADOW + shadow = sampleDirectionalShadow(pos.xyz, norm.xyz, frag); #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, float ambFactor) { - - 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; - - /* decrease value and saturation (that in HSV, not HSL) for occluded areas - * // for HSV color/geometry used here, see http://gimp-savvy.com/BOOK/index.html?node52.html - * // The following line of code performs the equivalent of: - * float ambAlpha = tmpAmbient.a; - * float ambValue = dot(vec3(tmpAmbient), vec3(0.577)); // projection onto <1/rt(3), 1/rt(3), 1/rt(3)>, the neutral white-black axis - * vec3 ambHueSat = vec3(tmpAmbient) - vec3(ambValue); - * tmpAmbient = vec4(RenderSSAOEffect.valueFactor * vec3(ambValue) + RenderSSAOEffect.saturationFactor *(1.0 - ambFactor) * ambHueSat, ambAlpha); - */ - tmpAmbient = vec4(mix(ssao_effect_mat * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a); - - //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)); -} +#ifdef USE_DIFFUSE_TEX + vec4 diffuse_tap = texture2D(diffuseMap,vary_texcoord0.xy); +#endif -vec3 atmosLighting(vec3 light) -{ - light *= getAtmosAttenuation().r; - light += getAdditiveColor(); - return (2.0 * light); -} +#ifdef USE_INDEXED_TEX + vec4 diffuse_tap = diffuseLookup(vary_texcoord0.xy); +#endif -vec3 atmosTransport(vec3 light) { - light *= getAtmosAttenuation().r; - light += getAdditiveColor() * 2.0; - return light; -} -vec3 atmosGetDiffuseSunlightColor() -{ - return getSunlitColor(); -} + vec4 diffuse_srgb = diffuse_tap; + vec4 diffuse_linear = vec4(srgb_to_linear(diffuse_srgb.rgb), diffuse_srgb.a); -vec3 scaleDownLight(vec3 light) -{ - return (light / vec3(scene_light_strength, scene_light_strength, scene_light_strength)); -} +#ifdef FOR_IMPOSTOR + vec4 color; + color.rgb = diffuse_srgb.rgb; + color.a = 1.0; + + float final_alpha = diffuse_srgb.a * vertex_color.a; + diffuse_srgb.rgb *= vertex_color.rgb; + diffuse_linear.rgb = srgb_to_linear(diffuse_srgb.rgb); + + // Insure we don't pollute depth with invis pixels in impostor rendering + // + if (final_alpha < 0.01) + { + discard; + } +#else + + vec3 light_dir = (sun_up_factor == 1) ? sun_dir: moon_dir; -vec3 scaleUpLight(vec3 light) -{ - return (light * vec3(scene_light_strength, scene_light_strength, scene_light_strength)); -} + float final_alpha = diffuse_linear.a; -vec3 atmosAmbient(vec3 light) -{ - return getAmblitColor() + (light * vec3(0.5f, 0.5f, 0.5f)); -} +#ifdef USE_VERTEX_COLOR + final_alpha *= vertex_color.a; + diffuse_srgb.rgb *= vertex_color.rgb; + diffuse_linear.rgb = srgb_to_linear(diffuse_srgb.rgb); +#endif -vec3 atmosAffectDirectionalLight(float lightIntensity) -{ - return getSunlitColor() * vec3(lightIntensity, lightIntensity, lightIntensity); -} + vec3 sunlit; + vec3 amblit; + vec3 additive; + vec3 atten; -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); + calcAtmosphericVars(pos.xyz, light_dir, 1.0, sunlit, amblit, additive, atten, false); - light = ones - clamp(light, zeroes, ones); - light = ones - pow(light, gamma.xxx); + vec2 abnormal = encode_normal(norm.xyz); - return light; -} + float da = dot(norm.xyz, light_dir.xyz); + da = clamp(da, -1.0, 1.0); + da = pow(da, 1.0/1.3); + + float final_da = da; + final_da = clamp(final_da, 0.0f, 1.0f); -vec3 fullbrightAtmosTransport(vec3 light) { - float brightness = dot(light.rgb, vec3(0.33333)); + vec4 color = vec4(0.0); - return mix(atmosTransport(light.rgb), light.rgb + getAdditiveColor().rgb, brightness * brightness); -} + color.a = final_alpha; -vec3 fullbrightScaleSoftClip(vec3 light) -{ - //soft clip effect: - return light; -} + float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0); + ambient *= 0.5; + ambient *= ambient; + ambient = (1.0 - ambient); -void main() -{ - vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; - frag *= screen_res; - - vec4 pos = vec4(vary_position, 1.0); - - float shadow = 1.0; - -#if HAS_SHADOW - 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)*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)*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)*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)*w; - weight += w; - } - - - shadow /= weight; - } - else - { - shadow = 1.0; - } -#endif + vec3 sun_contrib = min(final_da, shadow) * sunlit; -#ifdef USE_INDEXED_TEX - vec4 diff = diffuseLookup(vary_texcoord0.xy); -#else - vec4 diff = texture2D(diffuseMap,vary_texcoord0.xy); +#if !defined(AMBIENT_KILL) + color.rgb = amblit; + color.rgb *= ambient; #endif -#ifdef FOR_IMPOSTOR - vec4 color; - color.rgb = diff.rgb; - color.a = 1.0; +vec3 post_ambient = color.rgb; -#ifdef USE_VERTEX_COLOR - float final_alpha = diff.a * vertex_color.a; - diff.rgb *= vertex_color.rgb; -#else - float final_alpha = diff.a; -#endif - - // Insure we don't pollute depth with invis pixels in impostor rendering - // - if (final_alpha < 0.01) - { - discard; - } -#else - -#ifdef USE_VERTEX_COLOR - float final_alpha = diff.a * vertex_color.a; - diff.rgb *= vertex_color.rgb; -#else - float final_alpha = diff.a; +#if !defined(SUNLIGHT_KILL) + color.rgb += sun_contrib; #endif +vec3 post_sunlight = color.rgb; - vec4 gamma_diff = diff; - diff.rgb = srgb_to_linear(diff.rgb); + color.rgb *= diffuse_srgb.rgb; - vec3 norm = vary_norm; +vec3 post_diffuse = color.rgb; - calcAtmospherics(pos.xyz, 1.0); + color.rgb = atmosFragLighting(color.rgb, additive, atten); - vec2 abnormal = encode_normal(norm.xyz); - norm.xyz = decode_normal(abnormal.xy); +vec3 post_atmo = color.rgb; - float da = dot(norm.xyz, sun_dir.xyz); + vec4 light = vec4(0,0,0,0); + + color.rgb = scaleSoftClipFrag(color.rgb); - 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); + //convert to linear before applying local lights + color.rgb = srgb_to_linear(color.rgb); - vec4 color = vec4(0,0,0,0); + #define LIGHT_LOOP(i) light.rgb += calcPointLightOrSpotLight(light_diffuse[i].rgb, diffuse_linear.rgb, pos.xyz, norm, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z, light_attenuation[i].w); - color.rgb = atmosAmbient(color.rgb); - color.a = 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); + LIGHT_LOOP(1) + LIGHT_LOOP(2) + LIGHT_LOOP(3) + LIGHT_LOOP(4) + LIGHT_LOOP(5) + LIGHT_LOOP(6) + LIGHT_LOOP(7) - 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); + // sum local light contrib in linear colorspace +#if !defined(LOCAL_LIGHT_KILL) + color.rgb += light.rgb; +#endif + // back to sRGB as we're going directly to the final RT post-deferred gamma correction + color.rgb = linear_to_srgb(color.rgb); + +//color.rgb = amblit; +//color.rgb = vec3(ambient); +//color.rgb = sunlit; +//color.rgb = vec3(final_da); +//color.rgb = post_ambient; +//color.rgb = post_sunlight; +//color.rgb = sun_contrib; +//color.rgb = diffuse_srgb.rgb; +//color.rgb = post_diffuse; +//color.rgb = post_atmo; #ifdef WATER_FOG - color = applyWaterFogDeferred(pos.xyz, color); -#endif + color = applyWaterFogView(pos.xyz, color); +#endif // WATER_FOG #endif - - frag_color = color; + + frag_color = color; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/aoUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/aoUtil.glsl new file mode 100644 index 0000000000..23adbded5e --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/aoUtil.glsl @@ -0,0 +1,123 @@ +/** + * @file class1/deferred/aoUtil.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 sampler2D noiseMap; +uniform sampler2DRect normalMap; +uniform sampler2DRect depthMap; + +uniform float ssao_radius; +uniform float ssao_max_radius; +uniform float ssao_factor; +uniform float ssao_factor_inv; + +uniform mat4 inv_proj; +uniform vec2 screen_res; + +vec2 getScreenCoordinateAo(vec2 screenpos) +{ + vec2 sc = screenpos.xy * 2.0; + if (screen_res.x > 0 && screen_res.y > 0) + { + sc /= screen_res; + } + return sc - vec2(1.0, 1.0); +} + +float getDepthAo(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen).r; + return depth; +} + +vec4 getPositionAo(vec2 pos_screen) +{ + float depth = getDepthAo(pos_screen); + vec2 sc = getScreenCoordinateAo(pos_screen); + 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; +} + +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, vec2 pos_screen) +{ + float ret = 1.0; + vec3 pos_world = pos.xyz; + vec2 noise_reflect = texture2D(noiseMap, pos_screen.xy/128.0).xy; + + float angle_hidden = 0.0; + float points = 0; + + float scale = min(ssao_radius / -pos_world.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 = getPositionAo(samppos_screen).xyz; + + vec3 diff = pos_world - samppos_world; + float dist2 = dot(diff, diff); + + // assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area + // --> solid angle shrinking by the square of distance + //radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2 + //(k should vary inversely with # of samples, but this is taken care of later) + + float funky_val = (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) ? 1.0 : 0.0; + angle_hidden = angle_hidden + funky_val * min(1.0/dist2, ssao_factor_inv); + + // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" + float diffz_val = (diff.z > -1.0) ? 1.0 : 0.0; + points = points + diffz_val; + } + + angle_hidden = min(ssao_factor*angle_hidden/points, 1.0); + + float points_val = (points > 0.0) ? 1.0 : 0.0; + ret = (1.0 - (points_val * angle_hidden)); + + ret = max(ret, 0.0); + return min(ret, 1.0); +} + diff --git a/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowF.glsl index 22c9a4d14e..8e9a5fcd41 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowF.glsl @@ -22,6 +22,8 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; #else diff --git a/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl index 3f90600ace..0fa0edfd67 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl @@ -41,7 +41,7 @@ void main() vec4 p = projection_matrix * vec4(pos, 1.0); -#if !DEPTH_CLAMP +#if !defined(DEPTH_CLAMP) p.z = max(p.z, -p.w+0.01); gl_Position = p; #else diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaNoColorV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaNoColorV.glsl index c8ddefac26..bbdc8fdd1c 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaNoColorV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaNoColorV.glsl @@ -29,17 +29,13 @@ 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 atmosAmbient(); vec3 atmosAffectDirectionalLight(float lightIntensity); -vec3 scaleDownLight(vec3 light); -vec3 scaleUpLight(vec3 light); VARYING vec3 vary_position; VARYING vec3 vary_ambient; @@ -59,41 +55,7 @@ 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; -} +float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight); void main() { @@ -137,7 +99,7 @@ void main() col.rgb = vec3(0,0,0); // Add windlight lights - col.rgb = atmosAmbient(vec3(0.)); + col.rgb = atmosAmbient(); vary_ambient = col.rgb*color.rgb; vary_directional = color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, light_position[0].xyz), 0.0)); diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl index 662c762bca..60d83cc623 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl @@ -23,6 +23,8 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_data[3]; #else @@ -36,11 +38,7 @@ uniform float minimum_alpha; VARYING vec3 vary_normal; VARYING vec2 vary_texcoord0; -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} +vec2 encode_normal(vec3 n); void main() { diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl index b809b73973..50020a50d8 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl @@ -22,7 +22,9 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; #else @@ -31,7 +33,7 @@ out vec4 frag_color; uniform sampler2D diffuseMap; -#if !DEPTH_CLAMP +#if !defined(DEPTH_CLAMP) VARYING vec4 post_pos; #endif @@ -39,7 +41,7 @@ void main() { frag_color = vec4(1,1,1,1); -#if !DEPTH_CLAMP +#if !defined(DEPTH_CLAMP) gl_FragDepth = max(post_pos.z/post_pos.w*0.5+0.5, 0.0); #endif } diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl index bde1ad4e9f..91b25613e0 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl @@ -31,7 +31,7 @@ ATTRIBUTE vec3 position; ATTRIBUTE vec3 normal; ATTRIBUTE vec2 texcoord0; -#if !DEPTH_CLAMP +#if !defined(DEPTH_CLAMP) VARYING vec4 post_pos; #endif @@ -53,7 +53,7 @@ void main() norm = normalize(norm); pos = projection_matrix * pos; -#if !DEPTH_CLAMP +#if !defined(DEPTH_CLAMP) post_pos = pos; gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl index cbd8d2ebfc..596d0274af 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl @@ -33,7 +33,6 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect depthMap; uniform sampler2DRect normalMap; uniform sampler2DRect lightMap; @@ -45,100 +44,68 @@ uniform float kern_scale; 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; -} - -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); +vec3 getNorm(vec2 pos_screen); void main() { vec2 tc = vary_fragcoord.xy; - vec3 norm = texture2DRect(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 / (1.0+norm.xy*norm.xy); - dlt /= max(-pos.z*dist_factor, 1.0); - - vec2 defined_weight = kern[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' - vec4 col = defined_weight.xyxx * ccol; - - // relax tolerance according to distance to avoid speckling artifacts, as angles and distances are a lot more abrupt within a small screen area at larger distances - float pointplanedist_tolerance_pow2 = pos.z*pos.z*0.00005; - - // perturb sampling origin slightly in screen-space to hide edge-ghosting artifacts where smoothing radius is quite large - float tc_mod = 0.5*(tc.x + tc.y); // mod(tc.x+tc.y,2) - tc_mod -= floor(tc_mod); - tc_mod *= 2.0; - tc += ( (tc_mod - 0.5) * kern[1].z * dlt * 0.5 ); - - for (int i = 1; i < 4; i++) - { - vec2 samptc = tc + kern[i].z*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)*kern[i].xyxx; - defined_weight += kern[i].xy; - } - } - - for (int i = 1; i < 4; i++) - { - vec2 samptc = tc - kern[i].z*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)*kern[i].xyxx; - defined_weight += kern[i].xy; - } - } - - col /= defined_weight.xyxx; - col.y *= col.y; - - frag_color = col; + vec3 norm = getNorm(tc); + vec3 pos = getPosition(tc).xyz; + vec4 ccol = texture2DRect(lightMap, tc).rgba; + + vec2 dlt = kern_scale * delta / (1.0+norm.xy*norm.xy); + dlt /= max(-pos.z*dist_factor, 1.0); + + vec2 defined_weight = kern[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' + vec4 col = defined_weight.xyxx * ccol; + + // relax tolerance according to distance to avoid speckling artifacts, as angles and distances are a lot more abrupt within a small screen area at larger distances + float pointplanedist_tolerance_pow2 = pos.z*pos.z*0.00005; + + // perturb sampling origin slightly in screen-space to hide edge-ghosting artifacts where smoothing radius is quite large + float tc_mod = 0.5*(tc.x + tc.y); // mod(tc.x+tc.y,2) + tc_mod -= floor(tc_mod); + tc_mod *= 2.0; + tc += ( (tc_mod - 0.5) * kern[1].z * dlt * 0.5 ); + + for (int i = 1; i < 4; i++) + { + vec2 samptc = tc + kern[i].z*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)*kern[i].xyxx; + defined_weight += kern[i].xy; + } + } + + for (int i = 1; i < 4; i++) + { + vec2 samptc = tc - kern[i].z*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)*kern[i].xyxx; + defined_weight += kern[i].xy; + } + } + + col /= defined_weight.xyxx; + col.y *= col.y; + + frag_color = col; #ifdef IS_AMD_CARD - // If it's AMD make sure the GLSL compiler sees the arrays referenced once by static index. Otherwise it seems to optimise the storage awawy which leads to unfun crashes and artifacts. - vec3 dummy1 = kern[0]; - vec3 dummy2 = kern[3]; + // If it's AMD make sure the GLSL compiler sees the arrays referenced once by static index. Otherwise it seems to optimise the storage awawy which leads to unfun crashes and artifacts. + vec3 dummy1 = kern[0]; + vec3 dummy2 = kern[3]; #endif } diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl index 58fb01d200..b5677a07ee 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl @@ -22,6 +22,8 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ + +/*[EXTRA_CODE_HERE]*/ #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_data[3]; @@ -40,11 +42,7 @@ VARYING vec3 vary_mat2; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} +vec2 encode_normal(vec3 n); void main() { diff --git a/indra/newview/app_settings/shaders/class1/deferred/cloudShadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/cloudShadowF.glsl new file mode 100644 index 0000000000..0157d166e0 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/cloudShadowF.glsl @@ -0,0 +1,127 @@ +/** + * @file class3/deferred/cloudsF.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$ + */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2D diffuseMap; + +VARYING vec4 pos; +VARYING float target_pos_x; +VARYING float vary_CloudDensity; +VARYING vec2 vary_texcoord0; +VARYING vec2 vary_texcoord1; +VARYING vec2 vary_texcoord2; +VARYING vec2 vary_texcoord3; + +uniform sampler2D cloud_noise_texture; +uniform sampler2D cloud_noise_texture_next; +uniform float blend_factor; +uniform vec4 cloud_pos_density1; +uniform vec4 cloud_pos_density2; +uniform vec4 sunlight_color; +uniform vec4 cloud_color; +uniform float cloud_shadow; +uniform float cloud_scale; +uniform float cloud_variance; +uniform vec3 camPosLocal; +uniform vec3 sun_dir; +uniform float sun_size; +uniform float far_z; + +#if !defined(DEPTH_CLAMP) +VARYING vec4 post_pos; +#endif + +vec4 cloudNoise(vec2 uv) +{ + vec4 a = texture2D(cloud_noise_texture, uv); + vec4 b = texture2D(cloud_noise_texture_next, uv); + vec4 cloud_noise_sample = mix(a, b, blend_factor); + return normalize(cloud_noise_sample); +} + +void main() +{ + // Set variables + vec2 uv1 = vary_texcoord0.xy; + vec2 uv2 = vary_texcoord1.xy; + vec2 uv3 = vary_texcoord2.xy; + float cloudDensity = 2.0 * (cloud_shadow - 0.25); + + if (cloud_scale >= 0.0001) + { + vec2 uv4 = vary_texcoord3.xy; + + vec2 disturbance = vec2(cloudNoise(uv1 / 8.0f).x, cloudNoise((uv3 + uv1) / 16.0f).x) * cloud_variance * (1.0f - cloud_scale * 0.25f); + vec2 disturbance2 = vec2(cloudNoise((uv1 + uv3) / 4.0f).x, cloudNoise((uv4 + uv2) / 8.0f).x) * cloud_variance * (1.0f - cloud_scale * 0.25f); + + // Offset texture coords + uv1 += cloud_pos_density1.xy + (disturbance * 0.2); //large texture, visible density + uv2 += cloud_pos_density1.xy; //large texture, self shadow + uv3 += cloud_pos_density2.xy; //small texture, visible density + uv4 += cloud_pos_density2.xy; //small texture, self shadow + + float density_variance = min(1.0, (disturbance.x* 2.0 + disturbance.y* 2.0 + disturbance2.x + disturbance2.y) * 4.0); + + cloudDensity *= 1.0 - (density_variance * density_variance); + + // Compute alpha1, the main cloud opacity + float alpha1 = (cloudNoise(uv1).x - 0.5) + (cloudNoise(uv3).x - 0.5) * cloud_pos_density2.z; + alpha1 = min(max(alpha1 + cloudDensity, 0.) * 10 * cloud_pos_density1.z, 1.); + + // And smooth + alpha1 = 1. - alpha1 * alpha1; + alpha1 = 1. - alpha1 * alpha1; + + if (alpha1 < 0.001f) + { + discard; + } + + // Compute alpha2, for self shadowing effect + // (1 - alpha2) will later be used as percentage of incoming sunlight + float alpha2 = (cloudNoise(uv2).x - 0.5); + alpha2 = min(max(alpha2 + cloudDensity, 0.) * 2.5 * cloud_pos_density1.z, 1.); + + // And smooth + alpha2 = 1. - alpha2; + alpha2 = 1. - alpha2 * alpha2; + + frag_color = vec4(alpha1, alpha1, alpha1, 1); + } + else + { + frag_color = vec4(1); + } + +#if !defined(DEPTH_CLAMP) + gl_FragDepth = max(post_pos.z/post_pos.w*0.5+0.5, 0.0); +#endif + +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/cloudShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/cloudShadowV.glsl new file mode 100644 index 0000000000..effb070f93 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/cloudShadowV.glsl @@ -0,0 +1,63 @@ +/** + * @file cloudShadowV.glsl + * + * $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$ + */ + +uniform mat4 texture_matrix0; +uniform mat4 modelview_projection_matrix; +uniform float shadow_target_width; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec4 diffuse_color; +ATTRIBUTE vec2 texcoord0; + +#if !defined(DEPTH_CLAMP) +VARYING float pos_zd2; +#endif + +VARYING vec4 pos; +VARYING float target_pos_x; +VARYING vec2 vary_texcoord0; +VARYING vec4 vertex_color; + +void passTextureIndex(); + +void main() +{ + //transform vertex + vec4 pre_pos = vec4(position.xyz, 1.0); + pos = modelview_projection_matrix * pre_pos; + target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x; + +#if !defined(DEPTH_CLAMP) + pos_zd2 = pos.z * 0.5; + gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); +#else + gl_Position = pos; +#endif + + passTextureIndex(); + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; + vertex_color = diffuse_color; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/cloudsF.glsl b/indra/newview/app_settings/shaders/class1/deferred/cloudsF.glsl index 1d8ca04ccd..ae1ac5de7f 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/cloudsF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/cloudsF.glsl @@ -1,5 +1,5 @@ /** - * @file WLCloudsF.glsl + * @file class1\deferred\cloudsF.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -22,7 +22,7 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - +/*[EXTRA_CODE_HERE]*/ #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_data[3]; @@ -39,69 +39,93 @@ VARYING vec4 vary_CloudColorAmbient; VARYING float vary_CloudDensity; uniform sampler2D cloud_noise_texture; +uniform sampler2D cloud_noise_texture_next; +uniform float blend_factor; uniform vec4 cloud_pos_density1; uniform vec4 cloud_pos_density2; -uniform vec4 gamma; +uniform float cloud_scale; +uniform float cloud_variance; VARYING vec2 vary_texcoord0; VARYING vec2 vary_texcoord1; VARYING vec2 vary_texcoord2; VARYING vec2 vary_texcoord3; +VARYING float altitude_blend_factor; /// Soft clips the light with a gamma correction -vec3 scaleSoftClip(vec3 light) { - //soft clip effect: - light = 1. - clamp(light, vec3(0.), vec3(1.)); - light = 1. - pow(light, gamma.xxx); +vec3 scaleSoftClip(vec3 light); - return light; +vec4 cloudNoise(vec2 uv) +{ + vec4 a = texture2D(cloud_noise_texture, uv); + vec4 b = texture2D(cloud_noise_texture_next, uv); + vec4 cloud_noise_sample = mix(a, b, blend_factor); + return cloud_noise_sample; } void main() { - // Set variables - vec2 uv1 = vary_texcoord0.xy; - vec2 uv2 = vary_texcoord1.xy; - - vec4 cloudColorSun = vary_CloudColorSun; - vec4 cloudColorAmbient = vary_CloudColorAmbient; - float cloudDensity = vary_CloudDensity; - vec2 uv3 = vary_texcoord2.xy; - vec2 uv4 = vary_texcoord3.xy; - - // Offset texture coords - uv1 += cloud_pos_density1.xy; //large texture, visible density - uv2 += cloud_pos_density1.xy; //large texture, self shadow - uv3 += cloud_pos_density2.xy; //small texture, visible density - uv4 += cloud_pos_density2.xy; //small texture, self shadow - - - // Compute alpha1, the main cloud opacity - float alpha1 = (texture2D(cloud_noise_texture, uv1).x - 0.5) + (texture2D(cloud_noise_texture, uv3).x - 0.5) * cloud_pos_density2.z; - alpha1 = min(max(alpha1 + cloudDensity, 0.) * 10. * cloud_pos_density1.z, 1.); - - // And smooth - alpha1 = 1. - alpha1 * alpha1; - alpha1 = 1. - alpha1 * alpha1; - - - // Compute alpha2, for self shadowing effect - // (1 - alpha2) will later be used as percentage of incoming sunlight - float alpha2 = (texture2D(cloud_noise_texture, uv2).x - 0.5); - alpha2 = min(max(alpha2 + cloudDensity, 0.) * 2.5 * cloud_pos_density1.z, 1.); - - // And smooth - alpha2 = 1. - alpha2; - alpha2 = 1. - alpha2 * alpha2; - - // Combine - vec4 color; - color = (cloudColorSun*(1.-alpha2) + cloudColorAmbient); - color *= 2.; - - /// 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); - frag_data[2] = vec4(0,0,1,0); + // Set variables + vec2 uv1 = vary_texcoord0.xy; + vec2 uv2 = vary_texcoord1.xy; + + vec4 cloudColorSun = vary_CloudColorSun; + vec4 cloudColorAmbient = vary_CloudColorAmbient; + float cloudDensity = vary_CloudDensity; + vec2 uv3 = vary_texcoord2.xy; + vec2 uv4 = vary_texcoord3.xy; + + if (cloud_scale < 0.001) + { + discard; + } + + vec2 disturbance = vec2(cloudNoise(uv1 / 8.0f).x, cloudNoise((uv3 + uv1) / 16.0f).x) * cloud_variance * (1.0f - cloud_scale * 0.25f); + vec2 disturbance2 = vec2(cloudNoise((uv1 + uv3) / 4.0f).x, cloudNoise((uv4 + uv2) / 8.0f).x) * cloud_variance * (1.0f - cloud_scale * 0.25f); + + // Offset texture coords + uv1 += cloud_pos_density1.xy + (disturbance * 0.2); //large texture, visible density + uv2 += cloud_pos_density1.xy; //large texture, self shadow + uv3 += cloud_pos_density2.xy; //small texture, visible density + uv4 += cloud_pos_density2.xy; //small texture, self shadow + + float density_variance = min(1.0, (disturbance.x* 2.0 + disturbance.y* 2.0 + disturbance2.x + disturbance2.y) * 4.0); + + cloudDensity *= 1.0 - (density_variance * density_variance); + + // Compute alpha1, the main cloud opacity + + float alpha1 = (cloudNoise(uv1).x - 0.5) + (cloudNoise(uv3).x - 0.5) * cloud_pos_density2.z; + alpha1 = min(max(alpha1 + cloudDensity, 0.) * 10 * cloud_pos_density1.z, 1.); + + // And smooth + alpha1 = 1. - alpha1 * alpha1; + alpha1 = 1. - alpha1 * alpha1; + + alpha1 *= altitude_blend_factor; + alpha1 = clamp(alpha1, 0.0, 1.0); + + // Compute alpha2, for self shadowing effect + // (1 - alpha2) will later be used as percentage of incoming sunlight + float alpha2 = (cloudNoise(uv2).x - 0.5); + alpha2 = min(max(alpha2 + cloudDensity, 0.) * 2.5 * cloud_pos_density1.z, 1.); + + // And smooth + alpha2 = 1. - alpha2; + alpha2 = 1. - alpha2 * alpha2; + + // Combine + vec4 color; + color = (cloudColorSun*(1.-alpha2) + cloudColorAmbient); + color.rgb= max(vec3(0), color.rgb); + color.rgb *= 2.0; + color.rgb = scaleSoftClip(color.rgb); + + /// Gamma correct for WL (soft clip effect). + frag_data[0] = vec4(color.rgb, alpha1); + frag_data[1] = vec4(0.0,0.0,0.0,0.0); + frag_data[2] = vec4(0,0,0,1); + + gl_FragDepth = 0.99995f; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/cloudsV.glsl b/indra/newview/app_settings/shaders/class1/deferred/cloudsV.glsl index 17f425475c..8e0a001403 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/cloudsV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/cloudsV.glsl @@ -41,13 +41,16 @@ VARYING vec2 vary_texcoord0; VARYING vec2 vary_texcoord1; VARYING vec2 vary_texcoord2; VARYING vec2 vary_texcoord3; +VARYING float altitude_blend_factor; // Inputs uniform vec3 camPosLocal; uniform vec4 lightnorm; uniform vec4 sunlight_color; -uniform vec4 ambient; +uniform vec4 moonlight_color; +uniform int sun_up_factor; +uniform vec4 ambient_color; uniform vec4 blue_horizon; uniform vec4 blue_density; uniform float haze_horizon; @@ -58,128 +61,128 @@ uniform float density_multiplier; uniform float max_y; uniform vec4 glow; +uniform float sun_moon_glow_factor; uniform vec4 cloud_color; uniform float cloud_scale; +// NOTE: Keep these in sync! +// indra\newview\app_settings\shaders\class1\deferred\skyV.glsl +// indra\newview\app_settings\shaders\class1\deferred\cloudsV.glsl +// indra\newview\app-settings\shaders\class2\windlight\cloudsV.glsl +// indra\newview\lllegacyatmospherics.cpp +// indra\newview\llsettingsvo.cpp void main() { - // World / view / projection gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); - vary_texcoord0 = texcoord0; + // Texture coords + // SL-13084 EEP added support for custom cloud textures -- flip them horizontally to match the preview of Clouds > Cloud Scroll + vary_texcoord0 = vec2(-texcoord0.x, texcoord0.y); // See: LLSettingsVOSky::applySpecial + + vary_texcoord0.xy -= 0.5; + vary_texcoord0.xy /= cloud_scale; + vary_texcoord0.xy += 0.5; + + vary_texcoord1 = vary_texcoord0; + vary_texcoord1.x += lightnorm.x * 0.0125; + vary_texcoord1.y += lightnorm.z * 0.0125; + + vary_texcoord2 = vary_texcoord0 * 16.; + vary_texcoord3 = vary_texcoord1 * 16.; // Get relative position - vec3 P = position.xyz - camPosLocal.xyz + vec3(0,50,0); + vec3 rel_pos = position.xyz - camPosLocal.xyz + vec3(0, 50, 0); + + altitude_blend_factor = clamp((rel_pos.y + 512.0) / max_y, 0.0, 1.0); // Set altitude - if (P.y > 0.) + if (rel_pos.y > 0) { - P *= (max_y / P.y); + rel_pos *= (max_y / rel_pos.y); } - else + if (rel_pos.y < 0) { - P *= (-32000. / P.y); + altitude_blend_factor = 0; // SL-11589 Fix clouds drooping below horizon + rel_pos *= (-32000. / rel_pos.y); } // Can normalize then - vec3 Pn = normalize(P); - float Plen = length(P); + vec3 rel_pos_norm = normalize(rel_pos); + float rel_pos_len = length(rel_pos); // Initialize temp variables - vec4 temp1 = vec4(0.); - vec4 temp2 = vec4(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); + light_atten = (blue_density + vec4(haze_density * 0.25)) * (density_multiplier * max_y); // Calculate relative weights - temp1 = blue_density + haze_density; - blue_weight = blue_density / temp1; - haze_weight = haze_density / temp1; + vec4 combined_haze = abs(blue_density) + vec4(abs(haze_density)); + vec4 blue_weight = blue_density / combined_haze; + vec4 haze_weight = haze_density / combined_haze; - // Compute sunlight from P & lightnorm (for long rays like sky) - temp2.y = max(0., max(0., Pn.y) * 1.0 + lightnorm.y ); - temp2.y = 1. / temp2.y; - sunlight *= exp( - light_atten * temp2.y); + // Compute sunlight from rel_pos & lightnorm (for long rays like sky) + float off_axis = 1.0 / max(1e-6, max(0., rel_pos_norm.y) + lightnorm.y); + sunlight *= exp(-light_atten * off_axis); // Distance - temp2.z = Plen * density_multiplier; + float density_dist = rel_pos_len * density_multiplier; - // Transparency (-> temp1) - // ATI Bugfix -- can't store temp1*temp2.z in a variable because the ati + // Transparency (-> combined_haze) + // ATI Bugfix -- can't store combined_haze*density_dist in a variable because the ati // compiler gets confused. - temp1 = exp(-temp1 * temp2.z); - + combined_haze = exp(-combined_haze * density_dist); // Compute haze glow - temp2.x = dot(Pn, lightnorm.xyz); - temp2.x = 1. - temp2.x; - // temp2.x is 0 at the sun and increases away from sun - temp2.x = max(temp2.x, .001); + float haze_glow = 1.0 - dot(rel_pos_norm, lightnorm.xyz); + // haze_glow is 0 at the sun and increases away from sun + haze_glow = max(haze_glow, .001); // Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) - temp2.x *= glow.x; + haze_glow *= glow.x; // Higher glow.x gives dimmer glow (because next step is 1 / "angle") - temp2.x = pow(temp2.x, glow.z); + haze_glow = pow(haze_glow, glow.z); // glow.z should be negative, so we're doing a sort of (1 / "angle") function + haze_glow *= sun_moon_glow_factor; + // Add "minimum anti-solar illumination" - temp2.x += .25; + // For sun, add to glow. For moon, remove glow entirely. SL-13768 + haze_glow = (sun_moon_glow_factor < 1.0) ? 0.0 : (haze_glow + 0.25); // Increase ambient when there are more clouds - vec4 tmpAmbient = ambient; + vec4 tmpAmbient = ambient_color; tmpAmbient += (1. - tmpAmbient) * cloud_shadow * 0.5; // Dim sunlight by cloud shadow percentage sunlight *= (1. - cloud_shadow); // Haze color below cloud - vec4 additiveColorBelowCloud = ( blue_horizon * blue_weight * (sunlight + tmpAmbient) - + (haze_horizon * haze_weight) * (sunlight * temp2.x + tmpAmbient) - ); + vec4 additiveColorBelowCloud = + (blue_horizon * blue_weight * (sunlight + tmpAmbient) + (haze_horizon * haze_weight) * (sunlight * haze_glow + tmpAmbient)); // CLOUDS - - sunlight = sunlight_color; - temp2.y = max(0., lightnorm.y * 2.); - temp2.y = 1. / temp2.y; - sunlight *= exp( - light_atten * temp2.y); + sunlight = sunlight_color; // SL-14707 reset color -- Clouds are unusually dim in EEP + off_axis = 1.0 / max(1e-6, lightnorm.y * 2.); + sunlight *= exp(-light_atten * off_axis); // Cloud color out - vary_CloudColorSun = (sunlight * temp2.x) * cloud_color; + vary_CloudColorSun = (sunlight * haze_glow) * cloud_color; vary_CloudColorAmbient = tmpAmbient * cloud_color; // Attenuate cloud color by atmosphere - temp1 = sqrt(temp1); //less atmos opacity (more transparency) below clouds - vary_CloudColorSun *= temp1; - vary_CloudColorAmbient *= temp1; - vec4 oHazeColorBelowCloud = additiveColorBelowCloud * (1. - temp1); + combined_haze = sqrt(combined_haze); // less atmos opacity (more transparency) below clouds + vary_CloudColorSun *= combined_haze; + vary_CloudColorAmbient *= combined_haze; + vec4 oHazeColorBelowCloud = additiveColorBelowCloud * (1. - combined_haze); // Make a nice cloud density based on the cloud_shadow value that was passed in. vary_CloudDensity = 2. * (cloud_shadow - 0.25); - - // Texture coords - vary_texcoord0 = texcoord0; - vary_texcoord0.xy -= 0.5; - vary_texcoord0.xy /= cloud_scale; - vary_texcoord0.xy += 0.5; - - vary_texcoord1 = vary_texcoord0; - vary_texcoord1.x += lightnorm.x * 0.0125; - vary_texcoord1.y += lightnorm.z * 0.0125; - - vary_texcoord2 = vary_texcoord0 * 16.; - vary_texcoord3 = vary_texcoord1 * 16.; - // Combine these to minimize register use vary_CloudColorAmbient += oHazeColorBelowCloud; @@ -188,4 +191,3 @@ void main() // END CLOUDS } - diff --git a/indra/newview/app_settings/shaders/class1/deferred/cofF.glsl b/indra/newview/app_settings/shaders/class1/deferred/cofF.glsl index fef1c5a584..079d8458c9 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/cofF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/cofF.glsl @@ -50,15 +50,6 @@ uniform vec2 screen_res; VARYING vec2 vary_fragcoord; -float getDepth(vec2 pos_screen) -{ - float z = texture2DRect(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; - return p.z/p.w; -} - float calc_cof(float depth) { float sc = (depth-focal_distance)/-depth*blur_constant; @@ -77,8 +68,12 @@ float calc_cof(float depth) void main() { vec2 tc = vary_fragcoord.xy; - - float depth = getDepth(tc); + + float z = texture2DRect(depthMap, tc).r; + z = z*2.0-1.0; + vec4 ndc = vec4(0.0, 0.0, z, 1.0); + vec4 p = inv_proj*ndc; + float depth = p.z/p.w; vec4 diff = texture2DRect(diffuseRect, vary_fragcoord.xy); diff --git a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl new file mode 100644 index 0000000000..e27bbce094 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl @@ -0,0 +1,79 @@ +/** + * @file class1/deferred/deferredUtil.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 normalMap; +uniform sampler2DRect depthMap; + +uniform mat4 inv_proj; +uniform vec2 screen_res; + +vec2 getScreenCoordinate(vec2 screenpos) +{ + vec2 sc = screenpos.xy * 2.0; + if (screen_res.x > 0 && screen_res.y > 0) + { + sc /= screen_res; + } + return sc - vec2(1.0, 1.0); +} + +vec3 getNorm(vec2 screenpos) +{ + vec2 enc = texture2DRect(normalMap, screenpos.xy).xy; + 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; +} + +float getDepth(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen).r; + return depth; +} + +vec4 getPosition(vec2 pos_screen) +{ + float depth = getDepth(pos_screen); + vec2 sc = getScreenCoordinate(pos_screen); + 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 getPositionWithDepth(vec2 pos_screen, float depth) +{ + vec2 sc = getScreenCoordinate(pos_screen); + 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; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl index 7930b5d18b..b328ee9483 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl @@ -23,6 +23,8 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_data[3]; #else @@ -37,11 +39,7 @@ VARYING vec3 vary_normal; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} +vec2 encode_normal(vec3 n); void main() { diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl index 8525e13333..fc5c86b4d6 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl @@ -23,6 +23,8 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_data[3]; #else @@ -36,11 +38,7 @@ uniform float minimum_alpha; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} +vec2 encode_normal(vec3 n); void main() { diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl index 37d70a2412..1bb8eb8bd0 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl @@ -23,6 +23,7 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_data[3]; @@ -37,11 +38,7 @@ uniform sampler2D diffuseMap; VARYING vec3 vary_normal; VARYING vec2 vary_texcoord0; -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} +vec2 encode_normal(vec3 n); void main() { diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl index 6befb1bd8b..8319e61242 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl @@ -22,6 +22,8 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ + +/*[EXTRA_CODE_HERE]*/ #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_data[3]; @@ -35,11 +37,7 @@ VARYING vec3 vary_normal; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} +vec2 encode_normal(vec3 n); void main() { diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl index adc361d7a2..ccd1df84f9 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl @@ -23,6 +23,8 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_data[3]; #else @@ -33,17 +35,13 @@ VARYING vec3 vary_normal; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} - +vec2 encode_normal(vec3 n); +vec3 linear_to_srgb(vec3 c); void main() { vec3 col = vertex_color.rgb * diffuseLookup(vary_texcoord0.xy).rgb; - + vec3 spec; spec.rgb = vec3(vertex_color.a); diff --git a/indra/newview/app_settings/shaders/class1/deferred/emissiveF.glsl b/indra/newview/app_settings/shaders/class1/deferred/emissiveF.glsl index 0ffca8515c..f0522850de 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/emissiveF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/emissiveF.glsl @@ -44,7 +44,6 @@ void main() float shadow = 1.0; vec4 color = diffuseLookup(vary_texcoord0.xy)*vertex_color; - color.rgb = pow(color.rgb, vec3(2.2)); color.rgb = fullbrightAtmosTransport(color.rgb); color.rgb = fullbrightScaleSoftClip(color.rgb); diff --git a/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl b/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl index 115b04797f..5e4f08b017 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl @@ -34,11 +34,8 @@ ATTRIBUTE vec2 texcoord0; void calcAtmospherics(vec3 inPositionEye); -vec3 atmosAmbient(vec3 light); +vec3 atmosAmbient(); vec3 atmosAffectDirectionalLight(float lightIntensity); -vec3 scaleDownLight(vec3 light); -vec3 scaleUpLight(vec3 light); - VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl index 756e625d07..57420158ca 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl @@ -1,5 +1,5 @@ /** - * @file fullbrightF.glsl + * @file deferred/fullbrightF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -33,7 +33,7 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -#if !HAS_DIFFUSE_LOOKUP +#if !defined(HAS_DIFFUSE_LOOKUP) uniform sampler2D diffuseMap; #endif @@ -41,108 +41,22 @@ VARYING vec3 vary_position; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; - -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)); - -#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 - -} - -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); +#ifdef WATER_FOG +vec4 applyWaterFogView(vec3 pos, vec4 color); #endif -} - -vec3 fullbrightAtmosTransportDeferred(vec3 light) -{ - return light; -} - -vec3 fullbrightScaleSoftClipDeferred(vec3 light) -{ - //soft clip effect: - return light; -} +vec3 srgb_to_linear(vec3 cs); +vec3 linear_to_srgb(vec3 cl); +vec3 fullbrightAtmosTransport(vec3 light); +vec3 fullbrightScaleSoftClip(vec3 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() { -#if HAS_DIFFUSE_LOOKUP +#ifdef HAS_DIFFUSE_LOOKUP vec4 color = diffuseLookup(vary_texcoord0.xy); #else vec4 color = texture2D(diffuseMap, vary_texcoord0.xy); @@ -158,19 +72,14 @@ void main() #endif color.rgb *= vertex_color.rgb; - color.rgb = srgb_to_linear(color.rgb); - color.rgb = fullbrightAtmosTransportDeferred(color.rgb); - color.rgb = fullbrightScaleSoftClipDeferred(color.rgb); - - color.rgb = linear_to_srgb(color.rgb); #ifdef WATER_FOG vec3 pos = vary_position; - vec4 fogged = applyWaterFogDeferred(pos, vec4(color.rgb, final_alpha)); + vec4 fogged = applyWaterFogView(pos, vec4(color.rgb, final_alpha)); color.rgb = fogged.rgb; color.a = fogged.a; #else - color.a = final_alpha; + color.a = final_alpha; #endif frag_color.rgb = color.rgb; diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl index b0db9876d3..9fcee04c32 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ - +/*[EXTRA_CODE_HERE]*/ #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,41 +31,75 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -#ifndef diffuseLookup +#ifndef HAS_DIFFUSE_LOOKUP uniform sampler2D diffuseMap; #endif VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; VARYING vec3 vary_texcoord1; +VARYING vec4 vary_position; uniform samplerCube environmentMap; +// render_hud_attachments() -> HUD objects set LLShaderMgr::NO_ATMO; used in LLDrawPoolAlpha::beginRenderPass() +uniform int no_atmo; + vec3 fullbrightShinyAtmosTransport(vec3 light); +vec3 fullbrightAtmosTransportFrag(vec3 light, vec3 additive, vec3 atten); vec3 fullbrightScaleSoftClip(vec3 light); +void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten, bool use_ao); + +vec3 linear_to_srgb(vec3 c); +vec3 srgb_to_linear(vec3 c); + +// See: +// class1\deferred\fullbrightShinyF.glsl +// class1\lighting\lightFullbrightShinyF.glsl void main() { -#if HAS_DIFFUSE_LOOKUP +#ifdef HAS_DIFFUSE_LOOKUP vec4 color = diffuseLookup(vary_texcoord0.xy); #else vec4 color = texture2D(diffuseMap, vary_texcoord0.xy); #endif - color.rgb *= vertex_color.rgb; + + // SL-9632 HUDs are affected by Atmosphere + if (no_atmo == 0) + { + vec3 sunlit; + vec3 amblit; + vec3 additive; + vec3 atten; + vec3 pos = vary_position.xyz/vary_position.w; + + calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten, false); vec3 envColor = textureCube(environmentMap, vary_texcoord1.xyz).rgb; - color.rgb = mix(color.rgb, envColor.rgb, vertex_color.a); + float env_intensity = vertex_color.a; - color.rgb = pow(color.rgb,vec3(2.2f,2.2f,2.2f)); - - color.rgb = fullbrightShinyAtmosTransport(color.rgb); + //color.rgb = srgb_to_linear(color.rgb); + color.rgb = mix(color.rgb, envColor.rgb, env_intensity); + color.rgb = fullbrightAtmosTransportFrag(color.rgb, additive, atten); color.rgb = fullbrightScaleSoftClip(color.rgb); + } + +/* + // NOTE: HUD objects will be full bright. Uncomment if you want "some" environment lighting effecting these HUD objects. + else + { + vec3 envColor = textureCube(environmentMap, vary_texcoord1.xyz).rgb; + float env_intensity = vertex_color.a; + color.rgb = mix(color.rgb, envColor.rgb, env_intensity); + } +*/ color.a = 1.0; - color.rgb = pow(color.rgb, vec3(1.0/2.2)); + //color.rgb = linear_to_srgb(color.rgb); 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 index 34bd8d445a..8f6eb79668 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl @@ -45,7 +45,7 @@ ATTRIBUTE vec2 texcoord0; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; VARYING vec3 vary_texcoord1; - +VARYING vec4 vary_position; void main() { @@ -53,7 +53,7 @@ void main() vec4 vert = vec4(position.xyz,1.0); passTextureIndex(); vec4 pos = (modelview_matrix * vert); - gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); + vary_position = gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); vec3 norm = normalize(normal_matrix * normal); vec3 ref = reflect(pos.xyz, -norm); diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl index 8e899e3e0f..bdf3546aa5 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl @@ -35,10 +35,8 @@ ATTRIBUTE vec2 texcoord0; void calcAtmospherics(vec3 inPositionEye); -vec3 atmosAmbient(vec3 light); +vec3 atmosAmbient(); vec3 atmosAffectDirectionalLight(float lightIntensity); -vec3 scaleDownLight(vec3 light); -vec3 scaleUpLight(vec3 light); #ifdef WATER_FOG VARYING vec3 vary_position; diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl index f8fdde43f9..eb6e56e718 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl @@ -23,6 +23,8 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_data[3]; #else @@ -38,41 +40,7 @@ uniform sampler2D specularMap; VARYING vec2 vary_texcoord0; -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; -} - -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} - -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 - -} +vec3 linear_to_srgb(vec3 c); void main() { @@ -87,7 +55,6 @@ void main() 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/indirect.glsl b/indra/newview/app_settings/shaders/class1/deferred/indirect.glsl new file mode 100644 index 0000000000..49bfa660f8 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/indirect.glsl @@ -0,0 +1,30 @@ +/** + * @file class1/deferred/indirect.glsl + * + * $LicenseInfo:firstyear=2018&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 getIndirect(vec3 ambient, vec3 norm, vec3 pos, vec2 pos_screen) +{ + return ambient; +} + diff --git a/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl b/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl index dcf474824d..be1003a7e0 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl @@ -22,8 +22,8 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - -uniform sampler2DRect diffuseMap; + +/*[EXTRA_CODE_HERE]*/ #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,6 +31,7 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif +uniform sampler2DRect diffuseMap; VARYING vec2 vary_fragcoord; void main() diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl index 07d28ed4cd..e1f7031af6 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl @@ -1,72 +1,56 @@ -/** - * @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 +/** +* @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$ +*/ + +/*[EXTRA_CODE_HERE]*/ + +//class1/deferred/materialF.glsl + +// This shader is used for both writing opaque/masked content to the gbuffer and writing blended content to the framebuffer during the alpha pass. + +#define DIFFUSE_ALPHA_MODE_NONE 0 +#define DIFFUSE_ALPHA_MODE_BLEND 1 +#define DIFFUSE_ALPHA_MODE_MASK 2 #define DIFFUSE_ALPHA_MODE_EMISSIVE 3 -uniform float emissive_brightness; -uniform float display_gamma; +uniform float emissive_brightness; // fullbright flag, 1.0 == fullbright, 0.0 otherwise +uniform int sun_up_factor; -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)); - -#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); +#ifdef WATER_FOG +vec4 applyWaterFogView(vec3 pos, vec4 color); #endif -} +vec3 atmosFragLighting(vec3 l, vec3 additive, vec3 atten); +vec3 scaleSoftClipFrag(vec3 l); -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 +vec3 fullbrightAtmosTransportFrag(vec3 light, vec3 additive, vec3 atten); +vec3 fullbrightScaleSoftClip(vec3 light); -} +void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten, bool use_ao); + +vec3 srgb_to_linear(vec3 cs); +vec3 linear_to_srgb(vec3 cs); #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) @@ -76,404 +60,115 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -#if HAS_SUN_SHADOW - -uniform sampler2DShadow shadowMap0; -uniform sampler2DShadow shadowMap1; -uniform sampler2DShadow shadowMap2; -uniform sampler2DShadow shadowMap3; - -uniform mat4 shadow_matrix[6]; -uniform vec4 shadow_clip; -uniform vec2 shadow_res; -uniform float shadow_bias; - -float pcfShadow(sampler2DShadow shadowMap, vec4 stc) -{ - stc.xyz /= stc.w; - stc.z += shadow_bias; - - stc.x = floor(stc.x*shadow_res.x + fract(stc.y*shadow_res.y*12345))/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; -} - +#ifdef HAS_SUN_SHADOW +float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); #endif uniform samplerCube environmentMap; -uniform sampler2D lightFunc; +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 mat3 ssao_effect_mat; uniform vec3 sun_dir; +uniform vec3 moon_dir; VARYING vec2 vary_fragcoord; VARYING vec3 vary_position; -vec3 vary_PositionEye; - -vec3 vary_SunlitColor; -vec3 vary_AmblitColor; -vec3 vary_AdditiveColor; -vec3 vary_AtmosAttenuation; - +uniform mat4 proj_mat; uniform mat4 inv_proj; uniform vec2 screen_res; uniform vec4 light_position[8]; uniform vec3 light_direction[8]; -uniform vec3 light_attenuation[8]; +uniform vec4 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)); - -} - -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; - pos /= pos.w; - pos.w = 1.0; - return pos; -} - -#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; -} +float getAmbientClamp(); -void setAmblitColor(vec3 v) +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, float ambiance) { - vary_AmblitColor = v; -} - -void setAdditiveColor(vec3 v) -{ - vary_AdditiveColor = v; -} - -void setAtmosAttenuation(vec3 v) -{ - vary_AtmosAttenuation = v; -} - -void calcAtmospherics(vec3 inPositionEye, float ambFactor) { - - 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; - - /* decrease value and saturation (that in HSV, not HSL) for occluded areas - * // for HSV color/geometry used here, see http://gimp-savvy.com/BOOK/index.html?node52.html - * // The following line of code performs the equivalent of: - * float ambAlpha = tmpAmbient.a; - * float ambValue = dot(vec3(tmpAmbient), vec3(0.577)); // projection onto <1/rt(3), 1/rt(3), 1/rt(3)>, the neutral white-black axis - * vec3 ambHueSat = vec3(tmpAmbient) - vec3(ambValue); - * tmpAmbient = vec4(RenderSSAOEffect.valueFactor * vec3(ambValue) + RenderSSAOEffect.saturationFactor *(1.0 - ambFactor) * ambHueSat, ambAlpha); - */ - tmpAmbient = vec4(mix(ssao_effect_mat * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a); - - //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; + vec3 col = vec3(0); + + //get light vector + vec3 lv = lp.xyz - v; + + //get distance + float dist = length(lv); + float da = 1.0; + + dist /= la; + + if (dist > 0.0 && la > 0.0) + { + //normalize light vector + lv = normalize(lv); + + //distance attenuation + float dist_atten = clamp(1.0 - (dist - 1.0*(1.0 - fa)) / fa, 0.0, 1.0); + dist_atten *= dist_atten; + dist_atten *= 2.0f; + + if (dist_atten <= 0.0) + { + return col; + } + + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 + + //angular attenuation + da *= dot(n, lv); + + float lit = 0.0f; + + float amb_da = ambiance; + if (da >= 0) + { + lit = max(da * dist_atten, 0.0); + col = lit * light_col * diffuse; + amb_da += (da*0.5 + 0.5) * ambiance; + } + amb_da += (da*da*0.5 + 0.5) * ambiance; + amb_da *= dist_atten; + amb_da = min(amb_da, 1.0f - lit); + + // SL-10969 need to see why these are blown out + //col.rgb += amb_da * light_col * 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; + speccol = clamp(speccol, vec3(0), vec3(1)); + 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); + } + } + } + + return max(col, vec3(0.0, 0.0, 0.0)); } #else @@ -484,13 +179,13 @@ out vec4 frag_data[3]; #endif #endif -uniform sampler2D diffuseMap; +uniform sampler2D diffuseMap; //always in sRGB space -#if HAS_NORMAL_MAP +#ifdef HAS_NORMAL_MAP uniform sampler2D bumpMap; #endif -#if HAS_SPECULAR_MAP +#ifdef HAS_SPECULAR_MAP uniform sampler2D specularMap; VARYING vec2 vary_texcoord2; @@ -503,7 +198,7 @@ uniform vec4 specular_color; // specular color RGB and specular exponent (gloss uniform float minimum_alpha; #endif -#if HAS_NORMAL_MAP +#ifdef HAS_NORMAL_MAP VARYING vec3 vary_mat0; VARYING vec3 vary_mat1; VARYING vec3 vary_mat2; @@ -515,33 +210,23 @@ VARYING vec3 vary_normal; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} +vec2 encode_normal(vec3 n); -vec3 decode_normal (vec2 enc) +void main() { - 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; -} + vec2 pos_screen = vary_texcoord0.xy; -void main() -{ - vec4 diffcol = texture2D(diffuseMap, vary_texcoord0.xy); + 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; - } + + // Comparing floats cast from 8-bit values, produces acne right at the 8-bit transition points + float bias = 0.001953125; // 1/512, or half an 8-bit quantization + if (diffcol.a < minimum_alpha-bias) + { + discard; + } #endif #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) @@ -549,14 +234,14 @@ void main() diffcol.rgb = srgb_to_linear(diffcol.rgb); #endif -#if HAS_SPECULAR_MAP - vec4 spec = texture2D(specularMap, vary_texcoord2.xy); - spec.rgb *= specular_color.rgb; +#ifdef HAS_SPECULAR_MAP + vec4 spec = texture2D(specularMap, vary_texcoord2.xy); + spec.rgb *= specular_color.rgb; #else - vec4 spec = vec4(specular_color.rgb, 1.0); + vec4 spec = vec4(specular_color.rgb, 1.0); #endif -#if HAS_NORMAL_MAP +#ifdef HAS_NORMAL_MAP vec4 norm = texture2D(bumpMap, vary_texcoord1.xy); norm.xyz = norm.xyz * 2 - 1; @@ -569,220 +254,192 @@ void main() vec3 tnorm = vary_normal; #endif - norm.xyz = tnorm; - norm.xyz = normalize(norm.xyz); + norm.xyz = normalize(tnorm.xyz); - vec2 abnormal = encode_normal(norm.xyz); - norm.xyz = decode_normal(abnormal.xy); + vec2 abnormal = encode_normal(norm.xyz); + + vec4 final_color = diffcol; - 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); + vec4 final_specular = spec; + +#ifdef 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 - 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)*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)*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)*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)*w; - weight += w; - } - - - shadow /= weight; - } - else - { - shadow = 1.0; - } -#else - float shadow = 1.0; + + //forward rendering, output just lit sRGBA + vec3 pos = vary_position; + + float shadow = 1.0f; + +#ifdef HAS_SUN_SHADOW + shadow = sampleDirectionalShadow(pos.xyz, norm.xyz, pos_screen); #endif - spec = final_specular; - vec4 diffuse = final_color; - float envIntensity = final_normal.z; + spec = final_specular; + vec4 diffuse = final_color; + float envIntensity = final_normal.z; + + vec3 color = vec3(0,0,0); + + vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; + + float bloom = 0.0; + vec3 sunlit; + vec3 amblit; + vec3 additive; + vec3 atten; + + calcAtmosphericVars(pos.xyz, light_dir, 1.0, sunlit, amblit, additive, atten, false); + + // This call breaks the Mac GLSL compiler/linker for unknown reasons (17Mar2020) + // The call is either a no-op or a pure (pow) gamma adjustment, depending on GPU level + // TODO: determine if we want to re-apply the gamma adjustment, and if so understand & fix Mac breakage + //color = fullbrightScaleSoftClip(color); + + vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); - vec3 col = vec3(0.0f,0.0f,0.0f); + //we're in sRGB space, so gamma correct this dot product so + // lighting from the sun stays sharp + float da = clamp(dot(normalize(norm.xyz), light_dir.xyz), 0.0, 1.0); + da = pow(da, 1.0 / 1.3); - float bloom = 0.0; - calcAtmospherics(pos.xyz, 1.0); - - vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); + color = amblit; - float da =dot(norm.xyz, sun_dir.xyz); + //darken ambient for normals perpendicular to light vector so surfaces in shadow + // and facing away from light still have some definition to them. + // do NOT gamma correct this dot product so ambient lighting stays soft + float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0); + ambient *= 0.5; + ambient *= ambient; + ambient = (1.0 - ambient); - 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); + vec3 sun_contrib = min(da, shadow) * sunlit; + + color *= ambient; - col.rgb = atmosAmbient(col); - - float ambient = min(abs(da), 1.0); - ambient *= 0.5; - ambient *= ambient; - ambient = (1.0-ambient); + color += sun_contrib; - col.rgb *= ambient; + color *= gamma_diff.rgb; - col.rgb = col.rgb + atmosAffectDirectionalLight(final_da); + float glare = 0.0; - col.rgb *= gamma_diff.rgb; - + if (spec.a > 0.0) // specular reflection + { + /* // Reverting this specular calculation to previous 'dumbshiny' version - DJH 6/17/2020 + // Preserving the refactored version as a comment for potential reconsideration, + // overriding the general rule to avoid pollutiong the source with commented code. + // + // If you're reading this in 2021+, feel free to obliterate. - float glare = 0.0; + vec3 npos = -normalize(pos.xyz); - 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; + //vec3 ref = dot(pos+lv, norm); + vec3 h = normalize(light_dir.xyz + npos); + float nh = dot(norm.xyz, h); + float nv = dot(norm.xyz, npos); + float vh = dot(npos, h); + float sa = nh; + float fres = pow(1 - dot(h, npos), 5)*0.4 + 0.5; - glare = max(spec_contrib.r, spec_contrib.g); - glare = max(glare, spec_contrib.b); + float gtdenom = 2 * nh; + float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh)); - col += spec_contrib; - } + if (nh > 0.0) + { + float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt / (nh*da); + vec3 sp = sun_contrib*scol / 6.0f; + sp = clamp(sp, vec3(0), vec3(1)); + bloom = dot(sp, sp) / 4.0; + color += sp * spec.rgb; + } + */ + float sa = dot(refnormpersp, sun_dir.xyz); + vec3 dumbshiny = sunlit * shadow * (texture2D(lightFunc, vec2(sa, spec.a)).r); - col = mix(col.rgb, diffcol.rgb, diffuse.a); + // add the two types of shiny together + vec3 spec_contrib = dumbshiny * spec.rgb; + bloom = dot(spec_contrib, spec_contrib) / 6; - if (envIntensity > 0.0) - { - //add environmentmap - vec3 env_vec = env_mat * refnormpersp; - - vec3 refcol = textureCube(environmentMap, env_vec).rgb; + glare = max(spec_contrib.r, spec_contrib.g); + glare = max(glare, spec_contrib.b); - col = mix(col.rgb, refcol, - envIntensity); + color += spec_contrib; + } - float cur_glare = max(refcol.r, refcol.g); - cur_glare = max(cur_glare, refcol.b); - cur_glare *= envIntensity*4.0; - glare += cur_glare; - } + color = mix(color.rgb, diffcol.rgb, diffuse.a); - //col = mix(atmosLighting(col), fullbrightAtmosTransport(col), diffuse.a); - //col = mix(scaleSoftClip(col), fullbrightScaleSoftClip(col), diffuse.a); + if (envIntensity > 0.0) + { + //add environmentmap + vec3 env_vec = env_mat * refnormpersp; - col = atmosLighting(col); - col = scaleSoftClip(col); + vec3 reflected_color = textureCube(environmentMap, env_vec).rgb; - //convert to linear space before adding local lights - col = srgb_to_linear(col); + color = mix(color, reflected_color, envIntensity); - vec3 npos = normalize(-pos.xyz); - - vec3 light = vec3(0,0,0); + float cur_glare = max(reflected_color.r, reflected_color.g); + cur_glare = max(cur_glare, reflected_color.b); + cur_glare *= envIntensity*4.0; + glare += cur_glare; + } - #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); + color = atmosFragLighting(color, additive, atten); + color = scaleSoftClipFrag(color); - LIGHT_LOOP(1) - LIGHT_LOOP(2) - LIGHT_LOOP(3) - LIGHT_LOOP(4) - LIGHT_LOOP(5) - LIGHT_LOOP(6) - LIGHT_LOOP(7) + //convert to linear before adding local lights + color = srgb_to_linear(color); - col.rgb += light.rgb; + vec3 npos = normalize(-pos.xyz); - glare = min(glare, 1.0); - float al = max(diffcol.a,glare)*vertex_color.a; + vec3 light = vec3(0, 0, 0); + + final_specular.rgb = srgb_to_linear(final_specular.rgb); // SL-14035 - //convert to gamma space for display on screen - col.rgb = linear_to_srgb(col.rgb); +#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_attenuation[i].w ); + + LIGHT_LOOP(1) + LIGHT_LOOP(2) + LIGHT_LOOP(3) + LIGHT_LOOP(4) + LIGHT_LOOP(5) + LIGHT_LOOP(6) + LIGHT_LOOP(7) + + color += light; + + glare = min(glare, 1.0); + float al = max(diffcol.a, glare)*vertex_color.a; + + //convert to srgb as this color is being written post gamma correction + color = linear_to_srgb(color); #ifdef WATER_FOG - vec4 temp = applyWaterFogDeferred(pos, vec4(col.rgb, al)); - col.rgb = temp.rgb; - al = temp.a; + vec4 temp = applyWaterFogView(pos, vec4(color, al)); + color = temp.rgb; + al = temp.a; #endif - frag_color.rgb = col.rgb; - frag_color.a = al; + frag_color = vec4(color, 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. +#else // mode is not DIFFUSE_ALPHA_MODE_BLEND, encode to gbuffer + + // deferred path + frag_data[0] = final_color; //gbuffer is sRGB + 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 index 393d1e69da..7e29ada205 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl @@ -28,7 +28,7 @@ #define DIFFUSE_ALPHA_MODE_MASK 2 #define DIFFUSE_ALPHA_MODE_EMISSIVE 3 -#if HAS_SKIN +#ifdef HAS_SKIN uniform mat4 modelview_matrix; uniform mat4 projection_matrix; mat4 getObjectSkinnedTransform(); @@ -39,7 +39,7 @@ uniform mat4 modelview_projection_matrix; #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) -#if !HAS_SKIN +#if !defined(HAS_SKIN) uniform mat4 modelview_matrix; #endif @@ -55,7 +55,7 @@ ATTRIBUTE vec3 normal; ATTRIBUTE vec2 texcoord0; -#if HAS_NORMAL_MAP +#ifdef HAS_NORMAL_MAP ATTRIBUTE vec4 tangent; ATTRIBUTE vec2 texcoord1; @@ -68,7 +68,7 @@ VARYING vec2 vary_texcoord1; VARYING vec3 vary_normal; #endif -#if HAS_SPECULAR_MAP +#ifdef HAS_SPECULAR_MAP ATTRIBUTE vec2 texcoord2; VARYING vec2 vary_texcoord2; #endif @@ -78,7 +78,7 @@ VARYING vec2 vary_texcoord0; void main() { -#if HAS_SKIN +#ifdef HAS_SKIN mat4 mat = getObjectSkinnedTransform(); mat = modelview_matrix * mat; @@ -99,17 +99,17 @@ void main() vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; -#if HAS_NORMAL_MAP +#ifdef HAS_NORMAL_MAP vary_texcoord1 = (texture_matrix0 * vec4(texcoord1,0,1)).xy; #endif -#if HAS_SPECULAR_MAP +#ifdef HAS_SPECULAR_MAP vary_texcoord2 = (texture_matrix0 * vec4(texcoord2,0,1)).xy; #endif -#if HAS_SKIN +#ifdef HAS_SKIN vec3 n = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz); -#if HAS_NORMAL_MAP +#ifdef HAS_NORMAL_MAP vec3 t = normalize((mat*vec4(tangent.xyz+position.xyz,1.0)).xyz-pos.xyz); vec3 b = cross(n, t)*tangent.w; @@ -121,7 +121,7 @@ vary_normal = n; #endif //HAS_NORMAL_MAP #else //HAS_SKIN vec3 n = normalize(normal_matrix * normal); -#if HAS_NORMAL_MAP +#ifdef HAS_NORMAL_MAP vec3 t = normalize(normal_matrix * tangent.xyz); vec3 b = cross(n,t)*tangent.w; //vec3 t = cross(b,n) * binormal.w; @@ -137,7 +137,7 @@ vary_normal = n; vertex_color = diffuse_color; #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) -#if !HAS_SKIN +#if !defined(HAS_SKIN) vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz; #endif #endif diff --git a/indra/newview/app_settings/shaders/class1/deferred/moonF.glsl b/indra/newview/app_settings/shaders/class1/deferred/moonF.glsl new file mode 100644 index 0000000000..35068899ee --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/moonF.glsl @@ -0,0 +1,73 @@ +/** + * @file class1\deferred\moonF.glsl + * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2005, 2020 Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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 + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_data[3]; +#else +#define frag_data gl_FragData +#endif + +uniform vec4 color; +uniform vec4 sunlight_color; +uniform vec4 moonlight_color; +uniform vec3 moon_dir; +uniform float moon_brightness; +uniform sampler2D diffuseMap; + +VARYING vec2 vary_texcoord0; + +vec3 srgb_to_linear(vec3 c); + +/// Soft clips the light with a gamma correction +vec3 scaleSoftClip(vec3 light); + +void main() +{ + // Restore Pre-EEP alpha fade moon near horizon + float fade = 1.0; + if( moon_dir.z > 0 ) + fade = clamp( moon_dir.z*moon_dir.z*4.0, 0.0, 1.0 ); + + vec4 c = texture2D(diffuseMap, vary_texcoord0.xy); +// c.rgb = srgb_to_linear(c.rgb); + c.rgb *= moonlight_color.rgb; + c.rgb *= moon_brightness; + + c.rgb *= fade; + c.a *= fade; + + c.rgb = scaleSoftClip(c.rgb); + + frag_data[0] = vec4(c.rgb, c.a); + frag_data[1] = vec4(0.0); + frag_data[2] = vec4(0.0f); + + gl_FragDepth = 0.999985f; +} + diff --git a/indra/newview/app_settings/shaders/class1/deferred/moonV.glsl b/indra/newview/app_settings/shaders/class1/deferred/moonV.glsl new file mode 100644 index 0000000000..c4922afd7d --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/moonV.glsl @@ -0,0 +1,44 @@ +/** + * @file class1\deferred\moonV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 2020 Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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_matrix; +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec2 texcoord0; + +VARYING vec2 vary_texcoord0; + +void main() +{ + //transform vertex + vec4 vert = vec4(position.xyz, 1.0); + vec4 pos = (modelview_matrix * vert); + + gl_Position = modelview_projection_matrix*vert; + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl index 9974f8f31b..09c47165dd 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl @@ -1,24 +1,24 @@ -/** - * @file multiPointLightF.glsl +/** + * @file class1/deferred/multiPointLightF.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$ */ @@ -36,139 +36,110 @@ out vec4 frag_color; uniform sampler2DRect depthMap; uniform sampler2DRect diffuseRect; uniform sampler2DRect specularRect; -uniform sampler2DRect normalMap; -uniform samplerCube environmentMap; -uniform sampler2D noiseMap; -uniform sampler2D lightFunc; - +uniform samplerCube environmentMap; +uniform sampler2D noiseMap; +uniform sampler2D lightFunc; -uniform vec3 env_mat[3]; +uniform vec3 env_mat[3]; uniform float sun_wash; +uniform int light_count; +uniform vec4 light[LIGHT_COUNT]; +uniform vec4 light_col[LIGHT_COUNT]; -uniform int light_count; - -uniform vec4 light[LIGHT_COUNT]; -uniform vec4 light_col[LIGHT_COUNT]; - -VARYING vec4 vary_fragcoord; -uniform vec2 screen_res; - +uniform vec2 screen_res; uniform float far_z; +uniform mat4 inv_proj; -uniform mat4 inv_proj; +VARYING vec4 vary_fragcoord; -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} +vec4 getPosition(vec2 pos_screen); +vec3 getNorm(vec2 pos_screen); +vec3 srgb_to_linear(vec3 c); -vec3 decode_normal (vec2 enc) +void main() { - 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 = 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; -} +#if defined(LOCAL_LIGHT_KILL) + discard; // Bail immediately +#endif -void main() -{ - vec2 frag = (vary_fragcoord.xy*0.5+0.5)*screen_res; - vec3 pos = getPosition(frag.xy).xyz; - if (pos.z < far_z) - { - discard; - } - - vec3 norm = texture2DRect(normalMap, frag.xy).xyz; - norm = decode_normal(norm.xy); // unpack norm - norm = normalize(norm); - vec4 spec = texture2DRect(specularRect, frag.xy); - vec3 diff = texture2DRect(diffuseRect, frag.xy).rgb; - - float noise = texture2D(noiseMap, frag.xy/128.0).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 < LIGHT_COUNT; ++i) - { - vec3 lv = light[i].xyz-pos; - float dist = length(lv); - dist /= light[i].w; - if (dist <= 1.0) - { - float da = dot(norm, lv); - 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-(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); - 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 += lit*scol*light_col[i].rgb*spec.rgb; - //col += spec.rgb; - } - } - - out_col += col; - } - } - } - - - frag_color.rgb = out_col; - frag_color.a = 0.0; + vec3 out_col = vec3(0, 0, 0); + vec2 frag = (vary_fragcoord.xy * 0.5 + 0.5) * screen_res; + vec3 pos = getPosition(frag.xy).xyz; + if (pos.z < far_z) + { + discard; + } + + vec3 norm = getNorm(frag.xy); + + vec4 spec = texture2DRect(specularRect, frag.xy); + vec3 diff = texture2DRect(diffuseRect, frag.xy).rgb; + + float noise = texture2D(noiseMap, frag.xy / 128.0).b; + 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 < LIGHT_COUNT; ++i) + { + vec3 lv = light[i].xyz - pos; + float dist = length(lv); + dist /= light[i].w; + if (dist <= 1.0) + { + float da = dot(norm, lv); + 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 - (dist - 1.0 * (1.0 - fa)) / fa, 0.0, 1.0); + dist_atten *= dist_atten; + + // Tweak falloff slightly to match pre-EEP attenuation + // NOTE: this magic number also shows up in a great many other places, search for dist_atten *= to audit + dist_atten *= 2.0; + + dist_atten *= noise; + + float lit = da * dist_atten; + + vec3 col = light_col[i].rgb * lit * diff; + + if (spec.a > 0.0) + { + lit = min(da * 6.0, 1.0) * dist_atten; + 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 += lit * scol * light_col[i].rgb * spec.rgb; + } + } + + out_col += col; + } + } + } + + frag_color.rgb = out_col; + frag_color.a = 0.0; #ifdef IS_AMD_CARD - // If it's AMD make sure the GLSL compiler sees the arrays referenced once by static index. Otherwise it seems to optimise the storage awawy which leads to unfun crashes and artifacts. - vec4 dummy1 = light[0]; - vec4 dummy2 = light_col[0]; - vec4 dummy3 = light[LIGHT_COUNT-1]; - vec4 dummy4 = light_col[LIGHT_COUNT-1]; + // If it's AMD make sure the GLSL compiler sees the arrays referenced once by static index. Otherwise it seems to optimise the storage + // awawy which leads to unfun crashes and artifacts. + vec4 dummy1 = light[0]; + vec4 dummy2 = light_col[0]; + vec4 dummy3 = light[LIGHT_COUNT - 1]; + vec4 dummy4 = light_col[LIGHT_COUNT - 1]; #endif } diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl index 3a3e871ade..ec3fb9c543 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl @@ -30,14 +30,14 @@ #extension GL_ARB_texture_rectangle : enable #extension GL_ARB_shader_texture_lod : enable +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; #else #define frag_color gl_FragColor #endif -/*[EXTRA_CODE_HERE]*/ - uniform sampler2DRect diffuseRect; uniform sampler2DRect specularRect; uniform sampler2DRect depthMap; @@ -71,60 +71,8 @@ VARYING vec4 vary_fragcoord; uniform vec2 screen_res; uniform mat4 inv_proj; - -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; -} -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)); - -#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 - -} - -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 - -} - +vec3 getNorm(vec2 pos_screen); +vec3 srgb_to_linear(vec3 c); vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) { @@ -178,22 +126,15 @@ 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; -} +vec4 getPosition(vec2 pos_screen); void main() { + vec3 col = vec3(0,0,0); + +#if defined(LOCAL_LIGHT_KILL) + discard; +#else vec4 frag = vary_fragcoord; frag.xyz /= frag.w; frag.xyz = frag.xyz*0.5+0.5; @@ -208,12 +149,9 @@ void main() discard; } - vec3 norm = texture2DRect(normalMap, frag.xy).xyz; - float envIntensity = norm.z; + float envIntensity = texture2DRect(normalMap, frag.xy).z; + vec3 norm = getNorm(frag.xy); - norm = decode_normal(norm.xy); - - norm = normalize(norm); float l_dist = -dot(lv, proj_n); vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0)); @@ -225,25 +163,29 @@ void main() proj_tc.xyz /= proj_tc.w; float fa = falloff+1.0; - float dist_atten = min(1.0-(dist-1.0*(1.0-fa))/fa, 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; + if (dist_atten <= 0.0) { discard; } + float noise = texture2D(noiseMap, frag.xy/128.0).b; + dist_atten *= noise; + 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; + vec3 dlit = vec3(0, 0, 0); - float noise = texture2D(noiseMap, frag.xy/128.0).b; + if (proj_tc.z > 0.0 && proj_tc.x < 1.0 && proj_tc.y < 1.0 && @@ -262,7 +204,7 @@ void main() dlit = color.rgb * plcol.rgb * plcol.a; - lit = da * dist_atten * noise; + lit = da * dist_atten; col = dlit*lit*diff_tex; amb_da += (da*0.5)*proj_ambiance; @@ -304,7 +246,7 @@ void main() col += dlit*scol*spec.rgb; //col += spec.rgb; } - } + } if (envIntensity > 0.0) { @@ -334,7 +276,9 @@ void main() } } } - +#endif + + //output linear, sum of lights will be gamma corrected later frag_color.rgb = col; frag_color.a = 0.0; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl index aba4a01754..18616a9bb3 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl @@ -56,103 +56,77 @@ uniform vec2 screen_res; uniform mat4 inv_proj; uniform vec4 viewport; -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 = 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 getNorm(vec2 pos_screen); +vec4 getPosition(vec2 pos_screen); +vec3 srgb_to_linear(vec3 c); 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 dist = length(lv); - dist /= size; - if (dist > 1.0) - { - discard; - } - - vec3 norm = texture2DRect(normalMap, frag.xy).xyz; - norm = decode_normal(norm.xy); // unpack norm - float da = dot(norm, lv); - if (da < 0.0) - { - discard; - } - - norm = normalize(norm); - lv = normalize(lv); - da = dot(norm, lv); - - float noise = texture2D(noiseMap, frag.xy/128.0).b; - - vec3 col = texture2DRect(diffuseRect, frag.xy).rgb; - float fa = falloff+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; - - float lit = da * dist_atten * noise; - - col = color.rgb*lit*col; - - vec4 spec = texture2DRect(specularRect, frag.xy); - if (spec.a > 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) - { - float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da); - col += lit*scol*color.rgb*spec.rgb; - } - } - - if (dot(col, col) <= 0.0) - { - discard; - } - - frag_color.rgb = col; - frag_color.a = 0.0; + 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 dist = length(lv); + dist /= size; + if (dist > 1.0) + { + discard; + } + + vec3 norm = getNorm(frag.xy); + + float da = dot(norm, lv); + if (da < 0.0) + { + discard; + } + + lv = normalize(lv); + da = dot(norm, lv); + + float noise = texture2D(noiseMap, frag.xy/128.0).b; + + vec3 col = texture2DRect(diffuseRect, frag.xy).rgb; + + float fa = falloff+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; + + float lit = da * dist_atten * noise; + + col = color.rgb*lit*col; + + vec4 spec = texture2DRect(specularRect, frag.xy); + if (spec.a > 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) + { + float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da); + col += lit*scol*color.rgb*spec.rgb; + } + } + + if (dot(col, col) <= 0.0) + { + discard; + } + + frag_color.rgb = col; + frag_color.a = 0.0; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl index a5625fbc16..3da8531442 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl @@ -1,5 +1,5 @@ /** - * @file pointLightF.glsl + * @file pointLightV.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl index 6669947d1b..cd37a34e0d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl @@ -37,33 +37,16 @@ uniform sampler2DRect diffuseRect; uniform vec2 screen_res; VARYING vec2 vary_fragcoord; - uniform float display_gamma; -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 - -} - +vec3 linear_to_srgb(vec3 cl); void main() { - vec4 diff = texture2DRect(diffuseRect, vary_fragcoord); - diff.rgb = linear_to_srgb(diff.rgb); - frag_color = diff; + //this is the one of the rare spots where diffuseRect contains linear color values (not sRGB) + vec4 diff = texture2DRect(diffuseRect, vary_fragcoord); + //diff.rgb = pow(diff.rgb, vec3(display_gamma)); + diff.rgb = linear_to_srgb(diff.rgb); + frag_color = diff; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl index 018ced4cad..cf994d3547 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl @@ -23,6 +23,8 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; #else @@ -47,18 +49,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/shadowAlphaBlendF.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaBlendF.glsl new file mode 100644 index 0000000000..44f2a73e1f --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaBlendF.glsl @@ -0,0 +1,55 @@ +/** + * @file shadowAlphaMaskF.glsl + * + * $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$ + */ + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2D diffuseMap; + +#if !defined(DEPTH_CLAMP) +VARYING float pos_zd2; +#endif + +VARYING float pos_w; + +VARYING float target_pos_x; +VARYING vec4 vertex_color; +VARYING vec2 vary_texcoord0; + +void main() +{ + float alpha = diffuseLookup(vary_texcoord0.xy).a * vertex_color.a; + + frag_color = vec4(alpha, alpha, alpha, 1); + +#if !defined(DEPTH_CLAMP) + gl_FragDepth = max(pos_zd2/pos_w+0.5, 0.0); +#endif +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaBlendV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaBlendV.glsl new file mode 100644 index 0000000000..f45c343066 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaBlendV.glsl @@ -0,0 +1,67 @@ +/** + * @file shadowAlphaMaskV.glsl + * + * $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$ + */ + +uniform mat4 texture_matrix0; +uniform mat4 modelview_projection_matrix; +uniform float shadow_target_width; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec4 diffuse_color; +ATTRIBUTE vec2 texcoord0; + +#if !defined(DEPTH_CLAMP) +VARYING float pos_zd2; +#endif + +VARYING float pos_w; + +VARYING float target_pos_x; +VARYING vec4 vertex_color; +VARYING vec2 vary_texcoord0; + +void passTextureIndex(); + +void main() +{ + //transform vertex + vec4 pre_pos = vec4(position.xyz, 1.0); + vec4 pos = modelview_projection_matrix * pre_pos; + target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x; + + pos_w = pos.w; + +#if !defined(DEPTH_CLAMP) + pos_zd2 = pos.z * 0.5; + + gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); +#else + gl_Position = pos; +#endif + + passTextureIndex(); + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; + vertex_color = diffuse_color; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskF.glsl index 91a96977f0..9b8df0a5a4 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskF.glsl @@ -23,6 +23,8 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; #else @@ -31,19 +33,25 @@ out vec4 frag_color; uniform sampler2D diffuseMap; -#if !DEPTH_CLAMP -VARYING float pos_zd2; -#endif - -VARYING float pos_w; - +VARYING vec4 post_pos; VARYING float target_pos_x; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; +uniform float minimum_alpha; void main() { - float alpha = diffuseLookup(vary_texcoord0.xy).a * vertex_color.a; + float alpha = diffuseLookup(vary_texcoord0.xy).a; + + // mask cutoff 0 -> no shadow SL-11051 + if (minimum_alpha == 0) + { + discard; + } + +#if !defined(IS_FULLBRIGHT) + alpha *= vertex_color.a; +#endif if (alpha < 0.05) // treat as totally transparent { @@ -52,7 +60,7 @@ void main() if (alpha < 0.88) // treat as semi-transparent { - if (fract(0.5*floor(target_pos_x / pos_w )) < 0.25) + if (fract(0.5*floor(target_pos_x / post_pos.w )) < 0.25) { discard; } @@ -60,7 +68,7 @@ void main() frag_color = vec4(1,1,1,1); -#if !DEPTH_CLAMP - gl_FragDepth = max(pos_zd2/pos_w+0.5, 0.0); +#if !defined(DEPTH_CLAMP) + gl_FragDepth = max(post_pos.z/post_pos.w*0.5+0.5, 0.0); #endif } diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskV.glsl index 11411a605c..b6a0f0b165 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskV.glsl @@ -31,12 +31,7 @@ ATTRIBUTE vec3 position; ATTRIBUTE vec4 diffuse_color; ATTRIBUTE vec2 texcoord0; -#if !DEPTH_CLAMP -VARYING float pos_zd2; -#endif - -VARYING float pos_w; - +VARYING vec4 post_pos; VARYING float target_pos_x; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; @@ -50,11 +45,9 @@ void main() vec4 pos = modelview_projection_matrix * pre_pos; target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x; - pos_w = pos.w; + post_pos = pos; -#if !DEPTH_CLAMP - pos_zd2 = pos.z * 0.5; - +#if !defined(DEPTH_CLAMP) gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); #else gl_Position = pos; diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl index ef153dfc5b..0e74d2eb8a 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl @@ -27,7 +27,7 @@ uniform mat4 modelview_projection_matrix; ATTRIBUTE vec3 position; -#if !DEPTH_CLAMP +#if !defined(DEPTH_CLAMP) VARYING vec4 post_pos; #endif @@ -40,7 +40,7 @@ void main() vec3 p = position*box_size+box_center; vec4 pos = modelview_projection_matrix*vec4(p.xyz, 1.0); -#if !DEPTH_CLAMP +#if !defined(DEPTH_CLAMP) post_pos = pos; gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl index 3d1b182875..1ea96918bb 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl @@ -23,21 +23,21 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; #else #define frag_color gl_FragColor #endif -#if !DEPTH_CLAMP VARYING vec4 post_pos; -#endif void main() { frag_color = vec4(1,1,1,1); -#if !DEPTH_CLAMP +#if !defined(DEPTH_CLAMP) gl_FragDepth = max(post_pos.z/post_pos.w*0.5+0.5, 0.0); #endif diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowUtil.glsl new file mode 100644 index 0000000000..4134220306 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowUtil.glsl @@ -0,0 +1,221 @@ +/** + * @file class1/deferred/shadowUtil.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 normalMap; +uniform sampler2DRect depthMap; +uniform sampler2DShadow shadowMap0; +uniform sampler2DShadow shadowMap1; +uniform sampler2DShadow shadowMap2; +uniform sampler2DShadow shadowMap3; +uniform sampler2DShadow shadowMap4; +uniform sampler2DShadow shadowMap5; + +uniform vec3 sun_dir; +uniform vec3 moon_dir; +uniform vec2 shadow_res; +uniform vec2 proj_shadow_res; +uniform mat4 shadow_matrix[6]; +uniform vec4 shadow_clip; +uniform float shadow_bias; +uniform float shadow_offset; +uniform float spot_shadow_bias; +uniform float spot_shadow_offset; +uniform mat4 inv_proj; +uniform vec2 screen_res; +uniform int sun_up_factor; + +float pcfShadow(sampler2DShadow shadowMap, vec3 norm, vec4 stc, float bias_mul, vec2 pos_screen, vec3 light_dir) +{ + float offset = shadow_bias * bias_mul; + stc.xyz /= stc.w; + stc.z += offset * 2.0; + stc.x = floor(stc.x*shadow_res.x + fract(pos_screen.y*shadow_res.y))/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 * 4.0; + shadow += shadow2D(shadowMap, stc.xyz+vec3( 1.5/shadow_res.x, 0.5/shadow_res.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3( 0.5/shadow_res.x, -1.5/shadow_res.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(-1.5/shadow_res.x, -0.5/shadow_res.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(-0.5/shadow_res.x, 1.5/shadow_res.y, 0.0)).x; + return clamp(shadow * 0.125, 0.0, 1.0); +} + +float pcfSpotShadow(sampler2DShadow shadowMap, vec4 stc, float bias_scale, vec2 pos_screen) +{ + stc.xyz /= stc.w; + stc.z += spot_shadow_bias * bias_scale; + 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; +} + +float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen) +{ + float shadow = 0.0f; + vec3 light_dir = normalize((sun_up_factor == 1) ? sun_dir : moon_dir); + + float dp_directional_light = max(0.0, dot(norm.xyz, light_dir)); + dp_directional_light = clamp(dp_directional_light, 0.0, 1.0); + + vec3 shadow_pos = pos.xyz; + + vec3 offset = light_dir.xyz * (1.0 - dp_directional_light); + + shadow_pos += offset * shadow_offset * 2.0; + + vec4 spos = vec4(shadow_pos.xyz, 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; + //w = clamp(w, 0.0, 1.0); + float contrib = pcfShadow(shadowMap3, norm, lpos, 1.0, pos_screen, light_dir)*w; + //if (contrib > 0) + { + shadow += contrib; + 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; + //w = clamp(w, 0.0, 1.0); + float contrib = pcfShadow(shadowMap2, norm, lpos, 1.0, pos_screen, light_dir)*w; + //if (contrib > 0) + { + shadow += contrib; + 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; + //w = clamp(w, 0.0, 1.0); + float contrib = pcfShadow(shadowMap1, norm, lpos, 1.0, pos_screen, light_dir)*w; + //if (contrib > 0) + { + shadow += contrib; + 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; + //w = clamp(w, 0.0, 1.0); + float contrib = pcfShadow(shadowMap0, norm, lpos, 1.0, pos_screen, light_dir)*w; + //if (contrib > 0) + { + shadow += contrib; + weight += w; + } + } + + shadow /= weight; + } + else + { + return 1.0f; // lit beyond the far split... + } + //shadow = min(dp_directional_light,shadow); + return shadow; +} + +float sampleSpotShadow(vec3 pos, vec3 norm, int index, vec2 pos_screen) +{ + float shadow = 0.0f; + pos += norm * spot_shadow_offset; + + 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; + + { + float w = 1.0; + w -= max(spos.z-far_split.z, 0.0)/transition_domain.z; + + if (index == 0) + { + lpos = shadow_matrix[4]*spos; + shadow += pcfSpotShadow(shadowMap4, lpos, 0.8, spos.xy)*w; + } + else + { + lpos = shadow_matrix[5]*spos; + shadow += pcfSpotShadow(shadowMap5, lpos, 0.8, spos.xy)*w; + } + weight += w; + shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); + } + + shadow /= weight; + } + else + { + shadow = 1.0f; + } + return shadow; +} + diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl index cc77a4cea0..72bd0f0f34 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl @@ -27,20 +27,19 @@ uniform mat4 modelview_projection_matrix; ATTRIBUTE vec3 position; -#if !DEPTH_CLAMP VARYING vec4 post_pos; -#endif void main() { //transform vertex vec4 pos = modelview_projection_matrix*vec4(position.xyz, 1.0); -#if !DEPTH_CLAMP post_pos = pos; +#if !defined(DEPTH_CLAMP) gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); #else gl_Position = pos; #endif + } diff --git a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl index 22f4729e2e..331249dc33 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl @@ -1,5 +1,5 @@ /** - * @file WLSkyF.glsl + * @file class1/deferred/skyF.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -23,6 +23,8 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_data[3]; #else @@ -35,32 +37,28 @@ out vec4 frag_data[3]; VARYING vec4 vary_HazeColor; -uniform sampler2D cloud_noise_texture; -uniform vec4 gamma; - /// Soft clips the light with a gamma correction -vec3 scaleSoftClip(vec3 light) { - //soft clip effect: - light = 1. - clamp(light, vec3(0.), vec3(1.)); - light = 1. - pow(light, gamma.xxx); - - return light; -} +vec3 scaleSoftClip(vec3 light); +vec3 srgb_to_linear(vec3 c); void main() { - // Potential Fill-rate optimization. Add cloud calculation - // back in and output alpha of 0 (so that alpha culling kills - // the fragment) if the sky wouldn't show up because the clouds - // are fully opaque. + // Potential Fill-rate optimization. Add cloud calculation + // back in and output alpha of 0 (so that alpha culling kills + // the fragment) if the sky wouldn't show up because the clouds + // are fully opaque. + + vec4 color; + color = vary_HazeColor; + + color.rgb *= 2.; + color.rgb = scaleSoftClip(color.rgb); - vec4 color; - color = vary_HazeColor; - color *= 2.; + /// Gamma correct for WL (soft clip effect). + frag_data[0] = vec4(color.rgb, 0.0); + frag_data[1] = vec4(0.0,0.0,0.0,0.0); + frag_data[2] = vec4(0.0,0.0,0.0,1.0); //1.0 in norm.w masks off fog - /// Gamma correct for WL (soft clip effect). - frag_data[0] = vec4(scaleSoftClip(color.rgb), 1.0); - frag_data[1] = vec4(0.0,0.0,0.0,0.0); - frag_data[2] = vec4(0.5,0.5,0.0,1.0); //1.0 in norm.w masks off fog + gl_FragDepth = 0.99999f; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl b/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl index 7c02d31d43..28a1faf24f 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl @@ -1,24 +1,24 @@ -/** +/** * @file WLSkyV.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$ */ @@ -37,121 +37,117 @@ VARYING vec4 vary_HazeColor; // Inputs uniform vec3 camPosLocal; -uniform vec4 lightnorm; -uniform vec4 sunlight_color; -uniform vec4 ambient; -uniform vec4 blue_horizon; -uniform vec4 blue_density; +uniform vec4 lightnorm; +uniform vec4 sunlight_color; +uniform vec4 moonlight_color; +uniform int sun_up_factor; +uniform vec4 ambient_color; +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 vec4 glow; +uniform float sun_moon_glow_factor; uniform vec4 cloud_color; +// NOTE: Keep these in sync! +// indra\newview\app_settings\shaders\class1\deferred\skyV.glsl +// indra\newview\app_settings\shaders\class1\deferred\cloudsV.glsl +// indra\newview\lllegacyatmospherics.cpp void main() { + // World / view / projection + vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); - // World / view / projection - gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); - - // Get relative position - vec3 P = position.xyz - camPosLocal.xyz + vec3(0,50,0); - //vec3 P = position.xyz + vec3(0,50,0); - - // Set altitude - if (P.y > 0.) - { - P *= (max_y / P.y); - } - else - { - P *= (-32000. / P.y); - } - - // Can normalize then - vec3 Pn = normalize(P); - float Plen = length(P); - - // Initialize temp variables - vec4 temp1 = vec4(0.); - vec4 temp2 = vec4(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); - - // Calculate relative weights - temp1 = blue_density + haze_density; - blue_weight = blue_density / temp1; - haze_weight = haze_density / temp1; - - // Compute sunlight from P & lightnorm (for long rays like sky) - temp2.y = max(0., max(0., Pn.y) * 1.0 + lightnorm.y ); - temp2.y = 1. / temp2.y; - sunlight *= exp( - light_atten * temp2.y); - - // Distance - temp2.z = Plen * density_multiplier; - - // Transparency (-> temp1) - // ATI Bugfix -- can't store temp1*temp2.z in a variable because the ati - // compiler gets confused. - temp1 = exp(-temp1 * temp2.z); - - - // Compute haze glow - temp2.x = dot(Pn, lightnorm.xyz); - temp2.x = 1. - temp2.x; - // temp2.x is 0 at the sun and increases away from sun - temp2.x = max(temp2.x, .001); - // 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; - - - // Haze color above cloud - vary_HazeColor = ( blue_horizon * blue_weight * (sunlight + ambient) - + (haze_horizon * haze_weight) * (sunlight * temp2.x + ambient) - ); - - - // Increase ambient when there are more clouds - vec4 tmpAmbient = ambient; - tmpAmbient += (1. - tmpAmbient) * cloud_shadow * 0.5; - - // Dim sunlight by cloud shadow percentage - sunlight *= (1. - cloud_shadow); - - // Haze color below cloud - vec4 additiveColorBelowCloud = ( blue_horizon * blue_weight * (sunlight + tmpAmbient) - + (haze_horizon * haze_weight) * (sunlight * temp2.x + tmpAmbient) - ); - - // Final atmosphere additive - vary_HazeColor *= (1. - temp1); - - // Attenuate cloud color by atmosphere - temp1 = sqrt(temp1); //less atmos opacity (more transparency) below clouds - - // At horizon, blend high altitude sky color towards the darker color below the clouds - vary_HazeColor += (additiveColorBelowCloud - vary_HazeColor) * (1. - sqrt(temp1)); - - // won't compile on mac without this being set - //vary_AtmosAttenuation = vec3(0.0,0.0,0.0); -} + gl_Position = pos; + + // Get relative position + vec3 rel_pos = position.xyz - camPosLocal.xyz + vec3(0, 50, 0); + + // Adj position vector to clamp altitude + if (rel_pos.y > 0) + { + rel_pos *= (max_y / rel_pos.y); + } + if (rel_pos.y < 0) + { + rel_pos *= (-32000. / rel_pos.y); + } + + // Can normalize then + vec3 rel_pos_norm = normalize(rel_pos); + + float rel_pos_len = length(rel_pos); + + // Initialize temp variables + vec4 sunlight = (sun_up_factor == 1) ? sunlight_color : moonlight_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); + + // Calculate relative weights + vec4 combined_haze = abs(blue_density) + vec4(abs(haze_density)); + vec4 blue_weight = blue_density / combined_haze; + vec4 haze_weight = haze_density / combined_haze; + + // Compute sunlight from rel_pos & lightnorm (for long rays like sky) + float off_axis = 1.0 / max(1e-6, max(0., rel_pos_norm.y) + lightnorm.y); + sunlight *= exp(-light_atten * off_axis); + // Distance + float density_dist = rel_pos_len * density_multiplier; + + // Transparency (-> combined_haze) + // ATI Bugfix -- can't store combined_haze*density_dist in a variable because the ati + // compiler gets confused. + combined_haze = exp(-combined_haze * density_dist); + + // Compute haze glow + float haze_glow = 1.0 - dot(rel_pos_norm, lightnorm.xyz); + // haze_glow is 0 at the sun and increases away from sun + haze_glow = max(haze_glow, .001); + // Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) + haze_glow *= glow.x; + // Higher glow.x gives dimmer glow (because next step is 1 / "angle") + haze_glow = pow(haze_glow, glow.z); + // glow.z should be negative, so we're doing a sort of (1 / "angle") function + + // Add "minimum anti-solar illumination" + // For sun, add to glow. For moon, remove glow entirely. SL-13768 + haze_glow = (sun_moon_glow_factor < 1.0) ? 0.0 : (haze_glow + 0.25); + + vec4 color = + (blue_horizon * blue_weight * (sunlight + ambient_color) + (haze_horizon * haze_weight) * (sunlight * haze_glow + ambient_color)); + + // Final atmosphere additive + color *= (1. - combined_haze); + + // Increase ambient when there are more clouds + vec4 tmpAmbient = ambient_color; + tmpAmbient += max(vec4(0), (1. - ambient_color)) * cloud_shadow * 0.5; + + // Dim sunlight by cloud shadow percentage + sunlight *= max(0.0, (1. - cloud_shadow)); + + // Haze color below cloud + vec4 additiveColorBelowCloud = + (blue_horizon * blue_weight * (sunlight + tmpAmbient) + (haze_horizon * haze_weight) * (sunlight * haze_glow + tmpAmbient)); + + // Attenuate cloud color by atmosphere + combined_haze = sqrt(combined_haze); // less atmos opacity (more transparency) below clouds + + // At horizon, blend high altitude sky color towards the darker color below the clouds + color += (additiveColorBelowCloud - color) * (1. - sqrt(combined_haze)); + + // Haze color above cloud + vary_HazeColor = color; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl index 03bdb754b5..7f2c603f87 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl @@ -1,5 +1,5 @@ /** - * @file softenLightF.glsl + * @file class1/deferred/softenLightF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -36,442 +36,135 @@ out vec4 frag_color; uniform sampler2DRect diffuseRect; uniform sampler2DRect specularRect; -uniform sampler2DRect positionMap; uniform sampler2DRect normalMap; uniform sampler2DRect lightMap; uniform sampler2DRect depthMap; uniform samplerCube environmentMap; -uniform sampler2D lightFunc; +uniform sampler2D lightFunc; uniform float blur_size; uniform float blur_fidelity; // 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 global_gamma; -uniform float scene_light_strength; uniform mat3 env_mat; -uniform mat3 ssao_effect_mat; uniform vec3 sun_dir; +uniform vec3 moon_dir; +uniform int sun_up_factor; VARYING vec2 vary_fragcoord; -vec3 vary_PositionEye; - -vec3 vary_SunlitColor; -vec3 vary_AmblitColor; -vec3 vary_AdditiveColor; -vec3 vary_AtmosAttenuation; - uniform mat4 inv_proj; uniform vec2 screen_res; -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)); - -#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 +vec3 getNorm(vec2 pos_screen); +vec4 getPositionWithDepth(vec2 pos_screen, float depth); -} - -vec3 linear_to_srgb(vec3 cl) -{ - 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 - -} - - -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_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; - pos /= pos.w; - pos.w = 1.0; - 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; -} -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 calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten, bool use_ao); +float getAmbientClamp(); +vec3 atmosFragLighting(vec3 l, vec3 additive, vec3 atten); +vec3 scaleSoftClipFrag(vec3 l); +vec3 fullbrightAtmosTransportFrag(vec3 light, vec3 additive, vec3 atten); +vec3 fullbrightScaleSoftClip(vec3 light); +vec3 linear_to_srgb(vec3 c); +vec3 srgb_to_linear(vec3 c); #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; -} +vec4 applyWaterFogView(vec3 pos, vec4 color); #endif -void calcAtmospherics(vec3 inPositionEye, float ambFactor) { - - 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; - - /* decrease value and saturation (that in HSV, not HSL) for occluded areas - * // for HSV color/geometry used here, see http://gimp-savvy.com/BOOK/index.html?node52.html - * // The following line of code performs the equivalent of: - * float ambAlpha = tmpAmbient.a; - * float ambValue = dot(vec3(tmpAmbient), vec3(0.577)); // projection onto <1/rt(3), 1/rt(3), 1/rt(3)>, the neutral white-black axis - * vec3 ambHueSat = vec3(tmpAmbient) - vec3(ambValue); - * tmpAmbient = vec4(RenderSSAOEffect.valueFactor * vec3(ambValue) + RenderSSAOEffect.saturationFactor *(1.0 - ambFactor) * ambHueSat, ambAlpha); - */ - tmpAmbient = vec4(mix(ssao_effect_mat * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a); - - //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 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(); -} - -vec3 scaleDownLight(vec3 light) -{ - return (light / scene_light_strength ); -} - -vec3 scaleUpLight(vec3 light) -{ - return (light * scene_light_strength); -} - -vec3 atmosAmbient(vec3 light) -{ - return getAmblitColor() + light / 2.0; -} - -vec3 atmosAffectDirectionalLight(float lightIntensity) -{ - return getSunlitColor() * lightIntensity; -} - -vec3 scaleSoftClip(vec3 light) -{ - //soft clip effect: - light = 1. - clamp(light, vec3(0.), vec3(1.)); - light = 1. - pow(light, gamma.xxx); - - return light; -} - - -vec3 fullbrightScaleSoftClip(vec3 light) -{ - //soft clip effect: - return light; -} - void main() { - vec2 tc = vary_fragcoord.xy; - float depth = texture2DRect(depthMap, tc.xy).r; - vec3 pos = getPosition_d(tc, depth).xyz; - vec4 norm = texture2DRect(normalMap, tc); - float envIntensity = norm.z; - norm.xyz = decode_normal(norm.xy); // unpack norm - - 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); - - vec4 diffuse = texture2DRect(diffuseRect, tc); - - //convert to gamma space - diffuse.rgb = linear_to_srgb(diffuse.rgb); - - vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy); - vec3 col; - float bloom = 0.0; - { - calcAtmospherics(pos.xyz, 1.0); - - col = atmosAmbient(vec3(0)); - 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 - // - - float sa = dot(refnormpersp, sun_dir.xyz); - 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) / 6; - col += spec_contrib; - } - - - col = mix(col.rgb, diffuse.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); - } - - if (norm.w < 0.5) - { - col = mix(atmosLighting(col), fullbrightAtmosTransport(col), diffuse.a); - col = mix(scaleSoftClip(col), fullbrightScaleSoftClip(col), diffuse.a); - } - - #ifdef WATER_FOG - vec4 fogged = applyWaterFogDeferred(pos,vec4(col, bloom)); - col = fogged.rgb; - bloom = fogged.a; - #endif - - col = srgb_to_linear(col); - - //col = vec3(1,0,1); - //col.g = envIntensity; - } - - frag_color.rgb = col.rgb; - frag_color.a = bloom; + vec2 tc = vary_fragcoord.xy; + float depth = texture2DRect(depthMap, tc.xy).r; + vec4 pos = getPositionWithDepth(tc, depth); + vec4 norm = texture2DRect(normalMap, tc); + float envIntensity = norm.z; + norm.xyz = getNorm(tc); + + vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; + float da = clamp(dot(norm.xyz, light_dir.xyz), 0.0, 1.0); + float light_gamma = 1.0/1.3; + da = pow(da, light_gamma); + + vec4 diffuse = texture2DRect(diffuseRect, tc); + + //convert to gamma space + diffuse.rgb = linear_to_srgb(diffuse.rgb); // SL-14035 + + vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy); + vec3 color = vec3(0); + float bloom = 0.0; + { + float ambocc = 1.0; // no AO... + + vec3 sunlit; + vec3 amblit; + vec3 additive; + vec3 atten; + + calcAtmosphericVars(pos.xyz, light_dir, ambocc, sunlit, amblit, additive, atten, false); + + color.rgb = amblit; + + float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0); + ambient *= 0.5; + ambient *= ambient; + ambient = (1.0 - ambient); + + color.rgb *= ambient; + + vec3 sun_contrib = da * sunlit; + + color.rgb += sun_contrib; + + color.rgb *= diffuse.rgb; + + vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); + + if (spec.a > 0.0) // specular reflection + { + float sa = dot(refnormpersp, light_dir.xyz); + vec3 dumbshiny = sunlit * (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; + color.rgb += spec_contrib; + } + + color.rgb = mix(color.rgb, diffuse.rgb, diffuse.a); + + if (envIntensity > 0.0) + { //add environmentmap + vec3 env_vec = env_mat * refnormpersp; + vec3 reflected_color = textureCube(environmentMap, env_vec).rgb; + color = mix(color.rgb, reflected_color, envIntensity); + } + + if (norm.w < 0.5) + { + color = mix(atmosFragLighting(color, additive, atten), fullbrightAtmosTransportFrag(color, additive, atten), diffuse.a); + color = mix(scaleSoftClipFrag(color), fullbrightScaleSoftClip(color), diffuse.a); + } + + #ifdef WATER_FOG + vec4 fogged = applyWaterFogView(pos.xyz,vec4(color, bloom)); + color = fogged.rgb; + bloom = fogged.a; + #endif + + } + +// linear debuggables +//color.rgb = vec3(final_da); +//color.rgb = vec3(ambient); +//color.rgb = vec3(scol); +//color.rgb = diffuse_srgb.rgb; + + // convert to linear as fullscreen lights need to sum in linear colorspace + // and will be gamma (re)corrected downstream... + + frag_color.rgb = srgb_to_linear(color.rgb); + frag_color.a = bloom; } - diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl index b59fcbe017..8891315e15 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl @@ -1,5 +1,5 @@ /** - * @file softenLightF.glsl + * @file softenLightV.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -29,12 +29,17 @@ ATTRIBUTE vec3 position; uniform vec2 screen_res; +void setAtmosAttenuation(vec3 c); +void setAdditiveColor(vec3 c); + 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; + //transform vertex + vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); + gl_Position = pos; + // appease OSX GLSL compiler/linker by touching all the varyings we said we would + setAtmosAttenuation(vec3(1)); + setAdditiveColor(vec3(0)); + 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 f1aec315cc..694b19cdfb 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl @@ -70,64 +70,8 @@ uniform vec2 screen_res; uniform mat4 inv_proj; -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; -} - -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)); - -#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 - -} - -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 correctWithGamma(vec4 col) -{ - return vec4(srgb_to_linear(col.rgb), col.a); -} +vec3 getNorm(vec2 pos_screen); +vec3 srgb_to_linear(vec3 c); vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) { @@ -152,7 +96,7 @@ vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); - ret = correctWithGamma(ret); + ret.rgb = srgb_to_linear(ret.rgb); vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); @@ -170,7 +114,7 @@ vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); - ret = correctWithGamma(ret); + ret.rgb = srgb_to_linear(ret.rgb); vec2 dist = tc-vec2(0.5); @@ -181,22 +125,15 @@ 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; -} +vec4 getPosition(vec2 pos_screen); void main() { + vec3 col = vec3(0,0,0); + +#if defined(LOCAL_LIGHT_KILL) + discard; +#else vec4 frag = vary_fragcoord; frag.xyz /= frag.w; frag.xyz = frag.xyz*0.5+0.5; @@ -210,12 +147,10 @@ void main() { discard; } - vec3 norm = texture2DRect(normalMap, frag.xy).xyz; float envIntensity = norm.z; - norm = decode_normal(norm.xy); - + norm = getNorm(frag.xy); norm = normalize(norm); float l_dist = -dot(lv, proj_n); @@ -241,13 +176,11 @@ void main() lv = normalize(lv); float da = dot(norm, lv); - vec3 col = vec3(0,0,0); - vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb; - - vec4 spec = texture2DRect(specularRect, frag.xy); + //light shaders output linear and are gamma corrected later in postDeferredGammaCorrectF.glsl + diff_tex.rgb = srgb_to_linear(diff_tex.rgb); - + vec4 spec = texture2DRect(specularRect, frag.xy); float noise = texture2D(noiseMap, frag.xy/128.0).b; vec3 dlit = vec3(0, 0, 0); @@ -284,7 +217,6 @@ void main() amb_da = min(amb_da, 1.0-lit); col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a*diff_tex.rgb; } - if (spec.a > 0.0) { @@ -311,7 +243,6 @@ void main() } } - if (envIntensity > 0.0) { vec3 ref = reflect(normalize(pos), norm); @@ -340,7 +271,9 @@ void main() } } } - +#endif + + //col.r = 1.0; frag_color.rgb = col; frag_color.a = 0.0; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl b/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl index 821058804c..bac79a9fdc 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl @@ -23,6 +23,8 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_data[3]; #else @@ -31,14 +33,35 @@ out vec4 frag_data[3]; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; +VARYING vec2 screenpos; uniform sampler2D diffuseMap; +uniform sampler2D altDiffuseMap; +uniform float blend_factor; +uniform float custom_alpha; +uniform float time; + +float twinkle(){ + float d = fract(screenpos.x + screenpos.y); + return abs(d); +} void main() { - vec4 col = vertex_color * texture2D(diffuseMap, vary_texcoord0.xy); - - frag_data[0] = col; - frag_data[1] = vec4(0,0,0,0); - frag_data[2] = vec4(0,0,1,0); + vec4 col_a = texture2D(diffuseMap, vary_texcoord0.xy); + vec4 col_b = texture2D(diffuseMap, vary_texcoord0.xy); + vec4 col = mix(col_b, col_a, blend_factor); + col.rgb *= vertex_color.rgb; + + float factor = smoothstep(0.0f, 0.9f, custom_alpha); + + col.a = (col.a * factor) * 32.0f; + col.a *= twinkle(); + + frag_data[0] = col; + frag_data[1] = vec4(0.0f); + frag_data[2] = vec4(0.0, 1.0, 0.0, 1.0); + + gl_FragDepth = 0.99995f; } + diff --git a/indra/newview/app_settings/shaders/class1/deferred/starsV.glsl b/indra/newview/app_settings/shaders/class1/deferred/starsV.glsl index 8bc5b06379..bb2a2ee72b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/starsV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/starsV.glsl @@ -25,6 +25,7 @@ uniform mat4 texture_matrix0; uniform mat4 modelview_projection_matrix; +uniform float time; ATTRIBUTE vec3 position; ATTRIBUTE vec4 diffuse_color; @@ -32,11 +33,20 @@ ATTRIBUTE vec2 texcoord0; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; +VARYING vec2 screenpos; void main() { //transform vertex - gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); + vec4 pos = modelview_projection_matrix * vec4(position, 1.0); + +// bias z to fix SL-9806 and get stars to depth test against clouds + pos.z += 0.001f; + + gl_Position = pos; + + float t = mod(time, 1.25f); + screenpos = position.xy * vec2(t, t); vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; vertex_color = diffuse_color; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunDiscF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunDiscF.glsl new file mode 100644 index 0000000000..b2fa5d8a25 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/sunDiscF.glsl @@ -0,0 +1,64 @@ +/** + * @file sunDiscF.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 + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_data[3]; +#else +#define frag_data gl_FragData +#endif + +vec3 srgb_to_linear(vec3 c); +vec3 fullbrightAtmosTransport(vec3 light); +vec3 fullbrightScaleSoftClip(vec3 light); + +uniform sampler2D diffuseMap; +uniform sampler2D altDiffuseMap; +uniform float blend_factor; // interp factor between sunDisc A/B +VARYING vec2 vary_texcoord0; +VARYING float sun_fade; + +void main() +{ + vec4 sunDiscA = texture2D(diffuseMap, vary_texcoord0.xy); + vec4 sunDiscB = texture2D(altDiffuseMap, vary_texcoord0.xy); + vec4 c = mix(sunDiscA, sunDiscB, blend_factor); + + //c.rgb = fullbrightAtmosTransport(c.rgb); + c.rgb = fullbrightScaleSoftClip(c.rgb); + + // SL-9806 stars poke through + //c.a *= sun_fade; + + frag_data[0] = c; + frag_data[1] = vec4(0.0f); + frag_data[2] = vec4(0.0, 1.0, 0.0, 1.0); + + gl_FragDepth = 0.999988f; +} + diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunDiscV.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunDiscV.glsl new file mode 100644 index 0000000000..0d117c6bc7 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/sunDiscV.glsl @@ -0,0 +1,52 @@ +/** + * @file sunDiscV.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_matrix; +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec2 texcoord0; + +VARYING vec2 vary_texcoord0; +VARYING float sun_fade; + +void calcAtmospherics(vec3 eye_pos); + +void main() +{ + //transform vertex + vec3 offset = vec3(0, 0, 50); + vec4 vert = vec4(position.xyz - offset, 1.0); + vec4 pos = modelview_projection_matrix*vert; + + sun_fade = smoothstep(0.3, 1.0, (position.z + 50) / 512.0f); + + gl_Position = pos; + + calcAtmospherics(pos.xyz); + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl index 930255729b..15f141cbe5 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl @@ -35,103 +35,16 @@ out vec4 frag_color; //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; - -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 = 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 getNorm(vec2 pos_screen); +vec4 getPosition(vec2 pos_screen); //calculate decreases in ambient lighting when crowded out (SSAO) -float calcAmbientOcclusion(vec4 pos, vec3 norm) -{ - float ret = 1.0; - - 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; - - vec2 pos_screen = vary_fragcoord.xy; - vec3 pos_world = pos.xyz; - vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; - - float angle_hidden = 0.0; - int points = 0; - - float scale = min(ssao_radius / -pos_world.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 = pos_world - samppos_world; - float dist2 = dot(diff, diff); - - // assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area - // --> solid angle shrinking by the square of distance - //radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2 - //(k should vary inversely with # of samples, but this is taken care of later) - - angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv); - - // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" - points = points + int(diff.z > -1.0); - } - - angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0); - - ret = (1.0 - (float(points != 0) * angle_hidden)); - - return min(ret, 1.0); -} +float calcAmbientOcclusion(vec4 pos, vec3 norm, vec2 pos_screen); void main() { @@ -139,13 +52,11 @@ void main() //try doing an unproject here - vec4 pos = getPosition(pos_screen); - - vec3 norm = texture2DRect(normalMap, pos_screen).xyz; - norm = decode_normal(norm.xy); - + vec4 pos = getPosition(pos_screen); + vec3 norm = getNorm(pos_screen); + frag_color[0] = 1.0; - frag_color[1] = calcAmbientOcclusion(pos, norm); + frag_color[1] = calcAmbientOcclusion(pos, norm, pos_screen); frag_color[2] = 1.0; frag_color[3] = 1.0; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl index 52a429465f..6b6eed9db8 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl @@ -1,5 +1,5 @@ /** - * @file terrainF.glsl + * @file class1\deferred\terrainF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -23,6 +23,8 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_data[3]; #else @@ -35,33 +37,32 @@ uniform sampler2D detail_2; uniform sampler2D detail_3; uniform sampler2D alpha_ramp; +VARYING vec3 pos; VARYING vec3 vary_normal; VARYING vec4 vary_texcoord0; VARYING vec4 vary_texcoord1; -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} +vec2 encode_normal(vec3 n); void main() { - /// Note: This should duplicate the blending functionality currently used for the terrain rendering. - - vec4 color0 = texture2D(detail_0, vary_texcoord0.xy); - vec4 color1 = texture2D(detail_1, vary_texcoord0.xy); - vec4 color2 = texture2D(detail_2, vary_texcoord0.xy); - vec4 color3 = texture2D(detail_3, vary_texcoord0.xy); + /// Note: This should duplicate the blending functionality currently used for the terrain rendering. + + vec4 color0 = texture2D(detail_0, vary_texcoord0.xy); + vec4 color1 = texture2D(detail_1, vary_texcoord0.xy); + vec4 color2 = texture2D(detail_2, vary_texcoord0.xy); + vec4 color3 = texture2D(detail_3, vary_texcoord0.xy); - float alpha1 = texture2D(alpha_ramp, vary_texcoord0.zw).a; - float alpha2 = texture2D(alpha_ramp,vary_texcoord1.xy).a; - float alphaFinal = texture2D(alpha_ramp, vary_texcoord1.zw).a; - vec4 outColor = mix( mix(color3, color2, alpha2), mix(color1, color0, alpha1), alphaFinal ); - - 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(encode_normal(nvn.xyz), 0.0, 0.0); + float alpha1 = texture2D(alpha_ramp, vary_texcoord0.zw).a; + float alpha2 = texture2D(alpha_ramp,vary_texcoord1.xy).a; + float alphaFinal = texture2D(alpha_ramp, vary_texcoord1.zw).a; + vec4 outColor = mix( mix(color3, color2, alpha2), mix(color1, color0, alpha1), alphaFinal ); + + outColor.a = 0.0; // yes, downstream atmospherics + + frag_data[0] = outColor; + frag_data[1] = vec4(0.0,0.0,0.0,-1.0); + vec3 nvn = normalize(vary_normal); + frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl index 5effee4e4e..f42cb6ff6d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl @@ -1,5 +1,5 @@ /** - * @file terrainV.glsl + * @file class1\environment\terrainV.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -33,8 +33,8 @@ ATTRIBUTE vec4 diffuse_color; ATTRIBUTE vec2 texcoord0; ATTRIBUTE vec2 texcoord1; +VARYING vec3 pos; VARYING vec3 vary_normal; - VARYING vec4 vary_texcoord0; VARYING vec4 vary_texcoord1; @@ -43,31 +43,35 @@ uniform vec4 object_plane_t; vec4 texgen_object(vec4 vpos, vec4 tc, mat4 mat, vec4 tp0, vec4 tp1) { - vec4 tcoord; - - tcoord.x = dot(vpos, tp0); - tcoord.y = dot(vpos, tp1); - tcoord.z = tc.z; - tcoord.w = tc.w; - - tcoord = mat * tcoord; - - return tcoord; + vec4 tcoord; + + tcoord.x = dot(vpos, tp0); + tcoord.y = dot(vpos, tp1); + tcoord.z = tc.z; + tcoord.w = tc.w; + + tcoord = mat * tcoord; + + return tcoord; } void main() { - //transform vertex - gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); - - vary_normal = normalize(normal_matrix * normal); - - // Transform and pass tex coords - vary_texcoord0.xy = texgen_object(vec4(position, 1.0), vec4(texcoord0,0,1), texture_matrix0, object_plane_s, object_plane_t).xy; - - vec4 t = vec4(texcoord1,0,1); - - vary_texcoord0.zw = t.xy; - vary_texcoord1.xy = t.xy-vec2(2.0, 0.0); - vary_texcoord1.zw = t.xy-vec2(1.0, 0.0); + //transform vertex + vec4 pre_pos = vec4(position.xyz, 1.0); + vec4 t_pos = modelview_projection_matrix * pre_pos; + + gl_Position = t_pos; + pos = t_pos.xyz; + + vary_normal = normalize(normal_matrix * normal); + + // Transform and pass tex coords + vary_texcoord0.xy = texgen_object(vec4(position, 1.0), vec4(texcoord0,0,1), texture_matrix0, object_plane_s, object_plane_t).xy; + + vec4 t = vec4(texcoord1,0,1); + + vary_texcoord0.zw = t.xy; + vary_texcoord1.xy = t.xy-vec2(2.0, 0.0); + vary_texcoord1.zw = t.xy-vec2(1.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 808750496f..89e354558a 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl @@ -23,6 +23,8 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_data[3]; #else @@ -37,11 +39,7 @@ VARYING vec2 vary_texcoord0; uniform float minimum_alpha; -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} +vec2 encode_normal(vec3 n); void main() { diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeShadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeShadowF.glsl index d4d2f5f571..e34d75ba1d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/treeShadowF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/treeShadowF.glsl @@ -23,6 +23,8 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; #else diff --git a/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl index 78f841c733..9a5debb3c1 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl @@ -23,6 +23,8 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_data[3]; #else @@ -56,84 +58,7 @@ VARYING vec4 refCoord; VARYING vec4 littleWave; VARYING vec4 view; -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)); - -#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 - -} - -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 - -} - -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} - -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); -} +vec2 encode_normal(vec3 n); void main() { @@ -151,7 +76,7 @@ void main() vec4 fb = texture2D(screenTex, distort); - frag_data[0] = vec4(linear_to_srgb(fb.rgb), 1.0); // diffuse + 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 + frag_data[2] = vec4(encode_normal(wavef), 0.0, 0.0); // normalxyz, env intens, atmo kill } diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl index 37dcd3ad34..a157e9c017 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl @@ -1,5 +1,5 @@ /** - * @file waterF.glsl + * @file class1/deferred/waterF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -37,17 +37,10 @@ vec3 scaleSoftClip(vec3 inColor); vec3 atmosTransport(vec3 inColor); uniform sampler2D bumpMap; +uniform sampler2D bumpMap2; +uniform float blend_factor; 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]; -uniform vec4 shadow_clip; - uniform float sunAngle; uniform float sunAngle2; uniform vec3 lightDir; @@ -62,6 +55,7 @@ uniform float fresnelOffset; uniform float blurMultiplier; uniform vec2 screen_res; uniform mat4 norm_mat; //region space to screen space +uniform int water_edge; //bigWave is (refCoord.w, view.w); VARYING vec4 refCoord; @@ -69,111 +63,89 @@ VARYING vec4 littleWave; VARYING vec4 view; VARYING vec4 vary_position; -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)); - -#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 - -} - -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 - -} +vec2 encode_normal(vec3 n); +vec3 scaleSoftClip(vec3 l); +vec3 srgb_to_linear(vec3 c); +vec3 linear_to_srgb(vec3 c); -vec2 encode_normal(vec3 n) +vec3 BlendNormal(vec3 bump1, vec3 bump2) { - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; + vec3 n = mix(bump1, bump2, blend_factor); + return n; } void main() { - vec4 color; - float dist = length(view.xy); - - //normalize view vector - vec3 viewVec = normalize(view.xyz); - - //get wave 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; - //get base fresnel components - - vec3 df = vec3( - dot(viewVec, wave1), - dot(viewVec, (wave2 + wave3) * 0.5), - dot(viewVec, wave3) - ) * fresnelScale + fresnelOffset; - df *= df; - - vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5; - - float dist2 = dist; - dist = max(dist, 5.0); - - float dmod = sqrt(dist); - - vec2 dmod_scale = vec2(dmod*dmod, dmod); - - //get reflected color - vec2 refdistort1 = wave1.xy*normScale.x; - vec2 refvec1 = distort+refdistort1/dmod_scale; - vec4 refcol1 = texture2D(refTex, refvec1); - - vec2 refdistort2 = wave2.xy*normScale.y; - vec2 refvec2 = distort+refdistort2/dmod_scale; - vec4 refcol2 = texture2D(refTex, refvec2); - - vec2 refdistort3 = wave3.xy*normScale.z; - vec2 refvec3 = distort+refdistort3/dmod_scale; - vec4 refcol3 = texture2D(refTex, refvec3); - - vec4 refcol = refcol1 + refcol2 + refcol3; - float df1 = df.x + df.y + df.z; + vec4 color; + float dist = length(view.xyz); + + //normalize view vector + vec3 viewVec = normalize(view.xyz); + + //get wave normals + vec3 wave1_a = texture2D(bumpMap, vec2(refCoord.w, view.w)).xyz*2.0-1.0; + vec3 wave2_a = texture2D(bumpMap, littleWave.xy).xyz*2.0-1.0; + vec3 wave3_a = texture2D(bumpMap, littleWave.zw).xyz*2.0-1.0; + + + vec3 wave1_b = texture2D(bumpMap2, vec2(refCoord.w, view.w)).xyz*2.0-1.0; + vec3 wave2_b = texture2D(bumpMap2, littleWave.xy).xyz*2.0-1.0; + vec3 wave3_b = texture2D(bumpMap2, littleWave.zw).xyz*2.0-1.0; + + vec3 wave1 = BlendNormal(wave1_a, wave1_b); + vec3 wave2 = BlendNormal(wave2_a, wave2_b); + vec3 wave3 = BlendNormal(wave3_a, wave3_b); + + //get base fresnel components + + vec3 df = vec3( + dot(viewVec, wave1), + dot(viewVec, (wave2 + wave3) * 0.5), + dot(viewVec, wave3) + ) * fresnelScale + fresnelOffset; + df *= df; + + vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5; + + float dist2 = dist; + dist = max(dist, 5.0); + + float dmod = sqrt(dist); + + vec2 dmod_scale = vec2(dmod*dmod, dmod); + + //get reflected color + vec2 refdistort1 = wave1.xy*normScale.x; + vec2 refvec1 = distort+refdistort1/dmod_scale; + vec4 refcol1 = texture2D(refTex, refvec1); + + vec2 refdistort2 = wave2.xy*normScale.y; + vec2 refvec2 = distort+refdistort2/dmod_scale; + vec4 refcol2 = texture2D(refTex, refvec2); + + vec2 refdistort3 = wave3.xy*normScale.z; + vec2 refvec3 = distort+refdistort3/dmod_scale; + vec4 refcol3 = texture2D(refTex, refvec3); + + vec4 refcol = refcol1 + refcol2 + refcol3; + float df1 = df.x + df.y + df.z; refcol *= df1 * 0.333; - - vec3 wavef = (wave1 + wave2 * 0.4 + wave3 * 0.6) * 0.5; - wavef.z *= max(-viewVec.z, 0.1); - wavef = normalize(wavef); - - float df2 = dot(viewVec, wavef) * fresnelScale+fresnelOffset; - - vec2 refdistort4 = wavef.xy*0.125; - refdistort4.y -= abs(refdistort4.y); - 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 + + vec3 wavef = (wave1 + wave2 * 0.4 + wave3 * 0.6) * 0.5; + wavef.z *= max(-viewVec.z, 0.1); + wavef = normalize(wavef); + + float df2 = dot(viewVec, wavef) * fresnelScale+fresnelOffset; + + vec2 refdistort4 = wavef.xy*0.125; + refdistort4.y -= abs(refdistort4.y); + 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); //harden specular @@ -186,19 +158,27 @@ void main() //mix with reflection // 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); + color.rgb = mix(fb.rgb, refcol.rgb, df1 * 0.99999f); vec4 pos = vary_position; color.rgb += spec * specular; - + color.rgb = atmosTransport(color.rgb); color.rgb = scaleSoftClip(color.rgb); + color.a = spec * sunAngle2; - + vec3 screenspacewavef = normalize((norm_mat*vec4(wavef, 1.0)).xyz); - - frag_data[0] = vec4(color.rgb, color); // diffuse - frag_data[1] = vec4(0); // speccolor, spec - frag_data[2] = vec4(encode_normal(screenspacewavef.xyz*0.5+0.5), 0.05, 0);// normalxy, 0, 0 + + //frag_data[0] = color; + + // TODO: The non-obvious assignment below is copied from the pre-EEP WL shader code + // Unfortunately, fixing it causes a mismatch for EEP, and so it remains... for now + // SL-12975 (unfix pre-EEP broken alpha) + frag_data[0] = vec4(color.rgb, color); // Effectively, color.rgbr + + + 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 9734acf005..8863869e44 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl @@ -31,8 +31,8 @@ ATTRIBUTE vec3 position; void calcAtmospherics(vec3 inPositionEye); -uniform vec2 d1; -uniform vec2 d2; +uniform vec2 waveDir1; +uniform vec2 waveDir2; uniform float time; uniform vec3 eyeVec; uniform float waterHeight; @@ -88,10 +88,10 @@ void main() calcAtmospherics(pos.xyz); //pass wave parameters to pixel shader - vec2 bigWave = (v.xy) * vec2(0.04,0.04) + d1 * time * 0.055; + vec2 bigWave = (v.xy) * vec2(0.04,0.04) + waveDir1 * time * 0.055; //get two normal map (detail map) texture coordinates - littleWave.xy = (v.xy) * vec2(0.45, 0.9) + d2 * time * 0.13; - littleWave.zw = (v.xy) * vec2(0.1, 0.2) + d1 * time * 0.1; + littleWave.xy = (v.xy) * vec2(0.45, 0.9) + waveDir2 * time * 0.13; + littleWave.zw = (v.xy) * vec2(0.1, 0.2) + waveDir1 * time * 0.1; view.w = bigWave.y; refCoord.w = bigWave.x; diff --git a/indra/newview/app_settings/shaders/class1/environment/encodeNormF.glsl b/indra/newview/app_settings/shaders/class1/environment/encodeNormF.glsl new file mode 100644 index 0000000000..6cd2445522 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/environment/encodeNormF.glsl @@ -0,0 +1,34 @@ +/** + * @file encodeNormF.glsl + * + * $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$ + */ + +// Lambert Azimuthal Equal-Area projection +// See: https://aras-p.info/texts/CompactNormalStorage.html +// Also see: A_bit_more_deferred_-_CryEngine3.ppt +vec2 encode_normal(vec3 n) +{ + float f = sqrt(8 * n.z + 8); + return n.xy / f + 0.5; +} + diff --git a/indra/newview/app_settings/shaders/class1/deferred/srgb_mac.glsl b/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl index 6cc1e6e798..4a8b892c3a 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/srgb_mac.glsl +++ b/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl @@ -1,5 +1,5 @@ /** - * @file srgb.glsl + * @file srgbF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -27,14 +27,18 @@ 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)); +#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 + } vec3 linear_to_srgb(vec3 cl) @@ -42,13 +46,39 @@ 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; + return result; +#else + return mix(high_range, low_range, lt); +#endif + +} + +vec3 ColorFromRadiance(vec3 radiance) +{ + return vec3(1.0) - exp(-radiance * 0.0001); } +vec3 rgb2hsv(vec3 c) +{ + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +vec3 hsv2rgb(vec3 c) +{ + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} diff --git a/indra/newview/app_settings/shaders/class1/environment/terrainF.glsl b/indra/newview/app_settings/shaders/class1/environment/terrainF.glsl index 668a710c04..6b68ed4169 100644 --- a/indra/newview/app_settings/shaders/class1/environment/terrainF.glsl +++ b/indra/newview/app_settings/shaders/class1/environment/terrainF.glsl @@ -1,5 +1,5 @@ /** - * @file terrainF.glsl + * @file class1\environment\terrainF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/environment/terrainV.glsl b/indra/newview/app_settings/shaders/class1/environment/terrainV.glsl index d09c5f9247..ef27848d37 100644 --- a/indra/newview/app_settings/shaders/class1/environment/terrainV.glsl +++ b/indra/newview/app_settings/shaders/class1/environment/terrainV.glsl @@ -1,5 +1,5 @@ /** - * @file terrainV.glsl + * @file class1\environment\terrainV.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -35,6 +35,7 @@ ATTRIBUTE vec3 position; ATTRIBUTE vec3 normal; ATTRIBUTE vec2 texcoord0; ATTRIBUTE vec2 texcoord1; +ATTRIBUTE vec4 diffuse_color; VARYING vec4 vertex_color; VARYING vec4 vary_texcoord0; @@ -42,7 +43,7 @@ VARYING vec4 vary_texcoord1; void calcAtmospherics(vec3 inPositionEye); -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); +vec4 calcLighting(vec3 pos, vec3 norm, vec4 color); vec4 texgen_object(vec4 vpos, vec4 tc, mat4 mat, vec4 tp0, vec4 tp1) { @@ -71,7 +72,7 @@ void main() /// Potentially better without it for water. pos /= pos.w; - vec4 color = calcLighting(pos.xyz, norm, vec4(1,1,1,1), vec4(0)); + vec4 color = calcLighting(pos.xyz, norm, /*diffuse_color*/vec4(1)); vertex_color = color; diff --git a/indra/newview/app_settings/shaders/class1/environment/terrainWaterF.glsl b/indra/newview/app_settings/shaders/class1/environment/terrainWaterF.glsl index a956562396..e53bb46177 100644 --- a/indra/newview/app_settings/shaders/class1/environment/terrainWaterF.glsl +++ b/indra/newview/app_settings/shaders/class1/environment/terrainWaterF.glsl @@ -1,5 +1,5 @@ /** - * @file terrainWaterF.glsl + * @file class1\environment\terrainWaterF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -64,4 +64,3 @@ void main() outColor = applyWaterFog(outColor); frag_color = outColor; } - diff --git a/indra/newview/app_settings/shaders/class1/environment/terrainWaterV.glsl b/indra/newview/app_settings/shaders/class1/environment/terrainWaterV.glsl new file mode 100644 index 0000000000..a075cfeef2 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/environment/terrainWaterV.glsl @@ -0,0 +1,84 @@ +/** + * @file class1\environment\terrainV.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; + +uniform vec4 object_plane_t; +uniform vec4 object_plane_s; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec3 normal; +ATTRIBUTE vec2 texcoord0; +ATTRIBUTE vec2 texcoord1; +ATTRIBUTE vec4 diffuse_color; + +VARYING vec4 vertex_color; +VARYING vec4 vary_texcoord0; +VARYING vec4 vary_texcoord1; + +void calcAtmospherics(vec3 inPositionEye); +vec4 calcLighting(vec3 pos, vec3 norm, vec4 color); + +vec4 texgen_object(vec4 vpos, vec4 tc, mat4 mat, vec4 tp0, vec4 tp1) +{ + vec4 tcoord; + + tcoord.x = dot(vpos, tp0); + tcoord.y = dot(vpos, tp1); + tcoord.z = tc.z; + tcoord.w = tc.w; + + tcoord = mat * tcoord; + + return tcoord; +} + +void main() +{ + //transform vertex + gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); + + vec4 pos = modelview_matrix * vec4(position.xyz, 1.0); + vec3 norm = normalize(normal_matrix * normal); + + calcAtmospherics(pos.xyz); + + vec4 color = calcLighting(pos.xyz, norm, vec4(1.0)); + + vertex_color.rgb = color.rgb; + + // Transform and pass tex coords + vary_texcoord0.xy = texgen_object(vec4(position.xyz, 1.0), vec4(texcoord0,0,1), texture_matrix0, object_plane_s, object_plane_t).xy; + + vec4 t = vec4(texcoord1,0,1); + + vary_texcoord0.zw = t.xy; + vary_texcoord1.xy = t.xy-vec2(2.0, 0.0); + vary_texcoord1.zw = t.xy-vec2(1.0, 0.0); +} + diff --git a/indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl b/indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl index 0d8dab0a41..8c8bd6d0d5 100644 --- a/indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl +++ b/indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl @@ -1,5 +1,5 @@ /** - * @file underWaterF.glsl + * @file class1\environment\underWaterF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -47,7 +47,6 @@ uniform float kd; uniform vec4 waterPlane; uniform vec3 eyeVec; uniform vec4 waterFogColor; -uniform float waterFogDensity; uniform float waterFogKS; uniform vec2 screenRes; @@ -56,41 +55,7 @@ VARYING vec4 refCoord; VARYING vec4 littleWave; VARYING vec4 view; -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); -} +vec4 applyWaterFogView(vec3 pos, vec4 color); void main() { @@ -108,5 +73,5 @@ void main() vec4 fb = texture2D(screenTex, distort); - frag_color = applyWaterFog(fb,view.xyz); + frag_color = applyWaterFogView(view.xyz, fb); } diff --git a/indra/newview/app_settings/shaders/class1/environment/waterF.glsl b/indra/newview/app_settings/shaders/class1/environment/waterF.glsl index 79bffab745..d370997123 100644 --- a/indra/newview/app_settings/shaders/class1/environment/waterF.glsl +++ b/indra/newview/app_settings/shaders/class1/environment/waterF.glsl @@ -32,7 +32,9 @@ out vec4 frag_color; vec3 scaleSoftClip(vec3 inColor); vec3 atmosTransport(vec3 inColor); -uniform sampler2D bumpMap; +uniform sampler2D bumpMap; +uniform sampler2D bumpMap2; +uniform float blend_factor; uniform sampler2D screenTex; uniform sampler2D refTex; @@ -55,6 +57,13 @@ VARYING vec4 refCoord; VARYING vec4 littleWave; VARYING vec4 view; +vec3 BlendNormal(vec3 bump1, vec3 bump2) +{ + vec3 n = mix(bump1, bump2, blend_factor); + return n; +} + + void main() { vec4 color; @@ -65,9 +74,21 @@ void main() vec3 viewVec = normalize(view.xyz); //get wave 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; + vec2 bigwave = vec2(refCoord.w, view.w); + vec3 wave1_a = texture2D(bumpMap, bigwave ).xyz*2.0-1.0; + vec3 wave2_a = texture2D(bumpMap, littleWave.xy).xyz*2.0-1.0; + vec3 wave3_a = texture2D(bumpMap, littleWave.zw).xyz*2.0-1.0; + + + vec3 wave1_b = texture2D(bumpMap2, bigwave ).xyz*2.0-1.0; + vec3 wave2_b = texture2D(bumpMap2, littleWave.xy).xyz*2.0-1.0; + vec3 wave3_b = texture2D(bumpMap2, littleWave.zw).xyz*2.0-1.0; + + vec3 wave1 = BlendNormal(wave1_a, wave1_b); + vec3 wave2 = BlendNormal(wave2_a, wave2_b); + vec3 wave3 = BlendNormal(wave3_a, wave3_b); + + //get base fresnel components vec3 df = vec3( @@ -136,6 +157,12 @@ void main() color.rgb = atmosTransport(color.rgb); color.rgb = scaleSoftClip(color.rgb); color.a = spec * sunAngle2; - + frag_color = color; + +#if defined(WATER_EDGE) + gl_FragDepth = 0.9999847f; +#endif + } + diff --git a/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl b/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl index 4bdfce9260..df640cba05 100644 --- a/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl +++ b/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl @@ -1,5 +1,5 @@ /** - * @file waterFogF.glsl + * @file class1\environment\waterFogF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -25,7 +25,6 @@ -uniform vec4 lightnorm; uniform vec4 waterPlane; uniform vec4 waterFogColor; uniform float waterFogDensity; @@ -33,42 +32,48 @@ uniform float waterFogKS; vec3 getPositionEye(); -vec4 applyWaterFog(vec4 color) +vec4 applyWaterFogView(vec3 pos, vec4 color) { - //normalize view vector - vec3 view = normalize(getPositionEye()); - float es = -(dot(view, waterPlane.xyz)); + vec3 view = normalize(pos); + //normalize view vector + 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; - //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(getPositionEye() - int_v); - - //get "thickness" of water - float l = max(depth, 0.1); + return color; +} - 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; +vec4 applyWaterFog(vec4 color) +{ + //normalize view vector + return applyWaterFogView(getPositionEye(), color); } diff --git a/indra/newview/app_settings/shaders/class1/environment/waterV.glsl b/indra/newview/app_settings/shaders/class1/environment/waterV.glsl index 352cea7aaa..cc41e3f740 100644 --- a/indra/newview/app_settings/shaders/class1/environment/waterV.glsl +++ b/indra/newview/app_settings/shaders/class1/environment/waterV.glsl @@ -1,5 +1,5 @@ /** - * @file waterV.glsl + * @file class1\environment\waterV.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -31,8 +31,8 @@ ATTRIBUTE vec3 position; void calcAtmospherics(vec3 inPositionEye); -uniform vec2 d1; -uniform vec2 d2; +uniform vec2 waveDir1; +uniform vec2 waveDir2; uniform float time; uniform vec3 eyeVec; uniform float waterHeight; @@ -86,10 +86,10 @@ void main() //pass wave parameters to pixel shader - vec2 bigWave = (v.xy) * vec2(0.04,0.04) + d1 * time * 0.055; + vec2 bigWave = (v.xy) * vec2(0.04,0.04) + waveDir1 * time * 0.055; //get two normal map (detail map) texture coordinates - littleWave.xy = (v.xy) * vec2(0.45, 0.9) + d2 * time * 0.13; - littleWave.zw = (v.xy) * vec2(0.1, 0.2) + d1 * time * 0.1; + littleWave.xy = (v.xy) * vec2(0.45, 0.9) + waveDir2 * time * 0.13; + littleWave.zw = (v.xy) * vec2(0.1, 0.2) + waveDir1 * time * 0.1; view.w = bigWave.y; refCoord.w = bigWave.x; diff --git a/indra/newview/app_settings/shaders/class1/interface/customalphaF.glsl b/indra/newview/app_settings/shaders/class1/interface/customalphaF.glsl index a96d04cc39..f6b31a5956 100644 --- a/indra/newview/app_settings/shaders/class1/interface/customalphaF.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/customalphaF.glsl @@ -38,7 +38,9 @@ VARYING vec2 vary_texcoord0; void main() { - vec4 color = vertex_color*texture2D(diffuseMap, vary_texcoord0.xy); - color.a *= custom_alpha; + vec4 color = texture2D(diffuseMap, vary_texcoord0.xy); + color.rgb = pow(color.rgb, vec3(0.45)); + color.rgb *= vertex_color.rgb; + color.a *= max(custom_alpha, vertex_color.a); frag_color = color; } diff --git a/indra/newview/app_settings/shaders/class1/interface/glowcombineF.glsl b/indra/newview/app_settings/shaders/class1/interface/glowcombineF.glsl index 5c088b3a3c..b5bbbb5c73 100644 --- a/indra/newview/app_settings/shaders/class1/interface/glowcombineF.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/glowcombineF.glsl @@ -25,14 +25,14 @@ #extension GL_ARB_texture_rectangle : enable +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; #else #define frag_color gl_FragColor #endif -/*[EXTRA_CODE_HERE]*/ - uniform sampler2D glowMap; uniform sampler2DRect screenMap; diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl index cad5b9ff04..0bb48061e0 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl @@ -1,5 +1,5 @@ /** - * @file lightAlphaMaskF.glsl + * @file class1\lighting\lightAlphaMaskF.glsl * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code @@ -31,6 +31,9 @@ out vec4 frag_color; uniform float minimum_alpha; +// render_hud_attachments() -> HUD objects set LLShaderMgr::NO_ATMO; +uniform int no_atmo; + vec3 atmosLighting(vec3 light); vec3 scaleSoftClip(vec3 light); @@ -41,16 +44,19 @@ void default_lighting() { vec4 color = diffuseLookup(vary_texcoord0.xy); - color *= vertex_color; - if (color.a < minimum_alpha) { discard; } + + color *= vertex_color; - color.rgb = atmosLighting(color.rgb); - - color.rgb = scaleSoftClip(color.rgb); + // SL-9632 HUDs are affected by Atmosphere + if (no_atmo == 0) + { + color.rgb = atmosLighting(color.rgb); + color.rgb = scaleSoftClip(color.rgb); + } frag_color = color; } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl index 8918182853..b768d609f4 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl @@ -1,5 +1,5 @@ /** - * @file lightAlphaMaskNonIndexedF.glsl + * @file class1\lighting\lightAlphaMaskNonIndexedF.glsl * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightF.glsl index d6ebfcb825..9fd189358b 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightF.glsl @@ -1,5 +1,5 @@ /** - * @file lightF.glsl + * @file class1\lighting\lightF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightAlphaMaskF.glsl index 5740987ab1..1855cfceeb 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightAlphaMaskF.glsl @@ -1,5 +1,5 @@ /** - * @file lightFullbrightAlphaMaskF.glsl + * @file class1\lighting\lightFullbrightAlphaMaskF.glsl * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code @@ -30,7 +30,10 @@ out vec4 frag_color; #endif uniform float minimum_alpha; -uniform float texture_gamma; +uniform float texture_gamma; // either 1.0 or 2.2; see: "::TEXTURE_GAMMA" + +// render_hud_attachments() -> HUD objects set LLShaderMgr::NO_ATMO; used in LLDrawPoolAlpha::beginRenderPass() +uniform int no_atmo; vec3 fullbrightAtmosTransport(vec3 light); vec3 fullbrightScaleSoftClip(vec3 light); @@ -50,9 +53,17 @@ void fullbright_lighting() color.rgb *= vertex_color.rgb; color.rgb = pow(color.rgb, vec3(texture_gamma)); - color.rgb = fullbrightAtmosTransport(color.rgb); - - color.rgb = fullbrightScaleSoftClip(color.rgb); + + // SL-9632 HUDs are affected by Atmosphere + if (no_atmo == 0) + { + color.rgb = fullbrightAtmosTransport(color.rgb); + color.rgb = fullbrightScaleSoftClip(color.rgb); + } + + //*TODO: Are we missing an inverse pow() here? + // class1\lighting\lightFullbrightF.glsl has: + // color.rgb = pow(color.rgb, vec3(1.0/texture_gamma)); frag_color = color; } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl index c8771a3f1e..5fcdf3107c 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl @@ -1,5 +1,5 @@ /** - * @file lightFullbrightF.glsl + * @file class1\lighting\lightFullbrightF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -34,6 +34,9 @@ VARYING vec2 vary_texcoord0; uniform float texture_gamma; +// render_hud_attachments() -> HUD objects set LLShaderMgr::NO_ATMO; +uniform int no_atmo; + vec3 fullbrightAtmosTransport(vec3 light); vec3 fullbrightScaleSoftClip(vec3 light); @@ -43,9 +46,12 @@ void fullbright_lighting() color.rgb = pow(color.rgb, vec3(texture_gamma)); - color.rgb = fullbrightAtmosTransport(color.rgb); - - color.rgb = fullbrightScaleSoftClip(color.rgb); + // SL-9632 HUDs are affected by Atmosphere + if (no_atmo == 0) + { + color.rgb = fullbrightAtmosTransport(color.rgb); + color.rgb = fullbrightScaleSoftClip(color.rgb); + } color.rgb = pow(color.rgb, vec3(1.0/texture_gamma)); diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightNonIndexedAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightNonIndexedAlphaMaskF.glsl index f72f20b03d..e8e71beb44 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightNonIndexedAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightNonIndexedAlphaMaskF.glsl @@ -1,5 +1,5 @@ /** - * @file lightFullbrightNonIndexedAlphaMaskF.glsl + * @file class1\lighting\lightFullbrightNonIndexedAlphaMaskF.glsl * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightNonIndexedF.glsl index 2738ff8947..11a0919086 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightNonIndexedF.glsl @@ -1,5 +1,5 @@ /** - * @file lightFullbrightF.glsl + * @file class1\lighting\lightFullbrightF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl index c8282e9a51..5e966293c6 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl @@ -1,5 +1,5 @@ /** - * @file lightFullbrightShinyF.glsl + * @file class1\lighting\lightFullbrightShinyF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -35,20 +35,37 @@ VARYING vec3 vary_texcoord1; uniform samplerCube environmentMap; +// render_hud_attachments() -> HUD objects set LLShaderMgr::NO_ATMO; used in LLDrawPoolAlpha::beginRenderPass() +uniform int no_atmo; + vec3 fullbrightShinyAtmosTransport(vec3 light); vec3 fullbrightScaleSoftClip(vec3 light); +// See: +// class1\deferred\fullbrightShinyF.glsl +// class1\lighting\lightFullbrightShinyF.glsl void fullbright_shiny_lighting() { vec4 color = diffuseLookup(vary_texcoord0.xy); color.rgb *= vertex_color.rgb; + // SL-9632 HUDs are affected by Atmosphere + if (no_atmo == 0) + { vec3 envColor = textureCube(environmentMap, vary_texcoord1.xyz).rgb; - color.rgb = mix(color.rgb, envColor.rgb, vertex_color.a); + color.rgb = mix(color.rgb, envColor.rgb, vertex_color.a*0.75); // MAGIC NUMBER SL-12574; ALM: Off, Quality > Low color.rgb = fullbrightShinyAtmosTransport(color.rgb); - color.rgb = fullbrightScaleSoftClip(color.rgb); + } +/* + // NOTE: HUD objects will be full bright. Uncomment if you want "some" environment lighting effecting these HUD objects. + else + { + vec3 envColor = textureCube(environmentMap, vary_texcoord1.xyz).rgb; + color.rgb = mix(color.rgb, envColor.rgb, vertex_color.a*0.75); // MAGIC NUMBER SL-12574; ALM: Off, Quality > Low + } +*/ color.a = 1.0; diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyNonIndexedF.glsl index e7dbd4bbd2..3118453342 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyNonIndexedF.glsl @@ -1,5 +1,5 @@ /** - * @file lightFullbrightShinyF.glsl + * @file class1\lighting\lightFullbrightShinyF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterF.glsl index 5886fc65be..f78e5e0e8a 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterF.glsl @@ -1,5 +1,5 @@ /** - * @file lightFullbrightShinyWaterF.glsl + * @file class1\lighting\lightFullbrightShinyWaterF.glsl * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2007, Linden Research, Inc. diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterNonIndexedF.glsl index cddc7d8df8..90668bd2b6 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterNonIndexedF.glsl @@ -1,5 +1,5 @@ /** - * @file lightFullbrightShinyWaterF.glsl + * @file class1\lighting\lightFullbrightShinyWaterF.glsl * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2007, Linden Research, Inc. diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl index 6dd3bb937f..d04cd79f4b 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl @@ -1,5 +1,5 @@ /** - * @file lightFullbrightWaterAlphaMaskF.glsl + * @file class1\lighting\lightFullbrightWaterAlphaMaskF.glsl * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl index d3dacf9bc4..27880b720c 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl @@ -1,5 +1,5 @@ /** - * @file lightFullbrightWaterF.glsl + * @file class1\lighting\lightFullbrightWaterF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl index 63f92a8844..3b9c04b22b 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl @@ -1,5 +1,5 @@ /** - * @file lightFullbrightWaterNonIndexedAlphaMaskF.glsl + * @file class1\lighting\lightFullbrightWaterNonIndexedAlphaMaskF.glsl * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedF.glsl index 0e68091e7c..e9fd8ac820 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedF.glsl @@ -1,5 +1,5 @@ /** - * @file lightFullbrightWaterF.glsl + * @file class1\lighting\lightFullbrightWaterF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFuncSpecularV.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFuncSpecularV.glsl index 85cddc647d..13a6dde4aa 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFuncSpecularV.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFuncSpecularV.glsl @@ -1,5 +1,5 @@ /** - * @file lightFuncSpecularV.glsl + * @file class1/lighting\lightFuncSpecularV.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -23,14 +23,6 @@ * $/LicenseInfo$ */ - - -float calcDirectionalLight(vec3 n, vec3 l) -{ - float a = max(dot(n,l),0.0); - return a; -} - float calcDirectionalSpecular(vec3 view, vec3 n, vec3 l) { return pow(max(dot(reflect(view, n),l), 0.0),8.0); diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl index a9288b3df6..45701002b8 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl @@ -1,5 +1,5 @@ /** - * @file lightFuncV.glsl + * @file class1\lighting\lightFuncV.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -32,8 +32,7 @@ float calcDirectionalLight(vec3 n, vec3 l) return a; } - -float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight) +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; @@ -54,6 +53,6 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa //angular attenuation da *= calcDirectionalLight(n, lv); - return da; + 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..f9c7ad2ab3 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightNonIndexedF.glsl @@ -1,5 +1,5 @@ /** - * @file lightF.glsl + * @file class1\lighting\lightF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl index 9208c148ef..f621a00785 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl @@ -1,5 +1,5 @@ /** - * @file lightShinyF.glsl + * @file class1\lighting\lightShinyF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -45,7 +45,7 @@ void shiny_lighting() 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 = mix(color.rgb, envColor.rgb, vertex_color.a*0.75); // MAGIC NUMBER SL-12574; ALM: Off, Quality > Low color.rgb = atmosLighting(color.rgb); diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightShinyNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightShinyNonIndexedF.glsl index 92628faa68..2b6f414005 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightShinyNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightShinyNonIndexedF.glsl @@ -1,5 +1,5 @@ /** - * @file lightShinyF.glsl + * @file class1\lighting\lightShinyF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl index 61841674e2..0f3371eba9 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl @@ -1,5 +1,5 @@ /** - * @file lightShinyWaterF.glsl + * @file class1\lighting\lightShinyWaterF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterNonIndexedF.glsl index 0b6e835fd0..c607fa64cb 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterNonIndexedF.glsl @@ -1,5 +1,5 @@ /** - * @file lightShinyWaterF.glsl + * @file class1\lighting\lightShinyWaterNonIndexedF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightSpecularV.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightSpecularV.glsl index 24bf9b3cee..06aed40e26 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightSpecularV.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightSpecularV.glsl @@ -1,5 +1,5 @@ /** - * @file lightSpecularV.glsl + * @file class1\lighting\lightSpecularV.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -27,10 +27,10 @@ // All lights, no specular highlights -vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol); +vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor); -vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol) +vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor) { - return sumLightsSpecular(pos, norm, color, specularColor, baseCol); + return sumLightsSpecular(pos, norm, color, specularColor); } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightV.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightV.glsl index 8045809b82..5e39d1629d 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightV.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightV.glsl @@ -1,5 +1,5 @@ /** - * @file lightV.glsl + * @file class1\lighting\lightV.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -26,11 +26,18 @@ // All lights, no specular highlights +vec3 atmosAmbient(); +vec4 sumLights(vec3 pos, vec3 norm, vec4 color); +float getAmbientClamp(); -vec4 sumLights(vec3 pos, vec3 norm, vec4 color, vec4 baseLight); - -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseLight) +vec4 calcLighting(vec3 pos, vec3 norm, vec4 color) { - return sumLights(pos, norm, color, baseLight); + vec4 c = sumLights(pos, norm, color); + +#if !defined(AMBIENT_KILL) + c.rgb += atmosAmbient() * color.rgb * 0.5 * getAmbientClamp(); +#endif + + return c; } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl index 3426fea52f..0916797259 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl @@ -1,5 +1,5 @@ /** - * @file lightWaterAlphaMaskF.glsl + * @file class1\lighting\lightWaterAlphaMaskF.glsl * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl index d9faa9b314..f2a84f1d42 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl @@ -1,5 +1,5 @@ /** - * @file lightWaterAlphaMaskNonIndexedF.glsl + * @file class1\lighting\lightWaterAlphaMaskNonIndexedF.glsl * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl index 00609e93cd..57ed993a66 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl @@ -1,5 +1,5 @@ /** - * @file lightWaterF.glsl + * @file class1\lighting\lightWaterF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterNonIndexedF.glsl index 13ecb7a636..af5da1411b 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightWaterNonIndexedF.glsl @@ -1,5 +1,5 @@ /** - * @file lightWaterF.glsl + * @file class1\lighting\lightWaterNonIndexedF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl b/indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl index 7059ff31ae..7c3697c333 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl @@ -1,5 +1,5 @@ /** - * @file sumLightsSpecularV.glsl + * @file class1\lighting\sumLightsSpecularV.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -26,7 +26,7 @@ float calcDirectionalLightSpecular(inout vec4 specular, vec3 view, vec3 n, vec3 l, vec3 lightCol, float da); -vec3 atmosAmbient(vec3 light); +vec3 atmosAmbient(); vec3 atmosAffectDirectionalLight(float lightIntensity); vec3 atmosGetDiffuseSunlightColor(); vec3 scaleDownLight(vec3 light); @@ -34,7 +34,7 @@ vec3 scaleDownLight(vec3 light); uniform vec4 light_position[8]; uniform vec3 light_diffuse[8]; -vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol) +vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor) { vec4 col = vec4(0,0,0, color.a); @@ -45,8 +45,8 @@ vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor col.rgb += light_diffuse[1].rgb * calcDirectionalLightSpecular(specularColor, view, norm, light_position[1].xyz,light_diffuse[1].rgb, 1.0); col.rgb = scaleDownLight(col.rgb); - col.rgb += atmosAmbient(baseCol.rgb); - col.rgb += atmosAffectDirectionalLight(calcDirectionalLightSpecular(specularSum, view, norm, light_position[0].xyz,atmosGetDiffuseSunlightColor()*baseCol.a, 1.0)); + col.rgb += atmosAmbient(); + col.rgb += atmosAffectDirectionalLight(calcDirectionalLightSpecular(specularSum, view, norm, light_position[0].xyz, atmosGetDiffuseSunlightColor(), 1.0)); col.rgb = min(col.rgb * color.rgb, 1.0); specularColor.rgb = min(specularColor.rgb * specularSum.rgb, 1.0); diff --git a/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl index 41288c21c1..0c3ea4231e 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl @@ -1,5 +1,5 @@ /** - * @file sumLightsV.glsl + * @file class1\lighting\sumLightsV.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -28,22 +28,27 @@ uniform vec3 light_diffuse[8]; float calcDirectionalLight(vec3 n, vec3 l); -vec3 atmosAmbient(vec3 light); +vec3 atmosAmbient(); vec3 atmosAffectDirectionalLight(float lightIntensity); vec3 scaleDownLight(vec3 light); -vec4 sumLights(vec3 pos, vec3 norm, vec4 color, vec4 baseLight) +vec4 sumLights(vec3 pos, vec3 norm, vec4 color) { - vec4 col; + vec4 col = vec4(0); col.a = color.a; col.rgb = light_diffuse[1].rgb * calcDirectionalLight(norm, light_position[1].xyz); col.rgb = scaleDownLight(col.rgb); - col.rgb += atmosAmbient(baseLight.rgb); + +#if defined(LOCAL_LIGHT_KILL) + col.rgb = vec3(0); +#endif + +#if !defined(SUNLIGHT_KILL) col.rgb += atmosAffectDirectionalLight(calcDirectionalLight(norm, light_position[0].xyz)); - +#endif + col.rgb = min(col.rgb*color.rgb, 1.0); - return col; } diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightF.glsl index a54c0caf81..31a262f1db 100644 --- a/indra/newview/app_settings/shaders/class1/objects/fullbrightF.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightF.glsl @@ -1,5 +1,5 @@ /** - * @file fullbrightF.glsl + * @file objects/fullbrightF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl index 79b552ee1a..1e244d9dfd 100644 --- a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl @@ -35,6 +35,7 @@ ATTRIBUTE vec2 texcoord0; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; VARYING vec3 vary_texcoord1; +VARYING vec4 vary_position; void calcAtmospherics(vec3 inPositionEye); @@ -46,6 +47,9 @@ void main() mat = modelview_matrix * mat; vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; + + mat4 mvp = modelview_matrix * projection_matrix; + vary_position = mvp * vec4(position, 1.0); vec4 norm = vec4(position.xyz, 1.0); norm.xyz += normal.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..4bb588335a 100644 --- a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl @@ -52,7 +52,7 @@ float calcDirectionalLight(vec3 n, vec3 l) } -float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight) +float calcLocalLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight) { //get light vector vec3 lv = lp.xyz-v; @@ -91,8 +91,7 @@ void main() // 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[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[2].rgb*calcLocalLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].z); + col.rgb += light_diffuse[3].rgb*calcLocalLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].z); vertex_color = col*color; } diff --git a/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl index 591d6fc5c9..727bae19c0 100644 --- a/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl @@ -36,7 +36,7 @@ VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; VARYING vec3 vary_texcoord1; -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); +vec4 calcLighting(vec3 pos, vec3 norm, vec4 color); void calcAtmospherics(vec3 inPositionEye); mat4 getObjectSkinnedTransform(); @@ -59,7 +59,7 @@ void main() calcAtmospherics(pos.xyz); - vec4 color = calcLighting(pos.xyz, norm.xyz, diffuse_color, vec4(0.)); + vec4 color = calcLighting(pos.xyz, norm.xyz, diffuse_color); vertex_color = color; gl_Position = projection_matrix*vec4(pos, 1.0); diff --git a/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl index fdb3453cc5..4ba8194d03 100644 --- a/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl @@ -39,7 +39,7 @@ VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; VARYING vec3 vary_texcoord1; -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); +vec4 calcLighting(vec3 pos, vec3 norm, vec4 color); void calcAtmospherics(vec3 inPositionEye); @@ -61,5 +61,5 @@ void main() calcAtmospherics(pos.xyz); - vertex_color = calcLighting(pos.xyz, norm, diffuse_color, vec4(0.0)); + vertex_color = calcLighting(pos.xyz, norm, diffuse_color); } diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleNoColorV.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleNoColorV.glsl index 0be52a52af..22821a2f76 100644 --- a/indra/newview/app_settings/shaders/class1/objects/simpleNoColorV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/simpleNoColorV.glsl @@ -38,7 +38,7 @@ VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); +vec4 calcLighting(vec3 pos, vec3 norm, vec4 color); void calcAtmospherics(vec3 inPositionEye); void main() @@ -52,7 +52,7 @@ void main() calcAtmospherics(pos.xyz); - vec4 col = calcLighting(pos.xyz, norm, color, vec4(0.)); + vec4 col = calcLighting(pos.xyz, norm, color); vertex_color = col; diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleNonIndexedV.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleNonIndexedV.glsl index cb80697d15..e605676819 100644 --- a/indra/newview/app_settings/shaders/class1/objects/simpleNonIndexedV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/simpleNonIndexedV.glsl @@ -37,7 +37,7 @@ VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); +vec4 calcLighting(vec3 pos, vec3 norm, vec4 color); void calcAtmospherics(vec3 inPositionEye); void main() @@ -54,7 +54,7 @@ void main() calcAtmospherics(pos.xyz); - vec4 color = calcLighting(pos.xyz, norm, diffuse_color, vec4(0.)); + vec4 color = calcLighting(pos.xyz, norm, diffuse_color); vertex_color = color; diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl index 1c6e53b187..df31b5a79f 100644 --- a/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl @@ -35,7 +35,7 @@ VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); +vec4 calcLighting(vec3 pos, vec3 norm, vec4 color); void calcAtmospherics(vec3 inPositionEye); mat4 getObjectSkinnedTransform(); @@ -56,7 +56,7 @@ void main() calcAtmospherics(pos.xyz); - vec4 color = calcLighting(pos.xyz, norm.xyz, diffuse_color, vec4(0.)); + vec4 color = calcLighting(pos.xyz, norm.xyz, diffuse_color); vertex_color = color; gl_Position = projection_matrix*vec4(pos, 1.0); diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleTexGenV.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleTexGenV.glsl index d4dee78793..945f80f31e 100644 --- a/indra/newview/app_settings/shaders/class1/objects/simpleTexGenV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/simpleTexGenV.glsl @@ -37,7 +37,7 @@ uniform vec4 color; uniform vec4 object_plane_t; uniform vec4 object_plane_s; -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); +vec4 calcLighting(vec3 pos, vec3 norm, vec4 color); void calcAtmospherics(vec3 inPositionEye); VARYING vec4 vertex_color; @@ -70,7 +70,7 @@ void main() calcAtmospherics(pos.xyz); - vec4 color = calcLighting(pos.xyz, norm, color, vec4(0.)); + vec4 color = calcLighting(pos.xyz, norm, color); vertex_color = color; diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl index 37a20383e2..9ef7704b70 100644 --- a/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl @@ -1,4 +1,4 @@ -/** +/** * @file simpleV.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ @@ -28,13 +28,16 @@ uniform mat4 texture_matrix0; uniform mat4 modelview_matrix; uniform mat4 modelview_projection_matrix; +// render_hud_attachments() -> HUD objects set LLShaderMgr::NO_ATMO; used in LLDrawPoolAlpha::beginRenderPass() +uniform int no_atmo; + ATTRIBUTE vec3 position; void passTextureIndex(); ATTRIBUTE vec2 texcoord0; ATTRIBUTE vec3 normal; ATTRIBUTE vec4 diffuse_color; -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); +vec4 calcLighting(vec3 pos, vec3 norm, vec4 color); void calcAtmospherics(vec3 inPositionEye); @@ -46,19 +49,23 @@ 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); + + passTextureIndex(); vary_texcoord0 = (texture_matrix0 * vec4(texcoord0, 0, 1)).xy; - - - - vec3 norm = normalize(normal_matrix * normal); - calcAtmospherics(pos.xyz); + // SL-9632 HUDs are affected by Atmosphere + if (no_atmo == 1) + { + vertex_color = diffuse_color; + } + else + { + vec4 pos = (modelview_matrix * vert); + vec3 norm = normalize(normal_matrix * normal); - vec4 color = calcLighting(pos.xyz, norm, diffuse_color, vec4(0.)); - vertex_color = color; + calcAtmospherics(pos.xyz); - + vertex_color = calcLighting(pos.xyz, norm, diffuse_color); + } } diff --git a/indra/newview/app_settings/shaders/class1/objects/treeV.glsl b/indra/newview/app_settings/shaders/class1/objects/treeV.glsl index fa01a27ec0..0227e6e3b8 100644 --- a/indra/newview/app_settings/shaders/class1/objects/treeV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/treeV.glsl @@ -31,8 +31,9 @@ uniform mat4 modelview_projection_matrix; ATTRIBUTE vec3 position; ATTRIBUTE vec2 texcoord0; ATTRIBUTE vec3 normal; +ATTRIBUTE vec4 diffuse_color; -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); +vec4 calcLighting(vec3 pos, vec3 norm, vec4 color); void calcAtmospherics(vec3 inPositionEye); VARYING vec4 vertex_color; @@ -53,8 +54,6 @@ void main() calcAtmospherics(pos.xyz); - vec4 color = calcLighting(pos.xyz, norm, vec4(1,1,1,1), vec4(0.)); + vec4 color = calcLighting(pos.xyz, norm, diffuse_color); vertex_color = color; - - } diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl index aacc503e13..4e0618e276 100644 --- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl +++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl @@ -1,5 +1,5 @@ /** - * @file atmosphericsF.glsl + * @file class1\windlight\atmosphericsF.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -23,11 +23,26 @@ * $/LicenseInfo$ */ +vec3 atmosFragAmbient(vec3 light, vec3 sunlit) +{ + /* stub function for fallback compatibility on class1 hardware */ + return light; +} +vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten) +{ + /* stub function for fallback compatibility on class1 hardware */ + return light; +} + +vec3 atmosFragAffectDirectionalLight(float light, vec3 sunlit) +{ + return light * sunlit; +} vec3 atmosLighting(vec3 light) { - /* stub function for fallback compatibility on class1 hardware */ - return light; + /* stub function for fallback compatibility on class1 hardware */ + return light; } diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl new file mode 100644 index 0000000000..ea2690ba09 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl @@ -0,0 +1,134 @@ +/** + * @file class1\windlight\atmosphericsFuncs.glsl + * + * $LicenseInfo:firstyear=2005&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$ + */ +uniform vec4 lightnorm; +uniform vec4 sunlight_color; +uniform vec4 moonlight_color; +uniform int sun_up_factor; +uniform vec4 ambient_color; +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 ssao_effect_mat; +uniform int no_atmo; +uniform float sun_moon_glow_factor; + +float getAmbientClamp() { return 1.0f; } + +void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, + out vec3 atten, bool use_ao) +{ + vec3 rel_pos = inPositionEye; + + //(TERRAIN) limit altitude + if (abs(rel_pos.y) > max_y) rel_pos *= (max_y / rel_pos.y); + + vec3 rel_pos_norm = normalize(rel_pos); + float rel_pos_len = length(rel_pos); + vec4 sunlight = (sun_up_factor == 1) ? sunlight_color : moonlight_color; + + // sunlight attenuation effect (hue and brightness) due to atmosphere + // this is used later for sunlight modulation at various altitudes + vec4 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 + + vec4 combined_haze = blue_density + vec4(haze_density); + vec4 blue_weight = blue_density / combined_haze; + vec4 haze_weight = vec4(haze_density) / combined_haze; + + //(TERRAIN) compute sunlight from lightnorm y component. Factor is roughly cosecant(sun elevation) (for short rays like terrain) + float above_horizon_factor = 1.0 / max(1e-6, lightnorm.y); + sunlight *= exp(-light_atten * above_horizon_factor); // for sun [horizon..overhead] this maps to an exp curve [0..1] + + // main atmospheric scattering line integral + float density_dist = rel_pos_len * density_multiplier; + + // Transparency (-> combined_haze) + // ATI Bugfix -- can't store combined_haze*density_dist*distance_multiplier in a variable because the ati + // compiler gets confused. + combined_haze = exp(-combined_haze * density_dist * distance_multiplier); + + // final atmosphere attenuation factor + atten = combined_haze.rgb; + + // compute haze glow + float haze_glow = dot(rel_pos_norm, lightnorm.xyz); + + // dampen sun additive contrib when not facing it... + // SL-13539: This "if" clause causes an "additive" white artifact at roughly 77 degreees. + // if (length(light_dir) > 0.01) + haze_glow *= max(0.0f, dot(light_dir, rel_pos_norm)); + + haze_glow = 1. - haze_glow; + // haze_glow is 0 at the sun and increases away from sun + haze_glow = max(haze_glow, .001); // set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) + haze_glow *= glow.x; + // higher glow.x gives dimmer glow (because next step is 1 / "angle") + haze_glow = pow(haze_glow, glow.z); + // glow.z should be negative, so we're doing a sort of (1 / "angle") function + + // add "minimum anti-solar illumination" + haze_glow += .25; + + haze_glow *= sun_moon_glow_factor; + + vec4 amb_color = ambient_color; + + // increase ambient when there are more clouds + vec4 tmpAmbient = amb_color + (vec4(1.) - amb_color) * cloud_shadow * 0.5; + + /* decrease value and saturation (that in HSV, not HSL) for occluded areas + * // for HSV color/geometry used here, see http://gimp-savvy.com/BOOK/index.html?node52.html + * // The following line of code performs the equivalent of: + * float ambAlpha = tmpAmbient.a; + * float ambValue = dot(vec3(tmpAmbient), vec3(0.577)); // projection onto <1/rt(3), 1/rt(3), 1/rt(3)>, the neutral white-black axis + * vec3 ambHueSat = vec3(tmpAmbient) - vec3(ambValue); + * tmpAmbient = vec4(RenderSSAOEffect.valueFactor * vec3(ambValue) + RenderSSAOEffect.saturationFactor *(1.0 - ambFactor) * ambHueSat, + * ambAlpha); + */ + if (use_ao) + { + tmpAmbient = vec4(mix(ssao_effect_mat * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a); + } + + // Similar/Shared Algorithms: + // indra\llinventory\llsettingssky.cpp -- LLSettingsSky::calculateLightSettings() + // indra\newview\app_settings\shaders\class1\windlight\atmosphericsFuncs.glsl -- calcAtmosphericVars() + // haze color + vec3 cs = sunlight.rgb * (1. - cloud_shadow); + additive = (blue_horizon.rgb * blue_weight.rgb) * (cs + tmpAmbient.rgb) + (haze_horizon * haze_weight.rgb) * (cs * haze_glow + tmpAmbient.rgb); + + // brightness of surface both sunlight and ambient + sunlit = sunlight.rgb * 0.5; + amblit = tmpAmbient.rgb * .25; + additive *= vec3(1.0 - combined_haze); +} diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersF.glsl new file mode 100644 index 0000000000..206a51db27 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersF.glsl @@ -0,0 +1,51 @@ +/** + * @file class1\windlight\atmosphericsHelpersF.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$ + */ + +uniform vec4 sunlight_color; +uniform vec4 light_ambient; +uniform int no_atmo; + +vec3 atmosAmbient() +{ + if (no_atmo == 1) return vec3(0.16); + return light_ambient.rgb; +} + +vec3 atmosAffectDirectionalLight(float lightIntensity) +{ + return sunlight_color.rgb * lightIntensity; +} + +vec3 atmosGetDiffuseSunlightColor() +{ + return sunlight_color.rgb; +} + +vec3 scaleDownLight(vec3 light) +{ + /* stub function for fallback compatibility on class1 hardware */ + return light; +} + diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl index 6ff860362c..c266f9732f 100644 --- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl +++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl @@ -1,5 +1,5 @@ /** - * @file atmosphericsHelpersV.glsl + * @file class1\windlight\atmosphericsHelpersV.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -23,33 +23,35 @@ * $/LicenseInfo$ */ -uniform vec4 sunlight_color_copy; +uniform vec4 sunlight_color; uniform vec4 light_ambient; +uniform int no_atmo; -vec3 atmosAmbient(vec3 light) +vec3 atmosAmbient() { - return light + light_ambient.rgb; + if (no_atmo == 1) return vec3(0.66); + return light_ambient.rgb; } vec3 atmosAffectDirectionalLight(float lightIntensity) { - return sunlight_color_copy.rgb * lightIntensity; + return sunlight_color.rgb * lightIntensity; } vec3 atmosGetDiffuseSunlightColor() { - return sunlight_color_copy.rgb; + return sunlight_color.rgb; } vec3 scaleDownLight(vec3 light) { - /* stub function for fallback compatibility on class1 hardware */ - return light; + /* stub function for fallback compatibility on class1 hardware */ + return light; } vec3 scaleUpLight(vec3 light) { - /* stub function for fallback compatibility on class1 hardware */ - return light; + /* stub function for fallback compatibility on class1 hardware */ + return light; } diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl index 76d7d5059d..20457ad125 100644 --- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl +++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl @@ -1,5 +1,5 @@ /** - * @file atmosphericsV.glsl + * @file class1\windlight\atmosphericsV.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -29,7 +29,7 @@ void setPositionEye(vec3 v); void calcAtmospherics(vec3 inPositionEye) { - /* stub function for fallback compatibility on class1 hardware */ - setPositionEye(inPositionEye); + /* stub function for fallback compatibility on class1 hardware */ + setPositionEye(inPositionEye); } diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl index 8bdae328bd..3b4d358cfa 100644 --- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl +++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl @@ -1,30 +1,37 @@ -/** - * @file atmosphericVarsF.glsl +/** + * @file class1\windlight\atmosphericVarsF.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 getPositionEye() -{ - return vec3(0,0,0); -} +VARYING vec3 vary_AdditiveColor; +VARYING vec3 vary_AtmosAttenuation; + +vec3 getAmblitColor() { return vec3(0, 0, 0); } + +vec3 getAdditiveColor() { return vary_AdditiveColor; } + +vec3 getAtmosAttenuation() { return vec3(vary_AtmosAttenuation); } + +vec3 getSunlitColor() { return vec3(0, 0, 0); } + +vec3 getPositionEye() { return vec3(0, 0, 0); } diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl index 8ec9ae617c..1fea2c3628 100644 --- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl +++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl @@ -1,36 +1,56 @@ -/** - * @file atmosphericVarsV.glsl +/** + * @file class1\windlight\atmosphericVarsV.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$ */ - +VARYING vec3 vary_AdditiveColor; +VARYING vec3 vary_AtmosAttenuation; -vec3 getPositionEye() +vec3 additive_color; +vec3 atmos_attenuation; +vec3 sunlit_color; +vec3 amblit_color; +vec3 position_eye; + +vec3 getSunlitColor() { return sunlit_color; } +void setSunlitColor(vec3 v) { sunlit_color = v; } + +vec3 getAdditiveColor() { return additive_color; } +void setAdditiveColor(vec3 v) { - return vec3(0,0,0); + additive_color = v; + vary_AdditiveColor = v; } -void setPositionEye(vec3 v) +vec3 getAmblitColor() { return amblit_color; } +void setAmblitColor(vec3 v) { amblit_color = v; } + +vec3 getAtmosAttenuation() { return atmos_attenuation; } +void setAtmosAttenuation(vec3 v) { - + atmos_attenuation = v; + vary_AtmosAttenuation = v; } + +vec3 getPositionEye() { return position_eye; } +void setPositionEye(vec3 v) { position_eye = v; } diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterF.glsl index 636d4af006..f83434b7ec 100644 --- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterF.glsl +++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterF.glsl @@ -1,33 +1,38 @@ -/** - * @file atmosphericVarsWaterF.glsl +/** + * @file class1\windlight\atmosphericVarsWaterF.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$ */ - VARYING vec3 vary_PositionEye; +VARYING vec3 vary_AdditiveColor; +VARYING vec3 vary_AtmosAttenuation; + +vec3 getSunlitColor() { return vec3(0, 0, 0); } + +vec3 getAmblitColor() { return vec3(0, 0, 0); } + +vec3 getAdditiveColor() { return vary_AdditiveColor; } -vec3 getPositionEye() -{ - return vary_PositionEye; -} +vec3 getAtmosAttenuation() { return vary_AtmosAttenuation; } +vec3 getPositionEye() { return vary_PositionEye; } diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterV.glsl index 8afcc20f6d..65d1176777 100644 --- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterV.glsl +++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterV.glsl @@ -1,37 +1,51 @@ -/** - * @file atmosphericVarsWaterV.glsl +/** + * @file class1\windlight\atmosphericVarsWaterV.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$ */ - - + VARYING vec3 vary_PositionEye; +VARYING vec3 vary_AdditiveColor; +VARYING vec3 vary_AtmosAttenuation; -vec3 getPositionEye() -{ - return vary_PositionEye; -} +vec3 atmos_attenuation; +vec3 sunlit_color; +vec3 amblit_color; + +vec3 getSunlitColor() { return sunlit_color; } +void setSunlitColor(vec3 v) { sunlit_color = v; } + +vec3 getAmblitColor() { return amblit_color; } +void setAmblitColor(vec3 v) { amblit_color = v; } -void setPositionEye(vec3 v) +vec3 getAdditiveColor() { return vary_AdditiveColor; } +void setAdditiveColor(vec3 v) { vary_AdditiveColor = v; } + +vec3 getAtmosAttenuation() { return atmos_attenuation; } +void setAtmosAttenuation(vec3 v) { - vary_PositionEye = v; + atmos_attenuation = v; + vary_AtmosAttenuation = v; } + +vec3 getPositionEye() { return vary_PositionEye; } +void setPositionEye(vec3 v) { vary_PositionEye = v; } diff --git a/indra/newview/app_settings/shaders/class1/windlight/cloudShadowF.glsl b/indra/newview/app_settings/shaders/class1/windlight/cloudShadowF.glsl new file mode 100644 index 0000000000..82fad4db5a --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/windlight/cloudShadowF.glsl @@ -0,0 +1,127 @@ +/** + * @file class1/windlight/cloudShadowF.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$ + */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2D diffuseMap; + +VARYING vec4 pos; +VARYING float target_pos_x; +VARYING float vary_CloudDensity; +VARYING vec2 vary_texcoord0; +VARYING vec2 vary_texcoord1; +VARYING vec2 vary_texcoord2; +VARYING vec2 vary_texcoord3; + +uniform sampler2D cloud_noise_texture; +uniform sampler2D cloud_noise_texture_next; +uniform float blend_factor; +uniform vec4 cloud_pos_density1; +uniform vec4 cloud_pos_density2; +uniform vec4 sunlight_color; +uniform vec4 cloud_color; +uniform float cloud_shadow; +uniform float cloud_scale; +uniform float cloud_variance; +uniform vec3 camPosLocal; +uniform vec3 sun_dir; +uniform float sun_size; +uniform float far_z; + +#if !defined(DEPTH_CLAMP) +VARYING vec4 post_pos; +#endif + +vec4 cloudNoise(vec2 uv) +{ + vec4 a = texture2D(cloud_noise_texture, uv); + vec4 b = texture2D(cloud_noise_texture_next, uv); + vec4 cloud_noise_sample = mix(a, b, blend_factor); + return normalize(cloud_noise_sample); +} + +void main() +{ + if (cloud_scale >= 0.0001) + { + // Set variables + vec2 uv1 = vary_texcoord0.xy; + vec2 uv2 = vary_texcoord1.xy; + vec2 uv3 = vary_texcoord2.xy; + float cloudDensity = 2.0 * (cloud_shadow - 0.25); + + vec2 uv4 = vary_texcoord3.xy; + + vec2 disturbance = vec2(cloudNoise(uv1 / 8.0f).x, cloudNoise((uv3 + uv1) / 16.0f).x) * cloud_variance * (1.0f - cloud_scale * 0.25f); + vec2 disturbance2 = vec2(cloudNoise((uv1 + uv3) / 4.0f).x, cloudNoise((uv4 + uv2) / 8.0f).x) * cloud_variance * (1.0f - cloud_scale * 0.25f); + + // Offset texture coords + uv1 += cloud_pos_density1.xy + (disturbance * 0.2); //large texture, visible density + uv2 += cloud_pos_density1.xy; //large texture, self shadow + uv3 += cloud_pos_density2.xy; //small texture, visible density + uv4 += cloud_pos_density2.xy; //small texture, self shadow + + float density_variance = min(1.0, (disturbance.x* 2.0 + disturbance.y* 2.0 + disturbance2.x + disturbance2.y) * 4.0); + + cloudDensity *= 1.0 - (density_variance * density_variance); + + // Compute alpha1, the main cloud opacity + float alpha1 = (cloudNoise(uv1).x - 0.5) + (cloudNoise(uv3).x - 0.5) * cloud_pos_density2.z; + alpha1 = min(max(alpha1 + cloudDensity, 0.) * 10 * cloud_pos_density1.z, 1.); + + // And smooth + alpha1 = 1. - alpha1 * alpha1; + alpha1 = 1. - alpha1 * alpha1; + + if (alpha1 < 0.001f) + { + discard; + } + + // Compute alpha2, for self shadowing effect + // (1 - alpha2) will later be used as percentage of incoming sunlight + float alpha2 = (cloudNoise(uv2).x - 0.5); + alpha2 = min(max(alpha2 + cloudDensity, 0.) * 2.5 * cloud_pos_density1.z, 1.); + + // And smooth + alpha2 = 1. - alpha2; + alpha2 = 1. - alpha2 * alpha2; + + frag_color = vec4(alpha1, alpha1, alpha1, 1); + } + else + { + frag_color = vec4(1); + } + +#if !defined(DEPTH_CLAMP) + gl_FragDepth = max(post_pos.z/post_pos.w*0.5+0.5, 0.0); +#endif + +} diff --git a/indra/newview/app_settings/shaders/class1/windlight/cloudShadowV.glsl b/indra/newview/app_settings/shaders/class1/windlight/cloudShadowV.glsl new file mode 100644 index 0000000000..09b6004481 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/windlight/cloudShadowV.glsl @@ -0,0 +1,61 @@ +/** + * @file class1\windlight\cloudShadowV.glsl + * + * $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$ + */ + +uniform mat4 texture_matrix0; +uniform mat4 modelview_projection_matrix; +uniform float shadow_target_width; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec4 diffuse_color; +ATTRIBUTE vec2 texcoord0; + +#if !defined(DEPTH_CLAMP) +VARYING float pos_zd2; +#endif + +VARYING vec4 pos; +VARYING float target_pos_x; +VARYING vec2 vary_texcoord0; + +void passTextureIndex(); + +void main() +{ + //transform vertex + vec4 pre_pos = vec4(position.xyz, 1.0); + pos = modelview_projection_matrix * pre_pos; + target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x; + +#if !defined(DEPTH_CLAMP) + pos_zd2 = pos.z * 0.5; + gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); +#else + gl_Position = pos; +#endif + + passTextureIndex(); + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; +} diff --git a/indra/newview/app_settings/shaders/class1/windlight/gammaF.glsl b/indra/newview/app_settings/shaders/class1/windlight/gammaF.glsl index 62f4e51449..fc51e81177 100644 --- a/indra/newview/app_settings/shaders/class1/windlight/gammaF.glsl +++ b/indra/newview/app_settings/shaders/class1/windlight/gammaF.glsl @@ -1,5 +1,5 @@ /** - * @file gammaF.glsl + * @file class1\windlight\gammaF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -23,17 +23,30 @@ * $/LicenseInfo$ */ +uniform int no_atmo; - -uniform vec4 gamma; +vec3 scaleSoftClipFrag(vec3 light) +{ + // For compatibility with lower cards. Do nothing. + return light; +} /// Soft clips the light with a gamma correction -vec3 scaleSoftClip(vec3 light) { - // For compatibility with lower cards. Do nothing. +vec3 scaleSoftClip(vec3 light) +{ + // For compatibility with lower cards. Do nothing + return light; +} + +vec3 fullbrightScaleSoftClipFrag(vec3 light, vec3 additive, vec3 atten) +{ + // For compatibility with lower cards. Do nothing return light; } -vec3 fullbrightScaleSoftClip(vec3 light) { - return scaleSoftClip(light); +vec3 fullbrightScaleSoftClip(vec3 light) +{ + // For compatibility with lower cards. Do nothing + return light; } diff --git a/indra/newview/app_settings/shaders/class1/windlight/moonF.glsl b/indra/newview/app_settings/shaders/class1/windlight/moonF.glsl new file mode 100644 index 0000000000..2425a2ad04 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/windlight/moonF.glsl @@ -0,0 +1,66 @@ +/** + * @file class1\wl\moonF.glsl + * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2005, 2020 Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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 + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform vec4 color; +uniform vec4 sunlight_color; +uniform vec4 moonlight_color; +uniform vec3 moon_dir; +uniform float moon_brightness; +uniform sampler2D diffuseMap; + +VARYING vec2 vary_texcoord0; + +vec3 scaleSoftClip(vec3 light); + +void main() +{ + // Restore Pre-EEP alpha fade moon near horizon + float fade = 1.0; + if( moon_dir.z > 0 ) + fade = clamp( moon_dir.z*moon_dir.z*4.0, 0.0, 1.0 ); + + vec4 c = texture2D(diffuseMap, vary_texcoord0.xy); +// c.rgb = pow(c.rgb, vec3(0.7f)); // can't use "srgb_to_linear(color.rgb)" as that is a deferred only function + c.rgb *= moonlight_color.rgb; + c.rgb *= moon_brightness; + + c.rgb *= fade; + c.a *= fade; + + c.rgb = scaleSoftClip(c.rgb); + + frag_color = vec4(c.rgb, c.a); +} + diff --git a/indra/newview/app_settings/shaders/class1/windlight/moonV.glsl b/indra/newview/app_settings/shaders/class1/windlight/moonV.glsl new file mode 100644 index 0000000000..2fceb5f743 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/windlight/moonV.glsl @@ -0,0 +1,44 @@ +/** + * @file class1\wl\moonV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 2020 Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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_matrix; +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec2 texcoord0; + +VARYING vec2 vary_texcoord0; + +void main() +{ + //transform vertex + vec4 vert = vec4(position.xyz, 1.0); + vec4 pos = (modelview_matrix * vert); + + gl_Position = modelview_projection_matrix*vert; + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; +} diff --git a/indra/newview/app_settings/shaders/class1/windlight/sunDiscF.glsl b/indra/newview/app_settings/shaders/class1/windlight/sunDiscF.glsl new file mode 100644 index 0000000000..5a41dc644a --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/windlight/sunDiscF.glsl @@ -0,0 +1,58 @@ +/** + * @file class1\wl\sunDiscF.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 + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +vec3 fullbrightAtmosTransport(vec3 light); +vec3 fullbrightScaleSoftClip(vec3 light); + +uniform sampler2D diffuseMap; +uniform sampler2D altDiffuseMap; +uniform float blend_factor; // interp factor between sun A/B +VARYING vec2 vary_texcoord0; +VARYING float sun_fade; + +void main() +{ + vec4 sunA = texture2D(diffuseMap, vary_texcoord0.xy); + vec4 sunB = texture2D(altDiffuseMap, vary_texcoord0.xy); + vec4 c = mix(sunA, sunB, blend_factor); + +// SL-9806 stars poke through +// c.a *= sun_fade; + + c.rgb = fullbrightAtmosTransport(c.rgb); + c.rgb = fullbrightScaleSoftClip(c.rgb); + frag_color = c; +} + diff --git a/indra/newview/app_settings/shaders/class1/windlight/sunDiscV.glsl b/indra/newview/app_settings/shaders/class1/windlight/sunDiscV.glsl new file mode 100644 index 0000000000..6c0e795f6b --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/windlight/sunDiscV.glsl @@ -0,0 +1,51 @@ +/** + * @file class1\wl\sunDiscV.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_matrix; +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec2 texcoord0; + +VARYING vec2 vary_texcoord0; +VARYING float sun_fade; + +void calcAtmospherics(vec3 eye_pos); + +void main() +{ + //transform vertex + vec3 offset = vec3(0, 0, 50); + vec4 vert = vec4(position.xyz - offset, 1.0); + vec4 pos = modelview_projection_matrix*vert; + + sun_fade = smoothstep(0.3, 1.0, (position.z + 50) / 512.0f); + gl_Position = pos; + + calcAtmospherics(pos.xyz); + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; +} diff --git a/indra/newview/app_settings/shaders/class1/windlight/transportF.glsl b/indra/newview/app_settings/shaders/class1/windlight/transportF.glsl index 7c95ecdb14..a937d9fa99 100644 --- a/indra/newview/app_settings/shaders/class1/windlight/transportF.glsl +++ b/indra/newview/app_settings/shaders/class1/windlight/transportF.glsl @@ -1,5 +1,5 @@ /** - * @file transportF.glsl + * @file class1/windlight/transportF.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -22,25 +22,35 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - +uniform int no_atmo; -vec3 atmosTransport(vec3 light) +vec3 atmosTransportFrag(vec3 light, vec3 additive, vec3 atten) { - /* stub function for fallback compatibility on class1 hardware */ + /* stub function for fallback compatibility on class1 hardware */ return light; } -vec3 fullbrightAtmosTransport(vec3 light) +vec3 atmosTransport(vec3 light) { /* stub function for fallback compatibility on class1 hardware */ - return light; + return light; +} + +vec3 fullbrightAtmosTransportFrag(vec3 light, vec3 additive, vec3 atten) +{ + /* stub function for fallback compatibility on class1 hardware */ + return light; } +vec3 fullbrightAtmosTransport(vec3 light) +{ + /* stub function for fallback compatibility on class1 hardware */ + return light; +} vec3 fullbrightShinyAtmosTransport(vec3 light) { - /* stub function for fallback compatibility on class1 hardware */ - return light; + /* stub function for fallback compatibility on class1 hardware */ + return light; } - diff --git a/indra/newview/app_settings/shaders/class2/avatar/eyeballV.glsl b/indra/newview/app_settings/shaders/class2/avatar/eyeballV.glsl index 5af9f5c902..563c5f562b 100644 --- a/indra/newview/app_settings/shaders/class2/avatar/eyeballV.glsl +++ b/indra/newview/app_settings/shaders/class2/avatar/eyeballV.glsl @@ -37,7 +37,7 @@ VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol); +vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor); void calcAtmospherics(vec3 inPositionEye); void main() @@ -53,7 +53,7 @@ void main() // vec4 specular = specularColor; vec4 specular = vec4(1.0); - vec4 color = calcLightingSpecular(pos, norm, diffuse_color, specular, vec4(0.0)); + vec4 color = calcLightingSpecular(pos, norm, diffuse_color, specular); vertex_color = color; diff --git a/indra/win_crash_logger/StdAfx.cpp b/indra/newview/app_settings/shaders/class2/deferred/indirect.glsl index f56711af73..67b98e0fb1 100644 --- a/indra/win_crash_logger/StdAfx.cpp +++ b/indra/newview/app_settings/shaders/class2/deferred/indirect.glsl @@ -1,10 +1,9 @@ /** - * @file StdAfx.cpp - * @brief windows crash logger source file for includes + * @file class2/deferred/indirect.glsl * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * $LicenseInfo:firstyear=2018&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * 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 @@ -24,11 +23,10 @@ * $/LicenseInfo$ */ -// stdafx.cpp : source file that includes just the standard includes -// win_crash_logger.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information +float calcAmbientOcclusion(vec4 pos, vec3 norm, vec2 pos_screen); -#include "stdafx.h" +vec3 getIndirect(vec3 ambient, vec3 norm, vec4 pos, vec2 pos_screen) +{ + return ambient * calcAmbientOcclusion(pos, norm, pos_screen); +} -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file diff --git a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl index b9bb522842..1b7a1cc6ec 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl @@ -71,294 +71,229 @@ uniform vec2 screen_res; uniform mat4 inv_proj; -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)); - -#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 - -} - -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 - -} - -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 correctWithGamma(vec4 col) -{ - return vec4(srgb_to_linear(col.rgb), col.a); -} +vec3 srgb_to_linear(vec3 cs); +vec3 getNorm(vec2 pos_screen); vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) { - vec4 ret = texture2DLod(projectionMap, tc, lod); - ret.rgb = srgb_to_linear(ret.rgb); - - 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); + vec4 ret = texture2DLod(projectionMap, tc, lod); + ret.rgb = srgb_to_linear(ret.rgb); + 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; + 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 = correctWithGamma(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); - - float edge = 0.25*det; - - ret *= clamp(d/edge, 0.0, 1.0); - - return ret; + vec4 ret = texture2DLod(projectionMap, tc, lod); + ret.rgb = srgb_to_linear(ret.rgb); + + 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); + + float edge = 0.25*det; + + ret *= clamp(d/edge, 0.0, 1.0); + + return ret; } vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) { - vec4 ret = texture2DLod(projectionMap, tc, lod); - ret = correctWithGamma(ret); - - vec2 dist = tc-vec2(0.5); - - float d = dot(dist,dist); - - ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0); - - return ret; -} + vec4 ret = texture2DLod(projectionMap, tc, lod); + ret.rgb = srgb_to_linear(ret.rgb); - -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; + vec2 dist = tc-vec2(0.5); + + float d = dot(dist,dist); + + ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0); + + return ret; } +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 = center.xyz-pos.xyz; - 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); - float sh[2]; - sh[0] = shd.b; - sh[1] = shd.a; - shadow = min(sh[proj_shadow_idx]+shadow_fade, 1.0); - } - - vec3 norm = texture2DRect(normalMap, frag.xy).xyz; - - float envIntensity = norm.z; - - norm = decode_normal(norm.xy); - - norm = normalize(norm); - float l_dist = -dot(lv, proj_n); - - vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0)); - if (proj_tc.z < 0.0) - { - discard; - } - - proj_tc.xyz /= proj_tc.w; - - float fa = falloff+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; - } - - 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; - - vec4 spec = texture2DRect(specularRect, frag.xy); - - vec3 dlit = vec3(0, 0, 0); - - float noise = texture2D(noiseMap, frag.xy/128.0).b; - if (proj_tc.z > 0.0 && - proj_tc.x < 1.0 && - proj_tc.y < 1.0 && - proj_tc.x > 0.0 && - proj_tc.y > 0.0) - { - float amb_da = proj_ambiance; - float lit = 0.0; - - 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); - - 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; - } - - - if (spec.a > 0.0) - { - vec3 npos = -normalize(pos); - dlit *= min(da*6.0, 1.0) * dist_atten; - - //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); - - //project from point pos in direction ref to plane proj_p, proj_n - vec3 pdelta = proj_p-pos; - float ds = dot(ref, proj_n); - - 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) - { + + vec3 col = vec3(0,0,0); + +#if defined(LOCAL_LIGHT_KILL) + discard; +#else + 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 dist = length(lv); + + if (dist >= size) + { + discard; + } + dist /= size; + + float shadow = 1.0; + + if (proj_shadow_idx >= 0) + { + vec4 shd = texture2DRect(lightMap, frag.xy); + shadow = (proj_shadow_idx==0)?shd.b:shd.a; + shadow += shadow_fade; + shadow = clamp(shadow, 0.0, 1.0); + } + + vec3 norm = texture2DRect(normalMap, frag.xy).xyz; + + float envIntensity = norm.z; + + norm = getNorm(frag.xy); + + norm = normalize(norm); + float l_dist = -dot(lv, proj_n); + + vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0)); + if (proj_tc.z < 0.0) + { + discard; + } + + proj_tc.xyz /= proj_tc.w; + + float fa = falloff+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; + } + + lv = proj_origin-pos.xyz; + lv = normalize(lv); + float da = dot(norm, lv); + + vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb; + + vec4 spec = texture2DRect(specularRect, frag.xy); + + vec3 dlit = vec3(0, 0, 0); + + float noise = texture2D(noiseMap, frag.xy/128.0).b; + if (proj_tc.z > 0.0 && + proj_tc.x < 1.0 && + proj_tc.y < 1.0 && + proj_tc.x > 0.0 && + proj_tc.y > 0.0) + { + float amb_da = proj_ambiance; + float lit = 0.0; + + 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); + + dlit = color.rgb * plcol.rgb * plcol.a; + + col = dlit*lit*diff_tex*shadow; + + // unshadowed for consistency between forward and deferred? + amb_da += (da*0.5+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); + + // use unshadowed for consistency between forward and deferred? + amb_da += (da*da*0.5+0.5) /* * (1.0-shadow) */ * 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; + } + + + if (spec.a > 0.0) + { + vec3 npos = -normalize(pos); + dlit *= min(da*6.0, 1.0) * dist_atten; + + //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); + vec3 speccol = dlit*scol*spec.rgb*shadow; + speccol = clamp(speccol, vec3(0), vec3(1)); + col += speccol; + } + } + + if (envIntensity > 0.0) + { + vec3 ref = reflect(normalize(pos), norm); + + //project from point pos in direction ref to plane proj_p, proj_n + vec3 pdelta = proj_p-pos; + float ds = dot(ref, proj_n); + + 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 /= stc.w; - - if (stc.x < 1.0 && - stc.y < 1.0 && - stc.x > 0.0 && - stc.y > 0.0) - { - 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; + + if (stc.x < 1.0 && + stc.y < 1.0 && + stc.x > 0.0 && + stc.y > 0.0) + { + col += color.rgb * texture2DLodSpecular(projectionMap, stc.xy, (1 - spec.a) * (proj_lod * 0.6)).rgb * shadow * envIntensity; + } + } + } + } +#endif + + //not sure why, but this line prevents MATBUG-194 + col = max(col, vec3(0.0)); + + //output linear + frag_color.rgb = col; + frag_color.a = 0.0; } diff --git a/indra/newview/app_settings/shaders/class2/deferred/skyF.glsl b/indra/newview/app_settings/shaders/class2/deferred/skyF.glsl new file mode 100644 index 0000000000..6841a8194f --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/skyF.glsl @@ -0,0 +1,199 @@ +/** + * @file class2/deferred/skyF.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$ + */ + +uniform mat4 modelview_projection_matrix; + +// SKY //////////////////////////////////////////////////////////////////////// +// The vertex shader for creating the atmospheric sky +/////////////////////////////////////////////////////////////////////////////// + +// Inputs +uniform vec3 camPosLocal; + +uniform vec4 lightnorm; +uniform vec4 sunlight_color; +uniform vec4 moonlight_color; +uniform int sun_up_factor; +uniform vec4 ambient_color; +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 sun_moon_glow_factor; + +uniform vec4 cloud_color; + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_data[3]; +#else +#define frag_data gl_FragData +#endif + +VARYING vec3 pos; + +///////////////////////////////////////////////////////////////////////// +// The fragment shader for the sky +///////////////////////////////////////////////////////////////////////// + +uniform sampler2D rainbow_map; +uniform sampler2D halo_map; + +uniform float moisture_level; +uniform float droplet_radius; +uniform float ice_level; + +vec3 rainbow(float d) +{ + // d is the dot product of view and sun directions, so ranging -1.0..1.0 + // 'interesting' values of d are the range -0.75..-0.825, when view is nearly opposite of sun vec + // Rainbox texture mode is GL_REPEAT, so tc of -.75 is equiv to 0.25, -0.825 equiv to 0.175. + + // SL-13629 Rainbow texture has colors within the correct .175...250 range, but order is inverted. + // Rather than replace the texture, we mirror and translate the y tc to keep the colors within the + // interesting range, but in reversed order: i.e. d = (1 - d) - 1.575 + d = clamp(-0.575 - d, 0.0, 1.0); + + // With the colors in the lower 1/4 of the texture, inverting the coords leaves most of it inaccessible. + // So, we can stretch the texcoord above the colors (ie > 0.25) to fill the entire remaining coordinate + // space. This improves gradation, reduces banding within the rainbow interior. (1-0.25) / (0.425/0.25) = 4.2857 + float interior_coord = max(0.0, d - 0.25) * 4.2857; + d = clamp(d, 0.0, 0.25) + interior_coord; + + float rad = (droplet_radius - 5.0f) / 1024.0f; + return pow(texture2D(rainbow_map, vec2(rad, d)).rgb, vec3(1.8)) * moisture_level; +} + +vec3 halo22(float d) +{ + d = clamp(d, 0.1, 1.0); + float v = sqrt(clamp(1 - (d * d), 0, 1)); + return texture2D(halo_map, vec2(0, v)).rgb * ice_level; +} + +/// Soft clips the light with a gamma correction +vec3 scaleSoftClip(vec3 light); + +void main() +{ + // World / view / projection + // Get relative position (offset why?) + vec3 rel_pos = pos.xyz - camPosLocal.xyz + vec3(0, 50, 0); + + // Adj position vector to clamp altitude + if (rel_pos.y > 0.) + { + rel_pos *= (max_y / rel_pos.y); + } + if (rel_pos.y < 0.) + { + rel_pos *= (-32000. / rel_pos.y); + } + + // Normalized + vec3 rel_pos_norm = normalize(rel_pos); + float rel_pos_len = length(rel_pos); + + // Initialize temp variables + vec4 sunlight = (sun_up_factor == 1) ? sunlight_color : moonlight_color; + + // Sunlight attenuation effect (hue and brightness) due to atmosphere + // this is used later for sunlight modulation at various altitudes + vec4 light_atten = (blue_density + vec4(haze_density * 0.25)) * (density_multiplier * max_y); + + // Calculate relative weights + vec4 combined_haze = abs(blue_density) + vec4(abs(haze_density)); + vec4 blue_weight = blue_density / combined_haze; + vec4 haze_weight = haze_density / combined_haze; + + // Compute sunlight from rel_pos & lightnorm (for long rays like sky) + float off_axis = 1.0 / max(1e-6, max(0, rel_pos_norm.y) + lightnorm.y); + sunlight *= exp(-light_atten * off_axis); + + // Distance + float density_dist = rel_pos_len * density_multiplier; + + // Transparency (-> combined_haze) + // ATI Bugfix -- can't store combined_haze*density_dist in a variable because the ati + // compiler gets confused. + combined_haze = exp(-combined_haze * density_dist); + + // Compute haze glow + float haze_glow = dot(rel_pos_norm, lightnorm.xyz); + haze_glow = 1. - haze_glow; + // haze_glow is 0 at the sun and increases away from sun + haze_glow = max(haze_glow, .001); + // Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) + haze_glow *= glow.x; + // Higher glow.x gives dimmer glow (because next step is 1 / "angle") + haze_glow = pow(haze_glow, glow.z); + // glow.z should be negative, so we're doing a sort of (1 / "angle") function + + // Add "minimum anti-solar illumination" + // For sun, add to glow. For moon, remove glow entirely. SL-13768 + haze_glow = (sun_moon_glow_factor < 1.0) ? 0.0 : (sun_moon_glow_factor * (haze_glow + 0.25)); + + // Haze color above cloud + vec4 color = blue_horizon * blue_weight * (sunlight + ambient_color) + + haze_horizon * haze_weight * (sunlight * haze_glow + ambient_color); + + // Final atmosphere additive + color *= (1. - combined_haze); + + // Increase ambient when there are more clouds + // TODO 9/20: DJH what does this do? max(0,(1-ambient)) will change the color + vec4 ambient = ambient_color + max(vec4(0), (1. - ambient_color)) * cloud_shadow * 0.5; + + // Dim sunlight by cloud shadow percentage + sunlight *= max(0.0, (1. - cloud_shadow)); + + // Haze color below cloud + vec4 add_below_cloud = blue_horizon * blue_weight * (sunlight + ambient) + + haze_horizon * haze_weight * (sunlight * haze_glow + ambient); + + // Attenuate cloud color by atmosphere + combined_haze = sqrt(combined_haze); // less atmos opacity (more transparency) below clouds + + // At horizon, blend high altitude sky color towards the darker color below the clouds + color += (add_below_cloud - color) * (1. - sqrt(combined_haze)); + + float optic_d = dot(rel_pos_norm, lightnorm.xyz); + vec3 halo_22 = halo22(optic_d); + color.rgb += rainbow(optic_d); + color.rgb += halo_22; + color.rgb *= 2.; + color.rgb = scaleSoftClip(color.rgb); + + // Gamma correct for WL (soft clip effect). + frag_data[0] = vec4(color.rgb, 1.0); + frag_data[1] = vec4(0.0, 0.0, 0.0, 0.0); + frag_data[2] = vec4(0.0, 0.0, 0.0, 1.0); // 1.0 in norm.w masks off fog +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/skyV.glsl b/indra/newview/app_settings/shaders/class2/deferred/skyV.glsl new file mode 100644 index 0000000000..bcf775577a --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/skyV.glsl @@ -0,0 +1,42 @@ +/** + * @file WLSkyV.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$ + */ + +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; + +// SKY //////////////////////////////////////////////////////////////////////// +// The vertex shader for creating the atmospheric sky +/////////////////////////////////////////////////////////////////////////////// + +VARYING vec3 pos; + +void main() +{ + + // World / view / projection + pos = position.xyz; + gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl index f7832521fa..7700d16007 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl @@ -1,29 +1,30 @@ -/** - * @file softenLightF.glsl +/** + * @file class2/deferred/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$ */ - + #extension GL_ARB_texture_rectangle : enable +#extension GL_ARB_shader_texture_lod : enable /*[EXTRA_CODE_HERE]*/ @@ -38,457 +39,120 @@ uniform sampler2DRect specularRect; uniform sampler2DRect normalMap; uniform sampler2DRect lightMap; uniform sampler2DRect depthMap; -uniform samplerCube environmentMap; -uniform sampler2D lightFunc; +uniform samplerCube environmentMap; +uniform sampler2D lightFunc; uniform float blur_size; uniform float blur_fidelity; // 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 global_gamma; -uniform float scene_light_strength; uniform mat3 env_mat; -uniform vec4 shadow_clip; -uniform mat3 ssao_effect_mat; uniform vec3 sun_dir; +uniform vec3 moon_dir; +uniform int sun_up_factor; VARYING vec2 vary_fragcoord; -vec3 vary_PositionEye; - -vec3 vary_SunlitColor; -vec3 vary_AmblitColor; -vec3 vary_AdditiveColor; -vec3 vary_AtmosAttenuation; - uniform mat4 inv_proj; uniform vec2 screen_res; -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)); - -#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 +vec3 getNorm(vec2 pos_screen); +vec4 getPositionWithDepth(vec2 pos_screen, float depth); -} +void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten, bool use_ao); +float getAmbientClamp(); +vec3 atmosFragLighting(vec3 l, vec3 additive, vec3 atten); +vec3 scaleSoftClipFrag(vec3 l); +vec3 fullbrightAtmosTransportFrag(vec3 light, vec3 additive, vec3 atten); +vec3 fullbrightScaleSoftClip(vec3 light); -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 linear_to_srgb(vec3 c); +vec3 srgb_to_linear(vec3 c); -#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); +#ifdef WATER_FOG +vec4 applyWaterFogView(vec3 pos, vec4 color); #endif -} - -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_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; - pos /= pos.w; - pos.w = 1.0; - 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; -} -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, float ambFactor) { - - 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; - - /* decrease value and saturation (that in HSV, not HSL) for occluded areas - * // for HSV color/geometry used here, see http://gimp-savvy.com/BOOK/index.html?node52.html - * // The following line of code performs the equivalent of: - * float ambAlpha = tmpAmbient.a; - * float ambValue = dot(vec3(tmpAmbient), vec3(0.577)); // projection onto <1/rt(3), 1/rt(3), 1/rt(3)>, the neutral white-black axis - * vec3 ambHueSat = vec3(tmpAmbient) - vec3(ambValue); - * tmpAmbient = vec4(RenderSSAOEffect.valueFactor * vec3(ambValue) + RenderSSAOEffect.saturationFactor *(1.0 - ambFactor) * ambHueSat, ambAlpha); - */ - tmpAmbient = vec4(mix(ssao_effect_mat * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a); - - //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(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)); -} +void main() +{ + vec2 tc = vary_fragcoord.xy; + float depth = texture2DRect(depthMap, tc.xy).r; + vec4 pos = getPositionWithDepth(tc, depth); + vec4 norm = texture2DRect(normalMap, tc); + float envIntensity = norm.z; + norm.xyz = getNorm(tc); + + vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; + float da = clamp(dot(norm.xyz, light_dir.xyz), 0.0, 1.0); + float light_gamma = 1.0 / 1.3; + da = pow(da, light_gamma); + + vec4 diffuse = texture2DRect(diffuseRect, tc); + diffuse.rgb = linear_to_srgb(diffuse.rgb); // SL-14025 + vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy); + + vec2 scol_ambocc = texture2DRect(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; + + vec3 color = vec3(0); + float bloom = 0.0; + + vec3 sunlit; + vec3 amblit; + vec3 additive; + vec3 atten; + calcAtmosphericVars(pos.xyz, light_dir, ambocc, sunlit, amblit, additive, atten, true); + + color.rgb = amblit; + + float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0); + ambient *= 0.5; + ambient *= ambient; + ambient = (1.0 - ambient); + color.rgb *= ambient; + + vec3 sun_contrib = min(da, scol) * sunlit; + color.rgb += sun_contrib; + color.rgb *= diffuse.rgb; + + vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); + + if (spec.a > 0.0) // specular reflection + { + float sa = dot(refnormpersp, light_dir.xyz); + vec3 dumbshiny = sunlit * scol * (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; + color.rgb += spec_contrib; + } + + color.rgb = mix(color.rgb, diffuse.rgb, diffuse.a); + + if (envIntensity > 0.0) + { // add environmentmap + vec3 env_vec = env_mat * refnormpersp; + vec3 reflected_color = textureCube(environmentMap, env_vec).rgb; + color = mix(color.rgb, reflected_color, envIntensity); + } + + if (norm.w < 0.5) + { + color = mix(atmosFragLighting(color, additive, atten), fullbrightAtmosTransportFrag(color, additive, atten), diffuse.a); + color = mix(scaleSoftClipFrag(color), fullbrightScaleSoftClip(color), diffuse.a); + } #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; -} + vec4 fogged = applyWaterFogView(pos.xyz, vec4(color, bloom)); + color = fogged.rgb; + bloom = fogged.a; #endif -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 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(); -} - -vec3 scaleDownLight(vec3 light) -{ - return (light / scene_light_strength ); -} - -vec3 scaleUpLight(vec3 light) -{ - return (light * scene_light_strength); -} - -vec3 atmosAmbient(vec3 light) -{ - return getAmblitColor() + light / 2.0; -} - -vec3 atmosAffectDirectionalLight(float lightIntensity) -{ - return getSunlitColor() * lightIntensity; -} - -vec3 scaleSoftClip(vec3 light) -{ - //soft clip effect: - light = 1. - clamp(light, vec3(0.), vec3(1.)); - light = 1. - pow(light, gamma.xxx); - - return light; -} - - -vec3 fullbrightScaleSoftClip(vec3 light) -{ - //soft clip effect: - return light; -} - -void main() -{ - vec2 tc = vary_fragcoord.xy; - float depth = texture2DRect(depthMap, tc.xy).r; - vec3 pos = getPosition_d(tc, depth).xyz; - vec4 norm = texture2DRect(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); - - float light_gamma = 1.0/1.3; - da = pow(da, light_gamma); - - - vec4 diffuse = texture2DRect(diffuseRect, tc); - - //convert to gamma space - diffuse.rgb = linear_to_srgb(diffuse.rgb); - - vec3 col; - float bloom = 0.0; - { - vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy); - - vec2 scol_ambocc = texture2DRect(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)); - 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 - // - - float sa = dot(refnormpersp, sun_dir.xyz); - 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) / 6; - col += spec_contrib; - } - - - col = mix(col, diffuse.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); - - } - - if (norm.w < 0.5) - { - col = mix(atmosLighting(col), fullbrightAtmosTransport(col), diffuse.a); - col = mix(scaleSoftClip(col), fullbrightScaleSoftClip(col), diffuse.a); - } - - #ifdef WATER_FOG - vec4 fogged = applyWaterFogDeferred(pos,vec4(col, bloom)); - col = fogged.rgb; - bloom = fogged.a; - #endif - - col = srgb_to_linear(col); - - //col = vec3(1,0,1); - //col.g = envIntensity; - } - - frag_color.rgb = col; - frag_color.a = bloom; + // convert to linear as fullscreen lights need to sum in linear colorspace + // and will be gamma (re)corrected downstream... + frag_color.rgb = srgb_to_linear(color.rgb); + 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 index c840d72784..bd11aa3f05 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl @@ -31,12 +31,19 @@ uniform vec2 screen_res; VARYING vec2 vary_fragcoord; +// forwards +void setAtmosAttenuation(vec3 c); +void setAdditiveColor(vec3 c); + void main() { //transform vertex vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); gl_Position = pos; - - + + // appease OSX GLSL compiler/linker by touching all the varyings we said we would + setAtmosAttenuation(vec3(1)); + setAdditiveColor(vec3(0)); + 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 81af1fdc8a..774f537821 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl @@ -71,70 +71,14 @@ uniform vec2 screen_res; uniform mat4 inv_proj; -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; -} - -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)); - -#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 - -} - -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 correctWithGamma(vec4 col) -{ - return vec4(srgb_to_linear(col.rgb), col.a); -} +vec3 getNorm(vec2 pos_screen); +vec3 srgb_to_linear(vec3 c); vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); ret.rgb = srgb_to_linear(ret.rgb); - + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); float det = min(lod/(proj_lod*0.5), 1.0); @@ -153,7 +97,7 @@ vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); - ret = correctWithGamma(ret); + ret.rgb = srgb_to_linear(ret.rgb); vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); @@ -171,7 +115,7 @@ vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); - ret = correctWithGamma(ret); + ret.rgb = srgb_to_linear(ret.rgb); vec2 dist = tc-vec2(0.5); @@ -182,22 +126,15 @@ 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; -} +vec4 getPosition(vec2 pos_screen); void main() { + vec3 col = vec3(0,0,0); + +#if defined(LOCAL_LIGHT_KILL) + discard; +#else vec4 frag = vary_fragcoord; frag.xyz /= frag.w; frag.xyz = frag.xyz*0.5+0.5; @@ -206,26 +143,26 @@ void main() vec3 pos = getPosition(frag.xy).xyz; vec3 lv = trans_center.xyz-pos.xyz; float dist = length(lv); + + if (dist >= size) + { + discard; + } dist /= size; - if (dist > 1.0) - { - discard; - } - + float shadow = 1.0; if (proj_shadow_idx >= 0) { vec4 shd = texture2DRect(lightMap, frag.xy); - float sh[2]; - sh[0] = shd.b; - sh[1] = shd.a; - shadow = min(sh[proj_shadow_idx]+shadow_fade, 1.0); + shadow = (proj_shadow_idx == 0) ? shd.b : shd.a; + shadow += shadow_fade; + shadow = clamp(shadow, 0.0, 1.0); } vec3 norm = texture2DRect(normalMap, frag.xy).xyz; float envIntensity = norm.z; - norm = decode_normal(norm.xy); + norm = getNorm(frag.xy); norm = normalize(norm); float l_dist = -dot(lv, proj_n); @@ -252,12 +189,8 @@ void main() lv = normalize(lv); float da = dot(norm, lv); - vec3 col = vec3(0,0,0); - vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb; - vec4 spec = texture2DRect(specularRect, frag.xy); - vec3 dlit = vec3(0, 0, 0); float noise = texture2D(noiseMap, frag.xy/128.0).b; @@ -280,23 +213,21 @@ void main() vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod); dlit = color.rgb * plcol.rgb * plcol.a; - + col = dlit*lit*diff_tex*shadow; - amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance; + + amb_da += (da*0.5+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 += (da*da*0.5+0.5) /* * (1.0-shadow) */ * 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.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; + } if (spec.a > 0.0) { @@ -317,14 +248,11 @@ void main() 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; + vec3 speccol = dlit*scol*spec.rgb*shadow; + speccol = clamp(speccol, vec3(0), vec3(1)); + col += speccol; } } - - - - if (envIntensity > 0.0) { @@ -354,10 +282,12 @@ void main() } } } +#endif //not sure why, but this line prevents MATBUG-194 col = max(col, vec3(0.0)); + //output linear colors as gamma correction happens down stream 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 265da8df99..8abdeae5ae 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl @@ -35,228 +35,26 @@ out vec4 frag_color; //class 2, shadows, no SSAO -uniform sampler2DRect depthMap; -uniform sampler2DRect normalMap; -uniform sampler2DShadow shadowMap0; -uniform sampler2DShadow shadowMap1; -uniform sampler2DShadow shadowMap2; -uniform sampler2DShadow shadowMap3; -uniform sampler2DShadow shadowMap4; -uniform sampler2DShadow shadowMap5; - - // 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 mat4 inv_proj; -uniform vec2 screen_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; - -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 = 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; -} - -float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl, vec2 pos_screen) -{ - stc.xyz /= stc.w; - stc.z += shadow_bias; - - stc.x = floor(stc.x*shadow_res.x + fract(pos_screen.y*0.666666666))/shadow_res.x; // add some 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; +vec3 getNorm(vec2 pos_screen); +vec4 getPosition(vec2 pos_screen); - 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(-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; - - - return shadow*0.2; -} - -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; -} +float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); +float sampleSpotShadow(vec3 pos, vec3 norm, int index, vec2 pos_screen); void main() { - vec2 pos_screen = vary_fragcoord.xy; - - //try doing an unproject here - - vec4 pos = getPosition(pos_screen); - - vec3 norm = texture2DRect(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 - return; - }*/ - - float shadow = 0.0; - float dp_directional_light = max(0.0, dot(norm, sun_dir.xyz)); - - 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); - - if (spos.z > -shadow_clip.w) - { - if (dp_directional_light == 0.0) - { - // if we know this point is facing away from the sun then we know it's in shadow without having to do a squirrelly shadow-map lookup - shadow = 0.0; - } - else - { - 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, 0.25, pos_screen)*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, 0.5, pos_screen)*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, 0.75, pos_screen)*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, 1.0, pos_screen)*w; - weight += w; - } - - - shadow /= weight; - - // take the most-shadowed value out of these two: - // * the blurred sun shadow in the light (shadow) map - // * an unblurred dot product between the sun and this norm - // the goal is to err on the side of most-shadow to fill-in shadow holes and reduce artifacting - shadow = min(shadow, dp_directional_light); - - //lpos.xy /= lpos.w*32.0; - //if (fract(lpos.x) < 0.1 || fract(lpos.y) < 0.1) - //{ - // shadow = 0.0; - //} - - } - } - else - { - // more distant than the shadow map covers - shadow = 1.0; - } - - frag_color[0] = shadow; - frag_color[1] = 1.0; - - spos = vec4(shadow_pos+norm*spot_shadow_offset, 1.0); - - //spotlight shadow 1 - vec4 lpos = shadow_matrix[4]*spos; - frag_color[2] = pcfSpotShadow(shadowMap4, lpos, 0.8, pos_screen); - - //spotlight shadow 2 - lpos = shadow_matrix[5]*spos; - frag_color[3] = pcfSpotShadow(shadowMap5, lpos, 0.8, pos_screen); - - //frag_color.rgb = pos.xyz; - //frag_color.b = shadow; + vec2 pos_screen = vary_fragcoord.xy; + vec4 pos = getPosition(pos_screen); + vec3 norm = getNorm(pos_screen); + + frag_color.r = sampleDirectionalShadow(pos.xyz, norm, pos_screen); + frag_color.g = 1.0f; + frag_color.b = sampleSpotShadow(pos.xyz, norm, 0, pos_screen); + frag_color.a = sampleSpotShadow(pos.xyz, norm, 1, pos_screen); } diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl index 5c6fe30daa..64d99bae2c 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl @@ -1,5 +1,5 @@ /** - * @file sunLightSSAOF.glsl + * @file class2/deferred/sunLightSSAOF.glsl * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2007, Linden Research, Inc. @@ -34,290 +34,24 @@ out vec4 frag_color; //class 2 -- shadows and SSAO -uniform sampler2DRect depthMap; -uniform sampler2DRect normalMap; -uniform sampler2DShadow shadowMap0; -uniform sampler2DShadow shadowMap1; -uniform sampler2DShadow shadowMap2; -uniform sampler2DShadow shadowMap3; -uniform sampler2DShadow shadowMap4; -uniform sampler2DShadow shadowMap5; -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 mat4 inv_proj; -uniform vec2 screen_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; - -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 = 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; -} - -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 ret = 1.0; - - vec2 pos_screen = vary_fragcoord.xy; - vec3 pos_world = pos.xyz; - vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; - - float angle_hidden = 0.0; - float points = 0; - - float scale = min(ssao_radius / -pos_world.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; - - vec3 diff = pos_world - samppos_world; - float dist2 = dot(diff, diff); - - // assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area - // --> solid angle shrinking by the square of distance - //radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2 - //(k should vary inversely with # of samples, but this is taken care of later) - - float funky_val = (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) ? 1.0 : 0.0; - angle_hidden = angle_hidden + funky_val * min(1.0/dist2, ssao_factor_inv); - - // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" - float diffz_val = (diff.z > -1.0) ? 1.0 : 0.0; - points = points + diffz_val; - } - - angle_hidden = min(ssao_factor*angle_hidden/points, 1.0); - - float points_val = (points > 0.0) ? 1.0 : 0.0; - ret = (1.0 - (points_val * angle_hidden)); - - ret = max(ret, 0.0); - return min(ret, 1.0); -} - -float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl, vec2 pos_screen) -{ - stc.xyz /= stc.w; - stc.z += shadow_bias; - - stc.x = floor(stc.x*shadow_res.x + fract(pos_screen.y*0.666666666))/shadow_res.x; - 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; -} - -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; +vec4 getPosition(vec2 pos_screen); +vec3 getNorm(vec2 pos_screen); - 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; -} +float sampleDirectionalShadow(vec3 shadow_pos, vec3 norm, vec2 pos_screen); +float sampleSpotShadow(vec3 shadow_pos, vec3 norm, int index, vec2 pos_screen); +float calcAmbientOcclusion(vec4 pos, vec3 norm, vec2 pos_screen); void main() { - vec2 pos_screen = vary_fragcoord.xy; - - //try doing an unproject here - - vec4 pos = getPosition(pos_screen); - - vec3 norm = texture2DRect(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 - return; - }*/ - - float shadow = 0.0; - float dp_directional_light = max(0.0, dot(norm, sun_dir.xyz)); - - 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); - - if (spos.z > -shadow_clip.w) - { - if (dp_directional_light == 0.0) - { - // if we know this point is facing away from the sun then we know it's in shadow without having to do a squirrelly shadow-map lookup - shadow = 0.0; - } - else - { - 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, 0.25, pos_screen)*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, 0.5, pos_screen)*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, 0.75, pos_screen)*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, 1.0, pos_screen)*w; - weight += w; - } - - - shadow /= weight; - - // take the most-shadowed value out of these two: - // * the blurred sun shadow in the light (shadow) map - // * an unblurred dot product between the sun and this norm - // the goal is to err on the side of most-shadow to fill-in shadow holes and reduce artifacting - shadow = min(shadow, dp_directional_light); - - //lpos.xy /= lpos.w*32.0; - //if (fract(lpos.x) < 0.1 || fract(lpos.y) < 0.1) - //{ - // shadow = 0.0; - //} - - } - } - else - { - // more distant than the shadow map covers - shadow = 1.0; - } - - frag_color[0] = shadow; - frag_color[1] = calcAmbientOcclusion(pos, norm); - - spos = vec4(shadow_pos+norm*spot_shadow_offset, 1.0); - - //spotlight shadow 1 - vec4 lpos = shadow_matrix[4]*spos; - frag_color[2] = pcfSpotShadow(shadowMap4, lpos, 0.8, pos_screen); - - //spotlight shadow 2 - lpos = shadow_matrix[5]*spos; - frag_color[3] = pcfSpotShadow(shadowMap5, lpos, 0.8, pos_screen); + vec2 pos_screen = vary_fragcoord.xy; + vec4 pos = getPosition(pos_screen); + vec3 norm = getNorm(pos_screen); - //frag_color.rgb = pos.xyz; - //frag_color.b = shadow; + frag_color.r = sampleDirectionalShadow(pos.xyz, norm, pos_screen); + frag_color.g = calcAmbientOcclusion(pos, norm, pos_screen); + frag_color.b = sampleSpotShadow(pos.xyz, norm, 0, pos_screen); + frag_color.a = sampleSpotShadow(pos.xyz, norm, 1, pos_screen); } diff --git a/indra/newview/app_settings/shaders/class2/lighting/sumLightsSpecularV.glsl b/indra/newview/app_settings/shaders/class2/lighting/sumLightsSpecularV.glsl index 3acf9fe883..89d9d1bde3 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 class2\lighting\sumLightsSpecularV.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -28,16 +28,16 @@ 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 atmosAmbient(); vec3 atmosAffectDirectionalLight(float lightIntensity); vec3 atmosGetDiffuseSunlightColor(); vec3 scaleDownLight(vec3 light); uniform vec4 light_position[8]; -uniform vec3 light_attenuation[8]; +uniform vec4 light_attenuation[8]; uniform vec3 light_diffuse[8]; -vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol) +vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor) { vec4 col = vec4(0.0, 0.0, 0.0, color.a); @@ -53,8 +53,8 @@ vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor 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 += atmosAmbient(); + col.rgb += atmosAffectDirectionalLight(calcDirectionalLightSpecular(specularSum, view, norm, light_position[0].xyz, atmosGetDiffuseSunlightColor(), 1.0)); col.rgb = min(col.rgb*color.rgb, 1.0); specularColor.rgb = min(specularColor.rgb*specularSum.rgb, 1.0); diff --git a/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl index c9987ef3b9..30ca88afd2 100644 --- a/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl +++ b/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl @@ -1,5 +1,5 @@ /** - * @file sumLightsV.glsl + * @file class2\lighting\sumLightsV.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -24,9 +24,8 @@ */ float calcDirectionalLight(vec3 n, vec3 l); -float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight); +float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight); -vec3 atmosAmbient(vec3 light); vec3 atmosAffectDirectionalLight(float lightIntensity); vec3 scaleDownLight(vec3 light); @@ -35,24 +34,27 @@ 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 sumLights(vec3 pos, vec3 norm, vec4 color) { 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); - - 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[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 = scaleDownLight(col.rgb); +#if defined(LOCAL_LIGHT_KILL) + col.rgb = vec3(0); +i#endif + // Add windlight lights - col.rgb += atmosAmbient(baseLight.rgb); col.rgb += atmosAffectDirectionalLight(calcDirectionalLight(norm, light_position[0].xyz)); - + +#if !defined(SUNLIGHT_KILL) col.rgb = min(col.rgb*color.rgb, 1.0); - +#endif + return col; } diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsF.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsF.glsl index fea3cbf69b..ee9c990b12 100644 --- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsF.glsl +++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsF.glsl @@ -1,5 +1,5 @@ /** - * @file atmosphericsF.glsl + * @file class2\wl\atmosphericsF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -22,23 +22,25 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - - - -////////////////////////////////////////////////////////// -// The fragment shader for the terrain atmospherics -////////////////////////////////////////////////////////// vec3 getAdditiveColor(); vec3 getAtmosAttenuation(); +vec3 scaleSoftClipFrag(vec3 light); -uniform sampler2D cloudMap; -uniform vec4 cloud_pos_density1; +uniform int no_atmo; -vec3 atmosLighting(vec3 light) +vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten) { - light *= getAtmosAttenuation().r; - light += getAdditiveColor(); - return (2.0 * light); + if (no_atmo == 1) + { + return light; + } + light *= atten.r; + light += additive; + return light * 2.0; } +vec3 atmosLighting(vec3 light) +{ + return atmosFragLighting(light, getAdditiveColor(), getAtmosAttenuation()); +} diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersF.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersF.glsl new file mode 100644 index 0000000000..5788871744 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersF.glsl @@ -0,0 +1,46 @@ +/** + * @file class2\wl\atmosphericsHelpersV.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$ + */ + +// Output variables + +uniform float scene_light_strength; +uniform int no_atmo; + +vec3 atmosFragAmbient(vec3 light, vec3 amblit) +{ + if (no_atmo == 1) return light; + return amblit + light / 2.0; +} + +vec3 atmosFragAffectDirectionalLight(float lightIntensity, vec3 sunlit) +{ + return sunlit * lightIntensity; +} + +vec3 scaleDownLightFrag(vec3 light) +{ + return (light / scene_light_strength ); +} + diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersV.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersV.glsl index 62a034ce05..9c42b84eca 100644 --- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersV.glsl +++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersV.glsl @@ -1,5 +1,5 @@ /** - * @file atmosphericsHelpersV.glsl + * @file class2\wl\atmosphericsHelpersV.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -33,29 +33,31 @@ vec3 getAtmosAttenuation(); vec3 getPositionEye(); uniform float scene_light_strength; +uniform int no_atmo; -vec3 atmosAmbient(vec3 light) +vec3 atmosAmbient() { - return getAmblitColor() + light / 2.0; + if (no_atmo == 1) return vec3(0.16); + return getAmblitColor(); } vec3 atmosAffectDirectionalLight(float lightIntensity) { - return getSunlitColor() * lightIntensity; + return getSunlitColor() * lightIntensity; } vec3 atmosGetDiffuseSunlightColor() { - return getSunlitColor(); + return getSunlitColor(); } vec3 scaleDownLight(vec3 light) { - return (light / scene_light_strength ); + return (light / scene_light_strength ); } vec3 scaleUpLight(vec3 light) { - return (light * scene_light_strength); + return (light * scene_light_strength); } diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl index d174805cc0..4c418e414f 100644 --- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl +++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl @@ -1,5 +1,5 @@ /** - * @file atmosphericsV.glsl + * @file class2\wl\atmosphericsV.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -22,10 +22,14 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - - // VARYING param funcs + + +uniform vec3 sun_dir; +uniform vec3 moon_dir; +uniform int sun_up_factor; + void setSunlitColor(vec3 v); void setAmblitColor(vec3 v); void setAdditiveColor(vec3 v); @@ -34,124 +38,19 @@ void setPositionEye(vec3 v); vec3 getAdditiveColor(); -//VARYING vec4 vary_CloudUVs; -//VARYING float vary_CloudDensity; - -// Inputs -uniform vec4 morphFactor; -uniform vec3 camPosLocal; -//uniform vec4 camPosWorld; - -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; +void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten, bool use_ao); void calcAtmospherics(vec3 inPositionEye) { - - vec3 P = inPositionEye; - setPositionEye(P); - - //(TERRAIN) limit altitude - if (P.y > max_y) P *= (max_y / P.y); - if (P.y < -max_y) P *= (-max_y / P.y); - - 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); - //vary_AtmosAttenuation = distance_multiplier / 10000.; - //vary_AtmosAttenuation = density_multiplier * 100.; - //vary_AtmosAttenuation = vec4(Plen / 100000., 0., 0., 1.); - - //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)); - - // vary_SunlitColor = vec3(0); - // vary_AmblitColor = vec3(0); - // vary_AdditiveColor = vec4(Pn, 1.0); - - /* - const float cloudShadowScale = 100.; - // Get cloud uvs for shadowing - vec3 cloudPos = inPositionEye + camPosWorld - cloudShadowScale / 2.; - vary_CloudUVs.xy = cloudPos.xz / cloudShadowScale; - - // We can take uv1 and multiply it by (TerrainSpan / CloudSpan) -// cloudUVs *= (((worldMaxZ - worldMinZ) * 20) /40000.); - vary_CloudUVs *= (10000./40000.); - - // Offset by sun vector * (CloudAltitude / CloudSpan) - vary_CloudUVs.x += tmpLightnorm.x / tmpLightnorm.y * (3000./40000.); - vary_CloudUVs.y += tmpLightnorm.z / tmpLightnorm.y * (3000./40000.); - */ + vec3 P = inPositionEye; + setPositionEye(P); + vec3 tmpsunlit = vec3(1); + vec3 tmpamblit = vec3(1); + vec3 tmpaddlit = vec3(1); + vec3 tmpattenlit = vec3(1); + vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; + calcAtmosphericVars(inPositionEye, light_dir, 1, tmpsunlit, tmpamblit, tmpaddlit, tmpattenlit, false); + setSunlitColor(tmpsunlit); + setAmblitColor(tmpamblit); + setAdditiveColor(tmpaddlit); + setAtmosAttenuation(tmpattenlit); } - diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsF.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsF.glsl index 765b0927c3..07733bda18 100644 --- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsF.glsl +++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsF.glsl @@ -1,5 +1,5 @@ /** - * @file atmosphericVars.glsl + * @file class2\wl\atmosphericVarsF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -24,7 +24,6 @@ */ -VARYING vec3 vary_SunlitColor; VARYING vec3 vary_AdditiveColor; VARYING vec3 vary_AtmosAttenuation; @@ -32,14 +31,17 @@ vec3 getSunlitColor() { return vec3(0,0,0); } + vec3 getAmblitColor() { return vec3(0,0,0); } + vec3 getAdditiveColor() { return vary_AdditiveColor; } + vec3 getAtmosAttenuation() { return vec3(vary_AtmosAttenuation); diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsV.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsV.glsl index 99dbee15ee..31109aed31 100644 --- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsV.glsl +++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsV.glsl @@ -1,5 +1,5 @@ /** - * @file atmosphericVars.glsl + * @file class2\wl\atmosphericVars.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsWaterF.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsWaterF.glsl index 163ef26444..22e16b7e0f 100644 --- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsWaterF.glsl +++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsWaterF.glsl @@ -1,5 +1,5 @@ /** - * @file atmosphericVarsWaterF.glsl + * @file class2\wl\atmosphericVarsWaterF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsWaterV.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsWaterV.glsl index 553f6752e6..0f2a3ee527 100644 --- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsWaterV.glsl +++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsWaterV.glsl @@ -1,5 +1,5 @@ /** - * @file atmosphericVarsWaterV.glsl + * @file class2\wl\atmosphericVarsWaterV.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class2/windlight/cloudsF.glsl b/indra/newview/app_settings/shaders/class2/windlight/cloudsF.glsl index 96c70651b1..fa928d993e 100644 --- a/indra/newview/app_settings/shaders/class2/windlight/cloudsF.glsl +++ b/indra/newview/app_settings/shaders/class2/windlight/cloudsF.glsl @@ -1,5 +1,5 @@ /** - * @file WLCloudsF.glsl + * @file class2\wl\cloudsF.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -22,7 +22,9 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + +/*[EXTRA_CODE_HERE]*/ + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; #else @@ -36,69 +38,94 @@ out vec4 frag_color; VARYING vec4 vary_CloudColorSun; VARYING vec4 vary_CloudColorAmbient; VARYING float vary_CloudDensity; -VARYING vec2 vary_texcoord0; -VARYING vec2 vary_texcoord1; -VARYING vec2 vary_texcoord2; -VARYING vec2 vary_texcoord3; uniform sampler2D cloud_noise_texture; +uniform sampler2D cloud_noise_texture_next; +uniform float blend_factor; uniform vec4 cloud_pos_density1; uniform vec4 cloud_pos_density2; -uniform vec4 gamma; +uniform float cloud_scale; +uniform float cloud_variance; + +VARYING vec2 vary_texcoord0; +VARYING vec2 vary_texcoord1; +VARYING vec2 vary_texcoord2; +VARYING vec2 vary_texcoord3; +VARYING float altitude_blend_factor; /// Soft clips the light with a gamma correction -vec3 scaleSoftClip(vec3 light) { - //soft clip effect: - light = 1. - clamp(light, vec3(0.), vec3(1.)); - light = 1. - pow(light, gamma.xxx); +vec3 scaleSoftClip(vec3 light); - return light; +vec4 cloudNoise(vec2 uv) +{ + vec4 a = texture2D(cloud_noise_texture, uv); + vec4 b = texture2D(cloud_noise_texture_next, uv); + vec4 cloud_noise_sample = mix(a, b, blend_factor); + return cloud_noise_sample; } void main() { - // Set variables - vec2 uv1 = vary_texcoord0.xy; - vec2 uv2 = vary_texcoord1.xy; + // Set variables + vec2 uv1 = vary_texcoord0.xy; + vec2 uv2 = vary_texcoord1.xy; + + vec4 cloudColorSun = vary_CloudColorSun; + vec4 cloudColorAmbient = vary_CloudColorAmbient; + float cloudDensity = vary_CloudDensity; + vec2 uv3 = vary_texcoord2.xy; + vec2 uv4 = vary_texcoord3.xy; + + if (cloud_scale < 0.001) + { + discard; + } + + vec2 disturbance = vec2(cloudNoise(uv1 / 8.0f).x, cloudNoise((uv3 + uv1) / 16.0f).x) * cloud_variance * (1.0f - cloud_scale * 0.25f); + vec2 disturbance2 = vec2(cloudNoise((uv1 + uv3) / 4.0f).x, cloudNoise((uv4 + uv2) / 8.0f).x) * cloud_variance * (1.0f - cloud_scale * 0.25f); + + // Offset texture coords + uv1 += cloud_pos_density1.xy + (disturbance * 0.2); //large texture, visible density + uv2 += cloud_pos_density1.xy; //large texture, self shadow + uv3 += cloud_pos_density2.xy; //small texture, visible density + uv4 += cloud_pos_density2.xy; //small texture, self shadow + + float density_variance = min(1.0, (disturbance.x* 2.0 + disturbance.y* 2.0 + disturbance2.x + disturbance2.y) * 4.0); - vec4 cloudColorSun = vary_CloudColorSun; - vec4 cloudColorAmbient = vary_CloudColorAmbient; - float cloudDensity = vary_CloudDensity; - vec2 uv3 = vary_texcoord2.xy; - vec2 uv4 = vary_texcoord3.xy; + cloudDensity *= 1.0 - (density_variance * density_variance); - // Offset texture coords - uv1 += cloud_pos_density1.xy; //large texture, visible density - uv2 += cloud_pos_density1.xy; //large texture, self shadow - uv3 += cloud_pos_density2.xy; //small texture, visible density - uv4 += cloud_pos_density2.xy; //small texture, self shadow + // Compute alpha1, the main cloud opacity + float alpha1 = (cloudNoise(uv1).x - 0.5) + (cloudNoise(uv3).x - 0.5) * cloud_pos_density2.z; + alpha1 = min(max(alpha1 + cloudDensity, 0.) * 10 * cloud_pos_density1.z, 1.); - // Compute alpha1, the main cloud opacity - float alpha1 = (texture2D(cloud_noise_texture, uv1).x - 0.5) + (texture2D(cloud_noise_texture, uv3).x - 0.5) * cloud_pos_density2.z; - alpha1 = min(max(alpha1 + cloudDensity, 0.) * 10. * cloud_pos_density1.z, 1.); + // And smooth + alpha1 = 1. - alpha1 * alpha1; + alpha1 = 1. - alpha1 * alpha1; - // And smooth - alpha1 = 1. - alpha1 * alpha1; - alpha1 = 1. - alpha1 * alpha1; + alpha1 *= altitude_blend_factor; + //if (alpha1 < 0.001f) + //{ + // discard; + //} - // Compute alpha2, for self shadowing effect - // (1 - alpha2) will later be used as percentage of incoming sunlight - float alpha2 = (texture2D(cloud_noise_texture, uv2).x - 0.5); - alpha2 = min(max(alpha2 + cloudDensity, 0.) * 2.5 * cloud_pos_density1.z, 1.); + // Compute alpha2, for self shadowing effect + // (1 - alpha2) will later be used as percentage of incoming sunlight + float alpha2 = (cloudNoise(uv2).x - 0.5); + alpha2 = min(max(alpha2 + cloudDensity, 0.) * 2.5 * cloud_pos_density1.z, 1.); - // And smooth - alpha2 = 1. - alpha2; - alpha2 = 1. - alpha2 * alpha2; + // And smooth + alpha2 = 1. - alpha2; + alpha2 = 1. - alpha2 * alpha2; - // Combine - vec4 color; - color = (cloudColorSun*(1.-alpha2) + cloudColorAmbient); - color *= 2.; + // Combine + vec4 color; + color = (cloudColorSun*(1.-alpha2) + cloudColorAmbient); + color.rgb *= 2.; + color.rgb = scaleSoftClip(color.rgb); - /// Gamma correct for WL (soft clip effect). - frag_color.rgb = scaleSoftClip(color.rgb); - frag_color.a = alpha1; + /// Gamma correct for WL (soft clip effect). + frag_color = vec4(color.rgb, alpha1); } diff --git a/indra/newview/app_settings/shaders/class2/windlight/cloudsV.glsl b/indra/newview/app_settings/shaders/class2/windlight/cloudsV.glsl index c1dd45cd67..97ffa9feef 100644 --- a/indra/newview/app_settings/shaders/class2/windlight/cloudsV.glsl +++ b/indra/newview/app_settings/shaders/class2/windlight/cloudsV.glsl @@ -1,5 +1,5 @@ /** - * @file WLCloudsV.glsl + * @file class2\wl\cloudsV.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -36,17 +36,21 @@ ATTRIBUTE vec2 texcoord0; VARYING vec4 vary_CloudColorSun; VARYING vec4 vary_CloudColorAmbient; VARYING float vary_CloudDensity; + VARYING vec2 vary_texcoord0; VARYING vec2 vary_texcoord1; VARYING vec2 vary_texcoord2; VARYING vec2 vary_texcoord3; +VARYING float altitude_blend_factor; // Inputs uniform vec3 camPosLocal; uniform vec4 lightnorm; uniform vec4 sunlight_color; -uniform vec4 ambient; +uniform vec4 moonlight_color; +uniform int sun_up_factor; +uniform vec4 ambient_color; uniform vec4 blue_horizon; uniform vec4 blue_density; uniform float haze_horizon; @@ -57,128 +61,128 @@ uniform float density_multiplier; uniform float max_y; uniform vec4 glow; +uniform float sun_moon_glow_factor; uniform vec4 cloud_color; uniform float cloud_scale; +// NOTE: Keep these in sync! +// indra\newview\app_settings\shaders\class1\deferred\skyV.glsl +// indra\newview\app_settings\shaders\class1\deferred\cloudsV.glsl +// indra\newview\app-settings\shaders\class2\windlight\cloudsV.glsl +// indra\newview\lllegacyatmospherics.cpp +// indra\newview\llsettingsvo.cpp void main() { - // World / view / projection gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); - vary_texcoord0 = texcoord0; + // Texture coords + // SL-13084 EEP added support for custom cloud textures -- flip them horizontally to match the preview of Clouds > Cloud Scroll + vary_texcoord0 = vec2(-texcoord0.x, texcoord0.y); // See: LLSettingsVOSky::applySpecial + + vary_texcoord0.xy -= 0.5; + vary_texcoord0.xy /= cloud_scale; + vary_texcoord0.xy += 0.5; + + vary_texcoord1 = vary_texcoord0; + vary_texcoord1.x += lightnorm.x * 0.0125; + vary_texcoord1.y += lightnorm.z * 0.0125; + + vary_texcoord2 = vary_texcoord0 * 16.; + vary_texcoord3 = vary_texcoord1 * 16.; // Get relative position - vec3 P = position.xyz - camPosLocal.xyz + vec3(0,50,0); + vec3 rel_pos = position.xyz - camPosLocal.xyz + vec3(0, 50, 0); + + // fade clouds beyond a certain point so the bottom of the sky dome doesn't look silly at high altitude + altitude_blend_factor = clamp((rel_pos.y + 512.0) / max_y, 0.0, 1.0); - // Set altitude - if (P.y > 0.) + // Adj position vector to clamp altitude + if (rel_pos.y > 0.) { - P *= (max_y / P.y); + rel_pos *= (max_y / rel_pos.y); } - else + if (rel_pos.y < 0.) { - P *= (-32000. / P.y); + rel_pos *= (-32000. / rel_pos.y); } // Can normalize then - vec3 Pn = normalize(P); - float Plen = length(P); + vec3 rel_pos_norm = normalize(rel_pos); + float rel_pos_len = length(rel_pos); // Initialize temp variables - vec4 temp1 = vec4(0.); - vec4 temp2 = vec4(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); + light_atten = (blue_density + vec4(haze_density * 0.25)) * (density_multiplier * max_y); // Calculate relative weights - temp1 = blue_density + haze_density; - blue_weight = blue_density / temp1; - haze_weight = haze_density / temp1; + vec4 combined_haze = abs(blue_density) + vec4(abs(haze_density)); + vec4 blue_weight = blue_density / combined_haze; + vec4 haze_weight = haze_density / combined_haze; - // Compute sunlight from P & lightnorm (for long rays like sky) - temp2.y = max(0., max(0., Pn.y) * 1.0 + lightnorm.y ); - temp2.y = 1. / temp2.y; - sunlight *= exp( - light_atten * temp2.y); + // Compute sunlight from rel_pos & lightnorm (for long rays like sky) + float off_axis = 1.0 / max(1e-6, max(0., rel_pos_norm.y) + lightnorm.y); + sunlight *= exp(-light_atten * off_axis); // Distance - temp2.z = Plen * density_multiplier; + float density_dist = rel_pos_len * density_multiplier; - // Transparency (-> temp1) - // ATI Bugfix -- can't store temp1*temp2.z in a variable because the ati + // Transparency (-> combined_haze) + // ATI Bugfix -- can't store combined_haze*density_dist in a variable because the ati // compiler gets confused. - temp1 = exp(-temp1 * temp2.z); - + combined_haze = exp(-combined_haze * density_dist); // Compute haze glow - temp2.x = dot(Pn, lightnorm.xyz); - temp2.x = 1. - temp2.x; - // temp2.x is 0 at the sun and increases away from sun - temp2.x = max(temp2.x, .001); + float haze_glow = 1.0 - dot(rel_pos_norm, lightnorm.xyz); + // haze_glow is 0 at the sun and increases away from sun + haze_glow = max(haze_glow, .001); // Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) - temp2.x *= glow.x; + haze_glow *= glow.x; // Higher glow.x gives dimmer glow (because next step is 1 / "angle") - temp2.x = pow(temp2.x, glow.z); + haze_glow = pow(haze_glow, glow.z); // glow.z should be negative, so we're doing a sort of (1 / "angle") function + haze_glow *= sun_moon_glow_factor; + // Add "minimum anti-solar illumination" - temp2.x += .25; + // For sun, add to glow. For moon, remove glow entirely. SL-13768 + haze_glow = (sun_moon_glow_factor < 1.0) ? 0.0 : (haze_glow + 0.25); // Increase ambient when there are more clouds - vec4 tmpAmbient = ambient; + vec4 tmpAmbient = ambient_color; tmpAmbient += (1. - tmpAmbient) * cloud_shadow * 0.5; // Dim sunlight by cloud shadow percentage sunlight *= (1. - cloud_shadow); // Haze color below cloud - vec4 additiveColorBelowCloud = ( blue_horizon * blue_weight * (sunlight + tmpAmbient) - + (haze_horizon * haze_weight) * (sunlight * temp2.x + tmpAmbient) - ); + vec4 additiveColorBelowCloud = + (blue_horizon * blue_weight * (sunlight + tmpAmbient) + (haze_horizon * haze_weight) * (sunlight * haze_glow + tmpAmbient)); // CLOUDS - - sunlight = sunlight_color; - temp2.y = max(0., lightnorm.y * 2.); - temp2.y = 1. / temp2.y; - sunlight *= exp( - light_atten * temp2.y); + sunlight = sunlight_color; // SL-14707 reset color -- Clouds are unusually dim in EEP + off_axis = 1.0 / max(1e-6, lightnorm.y * 2.); + sunlight *= exp(-light_atten * off_axis); // Cloud color out - vary_CloudColorSun = (sunlight * temp2.x) * cloud_color; + vary_CloudColorSun = (sunlight * haze_glow) * cloud_color; vary_CloudColorAmbient = tmpAmbient * cloud_color; // Attenuate cloud color by atmosphere - temp1 = sqrt(temp1); //less atmos opacity (more transparency) below clouds - vary_CloudColorSun *= temp1; - vary_CloudColorAmbient *= temp1; - vec4 oHazeColorBelowCloud = additiveColorBelowCloud * (1. - temp1); + combined_haze = sqrt(combined_haze); // less atmos opacity (more transparency) below clouds + vary_CloudColorSun *= combined_haze; + vary_CloudColorAmbient *= combined_haze; + vec4 oHazeColorBelowCloud = additiveColorBelowCloud * (1. - combined_haze); // Make a nice cloud density based on the cloud_shadow value that was passed in. vary_CloudDensity = 2. * (cloud_shadow - 0.25); - - // Texture coords - vary_texcoord0 = texcoord0; - vary_texcoord0.xy -= 0.5; - vary_texcoord0.xy /= cloud_scale; - vary_texcoord0.xy += 0.5; - - vary_texcoord1 = vary_texcoord0; - vary_texcoord1.x += lightnorm.x * 0.0125; - vary_texcoord1.y += lightnorm.z * 0.0125; - - vary_texcoord2 = vary_texcoord0 * 16.; - vary_texcoord3 = vary_texcoord1 * 16.; - // Combine these to minimize register use vary_CloudColorAmbient += oHazeColorBelowCloud; @@ -187,4 +191,3 @@ void main() // END CLOUDS } - diff --git a/indra/newview/app_settings/shaders/class2/windlight/gammaF.glsl b/indra/newview/app_settings/shaders/class2/windlight/gammaF.glsl index 478373d729..68db7fcbb1 100644 --- a/indra/newview/app_settings/shaders/class2/windlight/gammaF.glsl +++ b/indra/newview/app_settings/shaders/class2/windlight/gammaF.glsl @@ -1,5 +1,5 @@ /** - * @file gammaF.glsl + * @file class2\wl\gammaF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -22,23 +22,37 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - - - -uniform vec4 gamma; +uniform float gamma; +uniform int no_atmo; vec3 getAtmosAttenuation(); +vec3 getAdditiveColor(); -/// Soft clips the light with a gamma correction -vec3 scaleSoftClip(vec3 light) { - //soft clip effect: - light = 1. - clamp(light, vec3(0.), vec3(1.)); - light = 1. - pow(light, gamma.xxx); +vec3 scaleSoftClipFrag(vec3 light) +{ + if (no_atmo == 1) + { + return light; + } + //soft clip effect: + light = 1. - clamp(light, vec3(0.), vec3(1.)); + light = 1. - pow(light, vec3(gamma)); // s/b inverted already CPU-side + return light; +} + +vec3 scaleSoftClip(vec3 light) +{ + return scaleSoftClipFrag(light); +} - return light; +vec3 fullbrightScaleSoftClipFrag(vec3 light, vec3 add, vec3 atten) +{ + //return mix(scaleSoftClipFrag(light.rgb), add, atten); + return scaleSoftClipFrag(light.rgb); } -vec3 fullbrightScaleSoftClip(vec3 light) { - return mix(scaleSoftClip(light.rgb), light.rgb, getAtmosAttenuation()); +vec3 fullbrightScaleSoftClip(vec3 light) +{ + return fullbrightScaleSoftClipFrag(light, getAdditiveColor(), getAtmosAttenuation()); } diff --git a/indra/newview/app_settings/shaders/class2/windlight/skyF.glsl b/indra/newview/app_settings/shaders/class2/windlight/skyF.glsl index e2a2367626..7146349453 100644 --- a/indra/newview/app_settings/shaders/class2/windlight/skyF.glsl +++ b/indra/newview/app_settings/shaders/class2/windlight/skyF.glsl @@ -1,5 +1,5 @@ /** - * @file WLSkyF.glsl + * @file class2/windlight/skyF.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -35,17 +35,8 @@ out vec4 frag_color; VARYING vec4 vary_HazeColor; -uniform sampler2D cloud_noise_texture; -uniform vec4 gamma; - /// Soft clips the light with a gamma correction -vec3 scaleSoftClip(vec3 light) { - //soft clip effect: - light = 1. - clamp(light, vec3(0.), vec3(1.)); - light = 1. - pow(light, gamma.xxx); - - return light; -} +vec3 scaleSoftClip(vec3 light); void main() { @@ -56,8 +47,7 @@ void main() vec4 color; color = vary_HazeColor; - color *= 2.; - + color.rgb *= 2.; /// Gamma correct for WL (soft clip effect). frag_color.rgb = scaleSoftClip(color.rgb); frag_color.a = 1.0; diff --git a/indra/newview/app_settings/shaders/class2/windlight/skyV.glsl b/indra/newview/app_settings/shaders/class2/windlight/skyV.glsl index 3788ddaf2d..a0a33b8642 100644 --- a/indra/newview/app_settings/shaders/class2/windlight/skyV.glsl +++ b/indra/newview/app_settings/shaders/class2/windlight/skyV.glsl @@ -1,28 +1,28 @@ -/** - * @file WLSkyV.glsl +/** + * @file class2\wl\skyV.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$ */ - + uniform mat4 modelview_projection_matrix; ATTRIBUTE vec3 position; @@ -37,120 +37,113 @@ VARYING vec4 vary_HazeColor; // Inputs uniform vec3 camPosLocal; -uniform vec4 lightnorm; -uniform vec4 sunlight_color; -uniform vec4 ambient; -uniform vec4 blue_horizon; -uniform vec4 blue_density; +uniform vec4 lightnorm; +uniform vec4 sunlight_color; +uniform vec4 moonlight_color; +uniform int sun_up_factor; +uniform vec4 ambient_color; +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 vec4 glow; +uniform float sun_moon_glow_factor; uniform vec4 cloud_color; void main() { + // World / view / projection + vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); - // World / view / projection - gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); - - // Get relative position - vec3 P = position.xyz - camPosLocal.xyz + vec3(0,50,0); - //vec3 P = position.xyz + vec3(0,50,0); - - // Set altitude - if (P.y > 0.) - { - P *= (max_y / P.y); - } - else - { - P *= (-32000. / P.y); - } - - // Can normalize then - vec3 Pn = normalize(P); - float Plen = length(P); - - // Initialize temp variables - vec4 temp1 = vec4(0.); - vec4 temp2 = vec4(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); - - // Calculate relative weights - temp1 = blue_density + haze_density; - blue_weight = blue_density / temp1; - haze_weight = haze_density / temp1; - - // Compute sunlight from P & lightnorm (for long rays like sky) - temp2.y = max(0., max(0., Pn.y) * 1.0 + lightnorm.y ); - temp2.y = 1. / temp2.y; - sunlight *= exp( - light_atten * temp2.y); - - // Distance - temp2.z = Plen * density_multiplier; - - // Transparency (-> temp1) - // ATI Bugfix -- can't store temp1*temp2.z in a variable because the ati - // compiler gets confused. - temp1 = exp(-temp1 * temp2.z); - - - // Compute haze glow - temp2.x = dot(Pn, lightnorm.xyz); - temp2.x = 1. - temp2.x; - // temp2.x is 0 at the sun and increases away from sun - temp2.x = max(temp2.x, .001); - // 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; - - - // Haze color above cloud - vary_HazeColor = ( blue_horizon * blue_weight * (sunlight + ambient) - + (haze_horizon * haze_weight) * (sunlight * temp2.x + ambient) - ); - - - // Increase ambient when there are more clouds - vec4 tmpAmbient = ambient; - tmpAmbient += (1. - tmpAmbient) * cloud_shadow * 0.5; - - // Dim sunlight by cloud shadow percentage - sunlight *= (1. - cloud_shadow); - - // Haze color below cloud - vec4 additiveColorBelowCloud = ( blue_horizon * blue_weight * (sunlight + tmpAmbient) - + (haze_horizon * haze_weight) * (sunlight * temp2.x + tmpAmbient) - ); - - // Final atmosphere additive - vary_HazeColor *= (1. - temp1); - - // Attenuate cloud color by atmosphere - temp1 = sqrt(temp1); //less atmos opacity (more transparency) below clouds - - // At horizon, blend high altitude sky color towards the darker color below the clouds - vary_HazeColor += (additiveColorBelowCloud - vary_HazeColor) * (1. - sqrt(temp1)); - - // won't compile on mac without this being set - //vary_AtmosAttenuation = vec3(0.0,0.0,0.0); -} + gl_Position = pos; + + // Get relative position + vec3 rel_pos = position.xyz - camPosLocal.xyz + vec3(0, 50, 0); + + // Adj position vector to clamp altitude + if (rel_pos.y > 0.) + { + rel_pos *= (max_y / rel_pos.y); + } + if (rel_pos.y < 0.) + { + rel_pos *= (-32000. / rel_pos.y); + } + + // Can normalize then + vec3 rel_pos_norm = normalize(rel_pos); + + float rel_pos_len = length(rel_pos); + + // Initialize temp variables + vec4 sunlight = (sun_up_factor == 1) ? sunlight_color : moonlight_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); + + // Calculate relative weights + vec4 combined_haze = abs(blue_density) + vec4(abs(haze_density)); + vec4 blue_weight = blue_density / combined_haze; + vec4 haze_weight = haze_density / combined_haze; + // Compute sunlight from rel_pos & lightnorm (for long rays like sky) + float off_axis = 1.0 / max(1e-6, max(0., rel_pos_norm.y) + lightnorm.y); + sunlight *= exp(-light_atten * off_axis); + + // Distance + float density_dist = rel_pos_len * density_multiplier; + + // Transparency (-> combined_haze) + // ATI Bugfix -- can't store combined_haze*density_dist in a variable because the ati + // compiler gets confused. + combined_haze = exp(-combined_haze * density_dist); + + // Compute haze glow + float haze_glow = 1.0 - dot(rel_pos_norm, lightnorm.xyz); + // haze_glow is 0 at the sun and increases away from sun + haze_glow = max(haze_glow, .001); + // Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) + haze_glow *= glow.x; + // Higher glow.x gives dimmer glow (because next step is 1 / "angle") + haze_glow = pow(haze_glow, glow.z); + // glow.z should be negative, so we're doing a sort of (1 / "angle") function + + // Add "minimum anti-solar illumination" + // For sun, add to glow. For moon, remove glow entirely. SL-13768 + haze_glow = (sun_moon_glow_factor < 1.0) ? 0.0 : (haze_glow + 0.25); + + vec4 color = + (blue_horizon * blue_weight * (sunlight + ambient_color) + (haze_horizon * haze_weight) * (sunlight * haze_glow + ambient_color)); + + // Final atmosphere additive + color *= (1. - combined_haze); + + // Increase ambient when there are more clouds + vec4 tmpAmbient = ambient_color; + tmpAmbient += max(vec4(0), (1. - ambient_color)) * cloud_shadow * 0.5; + + // Dim sunlight by cloud shadow percentage + sunlight *= max(0.0, (1. - cloud_shadow)); + + // Haze color below cloud + vec4 additiveColorBelowCloud = + (blue_horizon * blue_weight * (sunlight + tmpAmbient) + (haze_horizon * haze_weight) * (sunlight * haze_glow + tmpAmbient)); + + // Attenuate cloud color by atmosphere + combined_haze = sqrt(combined_haze); // less atmos opacity (more transparency) below clouds + + // At horizon, blend high altitude sky color towards the darker color below the clouds + color += (additiveColorBelowCloud - color) * (1. - sqrt(combined_haze)); + + // Haze color above cloud + vary_HazeColor = color; +} diff --git a/indra/newview/app_settings/shaders/class2/windlight/transportF.glsl b/indra/newview/app_settings/shaders/class2/windlight/transportF.glsl index 8a8e4cb0f6..b53a2e237f 100644 --- a/indra/newview/app_settings/shaders/class2/windlight/transportF.glsl +++ b/indra/newview/app_settings/shaders/class2/windlight/transportF.glsl @@ -1,5 +1,5 @@ /** - * @file transportF.glsl + * @file class2\wl\transportF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -30,24 +30,33 @@ vec3 getAdditiveColor(); vec3 getAtmosAttenuation(); -uniform sampler2D cloudMap; -uniform vec4 cloud_pos_density1; +uniform int no_atmo; -vec3 atmosTransport(vec3 light) { - light *= getAtmosAttenuation().r; - light += getAdditiveColor() * 2.0; +vec3 atmosTransportFrag(vec3 light, vec3 additive, vec3 atten) +{ + light *= atten.r; + light += additive * 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 atmosTransport(vec3 light) +{ + return atmosTransportFrag(light, getAdditiveColor(), getAtmosAttenuation()); } -vec3 fullbrightShinyAtmosTransport(vec3 light) { - float brightness = dot(light.rgb, vec3(0.33333)); +vec3 fullbrightAtmosTransportFrag(vec3 light, vec3 additive, vec3 atten) +{ + float brightness = dot(light.rgb * 0.5, vec3(0.3333)) + 0.1; + return mix(atmosTransportFrag(light.rgb, additive, atten), light.rgb + additive, brightness * brightness); +} - return mix(atmosTransport(light.rgb), (light.rgb + getAdditiveColor().rgb) * (2.0 - brightness), brightness * brightness); +vec3 fullbrightAtmosTransport(vec3 light) +{ + return fullbrightAtmosTransportFrag(light, getAdditiveColor(), getAtmosAttenuation()); } +vec3 fullbrightShinyAtmosTransport(vec3 light) +{ + float brightness = dot(light.rgb, vec3(0.33333)); + return mix(atmosTransport(light.rgb), (light.rgb + getAdditiveColor().rgb) * (2.0 - brightness), brightness * brightness); +} diff --git a/indra/newview/app_settings/shaders/class3/avatar/avatarV.glsl b/indra/newview/app_settings/shaders/class3/avatar/avatarV.glsl index 721054b5ad..df9704ec25 100644 --- a/indra/newview/app_settings/shaders/class3/avatar/avatarV.glsl +++ b/indra/newview/app_settings/shaders/class3/avatar/avatarV.glsl @@ -33,7 +33,7 @@ ATTRIBUTE vec4 clothing; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); +vec4 calcLighting(vec3 pos, vec3 norm, vec4 color); mat4 getSkinnedTransform(); void calcAtmospherics(vec3 inPositionEye); @@ -127,7 +127,7 @@ void main() calcAtmospherics(pos.xyz); - vec4 col = calcLighting(pos.xyz, norm, color, vec4(0.0)); + vec4 col = calcLighting(pos.xyz, norm, color); vertex_color = col; gl_Position = projection_matrix * pos; diff --git a/indra/newview/app_settings/shaders/class3/deferred/attachmentShadowF.glsl b/indra/newview/app_settings/shaders/class3/deferred/attachmentShadowF.glsl new file mode 100644 index 0000000000..d973326f93 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/attachmentShadowF.glsl @@ -0,0 +1,44 @@ +/** + * @file avatarShadowF.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$ + */ + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2D diffuseMap; + +VARYING vec4 pos; +VARYING vec2 vary_texcoord0; + +vec4 computeMoments(float depth, float a); + +void main() +{ + frag_color = computeMoments(length(pos), 1.0); +} + diff --git a/indra/newview/app_settings/shaders/class3/deferred/attachmentShadowV.glsl b/indra/newview/app_settings/shaders/class3/deferred/attachmentShadowV.glsl new file mode 100644 index 0000000000..1a655e6467 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/attachmentShadowV.glsl @@ -0,0 +1,49 @@ +/** + * @file attachmentShadowV.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; +uniform mat4 texture_matrix0; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec2 texcoord0; + +mat4 getObjectSkinnedTransform(); + +VARYING vec4 pos; + +void main() +{ + //transform vertex + mat4 mat = getObjectSkinnedTransform(); + + mat = modelview_matrix * mat; + pos = (mat*vec4(position.xyz, 1.0)); + pos = projection_matrix * vec4(pos.xyz, 1.0); + +#if !defined(DEPTH_CLAMP) + pos.z = max(pos.z, -pos.w+0.01); +#endif + gl_Position = pos; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/srgb.glsl b/indra/newview/app_settings/shaders/class3/deferred/avatarShadowF.glsl index 587f3d5a94..48eefc7a73 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/srgb.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/avatarShadowF.glsl @@ -1,5 +1,5 @@ /** - * @file srgb.glsl + * @file avatarShadowF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -23,24 +23,30 @@ * $/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)); +/*[EXTRA_CODE_HERE]*/ - bvec3 lte = lessThanEqual(cs,vec3(0.04045)); - return mix(high_range, low_range, lte); +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif -} +uniform sampler2D diffuseMap; -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; +#if !defined(DEPTH_CLAMP) +VARYING vec4 post_pos; +#endif - bvec3 lt = lessThan(cl,vec3(0.0031308)); - return mix(high_range, low_range, lt); +VARYING vec4 pos; + +vec4 computeMoments(float depth, float a); + +void main() +{ + frag_color = computeMoments(length(pos), 1.0); +#if !defined(DEPTH_CLAMP) + gl_FragDepth = max(post_pos.z/post_pos.w*0.5+0.5, 0.0); +#endif } diff --git a/indra/newview/app_settings/shaders/class3/deferred/avatarShadowV.glsl b/indra/newview/app_settings/shaders/class3/deferred/avatarShadowV.glsl new file mode 100644 index 0000000000..164b355f20 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/avatarShadowV.glsl @@ -0,0 +1,68 @@ +/** + * @file avatarShadowV.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; + +mat4 getSkinnedTransform(); + +ATTRIBUTE vec3 position; +ATTRIBUTE vec3 normal; +ATTRIBUTE vec2 texcoord0; + +#if !defined(DEPTH_CLAMP) +VARYING vec4 post_pos; +#endif + +VARYING vec4 pos; + +void main() +{ + vec3 norm; + + vec4 pos_in = vec4(position.xyz, 1.0); + mat4 trans = getSkinnedTransform(); + + 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); + + pos = projection_matrix * pos; + +#if !defined(DEPTH_CLAMP) + post_pos = pos; + gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); +#else + gl_Position = pos; +#endif + +} + + diff --git a/indra/newview/app_settings/shaders/class3/deferred/cloudShadowF.glsl b/indra/newview/app_settings/shaders/class3/deferred/cloudShadowF.glsl new file mode 100644 index 0000000000..32210f60dc --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/cloudShadowF.glsl @@ -0,0 +1,119 @@ +/** + * @file class3/deferred/cloudsF.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$ + */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2D diffuseMap; + +VARYING vec4 pos; +VARYING float target_pos_x; +VARYING float vary_CloudDensity; +VARYING vec2 vary_texcoord0; +VARYING vec2 vary_texcoord1; +VARYING vec2 vary_texcoord2; +VARYING vec2 vary_texcoord3; + +uniform sampler2D cloud_noise_texture; +uniform sampler2D cloud_noise_texture_next; +uniform float blend_factor; +uniform vec4 cloud_pos_density1; +uniform vec4 cloud_pos_density2; +uniform vec4 cloud_color; +uniform float cloud_shadow; +uniform float cloud_scale; +uniform float cloud_variance; +uniform vec3 camPosLocal; +uniform vec3 sun_dir; +uniform float sun_size; +uniform float far_z; + +vec4 cloudNoise(vec2 uv) +{ + vec4 a = texture2D(cloud_noise_texture, uv); + vec4 b = texture2D(cloud_noise_texture_next, uv); + vec4 cloud_noise_sample = mix(a, b, blend_factor); + return normalize(cloud_noise_sample); +} + +vec4 computeMoments(float depth, float alpha); + +void main() +{ + if (cloud_scale >= 0.001) + { + // Set variables + vec2 uv1 = vary_texcoord0.xy; + vec2 uv2 = vary_texcoord1.xy; + vec2 uv3 = vary_texcoord2.xy; + float cloudDensity = 2.0 * (cloud_shadow - 0.25); + + vec2 uv4 = vary_texcoord3.xy; + + vec2 disturbance = vec2(cloudNoise(uv1 / 8.0f).x, cloudNoise((uv3 + uv1) / 16.0f).x) * cloud_variance * (1.0f - cloud_scale * 0.25f); + vec2 disturbance2 = vec2(cloudNoise((uv1 + uv3) / 4.0f).x, cloudNoise((uv4 + uv2) / 8.0f).x) * cloud_variance * (1.0f - cloud_scale * 0.25f); + + // Offset texture coords + uv1 += cloud_pos_density1.xy + (disturbance * 0.2); //large texture, visible density + uv2 += cloud_pos_density1.xy; //large texture, self shadow + uv3 += cloud_pos_density2.xy; //small texture, visible density + uv4 += cloud_pos_density2.xy; //small texture, self shadow + + float density_variance = min(1.0, (disturbance.x* 2.0 + disturbance.y* 2.0 + disturbance2.x + disturbance2.y) * 4.0); + + cloudDensity *= 1.0 - (density_variance * density_variance); + + // Compute alpha1, the main cloud opacity + float alpha1 = (cloudNoise(uv1).x - 0.5) + (cloudNoise(uv3).x - 0.5) * cloud_pos_density2.z; + alpha1 = min(max(alpha1 + cloudDensity, 0.) * 10 * cloud_pos_density1.z, 1.); + + // And smooth + alpha1 = 1. - alpha1 * alpha1; + alpha1 = 1. - alpha1 * alpha1; + + if (alpha1 < 0.001f) + { + discard; + } + + // Compute alpha2, for self shadowing effect + // (1 - alpha2) will later be used as percentage of incoming sunlight + float alpha2 = (cloudNoise(uv2).x - 0.5); + alpha2 = min(max(alpha2 + cloudDensity, 0.) * 2.5 * cloud_pos_density1.z, 1.); + + // And smooth + alpha2 = 1. - alpha2; + alpha2 = 1. - alpha2 * alpha2; + + frag_color = computeMoments(length(pos), alpha1); + } + else + { + frag_color = vec4(0); + } +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/cloudShadowV.glsl b/indra/newview/app_settings/shaders/class3/deferred/cloudShadowV.glsl new file mode 100644 index 0000000000..effb070f93 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/cloudShadowV.glsl @@ -0,0 +1,63 @@ +/** + * @file cloudShadowV.glsl + * + * $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$ + */ + +uniform mat4 texture_matrix0; +uniform mat4 modelview_projection_matrix; +uniform float shadow_target_width; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec4 diffuse_color; +ATTRIBUTE vec2 texcoord0; + +#if !defined(DEPTH_CLAMP) +VARYING float pos_zd2; +#endif + +VARYING vec4 pos; +VARYING float target_pos_x; +VARYING vec2 vary_texcoord0; +VARYING vec4 vertex_color; + +void passTextureIndex(); + +void main() +{ + //transform vertex + vec4 pre_pos = vec4(position.xyz, 1.0); + pos = modelview_projection_matrix * pre_pos; + target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x; + +#if !defined(DEPTH_CLAMP) + pos_zd2 = pos.z * 0.5; + gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); +#else + gl_Position = pos; +#endif + + passTextureIndex(); + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; + vertex_color = diffuse_color; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/cloudsF.glsl b/indra/newview/app_settings/shaders/class3/deferred/cloudsF.glsl new file mode 100644 index 0000000000..e40d7e7c75 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/cloudsF.glsl @@ -0,0 +1,166 @@ +/** + * @file class3/deferred/cloudsF.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$ + */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_data[3]; +#else +#define frag_data gl_FragData +#endif + +///////////////////////////////////////////////////////////////////////// +// The fragment shader for the sky +///////////////////////////////////////////////////////////////////////// + +VARYING vec4 vary_CloudColorSun; +VARYING vec4 vary_CloudColorAmbient; +VARYING float vary_CloudDensity; +VARYING vec2 vary_texcoord0; +VARYING vec2 vary_texcoord1; +VARYING vec2 vary_texcoord2; +VARYING vec2 vary_texcoord3; +VARYING vec3 vary_pos; + +uniform sampler2D cloud_noise_texture; +uniform sampler2D cloud_noise_texture_next; +uniform float blend_factor; +uniform vec4 cloud_pos_density1; +uniform vec4 cloud_pos_density2; +uniform vec4 cloud_color; +uniform float cloud_shadow; +uniform float cloud_scale; +uniform float cloud_variance; +uniform vec3 camPosLocal; +uniform vec3 sun_dir; +uniform float sun_size; +uniform float far_z; + +uniform sampler2D transmittance_texture; +uniform sampler3D scattering_texture; +uniform sampler3D single_mie_scattering_texture; +uniform sampler2D irradiance_texture; +uniform sampler2D sh_input_r; +uniform sampler2D sh_input_g; +uniform sampler2D sh_input_b; + +vec3 GetSkyLuminance(vec3 camPos, vec3 view_dir, float shadow_length, vec3 dir, out vec3 transmittance); + +/// Soft clips the light with a gamma correction +vec3 scaleSoftClip(vec3 light); + +vec4 cloudNoise(vec2 uv) +{ + vec4 a = texture2D(cloud_noise_texture, uv); + vec4 b = texture2D(cloud_noise_texture_next, uv); + vec4 cloud_noise_sample = mix(a, b, blend_factor); + return cloud_noise_sample; +} + +void main() +{ + // Set variables + vec2 uv1 = vary_texcoord0.xy; + vec2 uv2 = vary_texcoord1.xy; + vec2 uv3 = vary_texcoord2.xy; + float cloudDensity = 2.0 * (cloud_shadow - 0.25); + + if (cloud_scale < 0.001) + { + discard; + } + + vec2 uv4 = vary_texcoord3.xy; + + vec2 disturbance = vec2(cloudNoise(uv1 / 16.0f).x, cloudNoise((uv3 + uv1) / 16.0f).x) * cloud_variance * (1.0f - cloud_scale * 0.25f); + + // Offset texture coords + uv1 += cloud_pos_density1.xy + (disturbance * 0.2); //large texture, visible density + uv2 += cloud_pos_density1.xy; //large texture, self shadow + uv3 += cloud_pos_density2.xy; //small texture, visible density + uv4 += cloud_pos_density2.xy; //small texture, self shadow + + float density_variance = min(1.0, (disturbance.x* 2.0 + disturbance.y* 2.0) * 4.0); + + cloudDensity *= 1.0 - (density_variance * density_variance); + + // Compute alpha1, the main cloud opacity + float alpha1 = (cloudNoise(uv1).x - 0.5) + (cloudNoise(uv3).x - 0.5) * cloud_pos_density2.z; + alpha1 = min(max(alpha1 + cloudDensity, 0.) * 10 * cloud_pos_density1.z, 1.); + + // And smooth + alpha1 = 1. - alpha1 * alpha1; + alpha1 = 1. - alpha1 * alpha1; + + if (alpha1 < 0.001f) + { + discard; + } + + // Compute alpha2, for self shadowing effect + // (1 - alpha2) will later be used as percentage of incoming sunlight + float alpha2 = (cloudNoise(uv2).x - 0.5); + alpha2 = min(max(alpha2 + cloudDensity, 0.) * 2.5 * cloud_pos_density1.z, 1.); + + // And smooth + alpha2 = 1. - alpha2; + alpha2 = 1. - alpha2 * alpha2; + + vec3 view_ray = vary_pos.xyz + camPosLocal; + + vec3 view_direction = normalize(view_ray); + vec3 sun_direction = normalize(sun_dir); + vec3 earth_center = vec3(0, 0, -6360.0f); + vec3 camPos = (camPosLocal / 1000.0f) - earth_center; + + vec3 transmittance; + vec3 radiance_sun = GetSkyLuminance(camPos, view_direction, 1.0 - alpha1, sun_direction, transmittance); + + vec3 sun_color = vec3(1.0) - exp(-radiance_sun * 0.0001); + + // Combine + vec4 color; + + vec4 l1tap = vec4(1.0/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265)); + + vec4 l1r = texture2D(sh_input_r, vec2(0,0)); + vec4 l1g = texture2D(sh_input_g, vec2(0,0)); + vec4 l1b = texture2D(sh_input_b, vec2(0,0)); + + vec3 sun_indir = vec3(-view_direction.xy, view_direction.z); + vec3 amb = vec3(dot(l1r, l1tap * vec4(1, sun_indir)), + dot(l1g, l1tap * vec4(1, sun_indir)), + dot(l1b, l1tap * vec4(1, sun_indir))); + + + amb = max(vec3(0), amb); + + color.rgb = sun_color * cloud_color.rgb * (1. - alpha2); + color.rgb = pow(color.rgb, vec3(1.0 / 2.2)); + color.rgb += amb; + + frag_data[0] = vec4(color.rgb, alpha1); + frag_data[1] = vec4(0); + frag_data[2] = vec4(0,1,0,1); +} + diff --git a/indra/newview/app_settings/shaders/class3/deferred/cloudsV.glsl b/indra/newview/app_settings/shaders/class3/deferred/cloudsV.glsl new file mode 100644 index 0000000000..71e422ddf0 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/cloudsV.glsl @@ -0,0 +1,70 @@ +/** + * @file WLCloudsV.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$ + */ + +uniform mat4 modelview_projection_matrix; +uniform mat4 modelview_matrix; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec2 texcoord0; + +////////////////////////////////////////////////////////////////////////// +// The vertex shader for creating the atmospheric sky +/////////////////////////////////////////////////////////////////////////////// + +// Output parameters +VARYING vec2 vary_texcoord0; +VARYING vec2 vary_texcoord1; +VARYING vec2 vary_texcoord2; +VARYING vec2 vary_texcoord3; +VARYING vec3 vary_pos; + +// Inputs +uniform float cloud_scale; +uniform vec4 lightnorm; +uniform vec3 camPosLocal; + +void main() +{ + vary_pos = position; + + // World / view / projection + gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); + + // Texture coords + vary_texcoord0 = texcoord0; + vary_texcoord0.xy -= 0.5; + vary_texcoord0.xy /= max(0.001, cloud_scale); + vary_texcoord0.xy += 0.5; + + vary_texcoord1 = vary_texcoord0; + vary_texcoord1.x += lightnorm.x * 0.0125; + vary_texcoord1.y += lightnorm.z * 0.0125; + + vary_texcoord2 = vary_texcoord0 * 16.; + vary_texcoord3 = vary_texcoord1 * 16.; + + // END CLOUDS +} + diff --git a/indra/newview/app_settings/shaders/class3/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class3/deferred/deferredUtil.glsl new file mode 100644 index 0000000000..e27bbce094 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/deferredUtil.glsl @@ -0,0 +1,79 @@ +/** + * @file class1/deferred/deferredUtil.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 normalMap; +uniform sampler2DRect depthMap; + +uniform mat4 inv_proj; +uniform vec2 screen_res; + +vec2 getScreenCoordinate(vec2 screenpos) +{ + vec2 sc = screenpos.xy * 2.0; + if (screen_res.x > 0 && screen_res.y > 0) + { + sc /= screen_res; + } + return sc - vec2(1.0, 1.0); +} + +vec3 getNorm(vec2 screenpos) +{ + vec2 enc = texture2DRect(normalMap, screenpos.xy).xy; + 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; +} + +float getDepth(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen).r; + return depth; +} + +vec4 getPosition(vec2 pos_screen) +{ + float depth = getDepth(pos_screen); + vec2 sc = getScreenCoordinate(pos_screen); + 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 getPositionWithDepth(vec2 pos_screen, float depth) +{ + vec2 sc = getScreenCoordinate(pos_screen); + 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; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/depthToShadowVolumeG.glsl b/indra/newview/app_settings/shaders/class3/deferred/depthToShadowVolumeG.glsl new file mode 100644 index 0000000000..cdaff4b09f --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/depthToShadowVolumeG.glsl @@ -0,0 +1,202 @@ +/** + * @file depthToShadowVolumeG.glsl + * + * $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$ + */ +#extension GL_ARB_geometry_shader4 : enable +#extension GL_ARB_texture_rectangle : enable + +/*[EXTRA_CODE_HERE]*/ + +layout (triangles) in; +layout (triangle_strip, max_vertices = 128) out; + +uniform sampler2DRect depthMap; +uniform mat4 shadowMatrix[6]; +uniform vec4 lightpos; + +VARYING vec2 vary_texcoord0; + +out vec3 to_vec; + +void cross_products(out vec4 ns[3], int a, int b, int c) +{ + ns[0] = cross(gl_PositionIn[b].xyz - gl_PositionIn[a].xyz, gl_PositionIn[c].xyz - gl_PositionIn[a].xyz); + ns[1] = cross(gl_PositionIn[c].xyz - gl_PositionIn[b].xyz, gl_PositionIn[a].xyz - gl_PositionIn[b].xyz); + ns[2] = cross(gl_PositionIn[a].xyz - gl_PositionIn[c].xyz, gl_PositionIn[b].xyz - gl_PositionIn[c].xyz); +} + +vec3 getLightDirection(vec4 lightpos, vec3 pos) +{ + + vec3 lightdir = lightpos.xyz - lightpos.w * pos; + return lightdir; +} + +void emitTri(vec4 v[3]) +{ + gl_Position = proj_matrix * v[0]; + EmitVertex(); + + gl_Position = proj_matrix * v[1]; + EmitVertex(); + + gl_Position = proj_matrix * v[2]; + EmitVertex(); + + EndPrimitive(); +} + +void emitQuad(vec4 v[4] +{ + // Emit a quad as a triangle strip. + gl_Position = proj_matrix*v[0]; + EmitVertex(); + + gl_Position = proj_matrix*v[1]; + EmitVertex(); + + gl_Position = proj_matrix*v[2]; + EmitVertex(); + + gl_Position = proj_matrix*v[3]; + EmitVertex(); + + EndPrimitive(); +} + +void emitPrimitives(int layer) +{ + int i = layer; + gl_Layer = i; + + vec4 depth1 = vec4(texture2DRect(depthMap, tc0).rg, texture2DRect(depthMap, tc1).rg)); + vec3 depth2 = vec4(texture2DRect(depthMap, tc2).rg, texture2DRect(depthMap, tc3).rg)); + vec3 depth3 = vec4(texture2DRect(depthMap, tc4).rg, texture2DRect(depthMap, tc5).rg)); + vec3 depth4 = vec4(texture2DRect(depthMap, tc6).rg, texture2DRect(depthMap, tc7).rg)); + + depth1 = min(depth1, depth2); + depth1 = min(depth1, depth3); + depth1 = min(depth1, depth4); + + vec2 depth = min(depth1.xy, depth1.zw); + + int side = sqrt(gl_VerticesIn); + + for (int j = 0; j < side; j++) + { + for (int k = 0; k < side; ++k) + { + vec3 pos = gl_PositionIn[(j * side) + k].xyz; + vec4 v = shadowMatrix[i] * vec4(pos, 1.0); + gl_Position = v; + to_vec = pos - light_position.xyz * depth; + EmitVertex(); + } + + EndPrimitive(); + } + + vec3 norms[3]; // Normals + vec3 lightdir3]; // Directions toward light + + vec4 v[4]; // Temporary vertices + + vec4 or_pos[3] = + { // Triangle oriented toward light source + gl_PositionIn[0], + gl_PositionIn[2], + gl_PositionIn[4] + }; + + // Compute normal at each vertex. + cross_products(n, 0, 2, 4); + + // Compute direction from vertices to light. + lightdir[0] = getLightDirection(lightpos, gl_PositionIn[0].xyz); + lightdir[1] = getLightDirection(lightpos, gl_PositionIn[2].xyz); + lightdir[2] = getLightDirection(lightpos, gl_PositionIn[4].xyz); + + // Check if the main triangle faces the light. + bool faces_light = true; + if (!(dot(ns[0],d[0]) > 0 + |dot(ns[1],d[1]) > 0 + |dot(ns[2],d[2]) > 0)) + { + // Flip vertex winding order in or_pos. + or_pos[1] = gl_PositionIn[4]; + or_pos[2] = gl_PositionIn[2]; + faces_light = false; + } + + // Near cap: simply render triangle. + emitTri(or_pos); + + // Far cap: extrude positions to infinity. + v[0] =vec4(lightpos.w * or_pos[0].xyz - lightpos.xyz,0); + v[1] =vec4(lightpos.w * or_pos[2].xyz - lightpos.xyz,0); + v[2] =vec4(lightpos.w * or_pos[1].xyz - lightpos.xyz,0); + + emitTri(v); + + // Loop over all edges and extrude if needed. + for ( int i=0; i<3; i++ ) + { + // Compute indices of neighbor triangle. + int v0 = i*2; + int nb = (i*2+1); + int v1 = (i*2+2) % 6; + cross_products(n, v0, nb, v1); + + // Compute direction to light, again as above. + d[0] =lightpos.xyz-lightpos.w*gl_PositionIn[v0].xyz; + d[1] =lightpos.xyz-lightpos.w*gl_PositionIn[nb].xyz; + d[2] =lightpos.xyz-lightpos.w*gl_PositionIn[v1].xyz; + + bool is_parallel = gl_PositionIn[nb].w < 1e-5; + + // Extrude the edge if it does not have a + // neighbor, or if it's a possible silhouette. + if (is_parallel || + ( faces_light != (dot(ns[0],d[0])>0 || + dot(ns[1],d[1])>0 || + dot(ns[2],d[2])>0) )) + { + // Make sure sides are oriented correctly. + int i0 = faces_light ? v0 : v1; + int i1 = faces_light ? v1 : v0; + + v[0] = gl_PositionIn[i0]; + v[1] = vec4(lightpos.w*gl_PositionIn[i0].xyz - lightpos.xyz, 0); + v[2] = gl_PositionIn[i1]; + v[3] = vec4(lightpos.w*gl_PositionIn[i1].xyz - lightpos.xyz, 0); + + emitQuad(v); + } + } +} + +void main() +{ + // Output + emitPrimitives(0); +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShF.glsl b/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShF.glsl new file mode 100644 index 0000000000..34d26cddea --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShF.glsl @@ -0,0 +1,70 @@ +/** + * @file class3/deferred/gatherSkyShF.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$ + */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_data[3]; +#else +#define frag_data gl_FragData +#endif + +VARYING vec2 vary_frag; + +uniform vec2 screen_res; +uniform sampler2D sh_input_r; +uniform sampler2D sh_input_g; +uniform sampler2D sh_input_b; + +void main() +{ + vec2 offset = vec2(2.0) / screen_res; + + vec4 r = vec4(0); + vec4 g = vec4(0); + vec4 b = vec4(0); + + vec2 tc = vary_frag * 2.0; + + r += texture2D(sh_input_r, tc + vec2(0, 0)); + r += texture2D(sh_input_r, tc + vec2(offset.x, 0)); + r += texture2D(sh_input_r, tc + vec2(0, offset.y)); + r += texture2D(sh_input_r, tc + vec2(offset.x, offset.y)); + r /= 4.0f; + + g += texture2D(sh_input_g, tc + vec2(0, 0)); + g += texture2D(sh_input_g, tc + vec2(offset.x, 0)); + g += texture2D(sh_input_g, tc + vec2(0, offset.y)); + g += texture2D(sh_input_g, tc + vec2(offset.x, offset.y)); + g /= 4.0f; + + b += texture2D(sh_input_b, tc + vec2(0, 0)); + b += texture2D(sh_input_b, tc + vec2(offset.x, 0)); + b += texture2D(sh_input_b, tc + vec2(0, offset.y)); + b += texture2D(sh_input_b, tc + vec2(offset.x, offset.y)); + b /= 4.0f; + + frag_data[0] = r; + frag_data[1] = g; + frag_data[2] = b; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShV.glsl b/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShV.glsl new file mode 100644 index 0000000000..337c8a50fe --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShV.glsl @@ -0,0 +1,40 @@ +/** + * @file gatherSkyShV.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$ + */ + +ATTRIBUTE vec3 position; +ATTRIBUTE vec2 texcoord0; + +VARYING vec2 vary_frag; +uniform vec2 screen_res; + +void main() +{ + // pass through untransformed fullscreen pos + float oo_divisor = screen_res.x / 64.0; + vec3 pos = (position.xyz * oo_divisor) + vec3(oo_divisor - 1, oo_divisor - 1, 0); + gl_Position = vec4(pos.xyz, 1.0); + vary_frag = texcoord0 * oo_divisor; +} + diff --git a/indra/newview/app_settings/shaders/class3/deferred/genSkyShF.glsl b/indra/newview/app_settings/shaders/class3/deferred/genSkyShF.glsl new file mode 100644 index 0000000000..d5d91c88f0 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/genSkyShF.glsl @@ -0,0 +1,111 @@ +/** + * @file class3/deferred/genSkyShF.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$ + */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_data[3]; +#else +#define frag_data gl_FragData +#endif + +VARYING vec2 vary_frag; + +uniform vec3 sun_dir; + +uniform sampler2D transmittance_texture; +uniform sampler3D scattering_texture; +uniform sampler3D single_mie_scattering_texture; +uniform sampler2D irradiance_texture; + +vec3 GetSkyLuminance(vec3 camPos, vec3 view_dir, float shadow_length, vec3 dir, out vec3 transmittance); + +vec3 calcDirection(vec2 tc) +{ + float phi = tc.y * 2.0 * 3.14159265; + float cosTheta = sqrt(1.0 - tc.x); + float sinTheta = sqrt(1.0 - cosTheta * cosTheta); + return vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta); +} + +// reverse mapping above to convert a hemisphere direction into phi/theta values +void getPhiAndThetaFromDirection(vec3 dir, out float phi, out float theta) +{ + float sin_theta; + float cos_theta; + cos_theta = dir.z; + theta = acos(cos_theta); + sin_theta = sin(theta); + phi = abs(sin_theta) > 0.0001 ? acos(dir.x / sin_theta) : 1.0; +} + +// reverse mapping above to convert a hemisphere direction into an SH texture sample pos +vec2 calcShUvFromDirection(vec3 dir) +{ + vec2 uv; + float phi; + float theta; + getPhiAndThetaFromDirection(dir, phi, theta); + uv.y = phi / 2.0 * 3.14159265; + uv.x = theta / 2.0 * 3.14159265; + return uv; +} + +void projectToL1(vec3 n, vec3 c, vec4 basis, out vec4 coeffs[3]) +{ + coeffs[0] = vec4(basis.x, n * basis.yzw * c.r); + coeffs[1] = vec4(basis.x, n * basis.yzw * c.g); + coeffs[2] = vec4(basis.x, n * basis.yzw * c.b); +} + +void main() +{ + float Y00 = sqrt(1.0 / 3.14159265) * 0.5; + float Y1x = sqrt(3.0 / 3.14159265) * 0.5; + float Y1y = Y1x; + float Y1z = Y1x; + + vec4 L1 = vec4(Y00, Y1x, Y1y, Y1z); + + vec3 view_direction = calcDirection(vary_frag); + vec3 sun_direction = normalize(sun_dir); + vec3 cam_pos = vec3(0, 0, 6360); + + vec3 transmittance; + vec3 radiance = GetSkyLuminance(cam_pos, view_direction, 0.0f, sun_direction, transmittance); + + vec3 color = vec3(1.0) - exp(-radiance * 0.0001); + + color = pow(color, vec3(1.0/2.2)); + + vec4 coeffs[3]; + coeffs[0] = vec4(0); + coeffs[1] = vec4(0); + coeffs[2] = vec4(0); + + projectToL1(view_direction, color.rgb, L1, coeffs); + + frag_data[0] = coeffs[0]; + frag_data[1] = coeffs[1]; + frag_data[2] = coeffs[2]; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/genSkyShV.glsl b/indra/newview/app_settings/shaders/class3/deferred/genSkyShV.glsl new file mode 100644 index 0000000000..b466883dc7 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/genSkyShV.glsl @@ -0,0 +1,37 @@ +/** + * @file genSkyShV.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$ + */ + +ATTRIBUTE vec3 position; +ATTRIBUTE vec2 texcoord0; + +VARYING vec2 vary_frag; + +void main() +{ + // pass through untransformed fullscreen pos + gl_Position = vec4(position.xyz, 1.0); + vary_frag = texcoord0; +} + diff --git a/indra/newview/app_settings/shaders/class3/deferred/indirect.glsl b/indra/newview/app_settings/shaders/class3/deferred/indirect.glsl new file mode 100644 index 0000000000..33c5667cae --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/indirect.glsl @@ -0,0 +1,44 @@ +/** + * @file class3/deferred/indirect.glsl + * + * $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$ + */ + +/*[EXTRA_CODE_HERE]*/ + +uniform sampler2D sh_input_r; +uniform sampler2D sh_input_g; +uniform sampler2D sh_input_b; + +vec3 GetIndirect(vec3 norm) +{ + vec4 l1tap = vec4(1.0/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265)); + vec4 l1r = texture2D(sh_input_r, vec2(0,0)); + vec4 l1g = texture2D(sh_input_g, vec2(0,0)); + vec4 l1b = texture2D(sh_input_b, vec2(0,0)); + vec3 indirect = vec3(dot(l1r, l1tap * vec4(1, norm.xyz)), + dot(l1g, l1tap * vec4(1, norm.xyz)), + dot(l1b, l1tap * vec4(1, norm.xyz))); + indirect = clamp(indirect, vec3(0), vec3(1.0)); + return indirect; +} + diff --git a/indra/newview/app_settings/shaders/class3/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/multiSpotLightF.glsl new file mode 100644 index 0000000000..9d62b9d180 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/multiSpotLightF.glsl @@ -0,0 +1,291 @@ +/** + * @file multiSpotLightF.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 +#extension GL_ARB_shader_texture_lod : enable + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2DRect diffuseRect; +uniform sampler2DRect specularRect; +uniform sampler2DRect depthMap; +uniform sampler2DRect 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 +uniform vec3 proj_p; //plane projection is emitting from (in screen space) +uniform vec3 proj_n; +uniform float proj_focus; //distance from plane to begin blurring +uniform float proj_lod; //(number of mips in proj map) +uniform float proj_range; //range between near clip and far clip plane of projection +uniform float proj_ambient_lod; +uniform float proj_ambiance; +uniform float near_clip; +uniform float far_clip; + +uniform vec3 proj_origin; //origin of projection to be used for angular attenuation +uniform float sun_wash; +uniform int proj_shadow_idx; +uniform float shadow_fade; + +uniform vec3 center; +uniform float size; +uniform vec3 color; +uniform float falloff; + +VARYING vec4 vary_fragcoord; +uniform vec2 screen_res; + +uniform mat4 inv_proj; + +vec3 getNorm(vec2 pos_screen); + +vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + 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); + + 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); + + float edge = 0.25*det; + + ret *= clamp(d/edge, 0.0, 1.0); + + return ret; +} + +vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = tc-vec2(0.5); + + float d = dot(dist,dist); + + ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0); + + return ret; +} + + +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 = center.xyz-pos.xyz; + 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); + shadow = (proj_shadow_idx == 0) ? shd.b : shd.a; + shadow += shadow_fade; + shadow = clamp(shadow, 0.0, 1.0); + } + + vec3 norm = texture2DRect(normalMap, frag.xy).xyz; + + float envIntensity = norm.z; + + norm = getNorm(frag.xy); + + norm = normalize(norm); + float l_dist = -dot(lv, proj_n); + + vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0)); + if (proj_tc.z < 0.0) + { + discard; + } + + proj_tc.xyz /= proj_tc.w; + + float fa = (falloff*0.5)+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; + } + + lv = proj_origin-pos.xyz; + lv = normalize(lv); + float da = dot(norm, lv); + + vec3 col = vec3(0,0,0); + + vec3 diff_tex = srgb_to_linear(texture2DRect(diffuseRect, frag.xy).rgb); + + vec4 spec = texture2DRect(specularRect, frag.xy); + + vec3 dlit = vec3(0, 0, 0); + + float noise = texture2D(noiseMap, frag.xy/128.0).b; + if (proj_tc.z > 0.0 && + proj_tc.x < 1.0 && + proj_tc.y < 1.0 && + proj_tc.x > 0.0 && + proj_tc.y > 0.0) + { + float amb_da = proj_ambiance; + float lit = 0.0; + + 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); + + 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)*(1.0-shadow)*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; + } + + + if (spec.a > 0.0) + { + vec3 npos = -normalize(pos); + dlit *= min(da*6.0, 1.0) * dist_atten; + + //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); + + //project from point pos in direction ref to plane proj_p, proj_n + vec3 pdelta = proj_p-pos; + float ds = dot(ref, proj_n); + + 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 /= stc.w; + + if (stc.x < 1.0 && + stc.y < 1.0 && + stc.x > 0.0 && + stc.y > 0.0) + { + 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)); + + col = scaleDownLight(col); + + //output linear space color as gamma correction happens down stream + frag_color.rgb = col; + frag_color.a = 0.0; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/pointShadowBlurF.glsl b/indra/newview/app_settings/shaders/class3/deferred/pointShadowBlurF.glsl new file mode 100644 index 0000000000..ca9ce3a2e1 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/pointShadowBlurF.glsl @@ -0,0 +1,37 @@ +/** + * @file pointShadowBlur.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 samplerCube cube_map; + +in vec3 to_vec; + +out vec4 fragColor; + +void main() +{ + vec4 vcol = texture(cube_map, to_vec); + fragColor = vec4(vcol.rgb, 1.0); +} + diff --git a/indra/newview/app_settings/shaders/class3/deferred/shVisF.glsl b/indra/newview/app_settings/shaders/class3/deferred/shVisF.glsl new file mode 100644 index 0000000000..c8991f7a18 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/shVisF.glsl @@ -0,0 +1,73 @@ +/** + * @file class3/deferred/shVisF.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 + +///////////////////////////////////////////////////////////////////////// +// Fragment shader for L1 SH debug rendering +///////////////////////////////////////////////////////////////////////// + +uniform sampler2D sh_input_r; +uniform sampler2D sh_input_g; +uniform sampler2D sh_input_b; + +uniform mat3 inv_modelviewprojection; + +VARYING vec4 vary_pos; + +void main(void) +{ + vec2 coord = vary_pos.xy + vec2(0.5,0.5); + + coord.x *= (1.6/0.9); + + if (dot(coord, coord) > 0.25) + { + discard; + } + + vec4 n = vec4(coord*2.0, 0.0, 1); + //n.y = -n.y; + n.z = sqrt(max(1.0-n.x*n.x-n.y*n.y, 0.0)); + //n.xyz = inv_modelviewprojection * n.xyz; + + vec4 l1tap = vec4(1.0/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265)); + vec4 l1r = texture2D(sh_input_r, vec2(0,0)); + vec4 l1g = texture2D(sh_input_g, vec2(0,0)); + vec4 l1b = texture2D(sh_input_b, vec2(0,0)); + vec3 indirect = vec3( + dot(l1r, l1tap * n), + dot(l1g, l1tap * n), + dot(l1b, l1tap * n)); + + //indirect = pow(indirect, vec3(0.45)); + indirect *= 3.0; + + frag_color = vec4(indirect, 1.0); +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/shVisV.glsl b/indra/newview/app_settings/shaders/class3/deferred/shVisV.glsl new file mode 100644 index 0000000000..8f32dfde79 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/shVisV.glsl @@ -0,0 +1,33 @@ +/** + * @file class3/deferred/shVisV.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$ + */ +ATTRIBUTE vec3 position; +VARYING vec4 vary_pos; + +void main() +{ + // Output + vary_pos = vec4(position, 1); + gl_Position = vary_pos; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendF.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendF.glsl new file mode 100644 index 0000000000..345c07a354 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendF.glsl @@ -0,0 +1,58 @@ +/** + * @file shadowAlphaMaskF.glsl + * + * $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$ + */ + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2D diffuseMap; + +#if !defined(DEPTH_CLAMP) +VARYING float pos_zd2; +#endif + +VARYING float pos_w; + +VARYING float target_pos_x; +VARYING vec4 vertex_color; +VARYING vec2 vary_texcoord0; +VARYING vec3 pos; + +vec4 computeMoments(float depth, float a); + +void main() +{ + float alpha = diffuseLookup(vary_texcoord0.xy).a * vertex_color.a; + + frag_color = computeMoments(length(pos), float a); + +#if !defined(DEPTH_CLAMP) + gl_FragDepth = max(pos_zd2/pos_w+0.5, 0.0); +#endif +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendV.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendV.glsl new file mode 100644 index 0000000000..af1461c297 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendV.glsl @@ -0,0 +1,66 @@ +/** + * @file shadowAlphaMaskV.glsl + * + * $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$ + */ + +uniform mat4 texture_matrix0; +uniform mat4 modelview_projection_matrix; +uniform float shadow_target_width; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec4 diffuse_color; +ATTRIBUTE vec2 texcoord0; + +#if !defined(DEPTH_CLAMP) +VARYING float pos_zd2; +#endif + +VARYING float target_pos_x; +VARYING vec4 pos; +VARYING vec4 vertex_color; +VARYING vec2 vary_texcoord0; + +void passTextureIndex(); + +void main() +{ + //transform vertex + vec4 pre_pos = vec4(position.xyz, 1.0); + vec4 pos = modelview_projection_matrix * pre_pos; + target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x; + + pos_w = pos.w; + +#if !defined(DEPTH_CLAMP) + pos_zd2 = pos.z * 0.5; + + gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); +#else + gl_Position = pos; +#endif + + passTextureIndex(); + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; + vertex_color = diffuse_color; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskF.glsl new file mode 100644 index 0000000000..50f1ffd626 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskF.glsl @@ -0,0 +1,74 @@ +/** + * @file class3/deferred/shadowAlphaMaskF.glsl + * + * $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$ + */ + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2D diffuseMap; + +#if !defined(DEPTH_CLAMP) +VARYING float pos_zd2; +#endif + +VARYING float pos_w; + +VARYING float target_pos_x; +VARYING vec4 vertex_color; +VARYING vec2 vary_texcoord0; + +vec4 getPosition(vec2 screen_coord); +vec4 computeMoments(float depth, float a); + +void main() +{ + vec4 pos = getPosition(vary_texcoord0.xy); + + float alpha = diffuseLookup(vary_texcoord0.xy).a * vertex_color.a; + + if (alpha < 0.05) // treat as totally transparent + { + discard; + } + + if (alpha < 0.88) // treat as semi-transparent + { + if (fract(0.5*floor(target_pos_x / pos_w )) < 0.25) + { + discard; + } + } + + frag_color = computeMoments(length(pos.xyz), alpha); + +#if !defined(DEPTH_CLAMP) + gl_FragDepth = max(pos_zd2/pos_w+0.5, 0.0); +#endif + +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskV.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskV.glsl new file mode 100644 index 0000000000..6a646f5e9e --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskV.glsl @@ -0,0 +1,67 @@ +/** + * @file class3/deferred/shadowAlphaMaskV.glsl + * + * $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$ + */ + +uniform mat4 texture_matrix0; +uniform mat4 modelview_projection_matrix; +uniform float shadow_target_width; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec4 diffuse_color; +ATTRIBUTE vec2 texcoord0; + +#if !defined(DEPTH_CLAMP) +VARYING float pos_zd2; +#endif + +VARYING vec4 pos; +VARYING float target_pos_x; +VARYING vec4 vertex_color; +VARYING vec2 vary_texcoord0; + +void passTextureIndex(); + +void main() +{ + //transform vertex + vec4 pre_pos = vec4(position.xyz, 1.0); + + pos = modelview_projection_matrix * pre_pos; + + target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x; + +#if !defined(DEPTH_CLAMP) + pos_zd2 = pos.z * 0.5; + + gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); +#else + gl_Position = pos; +#endif + + passTextureIndex(); + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; + + vertex_color = diffuse_color; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowCubeV.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowCubeV.glsl new file mode 100644 index 0000000000..db8c75fb8a --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/shadowCubeV.glsl @@ -0,0 +1,50 @@ +/** + * @file class3/deferred/shadowCubeV.glsl + * + * $LicenseInfo:firstyear=2011&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; + +#if !defined(DEPTH_CLAMP) +VARYING vec4 post_pos; +#endif + +uniform vec3 box_center; +uniform vec3 box_size; + +void main() +{ + //transform vertex + vec3 p = position*box_size+box_center; + vec4 pos = modelview_projection_matrix*vec4(p.xyz, 1.0); + +#if !defined(DEPTH_CLAMP) + post_pos = pos; + + gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); +#else + gl_Position = pos; +#endif +} diff --git a/indra/win_crash_logger/win_crash_logger.h b/indra/newview/app_settings/shaders/class3/deferred/shadowF.glsl index 2cc2cf3dcf..3350267130 100644 --- a/indra/win_crash_logger/win_crash_logger.h +++ b/indra/newview/app_settings/shaders/class3/deferred/shadowF.glsl @@ -1,10 +1,9 @@ /** - * @file win_crash_logger.h - * @brief Windows crash logger project includes + * @file class3/deferred/shadowF.glsl * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * 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 @@ -24,15 +23,27 @@ * $/LicenseInfo$ */ +/*[EXTRA_CODE_HERE]*/ -#if !defined(AFX_WIN_CRASH_LOGGER_H__79802F4B_7C37_4F63_A2BB_0768788C3A27__INCLUDED_) -#define AFX_WIN_CRASH_LOGGER_H__79802F4B_7C37_4F63_A2BB_0768788C3A27__INCLUDED_ +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 +uniform sampler2D diffuseMap; -#include "resource.h" +#if !defined(DEPTH_CLAMP) +VARYING float pos_zd2; +#endif +VARYING vec4 pos; +VARYING float target_pos_x; + +vec4 computeMoments(float depth, float a); + +void main() +{ + frag_color = computeMoments(length(pos), 1.0); +} -#endif // !defined(AFX_WIN_CRASH_LOGGER_H__79802F4B_7C37_4F63_A2BB_0768788C3A27__INCLUDED_) diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowUtil.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowUtil.glsl new file mode 100644 index 0000000000..2f69a353e8 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/shadowUtil.glsl @@ -0,0 +1,157 @@ +/** + * @file class3/deferred/shadowUtil.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 sampler2D shadowMap0; +uniform sampler2D shadowMap1; +uniform sampler2D shadowMap2; +uniform sampler2D shadowMap3; +uniform sampler2D shadowMap4; +uniform sampler2D shadowMap5; + +uniform vec3 sun_dir; +uniform vec3 moon_dir; +uniform vec2 shadow_res; +uniform vec2 proj_shadow_res; +uniform mat4 shadow_matrix[6]; +uniform vec4 shadow_clip; +uniform float shadow_bias; + +uniform float spot_shadow_bias; +uniform float spot_shadow_offset; + +float getDepth(vec2 screenpos); +vec3 getNorm(vec2 screenpos); +vec4 getPosition(vec2 pos_screen); + +float ReduceLightBleeding(float p_max, float Amount) +{ + return smoothstep(Amount, 1, p_max); +} + +float ChebyshevUpperBound(vec2 m, float t, float min_v, float Amount) +{ + float p = (t <= m.x) ? 1.0 : 0.0; + + float v = m.y - (m.x*m.x); + v = max(v, min_v); + + float d = t - m.x; + + float p_max = v / (v + d*d); + + p_max = ReduceLightBleeding(p_max, Amount); + + return max(p, p_max); +} + +vec4 computeMoments(float depth, float a) +{ + float m1 = depth; + float dx = dFdx(depth); + float dy = dFdy(depth); + float m2 = m1*m1 + 0.25 * a * (dx*dx + dy*dy); + return vec4(m1, m2, a, max(dx, dy)); +} + +float vsmDirectionalSample(vec4 stc, float depth, sampler2D shadowMap, mat4 shadowMatrix) +{ + vec4 lpos = shadowMatrix * stc; + vec4 moments = texture2D(shadowMap, lpos.xy); + return ChebyshevUpperBound(moments.rg, depth - shadow_bias * 256.0f, 0.125, 0.9); +} + +float vsmSpotSample(vec4 stc, float depth, sampler2D shadowMap, mat4 shadowMatrix) +{ + vec4 lpos = shadowMatrix * stc; + vec4 moments = texture2D(shadowMap, lpos.xy); + lpos.xyz /= lpos.w; + lpos.xy *= 0.5; + lpos.xy += 0.5; + return ChebyshevUpperBound(moments.rg, depth - spot_shadow_bias * 16.0f, 0.125, 0.9); +} + +#if VSM_POINT_SHADOWS +float vsmPointSample(float lightDistance, vec3 lightDirection, samplerCube shadow_cube_map) +{ + vec4 moments = textureCube(shadow_cube_map, light_direction); + return ChebyshevUpperBound(moments.rg, light_distance, 0.01, 0.25); +} +#endif + +float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen) +{ + if (pos.z < -shadow_clip.w) + { + discard; + } + + float depth = getDepth(pos_screen); + + vec4 spos = vec4(pos,1.0); + vec4 near_split = shadow_clip*-0.75; + vec4 far_split = shadow_clip*-1.25; + + float shadow = 0.0f; + float weight = 1.0; + + if (spos.z < near_split.z) + { + shadow += vsmDirectionalSample(spos, depth, shadowMap3, shadow_matrix[3]); + weight += 1.0f; + } + if (spos.z < near_split.y) + { + shadow += vsmDirectionalSample(spos, depth, shadowMap2, shadow_matrix[2]); + weight += 1.0f; + } + if (spos.z < near_split.x) + { + shadow += vsmDirectionalSample(spos, depth, shadowMap1, shadow_matrix[1]); + weight += 1.0f; + } + if (spos.z > far_split.x) + { + shadow += vsmDirectionalSample(spos, depth, shadowMap0, shadow_matrix[0]); + weight += 1.0f; + } + + shadow /= weight; + + return shadow; +} + +float sampleSpotShadow(vec3 pos, vec3 norm, int index, vec2 pos_screen) +{ + if (pos.z < -shadow_clip.w) + { + discard; + } + + float depth = getDepth(pos_screen); + + pos += norm * spot_shadow_offset; + return vsmSpotSample(vec4(pos, 1.0), depth, (index == 0) ? shadowMap4 : shadowMap5, shadow_matrix[4 + index]); +} + diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowV.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowV.glsl new file mode 100644 index 0000000000..6577fe0ecf --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/shadowV.glsl @@ -0,0 +1,62 @@ +/** + * @file class3/deferred/shadowV.glsl + * + * $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$ + */ + +uniform mat4 modelview_projection_matrix; +uniform float shadow_target_width; +uniform mat4 texture_matrix0; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec2 texcoord0; + +#if !defined(DEPTH_CLAMP) +VARYING float pos_zd2; +#endif + +VARYING vec4 pos; +VARYING float target_pos_x; +VARYING vec4 vertex_color; +VARYING vec2 vary_texcoord0; + +void passTextureIndex(); + +void main() +{ + //transform vertex + vec4 pre_pos = vec4(position.xyz, 1.0); + + pos = modelview_projection_matrix * pre_pos; + + target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x; + +#if !defined(DEPTH_CLAMP) + pos_zd2 = pos.z * 0.5; + + gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); +#else + gl_Position = pos; +#endif + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/skyF.glsl b/indra/newview/app_settings/shaders/class3/deferred/skyF.glsl new file mode 100644 index 0000000000..a0b082ed7c --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/skyF.glsl @@ -0,0 +1,126 @@ +/** + * @file class3/deferred/skyF.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$ + */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_data[3]; +#else +#define frag_data gl_FragData +#endif + +VARYING vec2 vary_frag; + +uniform vec3 camPosLocal; +uniform vec3 sun_dir; +uniform float sun_size; +uniform float far_z; +uniform mat4 inv_proj; +uniform mat4 inv_modelview; + +uniform sampler2D transmittance_texture; +uniform sampler3D scattering_texture; +uniform sampler3D single_mie_scattering_texture; +uniform sampler2D irradiance_texture; +uniform sampler2D rainbow_map; +uniform sampler2D halo_map; + +uniform float moisture_level; +uniform float droplet_radius; +uniform float ice_level; + +vec3 GetSolarLuminance(); +vec3 GetSkyLuminance(vec3 camPos, vec3 view_dir, float shadow_length, vec3 dir, out vec3 transmittance); +vec3 GetSkyLuminanceToPoint(vec3 camPos, vec3 pos, float shadow_length, vec3 dir, out vec3 transmittance); + +vec3 ColorFromRadiance(vec3 radiance); +vec3 rainbow(float d) +{ + // d is the dot product of view and sun directions, so ranging -1.0..1.0 + // 'interesting' values of d are the range -0.75..-0.825, when view is nearly opposite of sun vec + // Rainbox texture mode is GL_REPEAT, so tc of -.75 is equiv to 0.25, -0.825 equiv to 0.175. + + // SL-13629 Rainbow texture has colors within the correct .175...250 range, but order is inverted. + // Rather than replace the texture, we mirror and translate the y tc to keep the colors within the + // interesting range, but in reversed order: i.e. d = (1 - d) - 1.575 + d = clamp(-0.575 - d, 0.0, 1.0); + + // With the colors in the lower 1/4 of the texture, inverting the coords leaves most of it inaccessible. + // So, we can stretch the texcoord above the colors (ie > 0.25) to fill the entire remaining coordinate + // space. This improves gradation, reduces banding within the rainbow interior. (1-0.25) / (0.425/0.25) = 4.2857 + float interior_coord = max(0.0, d - 0.25) * 4.2857; + d = clamp(d, 0.0, 0.25) + interior_coord; + + float rad = (droplet_radius - 5.0f) / 1024.0f; + return pow(texture2D(rainbow_map, vec2(rad, d)).rgb, vec3(1.8)) * moisture_level; +} + +vec3 halo22(float d) +{ + float v = sqrt(max(0, 1 - (d*d))); + return texture2D(halo_map, vec2(0, v)).rgb * ice_level; +} + +void main() +{ + vec3 pos = vec3((vary_frag * 2.0) - vec2(1.0, 1.0f), 1.0); + vec4 view_pos = (inv_proj * vec4(pos, 1.0f)); + + view_pos /= view_pos.w; + + vec3 view_ray = (inv_modelview * vec4(view_pos.xyz, 0.0f)).xyz + camPosLocal; + + vec3 view_direction = normalize(view_ray); + vec3 sun_direction = normalize(sun_dir); + vec3 earth_center = vec3(0, 0, -6360.0f); + vec3 camPos = (camPosLocal / 1000.0f) - earth_center; + + vec3 transmittance; + vec3 radiance_sun = GetSkyLuminance(camPos, view_direction, 0.0f, sun_direction, transmittance); + vec3 solar_luminance = GetSolarLuminance(); + + // If the view ray intersects the Sun, add the Sun radiance. + float s = dot(view_direction, sun_direction); + + // cheesy solar disc... + if (s >= (sun_size * 0.999)) + { + radiance_sun += pow(smoothstep(0.0, 1.3, (s - (sun_size * 0.9))), 2.0) * solar_luminance * transmittance; + } + s = smoothstep(0.9, 1.0, s) * 16.0f; + + vec3 color = ColorFromRadiance(radiance_sun); + + float optic_d = dot(view_direction, sun_direction); + vec3 halo_22 = halo22(optic_d); + + color.rgb += rainbow(optic_d) * optic_d; + color.rgb += halo_22; + + color = pow(color, vec3(1.0/2.2)); + + frag_data[0] = vec4(color, 1.0 + s); + frag_data[1] = vec4(0.0); + frag_data[2] = vec4(0.0, 1.0, 0.0, 1.0); +} + diff --git a/indra/newview/app_settings/shaders/class3/deferred/skyV.glsl b/indra/newview/app_settings/shaders/class3/deferred/skyV.glsl new file mode 100644 index 0000000000..2eb222ada4 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/skyV.glsl @@ -0,0 +1,37 @@ +/** + * @file class3/deferred/skyV.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$ + */ + +ATTRIBUTE vec3 position; +ATTRIBUTE vec2 texcoord0; + +VARYING vec2 vary_frag; + +void main() +{ + // pass through untransformed fullscreen pos at back of frustum for proper sky depth testing + gl_Position = vec4(position.xy, 1.0f, 1.0); + vary_frag = texcoord0; +} + diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl new file mode 100644 index 0000000000..7ed9e7b4fc --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl @@ -0,0 +1,177 @@ +/** + * @file class3/deferred/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$ + */ + +#extension GL_ARB_texture_rectangle : enable + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2DRect diffuseRect; +uniform sampler2DRect specularRect; +uniform sampler2DRect normalMap; +uniform sampler2DRect lightMap; +uniform sampler2DRect depthMap; +uniform sampler2D lightFunc; + +uniform samplerCube environmentMap; +uniform float blur_size; +uniform float blur_fidelity; + +// Inputs +uniform vec4 morphFactor; +uniform vec3 camPosLocal; +uniform float cloud_shadow; +uniform float max_y; +uniform vec4 glow; +uniform mat3 env_mat; +uniform vec4 shadow_clip; + +uniform vec3 sun_dir; +VARYING vec2 vary_fragcoord; + +uniform mat4 inv_proj; +uniform mat4 inv_modelview; + +uniform vec2 screen_res; + +uniform sampler2D transmittance_texture; +uniform sampler3D scattering_texture; +uniform sampler3D single_mie_scattering_texture; +uniform sampler2D irradiance_texture; + +uniform sampler2D sh_input_r; +uniform sampler2D sh_input_g; +uniform sampler2D sh_input_b; + +vec3 GetSunAndSkyIrradiance(vec3 camPos, vec3 norm, vec3 dir, out vec3 sky_irradiance); +vec3 GetSkyLuminance(vec3 camPos, vec3 view_dir, float shadow_length, vec3 dir, out vec3 transmittance); +vec3 GetSkyLuminanceToPoint(vec3 camPos, vec3 pos, float shadow_length, vec3 dir, out vec3 transmittance); + +vec3 ColorFromRadiance(vec3 radiance); +vec4 getPositionWithDepth(vec2 pos_screen, float depth); +vec4 getPosition(vec2 pos_screen); +vec3 getNorm(vec2 pos_screen); + +#ifdef WATER_FOG +vec4 applyWaterFogView(vec3 pos, vec4 color); +#endif + +void main() +{ + vec2 tc = vary_fragcoord.xy; + float depth = texture2DRect(depthMap, tc.xy).r; + vec3 pos = getPositionWithDepth(tc, depth).xyz; + vec4 norm = texture2DRect(normalMap, tc); + float envIntensity = norm.z; + norm.xyz = getNorm(tc); + + float da = max(dot(norm.xyz, sun_dir.xyz), 0.0); + + vec4 diffuse = texture2DRect(diffuseRect, tc); // sRGB + diffuse.rgb = srgb_to_linear(diffuse.rgb); + + vec3 col; + float bloom = 0.0; + { + vec3 camPos = (camPosLocal / 1000.0f) + vec3(0, 0, 6360.0f); + + vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy); + + vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg; + + float scol = max(scol_ambocc.r, diffuse.a); + + float ambocc = scol_ambocc.g; + + vec4 l1tap = vec4(1.0/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265)); + vec4 l1r = texture2D(sh_input_r, vec2(0,0)); + vec4 l1g = texture2D(sh_input_g, vec2(0,0)); + vec4 l1b = texture2D(sh_input_b, vec2(0,0)); + + vec3 indirect = vec3(dot(l1r, l1tap * vec4(1, norm.xyz)), + dot(l1g, l1tap * vec4(1, norm.xyz)), + dot(l1b, l1tap * vec4(1, norm.xyz))); + + indirect = clamp(indirect, vec3(0), vec3(1.0)); + + vec3 transmittance; + vec3 sky_irradiance; + vec3 sun_irradiance = GetSunAndSkyIrradiance(camPos, norm.xyz, sun_dir, sky_irradiance); + vec3 inscatter = GetSkyLuminanceToPoint(camPos, (pos / 1000.f) + vec3(0, 0, 6360.0f), scol, sun_dir, transmittance); + + vec3 radiance = scol * (sun_irradiance + sky_irradiance) + inscatter; + vec3 atmo_color = ColorFromRadiance(radiance); + + col = atmo_color + indirect; + col *= transmittance; + col *= diffuse.rgb; + + vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); + + if (spec.a > 0.0) // specular reflection + { + // the old infinite-sky shiny reflection + // + float sa = dot(refnormpersp, sun_dir.xyz); + vec3 dumbshiny = scol * texture2D(lightFunc, vec2(sa, spec.a)).r * atmo_color; + + // add the two types of shiny together + vec3 spec_contrib = dumbshiny * spec.rgb * 0.25; + bloom = dot(spec_contrib, spec_contrib); + col += spec_contrib; + } + + col = mix(col, diffuse.rgb, diffuse.a); + + if (envIntensity > 0.0) + { //add environmentmap + vec3 env_vec = env_mat * refnormpersp; + vec3 sun_direction = (inv_modelview * vec4(sun_dir, 1.0)).xyz; + vec3 radiance_sun = GetSkyLuminance(camPos, env_vec, 0.0f, sun_direction, transmittance); + vec3 refcol = ColorFromRadiance(radiance_sun); + col = mix(col.rgb, refcol, envIntensity); + } + + /*if (norm.w < 0.5) + { + col = scaleSoftClipFrag(col); + }*/ + + #ifdef WATER_FOG + vec4 fogged = applyWaterFogView(pos,vec4(col, bloom)); + col = fogged.rgb; + bloom = fogged.a; + #endif + } + + //output linear since gamma correction happens down stream + frag_color.rgb = col; + frag_color.a = bloom; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl new file mode 100644 index 0000000000..9d872b8df8 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl @@ -0,0 +1,38 @@ +/** + * @file class3/deferred/softenLightV.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$ + */ +ATTRIBUTE vec3 position; + +VARYING vec2 vary_fragcoord; + +uniform mat4 modelview_projection_matrix; +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/class3/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl new file mode 100644 index 0000000000..56b0f4e5ce --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl @@ -0,0 +1,287 @@ +/** + * @file spotLightF.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 +#extension GL_ARB_shader_texture_lod : enable + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2DRect diffuseRect; +uniform sampler2DRect specularRect; +uniform sampler2DRect depthMap; +uniform sampler2DRect 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 +uniform vec3 proj_p; //plane projection is emitting from (in screen space) +uniform vec3 proj_n; +uniform float proj_focus; //distance from plane to begin blurring +uniform float proj_lod; //(number of mips in proj map) +uniform float proj_range; //range between near clip and far clip plane of projection +uniform float proj_ambient_lod; +uniform float proj_ambiance; +uniform float near_clip; +uniform float far_clip; + +uniform vec3 proj_origin; //origin of projection to be used for angular attenuation +uniform float sun_wash; +uniform int proj_shadow_idx; +uniform float shadow_fade; + +uniform float size; +uniform vec3 color; +uniform float falloff; + +VARYING vec3 trans_center; +VARYING vec4 vary_fragcoord; +uniform vec2 screen_res; + +uniform mat4 inv_proj; + +vec3 getNorm(vec2 pos_screen); + +vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + 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); + + 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); + + float edge = 0.25*det; + + ret *= clamp(d/edge, 0.0, 1.0); + + return ret; +} + +vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = tc-vec2(0.5); + + float d = dot(dist,dist); + + ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0); + + return ret; +} + + +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.xyz; + 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); + shadow = (proj_shadow_idx == 0) ? shd.b : shd.a; + shadow += shadow_fade; + shadow = clamp(shadow, 0.0, 1.0); + } + + vec3 norm = texture2DRect(normalMap, frag.xy).xyz; + float envIntensity = norm.z; + norm = getNorm(frag.xy); + + norm = normalize(norm); + float l_dist = -dot(lv, proj_n); + + vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0)); + if (proj_tc.z < 0.0) + { + discard; + } + + proj_tc.xyz /= proj_tc.w; + + float fa = (falloff*0.5) + 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; + } + + lv = proj_origin-pos.xyz; + lv = normalize(lv); + float da = dot(norm, lv); + + vec3 col = vec3(0,0,0); + + vec3 diff_tex = srgb_to_linear(texture2DRect(diffuseRect, frag.xy).rgb); + + vec4 spec = texture2DRect(specularRect, frag.xy); + + vec3 dlit = vec3(0, 0, 0); + + float noise = texture2D(noiseMap, frag.xy/128.0).b; + if (proj_tc.z > 0.0 && + proj_tc.x < 1.0 && + proj_tc.y < 1.0 && + proj_tc.x > 0.0 && + proj_tc.y > 0.0) + { + float amb_da = proj_ambiance; + float lit = 0.0; + + 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); + + 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)*(1.0-shadow)*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; + } + + + 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; + } + } + + + if (envIntensity > 0.0) + { + vec3 ref = reflect(normalize(pos), norm); + + //project from point pos in direction ref to plane proj_p, proj_n + vec3 pdelta = proj_p-pos; + float ds = dot(ref, proj_n); + + 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 /= stc.w; + + if (stc.x < 1.0 && + stc.y < 1.0 && + stc.x > 0.0 && + stc.y > 0.0) + { + 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/class3/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/sunLightF.glsl new file mode 100644 index 0000000000..112b498c90 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/sunLightF.glsl @@ -0,0 +1,57 @@ +/** + * @file class3\deferred\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$ + */ + +#extension GL_ARB_texture_rectangle : enable + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +//class 2, shadows, no SSAO + +// Inputs +VARYING vec2 vary_fragcoord; + +vec4 getPosition(vec2 pos_screen); +vec3 getNorm(vec2 pos_screen); + +float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); +float sampleSpotShadow(vec3 pos, vec3 norm, int index, vec2 pos_screen); + +void main() +{ + vec2 pos_screen = vary_fragcoord.xy; + vec4 pos = getPosition(pos_screen); + vec3 norm = getNorm(pos_screen); + + frag_color.r = sampleDirectionalShadow(pos.xyz, norm, pos_screen); + frag_color.g = 1.0f; + frag_color.b = sampleSpotShadow(pos.xyz, norm, 0, pos_screen); + frag_color.a = sampleSpotShadow(pos.xyz, norm, 1, pos_screen); +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class3/deferred/sunLightSSAOF.glsl new file mode 100644 index 0000000000..342a2ff3ed --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/sunLightSSAOF.glsl @@ -0,0 +1,61 @@ +/** + * @file class3\deferred\sunLightSSAOF.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 + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +//class 2 -- shadows and SSAO + +// Inputs +VARYING vec2 vary_fragcoord; + +uniform vec3 sun_dir; + +vec4 getPosition(vec2 pos_screen); +vec3 getNorm(vec2 pos_screen); + +float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); +float sampleSpotShadow(vec3 pos, vec3 norm, int index, vec2 pos_screen); + +//calculate decreases in ambient lighting when crowded out (SSAO) +float calcAmbientOcclusion(vec4 pos, vec3 norm, vec2 pos_screen); + +void main() +{ + vec2 pos_screen = vary_fragcoord.xy; + vec4 pos = getPosition(pos_screen); + vec3 norm = getNorm(pos_screen); + + frag_color.r = sampleDirectionalShadow(pos.xyz, norm, pos_screen); + frag_color.b = calcAmbientOcclusion(pos, norm, pos_screen); + frag_color.b = sampleSpotShadow(pos.xyz, norm, 0, pos_screen); + frag_color.a = sampleSpotShadow(pos.xyz, norm, 1, pos_screen); +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/sunLightV.glsl b/indra/newview/app_settings/shaders/class3/deferred/sunLightV.glsl new file mode 100644 index 0000000000..bc5eb5181d --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/sunLightV.glsl @@ -0,0 +1,41 @@ +/** + * @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/class3/deferred/treeShadowF.glsl b/indra/newview/app_settings/shaders/class3/deferred/treeShadowF.glsl new file mode 100644 index 0000000000..41673d1669 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/treeShadowF.glsl @@ -0,0 +1,59 @@ +/** + * @file treeShadowF.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$ + */ + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform float minimum_alpha; + +uniform sampler2D diffuseMap; + +VARYING vec4 pos; +VARYING vec2 vary_texcoord0; + +vec4 computeMoments(float d, float a); + +void main() +{ + float alpha = texture2D(diffuseMap, vary_texcoord0.xy).a; + + if (alpha < minimum_alpha) + { + discard; + } + + frag_color = computeMoments(length(pos), 1.0); + +#if !defined(DEPTH_CLAMP) + gl_FragDepth = max(pos.z/pos.w*0.5+0.5, 0.0); +#endif + +} + diff --git a/indra/newview/app_settings/shaders/class3/deferred/treeShadowV.glsl b/indra/newview/app_settings/shaders/class3/deferred/treeShadowV.glsl new file mode 100644 index 0000000000..15e769ac10 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/treeShadowV.glsl @@ -0,0 +1,43 @@ +/** + * @file treeShadowV.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; + +VARYING vec4 pos; +VARYING vec2 vary_texcoord0; + +void main() +{ + //transform vertex + pos = modelview_projection_matrix*vec4(position.xyz, 1.0); + + gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/underWaterF.glsl b/indra/newview/app_settings/shaders/class3/deferred/underWaterF.glsl new file mode 100644 index 0000000000..540226e672 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/underWaterF.glsl @@ -0,0 +1,115 @@ +/** + * @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$ + */ + +/*[EXTRA_CODE_HERE]*/ + +#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); + +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 color * D + kc * L; +} + +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/class3/deferred/waterF.glsl b/indra/newview/app_settings/shaders/class3/deferred/waterF.glsl new file mode 100644 index 0000000000..c65cf48c67 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/waterF.glsl @@ -0,0 +1,174 @@ +/** + * @file waterF.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 + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_data[3]; +#else +#define frag_data gl_FragData +#endif + +uniform sampler2D bumpMap; +uniform sampler2D bumpMap2; +uniform float blend_factor; +uniform sampler2D screenTex; +uniform sampler2D refTex; + +uniform float sunAngle; +uniform float sunAngle2; +uniform vec3 lightDir; +uniform vec3 specular; +uniform float lightExp; +uniform float refScale; +uniform float kd; +uniform vec2 screenRes; +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); +VARYING vec4 refCoord; +VARYING vec4 littleWave; +VARYING vec4 view; +VARYING vec4 vary_position; + +vec3 scaleSoftClip(vec3 c); +vec2 encode_normal(vec3 n); + +vec3 BlendNormal(vec3 bump1, vec3 bump2) +{ + //vec3 normal = bump1.xyz * vec3( 2.0, 2.0, 2.0) - vec3(1.0, 1.0, 0.0); + //vec3 normal2 = bump2.xyz * vec3(-2.0, -2.0, 2.0) + vec3(1.0, 1.0, -1.0); + //vec3 n = normalize(normal * dot(normal, normal2) - (normal2 * normal.z)); + vec3 n = normalize(mix(bump1, bump2, blend_factor)); + return n; +} + +void main() +{ + vec4 color; + float dist = length(view.xy); + + //normalize view vector + vec3 viewVec = normalize(view.xyz); + + //get wave normals + vec3 wave1_a = texture2D(bumpMap, vec2(refCoord.w, view.w)).xyz*2.0-1.0; + vec3 wave2_a = texture2D(bumpMap, littleWave.xy).xyz*2.0-1.0; + vec3 wave3_a = texture2D(bumpMap, littleWave.zw).xyz*2.0-1.0; + + + vec3 wave1_b = texture2D(bumpMap2, vec2(refCoord.w, view.w)).xyz*2.0-1.0; + vec3 wave2_b = texture2D(bumpMap2, littleWave.xy).xyz*2.0-1.0; + vec3 wave3_b = texture2D(bumpMap2, littleWave.zw).xyz*2.0-1.0; + + vec3 wave1 = BlendNormal(wave1_a, wave1_b); + vec3 wave2 = BlendNormal(wave2_a, wave2_b); + vec3 wave3 = BlendNormal(wave3_a, wave3_b); + + //get base fresnel components + + vec3 df = vec3( + dot(viewVec, wave1), + dot(viewVec, (wave2 + wave3) * 0.5), + dot(viewVec, wave3) + ) * fresnelScale + fresnelOffset; + df *= df; + + vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5; + + float dist2 = dist; + dist = max(dist, 5.0); + + float dmod = sqrt(dist); + + vec2 dmod_scale = vec2(dmod*dmod, dmod); + + //get reflected color + vec2 refdistort1 = wave1.xy*normScale.x; + vec2 refvec1 = distort+refdistort1/dmod_scale; + vec4 refcol1 = texture2D(refTex, refvec1); + + vec2 refdistort2 = wave2.xy*normScale.y; + vec2 refvec2 = distort+refdistort2/dmod_scale; + vec4 refcol2 = texture2D(refTex, refvec2); + + vec2 refdistort3 = wave3.xy*normScale.z; + vec2 refvec3 = distort+refdistort3/dmod_scale; + vec4 refcol3 = texture2D(refTex, refvec3); + + vec4 refcol = refcol1 + refcol2 + refcol3; + float df1 = df.x + df.y + df.z; + refcol *= df1 * 0.333; + + vec3 wavef = (wave1 + wave2 * 0.4 + wave3 * 0.6) * 0.5; + wavef.z *= max(-viewVec.z, 0.1); + wavef = normalize(wavef); + + float df2 = dot(viewVec, wavef) * fresnelScale+fresnelOffset; + + vec2 refdistort4 = wavef.xy*0.125; + refdistort4.y -= abs(refdistort4.y); + 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); + + //harden specular + spec = pow(spec, 128.0); + + //figure out distortion vector (ripply) + vec2 distort2 = distort+wavef.xy*refScale/max(dmod*df1, 1.0); + + vec4 fb = texture2D(screenTex, distort2); + + //mix with reflection + // 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); + + color.rgb *= 2.0f; + color.rgb = scaleSoftClip(color.rgb); + + vec4 pos = vary_position; + + color.rgb += spec * specular; + color.a = spec * sunAngle2; + + vec3 screenspacewavef = normalize((norm_mat*vec4(wavef, 1.0)).xyz); + + frag_data[0] = vec4(color.rgb, color); // diffuse + frag_data[1] = vec4(spec * specular, spec); // speccolor, spec + frag_data[2] = vec4(encode_normal(wavef.xyz), 0.05, 0);// normalxy, 0, 0 +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/waterV.glsl b/indra/newview/app_settings/shaders/class3/deferred/waterV.glsl new file mode 100644 index 0000000000..02000d90ca --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/waterV.glsl @@ -0,0 +1,95 @@ +/** + * @file waterV.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_matrix; +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; + + +uniform vec2 d1; +uniform vec2 d2; +uniform float time; +uniform vec3 eyeVec; +uniform float waterHeight; + +VARYING vec4 refCoord; +VARYING vec4 littleWave; +VARYING vec4 view; + +VARYING vec4 vary_position; + +float wave(vec2 v, float t, float f, vec2 d, float s) +{ + return (dot(d, v)*f + t*s)*f; +} + +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 = pos.xyz-eyeVec; + + float d = length(oEyeVec.xy); + float ld = min(d, 2560.0); + + 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(position, 1.0); + oPosition.z = mix(oPosition.z, max(eyeVec.z*0.75, 0.0), d); + vary_position = modelview_matrix * oPosition; + oPosition = modelViewProj * oPosition; + + refCoord.xyz = oPosition.xyz + vec3(0,0,0.2); + + //get wave position parameter (create sweeping horizontal waves) + 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. + pos.xyz = oEyeVec.xyz*(waterHeight/oEyeVec.z); + pos.w = 1.0; + pos = modelview_matrix*pos; + + //pass wave parameters to pixel shader + vec2 bigWave = (v.xy) * vec2(0.04,0.04) + d1 * time * 0.055; + //get two normal map (detail map) texture coordinates + littleWave.xy = (v.xy) * vec2(0.45, 0.9) + d2 * time * 0.13; + littleWave.zw = (v.xy) * vec2(0.1, 0.2) + d1 * time * 0.1; + view.w = bigWave.y; + refCoord.w = bigWave.x; + + gl_Position = oPosition; +} diff --git a/indra/mac_crash_logger/llcrashloggermac.h b/indra/newview/app_settings/shaders/class3/lighting/lightV.glsl index 05ef8c9f53..30ad493331 100644 --- a/indra/mac_crash_logger/llcrashloggermac.h +++ b/indra/newview/app_settings/shaders/class3/lighting/lightV.glsl @@ -1,10 +1,9 @@ /** - * @file llcrashloggermac.h - * @brief Mac OSX crash logger definition + * @file class3\lighting\lightV.glsl * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * 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 @@ -23,23 +22,22 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ + -#ifndef LLCRASHLOGGERMAC_H -#define LLCRASHLOGGERMAC_H -#include "linden_common.h" -#include "llcrashlogger.h" -#include "llstring.h" +// All lights, no specular highlights +vec3 atmosAmbient(); +vec4 sumLights(vec3 pos, vec3 norm, vec4 color); +float getAmbientClamp(); -class LLCrashLoggerMac : public LLCrashLogger +vec4 calcLighting(vec3 pos, vec3 norm, vec4 color) { -public: - LLCrashLoggerMac(void); - ~LLCrashLoggerMac(void); - virtual bool init(); - virtual bool frame(); - virtual bool cleanup(); - virtual void gatherPlatformSpecificFiles(); -}; + vec4 c = sumLights(pos, norm, color); +#if !defined(AMBIENT_KILL) + c.rgb += atmosAmbient() * color.rgb * getAmbientClamp(); #endif + + return c; +} + diff --git a/indra/newview/app_settings/shaders/class3/lighting/sumLightsSpecularV.glsl b/indra/newview/app_settings/shaders/class3/lighting/sumLightsSpecularV.glsl index e043ac873e..c1aee69c30 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 class3\lighting\sumLightsSpecularV.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -26,16 +26,16 @@ 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 atmosAmbient(); vec3 atmosAffectDirectionalLight(float lightIntensity); vec3 atmosGetDiffuseSunlightColor(); vec3 scaleDownLight(vec3 light); uniform vec4 light_position[8]; -uniform vec3 light_attenuation[8]; +uniform vec4 light_attenuation[8]; uniform vec3 light_diffuse[8]; -vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol) +vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor) { vec4 col = vec4(0.0, 0.0, 0.0, color.a); @@ -55,8 +55,8 @@ vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor 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 += atmosAmbient(); + col.rgb += atmosAffectDirectionalLight(calcDirectionalLightSpecular(specularSum, view, norm, light_position[0].xyz,atmosGetDiffuseSunlightColor(), 1.0)); col.rgb = min(col.rgb*color.rgb, 1.0); specularColor.rgb = min(specularColor.rgb*specularSum.rgb, 1.0); diff --git a/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl index dadff40933..4b663dd5b2 100644 --- a/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl +++ b/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl @@ -1,5 +1,5 @@ /** - * @file sumLightsV.glsl + * @file class3\lighting\sumLightsV.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -25,37 +25,40 @@ float calcDirectionalLight(vec3 n, vec3 l); -float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight); +float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight); -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 vec4 light_attenuation[8]; uniform vec3 light_diffuse[8]; -vec4 sumLights(vec3 pos, vec3 norm, vec4 color, vec4 baseLight) +vec4 sumLights(vec3 pos, vec3 norm, vec4 color) { 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[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[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); col.rgb += light_diffuse[1].rgb*calcDirectionalLight(norm, light_position[1].xyz); - col.rgb = scaleDownLight(col.rgb); + col.rgb = scaleDownLight(col.rgb); + +#if defined(LOCAL_LIGHT_KILL) + col.rgb = vec3(0); +#endif // Add windlight lights +#if !defined(SUNLIGHT_KILL) col.rgb += atmosAffectDirectionalLight(calcDirectionalLight(norm, light_position[0].xyz)); - col.rgb += atmosAmbient(baseLight.rgb); +#endif col.rgb = min(col.rgb*color.rgb, 1.0); diff --git a/indra/newview/app_settings/shaders/class3/windlight/advancedAtmoF.glsl b/indra/newview/app_settings/shaders/class3/windlight/advancedAtmoF.glsl new file mode 100644 index 0000000000..c6ea3ec9d4 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/windlight/advancedAtmoF.glsl @@ -0,0 +1,73 @@ +/** + * @file class3\wl\advancedAtmoF.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$ + */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +in vec3 view_dir; + +uniform vec3 cameraPosLocal; +uniform vec3 sun_dir; +uniform float sun_size; + +uniform sampler2D transmittance_texture; +uniform sampler3D scattering_texture; +uniform sampler3D mie_scattering_texture; +uniform sampler2D irradiance_texture; + +vec3 GetSolarLuminance(); +vec3 GetSkyLuminance(vec3 camPos, vec3 view_dir, float shadow_length, vec3 sun_dir, out vec3 transmittance); +vec3 GetSkyLuminanceToPoint(vec3 camPos, vec3 pos, float shadow_length, vec3 sun_dir, out vec3 transmittance); +vec3 GetSunAndSkyIlluminance(vec3 pos, vec3 norm, vec3 sun_dir, out vec3 sky_irradiance); + +void main() +{ + vec3 view_direction = normalize(view_dir); + + vec3 camPos = cameraPosLocal; + vec3 transmittance; + vec3 sky_illum; + vec3 radiance = GetSkyLuminance(camPos, view_direction, 0.0f, sun_dir, transmittance); + vec3 radiance2 = GetSunAndSkyIlluminance(camPos, view_direction, sun_dir, sky_illum); + + //radiance *= transmittance; + + // If the view ray intersects the Sun, add the Sun radiance. + if (dot(view_direction, sun_dir) >= sun_size) + { + radiance = radiance + transmittance * GetSolarLuminance(); + } + + //vec3 color = vec3(1.0) - exp(-radiance); + //color = pow(color, vec3(1.0 / 2.2)); + + frag_color.rgb = radiance; + + frag_color.a = 1.0; +} + diff --git a/indra/newview/app_settings/shaders/class3/windlight/advancedAtmoV.glsl b/indra/newview/app_settings/shaders/class3/windlight/advancedAtmoV.glsl new file mode 100644 index 0000000000..65bb00b1f6 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/windlight/advancedAtmoV.glsl @@ -0,0 +1,43 @@ +/** + * @file class3\wl\advancedAtmoV.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$ + */ + +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; + +// Inputs +uniform vec3 camPosLocal; + +out vec3 view_dir; + +void main() +{ + // World / view / projection + gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); + + // this will be normalized in the frag shader... + view_dir = position.xyz - camPosLocal.xyz; +} + diff --git a/indra/newview/app_settings/shaders/class3/windlight/atmosphericsF.glsl b/indra/newview/app_settings/shaders/class3/windlight/atmosphericsF.glsl new file mode 100644 index 0000000000..2b70ba76dc --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/windlight/atmosphericsF.glsl @@ -0,0 +1,46 @@ +/** + * @file class3\wl\atmosphericsF.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 getAdditiveColor(); +vec3 getAtmosAttenuation(); +vec3 scaleSoftClipFrag(vec3 light); + +uniform int no_atmo; + +vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten) +{ + if (no_atmo == 1) + { + return light; + } + light *= atten.r; + light += additive; + return light * 2.0; +} + +vec3 atmosLighting(vec3 light) +{ + return atmosFragLighting(light, getAdditiveColor(), getAtmosAttenuation()); +} diff --git a/indra/newview/app_settings/shaders/class3/windlight/atmosphericsV.glsl b/indra/newview/app_settings/shaders/class3/windlight/atmosphericsV.glsl new file mode 100644 index 0000000000..b76192d73f --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/windlight/atmosphericsV.glsl @@ -0,0 +1,51 @@ +/** + * @file class3\wl\atmosphericsV.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$ + */ + +// VARYING param funcs +void setSunlitColor(vec3 v); +void setAmblitColor(vec3 v); +void setAdditiveColor(vec3 v); +void setAtmosAttenuation(vec3 v); +void setPositionEye(vec3 v); + +vec3 getAdditiveColor(); + +void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten, bool use_ao); + +void calcAtmospherics(vec3 inPositionEye) { + + vec3 P = inPositionEye; + setPositionEye(P); + vec3 tmpsunlit = vec3(1); + vec3 tmpamblit = vec3(1); + vec3 tmpaddlit = vec3(1); + vec3 tmpattenlit = vec3(1); + calcAtmosphericVars(inPositionEye, vec3(0), 1, tmpsunlit, tmpamblit, tmpaddlit, tmpattenlit, true); + setSunlitColor(tmpsunlit); + setAmblitColor(tmpamblit); + setAdditiveColor(tmpaddlit); + setAtmosAttenuation(tmpattenlit); +} + diff --git a/indra/newview/app_settings/shaders/class3/windlight/transportF.glsl b/indra/newview/app_settings/shaders/class3/windlight/transportF.glsl new file mode 100644 index 0000000000..545a32a227 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/windlight/transportF.glsl @@ -0,0 +1,68 @@ +/** + * @file class3\wl\transportF.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$ + */ + +////////////////////////////////////////////////////////// +// The fragment shader for the terrain atmospherics +////////////////////////////////////////////////////////// + +vec3 getAdditiveColor(); +vec3 getAtmosAttenuation(); + +uniform int no_atmo; + +vec3 atmosTransportFrag(vec3 light, vec3 additive, vec3 atten) +{ + if (no_atmo == 1) + { + return light; + } + // fullbright responds minimally to atmos scatter effects + light *= min(15.0 * atten.r, 1.0); + light += (0.1 * additive); + return light * 2.0; +} + +vec3 atmosTransport(vec3 light) +{ + return atmosTransportFrag(light, getAdditiveColor(), getAtmosAttenuation()); +} + +vec3 fullbrightAtmosTransportFrag(vec3 light, vec3 additive, vec3 atten) +{ + float brightness = dot(light.rgb, vec3(0.33333)); + return vec3(1,0,1); + //return atmosTransportFrag(light * 0.5, additive * (brightness * 0.5 + 0.5), atten); +} + +vec3 fullbrightAtmosTransport(vec3 light) +{ + return atmosTransportFrag(light, getAdditiveColor(), getAtmosAttenuation()); +} + +vec3 fullbrightShinyAtmosTransport(vec3 light) +{ + float brightness = dot(light.rgb, vec3(0.33333)); + return atmosTransportFrag(light * 0.5, getAdditiveColor() * (brightness * brightness), getAtmosAttenuation()); +} diff --git a/indra/newview/app_settings/shaders/shader_hierarchy.txt b/indra/newview/app_settings/shaders/shader_hierarchy.txt index d8bbf69b38..8ef04d8e1f 100644 --- a/indra/newview/app_settings/shaders/shader_hierarchy.txt +++ b/indra/newview/app_settings/shaders/shader_hierarchy.txt @@ -1,3 +1,9 @@ +Class 3 is highest quality / lowest performance +Class 2 is medium quality / medium performance +Class 1 is lowest quality / highest performance + +Shaders WILL fall back to "lower" classes for functionality. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ avatar/avatarV.glsl - gAvatarProgram, gAvatarWaterProgram main() - avatar/avatarV.glsl @@ -7,7 +13,6 @@ avatar/avatarV.glsl - gAvatarProgram, gAvatarWaterProgram sumLights() - lighting/sumLightsV.glsl calcDirectionalLight() - lighting/lightFuncV.glsl calcPointLight() - lighting/lightFuncV.glsl - scaleDownLight() - windlight/atmosphericsHelpersV.glsl atmosAmbient() - windlight/atmosphericsHelpersV.glsl atmosAffectDirectionalLight() - windlight/atmosphericsHelpersV.glsl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -28,7 +33,6 @@ avatar/eyeballV.glsl - gAvatarEyeballProgram atmosAmbient() - windlight/atmosphericsHelpersV.glsl atmosAffectDirectionalLight() - windlight/atmosphericsHelpersV.glsl atmosGetDiffuseSunlightColor() - windlight/atmosphericsHelpersV.glsl - scaleDownLight() - windlight/atmosphericsHelpersV.glsl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ avatar/eyeballF.glsl - gAvatarEyeballProgram main() - avatar/eyeballF.glsl @@ -53,7 +57,6 @@ environment/terrainV.glsl - gTerrainProgram, gTerrainWaterProgram sumLights() - lighting/sumLightsV.glsl calcDirectionalLight() - lighting/lightFuncV.glsl calcPointLight() - lighting/lightFuncV.glsl - scaleDownLight() - windlight/atmosphericsHelpersV.glsl atmosAmbient() - windlight/atmosphericsHelpersV.glsl atmosAffectDirectionalLight() - windlight/atmosphericsHelpersV.glsl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -120,7 +123,6 @@ objects/shinyV.glsl - gObjectShinyProgram, gObjectShinyWaterProgram sumLights() - lighting/sumLightsV.glsl calcDirectionalLight() - lighting/lightFuncV.glsl calcPointLight() - lighting/lightFuncV.glsl - scaleDownLight() - windlight/atmosphericsHelpersV.glsl atmosAmbient() - windlight/atmosphericsHelpersV.glsl atmosAffectDirectionalLight() - windlight/atmosphericsHelpersV.glsl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -143,7 +145,6 @@ objects/simpleV.glsl - gObjectSimpleProgram, gObjectSimpleWaterProgram sumLights() - lighting/sumLightsV.glsl calcDirectionalLight() - lighting/lightFuncV.glsl calcPointLight() - lighting/lightFuncV.glsl - scaleDownLight() - windlight/atmosphericsHelpersV.glsl atmosAmbient() - windlight/atmosphericsHelpersV.glsl atmosAffectDirectionalLight() - windlight/atmosphericsHelpersV.glsl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/indra/newview/app_settings/ultra_graphics.xml b/indra/newview/app_settings/ultra_graphics.xml index 3e7fccbd5f..eb2cd356d9 100644 --- a/indra/newview/app_settings/ultra_graphics.xml +++ b/indra/newview/app_settings/ultra_graphics.xml @@ -34,8 +34,6 @@ <!--Default for now--> <RenderVolumeLODFactor value="2.0"/> <!--NO SHADERS--> - <VertexShaderEnable value="TRUE"/> - <!--NO SHADERS--> <WindLightUseAtmosShaders value="TRUE"/> <!--Deferred Shading--> <RenderDeferred value="TRUE"/> diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index e99b94f150..f1bf8d76c2 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -56,7 +56,6 @@ RenderVBOMappingDisable 1 1 RenderVolumeLODFactor 1 2.0 UseStartScreen 1 1 UseOcclusion 1 1 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 Disregard128DefaultDrawDistance 1 1 @@ -66,6 +65,7 @@ RenderCompressTextures 1 1 RenderShaderLightingMaxLevel 1 3 RenderDeferred 1 1 RenderDeferredSSAO 1 1 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 2 RenderUseStreamVBO 1 1 RenderFSAASamples 1 16 @@ -94,10 +94,10 @@ RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 0 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 0 @@ -125,10 +125,10 @@ RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 0 @@ -155,10 +155,10 @@ RenderTerrainLODFactor 1 1.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 0 @@ -185,10 +185,10 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 0 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 2 @@ -215,10 +215,10 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 2 @@ -245,10 +245,10 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderDeferredSSAO 1 1 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 2 @@ -275,10 +275,10 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderDeferredSSAO 1 1 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 2 WLSkyDetail 1 48 RenderFSAASamples 1 2 @@ -304,11 +304,11 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderVolumeLODFactor 1 2.0 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 RenderDeferred 1 1 RenderDeferredSSAO 1 1 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 2 RenderFSAASamples 1 2 @@ -320,6 +320,7 @@ RenderVBOEnable 1 0 RenderShadowDetail 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 // // Class 0 Hardware (just old) @@ -370,11 +371,11 @@ list NoPixelShaders RenderAvatarVP 0 0 RenderAvatarCloth 0 0 RenderReflectionDetail 0 0 -VertexShaderEnable 0 0 WindLightUseAtmosShaders 0 0 RenderDeferred 0 0 RenderDeferredSSAO 0 0 RenderShadowDetail 0 0 +RenderUseAdvancedAtmospherics 0 0 // // No Vertex Shaders available @@ -383,11 +384,11 @@ list NoVertexShaders RenderAvatarVP 0 0 RenderAvatarCloth 0 0 RenderReflectionDetail 0 0 -VertexShaderEnable 0 0 WindLightUseAtmosShaders 0 0 RenderDeferred 0 0 RenderDeferredSSAO 0 0 RenderShadowDetail 0 0 +RenderUseAdvancedAtmospherics 0 0 // // GL_ARB_map_buffer_range exists diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt index 801a622e93..5542eee6ca 100644 --- a/indra/newview/featuretable_linux.txt +++ b/indra/newview/featuretable_linux.txt @@ -56,7 +56,6 @@ RenderVBOMappingDisable 1 1 RenderVolumeLODFactor 1 2.0 UseStartScreen 1 1 UseOcclusion 1 1 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 Disregard128DefaultDrawDistance 1 1 @@ -66,6 +65,7 @@ RenderCompressTextures 1 1 RenderShaderLightingMaxLevel 1 3 RenderDeferred 1 1 RenderDeferredSSAO 1 1 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 2 RenderFSAASamples 1 16 RenderMaxTextureIndex 1 16 @@ -93,10 +93,10 @@ RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 0 @@ -124,10 +124,10 @@ RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 0 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 0 @@ -154,10 +154,10 @@ RenderTerrainLODFactor 1 1.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 0 @@ -184,10 +184,10 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 0 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 2 @@ -214,9 +214,9 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 +RenderUseAdvancedAtmospherics 1 0 RenderDeferredSSAO 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 @@ -244,10 +244,10 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderDeferredSSAO 1 1 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 2 @@ -274,10 +274,10 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderDeferredSSAO 1 1 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 2 WLSkyDetail 1 48 RenderFSAASamples 1 2 @@ -303,11 +303,11 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderVolumeLODFactor 1 2.0 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 RenderDeferred 1 1 RenderDeferredSSAO 1 1 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 2 RenderFSAASamples 1 2 @@ -319,6 +319,7 @@ RenderVBOEnable 1 0 RenderShadowDetail 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 // // Class 0 Hardware (just old) @@ -369,10 +370,10 @@ list NoPixelShaders RenderAvatarVP 0 0 RenderAvatarCloth 0 0 RenderReflectionDetail 0 0 -VertexShaderEnable 0 0 WindLightUseAtmosShaders 0 0 RenderDeferred 0 0 RenderDeferredSSAO 0 0 +RenderUseAdvancedAtmospherics 0 0 RenderShadowDetail 0 0 // @@ -382,10 +383,10 @@ list NoVertexShaders RenderAvatarVP 0 0 RenderAvatarCloth 0 0 RenderReflectionDetail 0 0 -VertexShaderEnable 0 0 WindLightUseAtmosShaders 0 0 RenderDeferred 0 0 RenderDeferredSSAO 0 0 +RenderUseAdvancedAtmospherics 0 0 RenderShadowDetail 0 0 // @@ -413,6 +414,7 @@ RenderReflectionDetail 0 0 WindLightUseAtmosShaders 0 0 RenderDeferred 0 0 RenderDeferredSSAO 0 0 +RenderUseAdvancedAtmospherics 0 0 RenderShadowDetail 0 0 // diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt index 1f891ee4d7..bac6fd5708 100644 --- a/indra/newview/featuretable_mac.txt +++ b/indra/newview/featuretable_mac.txt @@ -56,7 +56,6 @@ RenderVBOMappingDisable 1 1 RenderVolumeLODFactor 1 2.0 UseStartScreen 1 1 UseOcclusion 1 1 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 Disregard128DefaultDrawDistance 1 1 @@ -66,6 +65,7 @@ RenderCompressTextures 1 1 RenderShaderLightingMaxLevel 1 3 RenderDeferred 1 1 RenderDeferredSSAO 1 1 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 2 RenderUseStreamVBO 1 1 RenderFSAASamples 1 16 @@ -94,10 +94,10 @@ RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 0.5 -VertexShaderEnable 1 0 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 0 @@ -125,10 +125,10 @@ RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 0.5 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 0 @@ -155,10 +155,10 @@ RenderTerrainLODFactor 1 1.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 0 @@ -185,10 +185,10 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 0 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 2 @@ -215,10 +215,10 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 2 @@ -245,10 +245,10 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderDeferredSSAO 1 1 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 2 @@ -275,11 +275,11 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderDeferredSSAO 1 1 RenderShadowDetail 1 2 +RenderUseAdvancedAtmospherics 1 0 WLSkyDetail 1 48 RenderFSAASamples 1 2 @@ -304,11 +304,11 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderVolumeLODFactor 1 2.0 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 RenderDeferred 1 1 RenderDeferredSSAO 1 1 +RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 2 RenderFSAASamples 1 2 @@ -320,6 +320,7 @@ RenderVBOEnable 1 0 RenderShadowDetail 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 +RenderUseAdvancedAtmospherics 1 0 // // Class 0 Hardware (just old) @@ -364,10 +365,10 @@ list NoPixelShaders RenderAvatarVP 0 0 RenderAvatarCloth 0 0 RenderReflectionDetail 0 0 -VertexShaderEnable 0 0 WindLightUseAtmosShaders 0 0 RenderDeferred 0 0 RenderDeferredSSAO 0 0 +RenderUseAdvancedAtmospherics 0 0 RenderShadowDetail 0 0 // @@ -377,10 +378,10 @@ list NoVertexShaders RenderAvatarVP 0 0 RenderAvatarCloth 0 0 RenderReflectionDetail 0 0 -VertexShaderEnable 0 0 WindLightUseAtmosShaders 0 0 RenderDeferred 0 0 RenderDeferredSSAO 0 0 +RenderUseAdvancedAtmospherics 0 0 RenderShadowDetail 0 0 // @@ -407,6 +408,7 @@ RenderReflectionDetail 0 0 WindLightUseAtmosShaders 0 0 RenderDeferred 0 0 RenderDeferredSSAO 0 0 +RenderUseAdvancedAtmospherics 0 0 RenderShadowDetail 0 0 // diff --git a/indra/newview/generate_breakpad_symbols.py b/indra/newview/generate_breakpad_symbols.py deleted file mode 100755 index d351c406bc..0000000000 --- a/indra/newview/generate_breakpad_symbols.py +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/env python -"""\ -@file generate_breakpad_symbols.py -@author Brad Kittenbrink <brad@lindenlab.com> -@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/icons/release/secondlife.icns b/indra/newview/icons/release/secondlife.icns Binary files differindex e15e34140d..a30b51b67a 100644 --- a/indra/newview/icons/release/secondlife.icns +++ b/indra/newview/icons/release/secondlife.icns diff --git a/indra/newview/icons/release/secondlife.ico b/indra/newview/icons/release/secondlife.ico Binary files differindex 28bf1e7664..93d4fa54ba 100644 --- a/indra/newview/icons/release/secondlife.ico +++ b/indra/newview/icons/release/secondlife.ico diff --git a/indra/newview/icons/release/secondlife_128.png b/indra/newview/icons/release/secondlife_128.png Binary files differindex 4c9544f498..2f21c1c7fc 100644 --- a/indra/newview/icons/release/secondlife_128.png +++ b/indra/newview/icons/release/secondlife_128.png diff --git a/indra/newview/icons/release/secondlife_16.png b/indra/newview/icons/release/secondlife_16.png Binary files differindex bb3168b8be..68f1427309 100644 --- a/indra/newview/icons/release/secondlife_16.png +++ b/indra/newview/icons/release/secondlife_16.png diff --git a/indra/newview/icons/release/secondlife_256.BMP b/indra/newview/icons/release/secondlife_256.BMP Binary files differindex 74deedd7d3..dba2636803 100644 --- a/indra/newview/icons/release/secondlife_256.BMP +++ b/indra/newview/icons/release/secondlife_256.BMP diff --git a/indra/newview/icons/release/secondlife_256.png b/indra/newview/icons/release/secondlife_256.png Binary files differindex bece338a90..8f324910e7 100644 --- a/indra/newview/icons/release/secondlife_256.png +++ b/indra/newview/icons/release/secondlife_256.png diff --git a/indra/newview/icons/release/secondlife_32.png b/indra/newview/icons/release/secondlife_32.png Binary files differindex 736359c147..2b7cdef03d 100644 --- a/indra/newview/icons/release/secondlife_32.png +++ b/indra/newview/icons/release/secondlife_32.png diff --git a/indra/newview/icons/release/secondlife_48.png b/indra/newview/icons/release/secondlife_48.png Binary files differindex 07d39ae585..c2ef372dd7 100644 --- a/indra/newview/icons/release/secondlife_48.png +++ b/indra/newview/icons/release/secondlife_48.png diff --git a/indra/newview/icons/release/secondlife_512.png b/indra/newview/icons/release/secondlife_512.png Binary files differindex 53d1643f45..d8a0c2924d 100644 --- a/indra/newview/icons/release/secondlife_512.png +++ b/indra/newview/icons/release/secondlife_512.png diff --git a/indra/newview/installers/darwin/apple-notarize.sh b/indra/newview/installers/darwin/apple-notarize.sh new file mode 100755 index 0000000000..466898ecda --- /dev/null +++ b/indra/newview/installers/darwin/apple-notarize.sh @@ -0,0 +1,54 @@ +#!/bin/sh +if [[ $SKIP_NOTARIZATION == "true" ]]; then + echo "Skipping notarization" + exit 0 +fi + +CONFIG_FILE="$build_secrets_checkout/code-signing-osx/notarize_creds.sh" +if [ -f "$CONFIG_FILE" ]; then + source $CONFIG_FILE + app_file="$1" + zip_file=${app_file/app/zip} + ditto -c -k --keepParent "$app_file" "$zip_file" + if [ -f "$zip_file" ]; then + res=$(xcrun altool --notarize-app --primary-bundle-id "com.secondlife.viewer" \ + --username $USERNAME \ + --password $PASSWORD \ + --asc-provider $ASC_PROVIDER \ + --file "$zip_file" 2>&1) + requestUUID=$(echo $res | awk '/RequestUUID/ { print $NF; }') + + echo "Apple Notarization RequestUUID: $requestUUID" + + if [[ -n $requestUUID ]]; then + status="in progress" + while [[ "$status" == "in progress" ]]; do + sleep 30 + status=$(xcrun altool --notarization-info "$requestUUID" \ + --username $USERNAME \ + --password $PASSWORD 2>&1 \ + | awk -F ': ' '/Status:/ { print $2; }' ) + echo "$status" + done + # log results + xcrun altool --notarization-info "$requestUUID" \ + --username $USERNAME \ + --password $PASSWORD + + #remove temporary file + rm "$zip_file" + + if [["$status" == "success"]]; then + xcrun stapler staple "$app_file" + elif [["$status" == "invalid"]]; then + echo "Notarization error: failed to process the app file" + exit 1 + fi + else + echo "Notarization error: couldn't get request UUID" + echo $res + exit 1 + fi + fi +fi + diff --git a/indra/newview/installers/windows/install_icon.BMP b/indra/newview/installers/windows/install_icon.BMP Binary files differindex 09df573870..dba2636803 100644 --- a/indra/newview/installers/windows/install_icon.BMP +++ b/indra/newview/installers/windows/install_icon.BMP diff --git a/indra/newview/installers/windows/install_icon.ico b/indra/newview/installers/windows/install_icon.ico Binary files differindex efe6c4f323..93d4fa54ba 100644 --- a/indra/newview/installers/windows/install_icon.ico +++ b/indra/newview/installers/windows/install_icon.ico diff --git a/indra/newview/installers/windows/uninstall_icon.BMP b/indra/newview/installers/windows/uninstall_icon.BMP Binary files differindex 562b56676a..dba2636803 100644 --- a/indra/newview/installers/windows/uninstall_icon.BMP +++ b/indra/newview/installers/windows/uninstall_icon.BMP diff --git a/indra/newview/installers/windows/uninstall_icon.ico b/indra/newview/installers/windows/uninstall_icon.ico Binary files differindex 05e1546860..93d4fa54ba 100644 --- a/indra/newview/installers/windows/uninstall_icon.ico +++ b/indra/newview/installers/windows/uninstall_icon.ico diff --git a/indra/newview/linux_tools/client-readme.txt b/indra/newview/linux_tools/client-readme.txt index e01b9e4bc6..cb8d1af535 100644 --- a/indra/newview/linux_tools/client-readme.txt +++ b/indra/newview/linux_tools/client-readme.txt @@ -187,8 +187,8 @@ The 'secondlife' script which launches Second Life contains some configuration options for advanced troubleshooters. * AUDIO - Edit the 'secondlife' script and you will see these audio - options: LL_BAD_OPENAL_DRIVER, LL_BAD_FMOD_ESD, LL_BAD_FMOD_OSS, and - LL_BAD_FMOD_ALSA. Second Life tries to use OpenAL, ESD, OSS, then ALSA + options: LL_BAD_OPENAL_DRIVER, LL_BAD_FMODSTUDIO_DRIVER. + Second Life tries to use OpenAL, FMODSTUDIO (PULSEAUDIO, ALSA) audio drivers in this order; you may uncomment the corresponding LL_BAD_* option to skip an audio driver which you believe may be causing you trouble. diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index c23401d5a6..eb3ead433b 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -4,17 +4,15 @@ ## 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 FMOD STUDIO audio driver. +#export LL_BAD_FMODSTUDIO_DRIVER=x ## - Avoids using any OpenAL audio driver. #export LL_BAD_OPENAL_DRIVER=x -## - Avoids using the FMOD Ex PulseAudio audio driver. +## - Avoids using the FMOD Studio or FMOD Ex PulseAudio audio driver. #export LL_BAD_FMOD_PULSEAUDIO=x -## - Avoids using the FMOD or FMOD Ex ALSA audio driver. +## - Avoids using the FMOD Studio 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 the optional OpenGL extensions which have proven most problematic ## on some hardware. Disabling this option may cause BETTER PERFORMANCE but diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index 1dddf52961..e09527a34b 100644 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -48,7 +48,7 @@ LLAccountingCostManager::LLAccountingCostManager() void LLAccountingCostManager::accountingCostCoro(std::string url, eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle) { - LL_DEBUGS("LLAccountingCostManager") << "Entering coroutine " << LLCoros::instance().getName() + LL_DEBUGS("LLAccountingCostManager") << "Entering coroutine " << LLCoros::getName() << " with url '" << url << LL_ENDL; LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); @@ -158,7 +158,7 @@ void LLAccountingCostManager::accountingCostCoro(std::string url, } catch (...) { - LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::instance().getName() + LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::getName() << "('" << url << "')")); throw; } diff --git a/indra/newview/llaccountingcostmanager.h b/indra/newview/llaccountingcostmanager.h index 55e1d19f05..d133c6437b 100644 --- a/indra/newview/llaccountingcostmanager.h +++ b/indra/newview/llaccountingcostmanager.h @@ -30,12 +30,6 @@ #include "llhandle.h" #include "llaccountingcost.h" -#include "httpcommon.h" -#include "llcoros.h" -#include "lleventcoro.h" -#include "httprequest.h" -#include "httpheaders.h" -#include "httpoptions.h" //=============================================================================== // An interface class for panels which display the parcel accounting information. diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 31b8b90518..389448654a 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -32,6 +32,7 @@ #include "pipeline.h" #include "llagentaccess.h" +#include "llagentbenefits.h" #include "llagentcamera.h" #include "llagentlistener.h" #include "llagentwearables.h" @@ -43,7 +44,6 @@ #include "llchicletbar.h" #include "llconsole.h" #include "lldonotdisturbnotificationstorage.h" -#include "llenvmanager.h" #include "llfirstuse.h" #include "llfloatercamera.h" #include "llfloaterimcontainer.h" @@ -108,7 +108,8 @@ const U8 AGENT_STATE_EDITING = 0x10; // Autopilot constants const F32 AUTOPILOT_HEIGHT_ADJUST_DISTANCE = 8.f; // meters const F32 AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND = 1.f; // meters -const F32 AUTOPILOT_MAX_TIME_NO_PROGRESS = 1.5f; // seconds +const F32 AUTOPILOT_MAX_TIME_NO_PROGRESS_WALK = 1.5f; // seconds +const F32 AUTOPILOT_MAX_TIME_NO_PROGRESS_FLY = 2.5f; // seconds. Flying is less presize, needs a bit more time const F32 MAX_VELOCITY_AUTO_LAND_SQUARED = 4.f * 4.f; const F64 CHAT_AGE_FAST_RATE = 3.0; @@ -137,6 +138,10 @@ public: EStatus getStatus() const {return mStatus;}; void setStatus(EStatus pStatus) {mStatus = pStatus;}; + static std::map<S32, std::string> sTeleportStatusName; + static const std::string& statusName(EStatus status); + virtual void toOstream(std::ostream& os) const; + virtual bool canRestartTeleport(); virtual void startTeleport() = 0; @@ -148,12 +153,19 @@ private: EStatus mStatus; }; +std::map<S32, std::string> LLTeleportRequest::sTeleportStatusName = { { kPending, "kPending" }, + { kStarted, "kStarted" }, + { kFailed, "kFailed" }, + { kRestartPending, "kRestartPending"} }; + class LLTeleportRequestViaLandmark : public LLTeleportRequest { public: LLTeleportRequestViaLandmark(const LLUUID &pLandmarkId); virtual ~LLTeleportRequestViaLandmark(); + virtual void toOstream(std::ostream& os) const; + virtual bool canRestartTeleport(); virtual void startTeleport(); @@ -172,6 +184,8 @@ public: LLTeleportRequestViaLure(const LLUUID &pLureId, BOOL pIsLureGodLike); virtual ~LLTeleportRequestViaLure(); + virtual void toOstream(std::ostream& os) const; + virtual bool canRestartTeleport(); virtual void startTeleport(); @@ -189,6 +203,8 @@ public: LLTeleportRequestViaLocation(const LLVector3d &pPosGlobal); virtual ~LLTeleportRequestViaLocation(); + virtual void toOstream(std::ostream& os) const; + virtual bool canRestartTeleport(); virtual void startTeleport(); @@ -208,6 +224,8 @@ public: LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal); virtual ~LLTeleportRequestViaLocationLookAt(); + virtual void toOstream(std::ostream& os) const; + virtual bool canRestartTeleport(); virtual void startTeleport(); @@ -370,6 +388,7 @@ LLAgent::LLAgent() : mTeleportFinishedSlot(), mTeleportFailedSlot(), mIsMaturityRatingChangingDuringTeleport(false), + mTPNeedsNeabyChatSeparator(false), mMaturityRatingChange(0U), mIsDoSendMaturityPreferenceToServer(false), mMaturityPreferenceRequestId(0U), @@ -383,6 +402,7 @@ LLAgent::LLAgent() : mAgentOriginGlobal(), mPositionGlobal(), + mLastTestGlobal(), mDistanceTraveled(0.F), mLastPositionGlobal(LLVector3d::zero), @@ -491,6 +511,8 @@ void LLAgent::init() void LLAgent::cleanup() { mRegionp = NULL; + mTeleportRequest = NULL; + mTeleportCanceled = NULL; if (mTeleportFinishedSlot.connected()) { mTeleportFinishedSlot.disconnect(); @@ -774,7 +796,7 @@ void LLAgent::setFlying(BOOL fly, BOOL fail_sound) // and it's OK if you're already flying if (fail_sound) { - make_ui_sound("UISndBadKeystroke"); + make_ui_sound("UISndBadKeystroke"); } return; } @@ -829,6 +851,17 @@ bool LLAgent::enableFlying() return !sitting; } +// static +bool LLAgent::isSitting() +{ + BOOL sitting = FALSE; + if (isAgentAvatarValid()) + { + sitting = gAgentAvatarp->isSitting(); + } + return sitting; +} + void LLAgent::standUp() { setControlFlags(AGENT_CONTROL_STAND_UP); @@ -846,6 +879,17 @@ boost::signals2::connection LLAgent::addParcelChangedCallback(parcel_changed_cal return mParcelChangedSignal.connect(cb); } +// static +void LLAgent::capabilityReceivedCallback(const LLUUID ®ion_id, LLViewerRegion *regionp) +{ + if (regionp && regionp->getRegionID() == region_id) + { + regionp->requestSimulatorFeatures(); + LLAppViewer::instance()->updateNameLookupUrl(regionp); + } +} + + //----------------------------------------------------------------------------- // setRegion() //----------------------------------------------------------------------------- @@ -855,9 +899,12 @@ void LLAgent::setRegion(LLViewerRegion *regionp) if (mRegionp != regionp) { - std::string ip = regionp->getHost().getString(); - LL_INFOS("AgentLocation") << "Moving agent into region: " << regionp->getName() - << " located at " << ip << LL_ENDL; + LL_INFOS("AgentLocation","Teleport") << "Moving agent into region: handle " << regionp->getHandle() + << " id " << regionp->getRegionID() + << " name " << regionp->getName() + << " previous region " + << (mRegionp ? mRegionp->getRegionID() : LLUUID::null) + << LL_ENDL; if (mRegionp) { // We've changed regions, we're now going to change our agent coordinate frame. @@ -889,10 +936,11 @@ void LLAgent::setRegion(LLViewerRegion *regionp) if (regionp->capabilitiesReceived()) { regionp->requestSimulatorFeatures(); + LLAppViewer::instance()->updateNameLookupUrl(regionp); } else { - regionp->setCapabilitiesReceivedCallback(boost::bind(&LLViewerRegion::requestSimulatorFeatures, regionp)); + regionp->setCapabilitiesReceivedCallback(LLAgent::capabilityReceivedCallback); } } @@ -911,6 +959,15 @@ void LLAgent::setRegion(LLViewerRegion *regionp) // Update all of the regions. LLWorld::getInstance()->updateAgentOffset(mAgentOriginGlobal); + + if (regionp->capabilitiesReceived()) + { + LLAppViewer::instance()->updateNameLookupUrl(regionp); + } + else + { + regionp->setCapabilitiesReceivedCallback([](const LLUUID ®ion_id, LLViewerRegion* regionp) {LLAppViewer::instance()->updateNameLookupUrl(regionp); }); + } } // Pass new region along to metrics components that care about this level of detail. @@ -1085,6 +1142,13 @@ void LLAgent::setPositionAgent(const LLVector3 &pos_agent) pos_agent_d.setVec(pos_agent); mPositionGlobal = pos_agent_d + mAgentOriginGlobal; } + + if (((mLastTestGlobal - mPositionGlobal).lengthSquared() > 1.0) && !mOnPositionChanged.empty()) + { // If the position has changed my more than 1 meter since the last time we triggered. + // filters out some noise. + mLastTestGlobal = mPositionGlobal; + mOnPositionChanged(mFrameAgent.getOrigin(), mPositionGlobal); + } } //----------------------------------------------------------------------------- @@ -1125,6 +1189,12 @@ const LLVector3 &LLAgent::getPositionAgent() return mFrameAgent.getOrigin(); } +boost::signals2::connection LLAgent::whenPositionChanged(position_signal_t::slot_type fn) +{ + return mOnPositionChanged.connect(fn); +} + + //----------------------------------------------------------------------------- // getRegionsVisited() //----------------------------------------------------------------------------- @@ -1493,6 +1563,12 @@ void LLAgent::startAutoPilotGlobal( { return; } + + if (target_global.isExactlyZero()) + { + LL_WARNS() << "Canceling attempt to start autopilot towards invalid position" << LL_ENDL; + return; + } // Are there any pending callbacks from previous auto pilot requests? if (mAutoPilotFinishedCallback) @@ -1708,7 +1784,16 @@ void LLAgent::autoPilot(F32 *delta_yaw) if (target_dist >= mAutoPilotTargetDist) { mAutoPilotNoProgressFrameCount++; - if (mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS * gFPSClamped) + bool out_of_time = false; + if (getFlying()) + { + out_of_time = mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS_FLY * gFPSClamped; + } + else + { + out_of_time = mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS_WALK * gFPSClamped; + } + if (out_of_time) { stopAutoPilot(); return; @@ -1757,7 +1842,7 @@ void LLAgent::autoPilot(F32 *delta_yaw) F32 slow_distance; if (getFlying()) { - slow_distance = llmax(6.f, mAutoPilotStopDistance + 5.f); + slow_distance = llmax(8.f, mAutoPilotStopDistance + 5.f); } else { @@ -1801,14 +1886,41 @@ void LLAgent::autoPilot(F32 *delta_yaw) } else if (mAutoPilotTargetDist > mAutoPilotStopDistance) { - // walking/flying slow + // walking/flying slow + U32 movement_flag = 0; + if (at * direction > 0.9f) { - setControlFlags(AGENT_CONTROL_AT_POS); - } - else if (at * direction < -0.9f) - { - setControlFlags(AGENT_CONTROL_AT_NEG); + movement_flag = AGENT_CONTROL_AT_POS; + } + else if (at * direction < -0.9f) + { + movement_flag = AGENT_CONTROL_AT_NEG; + } + + if (getFlying()) + { + // flying is too fast and has high inertia, artificially slow it down + // Don't update flags too often, server might not react + static U64 last_time_microsec = 0; + U64 time_microsec = LLTimer::getTotalTime(); + U64 delta = time_microsec - last_time_microsec; + // fly during ~0-40 ms, stop during ~40-250 ms + if (delta > 250000) // 250ms + { + // reset even if !movement_flag + last_time_microsec = time_microsec; + } + else if (delta > 40000) // 40 ms + { + clearControlFlags(AGENT_CONTROL_AT_POS | AGENT_CONTROL_AT_POS); + movement_flag = 0; + } + } + + if (movement_flag) + { + setControlFlags(movement_flag); } } @@ -2022,6 +2134,14 @@ U8 LLAgent::getRenderState() //----------------------------------------------------------------------------- void LLAgent::endAnimationUpdateUI() { + if (LLApp::isExiting() + || !gViewerWindow + || !gMenuBarView + || !gToolBarView + || !gStatusBar) + { + return; + } if (gAgentCamera.getCameraMode() == gAgentCamera.getLastCameraMode()) { // We're already done endAnimationUpdateUI for this transition. @@ -2598,6 +2718,7 @@ void LLAgent::handlePreferredMaturityResult(U8 pServerMaturity) else { mMaturityPreferenceNumRetries = 0; + LL_WARNS() << "Too many retries for maturity preference" << LL_ENDL; reportPreferredMaturityError(); } } @@ -2649,6 +2770,7 @@ void LLAgent::reportPreferredMaturityError() mIsMaturityRatingChangingDuringTeleport = false; if (hasPendingTeleportRequest()) { + LL_WARNS("Teleport") << "Teleport failing due to preferred maturity error" << LL_ENDL; setTeleportState(LLAgent::TELEPORT_NONE); } @@ -2984,7 +3106,7 @@ BOOL LLAgent::setUserGroupFlags(const LLUUID& group_id, BOOL accept_notices, BOO BOOL LLAgent::canJoinGroups() const { - return (S32)mGroups.size() < gMaxAgentGroups; + return (S32)mGroups.size() < LLAgentBenefitsMgr::current().getGroupMembershipLimit(); } LLQuaternion LLAgent::getHeadRotation() @@ -3744,7 +3866,7 @@ void LLAgent::clearVisualParams(void *data) // protected bool LLAgent::teleportCore(bool is_local) { - LL_INFOS("Teleport") << "In teleport core!" << LL_ENDL; + LL_DEBUGS("Teleport") << "In teleport core" << LL_ENDL; if ((TELEPORT_NONE != mTeleportState) && (mTeleportState != TELEPORT_PENDING)) { LL_WARNS() << "Attempt to teleport when already teleporting." << LL_ENDL; @@ -3810,11 +3932,13 @@ bool LLAgent::teleportCore(bool is_local) add(LLStatViewer::TELEPORT, 1); if (is_local) { + LL_INFOS("Teleport") << "Setting teleport state to TELEPORT_LOCAL" << LL_ENDL; gAgent.setTeleportState( LLAgent::TELEPORT_LOCAL ); } else { gTeleportDisplay = TRUE; + LL_INFOS("Teleport") << "Non-local, setting teleport state to TELEPORT_START" << LL_ENDL; gAgent.setTeleportState( LLAgent::TELEPORT_START ); //release geometry from old location @@ -3853,6 +3977,7 @@ void LLAgent::clearTeleportRequest() LLVoiceClient::getInstance()->setHidden(FALSE); } mTeleportRequest.reset(); + mTPNeedsNeabyChatSeparator = false; } void LLAgent::setMaturityRatingChangeDuringTeleport(U8 pMaturityRatingChange) @@ -3861,6 +3986,12 @@ void LLAgent::setMaturityRatingChangeDuringTeleport(U8 pMaturityRatingChange) mMaturityRatingChange = pMaturityRatingChange; } +void LLAgent::sheduleTeleportIM() +{ + // is supposed to be called during teleport so we are still waiting for parcel + mTPNeedsNeabyChatSeparator = true; +} + bool LLAgent::hasPendingTeleportRequest() { return ((mTeleportRequest != NULL) && @@ -3881,6 +4012,7 @@ void LLAgent::startTeleportRequest() if (!isMaturityPreferenceSyncedWithServer()) { gTeleportDisplay = TRUE; + LL_INFOS("Teleport") << "Maturity preference not synced yet, setting teleport state to TELEPORT_PENDING" << LL_ENDL; setTeleportState(TELEPORT_PENDING); } else @@ -3907,6 +4039,12 @@ void LLAgent::startTeleportRequest() void LLAgent::handleTeleportFinished() { LL_INFOS("Teleport") << "Agent handling teleport finished." << LL_ENDL; + if (mTPNeedsNeabyChatSeparator) + { + // parcel is ready at this point + addTPNearbyChatSeparator(); + mTPNeedsNeabyChatSeparator = false; + } clearTeleportRequest(); mTeleportCanceled.reset(); if (mIsMaturityRatingChangingDuringTeleport) @@ -3924,10 +4062,19 @@ void LLAgent::handleTeleportFinished() { if (mRegionp->capabilitiesReceived()) { + LL_DEBUGS("Teleport") << "capabilities have been received for region handle " + << mRegionp->getHandle() + << " id " << mRegionp->getRegionID() + << ", calling onCapabilitiesReceivedAfterTeleport()" + << LL_ENDL; onCapabilitiesReceivedAfterTeleport(); } else { + LL_DEBUGS("Teleport") << "Capabilities not yet received for region handle " + << mRegionp->getHandle() + << " id " << mRegionp->getRegionID() + << LL_ENDL; mRegionp->setCapabilitiesReceivedCallback(boost::bind(&LLAgent::onCapabilitiesReceivedAfterTeleport)); } } @@ -3960,11 +4107,61 @@ void LLAgent::handleTeleportFailed() LLNotificationsUtil::add("PreferredMaturityChanged", args); mIsMaturityRatingChangingDuringTeleport = false; } + + mTPNeedsNeabyChatSeparator = false; +} + +/*static*/ +void LLAgent::addTPNearbyChatSeparator() +{ + LLViewerRegion* agent_region = gAgent.getRegion(); + LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (!agent_region || !agent_parcel) + { + return; + } + + LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); + if (nearby_chat) + { + std::string location_name; + LLAgentUI::ELocationFormat format = LLAgentUI::LOCATION_FORMAT_NO_MATURITY; + + // Might be better to provide slurl to chat + if (!LLAgentUI::buildLocationString(location_name, format)) + { + location_name = "Teleport to new region"; // Shouldn't happen + } + + LLChat chat; + chat.mFromName = location_name; + chat.mMuted = FALSE; + chat.mFromID = LLUUID::null; + chat.mSourceType = CHAT_SOURCE_TELEPORT; + chat.mChatStyle = CHAT_STYLE_TELEPORT_SEP; + chat.mText = ""; + + LLSD args; + args["do_not_log"] = TRUE; + nearby_chat->addMessage(chat, true, args); + } } /*static*/ void LLAgent::onCapabilitiesReceivedAfterTeleport() { + if (gAgent.getRegion()) + { + LL_DEBUGS("Teleport") << "running after capabilities received callback has been triggered, agent region " + << gAgent.getRegion()->getHandle() + << " id " << gAgent.getRegion()->getRegionID() + << " name " << gAgent.getRegion()->getName() + << LL_ENDL; + } + else + { + LL_WARNS("Teleport") << "called when agent region is null!" << LL_ENDL; + } check_merchant_status(); } @@ -3978,8 +4175,8 @@ void LLAgent::teleportRequest( LLViewerRegion* regionp = getRegion(); if (regionp && teleportCore(region_handle == regionp->getHandle())) { - LL_INFOS("") << "TeleportLocationRequest: '" << region_handle << "':" - << pos_local << LL_ENDL; + LL_INFOS("Teleport") << "Sending TeleportLocationRequest: '" << region_handle << "':" + << pos_local << LL_ENDL; LLMessageSystem* msg = gMessageSystem; msg->newMessage("TeleportLocationRequest"); msg->nextBlockFast(_PREHASH_AgentData); @@ -4010,6 +4207,11 @@ void LLAgent::doTeleportViaLandmark(const LLUUID& landmark_asset_id) LLViewerRegion *regionp = getRegion(); if(regionp && teleportCore()) { + LL_INFOS("Teleport") << "Sending TeleportLandmarkRequest. Current region handle " << regionp->getHandle() + << " region id " << regionp->getRegionID() + << " requested landmark id " << landmark_asset_id + << LL_ENDL; + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_TeleportLandmarkRequest); msg->nextBlockFast(_PREHASH_Info); @@ -4042,6 +4244,11 @@ void LLAgent::doTeleportViaLure(const LLUUID& lure_id, BOOL godlike) teleport_flags |= TELEPORT_FLAGS_VIA_LURE; } + LL_INFOS("Teleport") << "Sending TeleportLureRequest." + << " Current region handle " << regionp->getHandle() + << " region id " << regionp->getRegionID() + << " lure id " << lure_id + << LL_ENDL; // send the message LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_TeleportLureRequest); @@ -4064,6 +4271,8 @@ void LLAgent::teleportCancel() LLViewerRegion* regionp = getRegion(); if(regionp) { + LL_INFOS("Teleport") << "Sending TeleportCancel" << LL_ENDL; + // send the message LLMessageSystem* msg = gMessageSystem; msg->newMessage("TeleportCancel"); @@ -4076,13 +4285,14 @@ void LLAgent::teleportCancel() } clearTeleportRequest(); gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - gPipeline.resetVertexBuffers(); + gPipeline.resetVertexBuffers(); } void LLAgent::restoreCanceledTeleportRequest() { if (mTeleportCanceled != NULL) { + LL_INFOS() << "Restoring canceled teleport request, setting state to TELEPORT_REQUESTED" << LL_ENDL; gAgent.setTeleportState( LLAgent::TELEPORT_REQUESTED ); mTeleportRequest = mTeleportCanceled; mTeleportCanceled.reset(); @@ -4120,7 +4330,6 @@ void LLAgent::doTeleportViaLocation(const LLVector3d& pos_global) else if(regionp && teleportCore(regionp->getHandle() == to_region_handle_global((F32)pos_global.mdV[VX], (F32)pos_global.mdV[VY]))) { - LL_WARNS() << "Using deprecated teleportlocationrequest." << LL_ENDL; // send the message LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_TeleportLocationRequest); @@ -4140,6 +4349,14 @@ void LLAgent::doTeleportViaLocation(const LLVector3d& pos_global) msg->addVector3Fast(_PREHASH_Position, pos); pos.mV[VX] += 1; msg->addVector3Fast(_PREHASH_LookAt, pos); + + LL_WARNS("Teleport") << "Sending deprecated(?) TeleportLocationRequest." + << " pos_global " << pos_global + << " region_x " << region_x + << " region_y " << region_y + << " region_handle " << region_handle + << LL_ENDL; + sendReliableMessage(); } } @@ -4181,7 +4398,11 @@ void LLAgent::setTeleportState(ETeleportState state) " for previously failed teleport. Ignore!" << LL_ENDL; return; } - LL_DEBUGS("Teleport") << "Setting teleport state to " << state << " Previous state: " << mTeleportState << LL_ENDL; + LL_DEBUGS("Teleport") << "Setting teleport state to " + << LLAgent::teleportStateName(state) << "(" << state << ")" + << " Previous state: " + << teleportStateName(mTeleportState) << "(" << mTeleportState << ")" + << LL_ENDL; mTeleportState = state; if (mTeleportState > TELEPORT_NONE && gSavedSettings.getBOOL("FreezeTime")) { @@ -4518,6 +4739,34 @@ void LLAgent::observeFriends() } } +std::map<S32, std::string> LLAgent::sTeleportStateName = { { TELEPORT_NONE, "TELEPORT_NONE" }, + { TELEPORT_START, "TELEPORT_START" }, + { TELEPORT_REQUESTED, "TELEPORT_REQUESTED" }, + { TELEPORT_MOVING, "TELEPORT_MOVING" }, + { TELEPORT_START_ARRIVAL, "TELEPORT_START_ARRIVAL" }, + { TELEPORT_ARRIVING, "TELEPORT_ARRIVING" }, + { TELEPORT_LOCAL, "TELEPORT_LOCAL" }, + { TELEPORT_PENDING, "TELEPORT_PENDING" } }; + +const std::string& LLAgent::teleportStateName(S32 state) +{ + static std::string invalid_state_str("INVALID"); + auto iter = LLAgent::sTeleportStateName.find(state); + if (iter != LLAgent::sTeleportStateName.end()) + { + return iter->second; + } + else + { + return invalid_state_str; + } +} + +const std::string& LLAgent::getTeleportStateName() const +{ + return teleportStateName(getTeleportState()); +} + void LLAgent::parseTeleportMessages(const std::string& xml_filename) { LLXMLNodePtr root; @@ -4641,40 +4890,70 @@ void LLTeleportRequest::restartTeleport() llassert(0); } +// TODO this enum -> name idiom should be in a common class rather than repeated various places. +const std::string& LLTeleportRequest::statusName(EStatus status) +{ + static std::string invalid_status_str("INVALID"); + auto iter = LLTeleportRequest::sTeleportStatusName.find(status); + if (iter != LLTeleportRequest::sTeleportStatusName.end()) + { + return iter->second; + } + else + { + return invalid_status_str; + } +} + +std::ostream& operator<<(std::ostream& os, const LLTeleportRequest& req) +{ + req.toOstream(os); + return os; +} + +void LLTeleportRequest::toOstream(std::ostream& os) const +{ + os << "status " << statusName(mStatus) << "(" << mStatus << ")"; +} + //----------------------------------------------------------------------------- // LLTeleportRequestViaLandmark //----------------------------------------------------------------------------- - LLTeleportRequestViaLandmark::LLTeleportRequestViaLandmark(const LLUUID &pLandmarkId) : LLTeleportRequest(), mLandmarkId(pLandmarkId) { - LL_INFOS("Teleport") << "LLTeleportRequestViaLandmark created." << LL_ENDL; + LL_INFOS("Teleport") << "LLTeleportRequestViaLandmark created, " << *this << LL_ENDL; } LLTeleportRequestViaLandmark::~LLTeleportRequestViaLandmark() { - LL_INFOS("Teleport") << "~LLTeleportRequestViaLandmark" << LL_ENDL; + LL_INFOS("Teleport") << "~LLTeleportRequestViaLandmark, " << *this << LL_ENDL; +} + +void LLTeleportRequestViaLandmark::toOstream(std::ostream& os) const +{ + os << "landmark " << mLandmarkId << " "; + LLTeleportRequest::toOstream(os); } bool LLTeleportRequestViaLandmark::canRestartTeleport() { - LL_INFOS("Teleport") << "LLTeleportRequestViaLandmark::canRestartTeleport? -> true" << LL_ENDL; + LL_INFOS("Teleport") << "LLTeleportRequestViaLandmark::canRestartTeleport? -> true, " << *this << LL_ENDL; return true; } void LLTeleportRequestViaLandmark::startTeleport() { - LL_INFOS("Teleport") << "LLTeleportRequestViaLandmark::startTeleport" << LL_ENDL; + LL_INFOS("Teleport") << "LLTeleportRequestViaLandmark::startTeleport, " << *this << LL_ENDL; gAgent.doTeleportViaLandmark(getLandmarkId()); } void LLTeleportRequestViaLandmark::restartTeleport() { - LL_INFOS("Teleport") << "LLTeleportRequestViaLandmark::restartTeleport" << LL_ENDL; + LL_INFOS("Teleport") << "LLTeleportRequestViaLandmark::restartTeleport, " << *this << LL_ENDL; gAgent.doTeleportViaLandmark(getLandmarkId()); } - //----------------------------------------------------------------------------- // LLTeleportRequestViaLure //----------------------------------------------------------------------------- @@ -4691,6 +4970,12 @@ LLTeleportRequestViaLure::~LLTeleportRequestViaLure() LL_INFOS("Teleport") << "~LLTeleportRequestViaLure" << LL_ENDL; } +void LLTeleportRequestViaLure::toOstream(std::ostream& os) const +{ + os << "mIsLureGodLike " << (S32) mIsLureGodLike << " "; + LLTeleportRequestViaLandmark::toOstream(os); +} + bool LLTeleportRequestViaLure::canRestartTeleport() { // stinson 05/17/2012 : cannot restart a teleport via lure because of server-side restrictions @@ -4731,6 +5016,12 @@ LLTeleportRequestViaLocation::~LLTeleportRequestViaLocation() LL_INFOS("Teleport") << "~LLTeleportRequestViaLocation" << LL_ENDL; } +void LLTeleportRequestViaLocation::toOstream(std::ostream& os) const +{ + os << "mPosGlobal " << mPosGlobal << " "; + LLTeleportRequest::toOstream(os); +} + bool LLTeleportRequestViaLocation::canRestartTeleport() { LL_INFOS("Teleport") << "LLTeleportRequestViaLocation::canRestartTeleport -> true" << LL_ENDL; @@ -4764,6 +5055,11 @@ LLTeleportRequestViaLocationLookAt::~LLTeleportRequestViaLocationLookAt() LL_INFOS("Teleport") << "~LLTeleportRequestViaLocationLookAt" << LL_ENDL; } +void LLTeleportRequestViaLocationLookAt::toOstream(std::ostream& os) const +{ + LLTeleportRequestViaLocation::toOstream(os); +} + bool LLTeleportRequestViaLocationLookAt::canRestartTeleport() { LL_INFOS("Teleport") << "LLTeleportRequestViaLocationLookAt::canRestartTeleport -> true" << LL_ENDL; diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 5ba1083d8e..134540c6b3 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -47,20 +47,15 @@ extern const BOOL ANIMATE; extern const U8 AGENT_STATE_TYPING; // Typing indication extern const U8 AGENT_STATE_EDITING; // Set when agent has objects selected -class LLChat; class LLViewerRegion; class LLMotion; -class LLToolset; class LLMessageSystem; class LLPermissions; class LLHost; class LLFriendObserver; -class LLPickInfo; -class LLViewerObject; class LLAgentDropGroupViewerNode; class LLAgentAccess; class LLSLURL; -class LLPauseRequestHandle; class LLUIColor; class LLTeleportRequest; @@ -91,8 +86,6 @@ struct LLGroupData class LLAgentListener; -class LLAgentImpl; - //------------------------------------------------------------------------ // LLAgent //------------------------------------------------------------------------ @@ -189,6 +182,8 @@ private: // Position //-------------------------------------------------------------------- public: + typedef boost::signals2::signal<void(const LLVector3 &position_local, const LLVector3d &position_global)> position_signal_t; + LLVector3 getPosAgentFromGlobal(const LLVector3d &pos_global) const; LLVector3d getPosGlobalFromAgent(const LLVector3 &pos_agent) const; const LLVector3d &getPositionGlobal() const; @@ -196,11 +191,17 @@ public: // Call once per frame to update position, angles (radians). void updateAgentPosition(const F32 dt, const F32 yaw, const S32 mouse_x, const S32 mouse_y); void setPositionAgent(const LLVector3 ¢er); + + boost::signals2::connection whenPositionChanged(position_signal_t::slot_type fn); + protected: void propagate(const F32 dt); // ! BUG ! Should roll into updateAgentPosition private: mutable LLVector3d mPositionGlobal; + position_signal_t mOnPositionChanged; + LLVector3d mLastTestGlobal; + //-------------------------------------------------------------------- // Velocity //-------------------------------------------------------------------- @@ -253,6 +254,8 @@ public: boost::signals2::connection addParcelChangedCallback(parcel_changed_callback_t); private: + static void capabilityReceivedCallback(const LLUUID ®ion_id, LLViewerRegion *regionp); + typedef boost::signals2::signal<void()> parcel_changed_signal_t; parcel_changed_signal_t mParcelChangedSignal; @@ -343,6 +346,7 @@ public: static void toggleFlying(); static bool enableFlying(); BOOL canFly(); // Does this parcel allow you to fly? + static bool isSitting(); //-------------------------------------------------------------------- // Voice @@ -610,6 +614,10 @@ public: TELEPORT_PENDING = 7 }; + static std::map<S32, std::string> sTeleportStateName; + static const std::string& teleportStateName(S32); + const std::string& getTeleportStateName() const; + public: static void parseTeleportMessages(const std::string& xml_filename); const void getTeleportSourceSLURL(LLSLURL& slurl) const; @@ -645,6 +653,7 @@ public: void restartFailedTeleportRequest(); void clearTeleportRequest(); void setMaturityRatingChangeDuringTeleport(U8 pMaturityRatingChange); + void sheduleTeleportIM(); private: @@ -661,6 +670,7 @@ private: boost::signals2::connection mTeleportFailedSlot; bool mIsMaturityRatingChangingDuringTeleport; + bool mTPNeedsNeabyChatSeparator; U8 mMaturityRatingChange; bool hasPendingTeleportRequest(); @@ -677,6 +687,7 @@ private: void handleTeleportFinished(); void handleTeleportFailed(); + static void addTPNearbyChatSeparator(); static void onCapabilitiesReceivedAfterTeleport(); //-------------------------------------------------------------------- diff --git a/indra/newview/llagentbenefits.cpp b/indra/newview/llagentbenefits.cpp new file mode 100644 index 0000000000..2d219735a0 --- /dev/null +++ b/indra/newview/llagentbenefits.cpp @@ -0,0 +1,236 @@ +/** +* @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; +} + +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 +const 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; + +} + +// 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..48aa6bd869 --- /dev/null +++ b/indra/newview/llagentbenefits.h @@ -0,0 +1,88 @@ +/** +* @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); + + 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<LLAgentBenefitsMgr> +{ + LLSINGLETON(LLAgentBenefitsMgr); + ~LLAgentBenefitsMgr(); + LOG_CLASS(LLAgentBenefitsMgr); + +public: + static const 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); + static bool has(const std::string& package); + static bool isCurrent(const std::string& package); + +private: + std::string mCurrentName; + LLAgentBenefits mCurrent; + LLAgentBenefits mDefault; + std::map<std::string, LLAgentBenefits> mPackageMap; +}; + + +#endif diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 92a3026096..ed6c3c307f 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -184,6 +184,9 @@ LLAgentCamera::LLAgentCamera() : clearGeneralKeys(); clearOrbitKeys(); clearPanKeys(); + + resetPanDiff(); + resetOrbitDiff(); } // Requires gSavedSettings to be initialized. @@ -205,15 +208,10 @@ void LLAgentCamera::init() mCameraFocusOffsetTarget = LLVector4(gSavedSettings.getVector3("CameraOffsetBuild")); - mCameraPreset = (ECameraPreset) gSavedSettings.getU32("CameraPreset"); - - mCameraOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("CameraOffsetRearView"); - mCameraOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("CameraOffsetFrontView"); - mCameraOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("CameraOffsetGroupView"); + mCameraPreset = (ECameraPreset) gSavedSettings.getU32("CameraPresetType"); - mFocusOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("FocusOffsetRearView"); - mFocusOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("FocusOffsetFrontView"); - mFocusOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("FocusOffsetGroupView"); + mCameraOffsetInitial = gSavedSettings.getControl("CameraOffsetRearView"); + mFocusOffsetInitial = gSavedSettings.getControl("FocusOffsetRearView"); mCameraCollidePlane.clearVec(); mCurrentCameraDistance = getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale"); @@ -282,6 +280,11 @@ LLAgentCamera::~LLAgentCamera() //----------------------------------------------------------------------------- void LLAgentCamera::resetView(BOOL reset_camera, BOOL change_camera) { + if (gDisconnected) + { + return; + } + if (gAgent.getAutoPilot()) { gAgent.stopAutoPilot(TRUE); @@ -348,8 +351,21 @@ void LLAgentCamera::resetView(BOOL reset_camera, BOOL change_camera) mCameraFOVZoomFactor = 0.f; } - + resetPanDiff(); + resetOrbitDiff(); mHUDTargetZoom = 1.f; + + if (LLSelectMgr::getInstance()->mAllowSelectAvatar) + { + // resetting camera also resets position overrides in debug mode 'AllowSelectAvatar' + LLObjectSelectionHandle selected_handle = LLSelectMgr::getInstance()->getSelection(); + if (selected_handle->getObjectCount() == 1 + && selected_handle->getFirstObject() != NULL + && selected_handle->getFirstObject()->isAvatar()) + { + LLSelectMgr::getInstance()->resetObjectOverrides(selected_handle); + } + } } // Allow camera to be moved somewhere other than behind avatar. @@ -718,7 +734,7 @@ BOOL LLAgentCamera::calcCameraMinDistance(F32 &obj_min_distance) return TRUE; } -F32 LLAgentCamera::getCameraZoomFraction() +F32 LLAgentCamera::getCameraZoomFraction(bool get_third_person) { // 0.f -> camera zoomed all the way out // 1.f -> camera zoomed all the way in @@ -728,7 +744,7 @@ F32 LLAgentCamera::getCameraZoomFraction() // already [0,1] return mHUDTargetZoom; } - else if (mFocusOnAvatar && cameraThirdPerson()) + else if (get_third_person || (mFocusOnAvatar && cameraThirdPerson())) { return clamp_rescale(mCameraZoomFraction, MIN_ZOOM_FRACTION, MAX_ZOOM_FRACTION, 1.f, 0.f); } @@ -790,13 +806,16 @@ void LLAgentCamera::setCameraZoomFraction(F32 fraction) if (mFocusObject.notNull()) { - if (mFocusObject->isAvatar()) - { - min_zoom = AVATAR_MIN_ZOOM; - } - else + if (mFocusObject.notNull()) { - min_zoom = OBJECT_MIN_ZOOM; + if (mFocusObject->isAvatar()) + { + min_zoom = AVATAR_MIN_ZOOM; + } + else + { + min_zoom = OBJECT_MIN_ZOOM; + } } } @@ -807,6 +826,12 @@ void LLAgentCamera::setCameraZoomFraction(F32 fraction) startCameraAnimation(); } +F32 LLAgentCamera::getAgentHUDTargetZoom() +{ + static LLCachedControl<F32> hud_scale_factor(gSavedSettings, "HUDScaleFactor"); + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + return (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD) ? hud_scale_factor*gAgentCamera.mHUDTargetZoom : hud_scale_factor; +} //----------------------------------------------------------------------------- // cameraOrbitAround() @@ -824,6 +849,7 @@ void LLAgentCamera::cameraOrbitAround(const F32 radians) } else { + mOrbitAroundRadians += radians; mCameraFocusOffsetTarget.rotVec(radians, 0.f, 0.f, 1.f); cameraZoomIn(1.f); @@ -855,12 +881,34 @@ void LLAgentCamera::cameraOrbitOver(const F32 angle) LLVector3d left_axis; left_axis.setVec(LLViewerCamera::getInstance()->getLeftAxis()); F32 new_angle = llclamp(angle_from_up - angle, 1.f * DEG_TO_RAD, 179.f * DEG_TO_RAD); + mOrbitOverAngle += angle_from_up - new_angle; mCameraFocusOffsetTarget.rotVec(angle_from_up - new_angle, left_axis); cameraZoomIn(1.f); } } +void LLAgentCamera::resetCameraOrbit() +{ + LLVector3 camera_offset_unit(mCameraFocusOffsetTarget); + camera_offset_unit.normalize(); + + LLVector3d left_axis; + left_axis.setVec(LLViewerCamera::getInstance()->getLeftAxis()); + mCameraFocusOffsetTarget.rotVec(-mOrbitOverAngle, left_axis); + + mCameraFocusOffsetTarget.rotVec(-mOrbitAroundRadians, 0.f, 0.f, 1.f); + + cameraZoomIn(1.f); + resetOrbitDiff(); +} + +void LLAgentCamera::resetOrbitDiff() +{ + mOrbitAroundRadians = 0; + mOrbitOverAngle = 0; +} + //----------------------------------------------------------------------------- // cameraZoomIn() //----------------------------------------------------------------------------- @@ -999,6 +1047,8 @@ void LLAgentCamera::cameraPanIn(F32 meters) LLVector3d at_axis; at_axis.setVec(LLViewerCamera::getInstance()->getAtAxis()); + mPanFocusDiff += meters * at_axis; + mFocusTargetGlobal += meters * at_axis; mFocusGlobal = mFocusTargetGlobal; // don't enforce zoom constraints as this is the only way for users to get past them easily @@ -1015,6 +1065,8 @@ void LLAgentCamera::cameraPanLeft(F32 meters) LLVector3d left_axis; left_axis.setVec(LLViewerCamera::getInstance()->getLeftAxis()); + mPanFocusDiff += meters * left_axis; + mFocusTargetGlobal += meters * left_axis; mFocusGlobal = mFocusTargetGlobal; @@ -1035,6 +1087,8 @@ void LLAgentCamera::cameraPanUp(F32 meters) LLVector3d up_axis; up_axis.setVec(LLViewerCamera::getInstance()->getUpAxis()); + mPanFocusDiff += meters * up_axis; + mFocusTargetGlobal += meters * up_axis; mFocusGlobal = mFocusTargetGlobal; @@ -1047,6 +1101,26 @@ void LLAgentCamera::cameraPanUp(F32 meters) mCameraSmoothingLastPositionGlobal = calcCameraPositionTargetGlobal(); } +void LLAgentCamera::resetCameraPan() +{ + mFocusTargetGlobal -= mPanFocusDiff; + + mFocusGlobal = mFocusTargetGlobal; + mCameraSmoothingStop = true; + + cameraZoomIn(1.f); + updateFocusOffset(); + + mCameraSmoothingLastPositionGlobal = calcCameraPositionTargetGlobal(); + + resetPanDiff(); +} + +void LLAgentCamera::resetPanDiff() +{ + mPanFocusDiff.clear(); +} + //----------------------------------------------------------------------------- // updateLookAt() //----------------------------------------------------------------------------- @@ -1140,7 +1214,7 @@ void LLAgentCamera::updateCamera() mCameraUpVector = mCameraUpVector * gAgentAvatarp->getRenderRotation(); } - if (cameraThirdPerson() && (mFocusOnAvatar || mAllowChangeToFollow) && LLFollowCamMgr::getActiveFollowCamParams()) + if (cameraThirdPerson() && (mFocusOnAvatar || mAllowChangeToFollow) && LLFollowCamMgr::getInstance()->getActiveFollowCamParams()) { mAllowChangeToFollow = FALSE; mFocusOnAvatar = TRUE; @@ -1240,7 +1314,7 @@ void LLAgentCamera::updateCamera() // *TODO: use combined rotation of frameagent and sit object LLQuaternion avatarRotationForFollowCam = gAgentAvatarp->isSitting() ? gAgentAvatarp->getRenderRotation() : gAgent.getFrameAgent().getQuaternion(); - LLFollowCamParams* current_cam = LLFollowCamMgr::getActiveFollowCamParams(); + LLFollowCamParams* current_cam = LLFollowCamMgr::getInstance()->getActiveFollowCamParams(); if (current_cam) { mFollowCam.copyParams(*current_cam); @@ -1449,7 +1523,7 @@ void LLAgentCamera::updateCamera() attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - LLViewerObject *attached_object = (*attachment_iter); + LLViewerObject *attached_object = attachment_iter->get(); if (attached_object && !attached_object->isDead() && attached_object->mDrawable.notNull()) { // clear any existing "early" movements of attachment @@ -1598,7 +1672,7 @@ LLVector3d LLAgentCamera::calcThirdPersonFocusOffset() agent_rot *= ((LLViewerObject*)(gAgentAvatarp->getParent()))->getRenderRotation(); } - focus_offset = convert_from_llsd<LLVector3d>(mFocusOffsetInitial[mCameraPreset]->get(), TYPE_VEC3D, ""); + focus_offset = convert_from_llsd<LLVector3d>(mFocusOffsetInitial->get(), TYPE_VEC3D, ""); return focus_offset * agent_rot; } @@ -1673,7 +1747,7 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) F32 camera_land_height; LLVector3d frame_center_global = !isAgentAvatarValid() ? gAgent.getPositionGlobal() : - gAgent.getPosGlobalFromAgent(gAgentAvatarp->mRoot->getWorldPosition()); + gAgent.getPosGlobalFromAgent(getAvatarRootPosition()); BOOL isConstrained = FALSE; LLVector3d head_offset; @@ -1747,7 +1821,7 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) at_axis.mV[VZ] = 0.f; at_axis.normalize(); gAgent.resetAxes(at_axis * ~parent_rot); - + local_camera_offset = local_camera_offset * gAgent.getFrameAgent().getQuaternion() * parent_rot; } else @@ -1928,9 +2002,38 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) } +LLVector3 LLAgentCamera::getCurrentCameraOffset() +{ + return (LLViewerCamera::getInstance()->getOrigin() - getAvatarRootPosition() - mThirdPersonHeadOffset) * ~getCurrentAvatarRotation(); +} + +LLVector3d LLAgentCamera::getCurrentFocusOffset() +{ + return (mFocusTargetGlobal - gAgent.getPositionGlobal()) * ~getCurrentAvatarRotation(); +} + +LLQuaternion LLAgentCamera::getCurrentAvatarRotation() +{ + LLViewerObject* sit_object = (LLViewerObject*)gAgentAvatarp->getParent(); + + LLQuaternion av_rot = gAgent.getFrameAgent().getQuaternion(); + LLQuaternion obj_rot = sit_object ? sit_object->getRenderRotation() : LLQuaternion::DEFAULT; + return av_rot * obj_rot; +} + +bool LLAgentCamera::isJoystickCameraUsed() +{ + return ((mOrbitAroundRadians != 0) || (mOrbitOverAngle != 0) || !mPanFocusDiff.isNull()); +} + LLVector3 LLAgentCamera::getCameraOffsetInitial() { - return convert_from_llsd<LLVector3>(mCameraOffsetInitial[mCameraPreset]->get(), TYPE_VEC3, ""); + return convert_from_llsd<LLVector3>(mCameraOffsetInitial->get(), TYPE_VEC3, ""); +} + +LLVector3d LLAgentCamera::getFocusOffsetInitial() +{ + return convert_from_llsd<LLVector3d>(mFocusOffsetInitial->get(), TYPE_VEC3D, ""); } F32 LLAgentCamera::getCameraMaxZoomDistance() @@ -1941,6 +2044,12 @@ F32 LLAgentCamera::getCameraMaxZoomDistance() LLWorld::getInstance()->getRegionWidthInMeters() - CAMERA_FUDGE_FROM_OBJECT); } +LLVector3 LLAgentCamera::getAvatarRootPosition() +{ + static LLCachedControl<bool> use_hover_height(gSavedSettings, "HoverHeightAffectsCamera"); + return use_hover_height ? gAgentAvatarp->mRoot->getWorldPosition() : gAgentAvatarp->mRoot->getWorldPosition() - gAgentAvatarp->getHoverOffset(); + +} //----------------------------------------------------------------------------- // handleScrollWheel() //----------------------------------------------------------------------------- @@ -2046,7 +2155,7 @@ void LLAgentCamera::changeCameraToMouselook(BOOL animate) // Menus should not remain open on switching to mouselook... LLMenuGL::sMenuContainer->hideMenus(); - LLUI::clearPopups(); + LLUI::getInstance()->clearPopups(); // unpause avatar animation gAgent.unpauseAnimation(); @@ -2100,7 +2209,7 @@ void LLAgentCamera::changeCameraToDefault() return; } - if (LLFollowCamMgr::getActiveFollowCamParams()) + if (LLFollowCamMgr::getInstance()->getActiveFollowCamParams()) { changeCameraToFollow(); } @@ -2220,15 +2329,7 @@ void LLAgentCamera::changeCameraToThirdPerson(BOOL animate) } // Remove any pitch from the avatar - if (isAgentAvatarValid() && gAgentAvatarp->getParent()) - { - LLQuaternion obj_rot = ((LLViewerObject*)gAgentAvatarp->getParent())->getRenderRotation(); - at_axis = LLViewerCamera::getInstance()->getAtAxis(); - at_axis.mV[VZ] = 0.f; - at_axis.normalize(); - gAgent.resetAxes(at_axis * ~obj_rot); - } - else + if (!isAgentAvatarValid() || !gAgentAvatarp->getParent()) { at_axis = gAgent.getFrameAgent().getAtAxis(); at_axis.mV[VZ] = 0.f; @@ -2327,7 +2428,10 @@ void LLAgentCamera::switchCameraPreset(ECameraPreset preset) mCameraPreset = preset; - gSavedSettings.setU32("CameraPreset", mCameraPreset); + resetPanDiff(); + resetOrbitDiff(); + + gSavedSettings.setU32("CameraPresetType", mCameraPreset); } @@ -2572,7 +2676,7 @@ void LLAgentCamera::setSitCamera(const LLUUID &object_id, const LLVector3 &camer //----------------------------------------------------------------------------- // setFocusOnAvatar() //----------------------------------------------------------------------------- -void LLAgentCamera::setFocusOnAvatar(BOOL focus_on_avatar, BOOL animate) +void LLAgentCamera::setFocusOnAvatar(BOOL focus_on_avatar, BOOL animate, BOOL reset_axes) { if (focus_on_avatar != mFocusOnAvatar) { @@ -2589,27 +2693,28 @@ void LLAgentCamera::setFocusOnAvatar(BOOL focus_on_avatar, BOOL animate) //RN: when focused on the avatar, we're not "looking" at it // looking implies intent while focusing on avatar means // you're just walking around with a camera on you...eesh. - if (!mFocusOnAvatar && focus_on_avatar) + if (!mFocusOnAvatar && focus_on_avatar && reset_axes) { setFocusGlobal(LLVector3d::zero); mCameraFOVZoomFactor = 0.f; if (mCameraMode == CAMERA_MODE_THIRD_PERSON) { LLVector3 at_axis; - if (isAgentAvatarValid() && gAgentAvatarp->getParent()) - { - LLQuaternion obj_rot = ((LLViewerObject*)gAgentAvatarp->getParent())->getRenderRotation(); - at_axis = LLViewerCamera::getInstance()->getAtAxis(); - at_axis.mV[VZ] = 0.f; - at_axis.normalize(); - gAgent.resetAxes(at_axis * ~obj_rot); - } - else + if (!isAgentAvatarValid() || !gAgentAvatarp->getParent()) { - at_axis = LLViewerCamera::getInstance()->getAtAxis(); - at_axis.mV[VZ] = 0.f; - at_axis.normalize(); - gAgent.resetAxes(at_axis); + // In case of front view rotate agent to look into direction opposite to camera + // In case of rear view rotate agent into diraction same as camera, e t c + LLVector3 vect = getCameraOffsetInitial(); + F32 rotxy = F32(atan2(vect.mV[VY], vect.mV[VX])); + + LLCoordFrame frameCamera = *((LLCoordFrame*)LLViewerCamera::getInstance()); + // front view angle rotxy is zero, rear view rotxy angle is 180, compensate + frameCamera.yaw((180 * DEG_TO_RAD) - rotxy); + at_axis = frameCamera.getAtAxis(); + at_axis.mV[VZ] = 0.f; + at_axis.normalize(); + gAgent.resetAxes(at_axis); + gAgent.yaw(0); } } } @@ -2752,6 +2857,17 @@ BOOL LLAgentCamera::setPointAt(EPointAtType target_type, LLViewerObject *object, return mPointAt->setPointAt(target_type, object, position); } +void LLAgentCamera::rotateToInitSitRot() +{ + gAgent.rotate(~gAgent.getFrameAgent().getQuaternion()); + gAgent.rotate(mInitSitRot); +} + +void LLAgentCamera::resetCameraZoomFraction() +{ + mCameraZoomFraction = INITIAL_ZOOM_FRACTION; +} + ELookAtType LLAgentCamera::getLookAtType() { if (mLookAt) diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h index d087de1e2f..ec1ed433d7 100644 --- a/indra/newview/llagentcamera.h +++ b/indra/newview/llagentcamera.h @@ -56,7 +56,10 @@ enum ECameraPreset CAMERA_PRESET_FRONT_VIEW, /** "Above and to the left, over the shoulder, pulled back a little on the zoom" */ - CAMERA_PRESET_GROUP_VIEW + CAMERA_PRESET_GROUP_VIEW, + + /** Current view when a preset is saved */ + CAMERA_PRESET_CUSTOM }; //------------------------------------------------------------------------ @@ -109,20 +112,32 @@ private: //-------------------------------------------------------------------- public: void switchCameraPreset(ECameraPreset preset); -private: /** Determines default camera offset depending on the current camera preset */ LLVector3 getCameraOffsetInitial(); + /** Determines default focus offset depending on the current camera preset */ + LLVector3d getFocusOffsetInitial(); + + LLVector3 getCurrentCameraOffset(); + LLVector3d getCurrentFocusOffset(); + LLQuaternion getCurrentAvatarRotation(); + bool isJoystickCameraUsed(); + void setInitSitRot(LLQuaternion sit_rot) { mInitSitRot = sit_rot; }; + void rotateToInitSitRot(); + +private: /** Determines maximum camera distance from target for mouselook, opposite to LAND_MIN_ZOOM */ F32 getCameraMaxZoomDistance(); /** Camera preset in Third Person Mode */ ECameraPreset mCameraPreset; - /** Initial camera offsets */ - std::map<ECameraPreset, LLPointer<LLControlVariable> > mCameraOffsetInitial; + /** Initial camera offset */ + LLPointer<LLControlVariable> mCameraOffsetInitial; + + /** Initial focus offset */ + LLPointer<LLControlVariable> mFocusOffsetInitial; - /** Initial focus offsets */ - std::map<ECameraPreset, LLPointer<LLControlVariable> > mFocusOffsetInitial; + LLQuaternion mInitSitRot; //-------------------------------------------------------------------- // Position @@ -137,6 +152,8 @@ public: F32 getCurrentCameraBuildOffset() { return (F32)mCameraFocusOffset.length(); } void clearCameraLag() { mCameraLag.clearVec(); } private: + LLVector3 getAvatarRootPosition(); + F32 mCurrentCameraDistance; // Current camera offset from avatar F32 mTargetCameraDistance; // Target camera offset from avatar F32 mCameraFOVZoomFactor; // Amount of fov zoom applied to camera when zeroing in on an object @@ -204,7 +221,7 @@ public: void validateFocusObject(); void setFocusGlobal(const LLPickInfo& pick); void setFocusGlobal(const LLVector3d &focus, const LLUUID &object_id = LLUUID::null); - void setFocusOnAvatar(BOOL focus, BOOL animate); + void setFocusOnAvatar(BOOL focus, BOOL animate, BOOL reset_axes = TRUE); void setCameraPosAndFocusGlobal(const LLVector3d& pos, const LLVector3d& focus, const LLUUID &object_id); void clearFocusObject(); void setFocusObject(LLViewerObject* object); @@ -256,16 +273,21 @@ public: void cameraOrbitAround(const F32 radians); // Rotate camera CCW radians about build focus point void cameraOrbitOver(const F32 radians); // Rotate camera forward radians over build focus point void cameraOrbitIn(const F32 meters); // Move camera in toward build focus point - + void resetCameraOrbit(); + void resetOrbitDiff(); //-------------------------------------------------------------------- // Zoom //-------------------------------------------------------------------- public: - void handleScrollWheel(S32 clicks); // Mousewheel driven zoom - void cameraZoomIn(const F32 factor); // Zoom in by fraction of current distance - F32 getCameraZoomFraction(); // Get camera zoom as fraction of minimum and maximum zoom - void setCameraZoomFraction(F32 fraction); // Set camera zoom as fraction of minimum and maximum zoom + void handleScrollWheel(S32 clicks); // Mousewheel driven zoom + void cameraZoomIn(const F32 factor); // Zoom in by fraction of current distance + F32 getCameraZoomFraction(bool get_third_person = false); // Get camera zoom as fraction of minimum and maximum zoom + void setCameraZoomFraction(F32 fraction); // Set camera zoom as fraction of minimum and maximum zoom F32 calcCameraFOVZoomFactor(); + F32 getAgentHUDTargetZoom(); + + void resetCameraZoomFraction(); + F32 getCurrentCameraZoomFraction() { return mCameraZoomFraction; } //-------------------------------------------------------------------- // Pan @@ -273,8 +295,9 @@ public: public: void cameraPanIn(const F32 meters); void cameraPanLeft(const F32 meters); - void cameraPanUp(const F32 meters); - + void cameraPanUp(const F32 meters); + void resetCameraPan(); + void resetPanDiff(); //-------------------------------------------------------------------- // View //-------------------------------------------------------------------- @@ -361,6 +384,9 @@ private: F32 mOrbitInKey; F32 mOrbitOutKey; + F32 mOrbitAroundRadians; + F32 mOrbitOverAngle; + //-------------------------------------------------------------------- // Pan //-------------------------------------------------------------------- @@ -388,6 +414,8 @@ private: F32 mPanInKey; F32 mPanOutKey; + LLVector3d mPanFocusDiff; + /** Keys ** ** *******************************************************************************/ diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 15e4de8f69..7f18ea6fe2 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -799,14 +799,13 @@ void LLAgentWearables::createStandardWearables() ((OnWearableItemCreatedCB*)(&(*cb)))->addPendingWearable(wearable); // no need to update here... LLUUID category_id = LLUUID::null; - create_inventory_item(gAgent.getID(), + create_inventory_wearable(gAgent.getID(), gAgent.getSessionID(), category_id, wearable->getTransactionID(), wearable->getName(), wearable->getDescription(), wearable->getAssetType(), - LLInventoryType::IT_WEARABLE, wearable->getType(), wearable->getPermissions().getMaskNextOwner(), cb); @@ -868,14 +867,13 @@ void LLAgentWearables::addWearableToAgentInventory(LLPointer<LLInventoryCallback const LLUUID& category_id, BOOL notify) { - create_inventory_item(gAgent.getID(), + create_inventory_wearable(gAgent.getID(), gAgent.getSessionID(), category_id, wearable->getTransactionID(), wearable->getName(), wearable->getDescription(), wearable->getAssetType(), - LLInventoryType::IT_WEARABLE, wearable->getType(), wearable->getPermissions().getMaskNextOwner(), cb); @@ -883,13 +881,6 @@ void LLAgentWearables::addWearableToAgentInventory(LLPointer<LLInventoryCallback void LLAgentWearables::removeWearable(const LLWearableType::EType type, bool do_remove_all, U32 index) { - if (gAgent.isTeen() && - (type == LLWearableType::WT_UNDERSHIRT || type == LLWearableType::WT_UNDERPANTS)) - { - // Can't take off underclothing in simple UI mode or on PG accounts - // TODO: enable the removing of a single undershirt/underpants if multiple are worn. - Nyx - return; - } if (getWearableCount(type) == 0) { // no wearables to remove @@ -1323,7 +1314,7 @@ void LLAgentWearables::findAttachmentsAddRemoveInfo(LLInventoryModel::item_array attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - LLViewerObject *objectp = (*attachment_iter); + LLViewerObject *objectp = attachment_iter->get(); if (objectp) { LLUUID object_item_id = objectp->getAttachmentItemID(); @@ -1387,7 +1378,7 @@ std::vector<LLViewerObject*> LLAgentWearables::getTempAttachments() attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - LLViewerObject *objectp = (*attachment_iter); + LLViewerObject *objectp = attachment_iter->get(); if (objectp && objectp->isTempAttachment()) { temp_attachs.push_back(objectp); @@ -1546,7 +1537,6 @@ void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, con LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); LLAssetType::EType asset_type = wearable->getAssetType(); - LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE; LLPointer<LLInventoryCallback> cb; if(wear) { @@ -1569,13 +1559,13 @@ void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, con folder_id = gInventory.findCategoryUUIDForType(folder_type); } - create_inventory_item(gAgent.getID(), + create_inventory_wearable(gAgent.getID(), gAgent.getSessionID(), folder_id, wearable->getTransactionID(), wearable->getName(), wearable->getDescription(), - asset_type, inv_type, + asset_type, wearable->getType(), LLFloaterPerms::getNextOwnerPerms("Wearables"), cb); diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index ee49125711..005259bcb8 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -44,6 +44,10 @@ const std::string AISAPI::INVENTORY_CAP_NAME("InventoryAPIv3"); const std::string AISAPI::LIBRARY_CAP_NAME("LibraryAPIv3"); +std::list<AISAPI::ais_query_item_t> AISAPI::sPostponedQuery; + +const S32 MAX_SIMULTANEOUS_COROUTINES = 2048; + //------------------------------------------------------------------------- /*static*/ bool AISAPI::isAvailable() @@ -366,9 +370,51 @@ void AISAPI::UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t /*static*/ void AISAPI::EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc) { + LLCoprocedureManager &inst = LLCoprocedureManager::instance(); + S32 pending_in_pool = inst.countPending("AIS"); std::string procFullName = "AIS(" + procName + ")"; - LLCoprocedureManager::instance().enqueueCoprocedure("AIS", procFullName, proc); + if (pending_in_pool < MAX_SIMULTANEOUS_COROUTINES) + { + inst.enqueueCoprocedure("AIS", procFullName, proc); + } + else + { + // As I understand it, coroutines have built-in 'pending' pool + // but unfortunately it has limited size which inventory often goes over + // so this is a workaround to not overfill it. + if (sPostponedQuery.empty()) + { + sPostponedQuery.push_back(ais_query_item_t(procFullName, proc)); + gIdleCallbacks.addFunction(onIdle, NULL); + } + else + { + sPostponedQuery.push_back(ais_query_item_t(procFullName, proc)); + } + } +} +/*static*/ +void AISAPI::onIdle(void *userdata) +{ + if (!sPostponedQuery.empty()) + { + LLCoprocedureManager &inst = LLCoprocedureManager::instance(); + S32 pending_in_pool = inst.countPending("AIS"); + while (pending_in_pool < MAX_SIMULTANEOUS_COROUTINES && !sPostponedQuery.empty()) + { + ais_query_item_t &item = sPostponedQuery.front(); + inst.enqueueCoprocedure("AIS", item.first, item.second); + sPostponedQuery.pop_front(); + pending_in_pool++; + } + } + + if (sPostponedQuery.empty()) + { + // Nothing to do anymore + gIdleCallbacks.deleteFunction(onIdle, NULL); + } } /*static*/ diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h index e97059014b..856f3fc180 100644 --- a/indra/newview/llaisapi.h +++ b/indra/newview/llaisapi.h @@ -31,7 +31,6 @@ #include <map> #include <set> #include <string> -#include "llhttpretrypolicy.h" #include "llviewerinventory.h" #include "llcorehttputil.h" #include "llcoproceduremanager.h" @@ -72,6 +71,7 @@ private: const std::string, LLSD, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t) > invokationFn_t; static void EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc); + static void onIdle(void *userdata); // launches postponed AIS commands static std::string getInvCap(); static std::string getLibCap(); @@ -80,6 +80,8 @@ private: invokationFn_t invoke, std::string url, LLUUID targetId, LLSD body, completion_t callback, COMMAND_TYPE type); + typedef std::pair<std::string, LLCoprocedureManager::CoProcedure_t> ais_query_item_t; + static std::list<ais_query_item_t> sPostponedQuery; }; class AISUpdate diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp index afa4414968..3da87e657c 100644 --- a/indra/newview/llappcorehttp.cpp +++ b/indra/newview/llappcorehttp.cpp @@ -116,6 +116,7 @@ static const struct }; static void setting_changed(); +static void ssl_verification_changed(); LLAppCoreHttp::HttpClass::HttpClass() @@ -195,6 +196,23 @@ void LLAppCoreHttp::init() LL_WARNS("Init") << "Failed to set SSL Verification. Reason: " << status.toString() << LL_ENDL; } + // Set up Default SSL Verification option. + const std::string no_verify_ssl("NoVerifySSLCert"); + if (gSavedSettings.controlExists(no_verify_ssl)) + { + LLPointer<LLControlVariable> cntrl_ptr = gSavedSettings.getControl(no_verify_ssl); + if (cntrl_ptr.isNull()) + { + LL_WARNS("Init") << "Unable to set signal on global setting '" << no_verify_ssl + << "'" << LL_ENDL; + } + else + { + mSSLNoVerifySignal = cntrl_ptr->getCommitSignal()->connect(boost::bind(&ssl_verification_changed)); + LLCore::HttpOptions::setDefaultSSLVerifyPeer(!cntrl_ptr->getValue().asBoolean()); + } + } + // Tracing levels for library & libcurl (note that 2 & 3 are beyond spammy): // 0 - None // 1 - Basic start, stop simple transitions @@ -296,6 +314,11 @@ void setting_changed() LLAppViewer::instance()->getAppCoreHttp().refreshSettings(false); } +void ssl_verification_changed() +{ + LLCore::HttpOptions::setDefaultSSLVerifyPeer(!gSavedSettings.getBOOL("NoVerifySSLCert")); +} + namespace { // The NoOpDeletor is used when wrapping LLAppCoreHttp in a smart pointer below for @@ -355,6 +378,7 @@ void LLAppCoreHttp::cleanup() { mHttpClasses[i].mSettingsSignal.disconnect(); } + mSSLNoVerifySignal.disconnect(); mPipelinedSignal.disconnect(); delete mRequest; @@ -522,20 +546,20 @@ void LLAppCoreHttp::refreshSettings(bool initial) LLCore::HttpStatus LLAppCoreHttp::sslVerify(const std::string &url, const LLCore::HttpHandler::ptr_t &handler, void *appdata) { - X509_STORE_CTX *ctx = static_cast<X509_STORE_CTX *>(appdata); - LLCore::HttpStatus result; - LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(""); - LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx); - LLSD validation_params = LLSD::emptyMap(); - LLURI uri(url); + LLCore::HttpStatus result; + try + { + X509_STORE_CTX *ctx = static_cast<X509_STORE_CTX *>(appdata); + LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(""); + LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx); + LLSD validation_params = LLSD::emptyMap(); + LLURI uri(url); - validation_params[CERT_HOSTNAME] = uri.hostName(); + validation_params[CERT_HOSTNAME] = uri.hostName(); - // *TODO: In the case of an exception while validating the cert, we need a way - // to pass the offending(?) cert back out. *Rider* + // *TODO: In the case of an exception while validating the cert, we need a way + // to pass the offending(?) cert back out. *Rider* - try - { // don't validate hostname. Let libcurl do it instead. That way, it'll handle redirects store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params); } diff --git a/indra/newview/llappcorehttp.h b/indra/newview/llappcorehttp.h index 95c138d598..751c498ab0 100644 --- a/indra/newview/llappcorehttp.h +++ b/indra/newview/llappcorehttp.h @@ -256,6 +256,7 @@ private: HttpClass mHttpClasses[AP_COUNT]; bool mPipelined; // Global setting boost::signals2::connection mPipelinedSignal; // Signal for 'HttpPipelining' setting + boost::signals2::connection mSSLNoVerifySignal; // Signal for 'NoVerifySSLCert' setting static LLCore::HttpStatus sslVerify(const std::string &uri, const LLCore::HttpHandler::ptr_t &handler, void *appdata); }; diff --git a/indra/newview/llappdelegate-objc.mm b/indra/newview/llappdelegate-objc.mm index 47fde299c7..aeb3294f53 100644 --- a/indra/newview/llappdelegate-objc.mm +++ b/indra/newview/llappdelegate-objc.mm @@ -66,6 +66,7 @@ constructViewer(); #if defined(LL_BUGSPLAT) + infos("bugsplat setup"); // Engage BugsplatStartupManager *before* calling initViewer() to handle // any crashes during initialization. // https://www.bugsplat.com/docs/platforms/os-x#initialization @@ -74,6 +75,7 @@ [BugsplatStartupManager sharedManager].delegate = self; [[BugsplatStartupManager sharedManager] start]; #endif + infos("post-bugsplat setup"); frameTimer = nil; @@ -134,6 +136,7 @@ // called again. Since it returned false, do not yet cancel // frameTimer. handleQuit(); + [[NSApplication sharedApplication] stopModal]; return NSTerminateCancel; } else { // pumpMainLoop() returned true: it's done. Okay, done with frameTimer. @@ -294,14 +297,19 @@ struct AttachmentInfo std::vector<AttachmentInfo> info{ AttachmentInfo(metadata.logFilePathname, "text/plain"), AttachmentInfo(metadata.userSettingsPathname, "text/xml"), + AttachmentInfo(metadata.accountSettingsPathname, "text/xml"), AttachmentInfo(metadata.staticDebugPathname, "text/xml") }; // We "happen to know" that info[0].basename is "SecondLife.old" -- due to // the fact that BugsplatMac only notices a crash during the viewer run - // following the crash. Replace .old with .log to reduce confusion. + // following the crash. + // The Bugsplat service doesn't respect the MIME type above when returning + // the log data to a browser, so take this opportunity to rename the file + // from <base>.old to <base>_log.txt info[0].basename = - boost::filesystem::path(info[0].pathname).stem().string() + ".log"; + boost::filesystem::path(info[0].pathname).stem().string() + "_log.txt"; + infos("attachmentsForBugsplatStartupManager attaching log " + info[0].basename); NSMutableArray *attachments = [[NSMutableArray alloc] init]; diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 22bcbad7da..9fc2e9ead8 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -148,7 +148,7 @@ public: { // 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")) + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableAppearance")) { LLNotificationsUtil::add("NoAppearance", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); return true; @@ -1029,14 +1029,13 @@ void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_cb,_1,type,wearable,this)); - create_inventory_item(gAgent.getID(), + create_inventory_wearable(gAgent.getID(), gAgent.getSessionID(), lost_and_found_id, wearable->getTransactionID(), wearable->getName(), wearable->getDescription(), wearable->getAssetType(), - LLInventoryType::IT_WEARABLE, wearable->getType(), wearable->getPermissions().getMaskNextOwner(), cb); @@ -1713,6 +1712,24 @@ void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_ LLInventoryModel::item_array_t* items; LLSD contents = LLSD::emptyArray(); gInventory.getDirectDescendentsOf(src_id, cats, items); + if (!cats || !items) + { + // 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). + LLViewerInventoryCategory* category = gInventory.getCategory(src_id); + if (category) + { + LL_WARNS() << "Category '" << category->getName() << "' descendents corrupted, linking content failed." << LL_ENDL; + } + else + { + LL_WARNS() << "Category could not be retrieved, linking content failed." << LL_ENDL; + } + llassert(cats != NULL && items != NULL); + + return; + } + LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); iter != items->end(); @@ -1940,7 +1957,7 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) } // Moved from LLWearableList::ContextMenu for wider utility. -bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids) +bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids) const { // TODO: investigate wearables may not be loaded at this point EXT-8231 @@ -1950,7 +1967,7 @@ bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids) // 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 = gInventory.getItem(*it); + const LLViewerInventoryItem* item = gInventory.getItem(*it); if (!item) { return false; @@ -2911,7 +2928,7 @@ void LLAppearanceMgr::removeAllAttachmentsFromAvatar() attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - LLViewerObject *attached_object = (*attachment_iter); + LLViewerObject *attached_object = attachment_iter->get(); if (attached_object) { objects_to_remove.push_back(attached_object); @@ -3261,6 +3278,50 @@ void update_base_outfit_after_ordering() bool copy_folder_links = false; app_mgr.slamCategoryLinks(app_mgr.getCOF(), base_outfit_id, copy_folder_links, dirty_state_updater); + if (base_outfit_id.notNull()) + { + LLIsValidItemLink collector; + + LLInventoryModel::cat_array_t cof_cats; + LLInventoryModel::item_array_t cof_item_array; + gInventory.collectDescendentsIf(app_mgr.getCOF(), cof_cats, cof_item_array, + LLInventoryModel::EXCLUDE_TRASH, collector); + + for (U32 i = 0; i < outfit_item_array.size(); ++i) + { + LLViewerInventoryItem* linked_item = outfit_item_array.at(i)->getLinkedItem(); + if (linked_item != NULL && linked_item->getActualType() == LLAssetType::AT_TEXTURE) + { + outfit_item_array.erase(outfit_item_array.begin() + i); + break; + } + } + + if (outfit_item_array.size() != cof_item_array.size()) + { + return; + } + + std::sort(cof_item_array.begin(), cof_item_array.end(), sort_by_linked_uuid); + std::sort(outfit_item_array.begin(), outfit_item_array.end(), sort_by_linked_uuid); + + for (U32 i = 0; i < cof_item_array.size(); ++i) + { + LLViewerInventoryItem *cof_it = cof_item_array.at(i); + LLViewerInventoryItem *base_it = outfit_item_array.at(i); + + if (cof_it->getActualDescription() != base_it->getActualDescription()) + { + if (cof_it->getLinkedUUID() == base_it->getLinkedUUID()) + { + base_it->setDescription(cof_it->getActualDescription()); + gInventory.updateItem(base_it); + } + } + } + LLAppearanceMgr::getInstance()->updateIsDirty(); + } + } // Save COF changes - update the contents of the current base outfit @@ -3565,6 +3626,10 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd } llcoro::suspend(); + if (LLApp::isExiting()) + { + return; + } S32 retryCount(0); bool bRetry; do @@ -3628,6 +3693,11 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData); + if (LLApp::isExiting()) + { + return; + } + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); @@ -3663,6 +3733,10 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd LL_WARNS("Avatar") << "Bake retry #" << retryCount << " in " << timeout << " seconds." << LL_ENDL; llcoro::suspendUntilTimeout(timeout); + if (LLApp::isExiting()) + { + return; + } bRetry = true; continue; } diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index c274a8b049..8a55a848db 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -101,7 +101,7 @@ public: bool getCanReplaceCOF(const LLUUID& outfit_cat_id); // Can we add all referenced items to the avatar? - bool canAddWearables(const uuid_vec_t& item_ids); + bool canAddWearables(const uuid_vec_t& item_ids) const; // Copy all items in a category. void shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id, diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index c8dcbb87c1..69606793db 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -33,6 +33,7 @@ #include "llfeaturemanager.h" #include "lluictrlfactory.h" #include "lltexteditor.h" +#include "llenvironment.h" #include "llerrorcontrol.h" #include "lleventtimer.h" #include "llviewertexturelist.h" @@ -48,6 +49,7 @@ #include "llwindow.h" #include "llviewerstats.h" #include "llviewerstatsrecorder.h" +#include "llkeyconflict.h" // for legacy keybinding support, remove later #include "llmarketplacefunctions.h" #include "llmarketplacenotifications.h" #include "llmd5.h" @@ -57,18 +59,23 @@ #include "llslurl.h" #include "llstartup.h" #include "llfocusmgr.h" +#include "llurlfloaterdispatchhandler.h" #include "llviewerjoystick.h" #include "llallocator.h" #include "llcalc.h" #include "llconversationlog.h" +#if LL_WINDOWS #include "lldxhardware.h" +#endif #include "lltexturestats.h" #include "lltrace.h" #include "lltracethreadrecorder.h" #include "llviewerwindow.h" #include "llviewerdisplay.h" #include "llviewermedia.h" +#include "llviewerparcelaskplay.h" #include "llviewerparcelmedia.h" +#include "llviewershadermgr.h" #include "llviewermediafocus.h" #include "llviewermessage.h" #include "llviewerobjectlist.h" @@ -84,6 +91,7 @@ #include "llsdutil_math.h" #include "lllocationhistory.h" #include "llfasttimerview.h" +#include "lltelemetry.h" #include "llvector4a.h" #include "llviewermenufile.h" #include "llvoicechannel.h" @@ -100,7 +108,6 @@ #include "llscenemonitor.h" #include "llavatarrenderinfoaccountant.h" #include "lllocalbitmaps.h" -#include "llskinningutil.h" // Linden library includes #include "llavatarnamecache.h" @@ -126,7 +133,7 @@ #include "llcoros.h" #include "llexception.h" #if !LL_LINUX -#include "cef/dullahan.h" +#include "cef/dullahan_version.h" #include "vlc/libvlc_version.h" #endif // LL_LINUX @@ -146,7 +153,7 @@ #include "llapr.h" #include <boost/lexical_cast.hpp> -#include "llviewerkeyboard.h" +#include "llviewerinput.h" #include "lllfsthread.h" #include "llworkerthread.h" #include "lltexturecache.h" @@ -172,8 +179,6 @@ #include "llviewerparcelmgr.h" #include "llworldmapview.h" #include "llpostprocess.h" -#include "llwlparammanager.h" -#include "llwaterparammanager.h" #include "lldebugview.h" #include "llconsole.h" @@ -209,6 +214,7 @@ #include "llfloateroutfitsnapshot.h" #include "llfloatersnapshot.h" #include "llsidepanelinventory.h" +#include "llatmosphere.h" // includes for idle() idleShutdown() #include "llviewercontrol.h" @@ -252,9 +258,9 @@ // define a self-registering event API object #include "llappviewerlistener.h" -#if (LL_LINUX || LL_SOLARIS) && LL_GTK +#if LL_LINUX && LL_GTK #include "glib.h" -#endif // (LL_LINUX || LL_SOLARIS) && LL_GTK +#endif // (LL_LINUX) && LL_GTK #if LL_MSVC // disable boost::lexical_cast warning @@ -283,7 +289,7 @@ extern BOOL gHiDPISupport; //////////////////////////////////////////////////////////// // All from the last globals push... -F32 gSimLastTime; // Used in LLAppViewer::init and send_stats() +F32 gSimLastTime; // Used in LLAppViewer::init and send_viewer_stats() F32 gSimFrames; BOOL gShowObjectUpdates = FALSE; @@ -524,7 +530,8 @@ bool create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* base) LLIconCtrl* icon; - if(gAgent.isInGroup(match_id, TRUE)) + if( match->getMenuName() == "menu_url_group.xml" // See LLUrlEntryGroup constructor + || gAgent.isInGroup(match_id, TRUE)) //This check seems unfiting, urls are either /agent or /group { LLGroupIconCtrl::Params icon_params; icon_params.group_id = match_id; @@ -602,8 +609,9 @@ static void settings_to_globals() static void settings_modify() { LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderDeferred"); + LLPipeline::sRenderTransparentWater = gSavedSettings.getBOOL("RenderTransparentWater"); LLPipeline::sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); - LLPipeline::sRenderDeferred = LLPipeline::sRenderBump && gSavedSettings.getBOOL("RenderDeferred"); + LLPipeline::sRenderDeferred = LLPipeline::sRenderTransparentWater && LLPipeline::sRenderBump && gSavedSettings.getBOOL("RenderDeferred"); LLVOSurfacePatch::sLODFactor = gSavedSettings.getF32("RenderTerrainLODFactor"); LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4] gDebugGL = gSavedSettings.getBOOL("RenderDebugGL") || gDebugSession; @@ -671,8 +679,10 @@ LLAppViewer::LLAppViewer() mReportedCrash(false), mNumSessions(0), mPurgeCache(false), - mPurgeOnExit(false), + mPurgeCacheOnExit(false), + mPurgeUserDataOnExit(false), mSecondInstance(false), + mUpdaterNotFound(false), mSavedFinalSnapshot(false), mSavePerAccountSettings(false), // don't save settings on logout unless login succeeded. mQuitRequested(false), @@ -720,16 +730,16 @@ LLAppViewer::LLAppViewer() // from the previous viewer run between this constructor call and the // init() call, which will overwrite the static_debug_info.log file for // THIS run. So setDebugFileNames() early. -#if LL_BUGSPLAT +# ifdef LL_BUGSPLAT // MAINT-8917: don't create a dump directory just for the // static_debug_info.log file std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); -#else // ! LL_BUGSPLAT +# else // ! LL_BUGSPLAT // write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues. std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); -#endif // ! LL_BUGSPLAT +# endif // ! LL_BUGSPLAT mDumpPath = logdir; - setMiniDumpDir(logdir); + setDebugFileNames(logdir); } @@ -752,17 +762,6 @@ public: } }; -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); -} - - -} - bool LLAppViewer::init() { @@ -774,7 +773,11 @@ bool LLAppViewer::init() // initialize LLWearableType translation bridge. // Memory will be cleaned up in ::cleanupClass() - LLWearableType::initClass(new LLUITranslationBridge()); + LLWearableType::initParamSingleton(new LLUITranslationBridge()); + + // initialize the LLSettingsType translation bridge. + LLTranslationBridge::ptr_t trans = std::make_shared<LLUITranslationBridge>(); + LLSettingsType::initParamSingleton(trans); // initialize SSE options LLVector4a::initClass(); @@ -798,9 +801,6 @@ bool LLAppViewer::init() LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ; - // initialize skinning util - LLSkinningUtil::initClass(); - //set the max heap size. initMaxHeapSize() ; LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize")); @@ -813,9 +813,9 @@ bool LLAppViewer::init() if (rc >= 0) { // QAModeTermCode set, terminate with that rc on LL_ERRS. Use - // fast_exit() rather than exit() because normal cleanup depends too + // _exit() rather than exit() because normal cleanup depends too // much on successful startup! - LLError::setFatalFunction(boost::bind(fast_exit, rc)); + LLError::setFatalFunction([rc](const std::string&){ _exit(rc); }); } mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); @@ -848,11 +848,10 @@ bool LLAppViewer::init() settings_map["floater"] = &gSavedSettings; // *TODO: New settings file settings_map["account"] = &gSavedPerAccountSettings; - LLUI::initClass(settings_map, + LLUI::initParamSingleton(settings_map, LLUIImageList::getInstance(), ui_audio_callback, - deferred_ui_audio_callback, - &LLUI::getScaleFactor()); + deferred_ui_audio_callback); LL_INFOS("InitInfo") << "UI initialized." << LL_ENDL ; // NOW LLUI::getLanguage() should work. gDirUtilp must know the language @@ -896,8 +895,6 @@ bool LLAppViewer::init() // LLKeyboard relies on LLUI to know what some accelerator keys are called. LLKeyboard::setStringTranslatorFunc( LLTrans::getKeyboardString ); - LLWeb::initClass(); // do this after LLUI - // Provide the text fields with callbacks for opening Urls LLUrlAction::setOpenURLCallback(boost::bind(&LLWeb::loadURL, _1, LLStringUtil::null, LLStringUtil::null)); LLUrlAction::setOpenURLInternalCallback(boost::bind(&LLWeb::loadURLInternal, _1, LLStringUtil::null, LLStringUtil::null, false)); @@ -905,12 +902,13 @@ bool LLAppViewer::init() LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor); // Let code in llui access the viewer help floater - LLUI::sHelpImpl = LLViewerHelp::getInstance(); + LLUI::getInstance()->mHelpImpl = LLViewerHelp::getInstance(); LL_INFOS("InitInfo") << "UI initialization is done." << LL_ENDL ; // Load translations for tooltips LLFloater::initClass(); + LLUrlFloaterDispatchHandler::registerInDispatcher(); ///////////////////////////////////////////////// @@ -1001,35 +999,32 @@ bool LLAppViewer::init() gGLManager.getGLInfo(gDebugInfo); gGLManager.printGLInfoString(); - // Load Default bindings - std::string key_bindings_file = gDirUtilp->findFile("keys.xml", - gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""), - gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - - - if (!gViewerKeyboard.loadBindingsXML(key_bindings_file)) - { - std::string key_bindings_file = gDirUtilp->findFile("keys.ini", - gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""), - gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - if (!gViewerKeyboard.loadBindings(key_bindings_file)) - { - LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL; - } - } - // If we don't have the right GL requirements, exit. if (!gGLManager.mHasRequirements) { // can't use an alert here since we're exiting and // all hell breaks lose. + LLUIString details = LLNotifications::instance().getGlobalString("UnsupportedGLRequirements"); OSMessageBox( - LLNotifications::instance().getGlobalString("UnsupportedGLRequirements"), + details.getString(), LLStringUtil::null, OSMB_OK); return 0; } + // If we don't have the right shader requirements. + if (!gGLManager.mHasShaderObjects + || !gGLManager.mHasVertexShader + || !gGLManager.mHasFragmentShader) + { + LLUIString details = LLNotifications::instance().getGlobalString("UnsupportedShaderRequirements"); + OSMessageBox( + details.getString(), + LLStringUtil::null, + OSMB_OK); + return 0; + } + // Without SSE2 support we will crash almost immediately, warn here. if (!gSysCPU.hasSSE2()) { @@ -1095,6 +1090,46 @@ bool LLAppViewer::init() } } +#if LL_WINDOWS && ADDRESS_SIZE == 64 + if (gGLManager.mIsIntel) + { + // Check intel driver's version + // Ex: "3.1.0 - Build 8.15.10.2559"; + std::string version = ll_safe_string((const char *)glGetString(GL_VERSION)); + + const boost::regex is_intel_string("[0-9].[0-9].[0-9] - Build [0-9]{1,2}.[0-9]{2}.[0-9]{2}.[0-9]{4}"); + + if (boost::regex_search(version, is_intel_string)) + { + // Valid string, extract driver version + std::size_t found = version.find("Build "); + std::string driver = version.substr(found + 6); + S32 v1, v2, v3, v4; + S32 count = sscanf(driver.c_str(), "%d.%d.%d.%d", &v1, &v2, &v3, &v4); + if (count > 0 && v1 <= 10) + { + LL_INFOS("AppInit") << "Detected obsolete intel driver: " << driver << LL_ENDL; + LLUIString details = LLNotifications::instance().getGlobalString("UnsupportedIntelDriver"); + std::string gpu_name = ll_safe_string((const char *)glGetString(GL_RENDERER)); + details.setArg("[VERSION]", driver); + details.setArg("[GPUNAME]", gpu_name); + S32 button = OSMessageBox(details.getString(), + LLStringUtil::null, + OSMB_YESNO); + if (OSBTN_YES == button && gViewerWindow) + { + std::string url = LLWeb::escapeURL(LLTrans::getString("IntelDriverPage")); + if (gViewerWindow->getWindow()) + { + gViewerWindow->getWindow()->spawnWebBrowser(url, false); + } + } + } + } + } +#endif + + // Obsolete? mExpectedGLVersion is always zero #if LL_WINDOWS if (gGLManager.mGLVersion < LLFeatureManager::getInstance()->getExpectedGLVersion()) { @@ -1125,94 +1160,127 @@ bool LLAppViewer::init() // Save the current version to the prefs file gSavedSettings.setString("LastRunVersion", - LLVersionInfo::getChannelAndVersion()); + LLVersionInfo::instance().getChannelAndVersion()); gSimLastTime = gRenderStartTime.getElapsedTimeF32(); gSimFrames = (F32)gFrameCount; - LLViewerJoystick::getInstance()->init(false); + if (gSavedSettings.getBOOL("JoystickEnabled")) + { + LLViewerJoystick::getInstance()->init(false); + } try { initializeSecHandler(); } - catch (LLProtectedDataException ex) + catch (LLProtectedDataException&) { LLNotificationsUtil::add("CorruptedProtectedDataStore"); } gGLActive = FALSE; +#if LL_RELEASE_FOR_DOWNLOAD + if (!gSavedSettings.getBOOL("CmdLineSkipUpdater")) + { LLProcess::Params updater; updater.desc = "updater process"; // Because it's the updater, it MUST persist beyond the lifespan of the // viewer itself. updater.autokill = false; + std::string updater_file; #if LL_WINDOWS - updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "SLVersionChecker.exe"); + updater_file = "SLVersionChecker.exe"; + updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, updater_file); #elif LL_DARWIN // explicitly run the system Python interpreter on SLVersionChecker.py updater.executable = "python"; - updater.args.add(gDirUtilp->add(gDirUtilp->getAppRODataDir(), "updater", "SLVersionChecker.py")); + updater_file = "SLVersionChecker.py"; + updater.args.add(gDirUtilp->add(gDirUtilp->getAppRODataDir(), "updater", updater_file)); #else - updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "SLVersionChecker"); + updater_file = "SLVersionChecker"; + updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, updater_file); #endif // add LEAP mode command-line argument to whichever of these we selected updater.args.add("leap"); // UpdaterServiceSettings - updater.args.add(stringize(gSavedSettings.getU32("UpdaterServiceSetting"))); + if (gSavedSettings.getBOOL("FirstLoginThisInstall")) + { + // Befor first login, treat this as 'manual' updates, + // updater won't install anything, but required updates + updater.args.add("0"); + } + else + { + updater.args.add(stringize(gSavedSettings.getU32("UpdaterServiceSetting"))); + } // channel - updater.args.add(LLVersionInfo::getChannel()); + updater.args.add(LLVersionInfo::instance().getChannel()); // testok updater.args.add(stringize(gSavedSettings.getBOOL("UpdaterWillingToTest"))); // ForceAddressSize updater.args.add(stringize(gSavedSettings.getU32("ForceAddressSize"))); -#if LL_WINDOWS && !LL_RELEASE_FOR_DOWNLOAD && !LL_SEND_CRASH_REPORTS - // This is neither a release package, nor crash-reporting enabled test build - // try to run version updater, but don't bother if it fails (file might be missing) - LLLeap *leap_p = LLLeap::create(updater, false); - if (!leap_p) - { - LL_WARNS("LLLeap") << "Failed to run LLLeap" << LL_ENDL; - } -#else - // Run the updater. An exception from launching the updater should bother us. - LLLeap::create(updater, true); -#endif - - // Iterate over --leap command-line options. But this is a bit tricky: if - // there's only one, it won't be an array at all. - LLSD LeapCommand(gSavedSettings.getLLSD("LeapCommand")); - LL_DEBUGS("InitInfo") << "LeapCommand: " << LeapCommand << LL_ENDL; - if (LeapCommand.isDefined() && ! LeapCommand.isArray()) - { - // If LeapCommand is actually a scalar value, make an array of it. - // Have to do it in two steps because LeapCommand.append(LeapCommand) - // trashes content! :-P - LLSD item(LeapCommand); - LeapCommand.append(item); + try + { + // Run the updater. An exception from launching the updater should bother us. + LLLeap::create(updater, true); + mUpdaterNotFound = false; + } + catch (...) + { + LLUIString details = LLNotifications::instance().getGlobalString("LLLeapUpdaterFailure"); + details.setArg("[UPDATER_APP]", updater_file); + OSMessageBox( + details.getString(), + LLStringUtil::null, + OSMB_OK); + mUpdaterNotFound = true; + } } - BOOST_FOREACH(const std::string& leap, llsd::inArray(LeapCommand)) + else { - LL_INFOS("InitInfo") << "processing --leap \"" << leap << '"' << LL_ENDL; - // We don't have any better description of this plugin than the - // user-specified command line. Passing "" causes LLLeap to derive a - // description from the command line itself. - // Suppress LLLeap::Error exception: trust LLLeap's own logging. We - // don't consider any one --leap command mission-critical, so if one - // fails, log it, shrug and carry on. - LLLeap::create("", leap, false); // exception=false + LL_WARNS("InitInfo") << "Skipping updater check." << LL_ENDL; } + if (mUpdaterNotFound) + { + LL_WARNS("InitInfo") << "Failed to launch updater. Skipping Leap commands." << LL_ENDL; + } + else + { + // Iterate over --leap command-line options. But this is a bit tricky: if + // there's only one, it won't be an array at all. + LLSD LeapCommand(gSavedSettings.getLLSD("LeapCommand")); + LL_DEBUGS("InitInfo") << "LeapCommand: " << LeapCommand << LL_ENDL; + if (LeapCommand.isDefined() && !LeapCommand.isArray()) + { + // If LeapCommand is actually a scalar value, make an array of it. + // Have to do it in two steps because LeapCommand.append(LeapCommand) + // trashes content! :-P + LLSD item(LeapCommand); + LeapCommand.append(item); + } + BOOST_FOREACH(const std::string& leap, llsd::inArray(LeapCommand)) + { + LL_INFOS("InitInfo") << "processing --leap \"" << leap << '"' << LL_ENDL; + // We don't have any better description of this plugin than the + // user-specified command line. Passing "" causes LLLeap to derive a + // description from the command line itself. + // Suppress LLLeap::Error exception: trust LLLeap's own logging. We + // don't consider any one --leap command mission-critical, so if one + // fails, log it, shrug and carry on. + LLLeap::create("", leap, false); // exception=false + } + } + if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getS32("QAModeEventHostPort") > 0) { LL_WARNS("InitInfo") << "QAModeEventHostPort DEPRECATED: " << "lleventhost no longer supported as a dynamic library" << LL_ENDL; } - - LLViewerMedia::initClass(); - LL_INFOS("InitInfo") << "Viewer media initialized." << LL_ENDL ; +#endif //LL_RELEASE_FOR_DOWNLOAD LLTextUtil::TextHelpers::iconCallbackCreationFunction = create_text_segment_icon_from_url_match; @@ -1253,7 +1321,7 @@ bool LLAppViewer::init() // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated. LLVoiceChannel::initClass(); - LLVoiceClient::getInstance()->init(gServicePump); + LLVoiceClient::initParamSingleton(gServicePump); LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLFloaterIMContainer::onCurrentChannelChanged, _1), true); joystick = LLViewerJoystick::getInstance(); @@ -1263,6 +1331,9 @@ bool LLAppViewer::init() gSavedSettings.getControl("FramePerSecondLimit")->getSignal()->connect(boost::bind(&LLAppViewer::onChangeFrameLimit, this, _2)); onChangeFrameLimit(gSavedSettings.getLLSD("FramePerSecondLimit")); + // Load User's bindings + loadKeyBindings(); + return true; } @@ -1283,39 +1354,8 @@ void LLAppViewer::initMaxHeapSize() //F32 max_heap_size_gb = llmin(1.6f, (F32)gSavedSettings.getF32("MaxHeapSize")) ; F32Gigabytes max_heap_size_gb = (F32Gigabytes)gSavedSettings.getF32("MaxHeapSize") ; - BOOL enable_mem_failure_prevention = (BOOL)gSavedSettings.getBOOL("MemoryFailurePreventionEnabled") ; - - LLMemory::initMaxHeapSizeGB(max_heap_size_gb, enable_mem_failure_prevention) ; -} - -void LLAppViewer::checkMemory() -{ - const static F32 MEMORY_CHECK_INTERVAL = 1.0f ; //second - //const static F32 MAX_QUIT_WAIT_TIME = 30.0f ; //seconds - //static F32 force_quit_timer = MAX_QUIT_WAIT_TIME + MEMORY_CHECK_INTERVAL ; - - if(!gGLManager.mDebugGPU) - { - return ; - } - - if(MEMORY_CHECK_INTERVAL > mMemCheckTimer.getElapsedTimeF32()) - { - return ; - } - mMemCheckTimer.reset() ; - - //update the availability of memory - LLMemory::updateMemoryInfo() ; - bool is_low = LLMemory::isMemoryPoolLow() ; - - LLPipeline::throttleNewMemoryAllocation(is_low) ; - - if(is_low) - { - LLMemory::logMemoryInfo() ; - } + LLMemory::initMaxHeapSizeGB(max_heap_size_gb); } static LLTrace::BlockTimerStatHandle FTM_MESSAGES("System Messages"); @@ -1324,6 +1364,8 @@ 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_FETCH("Image Fetch"); + static LLTrace::BlockTimerStatHandle FTM_VFS("VFS Thread"); static LLTrace::BlockTimerStatHandle FTM_LFS("LFS Thread"); static LLTrace::BlockTimerStatHandle FTM_PAUSE_THREADS("Pause Threads"); @@ -1351,7 +1393,7 @@ bool LLAppViewer::frame() { LOG_UNHANDLED_EXCEPTION(""); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { LLMemory::logMemoryInfo(TRUE); LLFloaterMemLeak* mem_leak_instance = LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking"); @@ -1392,9 +1434,6 @@ bool LLAppViewer::doFrame() //clear call stack records LL_CLEAR_CALLSTACKS(); - //check memory availability information - checkMemory() ; - { pingMainloopTimeout("Main:MiscNativeWindowEvents"); @@ -1430,6 +1469,8 @@ bool LLAppViewer::doFrame() // canonical per-frame event mainloop.post(newFrame); + // give listeners a chance to run + llcoro::suspend(); if (!LLApp::isExiting()) { @@ -1448,6 +1489,7 @@ bool LLAppViewer::doFrame() { joystick->scanJoystick(); gKeyboard->scanKeyboard(); + gViewerInput.scanMouse(); } // Update state based on messages, user input, object idle. @@ -1475,10 +1517,12 @@ bool LLAppViewer::doFrame() pingMainloopTimeout("Main:Display"); gGLActive = TRUE; + display(); + static U64 last_call = 0; if (!gTeleportDisplay) { - // Frame/draw throttling + // Frame/draw throttling, controlled by FramePerSecondLimit U64 elapsed_time = LLTimer::getTotalTime() - last_call; if (elapsed_time < mMinMicroSecPerFrame) { @@ -1490,8 +1534,6 @@ bool LLAppViewer::doFrame() } last_call = LLTimer::getTotalTime(); - display(); - pingMainloopTimeout("Main:Snapshot"); LLFloaterSnapshot::update(); // take snapshots LLFloaterOutfitSnapshot::update(); @@ -1516,8 +1558,10 @@ bool LLAppViewer::doFrame() } // yield cooperatively when not running as foreground window - if ( (gViewerWindow && !gViewerWindow->getWindow()->getVisible()) - || !gFocusMgr.getAppHasFocus()) + // and when not quiting (causes trouble at mac's cleanup stage) + if (!LLApp::isExiting() + && ((gViewerWindow && !gViewerWindow->getWindow()->getVisible()) + || !gFocusMgr.getAppHasFocus())) { // Sleep if we're not rendering, or the window is minimized. static LLCachedControl<S32> s_bacground_yeild_time(gSavedSettings, "BackgroundYieldTime", 40); @@ -1617,12 +1661,15 @@ bool LLAppViewer::doFrame() } delete gServicePump; + gServicePump = NULL; destroyMainloopTimeout(); LL_INFOS() << "Exiting main_loop" << LL_ENDL; } + LLPROFILE_UPDATE(); + return ! LLApp::isRunning(); } @@ -1638,7 +1685,7 @@ S32 LLAppViewer::updateTextureThreads(F32 max_time) work_pending += LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread } { - LL_RECORD_BLOCK_TIME(FTM_DECODE); + LL_RECORD_BLOCK_TIME(FTM_FETCH); work_pending += LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread } return work_pending; @@ -1661,6 +1708,8 @@ void LLAppViewer::flushVFSIO() bool LLAppViewer::cleanup() { + LLAtmosphere::cleanupClass(); + //ditch LLVOAvatarSelf instance gAgentAvatarp = NULL; @@ -1672,7 +1721,11 @@ bool LLAppViewer::cleanup() //dump scene loading monitor results if (LLSceneMonitor::instanceExists()) { - LLSceneMonitor::instance().dumpToFile(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "scene_monitor_results.csv")); + if (!isSecondInstance()) + { + LLSceneMonitor::instance().dumpToFile(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "scene_monitor_results.csv")); + } + LLSceneMonitor::deleteSingleton(); } // There used to be an 'if (LLFastTimerView::sAnalyzePerformance)' block @@ -1689,24 +1742,9 @@ bool LLAppViewer::cleanup() gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp"); } - { - // Kill off LLLeap objects. We can find them all because LLLeap is derived - // from LLInstanceTracker. But collect instances first: LLInstanceTracker - // specifically forbids adding/deleting instances while iterating. - std::vector<LLLeap*> leaps; - leaps.reserve(LLLeap::instanceCount()); - for (LLLeap::instance_iter li(LLLeap::beginInstances()), lend(LLLeap::endInstances()); - li != lend; ++li) - { - leaps.push_back(&*li); - } - // Okay, now trash them all. We don't have to NULL or erase the entry - // in 'leaps' because the whole vector is going away momentarily. - BOOST_FOREACH(LLLeap* leap, leaps) - { - delete leap; - } - } // destroy 'leaps' + // Kill off LLLeap objects. We can find them all because LLLeap is derived + // from LLInstanceTracker. + LLLeap::instance_snapshot().deleteAll(); //flag all elements as needing to be destroyed immediately // to ensure shutdown order @@ -1718,6 +1756,11 @@ bool LLAppViewer::cleanup() disconnectViewer(); LL_INFOS() << "Viewer disconnected" << LL_ENDL; + + if (gKeyboard) + { + gKeyboard->resetKeys(); + } display_cleanup(); @@ -1750,8 +1793,6 @@ bool LLAppViewer::cleanup() gTransferManager.cleanup(); #endif - SUBSYSTEM_CLEANUP(LLLocalBitmapMgr); - // Note: this is where gWorldMap used to be deleted. // Note: this is where gHUDManager used to be deleted. @@ -1857,8 +1898,11 @@ bool LLAppViewer::cleanup() delete gKeyboard; gKeyboard = NULL; - // Turn off Space Navigator and similar devices - LLViewerJoystick::getInstance()->terminate(); + if (LLViewerJoystick::instanceExists()) + { + // Turn off Space Navigator and similar devices + LLViewerJoystick::getInstance()->terminate(); + } LL_INFOS() << "Cleaning up Objects" << LL_ENDL; @@ -1866,8 +1910,6 @@ bool LLAppViewer::cleanup() SUBSYSTEM_CLEANUP(LLAvatarAppearance); - SUBSYSTEM_CLEANUP(LLAvatarAppearance); - SUBSYSTEM_CLEANUP(LLPostProcess); LLTracker::cleanupInstance(); @@ -1894,12 +1936,9 @@ bool LLAppViewer::cleanup() //end_messaging_system(); - SUBSYSTEM_CLEANUP(LLFollowCamMgr); - //SUBSYSTEM_CLEANUP(LLVolumeMgr); LLPrimitive::cleanupVolumeManager(); SUBSYSTEM_CLEANUP(LLWorldMapView); SUBSYSTEM_CLEANUP(LLFolderViewItem); - SUBSYSTEM_CLEANUP(LLUI); // // Shut down the VFS's AFTER the decode manager cleans up (since it cleans up vfiles). @@ -1915,6 +1954,12 @@ bool LLAppViewer::cleanup() // Store the time of our current logoff gSavedPerAccountSettings.setU32("LastLogoff", time_corrected()); + if (LLEnvironment::instanceExists()) + { + //Store environment settings if nessesary + LLEnvironment::getInstance()->saveToSettings(); + } + // Must do this after all panels have been deleted because panels that have persistent rects // save their rects on delete. gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); @@ -1938,6 +1983,11 @@ bool LLAppViewer::cleanup() { gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); LL_INFOS() << "Saved settings" << LL_ENDL; + + if (LLViewerParcelAskPlay::instanceExists()) + { + LLViewerParcelAskPlay::getInstance()->saveSettings(); + } } std::string warnings_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Warnings")); @@ -1956,9 +2006,11 @@ bool LLAppViewer::cleanup() if (LLConversationLog::instanceExists()) { LLConversationLog::instance().cache(); - } + } - if (mPurgeOnExit) + clearSecHandler(); + + if (mPurgeCacheOnExit) { LL_INFOS() << "Purging all cache files on exit" << LL_ENDL; gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), "*.*"); @@ -1999,6 +2051,14 @@ bool LLAppViewer::cleanup() } } + if (mPurgeUserDataOnExit) + { + // Ideally we should not save anything from this session since it is going to be purged now, + // but this is a very 'rare' case (user deleting himself), not worth overcomplicating 'save&cleanup' code + std::string user_path = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter() + LLStartUp::getUserId(); + gDirUtilp->deleteDirAndContents(user_path); + } + // Delete workers first // shotdown all worker threads before deleting them in case of co-dependencies mAppCoreHttp.requestStop(); @@ -2049,8 +2109,6 @@ bool LLAppViewer::cleanup() //Note: //SUBSYSTEM_CLEANUP(LLViewerMedia) has to be put before gTextureList.shutdown() //because some new image might be generated during cleaning up media. --bao - SUBSYSTEM_CLEANUP(LLViewerMedia); - SUBSYSTEM_CLEANUP(LLViewerParcelMedia); gTextureList.shutdown(); // shutdown again in case a callback added something LLUIImageList::getInstance()->cleanUp(); @@ -2099,66 +2157,36 @@ bool LLAppViewer::cleanup() LLWeb::loadURLExternal( gLaunchFileOnQuit, false ); LL_INFOS() << "File launched." << LL_ENDL; } + // make sure nothing uses applyProxySettings by this point. LL_INFOS() << "Cleaning up LLProxy." << LL_ENDL; SUBSYSTEM_CLEANUP(LLProxy); LLCore::LLHttp::cleanup(); - SUBSYSTEM_CLEANUP(LLWearableType); - LLMainLoopRepeater::instance().stop(); ll_close_fail_log(); LLError::LLCallStacks::cleanup(); - removeMarkerFiles(); - - // It's not at first obvious where, in this long sequence, generic cleanup - // calls OUGHT to go. So let's say this: as we migrate cleanup from + // It's not at first obvious where, in this long sequence, a generic cleanup + // call OUGHT to go. So let's say this: as we migrate cleanup from // explicit hand-placed calls into the generic mechanism, eventually - // all cleanup will get subsumed into the generic calls. So the calls you + // all cleanup will get subsumed into the generic call. So the calls you // still see above are calls that MUST happen before the generic cleanup // kicks in. - // This calls every remaining LLSingleton's cleanupSingleton() method. - // This method should perform any cleanup that might take significant - // realtime, or might throw an exception. - LLSingletonBase::cleanupAll(); - - // The logging subsystem depends on an LLSingleton. Any logging after - // LLSingletonBase::deleteAll() won't be recorded. - LL_INFOS() << "Goodbye!" << LL_ENDL; - - // This calls every remaining LLSingleton's deleteSingleton() method. - // No class destructor should perform any cleanup that might take - // significant realtime, or throw an exception. + // This calls every remaining LLSingleton's cleanupSingleton() and + // deleteSingleton() methods. LLSingletonBase::deleteAll(); + LL_INFOS() << "Goodbye!" << LL_ENDL; + removeDumpDir(); // return 0; return true; } -// 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); -#else - raise(SIGQUIT); -#endif -} - -// A callback for the watchdog to call. -void watchdog_killer_callback() -{ - LLError::setFatalFunction(watchdog_llerrs_callback); - LL_ERRS() << "Watchdog killer event" << LL_ENDL; -} - bool LLAppViewer::initThreads() { static const bool enable_threads = true; @@ -2193,22 +2221,23 @@ bool LLAppViewer::initThreads() return true; } -void errorCallback(const std::string &error_string) +void errorCallback(LLError::ELevel level, const std::string &error_string) { + if (level == LLError::LEVEL_ERROR) + { #ifndef LL_RELEASE_FOR_DOWNLOAD - OSMessageBox(error_string, LLTrans::getString("MBFatalError"), OSMB_OK); + OSMessageBox(error_string, LLTrans::getString("MBFatalError"), OSMB_OK); #endif - //Set the ErrorActivated global so we know to create a marker file - gLLErrorActivated = true; + //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); + 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(); + } } void LLAppViewer::initLoggingAndGetLastDuration() @@ -2219,7 +2248,7 @@ void LLAppViewer::initLoggingAndGetLastDuration() LLError::initForApplication( gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "") ,gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "") ); - LLError::setFatalFunction(errorCallback); + LLError::addGenericRecorder(&errorCallback); //LLError::setTimeFunction(getRuntime); // Remove the last ".old" log file. @@ -2639,7 +2668,7 @@ bool LLAppViewer::initConfiguration() std::string CmdLineChannel(gSavedSettings.getString("CmdLineChannel")); if(! CmdLineChannel.empty()) { - LLVersionInfo::resetChannel(CmdLineChannel); + LLVersionInfo::instance().resetChannel(CmdLineChannel); } // If we have specified crash on startup, set the global so we'll trigger the crash at the right time @@ -2860,12 +2889,11 @@ bool LLAppViewer::initConfiguration() // Let anyone else who cares know that we've populated our settings // variables. - for (LLControlGroup::key_iter ki(LLControlGroup::beginKeys()), kend(LLControlGroup::endKeys()); - ki != kend; ++ki) + for (const auto& key : LLControlGroup::key_snapshot()) { // For each named instance of LLControlGroup, send an event saying // we've initialized an LLControlGroup instance by that name. - LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", *ki)); + LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", key)); } return true; // Config was successful. @@ -2979,11 +3007,16 @@ bool LLAppViewer::initWindow() use_watchdog = bool(watchdog_enabled_setting); } + LL_INFOS("AppInit") << "watchdog" + << (use_watchdog ? " " : " NOT ") + << "enabled" + << " (setting = " << watchdog_enabled_setting << ")" + << LL_ENDL; + if (use_watchdog) { - LLWatchdog::getInstance()->init(watchdog_killer_callback); + LLWatchdog::getInstance()->init(); } - LL_INFOS("AppInit") << "watchdog setting is done." << LL_ENDL; LLNotificationsUI::LLNotificationManager::getInstance(); @@ -3047,7 +3080,7 @@ bool LLAppViewer::initWindow() gViewerWindow->getWindow()->maximize(); } - LLUI::sWindow = gViewerWindow->getWindow(); + LLUI::getInstance()->mWindow = gViewerWindow->getWindow(); // Show watch cursor gViewerWindow->setCursor(UI_CURSOR_WAIT); @@ -3085,16 +3118,12 @@ LLSD LLAppViewer::getViewerInfo() const // is available to a getInfo() caller as to the user opening // LLFloaterAbout. LLSD info; - LLSD version; - version.append(LLVersionInfo::getMajor()); - version.append(LLVersionInfo::getMinor()); - version.append(LLVersionInfo::getPatch()); - version.append(LLVersionInfo::getBuild()); - info["VIEWER_VERSION"] = version; - info["VIEWER_VERSION_STR"] = LLVersionInfo::getVersion(); - info["CHANNEL"] = LLVersionInfo::getChannel(); + auto& versionInfo(LLVersionInfo::instance()); + info["VIEWER_VERSION"] = LLSDArray(versionInfo.getMajor())(versionInfo.getMinor())(versionInfo.getPatch())(versionInfo.getBuild()); + info["VIEWER_VERSION_STR"] = versionInfo.getVersion(); + info["CHANNEL"] = versionInfo.getChannel(); info["ADDRESS_SIZE"] = ADDRESS_SIZE; - std::string build_config = LLVersionInfo::getBuildConfig(); + std::string build_config = versionInfo.getBuildConfig(); if (build_config != "Release") { info["BUILD_CONFIG"] = build_config; @@ -3102,11 +3131,14 @@ LLSD LLAppViewer::getViewerInfo() const // return a URL to the release notes for this viewer, such as: // https://releasenotes.secondlife.com/viewer/2.1.0.123456.html - std::string url = LLTrans::getString("RELEASE_NOTES_BASE_URL"); - if (! LLStringUtil::endsWith(url, "/")) - url += "/"; - url += LLURI::escape(LLVersionInfo::getVersion()) + ".html"; - + std::string url = versionInfo.getReleaseNotes(); // VVM supplied + if (url.empty()) + { + url = LLTrans::getString("RELEASE_NOTES_BASE_URL"); + if (!LLStringUtil::endsWith(url, "/")) + url += "/"; + url += LLURI::escape(versionInfo.getVersion()) + ".html"; + } info["VIEWER_RELEASE_NOTES_URL"] = url; // Position @@ -3117,8 +3149,9 @@ LLSD LLAppViewer::getViewerInfo() const info["POSITION"] = ll_sd_from_vector3d(pos); info["POSITION_LOCAL"] = ll_sd_from_vector3(gAgent.getPosAgentFromGlobal(pos)); info["REGION"] = gAgent.getRegion()->getName(); - info["HOSTNAME"] = gAgent.getRegion()->getHost().getHostName(); - info["HOSTIP"] = gAgent.getRegion()->getHost().getString(); + + boost::regex regex("\\.(secondlife|lindenlab)\\..*"); + info["HOSTNAME"] = boost::regex_replace(gAgent.getRegion()->getSimHostName(), regex, ""); info["SERVER_VERSION"] = gLastVersionChannel; LLSLURL slurl; LLAgentUI::buildSLURL(slurl); @@ -3130,8 +3163,8 @@ LLSD LLAppViewer::getViewerInfo() const info["MEMORY_MB"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().valueInUnits<LLUnits::Megabytes>()); // Moved hack adjustment to Windows memory size into llsys.cpp info["OS_VERSION"] = LLOSInfo::instance().getOSString(); - info["GRAPHICS_CARD_VENDOR"] = (const char*)(glGetString(GL_VENDOR)); - info["GRAPHICS_CARD"] = (const char*)(glGetString(GL_RENDERER)); + info["GRAPHICS_CARD_VENDOR"] = ll_safe_string((const char*)(glGetString(GL_VENDOR))); + info["GRAPHICS_CARD"] = ll_safe_string((const char*)(glGetString(GL_RENDERER))); #if LL_WINDOWS std::string drvinfo = gDXHardware.getDriverVersionWMI(); @@ -3150,7 +3183,7 @@ LLSD LLAppViewer::getViewerInfo() const } #endif - info["OPENGL_VERSION"] = (const char*)(glGetString(GL_VERSION)); + info["OPENGL_VERSION"] = ll_safe_string((const char*)(glGetString(GL_VERSION))); // Settings @@ -3198,12 +3231,16 @@ LLSD LLAppViewer::getViewerInfo() const cef_ver_codec << "."; cef_ver_codec << DULLAHAN_VERSION_MINOR; cef_ver_codec << "."; + cef_ver_codec << DULLAHAN_VERSION_POINT; + cef_ver_codec << "."; cef_ver_codec << DULLAHAN_VERSION_BUILD; - cef_ver_codec << " / CEF: "; + cef_ver_codec << std::endl; + cef_ver_codec << " CEF: "; cef_ver_codec << CEF_VERSION; - cef_ver_codec << " / Chromium: "; + cef_ver_codec << std::endl; + cef_ver_codec << " Chromium: "; cef_ver_codec << CHROME_VERSION_MAJOR; cef_ver_codec << "."; cef_ver_codec << CHROME_VERSION_MINOR; @@ -3396,12 +3433,12 @@ void LLAppViewer::writeSystemInfo() gDebugInfo["SLLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.old"); //LLError::logFileName(); #endif - 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"] = LLVersionInfo::getAddressSize(); + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); + gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); + gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); + gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); + gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::instance().getBuild(); + gDebugInfo["ClientInfo"]["AddressSize"] = LLVersionInfo::instance().getAddressSize(); gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); @@ -3412,8 +3449,8 @@ void LLAppViewer::writeSystemInfo() gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE(); gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2(); - gDebugInfo["RAMInfo"]["Physical"] = (LLSD::Integer)(gSysMemory.getPhysicalMemoryKB().value()); - gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer)(gMemoryAllocated.valueInUnits<LLUnits::Kilobytes>()); + gDebugInfo["RAMInfo"]["Physical"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().value()); + gDebugInfo["RAMInfo"]["Allocated"] = LLSD::Integer(gMemoryAllocated.valueInUnits<LLUnits::Kilobytes>()); gDebugInfo["OSInfo"] = LLOSInfo::instance().getOSStringSimple(); // The user is not logged on yet, but record the current grid choice login url @@ -3426,12 +3463,18 @@ void LLAppViewer::writeSystemInfo() gDebugInfo["MainloopThreadID"] = (S32)thread_id; #endif +#ifndef LL_BUGSPLAT // "CrashNotHandled" is set here, while things are running well, // in case of a freeze. If there is a freeze, the crash logger will be launched // and can read this value from the debug_info.log. // 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; + gDebugInfo["CrashNotHandled"] = LLSD::Boolean(true); +#else // LL_BUGSPLAT + // "CrashNotHandled" is obsolete; it used (not very successsfully) + // to try to distinguish crashes from freezes - the intent here to to avoid calling it a freeze + gDebugInfo["CrashNotHandled"] = LLSD::Boolean(false); +#endif // ! LL_BUGSPLAT // 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 @@ -3444,7 +3487,7 @@ void LLAppViewer::writeSystemInfo() // Dump some debugging info LL_INFOS("SystemInfo") << "Application: " << LLTrans::getString("APP_NAME") << LL_ENDL; - LL_INFOS("SystemInfo") << "Version: " << LLVersionInfo::getChannelAndVersion() << LL_ENDL; + LL_INFOS("SystemInfo") << "Version: " << LLVersionInfo::instance().getChannelAndVersion() << LL_ENDL; // Dump the local time and time zone time_t now; @@ -3462,10 +3505,16 @@ void LLAppViewer::writeSystemInfo() gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile"); gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName(); gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); - gDebugInfo["FirstLogin"] = (LLSD::Boolean) gAgent.isFirstLogin(); + gDebugInfo["FirstLogin"] = LLSD::Boolean(gAgent.isFirstLogin()); gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall"); gDebugInfo["StartupState"] = LLStartUp::getStartupStateString(); + std::vector<std::string> resolutions = gViewerWindow->getWindow()->getDisplaysResolutionList(); + for (auto res_iter : resolutions) + { + gDebugInfo["DisplayInfo"].append(res_iter); + } + writeDebugInfo(); // Save out debug_info.log early, in case of crash. } @@ -3570,7 +3619,7 @@ void LLAppViewer::handleViewerCrash() if(gAgent.getRegion()) { - gDebugInfo["Dynamic"]["CurrentSimHost"] = gAgent.getRegionHost().getHostName(); + gDebugInfo["Dynamic"]["CurrentSimHost"] = gAgent.getRegion()->getSimHostName(); gDebugInfo["Dynamic"]["CurrentRegion"] = gAgent.getRegion()->getName(); const LLVector3& loc = gAgent.getPositionAgent(); @@ -3586,7 +3635,7 @@ void LLAppViewer::handleViewerCrash() // The crash is being handled here so set this value to false. // Otherwise the crash logger will think this crash was a freeze. - gDebugInfo["Dynamic"]["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 @@ -3659,6 +3708,8 @@ void LLAppViewer::handleViewerCrash() if (LLWorld::instanceExists()) LLWorld::getInstance()->getInfo(gDebugInfo["Dynamic"]); + gDebugInfo["FatalMessage"] = LLError::getFatalMessage(); + // Close the debug file pApp->writeDebugInfo(false); //false answers the isStatic question with the least overhead. } @@ -3666,7 +3717,7 @@ void LLAppViewer::handleViewerCrash() // static void LLAppViewer::recordMarkerVersion(LLAPRFile& marker_file) { - std::string marker_version(LLVersionInfo::getChannelAndVersion()); + std::string marker_version(LLVersionInfo::instance().getChannelAndVersion()); if ( marker_version.length() > MAX_MARKER_LENGTH ) { LL_WARNS_ONCE("MarkerFile") << "Version length ("<< marker_version.length()<< ")" @@ -3683,7 +3734,7 @@ bool LLAppViewer::markerIsSameVersion(const std::string& marker_name) const { bool sameVersion = false; - std::string my_version(LLVersionInfo::getChannelAndVersion()); + std::string my_version(LLVersionInfo::instance().getChannelAndVersion()); char marker_version[MAX_MARKER_LENGTH]; S32 marker_version_length; @@ -3757,9 +3808,8 @@ void LLAppViewer::processMarkerFiles() 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; - + LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec crashed" << LL_ENDL; + gLastExecEvent = LAST_EXEC_OTHER_CRASH; } else { @@ -3962,7 +4012,9 @@ void LLAppViewer::requestQuit() gFloaterView->closeAllChildren(true); } - send_stats(); + // Send preferences once, when exiting + bool include_preferences = true; + send_viewer_stats(include_preferences); gLogoutTimer.reset(); mQuitRequested = true; @@ -3982,7 +4034,11 @@ static LLNotificationFunctorRegistration finish_quit_reg("ConfirmQuit", finish_q void LLAppViewer::userQuit() { - if (gDisconnected || gViewerWindow->getProgressView()->getVisible()) + LL_INFOS() << "User requested quit" << LL_ENDL; + if (gDisconnected + || !gViewerWindow + || !gViewerWindow->getProgressView() + || gViewerWindow->getProgressView()->getVisible()) { requestQuit(); } @@ -4146,7 +4202,7 @@ bool LLAppViewer::initCache() mPurgeCache = false; BOOL read_only = mSecondInstance ? TRUE : FALSE; LLAppViewer::getTextureCache()->setReadOnly(read_only) ; - LLVOCache::getInstance()->setReadOnly(read_only); + LLVOCache::initParamSingleton(read_only); bool texture_cache_mismatch = false; if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion()) @@ -4218,7 +4274,8 @@ bool LLAppViewer::initCache() S64 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()) ; + + LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion()); LLSplashScreen::update(LLTrans::getString("StartupInitializingVFS")); @@ -4379,6 +4436,134 @@ void LLAppViewer::addOnIdleCallback(const boost::function<void()>& cb) LLDeferredTaskList::instance().addTask(cb); } +void LLAppViewer::loadKeyBindings() +{ + std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml"); +#if 1 + // Legacy support + // Remove #if-#endif section half a year after DRTVWR-501 releases. + // Mouse actions are part of keybinding file since DRTVWR-501 instead of being stored in + // settings.xml. To support legacy viewers that were storing in settings.xml we need to + // transfer old variables to new format. + // Also part of backward compatibility is present in LLKeyConflictHandler to modify + // legacy variables on changes in new system (to make sure we won't enforce + // legacy values again if user dropped to defaults in new system) + if (LLVersionInfo::getInstance()->getChannelAndVersion() != gLastRunVersion + || !gDirUtilp->fileExists(key_bindings_file)) // if file is missing, assume that there were no changes by user yet + { + // copy mouse actions and voice key changes to new file + LL_INFOS("InitInfo") << "Converting legacy mouse bindings to new format" << LL_ENDL; + // Load settings from file + LLKeyConflictHandler third_person_view(LLKeyConflictHandler::MODE_THIRD_PERSON); + LLKeyConflictHandler sitting_view(LLKeyConflictHandler::MODE_SITTING); + + // Since we are only modifying keybindings if personal file doesn't exist yet, + // it should be safe to just overwrite the value + // If key is already in use somewhere by default, LLKeyConflictHandler should resolve it. + BOOL value = gSavedSettings.getBOOL("DoubleClickAutoPilot"); + third_person_view.registerControl("walk_to", + 0, + value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE, + KEY_NONE, + MASK_NONE, + value); + + U32 index = value ? 1 : 0; // we can store multiple combinations per action, so if first is in use by doubleclick, go to second + value = gSavedSettings.getBOOL("ClickToWalk"); + third_person_view.registerControl("walk_to", + index, + value ? EMouseClickType::CLICK_LEFT : EMouseClickType::CLICK_NONE, + KEY_NONE, + MASK_NONE, + value); + + value = gSavedSettings.getBOOL("DoubleClickTeleport"); + third_person_view.registerControl("teleport_to", + 0, + value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE, + KEY_NONE, + MASK_NONE, + value); + + // sitting also supports teleport + sitting_view.registerControl("teleport_to", + 0, + value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE, + KEY_NONE, + MASK_NONE, + value); + + std::string key_string = gSavedSettings.getString("PushToTalkButton"); + EMouseClickType mouse = EMouseClickType::CLICK_NONE; + KEY key = KEY_NONE; + if (key_string == "MiddleMouse") + { + mouse = EMouseClickType::CLICK_MIDDLE; + } + else if (key_string == "MouseButton4") + { + mouse = EMouseClickType::CLICK_BUTTON4; + } + else if (key_string == "MouseButton5") + { + mouse = EMouseClickType::CLICK_BUTTON5; + } + else + { + LLKeyboard::keyFromString(key_string, &key); + } + + value = gSavedSettings.getBOOL("PushToTalkToggle"); + std::string control_name = value ? "toggle_voice" : "voice_follow_key"; + third_person_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true); + sitting_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true); + + if (third_person_view.hasUnsavedChanges()) + { + // calls loadBindingsXML() + third_person_view.saveToSettings(); + } + + if (sitting_view.hasUnsavedChanges()) + { + // calls loadBindingsXML() + sitting_view.saveToSettings(); + } + + // in case of voice we need to repeat this in other modes + + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) + { + // edit and first person modes; MODE_SAVED_SETTINGS not in use at the moment + if (i != LLKeyConflictHandler::MODE_THIRD_PERSON && i != LLKeyConflictHandler::MODE_SITTING) + { + LLKeyConflictHandler handler((LLKeyConflictHandler::ESourceMode)i); + + handler.registerControl(control_name, 0, mouse, key, MASK_NONE, true); + + if (handler.hasUnsavedChanges()) + { + // calls loadBindingsXML() + handler.saveToSettings(); + } + } + } + } + // since something might have gone wrong or there might have been nothing to save + // (and because otherwise following code will have to be encased in else{}), + // load everything one last time +#endif + if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file)) + { + // Failed to load custom bindings, try default ones + key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml"); + if (!gViewerInput.loadBindingsXML(key_bindings_file)) + { + LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL; + } + } +} + void LLAppViewer::purgeCache() { LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << LL_ENDL; @@ -4471,7 +4656,7 @@ void LLAppViewer::badNetworkHandler() // Flush all of our caches on exit in the case of disconnect due to // invalid packets. - mPurgeOnExit = TRUE; + mPurgeCacheOnExit = TRUE; std::ostringstream message; message << @@ -4511,6 +4696,7 @@ void LLAppViewer::saveFinalSnapshot() gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, + gSavedSettings.getBOOL("RenderHUDInSnapshot"), TRUE, LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::SNAPSHOT_FORMAT_PNG); @@ -4548,7 +4734,7 @@ void LLAppViewer::loadNameCache() llifstream name_cache_stream(filename.c_str()); if(name_cache_stream.is_open()) { - if ( ! LLAvatarNameCache::importFile(name_cache_stream)) + if ( ! LLAvatarNameCache::getInstance()->importFile(name_cache_stream)) { LL_WARNS("AppInit") << "removing invalid '" << filename << "'" << LL_ENDL; name_cache_stream.close(); @@ -4575,7 +4761,7 @@ void LLAppViewer::saveNameCache() llofstream name_cache_stream(filename.c_str()); if(name_cache_stream.is_open()) { - LLAvatarNameCache::exportFile(name_cache_stream); + LLAvatarNameCache::getInstance()->exportFile(name_cache_stream); } // real names cache @@ -4639,6 +4825,9 @@ void LLAppViewer::idle() LLFrameTimer::updateFrameTime(); LLFrameTimer::updateFrameCount(); LLEventTimer::updateClass(); + // LLApp::stepFrame() performs the above three calls plus mRunner.run(). + // Not sure why we don't call stepFrame() here, except that LLRunner seems + // completely redundant with LLEventTimer. LLNotificationsUI::LLToast::updateClass(); LLSmoothInterpolation::updateInterpolants(); LLMortician::updateClass(); @@ -4752,7 +4941,8 @@ void LLAppViewer::idle() if (viewer_stats_timer.getElapsedTimeF32() >= SEND_STATS_PERIOD && !gDisconnected) { LL_INFOS() << "Transmitting sessions stats" << LL_ENDL; - send_stats(); + bool include_preferences = false; + send_viewer_stats(include_preferences); viewer_stats_timer.reset(); } @@ -4834,13 +5024,14 @@ void LLAppViewer::idle() { return; } + + gViewerWindow->updateUI(); + if (gTeleportDisplay) { return; } - gViewerWindow->updateUI(); - /////////////////////////////////////// // Agent and camera movement // @@ -4934,7 +5125,6 @@ void LLAppViewer::idle() // // Update weather effects // - gSky.propagateHeavenlyBodies(gFrameDTClamped); // moves sun, moon, and planets // Update wind vector LLVector3 wind_position_region; @@ -5163,11 +5353,55 @@ void LLAppViewer::sendLogoutRequest() } } +void LLAppViewer::updateNameLookupUrl(const LLViewerRegion * regionp) +{ + if (!regionp || !regionp->capabilitiesReceived()) + { + return; + } + + LLAvatarNameCache *name_cache = LLAvatarNameCache::getInstance(); + bool had_capability = LLAvatarNameCache::getInstance()->hasNameLookupURL(); + std::string name_lookup_url; + name_lookup_url.reserve(128); // avoid a memory allocation below + name_lookup_url = regionp->getCapability("GetDisplayNames"); + bool have_capability = !name_lookup_url.empty(); + 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://<host>:<port>/cap/<uuid>/?ids=<blah> + // but the caps are granted like: + // https://<host>:<port>/cap/<uuid> + if (url_size > 0 && name_lookup_url[url_size - 1] != '/') + { + name_lookup_url += '/'; + } + name_cache->setNameLookupURL(name_lookup_url); + } + else + { + // Display names not available on this region + name_cache->setNameLookupURL(std::string()); + } + + // Error recovery - did we change state? + if (had_capability != have_capability) + { + // name tags are persistant on screen, so make sure they refresh + LLVOAvatar::invalidateNameTags(); + } +} + void LLAppViewer::idleNameCache() { // Neither old nor new name cache can function before agent has a region LLViewerRegion* region = gAgent.getRegion(); - if (!region) return; + if (!region) + { + return; + } // deal with any queued name requests and replies. gCacheName->processPending(); @@ -5175,46 +5409,12 @@ void LLAppViewer::idleNameCache() // Can't run the new cache until we have the list of capabilities // for the agent region, and can therefore decide whether to use // display names or fall back to the old name system. - if (!region->capabilitiesReceived()) return; - - // Agent may have moved to a different region, so need to update cap URL - // for name lookups. Can't do this in the cap grant code, as caps are - // granted to neighbor regions before the main agent gets there. Can't - // do it in the move-into-region code because cap not guaranteed to be - // granted yet, for example on teleport. - bool had_capability = LLAvatarNameCache::hasNameLookupURL(); - std::string name_lookup_url; - name_lookup_url.reserve(128); // avoid a memory allocation below - name_lookup_url = region->getCapability("GetDisplayNames"); - bool have_capability = !name_lookup_url.empty(); - 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://<host>:<port>/cap/<uuid>/?ids=<blah> - // but the caps are granted like: - // https://<host>:<port>/cap/<uuid> - if (url_size > 0 && name_lookup_url[url_size-1] != '/') - { - name_lookup_url += '/'; - } - LLAvatarNameCache::setNameLookupURL(name_lookup_url); - } - else - { - // Display names not available on this region - LLAvatarNameCache::setNameLookupURL( std::string() ); - } - - // Error recovery - did we change state? - if (had_capability != have_capability) - { - // name tags are persistant on screen, so make sure they refresh - LLVOAvatar::invalidateNameTags(); - } + if (!region->capabilitiesReceived()) + { + return; + } - LLAvatarNameCache::idle(); + LLAvatarNameCache::getInstance()->idle(); } // @@ -5251,37 +5451,40 @@ void LLAppViewer::idleNetwork() const S64 frame_count = gFrameCount; // U32->S64 F32 total_time = 0.0f; - while (gMessageSystem->checkAllMessages(frame_count, gServicePump)) { - if (gDoDisconnect) + LockMessageChecker lmc(gMessageSystem); + while (lmc.checkAllMessages(frame_count, gServicePump)) { - // We're disconnecting, don't process any more messages from the server - // We're usually disconnecting due to either network corruption or a - // server going down, so this is OK. - break; - } + if (gDoDisconnect) + { + // We're disconnecting, don't process any more messages from the server + // We're usually disconnecting due to either network corruption or a + // server going down, so this is OK. + break; + } - total_decoded++; - gPacketsIn++; + total_decoded++; + gPacketsIn++; - if (total_decoded > MESSAGE_MAX_PER_FRAME) - { - break; - } + if (total_decoded > MESSAGE_MAX_PER_FRAME) + { + break; + } #ifdef TIME_THROTTLE_MESSAGES - // Prevent slow packets from completely destroying the frame rate. - // This usually happens due to clumps of avatars taking huge amount - // of network processing time (which needs to be fixed, but this is - // a good limit anyway). - total_time = check_message_timer.getElapsedTimeF32(); - if (total_time >= CheckMessagesMaxTime) - break; + // Prevent slow packets from completely destroying the frame rate. + // This usually happens due to clumps of avatars taking huge amount + // of network processing time (which needs to be fixed, but this is + // a good limit anyway). + total_time = check_message_timer.getElapsedTimeF32(); + if (total_time >= CheckMessagesMaxTime) + break; #endif - } + } - // Handle per-frame message system processing. - gMessageSystem->processAcks(gSavedSettings.getF32("AckCollectTime")); + // Handle per-frame message system processing. + lmc.processAcks(gSavedSettings.getF32("AckCollectTime")); + } #ifdef TIME_THROTTLE_MESSAGES if (total_time >= CheckMessagesMaxTime) @@ -5417,7 +5620,7 @@ bool LLAppViewer::onChangeFrameLimit(LLSD const & evt) { if (evt.asInteger() > 0) { - mMinMicroSecPerFrame = 1000000 / evt.asInteger(); + mMinMicroSecPerFrame = (U64)(1000000.0f / F32(evt.asInteger())); } else { @@ -5472,6 +5675,33 @@ void LLAppViewer::forceErrorDriverCrash() glDeleteTextures(1, NULL); } +void LLAppViewer::forceErrorCoroutineCrash() +{ + LL_WARNS() << "Forcing a crash in LLCoros" << LL_ENDL; + LLCoros::instance().launch("LLAppViewer::crashyCoro", [] {throw LLException("A deliberate crash from LLCoros"); }); +} + +void LLAppViewer::forceErrorThreadCrash() +{ + class LLCrashTestThread : public LLThread + { + public: + + LLCrashTestThread() : LLThread("Crash logging test thread") + { + } + + void run() + { + LL_ERRS() << "This is a deliberate llerror in thread" << LL_ENDL; + } + }; + + LL_WARNS() << "This is a deliberate crash in a thread" << LL_ENDL; + LLCrashTestThread *thread = new LLCrashTestThread(); + thread->start(); +} + void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs) { if(!mMainloopTimeout) @@ -5515,11 +5745,6 @@ void LLAppViewer::pauseMainloopTimeout() void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs) { -// if(!restoreErrorTrap()) -// { -// LL_WARNS() << "!!!!!!!!!!!!! Its an error trap!!!!" << state << LL_ENDL; -// } - if(mMainloopTimeout) { if(secs < 0.0f) @@ -5539,12 +5764,12 @@ void LLAppViewer::handleLoginComplete() initMainloopTimeout("Mainloop Init"); // Store some data to DebugInfo in case of a freeze. - gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel(); + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); - gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor(); - gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor(); - gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch(); - gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::getBuild(); + gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); + gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); + gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); + gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::instance().getBuild(); LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if ( parcel && parcel->getMusicURL()[0]) @@ -5563,7 +5788,7 @@ void LLAppViewer::handleLoginComplete() if(gAgent.getRegion()) { - gDebugInfo["CurrentSimHost"] = gAgent.getRegionHost().getHostName(); + gDebugInfo["CurrentSimHost"] = gAgent.getRegion()->getSimHostName(); gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName(); } diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 788fe6a19b..95f6efa29a 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -57,6 +57,7 @@ class LLImageDecodeThread; class LLTextureFetch; class LLWatchdogTimeout; class LLViewerJoystick; +class LLViewerRegion; extern LLTrace::BlockTimerStatHandle FTM_FRAME; @@ -95,6 +96,7 @@ public: bool quitRequested() { return mQuitRequested; } bool logoutRequestSent() { return mLogoutRequestSent; } bool isSecondInstance() { return mSecondInstance; } + bool isUpdaterMissing() { return mUpdaterNotFound; } void writeDebugInfo(bool isStatic=true); @@ -107,7 +109,6 @@ public: virtual bool restoreErrorTrap() = 0; // Require platform specific override to reset error handling mechanism. // return false if the error trap needed restoration. - virtual void initCrashReporting(bool reportFreeze = false) = 0; // What to do with crash report? static void handleViewerCrash(); // Hey! The viewer crashed. Do this, soon. void checkForCrash(); @@ -149,6 +150,8 @@ public: virtual void forceErrorInfiniteLoop(); virtual void forceErrorSoftwareException(); virtual void forceErrorDriverCrash(); + virtual void forceErrorCoroutineCrash(); + virtual void forceErrorThreadCrash(); // The list is found in app_settings/settings_files.xml // but since they are used explicitly in code, @@ -190,9 +193,12 @@ public: void addOnIdleCallback(const boost::function<void()>& cb); // add a callback to fire (once) when idle + void purgeUserDataOnExit() { mPurgeUserDataOnExit = true; } void purgeCache(); // Clear the local cache. void purgeCacheImmediate(); //clear local cache immediately. S32 updateTextureThreads(F32 max_time); + + void loadKeyBindings(); // mute/unmute the system's master audio virtual void setMasterSystemAudioMute(bool mute); @@ -204,7 +210,9 @@ public: // llcorehttp init/shutdown/config information. LLAppCoreHttp & getAppCoreHttp() { return mAppCoreHttp; } - + + void updateNameLookupUrl(const LLViewerRegion* regionp); + protected: virtual bool initWindow(); // Initialize the viewer's window. virtual void initLoggingAndGetLastDuration(); // Initialize log files, logging system @@ -229,7 +237,6 @@ private: bool initConfiguration(); // Initialize settings from the command line/config file. void initStrings(); // Initialize LLTrans machinery bool initCache(); // Initialize local client cache. - void checkMemory() ; // We have switched locations of both Mac and Windows cache, make sure // files migrate and old cache is cleared out. @@ -261,6 +268,7 @@ private: static LLAppViewer* sInstance; bool mSecondInstance; // Is this a second instance of the app? + bool mUpdaterNotFound; // True when attempt to start updater failed std::string mMarkerFileName; LLAPRFile mMarkerFile; // A file created to indicate the app is running. @@ -281,7 +289,8 @@ private: std::string mSerialNumber; bool mPurgeCache; - bool mPurgeOnExit; + bool mPurgeCacheOnExit; + bool mPurgeUserDataOnExit; LLViewerJoystick* joystick; bool mSavedFinalSnapshot; @@ -306,8 +315,6 @@ private: LLAllocator mAlloc; - LLFrameTimer mMemCheckTimer; - // llcorehttp library init/shutdown helper LLAppCoreHttp mAppCoreHttp; @@ -391,8 +398,6 @@ extern LLVector3 gRelativeWindVec; extern U32 gPacketsIn; extern BOOL gPrintMessagesThisFrame; -extern LLUUID gSunTextureID; -extern LLUUID gMoonTextureID; extern LLUUID gBlackSquareID; extern BOOL gRandomizeFramerate; diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index 6f32aab851..dc487967fc 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -73,10 +73,6 @@ static void exceptionTerminateHandler() int main( int argc, char **argv ) { -#if LL_SOLARIS && defined(__sparc) - asm ("ta\t6"); // NOTE: Make sure memory alignment is enforced on SPARC -#endif - gArgC = argc; gArgV = argv; @@ -336,8 +332,6 @@ void LLAppViewerLinux::initCrashReporting(bool reportFreeze) cmd += gDirUtilp->getDirDelimiter(); #if LL_LINUX cmd += "linux-crash-logger.bin"; -#elif LL_SOLARIS - cmd += "solaris-crash-logger"; #else # error Unknown platform #endif @@ -394,9 +388,6 @@ bool LLAppViewerLinux::beingDebugged() { static enum {unknown, no, yes} debugged = unknown; -#if LL_SOLARIS - return debugged == no; // BUG: fix this for Solaris -#else if (debugged == unknown) { pid_t ppid = getppid(); @@ -431,7 +422,6 @@ bool LLAppViewerLinux::beingDebugged() } return debugged == yes; -#endif } void LLAppViewerLinux::initLoggingAndGetLastDuration() diff --git a/indra/newview/llappviewerlistener.cpp b/indra/newview/llappviewerlistener.cpp index 94250f1fc2..2380a8ebf0 100644 --- a/indra/newview/llappviewerlistener.cpp +++ b/indra/newview/llappviewerlistener.cpp @@ -52,10 +52,12 @@ LLAppViewerListener::LLAppViewerListener(const LLAppViewerGetter& getter): void LLAppViewerListener::requestQuit(const LLSD& event) { + LL_INFOS() << "Listener requested quit" << LL_ENDL; mAppViewerGetter()->requestQuit(); } void LLAppViewerListener::forceQuit(const LLSD& event) { + LL_INFOS() << "Listener requested force quit" << LL_ENDL; mAppViewerGetter()->forceQuit(); } diff --git a/indra/newview/llappviewermacosx-for-objc.h b/indra/newview/llappviewermacosx-for-objc.h index 37e8a3917a..79c3efff91 100644 --- a/indra/newview/llappviewermacosx-for-objc.h +++ b/indra/newview/llappviewermacosx-for-objc.h @@ -41,6 +41,7 @@ struct CrashMetadata { std::string logFilePathname; std::string userSettingsPathname; + std::string accountSettingsPathname; std::string staticDebugPathname; std::string OSInfo; std::string agentFullname; diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index 3111540a13..aa932f9c89 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -68,39 +68,21 @@ namespace int gArgC; char** gArgV; LLAppViewerMacOSX* gViewerAppPtr = NULL; - - void (*gOldTerminateHandler)() = NULL; std::string gHandleSLURL; } -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. - long *null_ptr; - null_ptr = 0; - *null_ptr = 0xDEADBEEF; //Force an exception that will trigger breakpad. - //LLAppViewer::handleViewerCrash(); - // we've probably been killed-off before now, but... - gOldTerminateHandler(); // call old terminate() handler -} - void constructViewer() { // Set the working dir to <bundle>/Contents/Resources if (chdir(gDirUtilp->getAppRODataDir().c_str()) == -1) { - LL_WARNS() << "Could not change directory to " + LL_WARNS("InitOSX") << "Could not change directory to " << gDirUtilp->getAppRODataDir() << ": " << strerror(errno) << LL_ENDL; } gViewerAppPtr = new LLAppViewerMacOSX(); - // install unexpected exception handler - gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler); - gViewerAppPtr->setErrorHandler(LLAppViewer::handleViewerCrash); } @@ -109,7 +91,7 @@ bool initViewer() bool ok = gViewerAppPtr->init(); if(!ok) { - LL_WARNS() << "Application init failed." << LL_ENDL; + LL_WARNS("InitOSX") << "Application init failed." << LL_ENDL; } else if (!gHandleSLURL.empty()) { @@ -172,7 +154,7 @@ class CrashMetadataSingleton: public CrashMetadata, public LLSingleton<CrashMeta std::string get_metadata(const LLSD& info, const LLSD::String& key) const { std::string data(info[key].asString()); - LL_INFOS() << " " << key << "='" << data << "'" << LL_ENDL; + LL_INFOS("Bugsplat") << " " << key << "='" << data << "'" << LL_ENDL; return data; } }; @@ -188,19 +170,20 @@ CrashMetadataSingleton::CrashMetadataSingleton() LLSD info; if (! static_file.is_open()) { - LL_INFOS() << "Can't open '" << staticDebugPathname + LL_WARNS("Bugsplat") << "Can't open '" << staticDebugPathname << "'; no metadata about previous run" << LL_ENDL; } else if (! LLSDSerialize::deserialize(info, static_file, LLSDSerialize::SIZE_UNLIMITED)) { - LL_INFOS() << "Can't parse '" << staticDebugPathname + LL_WARNS("Bugsplat") << "Can't parse '" << staticDebugPathname << "'; no metadata about previous run" << LL_ENDL; } else { - LL_INFOS() << "Metadata from '" << staticDebugPathname << "':" << LL_ENDL; + LL_INFOS("Bugsplat") << "Previous run metadata from '" << staticDebugPathname << "':" << LL_ENDL; logFilePathname = get_metadata(info, "SLLog"); userSettingsPathname = get_metadata(info, "SettingsFilename"); + accountSettingsPathname = get_metadata(info, "PerAccountSettingsFilename"); OSInfo = get_metadata(info, "OSInfo"); agentFullname = get_metadata(info, "LoginName"); // Translate underscores back to spaces @@ -218,7 +201,7 @@ CrashMetadata& CrashMetadata_instance() void infos(const std::string& message) { - LL_INFOS() << message << LL_ENDL; + LL_INFOS("InitOSX", "Bugsplat") << message << LL_ENDL; } int main( int argc, char **argv ) @@ -239,17 +222,7 @@ LLAppViewerMacOSX::~LLAppViewerMacOSX() bool LLAppViewerMacOSX::init() { - bool success = LLAppViewer::init(); - -#if LL_SEND_CRASH_REPORTS - if (success) - { - LLAppViewer* pApp = LLAppViewer::instance(); - pApp->initCrashReporting(); - } -#endif - - return success; + return LLAppViewer::init(); } // MacOSX may add and addition command line arguement for the process serial number. @@ -333,11 +306,12 @@ bool LLAppViewerMacOSX::restoreErrorTrap() unsigned int reset_count = 0; -#define SET_SIG(S) sigaction(SIGABRT, &act, &old_act); \ - if(act.sa_sigaction != old_act.sa_sigaction) \ - ++reset_count; +#define SET_SIG(SIGNAL) sigaction(SIGNAL, &act, &old_act); \ + if(act.sa_sigaction != old_act.sa_sigaction) ++reset_count; // Synchronous signals - SET_SIG(SIGABRT) +# ifndef LL_BUGSPLAT + SET_SIG(SIGABRT) // let bugsplat catch this +# endif SET_SIG(SIGALRM) SET_SIG(SIGBUS) SET_SIG(SIGFPE) @@ -366,21 +340,6 @@ bool LLAppViewerMacOSX::restoreErrorTrap() return reset_count == 0; } -void LLAppViewerMacOSX::initCrashReporting(bool reportFreeze) -{ - std::string command_str = "mac-crash-logger.app"; - - std::stringstream pid_str; - pid_str << LLApp::getPid(); - std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); - std::string appname = gDirUtilp->getExecutableFilename(); - std::string str[] = { "-pid", pid_str.str(), "-dumpdir", logdir, "-procname", appname.c_str() }; - std::vector< std::string > args( str, str + ( sizeof ( str ) / sizeof ( std::string ) ) ); - LL_WARNS() << "about to launch mac-crash-logger" << pid_str.str() - << " " << logdir << " " << appname << LL_ENDL; - launchApplication(&command_str, &args); -} - std::string LLAppViewerMacOSX::generateSerialNumber() { char serial_md5[MD5HEX_STR_SIZE]; // Flawfinder: ignore @@ -390,7 +349,8 @@ std::string LLAppViewerMacOSX::generateSerialNumber() CFStringRef serialNumber = NULL; io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); - if (platformExpert) { + if (platformExpert) + { serialNumber = (CFStringRef) IORegistryEntryCreateCFProperty(platformExpert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0); diff --git a/indra/newview/llappviewermacosx.h b/indra/newview/llappviewermacosx.h index d5a80864be..b0e325a955 100644 --- a/indra/newview/llappviewermacosx.h +++ b/indra/newview/llappviewermacosx.h @@ -44,7 +44,6 @@ public: protected: virtual bool restoreErrorTrap(); - virtual void initCrashReporting(bool reportFreeze); std::string generateSerialNumber(); virtual bool initParseCommandLine(LLCommandLineParser& clp); diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index d208e135bb..25d18fa11f 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -139,6 +139,9 @@ namespace { // user name, when we have it sBugSplatSender->setDefaultUserName(WCSTR(gAgentAvatarp->getFullname())); + + sBugSplatSender->sendAdditionalFile( + WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "settings_per_account.xml"))); } // LL_ERRS message, when there is one @@ -174,7 +177,7 @@ static void exceptionTerminateHandler() long *null_ptr; null_ptr = 0; *null_ptr = 0xDEADBEEF; //Force an exception that will trigger breakpad. - //LLAppViewer::handleViewerCrash(); + // we've probably been killed-off before now, but... gOldTerminateHandler(); // call old terminate() handler } @@ -362,10 +365,6 @@ int APIENTRY WINMAIN(HINSTANCE hInstance, viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash); -#if LL_SEND_CRASH_REPORTS - // ::SetUnhandledExceptionFilter(catchallCrashHandler); -#endif - // Set a debug info flag to indicate if multiple instances are running. bool found_other_instance = !create_app_mutex(); gDebugInfo["FoundOtherInstanceAtStartup"] = LLSD::Boolean(found_other_instance); @@ -500,68 +499,76 @@ void LLAppViewerWin32::disableWinErrorReporting() } const S32 MAX_CONSOLE_LINES = 500; +// Only defined in newer SDKs than we currently use +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 4 +#endif -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 - 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); +namespace { - // 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) - { - LL_WARNS() << "create_console() failed to open stdout handle" << LL_ENDL; - } - else - { - fp = _fdopen( h_con_handle, "w" ); - *stdout = *fp; - setvbuf( stdout, NULL, _IONBF, 0 ); - } +void set_stream(const char* desc, FILE* fp, DWORD handle_id, const char* name, const char* mode="w"); - // 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) - { - LL_WARNS() << "create_console() failed to open stdin handle" << LL_ENDL; - } - else - { - fp = _fdopen( h_con_handle, "r" ); - *stdin = *fp; - setvbuf( stdin, NULL, _IONBF, 0 ); - } +bool create_console() +{ + // allocate a console for this app + const bool isConsoleAllocated = AllocConsole(); - // 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) - { - LL_WARNS() << "create_console() failed to open stderr handle" << LL_ENDL; - } - else - { - fp = _fdopen( h_con_handle, "w" ); - *stderr = *fp; - setvbuf( stderr, NULL, _IONBF, 0 ); - } + if (isConsoleAllocated) + { + // set the screen buffer to be big enough to let us scroll text + CONSOLE_SCREEN_BUFFER_INFO coninfo; + 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 + set_stream("stdout", stdout, STD_OUTPUT_HANDLE, "CONOUT$"); + // redirect unbuffered STDERR to the console + set_stream("stderr", stderr, STD_ERROR_HANDLE, "CONOUT$"); + // redirect unbuffered STDIN to the console + // Don't bother: our console is solely for log output. We never read stdin. +// set_stream("stdin", stdin, STD_INPUT_HANDLE, "CONIN$", "r"); + } return isConsoleAllocated; } +void set_stream(const char* desc, FILE* fp, DWORD handle_id, const char* name, const char* mode) +{ + // SL-13528: This code used to be based on + // http://dslweb.nwnexus.com/~ast/dload/guicon.htm + // (referenced in https://stackoverflow.com/a/191880). + // But one of the comments on that StackOverflow answer points out that + // assigning to *stdout or *stderr "probably doesn't even work with the + // Universal CRT that was introduced in 2015," suggesting freopen_s() + // instead. Code below is based on https://stackoverflow.com/a/55875595. + auto std_handle = GetStdHandle(handle_id); + if (std_handle == INVALID_HANDLE_VALUE) + { + LL_WARNS() << "create_console() failed to get " << desc << " handle" << LL_ENDL; + } + else + { + if (mode == std::string("w")) + { + // Enable color processing on Windows 10 console windows. + DWORD dwMode = 0; + GetConsoleMode(std_handle, &dwMode); + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(std_handle, dwMode); + } + // Redirect the passed fp to the console. + FILE* ignore; + if (freopen_s(&ignore, name, mode, fp) == 0) + { + // use unbuffered I/O + setvbuf( fp, NULL, _IONBF, 0 ); + } + } +} + +} // anonymous namespace + LLAppViewerWin32::LLAppViewerWin32(const char* cmd_line) : mCmdLine(cmd_line), mIsConsoleAllocated(false) @@ -592,12 +599,16 @@ bool LLAppViewerWin32::init() #if ! defined(LL_BUGSPLAT) #pragma message("Building without BugSplat") - LLAppViewer* pApp = LLAppViewer::instance(); - pApp->initCrashReporting(); - #else // LL_BUGSPLAT #pragma message("Building with BugSplat") + if (!isSecondInstance()) + { + // Cleanup previous session + std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "bugsplat.log"); + LLFile::remove(log_file, ENOENT); + } + std::string build_data_fname( gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json")); // Use llifstream instead of std::ifstream because LL_PATH_EXECUTABLE @@ -605,7 +616,7 @@ bool LLAppViewerWin32::init() llifstream inf(build_data_fname.c_str()); if (! inf.is_open()) { - LL_WARNS() << "Can't initialize BugSplat, can't read '" << build_data_fname + LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, can't read '" << build_data_fname << "'" << LL_ENDL; } else @@ -615,7 +626,7 @@ bool LLAppViewerWin32::init() if (! reader.parse(inf, build_data, false)) // don't collect comments { // gah, the typo is baked into Json::Reader API - LL_WARNS() << "Can't initialize BugSplat, can't parse '" << build_data_fname + LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, can't parse '" << build_data_fname << "': " << reader.getFormatedErrorMessages() << LL_ENDL; } else @@ -623,7 +634,7 @@ bool LLAppViewerWin32::init() Json::Value BugSplat_DB = build_data["BugSplat DB"]; if (! BugSplat_DB) { - LL_WARNS() << "Can't initialize BugSplat, no 'BugSplat DB' entry in '" + LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, no 'BugSplat DB' entry in '" << build_data_fname << "'" << LL_ENDL; } else @@ -634,18 +645,35 @@ bool LLAppViewerWin32::init() LL_VIEWER_VERSION_PATCH << '.' << LL_VIEWER_VERSION_BUILD)); + DWORD dwFlags = MDSF_NONINTERACTIVE | // automatically submit report without prompting + MDSF_PREVENTHIJACKING; // disallow swiping Exception filter + + bool needs_log_file = !isSecondInstance() && debugLoggingEnabled("BUGSPLAT"); + if (needs_log_file) + { + // Startup only! + LL_INFOS("BUGSPLAT") << "Engaged BugSplat logging to bugsplat.log" << LL_ENDL; + dwFlags |= MDSF_LOGFILE | MDSF_LOG_VERBOSE; + } + // have to convert normal wide strings to strings of __wchar_t sBugSplatSender = new MiniDmpSender( WCSTR(BugSplat_DB.asString()), WCSTR(LL_TO_WSTRING(LL_VIEWER_CHANNEL)), WCSTR(version_string), nullptr, // szAppIdentifier -- set later - MDSF_NONINTERACTIVE | // automatically submit report without prompting - MDSF_PREVENTHIJACKING); // disallow swiping Exception filter + dwFlags); sBugSplatSender->setCallback(bugsplatSendLog); + if (needs_log_file) + { + // Log file will be created in %TEMP%, but it will be moved into logs folder in case of crash + std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "bugsplat.log"); + sBugSplatSender->setLogFilePath(WCSTR(log_file)); + } + // engage stringize() overload that converts from wstring - LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) + LL_INFOS("BUGSPLAT") << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) << ' ' << stringize(version_string) << ')' << LL_ENDL; } // got BugSplat_DB } // parsed build_data.json @@ -674,6 +702,16 @@ bool LLAppViewerWin32::cleanup() return result; } +void LLAppViewerWin32::reportCrashToBugsplat(void* pExcepInfo) +{ +#if defined(LL_BUGSPLAT) + if (sBugSplatSender) + { + sBugSplatSender->createReport((EXCEPTION_POINTERS*)pExcepInfo); + } +#endif // LL_BUGSPLAT +} + void LLAppViewerWin32::initLoggingAndGetLastDuration() { LLAppViewer::initLoggingAndGetLastDuration(); @@ -802,59 +840,7 @@ bool LLAppViewerWin32::beingDebugged() bool LLAppViewerWin32::restoreErrorTrap() { - return true; - //return LLWinDebug::checkExceptionHandler(); -} - -void LLAppViewerWin32::initCrashReporting(bool reportFreeze) -{ - if (isSecondInstance()) return; //BUG-5707 do not start another crash reporter for second instance. - - const char* logger_name = "win_crash_logger.exe"; - std::string exe_path = gDirUtilp->getExecutableDir(); - exe_path += gDirUtilp->getDirDelimiter(); - exe_path += logger_name; - - std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); - std::string appname = gDirUtilp->getExecutableFilename(); - - S32 slen = logdir.length() -1; - S32 end = slen; - while (logdir.at(end) == '/' || logdir.at(end) == '\\') end--; - - if (slen !=end) - { - logdir = logdir.substr(0,end+1); - } - //std::string arg_str = "\"" + exe_path + "\" -dumpdir \"" + logdir + "\" -procname \"" + appname + "\" -pid " + stringize(LLApp::getPid()); - //_spawnl(_P_NOWAIT, exe_path.c_str(), arg_str.c_str(), NULL); - std::string arg_str = "\"" + exe_path + "\" -dumpdir \"" + logdir + "\" -procname \"" + appname + "\" -pid " + stringize(LLApp::getPid()); - - STARTUPINFO startInfo={sizeof(startInfo)}; - PROCESS_INFORMATION processInfo; - - std::wstring exe_wstr; - exe_wstr = utf8str_to_utf16str(exe_path); - - std::wstring arg_wstr; - arg_wstr = utf8str_to_utf16str(arg_str); - - LL_INFOS("CrashReport") << "Creating crash reporter process " << exe_path << " with params: " << arg_str << LL_ENDL; - if(CreateProcess(exe_wstr.c_str(), - &arg_wstr[0], // Application arguments - 0, - 0, - FALSE, - CREATE_DEFAULT_ERROR_MODE, - 0, - 0, // Working directory - &startInfo, - &processInfo) == FALSE) - // Could not start application -> call 'GetLastError()' - { - LL_WARNS("CrashReport") << "CreateProcess failed " << GetLastError() << LL_ENDL; - return; - } + return true; // we don't check for handler collisions on windows, so just say they're ok } //virtual diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h index c5fae6a3a3..82b6b0c77c 100644 --- a/indra/newview/llappviewerwin32.h +++ b/indra/newview/llappviewerwin32.h @@ -40,20 +40,21 @@ public: // // 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; + + void reportCrashToBugsplat(void* pExcepInfo) override; protected: - virtual void initLoggingAndGetLastDuration(); // 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 beingDebugged(); virtual bool restoreErrorTrap(); - virtual void initCrashReporting(bool reportFreeze); - virtual bool sendURLToOtherInstance(const std::string& url); + bool sendURLToOtherInstance(const std::string& url) override; std::string generateSerialNumber(); diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp index d3e66289d1..0fd6009074 100644 --- a/indra/newview/llattachmentsmgr.cpp +++ b/indra/newview/llattachmentsmgr.cpp @@ -248,6 +248,7 @@ void LLAttachmentsMgr::linkRecentlyArrivedAttachments() { if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(*it) && + !gAgentAvatarp->getWornAttachment(*it)->isTempAttachment() && // Don't link temp attachments in COF! !LLAppearanceMgr::instance().isLinkedInCOF(*it)) { LLUUID item_id = *it; diff --git a/indra/newview/llattachmentsmgr.h b/indra/newview/llattachmentsmgr.h index a4ef762e8b..90aeff3032 100644 --- a/indra/newview/llattachmentsmgr.h +++ b/indra/newview/llattachmentsmgr.h @@ -30,8 +30,6 @@ #include "llsingleton.h" -class LLViewerInventoryItem; - //-------------------------------------------------------------------------------- // LLAttachmentsMgr // diff --git a/indra/newview/llaudiosourcevo.cpp b/indra/newview/llaudiosourcevo.cpp index b37aba6c15..4b6c855bde 100644 --- a/indra/newview/llaudiosourcevo.cpp +++ b/indra/newview/llaudiosourcevo.cpp @@ -29,8 +29,10 @@ #include "llaudiosourcevo.h" +#include "llagent.h" #include "llagentcamera.h" #include "llmutelist.h" +#include "llviewercontrol.h" #include "llviewerparcelmgr.h" LLAudioSourceVO::LLAudioSourceVO(const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, LLViewerObject *objectp) @@ -54,6 +56,79 @@ void LLAudioSourceVO::setGain(const F32 gain) mGain = llclamp(gain, 0.f, 1.f); } +void LLAudioSourceVO::checkCutOffRadius() +{ + if (mSourceMuted // already muted by something, will be recalculated on update() + || !mObjectp) + { + return; + } + + F32 cutoff = mObjectp->getSoundCutOffRadius(); + if (cutoff < 0.1f) + { + // consider cutoff below 0.1m as off (to avoid near zero comparison) + return; + } + + LLVector3d pos_global = getPosGlobal(); + if (!isInCutOffRadius(pos_global, cutoff)) + { + mSourceMuted = true; + } +} + +LLVector3d LLAudioSourceVO::getPosGlobal() const +{ + if (mObjectp->isAttachment()) + { + LLViewerObject* parent = mObjectp; + while (parent && !parent->isAvatar()) + { + parent = (LLViewerObject*)parent->getParent(); + } + if (parent) + { + return parent->getPositionGlobal(); + } + } + else + { + return mObjectp->getPositionGlobal(); + } + return LLVector3d(); +} + +bool LLAudioSourceVO::isInCutOffRadius(const LLVector3d pos_global, const F32 cutoff) const +{ + static LLCachedControl<S32> ear_mode(gSavedSettings, "VoiceEarLocation", 0); + + LLVector3d pos_ear; + + switch (ear_mode()) + { + case 0: // camera + pos_ear = gAgentCamera.getCameraPositionGlobal(); + break; + + case 1: // avatar + case 2: + // voice support 'mixed' in '2' case with agent's position and camera's rotations + // but it is not defined in settings and uses camera as default + pos_ear = gAgent.getPositionGlobal(); + break; + + default: + pos_ear = gAgentCamera.getCameraPositionGlobal(); + break; + } + LLVector3d to_vec = pos_global - pos_ear; + + F32 dist = (F32)to_vec.magVec(); + + return dist < cutoff; +} + void LLAudioSourceVO::updateMute() { if (!mObjectp || mObjectp->isDead()) @@ -63,26 +138,11 @@ void LLAudioSourceVO::updateMute() } bool mute = false; - LLVector3d pos_global; - - if (mObjectp->isAttachment()) - { - LLViewerObject* parent = mObjectp; - while (parent && !parent->isAvatar()) - { - parent = (LLViewerObject*)parent->getParent(); - } - if (parent) - { - pos_global = parent->getPositionGlobal(); - } - } - else - { - pos_global = mObjectp->getPositionGlobal(); - } + LLVector3d pos_global = getPosGlobal(); - if (!LLViewerParcelMgr::getInstance()->canHearSound(pos_global)) + F32 cutoff = mObjectp->getSoundCutOffRadius(); + if ((cutoff > 0.1f && !isInCutOffRadius(pos_global, cutoff)) // consider cutoff below 0.1m as off + || !LLViewerParcelMgr::getInstance()->canHearSound(pos_global)) { mute = true; } diff --git a/indra/newview/llaudiosourcevo.h b/indra/newview/llaudiosourcevo.h index f1d8ef4528..672a07f7d3 100644 --- a/indra/newview/llaudiosourcevo.h +++ b/indra/newview/llaudiosourcevo.h @@ -41,7 +41,11 @@ public: /*virtual*/ void update(); /*virtual*/ void setGain(const F32 gain); + void checkCutOffRadius(); + private: + LLVector3d getPosGlobal() const; + bool isInCutOffRadius(LLVector3d pos_global, const F32 cutoff) const; void updateMute(); private: diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index f0b74e7439..1797d2dd6e 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -626,10 +626,10 @@ namespace action_give_inventory * Checks My Inventory visibility. */ - static bool is_give_inventory_acceptable() + static bool is_give_inventory_acceptable(LLInventoryPanel* panel = NULL) { // check selection in the panel - const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(); + const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel); if (inventory_selected_uuids.empty()) return false; // nothing selected bool acceptable = false; @@ -694,7 +694,7 @@ namespace action_give_inventory uuid_vec_t mAvatarUuids; }; - static void give_inventory_cb(const LLSD& notification, const LLSD& response) + static void give_inventory_cb(const LLSD& notification, const LLSD& response, std::set<LLUUID> inventory_selected_uuids) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); // if Cancel pressed @@ -703,7 +703,6 @@ namespace action_give_inventory return; } - const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(); if (inventory_selected_uuids.empty()) { return; @@ -786,11 +785,11 @@ namespace action_give_inventory * @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<LLAvatarName> avatar_names) + static void give_inventory(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names, LLInventoryPanel* panel = NULL) { llassert(avatar_names.size() == avatar_uuids.size()); - const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(); + const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel); if (inventory_selected_uuids.empty()) { return; @@ -824,7 +823,7 @@ namespace action_give_inventory substitutions["ITEMS"] = items; LLShareInfo::instance().mAvatarNames = avatar_names; LLShareInfo::instance().mAvatarUuids = avatar_uuids; - LLNotificationsUtil::add(notification, substitutions, LLSD(), &give_inventory_cb); + LLNotificationsUtil::add(notification, substitutions, LLSD(), boost::bind(&give_inventory_cb, _1, _2, inventory_selected_uuids)); } } @@ -877,11 +876,14 @@ void LLAvatarActions::buildResidentsString(const uuid_vec_t& avatar_uuids, std:: } //static -std::set<LLUUID> LLAvatarActions::getInventorySelectedUUIDs() +std::set<LLUUID> LLAvatarActions::getInventorySelectedUUIDs(LLInventoryPanel* active_panel) { std::set<LLFolderViewItem*> inventory_selected; - LLInventoryPanel* active_panel = action_give_inventory::get_active_inventory_panel(); + if (!active_panel) + { + active_panel = action_give_inventory::get_active_inventory_panel(); + } if (active_panel) { inventory_selected= active_panel->getRootFolder()->getSelectionList(); @@ -911,15 +913,16 @@ void LLAvatarActions::shareWithAvatars(LLView * panel) { using namespace action_give_inventory; - LLFloater* root_floater = gFloaterView->getParentFloater(panel); + LLFloater* root_floater = gFloaterView->getParentFloater(panel); + LLInventoryPanel* inv_panel = dynamic_cast<LLInventoryPanel*>(panel); LLFloaterAvatarPicker* picker = - LLFloaterAvatarPicker::show(boost::bind(give_inventory, _1, _2), TRUE, FALSE, FALSE, root_floater->getName()); + LLFloaterAvatarPicker::show(boost::bind(give_inventory, _1, _2, inv_panel), TRUE, FALSE, FALSE, root_floater->getName()); if (!picker) { return; } - picker->setOkBtnEnableCb(boost::bind(is_give_inventory_acceptable)); + picker->setOkBtnEnableCb(boost::bind(is_give_inventory_acceptable, inv_panel)); picker->openFriendsTab(); if (root_floater) diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h index b56d5b0fb9..7c721076c8 100644 --- a/indra/newview/llavataractions.h +++ b/indra/newview/llavataractions.h @@ -244,7 +244,7 @@ public: */ static void viewChatHistory(const LLUUID& id); - static std::set<LLUUID> getInventorySelectedUUIDs(); + static std::set<LLUUID> getInventorySelectedUUIDs(LLInventoryPanel* active_panel = NULL); private: static bool callbackAddFriendWithMessage(const LLSD& notification, const LLSD& response); diff --git a/indra/newview/llavatariconctrl.h b/indra/newview/llavatariconctrl.h index a1dacd1a27..c510e86958 100644 --- a/indra/newview/llavatariconctrl.h +++ b/indra/newview/llavatariconctrl.h @@ -31,7 +31,6 @@ #include "lliconctrl.h" #include "llavatarpropertiesprocessor.h" -#include "llviewermenu.h" class LLAvatarName; diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index 513f25e301..b0715a3afd 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -154,7 +154,7 @@ LLAvatarList::LLAvatarList(const Params& p) mLITUpdateTimer->start(); } - LLAvatarNameCache::addUseDisplayNamesCallback(boost::bind(&LLAvatarList::handleDisplayNamesOptionChanged, this)); + LLAvatarNameCache::getInstance()->addUseDisplayNamesCallback(boost::bind(&LLAvatarList::handleDisplayNamesOptionChanged, this)); } diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h index 36d18114aa..b95cd68526 100644 --- a/indra/newview/llavatarlistitem.h +++ b/indra/newview/llavatarlistitem.h @@ -30,7 +30,6 @@ #include <boost/signals2.hpp> #include "llpanel.h" -#include "lloutputmonitorctrl.h" #include "llbutton.h" #include "lltextbox.h" #include "llstyle.h" @@ -38,6 +37,7 @@ #include "llcallingcard.h" // for LLFriendObserver class LLAvatarIconCtrl; +class LLOutputMonitorCtrl; class LLAvatarName; class LLIconCtrl; diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp index 856eb3414e..f41eb3daf4 100644 --- a/indra/newview/llavatarpropertiesprocessor.cpp +++ b/indra/newview/llavatarpropertiesprocessor.cpp @@ -253,6 +253,19 @@ std::string LLAvatarPropertiesProcessor::paymentInfo(const LLAvatarData* avatar_ return LLTrans::getString(payment_text); } +//static +bool LLAvatarPropertiesProcessor::hasPaymentInfoOnFile(const LLAvatarData* avatar_data) +{ + // Special accounts like M Linden don't have payment info revealed. + if (!avatar_data->caption_text.empty()) return true; + + // Linden employees don't have payment info revealed + const S32 LINDEN_EMPLOYEE_INDEX = 3; + if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX) return true; + + return ((avatar_data->flags & AVATAR_TRANSACTED) || (avatar_data->flags & AVATAR_IDENTIFIED)); +} + void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem* msg, void**) { LLAvatarData avatar_data; diff --git a/indra/newview/llavatarpropertiesprocessor.h b/indra/newview/llavatarpropertiesprocessor.h index d5c5c75c69..b063048c26 100644 --- a/indra/newview/llavatarpropertiesprocessor.h +++ b/indra/newview/llavatarpropertiesprocessor.h @@ -232,6 +232,8 @@ public: // Used for profiles, inspectors. static std::string paymentInfo(const LLAvatarData* avatar_data); + static bool hasPaymentInfoOnFile(const LLAvatarData* avatar_data); + static void processAvatarPropertiesReply(LLMessageSystem* msg, void**); static void processAvatarInterestsReply(LLMessageSystem* msg, void**); diff --git a/indra/newview/llbrowsernotification.cpp b/indra/newview/llbrowsernotification.cpp index 19747757db..0460bff1b4 100644 --- a/indra/newview/llbrowsernotification.cpp +++ b/indra/newview/llbrowsernotification.cpp @@ -50,7 +50,7 @@ bool LLBrowserNotification::processNotification(const LLNotificationPtr& notific } else if (LLViewerMediaFocus::instance().getControlsMediaID() == media_id) { - LLViewerMediaImpl* impl = LLViewerMedia::getMediaImplFromTextureID(media_id); + LLViewerMediaImpl* impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(media_id); if (impl) { impl->showNotification(notification); diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp index d6240838b6..9e7a8ba95c 100644 --- a/indra/newview/llchannelmanager.cpp +++ b/indra/newview/llchannelmanager.cpp @@ -48,25 +48,39 @@ LLChannelManager::LLChannelManager() LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLChannelManager::onLoginCompleted, this)); mChannelList.clear(); mStartUpChannel = NULL; - + if(!gViewerWindow) { LL_ERRS() << "LLChannelManager::LLChannelManager() - viwer window is not initialized yet" << LL_ENDL; } + + // We don't actually need this instance right now, but our + // cleanupSingleton() method deletes LLScreenChannels, which need to + // unregister from LLUI. Calling LLUI::instance() here establishes the + // dependency so LLSingletonBase::deleteAll() calls our deleteSingleton() + // before LLUI::deleteSingleton(). + LLUI::instance(); } //-------------------------------------------------------------------------- LLChannelManager::~LLChannelManager() { - for(std::vector<ChannelElem>::iterator it = mChannelList.begin(); it != mChannelList.end(); ++it) - { - LLScreenChannelBase* channel = it->channel.get(); - if (!channel) continue; +} - delete channel; - } +//-------------------------------------------------------------------------- +void LLChannelManager::cleanupSingleton() +{ + // Note: LLScreenChannelBase is a LLUICtrl and depends onto other singletions + // not captured by singleton-dependency, so cleanup it here instead of destructor + for (std::vector<ChannelElem>::iterator it = mChannelList.begin(); it != mChannelList.end(); ++it) + { + LLScreenChannelBase* channel = it->channel.get(); + if (!channel) continue; - mChannelList.clear(); + delete channel; + } + + mChannelList.clear(); } //-------------------------------------------------------------------------- diff --git a/indra/newview/llchannelmanager.h b/indra/newview/llchannelmanager.h index 8b9d0dda8b..8abe350196 100644 --- a/indra/newview/llchannelmanager.h +++ b/indra/newview/llchannelmanager.h @@ -46,6 +46,7 @@ class LLChannelManager : public LLSingleton<LLChannelManager> LLSINGLETON(LLChannelManager); virtual ~LLChannelManager(); + void cleanupSingleton(); public: diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp index 54c6c985d6..e400609a74 100644 --- a/indra/newview/llchatbar.cpp +++ b/indra/newview/llchatbar.cpp @@ -57,8 +57,8 @@ #include "llinventorymodel.h" #include "llmultigesture.h" #include "llui.h" -#include "llviewermenu.h" #include "lluictrlfactory.h" +#include "lluiusage.h" // // Globals @@ -567,6 +567,8 @@ void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL // as soon as we say something, we no longer care about teaching the user // how to chat gWarningSettings.setBOOL("FirstOtherChatBeforeUser", FALSE); + + LLUIUsage::instance().logCommand("Chat.Send"); // Pseudo-command // Look for "/20 foo" channel chats. S32 channel = 0; diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 1099d4bc09..c110e0d815 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -64,6 +64,7 @@ #include "llstring.h" #include "llurlaction.h" #include "llviewercontrol.h" +#include "llviewermenu.h" #include "llviewerobjectlist.h" static LLDefaultChildRegistry::Register<LLChatHistory> r("chat_history"); @@ -121,6 +122,7 @@ public: mUserNameFont(NULL), mUserNameTextBox(NULL), mTimeBoxTextBox(NULL), + mNeedsTimeBox(true), mAvatarNameCacheConnection() {} @@ -642,8 +644,19 @@ public: user_name->setReadOnlyColor(style_params.readonly_color()); user_name->setColor(style_params.color()); - if (chat.mFromName.empty() - || mSourceType == CHAT_SOURCE_SYSTEM) + if (mSourceType == CHAT_SOURCE_TELEPORT + && chat.mChatStyle == CHAT_STYLE_TELEPORT_SEP) + { + mFrom = chat.mFromName; + mNeedsTimeBox = false; + user_name->setValue(mFrom); + updateMinUserNameWidth(); + LLColor4 sep_color = LLUIColorTable::instance().getColor("ChatTeleportSeparatorColor"); + setTransparentColor(sep_color); + mTimeBoxTextBox->setVisible(FALSE); + } + else if (chat.mFromName.empty() + || mSourceType == CHAT_SOURCE_SYSTEM) { mFrom = LLTrans::getString("SECOND_LIFE"); if(!chat.mFromName.empty() && (mFrom != chat.mFromName)) @@ -727,6 +740,9 @@ public: case CHAT_SOURCE_SYSTEM: icon->setValue(LLSD("SL_Logo")); break; + case CHAT_SOURCE_TELEPORT: + icon->setValue(LLSD("Command_Destinations_Icon")); + break; case CHAT_SOURCE_UNKNOWN: icon->setValue(LLSD("Unknown_Icon")); } @@ -765,7 +781,7 @@ public: S32 user_name_width = user_name_rect.getWidth(); S32 time_box_width = time_box->getRect().getWidth(); - if (!time_box->getVisible() && user_name_width > mMinUserNameWidth) + if (mNeedsTimeBox && !time_box->getVisible() && user_name_width > mMinUserNameWidth) { user_name_rect.mRight -= time_box_width; user_name->reshape(user_name_rect.getWidth(), user_name_rect.getHeight()); @@ -967,6 +983,8 @@ protected: LLTextBox* mUserNameTextBox; LLTextBox* mTimeBoxTextBox; + bool mNeedsTimeBox; + private: boost::signals2::connection mAvatarNameCacheConnection; }; @@ -1085,7 +1103,8 @@ LLView* LLChatHistory::getSeparator() LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args) { LLChatHistoryHeader* header = LLChatHistoryHeader::createInstance(mMessageHeaderFilename); - header->setup(chat, style_params, args); + if (header) + header->setup(chat, style_params, args); return header; } @@ -1200,6 +1219,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL } bool message_from_log = chat.mChatStyle == CHAT_STYLE_HISTORY; + bool teleport_separator = chat.mSourceType == CHAT_SOURCE_TELEPORT; // We graying out chat history by graying out messages that contains full date in a time string if (message_from_log) { @@ -1220,14 +1240,14 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL LLStyle::Params timestamp_style(body_message_params); // out of the timestamp - if (args["show_time"].asBoolean()) - { - if (!message_from_log) + if (args["show_time"].asBoolean() && !teleport_separator) { - LLColor4 timestamp_color = LLUIColorTable::instance().getColor("ChatTimestampColor"); - timestamp_style.color(timestamp_color); - timestamp_style.readonly_color(timestamp_color); - } + if (!message_from_log) + { + LLColor4 timestamp_color = LLUIColorTable::instance().getColor("ChatTimestampColor"); + timestamp_style.color(timestamp_color); + timestamp_style.readonly_color(timestamp_color); + } mEditor->appendText("[" + chat.mTimeStr + "] ", prependNewLineState, timestamp_style); prependNewLineState = false; } @@ -1270,6 +1290,13 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL prependNewLineState, link_params); prependNewLineState = false; } + else if (teleport_separator) + { + std::string tp_text = LLTrans::getString("teleport_preamble_compact_chat"); + mEditor->appendText(tp_text + " <nolink>" + chat.mFromName + "</nolink>", + prependNewLineState, body_message_params); + prependNewLineState = false; + } else { mEditor->appendText("<nolink>" + chat.mFromName + "</nolink>" + delimiter, @@ -1288,8 +1315,8 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL p.right_pad = mRightWidgetPad; LLDate new_message_time = LLDate::now(); - - if (mLastFromName == chat.mFromName + if (!teleport_separator + && mLastFromName == chat.mFromName && mLastFromID == chat.mFromID && mLastMessageTime.notNull() && (new_message_time.secondsSinceEpoch() - mLastMessageTime.secondsSinceEpoch()) < 60.0 @@ -1298,6 +1325,12 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL view = getSeparator(); p.top_pad = mTopSeparatorPad; p.bottom_pad = mBottomSeparatorPad; + if (!view) + { + // Might be wiser to make this LL_ERRS, getSeparator() should work in case of correct instalation. + LL_WARNS() << "Failed to create separator from " << mMessageSeparatorFilename << ": can't append to history" << LL_ENDL; + return; + } } else { @@ -1306,7 +1339,19 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL p.top_pad = 0; else p.top_pad = mTopHeaderPad; - p.bottom_pad = mBottomHeaderPad; + if (teleport_separator) + { + p.bottom_pad = mBottomSeparatorPad; + } + else + { + p.bottom_pad = mBottomHeaderPad; + } + if (!view) + { + LL_WARNS() << "Failed to create header from " << mMessageHeaderFilename << ": can't append to history" << LL_ENDL; + return; + } } p.view = view; @@ -1344,10 +1389,8 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL // We don't want multiple friendship offers to appear, this code checks if there are previous offers // by iterating though all panels. // Note: it might be better to simply add a "pending offer" flag somewhere - for (LLToastNotifyPanel::instance_iter ti(LLToastNotifyPanel::beginInstances()) - , tend(LLToastNotifyPanel::endInstances()); ti != tend; ++ti) + for (auto& panel : LLToastNotifyPanel::instance_snapshot()) { - LLToastNotifyPanel& panel = *ti; LLIMToastNotifyPanel * imtoastp = dynamic_cast<LLIMToastNotifyPanel *>(&panel); const std::string& notification_name = panel.getNotificationName(); if (notification_name == "OfferFriendship" @@ -1381,9 +1424,8 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL } } } - // usual messages showing - else + else if(!teleport_separator) { std::string message = irc_me ? chat.mText.substr(3) : chat.mText; @@ -1416,7 +1458,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL if (square_brackets) { message += "]"; - } + } mEditor->appendText(message, prependNewLineState, body_message_params); prependNewLineState = false; diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index 4f42868f1a..1c22e055bb 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "llchatitemscontainerctrl.h" +#include "llchatmsgbox.h" #include "lltextbox.h" #include "llavataractions.h" diff --git a/indra/newview/llchatitemscontainerctrl.h b/indra/newview/llchatitemscontainerctrl.h index f66670ec8c..ebff9ca298 100644 --- a/indra/newview/llchatitemscontainerctrl.h +++ b/indra/newview/llchatitemscontainerctrl.h @@ -28,12 +28,13 @@ #define LL_LLCHATITEMSCONTAINERCTRL_H_ #include "llchat.h" -#include "llchatmsgbox.h" #include "llpanel.h" #include "llscrollbar.h" #include "llviewerchat.h" #include "lltoastpanel.h" +class LLChatMsgBox; + typedef enum e_show_item_header { CHATITEMHEADER_SHOW_ONLY_NAME = 0, diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index dedb06c945..0f187b0ecf 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -36,6 +36,7 @@ #include "llsingleton.h" #include "llsyswellwindow.h" #include "llfloaternotificationstabbed.h" +#include "llviewermenu.h" static LLDefaultChildRegistry::Register<LLChicletPanel> t1("chiclet_panel"); static LLDefaultChildRegistry::Register<LLNotificationChiclet> t2("chiclet_notification"); @@ -1092,6 +1093,10 @@ void LLScriptChiclet::onMenuItemClicked(const LLSD& user_data) { LLScriptFloaterManager::instance().removeNotification(getSessionId()); } + else if ("close all" == action) + { + LLIMWellWindow::getInstance()->closeAll(); + } } void LLScriptChiclet::createPopupMenu() diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp index 1caefd58ab..b31981b235 100644 --- a/indra/newview/llcofwearables.cpp +++ b/indra/newview/llcofwearables.cpp @@ -140,10 +140,31 @@ protected: { LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + registrar.add("Attachment.Touch", boost::bind(handleMultiple, handle_attachment_touch, mUUIDs)); + registrar.add("Attachment.Edit", boost::bind(handleMultiple, handle_item_edit, mUUIDs)); registrar.add("Attachment.Detach", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs)); + LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; + enable_registrar.add("Attachment.OnEnable", boost::bind(&CofAttachmentContextMenu::onEnable, this, _2)); + return createFromFile("menu_cof_attachment.xml"); } + + bool onEnable(const LLSD& userdata) + { + const std::string event_name = userdata.asString(); + + if ("touch" == event_name) + { + return (1 == mUUIDs.size()) && (enable_attachment_touch(mUUIDs.front())); + } + else if ("edit" == event_name) + { + return (1 == mUUIDs.size()) && (get_is_item_editable(mUUIDs.front())); + } + + return true; + } }; ////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llcolorswatch.h b/indra/newview/llcolorswatch.h index 380fdccfa3..a17cab486a 100644 --- a/indra/newview/llcolorswatch.h +++ b/indra/newview/llcolorswatch.h @@ -36,7 +36,6 @@ // Classes // class LLColor4; -class LLFloaterColorPicker; class LLColorSwatchCtrl : public LLUICtrl diff --git a/indra/newview/llcommandhandler.cpp b/indra/newview/llcommandhandler.cpp index 76d965b1f1..23e2271eae 100644 --- a/indra/newview/llcommandhandler.cpp +++ b/indra/newview/llcommandhandler.cpp @@ -222,7 +222,7 @@ struct symbol_info #define ent(SYMBOL) \ { \ - #SYMBOL + 28, /* skip "LLCommandHandler::UNTRUSTED_" prefix */ \ + &#SYMBOL[28], /* skip "LLCommandHandler::UNTRUSTED_" prefix */ \ SYMBOL \ } diff --git a/indra/newview/llcommandlineparser.cpp b/indra/newview/llcommandlineparser.cpp index fe14bc081f..06d959ba3c 100644 --- a/indra/newview/llcommandlineparser.cpp +++ b/indra/newview/llcommandlineparser.cpp @@ -402,23 +402,30 @@ bool LLCommandLineParser::parseCommandLineString(const std::string& str) } } - // Split the string content into tokens - const char* escape_chars = "\\"; - const char* separator_chars = "\r\n "; - const char* quote_chars = "\"'"; - boost::escaped_list_separator<char> sep(escape_chars, separator_chars, quote_chars); - boost::tokenizer< boost::escaped_list_separator<char> > tok(cmd_line_string, sep); std::vector<std::string> tokens; - // std::copy(tok.begin(), tok.end(), std::back_inserter(tokens)); - for(boost::tokenizer< boost::escaped_list_separator<char> >::iterator i = tok.begin(); - i != tok.end(); - ++i) + try { - if(0 != i->size()) + // Split the string content into tokens + const char* escape_chars = "\\"; + const char* separator_chars = "\r\n "; + const char* quote_chars = "\"'"; + boost::escaped_list_separator<char> sep(escape_chars, separator_chars, quote_chars); + boost::tokenizer< boost::escaped_list_separator<char> > tok(cmd_line_string, sep); + // std::copy(tok.begin(), tok.end(), std::back_inserter(tokens)); + for (boost::tokenizer< boost::escaped_list_separator<char> >::iterator i = tok.begin(); + i != tok.end(); + ++i) { - tokens.push_back(*i); + if (0 != i->size()) + { + tokens.push_back(*i); + } } } + catch (...) + { + CRASH_ON_UNHANDLED_EXCEPTION(STRINGIZE("Unexpected crash while parsing: " << str)); + } po::command_line_parser clp(tokens); return parseAndStoreResults(clp); diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp index 76e16f5a1f..bf10a9f2b4 100644 --- a/indra/newview/llcompilequeue.cpp +++ b/indra/newview/llcompilequeue.cpp @@ -347,6 +347,13 @@ void LLFloaterCompileQueue::processExperienceIdResults(LLSD result, LLUUID paren bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloater, const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump) { + if (LLApp::isExiting()) + { + // Reply from coroutine came on shutdown + // We are quiting, don't start any more coroutines! + return true; + } + LLSD result; LLCheckedHandle<LLFloaterCompileQueue> floater(hfloater); // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle. @@ -381,6 +388,8 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, LLSDMap("timeout", LLSD::Boolean(true))); + floater.check(); + if (result.has("timeout")) { // A timeout filed in the result will always be true if present. LLStringUtil::format_map_t args; @@ -404,6 +413,12 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat } + if (!gAssetStorage) + { + // viewer likely is shutting down + return true; + } + { HandleScriptUserData userData(pump.getName()); @@ -468,6 +483,8 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, LLSDMap("timeout", LLSD::Boolean(true))); + floater.check(); + if (result.has("timeout")) { // A timeout filed in the result will always be true if present. LLStringUtil::format_map_t args; @@ -797,6 +814,7 @@ void LLFloaterScriptQueue::objectScriptProcessingQueueCoro(std::string action, L // but offers no guarantee of doing so. llcoro::suspend(); } + floater.check(); } floater->addStringMessage("Done"); diff --git a/indra/newview/llcompilequeue.h b/indra/newview/llcompilequeue.h index 1b3d8f83a0..adb854875a 100644 --- a/indra/newview/llcompilequeue.h +++ b/indra/newview/llcompilequeue.h @@ -29,14 +29,11 @@ #include "llinventory.h" #include "llviewerobject.h" -#include "llvoinventorylistener.h" #include "lluuid.h" #include "llfloater.h" #include "llscrolllistctrl.h" -#include "llviewerinventory.h" - #include "llevents.h" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index 92eeebd705..fab249f988 100644 --- a/indra/newview/llcontrolavatar.cpp +++ b/indra/newview/llcontrolavatar.cpp @@ -35,8 +35,6 @@ #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; @@ -80,6 +78,24 @@ void LLControlAvatar::initInstance() mInitFlags |= 1<<4; } +const LLVOAvatar *LLControlAvatar::getAttachedAvatar() const +{ + if (mRootVolp && mRootVolp->isAttachment()) + { + return mRootVolp->getAvatarAncestor(); + } + return NULL; +} + +LLVOAvatar *LLControlAvatar::getAttachedAvatar() +{ + if (mRootVolp && mRootVolp->isAttachment()) + { + return mRootVolp->getAvatarAncestor(); + } + return NULL; +} + void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_scale_fixup) const { @@ -167,11 +183,14 @@ void LLControlAvatar::matchVolumeTransform() if (mRootVolp->isAttachment()) { - LLVOAvatar *attached_av = mRootVolp->getAvatarAncestor(); + LLVOAvatar *attached_av = getAttachedAvatar(); if (attached_av) { LLViewerJointAttachment *attach = attached_av->getTargetAttachmentPoint(mRootVolp); - setPositionAgent(mRootVolp->getRenderPosition()); + if (getRegion() && !isDead()) + { + setPositionAgent(mRootVolp->getRenderPosition()); + } attach->updateWorldPRSParent(); LLVector3 joint_pos = attach->getWorldPosition(); LLQuaternion joint_rot = attach->getWorldRotation(); @@ -227,7 +246,10 @@ void LLControlAvatar::matchVolumeTransform() #endif setRotation(bind_rot*obj_rot); mRoot->setWorldRotation(bind_rot*obj_rot); - setPositionAgent(vol_pos); + if (getRegion() && !isDead()) + { + setPositionAgent(vol_pos); + } mRoot->setPosition(vol_pos + mPositionConstraintFixup); F32 global_scale = gSavedSettings.getF32("AnimatedObjectsGlobalScale"); @@ -257,7 +279,7 @@ void LLControlAvatar::recursiveScaleJoint(LLJoint* joint, F32 factor) { joint->setScale(factor * joint->getScale()); - for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); + for (LLJoint::joints_t::iterator iter = joint->mChildren.begin(); iter != joint->mChildren.end(); ++iter) { LLJoint* child = *iter; @@ -356,7 +378,34 @@ void LLControlAvatar::idleUpdate(LLAgent &agent, const F64 &time) } } -BOOL LLControlAvatar::updateCharacter(LLAgent &agent) +bool LLControlAvatar::computeNeedsUpdate() +{ + computeUpdatePeriod(); + + // Animesh attachments are a special case. Should have the same update cadence as their attached parent avatar. + LLVOAvatar *attached_av = getAttachedAvatar(); + if (attached_av) + { + // Have to run computeNeedsUpdate() for attached av in + // case it hasn't run updateCharacter() already this + // frame. Note this means that the attached av will + // run computeNeedsUpdate() multiple times per frame + // if it has animesh attachments. Results will be + // consistent except for the corner case of exceeding + // MAX_IMPOSTOR_INTERVAL in one call but not another, + // which should be rare. + attached_av->computeNeedsUpdate(); + mNeedsImpostorUpdate = attached_av->mNeedsImpostorUpdate; + if (mNeedsImpostorUpdate) + { + mLastImpostorUpdateReason = 12; + } + return mNeedsImpostorUpdate; + } + return LLVOAvatar::computeNeedsUpdate(); +} + +bool LLControlAvatar::updateCharacter(LLAgent &agent) { return LLVOAvatar::updateCharacter(agent); } @@ -574,12 +623,12 @@ LLViewerObject* LLControlAvatar::lineSegmentIntersectRiggedAttachments(const LLV return NULL; } - LLViewerObject* hit = NULL; + LLViewerObject* hit = NULL; - if (lineSegmentBoundingBox(start, end)) - { - LLVector4a local_end = end; - LLVector4a local_intersection; + 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; @@ -598,20 +647,20 @@ LLViewerObject* LLControlAvatar::lineSegmentIntersectRiggedAttachments(const LLV { LLVOVolume *volp = *vol_it; 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; - } + { + local_end = local_intersection; + if (intersection) + { + *intersection = local_intersection; + } hit = volp; break; } } } - } - - return hit; + } + + return hit; } // virtual @@ -630,29 +679,23 @@ std::string LLControlAvatar::getFullname() const // virtual bool LLControlAvatar::shouldRenderRigged() const { - if (mRootVolp && mRootVolp->isAttachment()) - { - LLVOAvatar *attached_av = mRootVolp->getAvatarAncestor(); - if (attached_av) - { - return attached_av->shouldRenderRigged(); - } - } + const LLVOAvatar *attached_av = getAttachedAvatar(); + if (attached_av) + { + return attached_av->shouldRenderRigged(); + } return true; } // virtual BOOL LLControlAvatar::isImpostor() { - 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(); - } - } + // Attached animated objects should match state of their attached av. + LLVOAvatar *attached_av = getAttachedAvatar(); + if (attached_av) + { + return attached_av->isImpostor(); + } return LLVOAvatar::isImpostor(); } diff --git a/indra/newview/llcontrolavatar.h b/indra/newview/llcontrolavatar.h index 288d07cd48..8e87299f3e 100644 --- a/indra/newview/llcontrolavatar.h +++ b/indra/newview/llcontrolavatar.h @@ -40,6 +40,10 @@ public: virtual void initInstance(); // Called after construction to initialize the class. virtual ~LLControlAvatar(); + // If this is an attachment, return the avatar it is attached to. Otherwise NULL. + virtual const LLVOAvatar *getAttachedAvatar() const; + virtual LLVOAvatar *getAttachedAvatar(); + void getNewConstraintFixups(LLVector3& new_pos_constraint, F32& new_scale_constraint) const; void matchVolumeTransform(); void updateVolumeGeom(); @@ -53,7 +57,8 @@ public: void markForDeath(); virtual void idleUpdate(LLAgent &agent, const F64 &time); - virtual BOOL updateCharacter(LLAgent &agent); + virtual bool computeNeedsUpdate(); + virtual bool updateCharacter(LLAgent &agent); void getAnimatedVolumes(std::vector<LLVOVolume*>& volumes); void updateAnimations(); diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp index 9ccf9b98f7..a696c99a82 100644 --- a/indra/newview/llconversationlog.cpp +++ b/indra/newview/llconversationlog.cpp @@ -189,16 +189,6 @@ LLConversationLog::LLConversationLog() : mAvatarNameCacheConnection(), mLoggingEnabled(false) { - if(gSavedPerAccountSettings.controlExists("KeepConversationLogTranscripts")) - { - LLControlVariable * keep_log_ctrlp = gSavedPerAccountSettings.getControl("KeepConversationLogTranscripts").get(); - S32 log_mode = keep_log_ctrlp->getValue(); - keep_log_ctrlp->getSignal()->connect(boost::bind(&LLConversationLog::enableLogging, this, _2)); - if (log_mode > 0) - { - enableLogging(log_mode); - } - } } void LLConversationLog::enableLogging(S32 log_mode) @@ -408,6 +398,24 @@ void LLConversationLog::deleteBackupLogs() } } +void LLConversationLog::verifyFilename(const LLUUID& session_id, const std::string &expected_filename, const std::string &new_session_name) +{ + conversations_vec_t::iterator conv_it = mConversations.begin(); + for (; conv_it != mConversations.end(); ++conv_it) + { + if (conv_it->getSessionID() == session_id) + { + if (conv_it->getHistoryFileName() != expected_filename) + { + LLLogChat::renameLogFile(conv_it->getHistoryFileName(), expected_filename); + conv_it->updateHistoryFileName(expected_filename); + conv_it->setConversationName(new_session_name); + } + break; + } + } +} + bool LLConversationLog::moveLog(const std::string &originDirectory, const std::string &targetDirectory) { @@ -443,6 +451,20 @@ bool LLConversationLog::moveLog(const std::string &originDirectory, const std::s return true; } +void LLConversationLog::initLoggingState() +{ + if (gSavedPerAccountSettings.controlExists("KeepConversationLogTranscripts")) + { + LLControlVariable * keep_log_ctrlp = gSavedPerAccountSettings.getControl("KeepConversationLogTranscripts").get(); + S32 log_mode = keep_log_ctrlp->getValue(); + keep_log_ctrlp->getSignal()->connect(boost::bind(&LLConversationLog::enableLogging, this, _2)); + if (log_mode > 0) + { + enableLogging(log_mode); + } + } +} + std::string LLConversationLog::getFileName() { std::string filename = "conversation"; @@ -478,6 +500,10 @@ bool LLConversationLog::saveToFile(const std::string& filename) conv_it->getSessionID().toString(conversation_id); conv_it->getParticipantID().toString(participant_id); + bool is_adhoc = (conv_it->getConversationType() == LLIMModel::LLIMSession::ADHOC_SESSION); + std::string conv_name = is_adhoc ? conv_it->getConversationName() : LLURI::escape(conv_it->getConversationName()); + std::string file_name = is_adhoc ? conv_it->getHistoryFileName() : LLURI::escape(conv_it->getHistoryFileName()); + // examples of two file entries // [1343221177] 0 1 0 John Doe| 7e4ec5be-783f-49f5-71dz-16c58c64c145 4ec62a74-c246-0d25-2af6-846beac2aa55 john.doe| // [1343222639] 2 0 0 Ad-hoc Conference| c3g67c89-c479-4c97-b21d-32869bcfe8rc 68f1c33e-4135-3e3e-a897-8c9b23115c09 Ad-hoc Conference hash597394a0-9982-766d-27b8-c75560213b9a| @@ -486,10 +512,10 @@ bool LLConversationLog::saveToFile(const std::string& filename) (S32)conv_it->getConversationType(), (S32)0, (S32)conv_it->hasOfflineMessages(), - conv_it->getConversationName().c_str(), + conv_name.c_str(), participant_id.c_str(), conversation_id.c_str(), - LLURI::escape(conv_it->getHistoryFileName()).c_str()); + file_name.c_str()); } fclose(fp); return true; @@ -510,7 +536,9 @@ bool LLConversationLog::loadFromFile(const std::string& filename) } bool purge_required = false; - char buffer[MAX_STRING]; + static constexpr int UTF_BUFFER{ 1024 }; // long enough to handle the most extreme Unicode nonsense and some to spare + + char buffer[UTF_BUFFER]; char conv_name_buffer[MAX_STRING]; char part_id_buffer[MAX_STRING]; char conv_id_buffer[MAX_STRING]; @@ -521,11 +549,14 @@ bool LLConversationLog::loadFromFile(const std::string& filename) // before CHUI-348 it was a flag of conversation voice state int prereserved_unused; - while (!feof(fp) && fgets(buffer, MAX_STRING, fp)) + memset(buffer, '\0', UTF_BUFFER); + while (!feof(fp) && fgets(buffer, UTF_BUFFER, fp)) { - conv_name_buffer[0] = '\0'; - part_id_buffer[0] = '\0'; - conv_id_buffer[0] = '\0'; + // force blank for added safety + memset(conv_name_buffer, '\0', MAX_STRING); + memset(part_id_buffer, '\0', MAX_STRING); + memset(conv_id_buffer, '\0', MAX_STRING); + memset(history_file_name, '\0', MAX_STRING); sscanf(buffer, "[%lld] %d %d %d %[^|]| %s %s %[^|]|", &time, @@ -537,14 +568,18 @@ bool LLConversationLog::loadFromFile(const std::string& filename) conv_id_buffer, history_file_name); + bool is_adhoc = ((SessionType)stype == LLIMModel::LLIMSession::ADHOC_SESSION); + std::string conv_name = is_adhoc ? conv_name_buffer : LLURI::unescape(conv_name_buffer); + std::string file_name = is_adhoc ? history_file_name : LLURI::unescape(history_file_name); + ConversationParams params; params.time(LLUnits::Seconds::fromValue(time)) .conversation_type((SessionType)stype) .has_offline_ims(has_offline_ims) - .conversation_name(conv_name_buffer) + .conversation_name(conv_name) .participant_id(LLUUID(part_id_buffer)) .session_id(LLUUID(conv_id_buffer)) - .history_filename(LLURI::unescape(history_file_name)); + .history_filename(file_name); LLConversation conversation(params); @@ -558,6 +593,7 @@ bool LLConversationLog::loadFromFile(const std::string& filename) } mConversations.push_back(conversation); + memset(buffer, '\0', UTF_BUFFER); } fclose(fp); diff --git a/indra/newview/llconversationlog.h b/indra/newview/llconversationlog.h index 035cbcb945..820a5db491 100644 --- a/indra/newview/llconversationlog.h +++ b/indra/newview/llconversationlog.h @@ -59,7 +59,7 @@ public: getTime() const { return mTime; } bool hasOfflineMessages() const { return mHasOfflineIMs; } - void setConversationName(std::string conv_name) { mConversationName = conv_name; } + void setConversationName(const std::string &conv_name) { mConversationName = conv_name; } void setOfflineMessages(bool new_messages) { mHasOfflineIMs = new_messages; } bool isOlderThan(U32Days days) const; @@ -68,6 +68,8 @@ public: */ void updateTimestamp(); + void updateHistoryFileName(const std::string &new_name) { mHistoryFileName = new_name; } + /* * Resets flag of unread offline message to false when im floater with this conversation is opened. */ @@ -111,7 +113,6 @@ class LLConversationLog : public LLSingleton<LLConversationLog>, LLIMSessionObse { LLSINGLETON(LLConversationLog); public: - void removeConversation(const LLConversation& conversation); /** @@ -138,6 +139,8 @@ public: * public method which is called on viewer exit to save conversation log */ void cache(); + // will check if current name is edentical with the one on disk and will rename the one on disk if it isn't + void verifyFilename(const LLUUID& session_id, const std::string &expected_filename, const std::string &new_session_name); bool moveLog(const std::string &originDirectory, const std::string &targetDirectory); void getListOfBackupLogs(std::vector<std::string>& list_of_backup_logs); void deleteBackupLogs(); @@ -149,6 +152,12 @@ public: bool isLogEmpty() { return mConversations.empty(); } /** + * inits connection to per account settings, + * loads saved file and inits enabled state + */ + void initLoggingState(); + + /** * constructs file name in which conversations log will be saved * file name is conversation.log */ diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index c258136889..a685639427 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -92,6 +92,23 @@ LLConversationItem::~LLConversationItem() } } +//virtual +void LLConversationItem::addChild(LLFolderViewModelItem* child) +{ + // Avoid duplicates: bail out if that child is already present in the list + // Note: this happens when models are created and 'parented' before views + // This is performance unfriendly, but conversation can addToFolder multiple times + child_list_t::const_iterator iter; + for (iter = mChildren.begin(); iter != mChildren.end(); iter++) + { + if (child == *iter) + { + return; + } + } + LLFolderViewModelItemCommon::addChild(child); +} + void LLConversationItem::postEvent(const std::string& event_type, LLConversationItemSession* session, LLConversationItemParticipant* participant) { LLUUID session_id = (session ? session->getUUID() : LLUUID()); @@ -324,11 +341,36 @@ void LLConversationItemSession::removeParticipant(const LLUUID& participant_id) void LLConversationItemSession::clearParticipants() { + // clearParticipants function potentially is malfunctioning since it only cleans children of models, + // it does nothing to views that own those models (listeners) + // probably needs to post some kind of 'remove all participants' event clearChildren(); mIsLoaded = false; mNeedsRefresh = true; } + +void LLConversationItemSession::clearAndDeparentModels() +{ + std::for_each(mChildren.begin(), mChildren.end(), + [](LLFolderViewModelItem* c) + { + if (c->getNumRefs() == 0) + { + // LLConversationItemParticipant can be created but not assigned to any view, + // it was waiting for an "add_participant" event to be processed + delete c; + } + else + { + // Model is still assigned to some view/widget + c->setParent(NULL); + } + } + ); + mChildren.clear(); +} + LLConversationItemParticipant* LLConversationItemSession::findParticipant(const LLUUID& participant_id) { // This is *not* a general tree parsing algorithm. It assumes that a session contains only @@ -338,7 +380,7 @@ LLConversationItemParticipant* LLConversationItemSession::findParticipant(const for (iter = mChildren.begin(); iter != mChildren.end(); iter++) { participant = dynamic_cast<LLConversationItemParticipant*>(*iter); - if (participant->hasSameValue(participant_id)) + if (participant && participant->hasSameValue(participant_id)) { break; } @@ -449,7 +491,7 @@ const bool LLConversationItemSession::getTime(F64& time) const { participant = dynamic_cast<LLConversationItemParticipant*>(*iter); F64 participant_time; - if (participant->getTime(participant_time)) + if (participant && participant->getTime(participant_time)) { has_time = true; most_recent_time = llmax(most_recent_time,participant_time); diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h index 80385fad5f..787deeb594 100644 --- a/indra/newview/llconversationmodel.h +++ b/indra/newview/llconversationmodel.h @@ -96,6 +96,7 @@ public: virtual void buildContextMenu(LLMenuGL& menu, U32 flags) { } virtual BOOL isUpToDate() const { return TRUE; } virtual bool hasChildren() const { return FALSE; } + virtual void addChild(LLFolderViewModelItem* child); virtual bool potentiallyVisible() { return true; } virtual bool filter( LLFolderViewFilter& filter) { return false; } @@ -164,6 +165,7 @@ public: void removeParticipant(LLConversationItemParticipant* participant); void removeParticipant(const LLUUID& participant_id); void clearParticipants(); + void clearAndDeparentModels(); // will delete unowned models and deparent owned ones LLConversationItemParticipant* findParticipant(const LLUUID& participant_id); void setParticipantIsMuted(const LLUUID& participant_id, bool is_muted); diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index 0075b62100..65cec68884 100644 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -31,6 +31,7 @@ #include <boost/bind.hpp> #include "llagentdata.h" +#include "llavataractions.h" #include "llconversationmodel.h" #include "llfloaterimsession.h" #include "llfloaterimnearbychat.h" @@ -102,6 +103,56 @@ LLConversationViewSession::~LLConversationViewSession() mFlashTimer->unset(); } +void LLConversationViewSession::destroyView() +{ + // Chat can create and parent models(listeners) to session's model before creating + // coresponding views, such participant's models normally will wait for idle cycles + // but since we are deleting session and won't be processing any more events, make + // sure unowned LLConversationItemParticipant models are removed as well. + + LLConversationItemSession* vmi = dynamic_cast<LLConversationItemSession*>(getViewModelItem()); + + // CONV_SESSION_1_ON_1 stores participants as two models that belong to views independent + // from session (nasty! These views are widgets in LLFloaterIMSessionTab, see buildConversationViewParticipant) + if (vmi && vmi->getType() != LLConversationItem::CONV_SESSION_1_ON_1) + { + // Destroy existing views + while (!mItems.empty()) + { + LLFolderViewItem *itemp = mItems.back(); + mItems.pop_back(); + + LLFolderViewModelItem* item_vmi = itemp->getViewModelItem(); + if (item_vmi) // supposed to exist + { + // unparent to remove from child list + vmi->removeChild(item_vmi); + } + itemp->destroyView(); + } + + // Not needed in scope of sessions, but just in case + while (!mFolders.empty()) + { + LLFolderViewFolder *folderp = mFolders.back(); + mFolders.pop_back(); + + LLFolderViewModelItem* folder_vmi = folderp->getViewModelItem(); + if (folder_vmi) + { + vmi->removeChild(folder_vmi); + } + folderp->destroyView(); + } + + // Now everything that is left in model(listener) is not owned by views, + // only by sessions, deparent so it won't point to soon to be dead model + vmi->clearAndDeparentModels(); + } + + LLFolderViewFolder::destroyView(); +} + void LLConversationViewSession::setFlashState(bool flash_state) { if (flash_state && !mFlashStateOn) @@ -175,7 +226,7 @@ BOOL LLConversationViewSession::postBuild() LLAvatarIconCtrl* icon = mItemPanel->getChild<LLAvatarIconCtrl>("avatar_icon"); icon->setVisible(true); icon->setValue(session->mOtherParticipantID); - mSpeakingIndicator->setSpeakerId(gAgentID, session->mSessionID, true); + mSpeakingIndicator->setSpeakerId(session->mOtherParticipantID, session->mSessionID, true); mHasArrow = false; } break; @@ -430,10 +481,15 @@ void LLConversationViewSession::refresh() // Refresh the session view from its model data LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(getViewModelItem()); vmi->resetRefresh(); - + if (mSessionTitle) - { - mSessionTitle->setText(vmi->getDisplayName()); + { + if (!highlightFriendTitle(vmi)) + { + LLStyle::Params title_style; + title_style.color = LLUIColorTable::instance().getColor("LabelTextColor"); + mSessionTitle->setText(vmi->getDisplayName(), title_style); + } } // Update all speaking indicators @@ -478,6 +534,22 @@ void LLConversationViewSession::onCurrentVoiceSessionChanged(const LLUUID& sessi } } +bool LLConversationViewSession::highlightFriendTitle(LLConversationItem* vmi) +{ + if(vmi->getType() == LLConversationItem::CONV_PARTICIPANT || vmi->getType() == LLConversationItem::CONV_SESSION_1_ON_1) + { + LLIMModel::LLIMSession* session= LLIMModel::instance().findIMSession(vmi->getUUID()); + if (session && LLAvatarActions::isFriend(session->mOtherParticipantID)) + { + LLStyle::Params title_style; + title_style.color = LLUIColorTable::instance().getColor("ConversationFriendColor"); + mSessionTitle->setText(vmi->getDisplayName(), title_style); + return true; + } + } + return false; +} + // // Implementation of conversations list participant (avatar) widgets // @@ -545,7 +617,9 @@ BOOL LLConversationViewParticipant::postBuild() } updateChildren(); - return LLFolderViewItem::postBuild(); + LLFolderViewItem::postBuild(); + refresh(); + return TRUE; } void LLConversationViewParticipant::draw() @@ -576,7 +650,14 @@ void LLConversationViewParticipant::draw() } else { - color = mIsSelected ? sHighlightFgColor : sFgColor; + if (LLAvatarActions::isFriend(mUUID)) + { + color = LLUIColorTable::instance().getColor("ConversationFriendColor"); + } + else + { + color = mIsSelected ? sHighlightFgColor : sFgColor; + } } LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(getViewModelItem()); @@ -615,11 +696,14 @@ void LLConversationViewParticipant::refresh() { // Refresh the participant view from its model data LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(getViewModelItem()); - participant_model->resetRefresh(); - - // *TODO: We should also do something with vmi->isModerator() to echo that state in the UI somewhat - mSpeakingIndicator->setIsModeratorMuted(participant_model->isModeratorMuted()); - + if (participant_model) + { + participant_model->resetRefresh(); + + // *TODO: We should also do something with vmi->isModerator() to echo that state in the UI somewhat + mSpeakingIndicator->setIsModeratorMuted(participant_model->isModeratorMuted()); + } + // Do the regular upstream refresh LLFolderViewItem::refresh(); } diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h index 420c250dfe..0932d24dfe 100644 --- a/indra/newview/llconversationview.h +++ b/indra/newview/llconversationview.h @@ -34,7 +34,9 @@ #include "lloutputmonitorctrl.h" class LLTextBox; +class LLFloater; class LLFloaterIMContainer; +class LLConversationItem; class LLConversationViewSession; class LLConversationViewParticipant; @@ -65,6 +67,8 @@ protected: public: virtual ~LLConversationViewSession(); + /*virtual*/ void destroyView(); + /*virtual*/ BOOL postBuild(); /*virtual*/ void draw(); /*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask ); @@ -92,6 +96,8 @@ public: LLFloater* getSessionFloater(); bool isInActiveVoiceChannel() { return mIsInActiveVoiceChannel; } + bool highlightFriendTitle(LLConversationItem* vmi); + private: void onCurrentVoiceSessionChanged(const LLUUID& session_id); diff --git a/indra/newview/llcurrencyuimanager.cpp b/indra/newview/llcurrencyuimanager.cpp index b4a1457f47..232e461fd0 100644 --- a/indra/newview/llcurrencyuimanager.cpp +++ b/indra/newview/llcurrencyuimanager.cpp @@ -166,11 +166,11 @@ void LLCurrencyUIManager::Impl::updateCurrencyInfo() gAgent.getSecureSessionID().asString()); keywordArgs.appendString("language", LLUI::getLanguage()); keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy); - keywordArgs.appendString("viewerChannel", LLVersionInfo::getChannel()); - keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::getMajor()); - keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::getMinor()); - keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::getPatch()); - keywordArgs.appendInt("viewerBuildVersion", LLVersionInfo::getBuild()); + keywordArgs.appendString("viewerChannel", LLVersionInfo::instance().getChannel()); + keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::instance().getMajor()); + keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::instance().getMinor()); + keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::instance().getPatch()); + keywordArgs.appendInt("viewerBuildVersion", LLVersionInfo::instance().getBuild()); LLXMLRPCValue params = LLXMLRPCValue::createArray(); params.append(keywordArgs); @@ -241,11 +241,11 @@ void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password) { keywordArgs.appendString("password", password); } - keywordArgs.appendString("viewerChannel", LLVersionInfo::getChannel()); - keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::getMajor()); - keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::getMinor()); - keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::getPatch()); - keywordArgs.appendInt("viewerBuildVersion", LLVersionInfo::getBuild()); + keywordArgs.appendString("viewerChannel", LLVersionInfo::instance().getChannel()); + keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::instance().getMajor()); + keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::instance().getMinor()); + keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::instance().getPatch()); + keywordArgs.appendInt("viewerBuildVersion", LLVersionInfo::instance().getBuild()); LLXMLRPCValue params = LLXMLRPCValue::createArray(); params.append(keywordArgs); @@ -454,7 +454,7 @@ void LLCurrencyUIManager::Impl::updateUI() if (!mUserEnteredCurrencyBuy) { - if (!mZeroMessage.empty() && mUserCurrencyBuy == 0) + if (mUserCurrencyBuy == 0) { lindenAmount->setText(LLStringUtil::null); } @@ -467,8 +467,9 @@ void LLCurrencyUIManager::Impl::updateUI() } } - mPanel.getChild<LLUICtrl>("currency_est")->setTextArg("[LOCALAMOUNT]", getLocalEstimate()); - mPanel.getChildView("currency_est")->setVisible( hasEstimate() && mUserCurrencyBuy > 0); + std::string estimated = (mUserCurrencyBuy == 0) ? mPanel.getString("estimated_zero") : getLocalEstimate(); + mPanel.getChild<LLUICtrl>("currency_est")->setTextArg("[LOCALAMOUNT]", estimated); + mPanel.getChildView("currency_est")->setVisible( hasEstimate() || mUserCurrencyBuy == 0); mPanel.getChildView("currency_links")->setVisible( mSupportsInternationalBilling); mPanel.getChildView("exchange_rate_note")->setVisible( mSupportsInternationalBilling); @@ -603,6 +604,11 @@ bool LLCurrencyUIManager::bought() return impl.mBought; } +void LLCurrencyUIManager::clearError() +{ + impl.clearError(); +} + bool LLCurrencyUIManager::hasError() { return impl.mError; diff --git a/indra/newview/llcurrencyuimanager.h b/indra/newview/llcurrencyuimanager.h index 3f37db8db1..7c05acbb05 100644 --- a/indra/newview/llcurrencyuimanager.h +++ b/indra/newview/llcurrencyuimanager.h @@ -80,6 +80,8 @@ public: bool buying(); // are we in the process of buying? bool bought(); // did the buy() transaction complete successfully + void clearError(); + bool hasError(); std::string errorMessage(); std::string errorURI(); diff --git a/indra/newview/lldaycyclemanager.cpp b/indra/newview/lldaycyclemanager.cpp deleted file mode 100644 index 803e2b2fb2..0000000000 --- a/indra/newview/lldaycyclemanager.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/** - * @file lldaycyclemanager.cpp - * @brief Implementation for the LLDayCycleManager class. - * - * $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 "lldaycyclemanager.h" - -#include "lldiriterator.h" - -void LLDayCycleManager::getPresetNames(preset_name_list_t& names) const -{ - names.clear(); - - for (dc_map_t::const_iterator it = mDayCycleMap.begin(); it != mDayCycleMap.end(); ++it) - { - names.push_back(it->first); - } -} - -void LLDayCycleManager::getPresetNames(preset_name_list_t& user, preset_name_list_t& sys) const -{ - user.clear(); - sys.clear(); - - for (dc_map_t::const_iterator it = mDayCycleMap.begin(); it != mDayCycleMap.end(); ++it) - { - const std::string& name = it->first; - - if (isSystemPreset(name)) - { - sys.push_back(name); - } - else - { - user.push_back(name); - } - } -} - -void LLDayCycleManager::getUserPresetNames(preset_name_list_t& user) const -{ - preset_name_list_t sys; // unused - getPresetNames(user, sys); -} - -bool LLDayCycleManager::getPreset(const std::string name, LLWLDayCycle& day_cycle) const -{ - dc_map_t::const_iterator it = mDayCycleMap.find(name); - if (it == mDayCycleMap.end()) - { - return false; - } - - day_cycle = it->second; - return true; -} - -bool LLDayCycleManager::getPreset(const std::string name, LLSD& day_cycle) const -{ - LLWLDayCycle dc; - if (!getPreset(name, dc)) - { - return false; - } - - day_cycle = dc.asLLSD(); - return true; -} - -bool LLDayCycleManager::presetExists(const std::string name) const -{ - LLWLDayCycle dummy; - return getPreset(name, dummy); -} - -bool LLDayCycleManager::isSystemPreset(const std::string& name) const -{ - return gDirUtilp->fileExists(getSysDir() + LLURI::escape(name) + ".xml"); -} - -bool LLDayCycleManager::savePreset(const std::string& name, const LLSD& data) -{ - // Save given preset. - LLWLDayCycle day; - day.loadDayCycle(data, LLEnvKey::SCOPE_LOCAL); - day.save(getUserDir() + LLURI::escape(name) + ".xml"); - - // Add it to our map. - addPreset(name, data); - mModifySignal(); - return true; -} - -bool LLDayCycleManager::deletePreset(const std::string& name) -{ - // Remove it from the map. - dc_map_t::iterator it = mDayCycleMap.find(name); - if (it == mDayCycleMap.end()) - { - LL_WARNS("Windlight") << "No day cycle named " << name << LL_ENDL; - return false; - } - mDayCycleMap.erase(it); - - // Remove from the filesystem. - std::string filename = LLURI::escape(name) + ".xml"; - if (gDirUtilp->fileExists(getUserDir() + filename)) - { - gDirUtilp->deleteFilesInDir(getUserDir(), filename); - } - - // Signal interested parties. - mModifySignal(); - return true; -} - -bool LLDayCycleManager::isSkyPresetReferenced(const std::string& preset_name) const -{ - // We're traversing local day cycles, they can only reference local skies. - LLWLParamKey key(preset_name, LLEnvKey::SCOPE_LOCAL); - - for (dc_map_t::const_iterator it = mDayCycleMap.begin(); it != mDayCycleMap.end(); ++it) - { - if (it->second.hasReferencesTo(key)) - { - return true; - } - } - - return false; -} - -boost::signals2::connection LLDayCycleManager::setModifyCallback(const modify_signal_t::slot_type& cb) -{ - return mModifySignal.connect(cb); -} - -// virtual -void LLDayCycleManager::initSingleton() -{ - LL_DEBUGS("Windlight") << "Loading all day cycles" << LL_ENDL; - loadAllPresets(); -} - -void LLDayCycleManager::loadAllPresets() -{ - mDayCycleMap.clear(); - - // First, load system (coming out of the box) day cycles. - loadPresets(getSysDir()); - - // Then load user presets. Note that user day cycles will modify any system ones already loaded. - loadPresets(getUserDir()); -} - -void LLDayCycleManager::loadPresets(const std::string& dir) -{ - LLDirIterator dir_iter(dir, "*.xml"); - - while (1) - { - std::string file; - if (!dir_iter.next(file)) break; // no more files - loadPreset(gDirUtilp->add(dir, file)); - } -} - -bool LLDayCycleManager::loadPreset(const std::string& path) -{ - LLSD data = LLWLDayCycle::loadDayCycleFromPath(path); - if (data.isUndefined()) - { - LL_WARNS() << "Error loading day cycle from " << path << LL_ENDL; - return false; - } - - std::string name(gDirUtilp->getBaseFileName(LLURI::unescape(path), /*strip_exten = */ true)); - addPreset(name, data); - - return true; -} - -bool LLDayCycleManager::addPreset(const std::string& name, const LLSD& data) -{ - if (name.empty()) - { - //llassert(name.empty()); - return false; - } - - LLWLDayCycle day; - day.loadDayCycle(data, LLEnvKey::SCOPE_LOCAL); - mDayCycleMap[name] = day; - return true; -} - -// static -std::string LLDayCycleManager::getSysDir() -{ - return gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/days", ""); -} - -// static -std::string LLDayCycleManager::getUserDir() -{ - return gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS , "windlight/days", ""); -} diff --git a/indra/newview/lldaycyclemanager.h b/indra/newview/lldaycyclemanager.h deleted file mode 100644 index 04db9d5dac..0000000000 --- a/indra/newview/lldaycyclemanager.h +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @file lldaycyclemanager.h - * @brief Implementation for the LLDayCycleManager class. - * - * $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_LLDAYCYCLEMANAGER_H -#define LL_LLDAYCYCLEMANAGER_H - -#include <map> -#include <string> - -#include "llwldaycycle.h" -#include "llwlparammanager.h" - -/** - * WindLight day cycles manager class - * - * Provides interface for accessing, loading and saving day cycles. - */ -class LLDayCycleManager : public LLSingleton<LLDayCycleManager> -{ - LLSINGLETON_EMPTY_CTOR(LLDayCycleManager); - LOG_CLASS(LLDayCycleManager); - -public: - typedef std::list<std::string> preset_name_list_t; - - typedef std::map<std::string, LLWLDayCycle> dc_map_t; - typedef boost::signals2::signal<void()> modify_signal_t; - - void getPresetNames(preset_name_list_t& names) const; - void getPresetNames(preset_name_list_t& user, preset_name_list_t& sys) const; - void getUserPresetNames(preset_name_list_t& user) const; - - bool getPreset(const std::string name, LLWLDayCycle& day_cycle) const; - bool getPreset(const std::string name, LLSD& day_cycle) const; - bool presetExists(const std::string name) const; - bool isSystemPreset(const std::string& name) const; - bool savePreset(const std::string& name, const LLSD& data); - bool deletePreset(const std::string& name); - - /// @return true if there is a day cycle that refers to the sky preset. - bool isSkyPresetReferenced(const std::string& preset_name) const; - - /// Emitted when a preset gets added or deleted. - boost::signals2::connection setModifyCallback(const modify_signal_t::slot_type& cb); - -private: - /*virtual*/ void initSingleton(); - - void loadAllPresets(); - void loadPresets(const std::string& dir); - bool loadPreset(const std::string& path); - bool addPreset(const std::string& name, const LLSD& data); - - static std::string getSysDir(); - static std::string getUserDir(); - - dc_map_t mDayCycleMap; - modify_signal_t mModifySignal; -}; - -#endif // LL_LLDAYCYCLEMANAGER_H diff --git a/indra/newview/lldelayedgestureerror.cpp b/indra/newview/lldelayedgestureerror.cpp index ef1b644ad4..934a38bb8e 100644 --- a/indra/newview/lldelayedgestureerror.cpp +++ b/indra/newview/lldelayedgestureerror.cpp @@ -113,7 +113,7 @@ bool LLDelayedGestureError::doDialog(const LLErrorEntry &ent, bool uuid_ok) } } - if(!LLApp::isQuitting()) + if(!LLApp::isExiting()) { LLNotificationsUtil::add(ent.mNotifyName, args); } diff --git a/indra/newview/lldensityctrl.cpp b/indra/newview/lldensityctrl.cpp new file mode 100644 index 0000000000..298a309e7c --- /dev/null +++ b/indra/newview/lldensityctrl.cpp @@ -0,0 +1,225 @@ +/** +* @file lldensityctrl.cpp +* @brief Control for specifying density over a height range for sky settings. +* +* $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 "lldensityctrl.h" + +#include "llslider.h" +#include "llsliderctrl.h" +#include "llsettingssky.h" + +static LLDefaultChildRegistry::Register<LLDensityCtrl> register_density_control("densityctrl"); + +const std::string LLDensityCtrl::DENSITY_RAYLEIGH("density_rayleigh"); +const std::string LLDensityCtrl::DENSITY_MIE("density_mie"); +const std::string LLDensityCtrl::DENSITY_ABSORPTION("density_absorption"); + +namespace +{ + const std::string FIELD_SKY_DENSITY_PROFILE_EXPONENTIAL("level_exponential"); + const std::string FIELD_SKY_DENSITY_PROFILE_EXPONENTIAL_SCALE("exponential_scale"); + const std::string FIELD_SKY_DENSITY_PROFILE_LINEAR("level_linear"); + const std::string FIELD_SKY_DENSITY_PROFILE_CONSTANT("level_constant"); + const std::string FIELD_SKY_DENSITY_MAX_ALTITUDE("max_altitude"); + const std::string FIELD_SKY_DENSITY_ANISO_FACTOR("aniso_factor"); + const std::string FIELD_SKY_DENSITY_ANISO_FACTOR_LABEL("aniso_factor_label"); +} + +const std::string& LLDensityCtrl::NameForDensityProfileType(DensityProfileType t) +{ + switch (t) + { + case Rayleigh: return DENSITY_RAYLEIGH; + case Mie: return DENSITY_MIE; + case Absorption: return DENSITY_ABSORPTION; + default: + break; + } + + llassert(false); + return DENSITY_RAYLEIGH; +} + +LLDensityCtrl::Params::Params() +: image_density_feedback("image_density_feedback") +, lbl_exponential("label_exponential") +, lbl_exponential_scale("label_exponential_scale") +, lbl_linear("label_linear") +, lbl_constant("label_constant") +, lbl_max_altitude("label_max_altitude") +, lbl_aniso_factor("label_aniso_factor") +, profile_type(LLDensityCtrl::Rayleigh) +{ +} + +LLDensityCtrl::LLDensityCtrl(const Params& params) +: mProfileType(params.profile_type) +, mImgDensityFeedback(params.image_density_feedback) +{ + +} + +LLSD LLDensityCtrl::getProfileConfig() +{ + LLSD config; + switch (mProfileType) + { + case Rayleigh: return mSkySettings->getRayleighConfigs(); + case Mie: return mSkySettings->getMieConfigs(); + case Absorption: return mSkySettings->getAbsorptionConfigs(); + default: + break; + } + llassert(false); + return config; +} + +BOOL LLDensityCtrl::postBuild() +{ + getChild<LLUICtrl>(FIELD_SKY_DENSITY_PROFILE_EXPONENTIAL)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onExponentialChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_PROFILE_EXPONENTIAL_SCALE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onExponentialScaleFactorChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_PROFILE_LINEAR)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onLinearChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_PROFILE_CONSTANT)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onConstantChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MAX_ALTITUDE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMaxAltitudeChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ANISO_FACTOR)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onAnisoFactorChanged(); }); + + if (mProfileType != Mie) + { + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ANISO_FACTOR_LABEL)->setValue(false); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ANISO_FACTOR)->setVisible(false); + } + + return TRUE; +} + +void LLDensityCtrl::setEnabled(BOOL enabled) +{ + getChild<LLUICtrl>(FIELD_SKY_DENSITY_PROFILE_EXPONENTIAL)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_PROFILE_EXPONENTIAL_SCALE)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_PROFILE_LINEAR)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_PROFILE_CONSTANT)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MAX_ALTITUDE)->setEnabled(enabled); + + if (mProfileType == Mie) + { + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ANISO_FACTOR)->setEnabled(enabled); + } +} + +void LLDensityCtrl::refresh() +{ + if (!mSkySettings) + { + setAllChildrenEnabled(FALSE); + setEnabled(FALSE); + return; + } + + setEnabled(TRUE); + setAllChildrenEnabled(TRUE); + + LLSD config = getProfileConfig(); + + getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_PROFILE_EXPONENTIAL)->setValue(config[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM]); + getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_PROFILE_EXPONENTIAL_SCALE)->setValue(config[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR]); + getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_PROFILE_LINEAR)->setValue(config[LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM]); + getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_PROFILE_CONSTANT)->setValue(config[LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM]); + getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_MAX_ALTITUDE)->setValue(config[LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH]); + + if (mProfileType == Mie) + { + getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_ANISO_FACTOR)->setValue(config[LLSettingsSky::SETTING_MIE_ANISOTROPY_FACTOR]); + } +} + +void LLDensityCtrl::updateProfile() +{ + F32 exponential_term = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_PROFILE_EXPONENTIAL)->getValueF32(); + F32 exponential_scale = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_PROFILE_EXPONENTIAL_SCALE)->getValueF32(); + F32 linear_term = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_PROFILE_LINEAR)->getValueF32(); + F32 constant_term = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_PROFILE_CONSTANT)->getValueF32(); + F32 max_alt = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_MAX_ALTITUDE)->getValueF32(); + F32 aniso_factor = 0.0f; + + if (mProfileType == Mie) + { + aniso_factor = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_ANISO_FACTOR)->getValueF32(); + } + + LLSD profile = LLSettingsSky::createSingleLayerDensityProfile(max_alt, exponential_term, exponential_scale, linear_term, constant_term, aniso_factor); + + switch (mProfileType) + { + case Rayleigh: mSkySettings->setRayleighConfigs(profile); break; + case Mie: mSkySettings->setMieConfigs(profile); break; + case Absorption: mSkySettings->setAbsorptionConfigs(profile); break; + default: + break; + } +} + +void LLDensityCtrl::onExponentialChanged() +{ + updateProfile(); + updatePreview(); +} + +void LLDensityCtrl::onExponentialScaleFactorChanged() +{ + updateProfile(); + updatePreview(); +} + +void LLDensityCtrl::onLinearChanged() +{ + updateProfile(); + updatePreview(); +} + +void LLDensityCtrl::onConstantChanged() +{ + updateProfile(); + updatePreview(); +} + +void LLDensityCtrl::onMaxAltitudeChanged() +{ + updateProfile(); + updatePreview(); +} + +void LLDensityCtrl::onAnisoFactorChanged() +{ + updateProfile(); +} + +void LLDensityCtrl::updatePreview() +{ + // AdvancedAtmospherics TODO + // Generate image according to current density profile +} + diff --git a/indra/newview/lldensityctrl.h b/indra/newview/lldensityctrl.h new file mode 100644 index 0000000000..789022803c --- /dev/null +++ b/indra/newview/lldensityctrl.h @@ -0,0 +1,104 @@ +/** +* @file lldensityctrl.h +* @brief Control for specifying density over a height range for sky settings. +* +* $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 LLDENSITY_CTRL_H +#define LLDENSITY_CTRL_H + +#include "lluictrl.h" +#include "llsettingssky.h" +#include "lltextbox.h" +#include "llsliderctrl.h" + +class LLDensityCtrl : public LLUICtrl +{ +public: + static const std::string DENSITY_RAYLEIGH; + static const std::string DENSITY_MIE; + static const std::string DENSITY_ABSORPTION; + + // Type of density profile this tab is updating + enum DensityProfileType + { + Rayleigh, + Mie, + Absorption + }; + + static const std::string& NameForDensityProfileType(DensityProfileType t); + + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<LLTextBox::Params> lbl_exponential, + lbl_exponential_scale, + lbl_linear, + lbl_constant, + lbl_max_altitude, + lbl_aniso_factor; + + Optional<LLSliderCtrl::Params> exponential_slider, + exponential_scale_slider, + linear_slider, + constant_slider, + aniso_factor_slider; + + Optional<LLUIImage*> image_density_feedback; + + DensityProfileType profile_type; + Params(); + }; + + virtual BOOL postBuild() override; + virtual void setEnabled(BOOL enabled) override; + + void setProfileType(DensityProfileType t) { mProfileType = t; } + + void refresh(); + void updateProfile(); + + LLSettingsSky::ptr_t getSky() const { return mSkySettings; } + void setSky(const LLSettingsSky::ptr_t &sky) { mSkySettings = sky; refresh(); } + +protected: + friend class LLUICtrlFactory; + LLDensityCtrl(const Params&); + + LLSD getProfileConfig(); + void updatePreview(); + +private: + void onExponentialChanged(); + void onExponentialScaleFactorChanged(); + void onLinearChanged(); + void onConstantChanged(); + void onMaxAltitudeChanged(); + void onAnisoFactorChanged(); + + DensityProfileType mProfileType = Rayleigh; + LLUIImage* mImgDensityFeedback = nullptr; + LLSettingsSky::ptr_t mSkySettings; +}; + +#endif LLDENSITY_CTRL_H diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp index b8e6e81ee6..01790ad19e 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/newview/lldirpicker.cpp @@ -37,7 +37,7 @@ #include "llviewercontrol.h" #include "llwin32headerslean.h" -#if LL_LINUX || LL_SOLARIS || LL_DARWIN +#if LL_LINUX || LL_DARWIN # include "llfilepicker.h" #endif @@ -187,7 +187,7 @@ std::string LLDirPicker::getDirName() return mFilePicker->getFirstFile(); } -#elif LL_LINUX || LL_SOLARIS +#elif LL_LINUX LLDirPicker::LLDirPicker() : mFileName(NULL), diff --git a/indra/newview/lldirpicker.h b/indra/newview/lldirpicker.h index c7dba12130..52febe4523 100644 --- a/indra/newview/lldirpicker.h +++ b/indra/newview/lldirpicker.h @@ -78,7 +78,7 @@ private: void buildDirname( void ); bool check_local_file_access_enabled(); -#if LL_LINUX || LL_SOLARIS || LL_DARWIN +#if LL_LINUX || LL_DARWIN // On Linux we just implement LLDirPicker on top of LLFilePicker LLFilePicker *mFilePicker; #endif diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp index 7d2712eec7..cb5f9c8a2c 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.cpp +++ b/indra/newview/lldonotdisturbnotificationstorage.cpp @@ -48,7 +48,6 @@ const char * LLDoNotDisturbNotificationStorage::offerName = "UserGiveItem"; LLDoNotDisturbNotificationStorageTimer::LLDoNotDisturbNotificationStorageTimer() : LLEventTimer(DND_TIMER) { - } LLDoNotDisturbNotificationStorageTimer::~LLDoNotDisturbNotificationStorageTimer() @@ -74,6 +73,7 @@ LLDoNotDisturbNotificationStorage::LLDoNotDisturbNotificationStorage() { nameToPayloadParameterMap[toastName] = "SESSION_ID"; nameToPayloadParameterMap[offerName] = "object_id"; + initialize(); } LLDoNotDisturbNotificationStorage::~LLDoNotDisturbNotificationStorage() diff --git a/indra/newview/lldonotdisturbnotificationstorage.h b/indra/newview/lldonotdisturbnotificationstorage.h index e6cb7835e3..c6f0bf1ab5 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.h +++ b/indra/newview/lldonotdisturbnotificationstorage.h @@ -45,7 +45,7 @@ public: BOOL tick(); }; -class LLDoNotDisturbNotificationStorage : public LLSingleton<LLDoNotDisturbNotificationStorage>, public LLNotificationStorage +class LLDoNotDisturbNotificationStorage : public LLParamSingleton<LLDoNotDisturbNotificationStorage>, public LLNotificationStorage { LLSINGLETON(LLDoNotDisturbNotificationStorage); ~LLDoNotDisturbNotificationStorage(); @@ -55,7 +55,6 @@ public: static const char * toastName; static const char * offerName; - void initialize(); bool getDirty(); void resetDirty(); void saveNotifications(); @@ -66,6 +65,8 @@ public: protected: private: + void initialize(); + bool mDirty; LLDoNotDisturbNotificationStorageTimer mTimer; diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 8c6cbc020b..507af56cb0 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -912,22 +912,18 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update) 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); + LLVector3 cam_pos_from_agent = LLViewerCamera::getInstance()->getOrigin(); + LLVector3 cam_to_box_offset = point_to_box_offset(cam_pos_from_agent, 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 + << " cam pos " << cam_pos_from_agent << " box " << av_box[0] << "," << av_box[1] << " -> dist " << mDistanceWRTCamera << LL_ENDL; mVObjp->updateLOD(); return; } - } else { @@ -1178,11 +1174,33 @@ LLSpatialPartition* LLDrawable::getSpatialPartition() } else if (isRoot()) { - if (mSpatialBridge && (mSpatialBridge->asPartition()->mPartitionType == LLViewerRegion::PARTITION_HUD) != mVObjp->isHUDAttachment()) + if (mSpatialBridge) { - // remove obsolete bridge - mSpatialBridge->markDead(); - setSpatialBridge(NULL); + U32 partition_type = mSpatialBridge->asPartition()->mPartitionType; + bool is_hud = mVObjp->isHUDAttachment(); + bool is_animesh = mVObjp->isAnimatedObject() && mVObjp->getControlAvatar() != NULL; + bool is_attachment = mVObjp->isAttachment() && !is_hud && !is_animesh; + if ((partition_type == LLViewerRegion::PARTITION_HUD) != is_hud) + { + // Was/became HUD + // remove obsolete bridge + mSpatialBridge->markDead(); + setSpatialBridge(NULL); + } + else if ((partition_type == LLViewerRegion::PARTITION_CONTROL_AV) != is_animesh) + { + // Was/became part of animesh + // remove obsolete bridge + mSpatialBridge->markDead(); + setSpatialBridge(NULL); + } + else if ((partition_type == LLViewerRegion::PARTITION_AVATAR) != is_attachment) + { + // Was/became part of avatar + // remove obsolete bridge + mSpatialBridge->markDead(); + setSpatialBridge(NULL); + } } //must be an active volume if (!mSpatialBridge) @@ -1191,6 +1209,15 @@ LLSpatialPartition* LLDrawable::getSpatialPartition() { setSpatialBridge(new LLHUDBridge(this, getRegion())); } + else if (mVObjp->isAnimatedObject() && mVObjp->getControlAvatar()) + { + setSpatialBridge(new LLControlAVBridge(this, getRegion())); + } + // check HUD first, because HUD is also attachment + else if (mVObjp->isAttachment()) + { + setSpatialBridge(new LLAvatarBridge(this, getRegion())); + } else { setSpatialBridge(new LLVolumeBridge(this, getRegion())); @@ -1454,7 +1481,7 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* LLVOAvatar* avatarp = (LLVOAvatar*) objparent; if (avatarp->isVisible()) { - impostor = objparent->isAvatar() && ((LLVOAvatar*) objparent)->isImpostor(); + impostor = objparent->isAvatar() && !LLPipeline::sImpostorRender && ((LLVOAvatar*) objparent)->isImpostor(); loaded = objparent->isAvatar() && ((LLVOAvatar*) objparent)->isFullyLoaded(); } else @@ -1538,7 +1565,8 @@ void LLSpatialBridge::updateDistance(LLCamera& camera_in, bool force_update) if (mDrawable->getVObj()) { - if (mDrawable->getVObj()->isAttachment()) + // Don't update if we are part of impostor, unles it's an impostor pass + if (!LLPipeline::sImpostorRender && mDrawable->getVObj()->isAttachment()) { LLDrawable* parent = mDrawable->getParent(); if (parent && parent->getVObj()) @@ -1698,12 +1726,26 @@ void LLDrawable::updateFaceSize(S32 idx) 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; } +LLAvatarPartition::LLAvatarPartition(LLViewerRegion* regionp) + : LLBridgePartition(regionp) +{ + mDrawableType = LLPipeline::RENDER_TYPE_AVATAR; + mPartitionType = LLViewerRegion::PARTITION_AVATAR; +} + +LLControlAVPartition::LLControlAVPartition(LLViewerRegion* regionp) + : LLBridgePartition(regionp) +{ + mDrawableType = LLPipeline::RENDER_TYPE_CONTROL_AV; + mPartitionType = LLViewerRegion::PARTITION_CONTROL_AV; +} + LLHUDBridge::LLHUDBridge(LLDrawable* drawablep, LLViewerRegion* regionp) : LLVolumeBridge(drawablep, regionp) { diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index 82888b2df6..d583a692f9 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -86,7 +86,8 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerTexture *tex0) poolp = new LLDrawPoolAlpha(); break; case POOL_AVATAR: - poolp = new LLDrawPoolAvatar(); + case POOL_CONTROL_AV: + poolp = new LLDrawPoolAvatar(type); break; case POOL_TREE: poolp = new LLDrawPoolTree(tex0); @@ -127,7 +128,7 @@ LLDrawPool::LLDrawPool(const U32 type) mType = type; sNumDrawPools++; mId = sNumDrawPools; - mVertexShaderLevel = 0; + mShaderLevel = 0; mSkipRender = false; } @@ -141,7 +142,7 @@ LLViewerTexture *LLDrawPool::getDebugTexture() return NULL; } -//virtuals +//virtual void LLDrawPool::beginRenderPass( S32 pass ) { } @@ -383,16 +384,6 @@ LLRenderPass::~LLRenderPass() } -LLDrawPool* LLRenderPass::instancePool() -{ -#if LL_RELEASE_FOR_DOWNLOAD - LL_WARNS() << "Attempting to instance a render pass. Invalid operation." << LL_ENDL; -#else - LL_ERRS() << "Attempting to instance a render pass. Invalid operation." << LL_ENDL; -#endif - return NULL; -} - void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture) { LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type]; @@ -406,9 +397,9 @@ void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL t } } -void LLRenderPass::renderTexture(U32 type, U32 mask) +void LLRenderPass::renderTexture(U32 type, U32 mask, BOOL batch_textures) { - pushBatches(type, mask, TRUE); + pushBatches(type, mask, true, batch_textures); } void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures) @@ -449,10 +440,10 @@ void LLRenderPass::applyModelMatrix(const LLDrawInfo& params) if (params.mModelMatrix != gGLLastMatrix) { gGLLastMatrix = params.mModelMatrix; + gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.loadMatrix(gGLModelView); if (params.mModelMatrix) { - llassert(gGL.getMatrixMode() == LLRender::MM_MODELVIEW); gGL.multMatrix((GLfloat*) params.mModelMatrix->mMatrix); } gPipeline.mMatrixOpCount++; @@ -461,6 +452,11 @@ void LLRenderPass::applyModelMatrix(const LLDrawInfo& params) void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) { + if (!params.mCount) + { + return; + } + applyModelMatrix(params); bool tex_setup = false; @@ -515,6 +511,7 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL ba if (tex_setup) { + gGL.matrixMode(LLRender::MM_TEXTURE0); gGL.loadIdentity(); gGL.matrixMode(LLRender::MM_MODELVIEW); } diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index bc299cc89f..ecd9bd034f 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -60,6 +60,7 @@ public: POOL_GRASS, POOL_INVISIBLE, // see below * POOL_AVATAR, + POOL_CONTROL_AV, // Animesh POOL_VOIDWATER, POOL_WATER, POOL_GLOW, @@ -107,16 +108,15 @@ public: virtual void prerender() = 0; virtual U32 getVertexDataMask() = 0; virtual BOOL verify() const { return TRUE; } // Verify that all data in the draw pool is correct! - virtual S32 getVertexShaderLevel() const { return mVertexShaderLevel; } + virtual S32 getShaderLevel() const { return mShaderLevel; } static LLDrawPool* createPool(const U32 type, LLViewerTexture *tex0 = NULL); - virtual LLDrawPool *instancePool() = 0; // Create an empty new instance of the pool. virtual LLViewerTexture* getTexture() = 0; virtual BOOL isFacePool() { return FALSE; } virtual void resetDrawOrders() = 0; protected: - S32 mVertexShaderLevel; + S32 mShaderLevel; S32 mId; U32 mType; // Type of draw pool BOOL mSkipRender; @@ -138,31 +138,30 @@ public: PASS_POST_BUMP, PASS_MATERIAL, PASS_MATERIAL_ALPHA, - PASS_MATERIAL_ALPHA_MASK, + PASS_MATERIAL_ALPHA_MASK, // Diffuse texture used as alpha mask PASS_MATERIAL_ALPHA_EMISSIVE, PASS_SPECMAP, PASS_SPECMAP_BLEND, - PASS_SPECMAP_MASK, + PASS_SPECMAP_MASK, // Diffuse texture used as alpha mask and specular texture(map) PASS_SPECMAP_EMISSIVE, PASS_NORMMAP, PASS_NORMMAP_BLEND, - PASS_NORMMAP_MASK, + PASS_NORMMAP_MASK, // Diffuse texture used as alpha mask and normal map PASS_NORMMAP_EMISSIVE, PASS_NORMSPEC, PASS_NORMSPEC_BLEND, - PASS_NORMSPEC_MASK, + PASS_NORMSPEC_MASK, // Diffuse texture used as alpha mask with normal and specular map PASS_NORMSPEC_EMISSIVE, PASS_GLOW, PASS_ALPHA, PASS_ALPHA_MASK, - PASS_FULLBRIGHT_ALPHA_MASK, + PASS_FULLBRIGHT_ALPHA_MASK, // Diffuse texture used as alpha mask and fullbright PASS_ALPHA_INVISIBLE, NUM_RENDER_TYPES, }; LLRenderPass(const U32 type); virtual ~LLRenderPass(); - /*virtual*/ LLDrawPool* instancePool(); /*virtual*/ LLViewerTexture* getDebugTexture() { return NULL; } LLViewerTexture* getTexture() { return NULL; } BOOL isDead() { return FALSE; } @@ -174,7 +173,7 @@ public: 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); - virtual void renderTexture(U32 type, U32 mask); + virtual void renderTexture(U32 type, U32 mask, BOOL batch_textures = TRUE); }; diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 0873300cd2..4ee08e869a 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -53,6 +53,22 @@ BOOL LLDrawPoolAlpha::sShowDebugAlpha = FALSE; static BOOL deferred_render = FALSE; +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_SETUP("Alpha Setup"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_GROUP_LOOP("Alpha Group"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_PUSH("Alpha Push Verts"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_DEFERRED("Alpha Deferred"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_SETBUFFER("Alpha SetBuffer"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_DRAW("Alpha Draw"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_TEX_BINDS("Alpha Tex Binds"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MATS("Alpha Mat Tex Binds"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_GLOW("Alpha Glow Binds"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_SHADER_BINDS("Alpha Shader Binds"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_DEFERRED_SHADER_BINDS("Alpha Def Binds"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_DEFERRED_TEX_BINDS("Alpha Def Tex Binds"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MESH_REBUILD("Alpha Mesh Rebuild"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_EMISSIVE("Alpha Emissive"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_LIGHT_SETUP("Alpha Light Setup"); + LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) : LLRenderPass(type), current_shader(NULL), target_shader(NULL), simple_shader(NULL), fullbright_shader(NULL), emissive_shader(NULL), @@ -69,7 +85,7 @@ LLDrawPoolAlpha::~LLDrawPoolAlpha() void LLDrawPoolAlpha::prerender() { - mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); + mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); } S32 LLDrawPoolAlpha::getNumPostDeferredPasses() @@ -90,37 +106,37 @@ S32 LLDrawPoolAlpha::getNumPostDeferredPasses() void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA); + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED); + + F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); + + emissive_shader = (LLPipeline::sRenderDeferred) ? &gDeferredEmissiveProgram : + (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram; + + emissive_shader->bind(); + emissive_shader->uniform1i(LLShaderMgr::NO_ATMO, (LLPipeline::sRenderingHUDs) ? 1 : 0); + emissive_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); + emissive_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); if (pass == 0) { - 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 = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightProgram : + (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightProgram; 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->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0); fullbright_shader->unbind(); + simple_shader = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram : + (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : &gDeferredAlphaProgram; + //prime simple shader (loads shadow relevant uniforms) gPipeline.bindDeferredShader(*simple_shader); simple_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); + simple_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0); } else if (!LLPipeline::sImpostorRender) { @@ -134,25 +150,8 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass) gObjectFullbrightAlphaMaskProgram.setMinimumAlpha(0.33f); } - - if (LLPipeline::sRenderDeferred) - { - emissive_shader = &gDeferredEmissiveProgram; - } - else - { - if (LLPipeline::sUnderWaterRender) - { - emissive_shader = &gObjectEmissiveWaterProgram; - } - else - { - emissive_shader = &gObjectEmissiveProgram; - } - } - deferred_render = TRUE; - if (mVertexShaderLevel > 0) + if (mShaderLevel > 0) { // Start out with no shaders. current_shader = target_shader = NULL; @@ -162,6 +161,8 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass) void LLDrawPoolAlpha::endPostDeferredPass(S32 pass) { + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED); + if (pass == 1 && !LLPipeline::sImpostorRender) { gPipeline.mDeferredDepth.flush(); @@ -175,44 +176,64 @@ void LLDrawPoolAlpha::endPostDeferredPass(S32 pass) void LLDrawPoolAlpha::renderPostDeferred(S32 pass) { + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED); render(pass); } void LLDrawPoolAlpha::beginRenderPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA); + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_SETUP); - if (LLPipeline::sImpostorRender) - { - simple_shader = &gObjectSimpleImpostorProgram; - fullbright_shader = &gObjectFullbrightProgram; - emissive_shader = &gObjectEmissiveProgram; - } - else if (LLPipeline::sUnderWaterRender) - { - simple_shader = &gObjectSimpleWaterProgram; - fullbright_shader = &gObjectFullbrightWaterProgram; - emissive_shader = &gObjectEmissiveWaterProgram; - } - else - { - simple_shader = &gObjectSimpleProgram; - fullbright_shader = &gObjectFullbrightProgram; - emissive_shader = &gObjectEmissiveProgram; - } + simple_shader = (LLPipeline::sImpostorRender) ? &gObjectSimpleImpostorProgram : + (LLPipeline::sUnderWaterRender) ? &gObjectSimpleWaterProgram : &gObjectSimpleProgram; - if (mVertexShaderLevel > 0) + fullbright_shader = (LLPipeline::sImpostorRender) ? &gObjectFullbrightProgram : + (LLPipeline::sUnderWaterRender) ? &gObjectFullbrightWaterProgram : &gObjectFullbrightProgram; + + emissive_shader = (LLPipeline::sImpostorRender) ? &gObjectEmissiveProgram : + (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram; + + if (LLPipeline::sImpostorRender) { - // Start out with no shaders. - current_shader = target_shader = NULL; - LLGLSLShader::bindNoShader(); + if (mShaderLevel > 0) + { + fullbright_shader->bind(); + fullbright_shader->setMinimumAlpha(0.5f); + fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0); + simple_shader->bind(); + simple_shader->setMinimumAlpha(0.5f); + simple_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0); + } + else + { + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); //OK + } } + else + { + if (mShaderLevel > 0) + { + fullbright_shader->bind(); + fullbright_shader->setMinimumAlpha(0.f); + fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0); + simple_shader->bind(); + simple_shader->setMinimumAlpha(0.f); + simple_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0); + } + else + { + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK + } + } gPipeline.enableLightsDynamic(); + + LLGLSLShader::bindNoShader(); + current_shader = NULL; } void LLDrawPoolAlpha::endRenderPass( S32 pass ) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA); + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_SETUP); LLRenderPass::endRenderPass(pass); if(gPipeline.canUseWindLightShaders()) @@ -255,38 +276,9 @@ void LLDrawPoolAlpha::render(S32 pass) mAlphaSFactor = LLRender::BF_ZERO; // } glow suppression mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); - - 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); - } - } - else - { - if (LLPipeline::sImpostorRender) - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); //OK - } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK - } - } } - if (mVertexShaderLevel > 0) + if (mShaderLevel > 0) { renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, pass); } @@ -311,7 +303,7 @@ void LLDrawPoolAlpha::render(S32 pass) } else { - gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); + gPipeline.enableLightsFullbright(); } gGL.diffuseColor4f(1,0,0,1); @@ -322,11 +314,15 @@ void LLDrawPoolAlpha::render(S32 pass) LLVertexBuffer::MAP_TEXCOORD0); pushBatches(LLRenderPass::PASS_ALPHA_MASK, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); - 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); + // Material alpha mask gGL.diffuseColor4f(0, 0, 1, 1); pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); + pushBatches(LLRenderPass::PASS_NORMMAP_MASK, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); + pushBatches(LLRenderPass::PASS_SPECMAP_MASK, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); + pushBatches(LLRenderPass::PASS_NORMSPEC_MASK, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); + pushBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); gGL.diffuseColor4f(0, 1, 0, 1); pushBatches(LLRenderPass::PASS_INVISIBLE, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); @@ -370,11 +366,257 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask) } } -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_GROUP_LOOP("Alpha Group"); -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_PUSH("Alpha Push Verts"); +inline bool IsFullbright(LLDrawInfo& params) +{ + return params.mFullbright; +} + +inline bool IsMaterial(LLDrawInfo& params) +{ + return params.mMaterial != nullptr; +} + +inline bool IsEmissive(LLDrawInfo& params) +{ + return params.mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE); +} + +inline void Draw(LLDrawInfo* draw, U32 mask) +{ + draw->mVertexBuffer->setBuffer(mask); + LLRenderPass::applyModelMatrix(*draw); + draw->mVertexBuffer->drawRange(draw->mDrawMode, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset); + gPipeline.addTrianglesDrawn(draw->mCount, draw->mDrawMode); +} + +bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_shaders, bool use_material, LLGLSLShader* current_shader) +{ + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_TEX_BINDS); + + bool tex_setup = false; + + if (deferred_render && use_material && current_shader) + { + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED_TEX_BINDS); + if (draw->mNormalMap) + { + draw->mNormalMap->addTextureStats(draw->mVSize); + current_shader->bindTexture(LLShaderMgr::BUMP_MAP, draw->mNormalMap); + } + + if (draw->mSpecularMap) + { + draw->mSpecularMap->addTextureStats(draw->mVSize); + current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, draw->mSpecularMap); + } + } + else if (current_shader == simple_shader) + { + LLViewerFetchedTexture::sFlatNormalImagep->addTextureStats(draw->mVSize); + LLViewerFetchedTexture::sWhiteImagep->addTextureStats(draw->mVSize); + current_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep); + current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep); + } + if (use_shaders && draw->mTextureList.size() > 1) + { + for (U32 i = 0; i < draw->mTextureList.size(); ++i) + { + if (draw->mTextureList[i].notNull()) + { + gGL.getTexUnit(i)->bind(draw->mTextureList[i], TRUE); + } + } + } + else + { //not batching textures or batch has only 1 texture -- might need a texture matrix + if (draw->mTexture.notNull()) + { + draw->mTexture->addTextureStats(draw->mVSize); + if (use_shaders && use_material) + { + current_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, draw->mTexture); + } + else + { + gGL.getTexUnit(0)->bind(draw->mTexture, TRUE) ; + } + + if (draw->mTextureMatrix) + { + tex_setup = true; + gGL.getTexUnit(0)->activate(); + gGL.matrixMode(LLRender::MM_TEXTURE); + gGL.loadMatrix((GLfloat*) draw->mTextureMatrix->mMatrix); + gPipeline.mTextureMatrixOps++; + } + } + else + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + } + + return tex_setup; +} + +void LLDrawPoolAlpha::RestoreTexSetup(bool tex_setup) +{ + if (tex_setup) + { + gGL.getTexUnit(0)->activate(); + gGL.matrixMode(LLRender::MM_TEXTURE); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + } +} + +void LLDrawPoolAlpha::renderSimples(U32 mask, std::vector<LLDrawInfo*>& simples) +{ + gPipeline.enableLightsDynamic(); + simple_shader->bind(); + simple_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep); + simple_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep); + simple_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, 1.0f, 1.0f, 1.0f, 1.0f); + simple_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, 0.0f); + simple_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 0.0f); + bool use_shaders = gPipeline.canUseVertexShaders(); + for (LLDrawInfo* draw : simples) + { + bool tex_setup = TexSetup(draw, use_shaders, false, simple_shader); + LLGLEnableFunc stencil_test(GL_STENCIL_TEST, draw->mSelected, &LLGLCommonFunc::selected_stencil_test); + gGL.blendFunc((LLRender::eBlendFactor) draw->mBlendFuncSrc, (LLRender::eBlendFactor) draw->mBlendFuncDst, mAlphaSFactor, mAlphaDFactor); + + Draw(draw, mask); + RestoreTexSetup(tex_setup); + } + simple_shader->unbind(); +} + +void LLDrawPoolAlpha::renderFullbrights(U32 mask, std::vector<LLDrawInfo*>& fullbrights) +{ + gPipeline.enableLightsFullbright(); + fullbright_shader->bind(); + fullbright_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.0f); + bool use_shaders = gPipeline.canUseVertexShaders(); + for (LLDrawInfo* draw : fullbrights) + { + bool tex_setup = TexSetup(draw, use_shaders, false, fullbright_shader); + + LLGLEnableFunc stencil_test(GL_STENCIL_TEST, draw->mSelected, &LLGLCommonFunc::selected_stencil_test); + gGL.blendFunc((LLRender::eBlendFactor) draw->mBlendFuncSrc, (LLRender::eBlendFactor) draw->mBlendFuncDst, mAlphaSFactor, mAlphaDFactor); + + Draw(draw, mask & ~(LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2)); + RestoreTexSetup(tex_setup); + } + fullbright_shader->unbind(); +} + +void LLDrawPoolAlpha::renderMaterials(U32 mask, std::vector<LLDrawInfo*>& materials) +{ + LLGLSLShader::bindNoShader(); + current_shader = NULL; + + gPipeline.enableLightsDynamic(); + bool use_shaders = gPipeline.canUseVertexShaders(); + for (LLDrawInfo* draw : materials) + { + U32 mask = draw->mShaderMask; + + llassert(mask < LLMaterial::SHADER_COUNT); + target_shader = (LLPipeline::sUnderWaterRender) ? &(gDeferredMaterialWaterProgram[mask]) : &(gDeferredMaterialProgram[mask]); + + if (current_shader != target_shader) + { + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED_SHADER_BINDS); + if (current_shader) + { + gPipeline.unbindDeferredShader(*current_shader); + } + gPipeline.bindDeferredShader(*target_shader); + current_shader = target_shader; + } + + bool tex_setup = TexSetup(draw, use_shaders, true, current_shader); + + current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, draw->mSpecColor.mV[0], draw->mSpecColor.mV[1], draw->mSpecColor.mV[2], draw->mSpecColor.mV[3]); + current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, draw->mEnvIntensity); + current_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, draw->mFullbright ? 1.f : 0.f); + + { + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED_TEX_BINDS); + if (draw->mNormalMap) + { + draw->mNormalMap->addTextureStats(draw->mVSize); + current_shader->bindTexture(LLShaderMgr::BUMP_MAP, draw->mNormalMap); + } + + if (draw->mSpecularMap) + { + draw->mSpecularMap->addTextureStats(draw->mVSize); + current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, draw->mSpecularMap); + } + } + + LLGLEnableFunc stencil_test(GL_STENCIL_TEST, draw->mSelected, &LLGLCommonFunc::selected_stencil_test); + gGL.blendFunc((LLRender::eBlendFactor) draw->mBlendFuncSrc, (LLRender::eBlendFactor) draw->mBlendFuncDst, mAlphaSFactor, mAlphaDFactor); + + Draw(draw, mask); + RestoreTexSetup(tex_setup); + } +} + +void LLDrawPoolAlpha::drawEmissive(U32 mask, LLDrawInfo* draw) +{ + draw->mVertexBuffer->setBuffer((mask & ~LLVertexBuffer::MAP_COLOR) | LLVertexBuffer::MAP_EMISSIVE); + draw->mVertexBuffer->drawRange(draw->mDrawMode, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset); + gPipeline.addTrianglesDrawn(draw->mCount, draw->mDrawMode); +} + +void LLDrawPoolAlpha::drawEmissiveInline(U32 mask, LLDrawInfo* draw) +{ + // 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(); + + drawEmissive(mask, draw); + + // restore our alpha blend mode + gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); + + current_shader->bind(); +} + +void LLDrawPoolAlpha::renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives) +{ + emissive_shader->bind(); + emissive_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f); + + gPipeline.enableLightsDynamic(); + + // install glow-accumulating blend mode + // don't touch color, add to alpha (glow) + gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, LLRender::BF_ONE, LLRender::BF_ONE); + bool use_shaders = gPipeline.canUseVertexShaders(); + for (LLDrawInfo* draw : emissives) + { + bool tex_setup = TexSetup(draw, use_shaders, false, emissive_shader); + drawEmissive(mask, draw); + RestoreTexSetup(tex_setup); + } + + // restore our alpha blend mode + gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); + + emissive_shader->unbind(); +} void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) { + BOOL batch_fullbrights = gSavedSettings.getBOOL("RenderAlphaBatchFullbrights"); + BOOL batch_emissives = gSavedSettings.getBOOL("RenderAlphaBatchEmissives"); BOOL initialized_lighting = FALSE; BOOL light_enabled = TRUE; @@ -389,10 +631,13 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) if (group->getSpatialPartition()->mRenderByGroup && !group->isDead()) { + std::vector<LLDrawInfo*> emissives; + std::vector<LLDrawInfo*> fullbrights; + bool is_particle_or_hud_particle = group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_PARTICLE || group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_HUD_PARTICLE; - bool draw_glow_for_this_partition = mVertexShaderLevel > 0; // no shaders = no glow. + bool draw_glow_for_this_partition = mShaderLevel > 0; // no shaders = no glow. LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_GROUP_LOOP); @@ -405,11 +650,11 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; - - if ((params.mVertexBuffer->getTypeMask() & mask) != mask) + U32 have_mask = params.mVertexBuffer->getTypeMask() & mask; + if (have_mask != mask) { //FIXME! LL_WARNS_ONCE() << "Missing required components, expected mask: " << mask - << " present: " << (params.mVertexBuffer->getTypeMask() & mask) + << " present: " << have_mask << ". Skipping render batch." << LL_ENDL; continue; } @@ -431,6 +676,12 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) } } + if (params.mFullbright && batch_fullbrights) + { + fullbrights.push_back(¶ms); + continue; + } + LLRenderPass::applyModelMatrix(params); LLMaterial* mat = NULL; @@ -445,6 +696,8 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) // Turn off lighting if it hasn't already been so. if (light_enabled || !initialized_lighting) { + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_LIGHT_SETUP); + initialized_lighting = TRUE; if (use_shaders) { @@ -452,7 +705,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) } else { - gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); + gPipeline.enableLightsFullbright(); } light_enabled = FALSE; } @@ -460,6 +713,8 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) // Turn on lighting if it isn't already. else if (!light_enabled || !initialized_lighting) { + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_LIGHT_SETUP); + initialized_lighting = TRUE; if (use_shaders) { @@ -486,7 +741,9 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) if (current_shader != target_shader) { + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED_SHADER_BINDS); gPipeline.bindDeferredShader(*target_shader); + current_shader = target_shader; } } else if (!params.mFullbright) @@ -501,6 +758,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) if(use_shaders && (current_shader != target_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). + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_SHADER_BINDS); current_shader = target_shader; current_shader->bind(); } @@ -510,83 +768,31 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) current_shader = NULL; } - if (use_shaders && mat) - { - // We have a material. Supply the appropriate data here. - if (LLPipeline::sRenderDeferred) - { - 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); + LLVector4 spec_color(1, 1, 1, 1); + F32 env_intensity = 0.0f; + F32 brightness = 1.0f; - 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 (LLPipeline::sRenderDeferred && current_shader && (current_shader == simple_shader)) + // We have a material. Supply the appropriate data here. + if (use_shaders && mat && deferred_render) { - 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); - } + spec_color = params.mSpecColor; + env_intensity = params.mEnvIntensity; + brightness = params.mFullbright ? 1.f : 0.f; + } + + if (current_shader) + { + current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, spec_color.mV[0], spec_color.mV[1], spec_color.mV[2], spec_color.mV[3]); + current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env_intensity); + current_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, brightness); + } if (params.mGroup) { params.mGroup->rebuildMesh(); } - bool tex_setup = false; - - if (use_shaders && 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.mTexture.notNull()) - { - params.mTexture->addTextureStats(params.mVSize); - if (use_shaders && mat) - { - 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); - gPipeline.mTextureMatrixOps++; - } - } - else - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - } - } + bool tex_setup = TexSetup(¶ms, use_shaders, use_shaders && (mat != nullptr), current_shader); { LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_PUSH); @@ -596,41 +802,56 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) gGL.blendFunc((LLRender::eBlendFactor) params.mBlendFuncSrc, (LLRender::eBlendFactor) params.mBlendFuncDst, mAlphaSFactor, mAlphaDFactor); params.mVertexBuffer->setBuffer(mask & ~(params.mFullbright ? (LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2) : 0)); - params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); - gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode); + { + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DRAW); + 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 this alpha mesh has glow, then draw it a second time to add the destination-alpha (=glow). Interleaving these state-changing calls is expensive, but glow must be drawn Z-sorted with alpha. if (current_shader && draw_glow_for_this_partition && 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(); - - params.mVertexBuffer->setBuffer((mask & ~LLVertexBuffer::MAP_COLOR) | 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); - - // restore our alpha blend mode - gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); - - current_shader->bind(); + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_EMISSIVE); + + if (batch_emissives) + { + emissives.push_back(¶ms); + } + else + { + drawEmissiveInline(mask, ¶ms); + } } if (tex_setup) { gGL.getTexUnit(0)->activate(); + gGL.matrixMode(LLRender::MM_TEXTURE); gGL.loadIdentity(); gGL.matrixMode(LLRender::MM_MODELVIEW); } } - } + + if (batch_fullbrights) + { + light_enabled = false; + renderFullbrights(mask, fullbrights); + } + + if (batch_emissives) + { + light_enabled = true; + renderEmissives(mask, emissives); + } + + if (current_shader) + { + current_shader->bind(); + } + } } gGL.setSceneBlendType(LLRender::BT_ALPHA); diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h index d064a3a324..a069f805e8 100644 --- a/indra/newview/lldrawpoolalpha.h +++ b/indra/newview/lldrawpoolalpha.h @@ -75,6 +75,17 @@ private: LLGLSLShader* fullbright_shader; LLGLSLShader* emissive_shader; + void renderSimples(U32 mask, std::vector<LLDrawInfo*>& simples); + void renderFullbrights(U32 mask, std::vector<LLDrawInfo*>& fullbrights); + void renderMaterials(U32 mask, std::vector<LLDrawInfo*>& fullbrights); + void renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives); + + void drawEmissive(U32 mask, LLDrawInfo* draw); + void drawEmissiveInline(U32 mask, LLDrawInfo* draw); + + bool TexSetup(LLDrawInfo* draw, bool use_shaders, bool use_material, LLGLSLShader* current_shader); + void RestoreTexSetup(bool tex_setup); + // our 'normal' alpha blend function for this pass LLRender::eBlendFactor mColorSFactor; LLRender::eBlendFactor mColorDFactor; diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 63abadbcf4..687b13d2c8 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -105,8 +105,8 @@ S32 cube_channel = -1; static LLTrace::BlockTimerStatHandle FTM_SHADOW_AVATAR("Avatar Shadow"); -LLDrawPoolAvatar::LLDrawPoolAvatar() : - LLFacePool(POOL_AVATAR) +LLDrawPoolAvatar::LLDrawPoolAvatar(U32 type) : + LLFacePool(type) { } @@ -135,26 +135,17 @@ BOOL LLDrawPoolAvatar::isDead() } return TRUE; } - -//----------------------------------------------------------------------------- -// instancePool() -//----------------------------------------------------------------------------- -LLDrawPool *LLDrawPoolAvatar::instancePool() -{ - return new LLDrawPoolAvatar(); -} - -S32 LLDrawPoolAvatar::getVertexShaderLevel() const +S32 LLDrawPoolAvatar::getShaderLevel() const { - return (S32) LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR); + return (S32) LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR); } void LLDrawPoolAvatar::prerender() { - mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR); + mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR); - sShaderLevel = mVertexShaderLevel; + sShaderLevel = mShaderLevel; if (sShaderLevel > 0) { @@ -305,7 +296,7 @@ void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass) void LLDrawPoolAvatar::beginPostDeferredAlpha() { sSkipOpaque = TRUE; - sShaderLevel = mVertexShaderLevel; + sShaderLevel = mShaderLevel; sVertexProgram = &gDeferredAvatarAlphaProgram; sRenderingSkinned = TRUE; @@ -396,7 +387,7 @@ void LLDrawPoolAvatar::endPostDeferredAlpha() gPipeline.unbindDeferredShader(*sVertexProgram); sDiffuseChannel = 0; - sShaderLevel = mVertexShaderLevel; + sShaderLevel = mShaderLevel; } void LLDrawPoolAvatar::renderPostDeferred(S32 pass) @@ -455,8 +446,13 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass) sVertexProgram = &gDeferredAvatarAlphaShadowProgram; // bind diffuse tex so we can reference the alpha channel... - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - + S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP); + sDiffuseChannel = 0; + if (loc != -1) + { + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + } + if ((sShaderLevel > 0)) // for hardware blending { sRenderingSkinned = TRUE; @@ -470,8 +466,13 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass) sVertexProgram = &gDeferredAvatarAlphaMaskShadowProgram; // bind diffuse tex so we can reference the alpha channel... - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - + S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP); + sDiffuseChannel = 0; + if (loc != -1) + { + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + } + if ((sShaderLevel > 0)) // for hardware blending { sRenderingSkinned = TRUE; @@ -485,7 +486,12 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass) sVertexProgram = &gDeferredAttachmentAlphaShadowProgram; // bind diffuse tex so we can reference the alpha channel... - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP); + sDiffuseChannel = 0; + if (loc != -1) + { + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + } if ((sShaderLevel > 0)) // for hardware blending { @@ -500,7 +506,12 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass) sVertexProgram = &gDeferredAttachmentAlphaMaskShadowProgram; // bind diffuse tex so we can reference the alpha channel... - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP); + sDiffuseChannel = 0; + if (loc != -1) + { + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + } if ((sShaderLevel > 0)) // for hardware blending { @@ -513,7 +524,12 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass) else // SHADOW_PASS_ATTACHMENT_OPAQUE { sVertexProgram = &gDeferredAttachmentShadowProgram; - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP); + sDiffuseChannel = 0; + if (loc != -1) + { + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + } sVertexProgram->bind(); } } @@ -556,12 +572,12 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) { return; } - - BOOL impostor = avatarp->isImpostor(); - if (impostor - && LLVOAvatar::AV_DO_NOT_RENDER != avatarp->getVisualMuteSettings() - && LLVOAvatar::AV_ALWAYS_RENDER != avatarp->getVisualMuteSettings()) + LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance(); + BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor(); + if (oa == LLVOAvatar::AOA_INVISIBLE || + (impostor && oa == LLVOAvatar::AOA_JELLYDOLL)) { + // No shadows for jellydolled or invisible avs. return; } @@ -776,7 +792,7 @@ void LLDrawPoolAvatar::beginImpostor() gImpostorProgram.setMinimumAlpha(0.01f); } - gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); + gPipeline.enableLightsFullbright(); sDiffuseChannel = 0; } @@ -806,6 +822,14 @@ void LLDrawPoolAvatar::beginRigid() { //eyeballs render with the specular shader sVertexProgram->bind(); sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha); + if (LLPipeline::sRenderingHUDs) + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); + } } } else @@ -816,7 +840,7 @@ void LLDrawPoolAvatar::beginRigid() void LLDrawPoolAvatar::endRigid() { - sShaderLevel = mVertexShaderLevel; + sShaderLevel = mShaderLevel; if (sVertexProgram != NULL) { sVertexProgram->unbind(); @@ -841,7 +865,7 @@ void LLDrawPoolAvatar::beginDeferredImpostor() void LLDrawPoolAvatar::endDeferredImpostor() { - sShaderLevel = mVertexShaderLevel; + sShaderLevel = mShaderLevel; sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL); sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP); sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); @@ -856,11 +880,19 @@ void LLDrawPoolAvatar::beginDeferredRigid() sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); sVertexProgram->bind(); sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha); + if (LLPipeline::sRenderingHUDs) + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); + } } void LLDrawPoolAvatar::endDeferredRigid() { - sShaderLevel = mVertexShaderLevel; + sShaderLevel = mShaderLevel; sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); sVertexProgram->unbind(); gGL.getTexUnit(0)->activate(); @@ -899,6 +931,14 @@ void LLDrawPoolAvatar::beginSkinned() sVertexProgram->bind(); sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP); + if (LLPipeline::sRenderingHUDs) + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); + } gGL.getTexUnit(0)->activate(); } else @@ -908,6 +948,14 @@ void LLDrawPoolAvatar::beginSkinned() // software skinning, use a basic shader for windlight. // TODO: find a better fallback method for software skinning. sVertexProgram->bind(); + if (LLPipeline::sRenderingHUDs) + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); + } } } @@ -926,7 +974,7 @@ void LLDrawPoolAvatar::endSkinned() sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP); gGL.getTexUnit(0)->activate(); sVertexProgram->unbind(); - sShaderLevel = mVertexShaderLevel; + sShaderLevel = mShaderLevel; } else { @@ -970,6 +1018,14 @@ void LLDrawPoolAvatar::beginRiggedSimple() { sDiffuseChannel = 0; sVertexProgram->bind(); + if (LLPipeline::sRenderingHUDs) + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); + } } } @@ -1035,6 +1091,16 @@ void LLDrawPoolAvatar::beginRiggedGlow() sVertexProgram->bind(); sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, LLPipeline::sRenderDeferred ? 2.2f : 1.1f); + + if (LLPipeline::sRenderingHUDs) + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); + } + F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); } @@ -1082,16 +1148,22 @@ void LLDrawPoolAvatar::beginRiggedFullbright() sDiffuseChannel = 0; sVertexProgram->bind(); - if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred) + if (LLPipeline::sRenderingHUDs) + { + sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else if (LLPipeline::sRenderDeferred) { - sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); + sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); + F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); + sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); } 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)); + sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); } } } @@ -1134,6 +1206,14 @@ void LLDrawPoolAvatar::beginRiggedShinySimple() if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) { sVertexProgram->bind(); + if (LLPipeline::sRenderingHUDs) + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); + } LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false); } } @@ -1184,17 +1264,32 @@ void LLDrawPoolAvatar::beginRiggedFullbrightShiny() if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) { sVertexProgram->bind(); + if (LLPipeline::sRenderingHUDs) + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); + } LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false); - if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred) + if (LLPipeline::sRenderingHUDs) { sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); - } - else + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else if (LLPipeline::sRenderDeferred) { - sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); + 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)); + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); + } + else + { + sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); } } } @@ -1216,6 +1311,14 @@ void LLDrawPoolAvatar::beginDeferredRiggedSimple() sVertexProgram = &gDeferredSkinnedDiffuseProgram; sDiffuseChannel = 0; sVertexProgram->bind(); + if (LLPipeline::sRenderingHUDs) + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); + } } void LLDrawPoolAvatar::endDeferredRiggedSimple() @@ -1229,6 +1332,14 @@ void LLDrawPoolAvatar::beginDeferredRiggedBump() { sVertexProgram = &gDeferredSkinnedBumpProgram; sVertexProgram->bind(); + if (LLPipeline::sRenderingHUDs) + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); + } normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP); sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); } @@ -1261,6 +1372,14 @@ void LLDrawPoolAvatar::beginDeferredRiggedMaterial(S32 pass) } sVertexProgram->bind(); + if (LLPipeline::sRenderingHUDs) + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); + } normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP); specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP); sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); @@ -1288,13 +1407,21 @@ void LLDrawPoolAvatar::endDeferredRiggedMaterial(S32 pass) void LLDrawPoolAvatar::beginDeferredSkinned() { - sShaderLevel = mVertexShaderLevel; + sShaderLevel = mShaderLevel; sVertexProgram = &gDeferredAvatarProgram; sRenderingSkinned = TRUE; sVertexProgram->bind(); sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha); - + if (LLPipeline::sRenderingHUDs) + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); + } + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); gGL.getTexUnit(0)->activate(); } @@ -1307,7 +1434,7 @@ void LLDrawPoolAvatar::endDeferredSkinned() sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - sShaderLevel = mVertexShaderLevel; + sShaderLevel = mShaderLevel; gGL.getTexUnit(0)->activate(); } @@ -1337,7 +1464,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) return; } - LLVOAvatar *avatarp; + LLVOAvatar *avatarp = NULL; if (single_avatar) { @@ -1383,11 +1510,12 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) return; } - BOOL impostor = avatarp->isImpostor() && !single_avatar; + BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor() && !single_avatar; if (( avatarp->isInMuteList() || impostor - || (LLVOAvatar::AV_DO_NOT_RENDER == avatarp->getVisualMuteSettings() && !avatarp->needsImpostorUpdate()) ) && pass != 0) + || (LLVOAvatar::AOA_NORMAL != avatarp->getOverallAppearance() && !avatarp->needsImpostorUpdate()) ) && pass != 0) +// || (LLVOAvatar::AV_DO_NOT_RENDER == avatarp->getVisualMuteSettings() && !avatarp->needsImpostorUpdate()) ) && pass != 0) { //don't draw anything but the impostor for impostored avatars return; } @@ -1397,6 +1525,13 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) return; } + LLVOAvatar *attached_av = avatarp->getAttachedAvatar(); + if (attached_av && LLVOAvatar::AOA_NORMAL != attached_av->getOverallAppearance()) + { + // Animesh attachment of a jellydolled or invisible parent - don't show + return; + } + if (pass == 0) { if (!LLPipeline::sReflectionRender) @@ -1404,7 +1539,8 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) LLVOAvatar::sNumVisibleAvatars++; } - if (impostor || (LLVOAvatar::AV_DO_NOT_RENDER == avatarp->getVisualMuteSettings() && !avatarp->needsImpostorUpdate())) +// if (impostor || (LLVOAvatar::AV_DO_NOT_RENDER == avatarp->getVisualMuteSettings() && !avatarp->needsImpostorUpdate())) + if (impostor || (LLVOAvatar::AOA_NORMAL != avatarp->getOverallAppearance() && !avatarp->needsImpostorUpdate())) { if (LLPipeline::sRenderDeferred && !LLPipeline::sReflectionRender && avatarp->mImpostor.isComplete()) { @@ -1604,11 +1740,16 @@ void LLDrawPoolAvatar::getRiggedGeometry( LLVolume* volume, const LLVolumeFace& vol_face) { - face->setGeomIndex(0); - face->setIndicesIndex(0); - - //rigged faces do not batch textures - face->setTextureIndex(255); + face->setGeomIndex(0); + face->setIndicesIndex(0); + + if (face->getTextureIndex() != FACE_DO_NOT_BATCH_TEXTURES) + { + face->setDrawInfo(NULL); + } + + //rigged faces do not batch textures + face->setTextureIndex(FACE_DO_NOT_BATCH_TEXTURES); if (buffer.isNull() || buffer->getTypeMask() != data_mask || !buffer->isWriteable()) { @@ -1673,7 +1814,7 @@ void LLDrawPoolAvatar::getRiggedGeometry( } else { - face->setPoolType(LLDrawPool::POOL_AVATAR); + face->setPoolType(mType); // either POOL_AVATAR or POOL_CONTROL_AV } //LL_INFOS() << "Rebuilt face " << face->getTEOffset() << " of " << face->getDrawable() << " at " << gFrameTimeSeconds << LL_ENDL; @@ -1697,15 +1838,13 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( LLFace* face, const LLMeshSkinInfo* skin, LLVolume* volume, - const LLVolumeFace& vol_face) + LLVolumeFace& vol_face) { LLVector4a* weights = vol_face.mWeights; if (!weights) { return; } - // FIXME ugly const cast - LLSkinningUtil::scrubInvalidJoints(avatar, const_cast<LLMeshSkinInfo*>(skin)); LLPointer<LLVertexBuffer> buffer = face->getVertexBuffer(); LLDrawable* drawable = face->getDrawable(); @@ -1715,6 +1854,48 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( return; } + const U32 max_joints = LLSkinningUtil::getMaxJointCount(); + +#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS + #define CONDITION_WEIGHT(f) ((U8)llclamp((S32)f, (S32)0, (S32)max_joints-1)) + LLVector4a* just_weights = vol_face.mJustWeights; + // we need to calculate the separated indices and store just the matrix weights for this vol... + if (!vol_face.mJointIndices) + { + // not very consty after all... + vol_face.allocateJointIndices(vol_face.mNumVertices); + just_weights = vol_face.mJustWeights; + + U8* joint_indices_cursor = vol_face.mJointIndices; + for (int i = 0; i < vol_face.mNumVertices; i++) + { + F32* w = weights[i].getF32ptr(); + F32* w_ = just_weights[i].getF32ptr(); + + F32 w0 = floorf(w[0]); + F32 w1 = floorf(w[1]); + F32 w2 = floorf(w[2]); + F32 w3 = floorf(w[3]); + + joint_indices_cursor[0] = CONDITION_WEIGHT(w0); + joint_indices_cursor[1] = CONDITION_WEIGHT(w1); + joint_indices_cursor[2] = CONDITION_WEIGHT(w2); + joint_indices_cursor[3] = CONDITION_WEIGHT(w3); + + // remove joint portion of combined weight + w_[0] = w[0] - w0; + w_[1] = w[1] - w1; + w_[2] = w[2] - w2; + w_[3] = w[3] - w3; + + joint_indices_cursor += 4; + } + } +#endif + + // FIXME ugly const cast + LLSkinningUtil::scrubInvalidJoints(avatar, const_cast<LLMeshSkinInfo*>(skin)); + U32 data_mask = face->getRiggedVertexBufferDataMask(); if (!vol_face.mWeightsScrubbed) @@ -1791,29 +1972,67 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( LLMatrix4a bind_shape_matrix; bind_shape_matrix.loadu(skin->mBindShapeMatrix); - const U32 max_joints = LLSkinningUtil::getMaxJointCount(); - for (U32 j = 0; j < buffer->getNumVerts(); ++j) - { - LLMatrix4a final_mat; - LLSkinningUtil::getPerVertexSkinMatrix(weights[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; - - if (norm) - { - LLVector4a& n = vol_face.mNormals[j]; - bind_shape_matrix.rotate(n, t); - final_mat.rotate(t, dst); - dst.normalize3fast(); - norm[j] = dst; - } - } +#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS + U8* joint_indices_cursor = vol_face.mJointIndices; + // fast path with joint indices separate from weights + if (joint_indices_cursor) + { + LLMatrix4a src[4]; + for (U32 j = 0; j < buffer->getNumVerts(); ++j) + { + LLMatrix4a final_mat; + //LLMatrix4a final_mat_correct; + + F32* jw = just_weights[j].getF32ptr(); + + LLSkinningUtil::getPerVertexSkinMatrixWithIndices(jw, joint_indices_cursor, mat, final_mat, src); + + joint_indices_cursor += 4; + + 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); + dst.normalize3fast(); + norm[j] = dst; + } + } + } + // slow path with joint indices calculated from weights + else +#endif + { + for (U32 j = 0; j < buffer->getNumVerts(); ++j) + { + LLMatrix4a final_mat; + LLSkinningUtil::getPerVertexSkinMatrix(weights[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; + + if (norm) + { + LLVector4a& n = vol_face.mNormals[j]; + bind_shape_matrix.rotate(n, t); + final_mat.rotate(t, dst); + //dst.normalize3fast(); + norm[j] = dst; + } + } + } } } @@ -2079,12 +2298,24 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) if (face->mTextureMatrix && vobj->mTexAnimMode) { - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadMatrix((F32*) face->mTextureMatrix->mMatrix); + U32 tex_index = gGL.getCurrentTexUnitIndex(); + + if (tex_index <= 1) + { + gGL.matrixMode(LLRender::eMatrixMode(LLRender::MM_TEXTURE0 + tex_index)); + gGL.pushMatrix(); + gGL.loadMatrix((F32*) face->mTextureMatrix->mMatrix); + } + buff->setBuffer(data_mask); buff->drawRange(LLRender::TRIANGLES, start, end, count, offset); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_MODELVIEW); + + if (tex_index <= 1) + { + gGL.matrixMode(LLRender::eMatrixMode(LLRender::MM_TEXTURE0 + tex_index)); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + } } else { @@ -2153,7 +2384,7 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) stop_glerror(); - const LLVolumeFace& vol_face = volume->getVolumeFace(te); + LLVolumeFace& vol_face = volume->getVolumeFace(te); updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face); } } @@ -2267,7 +2498,7 @@ LLColor3 LLDrawPoolAvatar::getDebugColor() const void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type) { llassert (facep->isState(LLFace::RIGGED)); - llassert(getType() == LLDrawPool::POOL_AVATAR); + llassert(getType() == LLDrawPool::POOL_AVATAR || getType() == LLDrawPool::POOL_CONTROL_AV); if (facep->getPool() && facep->getPool() != this) { LL_ERRS() << "adding rigged face that's already in another pool" << LL_ENDL; @@ -2289,7 +2520,7 @@ void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type) void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep) { llassert (facep->isState(LLFace::RIGGED)); - llassert(getType() == LLDrawPool::POOL_AVATAR); + llassert(getType() == LLDrawPool::POOL_AVATAR || getType() == LLDrawPool::POOL_CONTROL_AV); if (facep->getPool() != this) { LL_ERRS() << "Tried to remove a rigged face from the wrong pool" << LL_ENDL; diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h index 8c1bc70c8e..92a8538958 100644 --- a/indra/newview/lldrawpoolavatar.h +++ b/indra/newview/lldrawpoolavatar.h @@ -57,6 +57,7 @@ public: ~LLDrawPoolAvatar(); /*virtual*/ BOOL isDead(); + typedef enum { RIGGED_MATERIAL=0, @@ -175,14 +176,12 @@ typedef enum virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } - virtual S32 getVertexShaderLevel() const; + virtual S32 getShaderLevel() const; - LLDrawPoolAvatar(); + LLDrawPoolAvatar(U32 type); static LLMatrix4& getModelView(); - /*virtual*/ LLDrawPool *instancePool(); - /*virtual*/ S32 getNumPasses(); /*virtual*/ void beginRenderPass(S32 pass); /*virtual*/ void endRenderPass(S32 pass); @@ -256,7 +255,7 @@ typedef enum LLFace* facep, const LLMeshSkinInfo* skin, LLVolume* volume, - const LLVolumeFace& vol_face); + LLVolumeFace& vol_face); void updateRiggedVertexBuffers(LLVOAvatar* avatar); void renderRigged(LLVOAvatar* avatar, U32 type, bool glow = false); diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 7b9fd5c6c6..14069fa6c2 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -193,7 +193,7 @@ LLDrawPoolBump::LLDrawPoolBump() void LLDrawPoolBump::prerender() { - mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); + mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); } // static @@ -201,7 +201,7 @@ S32 LLDrawPoolBump::numBumpPasses() { if (gSavedSettings.getBOOL("RenderObjectBump")) { - if (mVertexShaderLevel > 1) + if (mShaderLevel > 1) { if (LLPipeline::sImpostorRender) { @@ -241,7 +241,7 @@ void LLDrawPoolBump::beginRenderPass(S32 pass) beginShiny(); break; case 1: - if (mVertexShaderLevel > 1) + if (mShaderLevel > 1) { beginFullbrightShiny(); } @@ -274,7 +274,7 @@ void LLDrawPoolBump::render(S32 pass) renderShiny(); break; case 1: - if (mVertexShaderLevel > 1) + if (mShaderLevel > 1) { renderFullbrightShiny(); } @@ -301,7 +301,7 @@ void LLDrawPoolBump::endRenderPass(S32 pass) endShiny(); break; case 1: - if (mVertexShaderLevel > 1) + if (mShaderLevel > 1) { endFullbrightShiny(); } @@ -335,12 +335,12 @@ void LLDrawPoolBump::beginShiny(bool invisible) mShiny = TRUE; sVertexMask = VERTEX_MASK_SHINY; // Second pass: environment map - if (!invisible && mVertexShaderLevel > 1) + if (!invisible && mShaderLevel > 1) { sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0; } - if (getVertexShaderLevel() > 0) + if (getShaderLevel() > 0) { if (LLPipeline::sUnderWaterRender) { @@ -351,15 +351,23 @@ void LLDrawPoolBump::beginShiny(bool invisible) shader = &gObjectShinyProgram; } shader->bind(); + if (LLPipeline::sRenderingHUDs) + { + shader->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + shader->uniform1i(LLShaderMgr::NO_ATMO, 0); + } } else { shader = NULL; } - bindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel, invisible); + bindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel, invisible); - if (mVertexShaderLevel > 1) + if (mShaderLevel > 1) { //indexed texture rendering, channel 0 is always diffuse diffuse_channel = 0; } @@ -428,7 +436,7 @@ void LLDrawPoolBump::renderShiny(bool invisible) if( gSky.mVOSkyp->getCubeMap() ) { LLGLEnable blend_enable(GL_BLEND); - if (!invisible && mVertexShaderLevel > 1) + if (!invisible && mShaderLevel > 1) { LLRenderPass::pushBatches(LLRenderPass::PASS_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); } @@ -453,7 +461,7 @@ void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& { shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); - if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0) + if (LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0) { if (diffuse_channel != 0) { @@ -486,7 +494,7 @@ void LLDrawPoolBump::endShiny(bool invisible) return; } - unbindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel, invisible); + unbindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel, invisible); if (shader) { shader->unbind(); @@ -534,6 +542,15 @@ void LLDrawPoolBump::beginFullbrightShiny() LLVector4(gGLModelView+8), LLVector4(gGLModelView+12)); shader->bind(); + if (LLPipeline::sRenderingHUDs) + { + shader->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + shader->uniform1i(LLShaderMgr::NO_ATMO, 0); + } + LLVector3 vec = LLVector3(gShinyOrigin) * mat; LLVector4 vec4(vec, gShinyOrigin.mV[3]); shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV); @@ -551,7 +568,7 @@ void LLDrawPoolBump::beginFullbrightShiny() gGL.getTexUnit(0)->activate(); } - if (mVertexShaderLevel > 1) + if (mShaderLevel > 1) { //indexed texture rendering, channel 0 is always diffuse diffuse_channel = 0; } @@ -571,7 +588,7 @@ void LLDrawPoolBump::renderFullbrightShiny() { LLGLEnable blend_enable(GL_BLEND); - if (mVertexShaderLevel > 1) + if (mShaderLevel > 1) { LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); } @@ -1524,7 +1541,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL tex_setup = true; } - if (mShiny && mVertexShaderLevel > 1 && texture) + if (mShiny && mShaderLevel > 1 && texture) { if (params.mTexture.notNull()) { diff --git a/indra/newview/lldrawpoolground.cpp b/indra/newview/lldrawpoolground.cpp index 59c3fbf7a1..5b74264dab 100644 --- a/indra/newview/lldrawpoolground.cpp +++ b/indra/newview/lldrawpoolground.cpp @@ -46,14 +46,9 @@ LLDrawPoolGround::LLDrawPoolGround() : { } -LLDrawPool *LLDrawPoolGround::instancePool() -{ - return new LLDrawPoolGround(); -} - void LLDrawPoolGround::prerender() { - mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT); + mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT); } void LLDrawPoolGround::render(S32 pass) @@ -63,13 +58,9 @@ void LLDrawPoolGround::render(S32 pass) return; } - LLGLSPipelineSkyBox gls_skybox; + LLGLSPipelineDepthTestSkyBox gls_skybox(true, false); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - - LLGLSquashToFarClip far_clip(glh_get_current_projection()); - F32 water_height = gAgent.getRegion()->getWaterHeight(); gGL.pushMatrix(); LLVector3 origin = LLViewerCamera::getInstance()->getOrigin(); @@ -77,8 +68,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/lldrawpoolground.h b/indra/newview/lldrawpoolground.h index a4f8a3fcf5..15b1dc60a2 100644 --- a/indra/newview/lldrawpoolground.h +++ b/indra/newview/lldrawpoolground.h @@ -43,8 +43,6 @@ public: LLDrawPoolGround(); - /*virtual*/ LLDrawPool *instancePool(); - /*virtual*/ void prerender(); /*virtual*/ void render(S32 pass = 0); }; diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp index 63e96a93b5..05b0c1f1a9 100644 --- a/indra/newview/lldrawpoolmaterials.cpp +++ b/indra/newview/lldrawpoolmaterials.cpp @@ -42,7 +42,7 @@ LLDrawPoolMaterials::LLDrawPoolMaterials() void LLDrawPoolMaterials::prerender() { - mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); + mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); } S32 LLDrawPoolMaterials::getNumDeferredPasses() @@ -81,6 +81,15 @@ void LLDrawPoolMaterials::beginDeferredPass(S32 pass) mShader->bind(); + if (LLPipeline::sRenderingHUDs) + { + mShader->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + mShader->uniform1i(LLShaderMgr::NO_ATMO, 0); + } + diffuse_channel = mShader->enableTexture(LLShaderMgr::DIFFUSE_MAP); LL_RECORD_BLOCK_TIME(FTM_RENDER_MATERIALS); @@ -194,7 +203,7 @@ void LLDrawPoolMaterials::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, tex_setup = true; } - if (mVertexShaderLevel > 1 && texture) + if (mShaderLevel > 1 && texture) { if (params.mTexture.notNull()) { diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp index bd180de6c6..f211cf6e27 100644 --- a/indra/newview/lldrawpoolsimple.cpp +++ b/indra/newview/lldrawpoolsimple.cpp @@ -47,6 +47,14 @@ void LLDrawPoolGlow::beginPostDeferredPass(S32 pass) { gDeferredEmissiveProgram.bind(); gDeferredEmissiveProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); + if (LLPipeline::sRenderingHUDs) + { + gDeferredEmissiveProgram.uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + gDeferredEmissiveProgram.uniform1i(LLShaderMgr::NO_ATMO, 0); + } } static LLTrace::BlockTimerStatHandle FTM_RENDER_GLOW_PUSH("Glow Push"); @@ -82,7 +90,7 @@ void LLDrawPoolGlow::endPostDeferredPass(S32 pass) S32 LLDrawPoolGlow::getNumPasses() { - if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0) + if (LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0) { return 1; } @@ -103,7 +111,7 @@ void LLDrawPoolGlow::render(S32 pass) glPolygonOffset(-1.0f, -1.0f); gGL.setSceneBlendType(LLRender::BT_ADD); - U32 shader_level = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); + U32 shader_level = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); //should never get here without basic shaders enabled llassert(shader_level > 0); @@ -119,6 +127,15 @@ void LLDrawPoolGlow::render(S32 pass) shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f); } + if (LLPipeline::sRenderingHUDs) + { + shader->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + shader->uniform1i(LLShaderMgr::NO_ATMO, 0); + } + LLGLDepthTest depth(GL_TRUE, GL_FALSE); gGL.setColorMask(false, true); @@ -147,7 +164,7 @@ LLDrawPoolSimple::LLDrawPoolSimple() : void LLDrawPoolSimple::prerender() { - mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); + mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); } void LLDrawPoolSimple::beginRenderPass(S32 pass) @@ -167,9 +184,18 @@ void LLDrawPoolSimple::beginRenderPass(S32 pass) simple_shader = &gObjectSimpleProgram; } - if (mVertexShaderLevel > 0) + if (mShaderLevel > 0) { simple_shader->bind(); + + if (LLPipeline::sRenderingHUDs) + { + simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0); + } } else { @@ -187,7 +213,7 @@ void LLDrawPoolSimple::endRenderPass(S32 pass) stop_glerror(); LLRenderPass::endRenderPass(pass); stop_glerror(); - if (mVertexShaderLevel > 0) + if (mShaderLevel > 0) { simple_shader->unbind(); } @@ -201,7 +227,7 @@ void LLDrawPoolSimple::render(S32 pass) LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE); gPipeline.enableLightsDynamic(); - if (mVertexShaderLevel > 0) + if (mShaderLevel > 0) { U32 mask = getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX; @@ -244,7 +270,7 @@ LLDrawPoolAlphaMask::LLDrawPoolAlphaMask() : void LLDrawPoolAlphaMask::prerender() { - mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); + mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); } void LLDrawPoolAlphaMask::beginRenderPass(S32 pass) @@ -260,9 +286,18 @@ void LLDrawPoolAlphaMask::beginRenderPass(S32 pass) simple_shader = &gObjectSimpleAlphaMaskProgram; } - if (mVertexShaderLevel > 0) + if (mShaderLevel > 0) { simple_shader->bind(); + + if (LLPipeline::sRenderingHUDs) + { + simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0); + } } else { @@ -280,7 +315,7 @@ void LLDrawPoolAlphaMask::endRenderPass(S32 pass) stop_glerror(); LLRenderPass::endRenderPass(pass); stop_glerror(); - if (mVertexShaderLevel > 0) + if (mShaderLevel > 0) { simple_shader->unbind(); } @@ -291,11 +326,20 @@ void LLDrawPoolAlphaMask::render(S32 pass) LLGLDisable blend(GL_BLEND); LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK); - if (mVertexShaderLevel > 0) + if (mShaderLevel > 0) { simple_shader->bind(); simple_shader->setMinimumAlpha(0.33f); + if (LLPipeline::sRenderingHUDs) + { + simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0); + } + 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); @@ -317,7 +361,7 @@ LLDrawPoolFullbrightAlphaMask::LLDrawPoolFullbrightAlphaMask() : void LLDrawPoolFullbrightAlphaMask::prerender() { - mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); + mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); } void LLDrawPoolFullbrightAlphaMask::beginRenderPass(S32 pass) @@ -333,9 +377,18 @@ void LLDrawPoolFullbrightAlphaMask::beginRenderPass(S32 pass) simple_shader = &gObjectFullbrightAlphaMaskProgram; } - if (mVertexShaderLevel > 0) + if (mShaderLevel > 0) { simple_shader->bind(); + + if (LLPipeline::sRenderingHUDs) + { + simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0); + } } else { @@ -353,7 +406,7 @@ void LLDrawPoolFullbrightAlphaMask::endRenderPass(S32 pass) stop_glerror(); LLRenderPass::endRenderPass(pass); stop_glerror(); - if (mVertexShaderLevel > 0) + if (mShaderLevel > 0) { simple_shader->unbind(); } @@ -363,18 +416,30 @@ void LLDrawPoolFullbrightAlphaMask::render(S32 pass) { LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK); - if (mVertexShaderLevel > 0) + if (mShaderLevel > 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); - } + + if (LLPipeline::sRenderingHUDs) + { + simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1); + simple_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); + } + else + { + simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0); + if (LLPipeline::sRenderDeferred) + { + simple_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); + } + else + { + simple_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); + } + } } pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); //LLGLSLShader::bindNoShader(); @@ -382,7 +447,7 @@ void LLDrawPoolFullbrightAlphaMask::render(S32 pass) else { LLGLEnable test(GL_ALPHA_TEST); - gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); + gPipeline.enableLightsFullbright(); pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask(), TRUE, FALSE); gPipeline.enableLightsDynamic(); gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK @@ -397,6 +462,15 @@ void LLDrawPoolSimple::beginDeferredPass(S32 pass) { LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED); gDeferredDiffuseProgram.bind(); + + if (LLPipeline::sRenderingHUDs) + { + gDeferredDiffuseProgram.uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + gDeferredDiffuseProgram.uniform1i(LLShaderMgr::NO_ATMO, 0); + } } void LLDrawPoolSimple::endDeferredPass(S32 pass) @@ -435,6 +509,16 @@ void LLDrawPoolAlphaMask::renderDeferred(S32 pass) LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_DEFERRED); gDeferredDiffuseAlphaMaskProgram.bind(); gDeferredDiffuseAlphaMaskProgram.setMinimumAlpha(0.33f); + + if (LLPipeline::sRenderingHUDs) + { + gDeferredDiffuseAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + gDeferredDiffuseAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 0); + } + pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); gDeferredDiffuseAlphaMaskProgram.unbind(); } @@ -449,7 +533,7 @@ LLDrawPoolGrass::LLDrawPoolGrass() : void LLDrawPoolGrass::prerender() { - mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); + mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); } @@ -467,10 +551,18 @@ void LLDrawPoolGrass::beginRenderPass(S32 pass) simple_shader = &gObjectAlphaMaskNonIndexedProgram; } - if (mVertexShaderLevel > 0) + if (mShaderLevel > 0) { simple_shader->bind(); simple_shader->setMinimumAlpha(0.5f); + if (LLPipeline::sRenderingHUDs) + { + simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0); + } } else { @@ -488,7 +580,7 @@ void LLDrawPoolGrass::endRenderPass(S32 pass) LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS); LLRenderPass::endRenderPass(pass); - if (mVertexShaderLevel > 0) + if (mShaderLevel > 0) { simple_shader->unbind(); } @@ -527,6 +619,16 @@ void LLDrawPoolGrass::renderDeferred(S32 pass) LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS_DEFERRED); gDeferredNonIndexedDiffuseAlphaMaskProgram.bind(); gDeferredNonIndexedDiffuseAlphaMaskProgram.setMinimumAlpha(0.5f); + + if (LLPipeline::sRenderingHUDs) + { + gDeferredNonIndexedDiffuseAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + gDeferredNonIndexedDiffuseAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 0); + } + //render grass LLRenderPass::renderTexture(LLRenderPass::PASS_GRASS, getVertexDataMask()); } @@ -541,7 +643,7 @@ LLDrawPoolFullbright::LLDrawPoolFullbright() : void LLDrawPoolFullbright::prerender() { - mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); + mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); } void LLDrawPoolFullbright::beginPostDeferredPass(S32 pass) @@ -553,6 +655,15 @@ void LLDrawPoolFullbright::beginPostDeferredPass(S32 pass) else { gDeferredFullbrightProgram.bind(); + + if (LLPipeline::sRenderingHUDs) + { + gDeferredFullbrightProgram.uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + gDeferredFullbrightProgram.uniform1i(LLShaderMgr::NO_ATMO, 0); + } } } @@ -600,7 +711,7 @@ void LLDrawPoolFullbright::endRenderPass(S32 pass) stop_glerror(); - if (mVertexShaderLevel > 0) + if (mShaderLevel > 0) { fullbright_shader->unbind(); } @@ -615,12 +726,21 @@ void LLDrawPoolFullbright::render(S32 pass) stop_glerror(); - if (mVertexShaderLevel > 0) + if (mShaderLevel > 0) { fullbright_shader->bind(); fullbright_shader->uniform1f(LLViewerShaderMgr::FULLBRIGHT, 1.f); fullbright_shader->uniform1f(LLViewerShaderMgr::TEXTURE_GAMMA, 1.f); + if (LLPipeline::sRenderingHUDs) + { + fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, 0); + } + 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); @@ -630,7 +750,7 @@ void LLDrawPoolFullbright::render(S32 pass) } else { - gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); + gPipeline.enableLightsFullbright(); 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); @@ -651,23 +771,32 @@ S32 LLDrawPoolFullbright::getNumPasses() void LLDrawPoolFullbrightAlphaMask::beginPostDeferredPass(S32 pass) { - if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred) - { - gObjectFullbrightAlphaMaskProgram.bind(); + if (LLPipeline::sRenderingHUDs) + { + gObjectFullbrightAlphaMaskProgram.bind(); gObjectFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); - } - else - { - if (LLPipeline::sUnderWaterRender) + gObjectFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else if (LLPipeline::sRenderDeferred) + { + if (LLPipeline::sUnderWaterRender) { gDeferredFullbrightAlphaMaskWaterProgram.bind(); gDeferredFullbrightAlphaMaskWaterProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); + gDeferredFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 1); } else { gDeferredFullbrightAlphaMaskProgram.bind(); gDeferredFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); + gDeferredFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 0); } + } + else + { + gObjectFullbrightAlphaMaskProgram.bind(); + gObjectFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); + gObjectFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 0); } } diff --git a/indra/newview/lldrawpoolsky.cpp b/indra/newview/lldrawpoolsky.cpp index bdb16abc78..b6f55e800a 100644 --- a/indra/newview/lldrawpoolsky.cpp +++ b/indra/newview/lldrawpoolsky.cpp @@ -48,14 +48,9 @@ LLDrawPoolSky::LLDrawPoolSky() { } -LLDrawPool *LLDrawPoolSky::instancePool() -{ - return new LLDrawPoolSky(); -} - void LLDrawPoolSky::prerender() { - mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT); + mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT); gSky.mVOSkyp->updateGeometry(gSky.mVOSkyp->mDrawable); } @@ -75,7 +70,7 @@ void LLDrawPoolSky::render(S32 pass) } // don't render sky under water (background just gets cleared to fog color) - if(mVertexShaderLevel > 0 && LLPipeline::sUnderWaterRender) + if(mShaderLevel > 0 && LLPipeline::sUnderWaterRender) { return; } @@ -98,18 +93,10 @@ void LLDrawPoolSky::render(S32 pass) } - LLGLSPipelineSkyBox gls_skybox; - - LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - - LLGLSquashToFarClip far_clip(glh_get_current_projection()); - - LLGLEnable fog_enable( (mVertexShaderLevel < 1 && LLViewerCamera::getInstance()->cameraUnderWater()) ? GL_FOG : 0); + LLGLSPipelineDepthTestSkyBox gls_skybox(true, false); - gPipeline.disableLights(); + LLGLEnable fog_enable( (mShaderLevel < 1 && LLViewerCamera::getInstance()->cameraUnderWater()) ? GL_FOG : 0); - LLGLDisable clip(GL_CLIP_PLANE0); - gGL.pushMatrix(); LLVector3 origin = LLViewerCamera::getInstance()->getOrigin(); gGL.translatef(origin.mV[0], origin.mV[1], origin.mV[2]); @@ -119,35 +106,41 @@ void LLDrawPoolSky::render(S32 pass) LLVertexBuffer::unbind(); gGL.diffuseColor4f(1,1,1,1); - for (S32 i = 0; i < llmin(6, face_count); ++i) + for (S32 i = 0; i < face_count; ++i) { - renderSkyCubeFace(i); + renderSkyFace(i); } gGL.popMatrix(); } -void LLDrawPoolSky::renderSkyCubeFace(U8 side) +void LLDrawPoolSky::renderSkyFace(U8 index) { - LLFace &face = *mDrawFace[LLVOSky::FACE_SIDE0 + side]; - if (!face.getGeomCount()) + LLFace* face = mDrawFace[index]; + + if (!face || !face->getGeomCount()) { return; } - llassert(mSkyTex); - mSkyTex[side].bindTexture(TRUE); - - face.renderIndexed(); - - if (LLSkyTex::doInterpolate()) - { - - LLGLEnable blend(GL_BLEND); - mSkyTex[side].bindTexture(FALSE); - gGL.diffuseColor4f(1, 1, 1, LLSkyTex::getInterpVal()); // lighting is disabled - face.renderIndexed(); - } + if (index < 6) // sky tex...interp + { + llassert(mSkyTex); + mSkyTex[index].bindTexture(true); // bind the current tex + + face->renderIndexed(); + } + else // heavenly body faces, no interp... + { + LLGLEnable blend(GL_BLEND); + + LLViewerTexture* tex = face->getTexture(LLRender::DIFFUSE_MAP); + if (tex) + { + gGL.getTexUnit(0)->bind(tex, true); + face->renderIndexed(); + } + } } void LLDrawPoolSky::endRenderPass( S32 pass ) diff --git a/indra/newview/lldrawpoolsky.h b/indra/newview/lldrawpoolsky.h index 098bd2134a..d1dcd6b22e 100644 --- a/indra/newview/lldrawpoolsky.h +++ b/indra/newview/lldrawpoolsky.h @@ -49,8 +49,6 @@ public: LLDrawPoolSky(); - /*virtual*/ LLDrawPool *instancePool(); - /*virtual*/ S32 getNumPostDeferredPasses() { return getNumPasses(); } /*virtual*/ void beginPostDeferredPass(S32 pass) { beginRenderPass(pass); } /*virtual*/ void endPostDeferredPass(S32 pass) { endRenderPass(pass); } @@ -61,7 +59,7 @@ public: /*virtual*/ void endRenderPass(S32 pass); void setSkyTex(LLSkyTex* const st) { mSkyTex = st; } - void renderSkyCubeFace(U8 side); + void renderSkyFace(U8 index); void renderHeavenlyBody(U8 hb, LLFace* face); void renderSunHalo(LLFace* face); diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp index 3eefcef7aa..37dc80e2b7 100644 --- a/indra/newview/lldrawpoolterrain.cpp +++ b/indra/newview/lldrawpoolterrain.cpp @@ -48,6 +48,8 @@ #include "pipeline.h" #include "llviewershadermgr.h" #include "llrender.h" +#include "llenvironment.h" +#include "llsettingsvo.h" const F32 DETAIL_SCALE = 1.f/16.f; int DebugDetailMap = 0; @@ -85,13 +87,6 @@ LLDrawPoolTerrain::~LLDrawPoolTerrain() llassert( gPipeline.findPool( getType(), getTexture() ) == NULL ); } - -LLDrawPool *LLDrawPoolTerrain::instancePool() -{ - return new LLDrawPoolTerrain(mTexturep); -} - - U32 LLDrawPoolTerrain::getVertexDataMask() { if (LLPipeline::sShadowRender) @@ -110,7 +105,7 @@ U32 LLDrawPoolTerrain::getVertexDataMask() void LLDrawPoolTerrain::prerender() { - mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT); + mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT); sDetailMode = gSavedSettings.getS32("RenderTerrainDetail"); } @@ -123,7 +118,7 @@ void LLDrawPoolTerrain::beginRenderPass( S32 pass ) &gTerrainWaterProgram : &gTerrainProgram; - if (mVertexShaderLevel > 1 && sShader->mShaderLevel > 0) + if (mShaderLevel > 1 && sShader->mShaderLevel > 0) { sShader->bind(); } @@ -134,7 +129,7 @@ void LLDrawPoolTerrain::endRenderPass( S32 pass ) LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); //LLFacePool::endRenderPass(pass); - if (mVertexShaderLevel > 1 && sShader->mShaderLevel > 0) { + if (mShaderLevel > 1 && sShader->mShaderLevel > 0) { sShader->unbind(); } } @@ -145,6 +140,18 @@ S32 LLDrawPoolTerrain::getDetailMode() return sDetailMode; } +void LLDrawPoolTerrain::boostTerrainDetailTextures() +{ + // Hack! Get the region that this draw pool is rendering from! + LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); + LLVLComposition *compp = regionp->getComposition(); + for (S32 i = 0; i < 4; i++) + { + compp->mDetailTextures[i]->setBoostLevel(LLGLTexture::BOOST_TERRAIN); + compp->mDetailTextures[i]->addTextureStats(1024.f*1024.f); // assume large pixel area + } +} + void LLDrawPoolTerrain::render(S32 pass) { LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); @@ -154,14 +161,7 @@ void LLDrawPoolTerrain::render(S32 pass) return; } - // Hack! Get the region that this draw pool is rendering from! - LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); - LLVLComposition *compp = regionp->getComposition(); - for (S32 i = 0; i < 4; i++) - { - compp->mDetailTextures[i]->setBoostLevel(LLGLTexture::BOOST_TERRAIN); - compp->mDetailTextures[i]->addTextureStats(1024.f*1024.f); // assume large pixel area - } + boostTerrainDetailTextures(); LLOverrideFaceColor override(this, 1.f, 1.f, 1.f, 1.f); @@ -180,7 +180,7 @@ void LLDrawPoolTerrain::render(S32 pass) LLGLSPipeline gls; - if (mVertexShaderLevel > 1 && sShader->mShaderLevel > 0) + if (mShaderLevel > 1 && sShader->mShaderLevel > 0) { gPipeline.enableLightsDynamic(); @@ -216,7 +216,7 @@ void LLDrawPoolTerrain::beginDeferredPass(S32 pass) LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); LLFacePool::beginRenderPass(pass); - sShader = &gDeferredTerrainProgram; + sShader = LLPipeline::sUnderWaterRender ? &gDeferredTerrainWaterProgram : &gDeferredTerrainProgram; sShader->bind(); } @@ -236,6 +236,8 @@ void LLDrawPoolTerrain::renderDeferred(S32 pass) return; } + boostTerrainDetailTextures(); + renderFullShader(); // Special-case for land ownership feedback @@ -252,6 +254,9 @@ void LLDrawPoolTerrain::beginShadowPass(S32 pass) LLFacePool::beginRenderPass(pass); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gDeferredShadowProgram.bind(); + + LLEnvironment& environment = LLEnvironment::instance(); + gDeferredShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); } void LLDrawPoolTerrain::endShadowPass(S32 pass) @@ -327,7 +332,8 @@ void LLDrawPoolTerrain::renderFullShader() // S32 detail0 = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0); gGL.getTexUnit(detail0)->bind(detail_texture0p); - gGL.getTexUnit(0)->activate(); + gGL.getTexUnit(detail0)->setTextureAddressMode(LLTexUnit::TAM_WRAP); + gGL.getTexUnit(detail0)->activate(); LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; llassert(shader); @@ -335,54 +341,40 @@ void LLDrawPoolTerrain::renderFullShader() 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(); - gGL.matrixMode(LLRender::MM_MODELVIEW); + LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater(); + + ((LLSettingsVOWater*)pwater.get())->updateShader(shader); // // detail texture 1 // S32 detail1 = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_DETAIL1); gGL.getTexUnit(detail1)->bind(detail_texture1p); - - /// ALPHA TEXTURE COORDS 0: - gGL.getTexUnit(1)->activate(); - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.getTexUnit(detail1)->setTextureAddressMode(LLTexUnit::TAM_WRAP); + gGL.getTexUnit(detail1)->activate(); // detail texture 2 // S32 detail2 = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_DETAIL2); gGL.getTexUnit(detail2)->bind(detail_texture2p); - - gGL.getTexUnit(2)->activate(); + gGL.getTexUnit(detail2)->setTextureAddressMode(LLTexUnit::TAM_WRAP); + gGL.getTexUnit(detail2)->activate(); - /// ALPHA TEXTURE COORDS 1: - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadIdentity(); - gGL.translatef(-2.f, 0.f, 0.f); - gGL.matrixMode(LLRender::MM_MODELVIEW); - // // detail texture 3 // S32 detail3 = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_DETAIL3); gGL.getTexUnit(detail3)->bind(detail_texture3p); - - /// ALPHA TEXTURE COORDS 2: - gGL.getTexUnit(3)->activate(); - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadIdentity(); - gGL.translatef(-1.f, 0.f, 0.f); - gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.getTexUnit(detail3)->setTextureAddressMode(LLTexUnit::TAM_WRAP); + gGL.getTexUnit(detail3)->activate(); // // Alpha Ramp // S32 alpha_ramp = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP); gGL.getTexUnit(alpha_ramp)->bind(m2DAlphaRampImagep); - + gGL.getTexUnit(alpha_ramp)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + // GL_BLEND disabled by default drawLoop(); @@ -394,47 +386,32 @@ void LLDrawPoolTerrain::renderFullShader() sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL3); gGL.getTexUnit(alpha_ramp)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(4)->disable(); - gGL.getTexUnit(4)->activate(); + gGL.getTexUnit(alpha_ramp)->disable(); + gGL.getTexUnit(alpha_ramp)->activate(); gGL.getTexUnit(detail3)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(3)->disable(); - gGL.getTexUnit(3)->activate(); - - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.getTexUnit(detail3)->disable(); + gGL.getTexUnit(detail3)->activate(); gGL.getTexUnit(detail2)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(2)->disable(); - gGL.getTexUnit(2)->activate(); - - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.getTexUnit(detail2)->disable(); + gGL.getTexUnit(detail2)->activate(); gGL.getTexUnit(detail1)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(1)->disable(); - gGL.getTexUnit(1)->activate(); - - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.getTexUnit(detail1)->disable(); + gGL.getTexUnit(detail1)->activate(); //---------------------------------------------------------------------------- // Restore Texture Unit 0 defaults gGL.getTexUnit(detail0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(0)->activate(); - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.getTexUnit(detail0)->enable(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(detail0)->activate(); } void LLDrawPoolTerrain::hilightParcelOwners(bool deferred) { - if (mVertexShaderLevel > 1) + if (mShaderLevel > 1) { //use fullbright shader for highlighting LLGLSLShader* old_shader = sShader; sShader->unbind(); diff --git a/indra/newview/lldrawpoolterrain.h b/indra/newview/lldrawpoolterrain.h index 484820491a..5b4558020d 100644 --- a/indra/newview/lldrawpoolterrain.h +++ b/indra/newview/lldrawpoolterrain.h @@ -49,8 +49,6 @@ public: LLDrawPoolTerrain(LLViewerTexture *texturep); virtual ~LLDrawPoolTerrain(); - /*virtual*/ LLDrawPool *instancePool(); - /*virtual*/ S32 getNumDeferredPasses() { return 1; } /*virtual*/ void beginDeferredPass(S32 pass); /*virtual*/ void endDeferredPass(S32 pass); @@ -78,6 +76,8 @@ public: static F32 sDetailScale; // meters per texture protected: + void boostTerrainDetailTextures(); + void renderSimple(); void renderOwnership(); diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp index b1f40781f7..0d5195bdbf 100644 --- a/indra/newview/lldrawpooltree.cpp +++ b/indra/newview/lldrawpooltree.cpp @@ -38,6 +38,7 @@ #include "llrender.h" #include "llviewercontrol.h" #include "llviewerregion.h" +#include "llenvironment.h" S32 LLDrawPoolTree::sDiffTex = 0; static LLGLSLShader* shader = NULL; @@ -50,14 +51,9 @@ LLDrawPoolTree::LLDrawPoolTree(LLViewerTexture *texturep) : mTexturep->setAddressMode(LLTexUnit::TAM_WRAP); } -LLDrawPool *LLDrawPoolTree::instancePool() -{ - return new LLDrawPoolTree(mTexturep); -} - void LLDrawPoolTree::prerender() { - mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); + mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); } void LLDrawPoolTree::beginRenderPass(S32 pass) @@ -96,7 +92,6 @@ void LLDrawPoolTree::render(S32 pass) } LLGLState test(GL_ALPHA_TEST, LLGLSLShader::sNoFixedFunction ? 0 : 1); - LLOverrideFaceColor color(this, 1.f, 1.f, 1.f, 1.f); gGL.getTexUnit(sDiffTex)->bind(mTexturep); @@ -138,7 +133,7 @@ void LLDrawPoolTree::endRenderPass(S32 pass) shader->unbind(); } - if (mVertexShaderLevel <= 0) + if (mShaderLevel <= 0) { gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); } @@ -178,7 +173,10 @@ void LLDrawPoolTree::beginShadowPass(S32 pass) glPolygonOffset(gSavedSettings.getF32("RenderDeferredTreeShadowOffset"), gSavedSettings.getF32("RenderDeferredTreeShadowBias")); + LLEnvironment& environment = LLEnvironment::instance(); + gDeferredTreeShadowProgram.bind(); + gDeferredTreeShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); gDeferredTreeShadowProgram.setMinimumAlpha(0.5f); } diff --git a/indra/newview/lldrawpooltree.h b/indra/newview/lldrawpooltree.h index e7e25453cf..13f9ec8dce 100644 --- a/indra/newview/lldrawpooltree.h +++ b/indra/newview/lldrawpooltree.h @@ -37,15 +37,14 @@ public: { VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | - LLVertexBuffer::MAP_TEXCOORD0 + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_TEXCOORD0 }; virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } LLDrawPoolTree(LLViewerTexture *texturep); - /*virtual*/ LLDrawPool *instancePool(); - /*virtual*/ void prerender(); /*virtual*/ S32 getNumDeferredPasses() { return 1; } diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index df06ad31e6..aa426cd785 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -46,10 +46,9 @@ #include "llworld.h" #include "pipeline.h" #include "llviewershadermgr.h" -#include "llwaterparammanager.h" - -const LLUUID TRANSPARENT_WATER_TEXTURE("2bfd3884-7e27-69b9-ba3a-3e673f680004"); -const LLUUID OPAQUE_WATER_TEXTURE("43c32285-d658-1793-c123-bf86315de055"); +#include "llenvironment.h" +#include "llsettingssky.h" +#include "llsettingswater.h" static float sTime; @@ -58,61 +57,56 @@ 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); F32 LLDrawPoolWater::sWaterFogEnd = 0.f; -LLVector3 LLDrawPoolWater::sLightDir; - -LLDrawPoolWater::LLDrawPoolWater() : - LLFacePool(POOL_WATER) +LLDrawPoolWater::LLDrawPoolWater() : LLFacePool(POOL_WATER) { - 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, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); - gGL.getTexUnit(0)->bind(mHBTex[1]); - mHBTex[1]->setAddressMode(LLTexUnit::TAM_CLAMP); - - - mWaterImagep = LLViewerTextureManager::getFetchedTexture(TRANSPARENT_WATER_TEXTURE); - llassert(mWaterImagep); - mWaterImagep->setNoDelete(); - mOpaqueWaterImagep = LLViewerTextureManager::getFetchedTexture(OPAQUE_WATER_TEXTURE); - llassert(mOpaqueWaterImagep); - mWaterNormp = LLViewerTextureManager::getFetchedTexture(DEFAULT_WATER_NORMAL); - mWaterNormp->setNoDelete(); - - restoreGL(); } LLDrawPoolWater::~LLDrawPoolWater() { } -//static -void LLDrawPoolWater::restoreGL() +void LLDrawPoolWater::setTransparentTextures(const LLUUID& transparentTextureId, const LLUUID& nextTransparentTextureId) { - + LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater(); + mWaterImagep[0] = LLViewerTextureManager::getFetchedTexture(!transparentTextureId.isNull() ? transparentTextureId : pwater->GetDefaultTransparentTextureAssetId()); + mWaterImagep[1] = LLViewerTextureManager::getFetchedTexture(!nextTransparentTextureId.isNull() ? nextTransparentTextureId : (!transparentTextureId.isNull() ? transparentTextureId : pwater->GetDefaultTransparentTextureAssetId())); + mWaterImagep[0]->addTextureStats(1024.f*1024.f); + mWaterImagep[1]->addTextureStats(1024.f*1024.f); } -LLDrawPool *LLDrawPoolWater::instancePool() +void LLDrawPoolWater::setOpaqueTexture(const LLUUID& opaqueTextureId) { - LL_ERRS() << "Should never be calling instancePool on a water pool!" << LL_ENDL; - return NULL; + LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater(); + mOpaqueWaterImagep = LLViewerTextureManager::getFetchedTexture(opaqueTextureId); + mOpaqueWaterImagep->addTextureStats(1024.f*1024.f); } - -void LLDrawPoolWater::prerender() +void LLDrawPoolWater::setNormalMaps(const LLUUID& normalMapId, const LLUUID& nextNormalMapId) { - mVertexShaderLevel = (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps) ? - LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WATER) : 0; + LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater(); + mWaterNormp[0] = LLViewerTextureManager::getFetchedTexture(!normalMapId.isNull() ? normalMapId : pwater->GetDefaultWaterNormalAssetId()); + mWaterNormp[1] = LLViewerTextureManager::getFetchedTexture(!nextNormalMapId.isNull() ? nextNormalMapId : (!normalMapId.isNull() ? normalMapId : pwater->GetDefaultWaterNormalAssetId())); + mWaterNormp[0]->addTextureStats(1024.f*1024.f); + mWaterNormp[1]->addTextureStats(1024.f*1024.f); +} - // got rid of modulation by light color since it got a little too - // green at sunset and sl-57047 (underwater turns black at 8:00) - sWaterFogColor = LLWaterParamManager::instance().getFogColor(); - sWaterFogColor.mV[3] = 0; +//static +void LLDrawPoolWater::restoreGL() +{ + /*LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater(); + if (pwater) + { + setTransparentTextures(pwater->getTransparentTextureID(), pwater->getNextTransparentTextureID()); + setOpaqueTexture(pwater->GetDefaultOpaqueTextureAssetId()); + setNormalMaps(pwater->getNormalMapID(), pwater->getNextNormalMapID()); + }*/ +} +void LLDrawPoolWater::prerender() +{ + mShaderLevel = (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps) ? LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_WATER) : 0; } S32 LLDrawPoolWater::getNumPasses() @@ -169,7 +163,7 @@ void LLDrawPoolWater::render(S32 pass) std::sort(mDrawFace.begin(), mDrawFace.end(), LLFace::CompareDistanceGreater()); // See if we are rendering water as opaque or not - if (!gSavedSettings.getBOOL("RenderTransparentWater")) + if (!LLPipeline::sRenderTransparentWater) { // render water for low end hardware renderOpaqueLegacyWater(); @@ -178,7 +172,7 @@ void LLDrawPoolWater::render(S32 pass) LLGLEnable blend(GL_BLEND); - if ((mVertexShaderLevel > 0) && !sSkipScreenCopy) + if ((mShaderLevel > 0) && !sSkipScreenCopy) { shade(); return; @@ -203,10 +197,13 @@ void LLDrawPoolWater::render(S32 pass) LLGLDisable cullFace(GL_CULL_FACE); // Set up second pass first - mWaterImagep->addTextureStats(1024.f*1024.f); gGL.getTexUnit(1)->activate(); gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(1)->bind(mWaterImagep) ; + gGL.getTexUnit(1)->bind(mWaterImagep[0]) ; + + gGL.getTexUnit(2)->activate(); + gGL.getTexUnit(2)->enable(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(2)->bind(mWaterImagep[1]) ; LLVector3 camera_up = LLViewerCamera::getInstance()->getUpAxis(); F32 up_dot = camera_up * LLVector3::z_axis; @@ -263,6 +260,14 @@ void LLDrawPoolWater::render(S32 pass) gGL.getTexUnit(1)->activate(); gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE); gGL.getTexUnit(1)->disable(); + + glDisable(GL_TEXTURE_GEN_S); //texture unit 1 + glDisable(GL_TEXTURE_GEN_T); //texture unit 1 + + gGL.getTexUnit(2)->activate(); + gGL.getTexUnit(2)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(2)->disable(); + glDisable(GL_TEXTURE_GEN_S); //texture unit 1 glDisable(GL_TEXTURE_GEN_T); //texture unit 1 @@ -362,8 +367,6 @@ void LLDrawPoolWater::renderOpaqueLegacyWater() gPipeline.disableLights(); - mOpaqueWaterImagep->addTextureStats(1024.f*1024.f); - // Activate the texture binding and bind one // texture since all images will have the same texture gGL.getTexUnit(0)->activate(); @@ -461,97 +464,39 @@ void LLDrawPoolWater::renderReflection(LLFace* face) LLGLSNoFog noFog; - gGL.getTexUnit(0)->bind(mHBTex[dr]); + gGL.getTexUnit(0)->bind((dr == 0) ? voskyp->getSunTex() : voskyp->getMoonTex()); LLOverrideFaceColor override(this, LLColor4(face->getFaceColor().mV)); face->renderIndexed(); } -void LLDrawPoolWater::shade() +void LLDrawPoolWater::shade2(bool edge, LLGLSLShader* shader, const LLColor3& light_diffuse, const LLVector3& light_dir, F32 light_exp) { - if (!deferred_render) - { - gGL.setColorMask(true, true); - } - - LLVOSky *voskyp = gSky.mVOSkyp; + F32 water_height = LLEnvironment::instance().getWaterHeight(); + F32 camera_height = LLViewerCamera::getInstance()->getOrigin().mV[2]; + F32 eyedepth = camera_height - water_height; + bool underwater = eyedepth <= 0.0f; - if(voskyp == NULL) - { - return; - } + LLEnvironment& environment = LLEnvironment::instance(); + LLSettingsWater::ptr_t pwater = environment.getCurrentWater(); + LLSettingsSky::ptr_t psky = environment.getCurrentSky(); - LLGLDisable blend(GL_BLEND); + shader->bind(); - LLColor3 light_diffuse(0,0,0); - F32 light_exp = 0.0f; - LLVector3 light_dir; - LLColor3 light_color; - - if (gSky.getSunDirection().mV[2] > LLSky::NIGHTTIME_ELEVATION_COS) - { - light_dir = gSky.getSunDirection(); - light_dir.normVec(); - light_color = gSky.getSunDiffuseColor(); - if(gSky.mVOSkyp) { - light_diffuse = gSky.mVOSkyp->getSun().getColorCached(); - light_diffuse.normVec(); - } - light_exp = light_dir * LLVector3(light_dir.mV[0], light_dir.mV[1], 0); - light_diffuse *= light_exp + 0.25f; - } - else - { - light_dir = gSky.getMoonDirection(); - light_dir.normVec(); - light_color = gSky.getMoonDiffuseColor(); - light_diffuse = gSky.mVOSkyp->getMoon().getColorCached(); - light_diffuse.normVec(); - light_diffuse *= 0.5f; - light_exp = light_dir * LLVector3(light_dir.mV[0], light_dir.mV[1], 0); - } - - light_exp *= light_exp; - light_exp *= light_exp; - light_exp *= light_exp; - light_exp *= light_exp; - light_exp *= 256.f; - light_exp = light_exp > 32.f ? light_exp : 32.f; - - LLGLSLShader* shader; - - F32 eyedepth = LLViewerCamera::getInstance()->getOrigin().mV[2] - gAgent.getRegion()->getWaterHeight(); - - if (eyedepth < 0.f && LLPipeline::sWaterReflections) - { +// bind textures for water rendering if (deferred_render) { - shader = &gDeferredUnderWaterProgram; - } - else - { - shader = &gUnderWaterProgram; - } - } - else if (deferred_render) - { - shader = &gDeferredWaterProgram; - } - else - { - shader = &gWaterProgram; + if (shader->getUniformLocation(LLShaderMgr::DEFERRED_NORM_MATRIX) >= 0) + { + glh::matrix4f norm_mat = get_current_modelview().inverse().transpose(); + shader->uniformMatrix4fv(LLShaderMgr::DEFERRED_NORM_MATRIX, 1, FALSE, norm_mat.m); + } } - if (deferred_render) - { - gPipeline.bindDeferredShader(*shader); - } - else - { - shader->bind(); - } + LLColor4 specular(psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor()); + shader->uniform4fv(LLShaderMgr::SPECULAR_COLOR, 1, specular.mV); - sTime = (F32)LLFrameTimer::getElapsedSeconds()*0.5f; + sTime = (F32)LLFrameTimer::getElapsedSeconds() * 0.5f; S32 reftex = shader->enableTexture(LLShaderMgr::WATER_REFTEX); @@ -563,62 +508,65 @@ void LLDrawPoolWater::shade() } //bind normal map - S32 bumpTex = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP); - - LLWaterParamManager * param_mgr = &LLWaterParamManager::instance(); + S32 bumpTex = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP); + S32 bumpTex2 = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP2); - // change mWaterNormp if needed - if (mWaterNormp->getID() != param_mgr->getNormalMapID()) - { - mWaterNormp = LLViewerTextureManager::getFetchedTexture(param_mgr->getNormalMapID()); - } + LLViewerTexture* tex_a = mWaterNormp[0]; + LLViewerTexture* tex_b = mWaterNormp[1]; - mWaterNormp->addTextureStats(1024.f*1024.f); - gGL.getTexUnit(bumpTex)->bind(mWaterNormp) ; - if (gSavedSettings.getBOOL("RenderWaterMipNormal")) - { - mWaterNormp->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); - } - else - { - mWaterNormp->setFilteringOption(LLTexUnit::TFO_POINT); - } + F32 blend_factor = LLEnvironment::instance().getCurrentWater()->getBlendFactor(); - S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX); - - if (screentex > -1) - { - shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV); - shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, - param_mgr->getFogDensity()); - gPipeline.mWaterDis.bindTexture(0, screentex); - } - - stop_glerror(); - - gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis); - - if (mVertexShaderLevel == 1) - { - sWaterFogColor.mV[3] = param_mgr->mDensitySliderValue; - shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV); - } + gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE); + if (tex_a && (!tex_b || (tex_a == tex_b))) + { + gGL.getTexUnit(bumpTex)->bind(tex_a); + blend_factor = 0; // only one tex provided, no blending + } + else if (tex_b && !tex_a) + { + gGL.getTexUnit(bumpTex)->bind(tex_b); + blend_factor = 0; // only one tex provided, no blending + } + else if (tex_b != tex_a) + { + gGL.getTexUnit(bumpTex)->bind(tex_a); + gGL.getTexUnit(bumpTex2)->bind(tex_b); + } + + // bind reflection texture from RenderTarget + S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX); F32 screenRes[] = { 1.f/gGLViewport[2], 1.f/gGLViewport[3] }; - shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes); - stop_glerror(); - + S32 diffTex = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP); stop_glerror(); - - light_dir.normVec(); - sLightDir = light_dir; - - light_diffuse *= 6.f; + +// set uniforms for water rendering + shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes); + shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor); + + LLColor4 fog_color(pwater->getWaterFogColor(), 0.0f); + F32 fog_density = pwater->getModifiedWaterFogDensity(underwater); + + if (screentex > -1) + { + shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, fog_density); + gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis); + } + + if (mShaderLevel == 1) + { + //F32 fog_density_slider_value = param_mgr->mDensitySliderValue; + //sWaterFogColor.mV[3] = fog_density_slider_value; + fog_color.mV[VW] = log(fog_density) / log(2); + } + + shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV); //shader->uniformMatrix4fv("inverse_ref", 1, GL_FALSE, (GLfloat*) gGLObliqueProjectionInverse.mMatrix); shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, eyedepth); @@ -626,76 +574,100 @@ void LLDrawPoolWater::shade() 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); + if (LLEnvironment::instance().isCloudScrollPaused()) + { + static const std::array<F32, 2> zerowave{ {0.0f, 0.0f} }; + + shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, zerowave.data()); + shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, zerowave.data()); + } + else + { + shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV); + shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->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()); + shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV); + shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale()); + shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset()); + shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, pwater->getBlurMultiplier()); - F32 sunAngle = llmax(0.f, light_dir.mV[2]); + F32 sunAngle = llmax(0.f, light_dir.mV[1]); F32 scaledAngle = 1.f - sunAngle; + shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); 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); + shader->uniform1i(LLShaderMgr::WATER_EDGE_FACTOR, edge ? 1 : 0); + + LLVector4 rotated_light_direction = LLEnvironment::instance().getRotatedLightNorm(); + shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV); + shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV); - LLColor4 water_color; - LLVector3 camera_up = LLViewerCamera::getInstance()->getUpAxis(); - F32 up_dot = camera_up * LLVector3::z_axis; if (LLViewerCamera::getInstance()->cameraUnderWater()) { - water_color.setVec(1.f, 1.f, 1.f, 0.4f); - shader->uniform1f(LLShaderMgr::WATER_REFSCALE, param_mgr->getScaleBelow()); + shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow()); } else { - water_color.setVec(1.f, 1.f, 1.f, 0.5f*(1.f + up_dot)); - shader->uniform1f(LLShaderMgr::WATER_REFSCALE, param_mgr->getScaleAbove()); + shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove()); } - if (water_color.mV[3] > 0.9f) - { - water_color.mV[3] = 0.9f; - } - - { - LLGLEnable depth_clamp(gGLManager.mHasDepthClamp ? GL_DEPTH_CLAMP : 0); + { LLGLDisable cullface(GL_CULL_FACE); - for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); - iter != mDrawFace.end(); iter++) - { - LLFace *face = *iter; - if (voskyp->isReflFace(face)) - { - continue; - } + if (edge) + { + for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++) + { + LLFace *face = *iter; + if (face) + { + LLVOWater* water = (LLVOWater*) face->getViewerObject(); + gGL.getTexUnit(diffTex)->bind(face->getTexture()); + + if (water) + { + bool edge_patch = water->getIsEdgePatch(); + if (edge_patch) + { + //sNeedsReflectionUpdate = TRUE; + face->renderIndexed(); + } + } + } + } + } + else + { + for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++) + { + LLFace *face = *iter; + if (face) + { + LLVOWater* water = (LLVOWater*) face->getViewerObject(); + gGL.getTexUnit(diffTex)->bind(face->getTexture()); + + if (water) + { + bool edge_patch = water->getIsEdgePatch(); + if (!edge_patch) + { + sNeedsReflectionUpdate = TRUE; + sNeedsDistortionUpdate = TRUE; + face->renderIndexed(); + } + } + } + } + } + } - LLVOWater* water = (LLVOWater*) face->getViewerObject(); - gGL.getTexUnit(diffTex)->bind(face->getTexture()); + gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE); - sNeedsReflectionUpdate = TRUE; - - if (water->getUseTexture() || !water->getIsEdgePatch()) - { - sNeedsDistortionUpdate = TRUE; - face->renderIndexed(); - } - else if (gGLManager.mHasDepthClamp || deferred_render) - { - face->renderIndexed(); - } - else - { - LLGLSquashToFarClip far_clip(glh_get_current_projection()); - face->renderIndexed(); - } - } - } - shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); shader->disableTexture(LLShaderMgr::WATER_SCREENTEX); shader->disableTexture(LLShaderMgr::BUMP_MAP); @@ -703,14 +675,117 @@ void LLDrawPoolWater::shade() shader->disableTexture(LLShaderMgr::WATER_REFTEX); shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH); - if (deferred_render) + shader->unbind(); +} + +void LLDrawPoolWater::shade() +{ + if (!deferred_render) { - gPipeline.unbindDeferredShader(*shader); + gGL.setColorMask(true, true); } - else + + LLVOSky *voskyp = gSky.mVOSkyp; + + if(voskyp == NULL) + { + return; + } + + LLGLDisable blend(GL_BLEND); + + LLColor3 light_diffuse(0,0,0); + F32 light_exp = 0.0f; + LLVector3 light_dir; + + LLEnvironment& environment = LLEnvironment::instance(); + LLSettingsWater::ptr_t pwater = environment.getCurrentWater(); + LLSettingsSky::ptr_t psky = environment.getCurrentSky(); + + light_dir = environment.getLightDirection(); + light_dir.normalize(); + + bool sun_up = environment.getIsSunUp(); + bool moon_up = environment.getIsMoonUp(); + + if (sun_up) + { + light_diffuse += voskyp->getSun().getColorCached(); + } + // moonlight is several orders of magnitude less bright than sunlight, + // so only use this color when the moon alone is showing + else if (moon_up) + { + light_diffuse += psky->getMoonDiffuse(); + } + + light_exp = light_dir * LLVector3(light_dir.mV[0], light_dir.mV[1], 0.f); + + light_diffuse.normalize(); + light_diffuse *= (light_exp + 0.25f); + + light_exp *= light_exp; + light_exp *= light_exp; + light_exp *= light_exp; + light_exp *= light_exp; + light_exp *= 256.f; + light_exp = light_exp > 32.f ? light_exp : 32.f; + + light_diffuse *= 6.f; + + LLGLSLShader* shader = nullptr; + LLGLSLShader* edge_shader = nullptr; + + F32 eyedepth = LLViewerCamera::getInstance()->getOrigin().mV[2] - LLEnvironment::instance().getWaterHeight(); + + if (eyedepth < 0.f && LLPipeline::sWaterReflections) { - shader->unbind(); + if (deferred_render) + { + shader = &gDeferredUnderWaterProgram; + } + else + { + shader = &gUnderWaterProgram; + } } + else if (deferred_render) + { + shader = &gDeferredWaterProgram; + edge_shader = nullptr; + } + else + { + shader = &gWaterProgram; + edge_shader = &gWaterEdgeProgram; + } + + if (mWaterNormp[0]) + { + if (gSavedSettings.getBOOL("RenderWaterMipNormal")) + { + mWaterNormp[0]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); + } + else + { + mWaterNormp[0]->setFilteringOption(LLTexUnit::TFO_POINT); + } + } + + if (mWaterNormp[1]) + { + if (gSavedSettings.getBOOL("RenderWaterMipNormal")) + { + mWaterNormp[1]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); + } + else + { + mWaterNormp[1]->setFilteringOption(LLTexUnit::TFO_POINT); + } + } + + shade2(false, shader, light_diffuse, light_dir, light_exp); + shade2(true, edge_shader ? edge_shader : shader, light_diffuse, light_dir, light_exp); gGL.getTexUnit(0)->activate(); gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); diff --git a/indra/newview/lldrawpoolwater.h b/indra/newview/lldrawpoolwater.h index aeeba179d6..a5d163e0d7 100644 --- a/indra/newview/lldrawpoolwater.h +++ b/indra/newview/lldrawpoolwater.h @@ -33,22 +33,20 @@ class LLFace; class LLHeavenBody; class LLWaterSurface; +class LLGLSLShader; class LLDrawPoolWater: public LLFacePool { protected: - LLPointer<LLViewerTexture> mHBTex[2]; - LLPointer<LLViewerTexture> mWaterImagep; - LLPointer<LLViewerTexture> mOpaqueWaterImagep; - LLPointer<LLViewerTexture> mWaterNormp; + LLPointer<LLViewerTexture> mWaterImagep[2]; + LLPointer<LLViewerTexture> mWaterNormp[2]; + + LLPointer<LLViewerTexture> mOpaqueWaterImagep; public: static BOOL sSkipScreenCopy; static BOOL sNeedsReflectionUpdate; static BOOL sNeedsDistortionUpdate; - static LLVector3 sLightDir; - - static LLColor4 sWaterFogColor; static F32 sWaterFogEnd; enum @@ -63,7 +61,6 @@ public: LLDrawPoolWater(); /*virtual*/ ~LLDrawPoolWater(); - /*virtual*/ LLDrawPool *instancePool(); static void restoreGL(); /*virtual*/ S32 getNumPostDeferredPasses() { return 0; } //getNumPasses(); } @@ -82,6 +79,11 @@ public: void renderReflection(LLFace* face); void shade(); + void shade2(bool edge, LLGLSLShader* shader, const LLColor3& light_diffuse, const LLVector3& light_dir, F32 light_exp); + + void setTransparentTextures(const LLUUID& transparentTextureId, const LLUUID& nextTransparentTextureId); + void setOpaqueTexture(const LLUUID& opaqueTextureId); + void setNormalMaps(const LLUUID& normalMapId, const LLUUID& nextNormalMapId); protected: void renderOpaqueLegacyWater(); diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp index 309f535c39..0c3d8f3098 100644 --- a/indra/newview/lldrawpoolwlsky.cpp +++ b/indra/newview/lldrawpoolwlsky.cpp @@ -29,66 +29,39 @@ #include "lldrawpoolwlsky.h" #include "llerror.h" -#include "llgl.h" -#include "pipeline.h" -#include "llviewercamera.h" +#include "llface.h" #include "llimage.h" -#include "llwlparammanager.h" -#include "llviewershadermgr.h" +#include "llrender.h" +#include "llatmosphere.h" +#include "llenvironment.h" #include "llglslshader.h" +#include "llgl.h" + +#include "llviewerregion.h" +#include "llviewershadermgr.h" +#include "llviewercamera.h" +#include "pipeline.h" #include "llsky.h" #include "llvowlsky.h" -#include "llviewerregion.h" -#include "llface.h" -#include "llrender.h" - -LLPointer<LLViewerTexture> LLDrawPoolWLSky::sCloudNoiseTexture = NULL; +#include "llsettingsvo.h" -LLPointer<LLImageRaw> LLDrawPoolWLSky::sCloudNoiseRawImage = NULL; +static LLStaticHashedString sCamPosLocal("camPosLocal"); +static LLStaticHashedString sCustomAlpha("custom_alpha"); static LLGLSLShader* cloud_shader = NULL; -static LLGLSLShader* sky_shader = NULL; +static LLGLSLShader* sky_shader = NULL; +static LLGLSLShader* sun_shader = NULL; +static LLGLSLShader* moon_shader = NULL; +static float sStarTime; LLDrawPoolWLSky::LLDrawPoolWLSky(void) : LLDrawPool(POOL_WL_SKY) { - const std::string cloudNoiseFilename(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", "clouds2.tga")); - LL_INFOS() << "loading WindLight cloud noise from " << cloudNoiseFilename << LL_ENDL; - - LLPointer<LLImageFormatted> cloudNoiseFile(LLImageFormatted::createFromExtension(cloudNoiseFilename)); - - if(cloudNoiseFile.isNull()) { - LL_ERRS() << "Error: Failed to load cloud noise image " << cloudNoiseFilename << LL_ENDL; - } - - if(cloudNoiseFile->load(cloudNoiseFilename)) - { - sCloudNoiseRawImage = new LLImageRaw(); - - if(cloudNoiseFile->decode(sCloudNoiseRawImage, 0.0f)) - { - //debug use - 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); - } - else - { - sCloudNoiseRawImage = NULL ; - } - } - - LLWLParamManager::getInstance()->propagateParameters(); } LLDrawPoolWLSky::~LLDrawPoolWLSky() { - //LL_INFOS() << "destructing wlsky draw pool." << LL_ENDL; - sCloudNoiseTexture = NULL; - sCloudNoiseRawImage = NULL; } LLViewerTexture *LLDrawPoolWLSky::getDebugTexture() @@ -107,39 +80,70 @@ void LLDrawPoolWLSky::beginRenderPass( S32 pass ) LLPipeline::sUnderWaterRender ? &gObjectFullbrightNoColorWaterProgram : &gWLCloudProgram; + + sun_shader = + LLPipeline::sUnderWaterRender ? + &gObjectFullbrightNoColorWaterProgram : + &gWLSunProgram; + + moon_shader = + LLPipeline::sUnderWaterRender ? + &gObjectFullbrightNoColorWaterProgram : + &gWLMoonProgram; } void LLDrawPoolWLSky::endRenderPass( S32 pass ) { + sky_shader = nullptr; + cloud_shader = nullptr; + sun_shader = nullptr; + moon_shader = nullptr; } void LLDrawPoolWLSky::beginDeferredPass(S32 pass) { sky_shader = &gDeferredWLSkyProgram; cloud_shader = &gDeferredWLCloudProgram; + + sun_shader = + LLPipeline::sUnderWaterRender ? + &gObjectFullbrightNoColorWaterProgram : + &gDeferredWLSunProgram; + + moon_shader = + LLPipeline::sUnderWaterRender ? + &gObjectFullbrightNoColorWaterProgram : + &gDeferredWLMoonProgram; } void LLDrawPoolWLSky::endDeferredPass(S32 pass) { - + sky_shader = nullptr; + cloud_shader = nullptr; + sun_shader = nullptr; + moon_shader = nullptr; } -void LLDrawPoolWLSky::renderDome(F32 camHeightLocal, LLGLSLShader * shader) const +void LLDrawPoolWLSky::renderFsSky(const LLVector3& camPosLocal, F32 camHeightLocal, LLGLSLShader * shader) const { - LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin(); + gSky.mVOWLSkyp->drawFsSky(); +} - llassert_always(NULL != shader); +void LLDrawPoolWLSky::renderDome(const LLVector3& camPosLocal, F32 camHeightLocal, LLGLSLShader * shader) const +{ + llassert_always(NULL != shader); + gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.pushMatrix(); //chop off translation - if (LLPipeline::sReflectionRender && origin.mV[2] > 256.f) + if (LLPipeline::sReflectionRender && camPosLocal.mV[2] > 256.f) { - gGL.translatef(origin.mV[0], origin.mV[1], 256.f-origin.mV[2]*0.5f); + gGL.translatef(camPosLocal.mV[0], camPosLocal.mV[1], 256.f-camPosLocal.mV[2]*0.5f); } else { - gGL.translatef(origin.mV[0], origin.mV[1], origin.mV[2]); + gGL.translatef(camPosLocal.mV[0], camPosLocal.mV[1], camPosLocal.mV[2]); } @@ -151,64 +155,122 @@ void LLDrawPoolWLSky::renderDome(F32 camHeightLocal, LLGLSLShader * shader) cons gGL.translatef(0.f,-camHeightLocal, 0.f); - // Draw WL Sky - static LLStaticHashedString sCamPosLocal("camPosLocal"); + // Draw WL Sky shader->uniform3f(sCamPosLocal, 0.f, camHeightLocal, 0.f); - gSky.mVOWLSkyp->drawDome(); + gSky.mVOWLSkyp->drawDome(); + gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.popMatrix(); } -void LLDrawPoolWLSky::renderSkyHaze(F32 camHeightLocal) const +void LLDrawPoolWLSky::renderSkyHazeDeferred(const LLVector3& camPosLocal, F32 camHeightLocal) const { + LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin(); + if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY)) { - LLGLDisable blend(GL_BLEND); + LLGLSPipelineDepthTestSkyBox sky(true, true); - sky_shader->bind(); + sky_shader->bind(); - /// Render the skydome - renderDome(camHeightLocal, sky_shader); + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + + LLViewerTexture* rainbow_tex = gSky.mVOSkyp->getRainbowTex(); + LLViewerTexture* halo_tex = gSky.mVOSkyp->getHaloTex(); + + sky_shader->bindTexture(LLShaderMgr::RAINBOW_MAP, rainbow_tex); + sky_shader->bindTexture(LLShaderMgr::HALO_MAP, halo_tex); + + ((LLSettingsVOSky*)psky.get())->updateShader(sky_shader); + + F32 moisture_level = (float)psky->getSkyMoistureLevel(); + F32 droplet_radius = (float)psky->getSkyDropletRadius(); + F32 ice_level = (float)psky->getSkyIceLevel(); + + // hobble halos and rainbows when there's no light source to generate them + if (!psky->getIsSunUp() && !psky->getIsMoonUp()) + { + moisture_level = 0.0f; + ice_level = 0.0f; + } + + sky_shader->uniform1f(LLShaderMgr::MOISTURE_LEVEL, moisture_level); + sky_shader->uniform1f(LLShaderMgr::DROPLET_RADIUS, droplet_radius); + sky_shader->uniform1f(LLShaderMgr::ICE_LEVEL, ice_level); + + sky_shader->uniform1f(LLShaderMgr::SUN_MOON_GLOW_FACTOR, psky->getSunMoonGlowFactor()); + + sky_shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, psky->getIsSunUp() ? 1 : 0); + + /// Render the skydome + renderDome(origin, camHeightLocal, sky_shader); sky_shader->unbind(); - } + } +} + +void LLDrawPoolWLSky::renderSkyHaze(const LLVector3& camPosLocal, F32 camHeightLocal) const +{ + LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin(); + + if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY)) + { + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + LLGLSPipelineDepthTestSkyBox sky(true, false); + sky_shader->bind(); + sky_shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, 1); + sky_shader->uniform1f(LLShaderMgr::SUN_MOON_GLOW_FACTOR, psky->getSunMoonGlowFactor()); + renderDome(origin, camHeightLocal, sky_shader); + sky_shader->unbind(); + } } -void LLDrawPoolWLSky::renderStars(void) const +void LLDrawPoolWLSky::renderStars(const LLVector3& camPosLocal) const { - LLGLSPipelineSkyBox gls_sky; - LLGLEnable blend(GL_BLEND); - gGL.setSceneBlendType(LLRender::BT_ALPHA); + LLGLSPipelineBlendSkyBox gls_skybox(true, false); // *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(); - // *NOTE: we divide by two here and GL_ALPHA_SCALE by two below to avoid // clamping and allow the star_alpha param to brighten the stars. - bool error; LLColor4 star_alpha(LLColor4::black); - star_alpha.mV[3] = LLWLParamManager::getInstance()->mCurParams.getFloat("star_brightness", error) / 2.f; - // If start_brightness is not set, exit - if( error ) + star_alpha.mV[3] = LLEnvironment::instance().getCurrentSky()->getStarBrightness() / 512.f; + + // If star brightness is not set, exit + if( star_alpha.mV[3] < 0.001 ) { - LL_WARNS() << "star_brightness missing in mCurParams" << LL_ENDL; + LL_DEBUGS("SKY") << "star_brightness below threshold." << LL_ENDL; return; } - gGL.getTexUnit(0)->bind(gSky.mVOSkyp->getBloomTex()); + LLViewerTexture* tex_a = gSky.mVOSkyp->getBloomTex(); + LLViewerTexture* tex_b = gSky.mVOSkyp->getBloomTexNext(); + + if (tex_a && (!tex_b || (tex_a == tex_b))) + { + // Bind current and next sun textures + gGL.getTexUnit(0)->bind(tex_a); + } + else if (tex_b && !tex_a) + { + gGL.getTexUnit(0)->bind(tex_b); + } + else if (tex_b != tex_a) + { + gGL.getTexUnit(0)->bind(tex_a); + } gGL.pushMatrix(); + gGL.translatef(camPosLocal.mV[0], camPosLocal.mV[1], camPosLocal.mV[2]); gGL.rotatef(gFrameTimeSeconds*0.01f, 0.f, 0.f, 1.f); if (LLGLSLShader::sNoFixedFunction) { gCustomAlphaProgram.bind(); - static LLStaticHashedString sCustomAlpha("custom_alpha"); gCustomAlphaProgram.uniform1f(sCustomAlpha, star_alpha.mV[3]); } else @@ -220,6 +282,8 @@ void LLDrawPoolWLSky::renderStars(void) const gSky.mVOWLSkyp->drawStars(); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.popMatrix(); if (LLGLSLShader::sNoFixedFunction) @@ -233,123 +297,299 @@ void LLDrawPoolWLSky::renderStars(void) const } } -void LLDrawPoolWLSky::renderSkyClouds(F32 camHeightLocal) const +void LLDrawPoolWLSky::renderStarsDeferred(const LLVector3& camPosLocal) const { - if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS) && sCloudNoiseTexture.notNull()) - { - LLGLEnable blend(GL_BLEND); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - - gGL.getTexUnit(0)->bind(sCloudNoiseTexture); + LLGLSPipelineBlendSkyBox gls_sky(true, false); - cloud_shader->bind(); + gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); - /// Render the skydome - renderDome(camHeightLocal, cloud_shader); + F32 star_alpha = LLEnvironment::instance().getCurrentSky()->getStarBrightness() / 500.0f; - cloud_shader->unbind(); + // If start_brightness is not set, exit + if(star_alpha < 0.001f) + { + LL_DEBUGS("SKY") << "star_brightness below threshold." << LL_ENDL; + return; } -} -void LLDrawPoolWLSky::renderHeavenlyBodies() -{ - LLGLSPipelineSkyBox gls_skybox; - LLGLEnable blend_on(GL_BLEND); - gPipeline.disableLights(); + gDeferredStarProgram.bind(); -#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]; - if (gSky.mVOSkyp->getSun().getDraw() && face->getGeomCount()) - { - LLViewerTexture * tex = face->getTexture(); - gGL.getTexUnit(0)->bind(tex); - LLColor4 color(gSky.mVOSkyp->getSun().getInterpColor()); - LLFacePool::LLOverrideFaceColor color_override(this, color); - face->renderIndexed(); - } -#endif + LLViewerTexture* tex_a = gSky.mVOSkyp->getBloomTex(); + LLViewerTexture* tex_b = gSky.mVOSkyp->getBloomTexNext(); + + F32 blend_factor = LLEnvironment::instance().getCurrentSky()->getBlendFactor(); + + if (tex_a && (!tex_b || (tex_a == tex_b))) + { + // Bind current and next sun textures + gGL.getTexUnit(0)->bind(tex_a); + gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE); + blend_factor = 0; + } + else if (tex_b && !tex_a) + { + gGL.getTexUnit(0)->bind(tex_b); + gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE); + blend_factor = 0; + } + else if (tex_b != tex_a) + { + gGL.getTexUnit(0)->bind(tex_a); + gGL.getTexUnit(1)->bind(tex_b); + } + + gGL.pushMatrix(); + gGL.translatef(camPosLocal.mV[0], camPosLocal.mV[1], camPosLocal.mV[2]); + gDeferredStarProgram.uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor); + + if (LLPipeline::sReflectionRender) + { + star_alpha = 1.0f; + } + gDeferredStarProgram.uniform1f(sCustomAlpha, star_alpha); - LLFace * face = gSky.mVOSkyp->mFace[LLVOSky::FACE_MOON]; + sStarTime = (F32)LLFrameTimer::getElapsedSeconds() * 0.5f; - if (gSky.mVOSkyp->getMoon().getDraw() && face->getGeomCount()) + gDeferredStarProgram.uniform1f(LLShaderMgr::WATER_TIME, sStarTime); + + gSky.mVOWLSkyp->drawStars(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE); + + gDeferredStarProgram.unbind(); + + gGL.popMatrix(); +} + +void LLDrawPoolWLSky::renderSkyCloudsDeferred(const LLVector3& camPosLocal, F32 camHeightLocal, LLGLSLShader* cloudshader) const +{ + if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS) && gSky.mVOSkyp->getCloudNoiseTex()) { - // *NOTE: even though we already bound this texture above for the - // stars register combiners, we bind again here for defensive reasons, - // since LLImageGL::bind detects that it's a noop, and optimizes it out. - gGL.getTexUnit(0)->bind(face->getTexture()); - LLColor4 color(gSky.mVOSkyp->getMoon().getInterpColor()); - F32 a = gSky.mVOSkyp->getMoon().getDirection().mV[2]; - if (a > 0.f) - { - a = a*a*4.f; - } - - color.mV[3] = llclamp(a, 0.f, 1.f); - - if (gPipeline.canUseVertexShaders()) - { - gHighlightProgram.bind(); - } + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); - LLFacePool::LLOverrideFaceColor color_override(this, color); + LLGLSPipelineBlendSkyBox pipeline(true, true); - face->renderIndexed(); + cloudshader->bind(); + + LLPointer<LLViewerTexture> cloud_noise = gSky.mVOSkyp->getCloudNoiseTex(); + LLPointer<LLViewerTexture> cloud_noise_next = gSky.mVOSkyp->getCloudNoiseTexNext(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE); + + F32 cloud_variance = psky ? psky->getCloudVariance() : 0.0f; + F32 blend_factor = psky ? psky->getBlendFactor() : 0.0f; + + // if we even have sun disc textures to work with... + if (cloud_noise || cloud_noise_next) + { + if (cloud_noise && (!cloud_noise_next || (cloud_noise == cloud_noise_next))) + { + // Bind current and next sun textures + cloudshader->bindTexture(LLShaderMgr::CLOUD_NOISE_MAP, cloud_noise, LLTexUnit::TT_TEXTURE); + blend_factor = 0; + } + else if (cloud_noise_next && !cloud_noise) + { + cloudshader->bindTexture(LLShaderMgr::CLOUD_NOISE_MAP, cloud_noise_next, LLTexUnit::TT_TEXTURE); + blend_factor = 0; + } + else if (cloud_noise_next != cloud_noise) + { + cloudshader->bindTexture(LLShaderMgr::CLOUD_NOISE_MAP, cloud_noise, LLTexUnit::TT_TEXTURE); + cloudshader->bindTexture(LLShaderMgr::CLOUD_NOISE_MAP_NEXT, cloud_noise_next, LLTexUnit::TT_TEXTURE); + } + } + + cloudshader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor); + cloudshader->uniform1f(LLShaderMgr::CLOUD_VARIANCE, cloud_variance); + cloudshader->uniform1f(LLShaderMgr::SUN_MOON_GLOW_FACTOR, psky->getSunMoonGlowFactor()); + + ((LLSettingsVOSky*)psky.get())->updateShader(cloudshader); + + /// Render the skydome + renderDome(camPosLocal, camHeightLocal, cloudshader); + + cloudshader->unbind(); - if (gPipeline.canUseVertexShaders()) - { - gHighlightProgram.unbind(); - } + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE); } } -void LLDrawPoolWLSky::renderDeferred(S32 pass) +void LLDrawPoolWLSky::renderSkyClouds(const LLVector3& camPosLocal, F32 camHeightLocal, LLGLSLShader* cloudshader) const { - if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY)) + if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS) && gSky.mVOSkyp->getCloudNoiseTex()) { - return; - } - LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY); + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); - const F32 camHeightLocal = LLWLParamManager::getInstance()->getDomeOffset() * LLWLParamManager::getInstance()->getDomeRadius(); + LLGLSPipelineBlendSkyBox pipeline(true, true); + + cloudshader->bind(); + + LLPointer<LLViewerTexture> cloud_noise = gSky.mVOSkyp->getCloudNoiseTex(); + LLPointer<LLViewerTexture> cloud_noise_next = gSky.mVOSkyp->getCloudNoiseTexNext(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE); + + F32 cloud_variance = psky ? psky->getCloudVariance() : 0.0f; + F32 blend_factor = psky ? psky->getBlendFactor() : 0.0f; + + // if we even have sun disc textures to work with... + if (cloud_noise || cloud_noise_next) + { + if (cloud_noise && (!cloud_noise_next || (cloud_noise == cloud_noise_next))) + { + // Bind current and next sun textures + cloudshader->bindTexture(LLShaderMgr::CLOUD_NOISE_MAP, cloud_noise, LLTexUnit::TT_TEXTURE); + blend_factor = 0; + } + else if (cloud_noise_next && !cloud_noise) + { + cloudshader->bindTexture(LLShaderMgr::CLOUD_NOISE_MAP, cloud_noise_next, LLTexUnit::TT_TEXTURE); + blend_factor = 0; + } + else if (cloud_noise_next != cloud_noise) + { + cloudshader->bindTexture(LLShaderMgr::CLOUD_NOISE_MAP, cloud_noise, LLTexUnit::TT_TEXTURE); + cloudshader->bindTexture(LLShaderMgr::CLOUD_NOISE_MAP_NEXT, cloud_noise_next, LLTexUnit::TT_TEXTURE); + } + } + + cloudshader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor); + cloudshader->uniform1f(LLShaderMgr::CLOUD_VARIANCE, cloud_variance); + cloudshader->uniform1f(LLShaderMgr::SUN_MOON_GLOW_FACTOR, psky->getSunMoonGlowFactor()); + + ((LLSettingsVOSky*)psky.get())->updateShader(cloudshader); - LLGLSNoFog disableFog; - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - LLGLDisable clip(GL_CLIP_PLANE0); + /// Render the skydome + renderDome(camPosLocal, camHeightLocal, cloudshader); - gGL.setColorMask(true, false); + cloudshader->unbind(); - LLGLSquashToFarClip far_clip(glh_get_current_projection()); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE); + } +} - renderSkyHaze(camHeightLocal); +void LLDrawPoolWLSky::renderHeavenlyBodies() +{ + LLGLSPipelineBlendSkyBox gls_skybox(true, false); - LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin(); + LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin(); gGL.pushMatrix(); + gGL.translatef(origin.mV[0], origin.mV[1], origin.mV[2]); - - gGL.translatef(origin.mV[0], origin.mV[1], origin.mV[2]); + LLFace * face = gSky.mVOSkyp->mFace[LLVOSky::FACE_SUN]; - gDeferredStarProgram.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 - // bind the moon's texture once. - gGL.getTexUnit(0)->bind(gSky.mVOSkyp->mFace[LLVOSky::FACE_MOON]->getTexture()); + F32 blend_factor = LLEnvironment::instance().getCurrentSky()->getBlendFactor(); + bool can_use_vertex_shaders = gPipeline.canUseVertexShaders(); + bool can_use_windlight_shaders = gPipeline.canUseWindLightShaders(); - renderHeavenlyBodies(); - renderStars(); - - gDeferredStarProgram.unbind(); - - gGL.popMatrix(); + if (gSky.mVOSkyp->getSun().getDraw() && face && face->getGeomCount()) + { + LLPointer<LLViewerTexture> tex_a = face->getTexture(LLRender::DIFFUSE_MAP); + LLPointer<LLViewerTexture> tex_b = face->getTexture(LLRender::ALTERNATE_DIFFUSE_MAP); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE); + + // if we even have sun disc textures to work with... + if (tex_a || tex_b) + { + // if and only if we have a texture defined, render the sun disc + if (can_use_vertex_shaders && can_use_windlight_shaders) + { + sun_shader->bind(); + + if (tex_a && (!tex_b || (tex_a == tex_b))) + { + // Bind current and next sun textures + sun_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, tex_a, LLTexUnit::TT_TEXTURE); + blend_factor = 0; + } + else if (tex_b && !tex_a) + { + sun_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, tex_b, LLTexUnit::TT_TEXTURE); + blend_factor = 0; + } + else if (tex_b != tex_a) + { + sun_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, tex_a, LLTexUnit::TT_TEXTURE); + sun_shader->bindTexture(LLShaderMgr::ALTERNATE_DIFFUSE_MAP, tex_b, LLTexUnit::TT_TEXTURE); + } + + LLColor4 color(gSky.mVOSkyp->getSun().getInterpColor()); + + sun_shader->uniform4fv(LLShaderMgr::DIFFUSE_COLOR, 1, color.mV); + sun_shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor); + + face->renderIndexed(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE); + + sun_shader->unbind(); + } + } + } - renderSkyClouds(camHeightLocal); + face = gSky.mVOSkyp->mFace[LLVOSky::FACE_MOON]; - gGL.setColorMask(true, true); - //gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + if (gSky.mVOSkyp->getMoon().getDraw() && face && face->getTexture(LLRender::DIFFUSE_MAP) && face->getGeomCount() && moon_shader) + { + LLViewerTexture* tex_a = face->getTexture(LLRender::DIFFUSE_MAP); + LLViewerTexture* tex_b = face->getTexture(LLRender::ALTERNATE_DIFFUSE_MAP); + LLColor4 color(gSky.mVOSkyp->getMoon().getInterpColor()); + + if (can_use_vertex_shaders && can_use_windlight_shaders && (tex_a || tex_b)) + { + moon_shader->bind(); + + if (tex_a && (!tex_b || (tex_a == tex_b))) + { + // Bind current and next sun textures + moon_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, tex_a, LLTexUnit::TT_TEXTURE); + //blend_factor = 0; + } + else if (tex_b && !tex_a) + { + moon_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, tex_b, LLTexUnit::TT_TEXTURE); + //blend_factor = 0; + } + else if (tex_b != tex_a) + { + moon_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, tex_a, LLTexUnit::TT_TEXTURE); + //moon_shader->bindTexture(LLShaderMgr::ALTERNATE_DIFFUSE_MAP, tex_b, LLTexUnit::TT_TEXTURE); + } + + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + + F32 moon_brightness = (float)psky->getMoonBrightness(); + + moon_shader->uniform1f(LLShaderMgr::MOON_BRIGHTNESS, moon_brightness); + moon_shader->uniform4fv(LLShaderMgr::MOONLIGHT_COLOR, 1, gSky.mVOSkyp->getMoon().getColor().mV); + moon_shader->uniform4fv(LLShaderMgr::DIFFUSE_COLOR, 1, color.mV); + //moon_shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor); + moon_shader->uniform3fv(LLShaderMgr::DEFERRED_MOON_DIR, 1, psky->getMoonDirection().mV); // shader: moon_dir + + face->renderIndexed(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE); + + moon_shader->unbind(); + } + } + + gGL.popMatrix(); } -void LLDrawPoolWLSky::render(S32 pass) +void LLDrawPoolWLSky::renderDeferred(S32 pass) { if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY)) { @@ -357,34 +597,37 @@ void LLDrawPoolWLSky::render(S32 pass) } 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); - - LLGLSquashToFarClip far_clip(glh_get_current_projection()); - - renderSkyHaze(camHeightLocal); - - LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin(); - gGL.pushMatrix(); - - gGL.translatef(origin.mV[0], origin.mV[1], origin.mV[2]); + const F32 camHeightLocal = LLEnvironment::instance().getCamHeight(); - // *NOTE: have to bind a texture here since register combiners blending in - // renderStars() requires something to be bound and we might as well only - // bind the moon's texture once. - gGL.getTexUnit(0)->bind(gSky.mVOSkyp->mFace[LLVOSky::FACE_MOON]->getTexture()); + gGL.setColorMask(true, false); - renderHeavenlyBodies(); + LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin(); - renderStars(); - + if (gPipeline.canUseWindLightShaders()) + { + renderSkyHazeDeferred(origin, camHeightLocal); + renderStarsDeferred(origin); + renderHeavenlyBodies(); + renderSkyCloudsDeferred(origin, camHeightLocal, cloud_shader); + } + gGL.setColorMask(true, true); +} - gGL.popMatrix(); +void LLDrawPoolWLSky::render(S32 pass) +{ + if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY)) + { + return; + } + LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY); - renderSkyClouds(camHeightLocal); + const F32 camHeightLocal = LLEnvironment::instance().getCamHeight(); + LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin(); + + renderSkyHaze(origin, camHeightLocal); + renderStars(origin); + renderHeavenlyBodies(); + renderSkyClouds(origin, camHeightLocal, cloud_shader); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } @@ -394,11 +637,6 @@ void LLDrawPoolWLSky::prerender() //LL_INFOS() << "wlsky prerendering pass." << LL_ENDL; } -LLDrawPoolWLSky *LLDrawPoolWLSky::instancePool() -{ - return new LLDrawPoolWLSky(); -} - LLViewerTexture* LLDrawPoolWLSky::getTexture() { return NULL; @@ -411,15 +649,9 @@ void LLDrawPoolWLSky::resetDrawOrders() //static void LLDrawPoolWLSky::cleanupGL() { - sCloudNoiseTexture = NULL; } //static void LLDrawPoolWLSky::restoreGL() { - if(sCloudNoiseRawImage.notNull()) - { - sCloudNoiseTexture = LLViewerTextureManager::getLocalTexture(sCloudNoiseRawImage.get(), TRUE); - } } - diff --git a/indra/newview/lldrawpoolwlsky.h b/indra/newview/lldrawpoolwlsky.h index cd15c991ee..324886ed42 100644 --- a/indra/newview/lldrawpoolwlsky.h +++ b/indra/newview/lldrawpoolwlsky.h @@ -38,7 +38,8 @@ public: LLVertexBuffer::MAP_TEXCOORD0; static const U32 STAR_VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXCOORD0; - + static const U32 ADV_ATMO_SKY_VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX + | LLVertexBuffer::MAP_TEXCOORD0; LLDrawPoolWLSky(void); /*virtual*/ ~LLDrawPoolWLSky(); @@ -57,12 +58,10 @@ public: /*virtual*/ void prerender(); /*virtual*/ U32 getVertexDataMask() { return SKY_VERTEX_DATA_MASK; } /*virtual*/ BOOL verify() const { return TRUE; } // Verify that all data in the draw pool is correct! - /*virtual*/ S32 getVertexShaderLevel() const { return mVertexShaderLevel; } + /*virtual*/ S32 getShaderLevel() const { return mShaderLevel; } //static LLDrawPool* createPool(const U32 type, LLViewerTexture *tex0 = NULL); - // Create an empty new instance of the pool. - /*virtual*/ LLDrawPoolWLSky *instancePool(); ///< covariant override /*virtual*/ LLViewerTexture* getTexture(); /*virtual*/ BOOL isFacePool() { return FALSE; } /*virtual*/ void resetDrawOrders(); @@ -70,15 +69,18 @@ public: static void cleanupGL(); static void restoreGL(); private: - void renderDome(F32 camHeightLocal, LLGLSLShader * shader) const; - void renderSkyHaze(F32 camHeightLocal) const; - void renderStars(void) const; - void renderSkyClouds(F32 camHeightLocal) const; - void renderHeavenlyBodies(); + void renderFsSky(const LLVector3& camPosLocal, F32 camHeightLocal, LLGLSLShader * shader) const; + void renderDome(const LLVector3& camPosLocal, F32 camHeightLocal, LLGLSLShader * shader) const; -private: - static LLPointer<LLViewerTexture> sCloudNoiseTexture; - static LLPointer<LLImageRaw> sCloudNoiseRawImage; + void renderSkyHaze(const LLVector3& camPosLocal, F32 camHeightLocal) const; + void renderSkyClouds(const LLVector3& camPosLocal, F32 camHeightLocal, LLGLSLShader* cloudshader) const; + + void renderSkyHazeDeferred(const LLVector3& camPosLocal, F32 camHeightLocal) const; + void renderSkyCloudsDeferred(const LLVector3& camPosLocal, F32 camHeightLocal, LLGLSLShader* cloudshader) const; + + void renderStarsDeferred(const LLVector3& camPosLocal) const; + void renderStars(const LLVector3& camPosLocal) const; + void renderHeavenlyBodies(); }; #endif // LL_DRAWPOOLWLSKY_H diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index 8ef0dd2865..8b8273d183 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -56,13 +56,6 @@ LLViewerDynamicTexture::LLViewerDynamicTexture(S32 width, S32 height, S32 compon { llassert((1 <= components) && (components <= 4)); - if(gGLManager.mDebugGPU) - { - if(components == 3) - { - mComponents = 4 ; //convert to 32bits. - } - } generateGLTexture(); llassert( 0 <= order && order < ORDER_COUNT ); @@ -125,11 +118,11 @@ BOOL LLViewerDynamicTexture::render() //----------------------------------------------------------------------------- void LLViewerDynamicTexture::preRender(BOOL clear_depth) { - //only images up to 1024*1024 are supported - llassert(mFullHeight <= 512); - llassert(mFullWidth <= 512); + gPipeline.allocatePhysicsBuffer(); + llassert(mFullWidth <= static_cast<S32>(gPipeline.mPhysicsDisplay.getWidth())); + llassert(mFullHeight <= static_cast<S32>(gPipeline.mPhysicsDisplay.getHeight())); - if (gGLManager.mHasFramebufferObject && gPipeline.mWaterDis.isComplete() && !gGLManager.mIsATI) + if (gGLManager.mHasFramebufferObject && gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsATI) { //using offscreen render target, just use the bottom left corner mOrigin.set(0, 0); } @@ -211,16 +204,17 @@ void LLViewerDynamicTexture::postRender(BOOL success) BOOL LLViewerDynamicTexture::updateAllInstances() { sNumRenders = 0; - if (gGLManager.mIsDisabled || LLPipeline::sMemAllocationThrottled) + if (gGLManager.mIsDisabled) { return TRUE; } - bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mWaterDis.isComplete() && !gGLManager.mIsATI; + bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mBake.isComplete() && !gGLManager.mIsATI; if (use_fbo) { - gPipeline.mWaterDis.bindTarget(); + gPipeline.mBake.bindTarget(); + gPipeline.mBake.clear(); } LLGLSLShader::bindNoShader(); @@ -240,6 +234,7 @@ BOOL LLViewerDynamicTexture::updateAllInstances() gDepthDirty = TRUE; gGL.color4f(1,1,1,1); + dynamicTexture->setBoundTarget(use_fbo ? &gPipeline.mBake : nullptr); dynamicTexture->preRender(); // Must be called outside of startRender() result = FALSE; if (dynamicTexture->render()) @@ -250,7 +245,7 @@ BOOL LLViewerDynamicTexture::updateAllInstances() } gGL.flush(); LLVertexBuffer::unbind(); - + dynamicTexture->setBoundTarget(nullptr); dynamicTexture->postRender(result); } } @@ -258,9 +253,11 @@ BOOL LLViewerDynamicTexture::updateAllInstances() if (use_fbo) { - gPipeline.mWaterDis.flush(); + gPipeline.mBake.flush(); } + gGL.flush(); + return ret; } diff --git a/indra/newview/lldynamictexture.h b/indra/newview/lldynamictexture.h index f3f57c9a6b..4bd74a8425 100644 --- a/indra/newview/lldynamictexture.h +++ b/indra/newview/lldynamictexture.h @@ -88,6 +88,9 @@ public: static BOOL updateAllInstances(); static void destroyGL() ; static void restoreGL() ; + + void setBoundTarget(LLRenderTarget* target) { mBoundTarget = target; } + protected: void generateGLTexture(); void generateGLTexture(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes = FALSE); @@ -97,6 +100,8 @@ protected: LLCoordGL mOrigin; LL_ALIGN_16(LLCamera mCamera); + LLRenderTarget* mBoundTarget; + typedef std::set<LLViewerDynamicTexture*> instance_list_t; static instance_list_t sInstances[ LLViewerDynamicTexture::ORDER_COUNT ]; static S32 sNumRenders; diff --git a/indra/newview/llenvadapters.cpp b/indra/newview/llenvadapters.cpp new file mode 100644 index 0000000000..fdbcf68fa4 --- /dev/null +++ b/indra/newview/llenvadapters.cpp @@ -0,0 +1,67 @@ +/** + * @file llenvadapters.cpp + * @brief Declaration of classes managing WindLight and water settings. + * + * $LicenseInfo:firstyear=2009&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 "llenvadapters.h" + +#include "llsettingssky.h" +#include "llsettingswater.h" +//========================================================================= + +LLSkySettingsAdapter::LLSkySettingsAdapter(): + mWLGamma(1.0f, LLSettingsSky::SETTING_GAMMA), + + // Lighting + mLightnorm(LLColor4(0.f, 0.707f, -0.707f, 1.f), LLSettingsSky::SETTING_LIGHT_NORMAL), + mSunlight(LLColor4(0.5f, 0.5f, 0.5f, 1.0f), LLSettingsSky::SETTING_SUNLIGHT_COLOR, "WLSunlight"), + + mGlow(LLColor4(18.0f, 0.0f, -0.01f, 1.0f), LLSettingsSky::SETTING_GLOW), + // Clouds + mCloudColor(LLColor4(0.5f, 0.5f, 0.5f, 1.0f), LLSettingsSky::SETTING_CLOUD_COLOR, "WLCloudColor"), + mCloudMain(LLColor4(0.5f, 0.5f, 0.125f, 1.0f), LLSettingsSky::SETTING_CLOUD_POS_DENSITY1), + mCloudCoverage(0.0f, LLSettingsSky::SETTING_CLOUD_SHADOW), + mCloudDetail(LLColor4(0.0f, 0.0f, 0.0f, 1.0f), LLSettingsSky::SETTING_CLOUD_POS_DENSITY2), + mCloudScale(0.42f, LLSettingsSky::SETTING_CLOUD_SCALE) +{ + +} + +LLWatterSettingsAdapter::LLWatterSettingsAdapter(): + mFogColor(LLColor4((22.f / 255.f), (43.f / 255.f), (54.f / 255.f), (0.0f)), LLSettingsWater::SETTING_FOG_COLOR, "WaterFogColor"), + mFogDensity(4, LLSettingsWater::SETTING_FOG_DENSITY, 2), + mUnderWaterFogMod(0.25, LLSettingsWater::SETTING_FOG_MOD), + mNormalScale(LLVector3(2.f, 2.f, 2.f), LLSettingsWater::SETTING_NORMAL_SCALE), + mFresnelScale(0.5f, LLSettingsWater::SETTING_FRESNEL_SCALE), + mFresnelOffset(0.4f, LLSettingsWater::SETTING_FRESNEL_OFFSET), + mScaleAbove(0.025f, LLSettingsWater::SETTING_SCALE_ABOVE), + mScaleBelow(0.2f, LLSettingsWater::SETTING_SCALE_BELOW), + mBlurMultiplier(0.1f, LLSettingsWater::SETTING_BLUR_MULTIPILER), + mWave1Dir(LLVector2(0.5f, 0.5f), LLSettingsWater::SETTING_WAVE1_DIR), + mWave2Dir(LLVector2(0.5f, 0.5f), LLSettingsWater::SETTING_WAVE2_DIR) + +{ + +} diff --git a/indra/newview/llenvadapters.h b/indra/newview/llenvadapters.h new file mode 100644 index 0000000000..bd58db0589 --- /dev/null +++ b/indra/newview/llenvadapters.h @@ -0,0 +1,459 @@ +/** + * @file llenvadapters.h + * @brief Declaration of classes managing WindLight and water settings. + * + * $LicenseInfo:firstyear=2009&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_ENVADAPTERS_H +#define LL_ENVADAPTERS_H + +#include "v3math.h" +#include "v3color.h" +#include "v4math.h" +#include "llsettingsbase.h" +#include "llsettingssky.h" + +class WLColorControl +{ +public: + inline WLColorControl(LLColor4 color, const std::string& n, const std::string& slider_name = std::string()): + mColor(color), + mName(n), + mSliderName(slider_name), + mHasSliderName(false), + mIsSunOrAmbientColor(false), + mIsBlueHorizonOrDensity(false) + { + // if there's a slider name, say we have one + mHasSliderName = !mSliderName.empty(); + + // if it's the sun controller + mIsSunOrAmbientColor = (mSliderName == "WLSunlight" || mSliderName == "WLAmbient"); + mIsBlueHorizonOrDensity = (mSliderName == "WLBlueHorizon" || mSliderName == "WLBlueDensity"); + } + + inline void setColor4(const LLColor4 & val) + { + mColor = val; + } + + inline void setColor3(const LLColor3 & val) + { + mColor = val; + } + + inline LLColor4 getColor4() const + { + return mColor; + } + + inline LLColor3 getColor3(void) const + { + return vec4to3(mColor); + } + + inline void update(const LLSettingsBase::ptr_t &psetting) const + { + psetting->setValue(mName, mColor); + } + + inline bool getHasSliderName() const + { + return mHasSliderName; + } + + inline std::string getSliderName() const + { + return mSliderName; + } + + inline bool getIsSunOrAmbientColor() const + { + return mIsSunOrAmbientColor; + } + + inline bool getIsBlueHorizonOrDensity() const + { + return mIsBlueHorizonOrDensity; + } + + inline F32 getRed() const + { + return mColor[0]; + } + + inline F32 getGreen() const + { + return mColor[1]; + } + + inline F32 getBlue() const + { + return mColor[2]; + } + + inline F32 getIntensity() const + { + return mColor[3]; + } + + inline void setRed(F32 red) + { + mColor[0] = red; + } + + inline void setGreen(F32 green) + { + mColor[1] = green; + } + + inline void setBlue(F32 blue) + { + mColor[2] = blue; + } + + inline void setIntensity(F32 intensity) + { + mColor[3] = intensity; + } + +private: + LLColor4 mColor; /// [3] is intensity, not alpha + std::string mName; /// name to use to dereference params + std::string mSliderName; /// name of the slider in menu + bool mHasSliderName; /// only set slider name for true color types + bool mIsSunOrAmbientColor; /// flag for if it's the sun or ambient color controller + bool mIsBlueHorizonOrDensity; /// flag for if it's the Blue Horizon or Density color controller + +}; + +// float slider control +class WLFloatControl +{ +public: + inline WLFloatControl(F32 val, const std::string& n, F32 m = 1.0f): + x(val), + mName(n), + mult(m) + { + } + + inline WLFloatControl &operator = (F32 val) + { + x = val; + return *this; + } + + inline operator F32 (void) const + { + return x; + } + + inline void update(const LLSettingsBase::ptr_t &psetting) const + { + psetting->setValue(mName, x); + } + + inline F32 getMult() const + { + return mult; + } + + inline void setValue(F32 val) + { + x = val; + } + +private: + F32 x; + std::string mName; + F32 mult; +}; + +class WLXFloatControl +{ +public: + inline WLXFloatControl(F32 val, const std::string& n, F32 b): + mExp(val), + mBase(b), + mName(n) + { + } + + inline WLXFloatControl & operator = (F32 val) + { + mExp = log(val) / log(mBase); + + return *this; + } + + inline operator F32 (void) const + { + return pow(mBase, mExp); + } + + inline void update(const LLSettingsBase::ptr_t &psetting) const + { + psetting->setValue(mName, pow(mBase, mExp)); + } + + inline F32 getExp() const + { + return mExp; + } + + inline void setExp(F32 val) + { + mExp = val; + } + + inline F32 getBase() const + { + return mBase; + } + + inline void setBase(F32 val) + { + mBase = val; + } + +private: + F32 mExp; + F32 mBase; + std::string mName; +}; + +class WLVect2Control +{ +public: + inline WLVect2Control(LLVector2 val, const std::string& n): + mU(val.mV[0]), + mV(val.mV[1]), + mName(n) + { + } + + inline WLVect2Control & operator = (const LLVector2 & val) + { + mU = val.mV[0]; + mV = val.mV[1]; + + return *this; + } + + inline void update(const LLSettingsBase::ptr_t &psetting) const + { + psetting->setValue(mName, LLVector2(mU, mV)); + } + + inline F32 getU() const + { + return mU; + } + + inline void setU(F32 val) + { + mU = val; + } + + inline F32 getV() const + { + return mV; + } + + inline void setV(F32 val) + { + mV = val; + } + +private: + F32 mU; + F32 mV; + std::string mName; +}; + +class WLVect3Control +{ +public: + inline WLVect3Control(LLVector3 val, const std::string& n): + mX(val.mV[0]), + mY(val.mV[1]), + mZ(val.mV[2]), + mName(n) + { + } + + inline WLVect3Control & operator = (const LLVector3 & val) + { + mX = val.mV[0]; + mY = val.mV[1]; + mZ = val.mV[2]; + + return *this; + } + + inline void update(const LLSettingsBase::ptr_t &psetting) const + { + psetting->setValue(mName, LLVector3(mX, mY, mZ)); + } + + inline F32 getX() const + { + return mX; + } + + inline void setX(F32 val) + { + mX = val; + } + + inline F32 getY() const + { + return mY; + } + + inline void setY(F32 val) + { + mY = val; + } + + inline F32 getZ() const + { + return mZ; + } + + inline void setZ(F32 val) + { + mZ = val; + } + +private: + F32 mX; + F32 mY; + F32 mZ; + std::string mName; +}; + +class LLDensityProfileSettingsAdapter +{ +public: + LLDensityProfileSettingsAdapter(const std::string& config, int layerIndex = 0) + : mConfig(config) + , mLayerIndex(layerIndex) + , mLayerWidth(1.0f, LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH) + , mExpTerm(1.0f, LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM) + , mExpScale(1.0f, LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR) + , mLinTerm(1.0f, LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM) + , mConstantTerm(1.0f, LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM) + {} + +protected: + std::string mConfig; + int mLayerIndex; + WLFloatControl mLayerWidth; // 0.0 -> to top of atmosphere, however big that may be. + WLFloatControl mExpTerm; + WLFloatControl mExpScale; + WLFloatControl mLinTerm; + WLFloatControl mConstantTerm; +}; + +class LLRayleighDensityProfileSettingsAdapter : public LLDensityProfileSettingsAdapter +{ +public: + LLRayleighDensityProfileSettingsAdapter(int layerIndex = 0) + : LLDensityProfileSettingsAdapter(LLSettingsSky::SETTING_RAYLEIGH_CONFIG, layerIndex) + { + } +}; + +class LLMieDensityProfileSettingsAdapter : public LLDensityProfileSettingsAdapter +{ +public: + LLMieDensityProfileSettingsAdapter(int layerIndex = 0) + : LLDensityProfileSettingsAdapter(LLSettingsSky::SETTING_MIE_CONFIG, layerIndex) + , mAnisotropy(0.8f, LLSettingsSky::SETTING_MIE_ANISOTROPY_FACTOR) + { + } + +protected: + WLFloatControl mAnisotropy; +}; + +class LLAbsorptionDensityProfileSettingsAdapter : public LLDensityProfileSettingsAdapter +{ +public: + LLAbsorptionDensityProfileSettingsAdapter(int layerIndex = 0) + : LLDensityProfileSettingsAdapter(LLSettingsSky::SETTING_ABSORPTION_CONFIG, layerIndex) + { + } +}; + +//------------------------------------------------------------------------- +class LLSkySettingsAdapter +{ +public: + typedef std::shared_ptr<LLSkySettingsAdapter> ptr_t; + + LLSkySettingsAdapter(); + + WLFloatControl mWLGamma; + + /// Lighting + WLColorControl mLightnorm; + WLColorControl mSunlight; + WLColorControl mGlow; + + /// Clouds + WLColorControl mCloudColor; + WLColorControl mCloudMain; + WLFloatControl mCloudCoverage; + WLColorControl mCloudDetail; + WLFloatControl mCloudScale; +}; + +class LLWatterSettingsAdapter +{ +public: + typedef std::shared_ptr<LLWatterSettingsAdapter> ptr_t; + + LLWatterSettingsAdapter(); + + WLColorControl mFogColor; + WLXFloatControl mFogDensity; + WLFloatControl mUnderWaterFogMod; + + /// wavelet scales and directions + WLVect3Control mNormalScale; + WLVect2Control mWave1Dir; + WLVect2Control mWave2Dir; + + // controls how water is reflected and refracted + WLFloatControl mFresnelScale; + WLFloatControl mFresnelOffset; + WLFloatControl mScaleAbove; + WLFloatControl mScaleBelow; + WLFloatControl mBlurMultiplier; + +}; + +#endif // LL_ENVIRONMENT_H diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp new file mode 100644 index 0000000000..8881d11802 --- /dev/null +++ b/indra/newview/llenvironment.cpp @@ -0,0 +1,3562 @@ +/** + * @file llenvmanager.cpp + * @brief Implementation of classes managing WindLight and water settings. + * + * $LicenseInfo:firstyear=2009&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 "llenvironment.h" + +#include <algorithm> + +#include "llagent.h" +#include "llviewercontrol.h" // for gSavedSettings +#include "llviewerregion.h" +#include "llwlhandlers.h" +#include "lltrans.h" +#include "lltrace.h" +#include "llfasttimer.h" +#include "llviewercamera.h" +#include "pipeline.h" +#include "llsky.h" + +#include "llviewershadermgr.h" + +#include "llparcel.h" +#include "llviewerparcelmgr.h" + +#include "llsdserialize.h" +#include "lldiriterator.h" + +#include "llsettingsvo.h" +#include "llnotificationsutil.h" + +#include "llregioninfomodel.h" + +#include <boost/make_shared.hpp> + +#include "llatmosphere.h" +#include "llagent.h" +#include "roles_constants.h" +#include "llestateinfomodel.h" + +#include "lldispatcher.h" +#include "llviewergenericmessage.h" +#include "llexperiencelog.h" + +//========================================================================= +namespace +{ + const std::string KEY_ENVIRONMENT("environment"); + const std::string KEY_DAYASSET("day_asset"); + const std::string KEY_DAYCYCLE("day_cycle"); + const std::string KEY_DAYHASH("day_hash"); + const std::string KEY_DAYLENGTH("day_length"); + const std::string KEY_DAYNAME("day_name"); + const std::string KEY_DAYNAMES("day_names"); + const std::string KEY_DAYOFFSET("day_offset"); + const std::string KEY_ENVVERSION("env_version"); + const std::string KEY_ISDEFAULT("is_default"); + const std::string KEY_PARCELID("parcel_id"); + const std::string KEY_REGIONID("region_id"); + const std::string KEY_TRACKALTS("track_altitudes"); + const std::string KEY_FLAGS("flags"); + + const std::string MESSAGE_PUSHENVIRONMENT("PushExpEnvironment"); + + const std::string ACTION_CLEARENVIRONMENT("ClearEnvironment"); + const std::string ACTION_PUSHFULLENVIRONMENT("PushFullEnvironment"); + const std::string ACTION_PUSHPARTIALENVIRONMENT("PushPartialEnvironment"); + + const std::string KEY_ASSETID("asset_id"); + const std::string KEY_TRANSITIONTIME("transition_time"); + const std::string KEY_ACTION("action"); + const std::string KEY_ACTIONDATA("action_data"); + const std::string KEY_EXPERIENCEID("public_id"); + const std::string KEY_OBJECTNAME("ObjectName"); // some of these do not conform to the '_' format. + const std::string KEY_PARCELNAME("ParcelName"); // But changing these would also alter the Experience Log requirements. + const std::string KEY_COUNT("Count"); + + const std::string LISTENER_NAME("LLEnvironmentSingleton"); + const std::string PUMP_EXPERIENCE("experience_permission"); + + const std::string LOCAL_ENV_STORAGE_FILE("local_environment_data.bin"); + + //--------------------------------------------------------------------- + LLTrace::BlockTimerStatHandle FTM_ENVIRONMENT_UPDATE("Update Environment Tick"); + LLTrace::BlockTimerStatHandle FTM_SHADER_PARAM_UPDATE("Update Shader Parameters"); + + LLSettingsBase::Seconds DEFAULT_UPDATE_THRESHOLD(10.0); + const LLSettingsBase::Seconds MINIMUM_SPANLENGTH(0.01f); + + //--------------------------------------------------------------------- + inline LLSettingsBase::TrackPosition get_wrapping_distance(LLSettingsBase::TrackPosition begin, LLSettingsBase::TrackPosition end) + { + if (begin < end) + { + return end - begin; + } + else if (begin > end) + { + return LLSettingsBase::TrackPosition(1.0) - (begin - end); + } + + return 1.0f; + } + + 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; + } + + LLSettingsDay::TrackBound_t get_bounding_entries(LLSettingsDay::CycleTrack_t &track, const LLSettingsBase::TrackPosition& keyframe) + { + return LLSettingsDay::TrackBound_t(get_wrapping_atbefore(track, keyframe), get_wrapping_atafter(track, keyframe)); + } + + // Find normalized track position of given time along full length of cycle + inline LLSettingsBase::TrackPosition convert_time_to_position(const LLSettingsBase::Seconds& time, const LLSettingsBase::Seconds& len) + { + LLSettingsBase::TrackPosition position = LLSettingsBase::TrackPosition(fmod((F64)time, (F64)len) / (F64)len); + return llclamp(position, 0.0f, 1.0f); + } + + inline LLSettingsBase::BlendFactor convert_time_to_blend_factor(const LLSettingsBase::Seconds& time, const LLSettingsBase::Seconds& len, LLSettingsDay::CycleTrack_t &track) + { + LLSettingsBase::TrackPosition position = convert_time_to_position(time, len); + LLSettingsDay::TrackBound_t bounds(get_bounding_entries(track, position)); + + LLSettingsBase::TrackPosition spanlength(get_wrapping_distance((*bounds.first).first, (*bounds.second).first)); + if (position < (*bounds.first).first) + position += 1.0; + + LLSettingsBase::TrackPosition start = position - (*bounds.first).first; + + return static_cast<LLSettingsBase::BlendFactor>(start / spanlength); + } + + //--------------------------------------------------------------------- + class LLTrackBlenderLoopingTime : public LLSettingsBlenderTimeDelta + { + public: + LLTrackBlenderLoopingTime(const LLSettingsBase::ptr_t &target, const LLSettingsDay::ptr_t &day, S32 trackno, + LLSettingsBase::Seconds cyclelength, LLSettingsBase::Seconds cycleoffset, LLSettingsBase::Seconds updateThreshold) : + LLSettingsBlenderTimeDelta(target, LLSettingsBase::ptr_t(), LLSettingsBase::ptr_t(), LLSettingsBase::Seconds(1.0)), + mDay(day), + mTrackNo(0), + mCycleLength(cyclelength), + mCycleOffset(cycleoffset) + { + // must happen prior to getBoundingEntries call... + mTrackNo = selectTrackNumber(trackno); + + LLSettingsBase::Seconds now(getAdjustedNow()); + LLSettingsDay::TrackBound_t initial = getBoundingEntries(now); + + mInitial = (*initial.first).second; + mFinal = (*initial.second).second; + mBlendSpan = getSpanTime(initial); + + initializeTarget(now); + setOnFinished([this](const LLSettingsBlender::ptr_t &){ onFinishedSpan(); }); + } + + void switchTrack(S32 trackno, const LLSettingsBase::TrackPosition&) override + { + S32 use_trackno = selectTrackNumber(trackno); + + if (use_trackno == mTrackNo) + { // results in no change + return; + } + + LLSettingsBase::ptr_t pstartsetting = mTarget->buildDerivedClone(); + mTrackNo = use_trackno; + + LLSettingsBase::Seconds now = getAdjustedNow() + LLEnvironment::TRANSITION_ALTITUDE; + LLSettingsDay::TrackBound_t bounds = getBoundingEntries(now); + + LLSettingsBase::ptr_t pendsetting = (*bounds.first).second->buildDerivedClone(); + LLSettingsBase::TrackPosition targetpos = convert_time_to_position(now, mCycleLength) - (*bounds.first).first; + LLSettingsBase::TrackPosition targetspan = get_wrapping_distance((*bounds.first).first, (*bounds.second).first); + + LLSettingsBase::BlendFactor blendf = calculateBlend(targetpos, targetspan); + pendsetting->blend((*bounds.second).second, blendf); + + reset(pstartsetting, pendsetting, LLEnvironment::TRANSITION_ALTITUDE); + } + + protected: + S32 selectTrackNumber(S32 trackno) + { + if (trackno == 0) + { // We are dealing with the water track. There is only ever one. + return trackno; + } + + for (S32 test = trackno; test != 0; --test) + { // Find the track below the requested one with data. + LLSettingsDay::CycleTrack_t &track = mDay->getCycleTrack(test); + + if (!track.empty()) + return test; + } + + return 1; + } + + LLSettingsDay::TrackBound_t getBoundingEntries(LLSettingsBase::Seconds time) + { + LLSettingsDay::CycleTrack_t &wtrack = mDay->getCycleTrack(mTrackNo); + LLSettingsBase::TrackPosition position = convert_time_to_position(time, mCycleLength); + LLSettingsDay::TrackBound_t bounds = get_bounding_entries(wtrack, position); + return bounds; + } + + void initializeTarget(LLSettingsBase::Seconds time) + { + LLSettingsBase::BlendFactor blendf(convert_time_to_blend_factor(time, mCycleLength, mDay->getCycleTrack(mTrackNo))); + + blendf = llclamp(blendf, 0.0, 0.999); + setTimeSpent(LLSettingsBase::Seconds(blendf * mBlendSpan)); + + setBlendFactor(blendf); + } + + LLSettingsBase::Seconds getAdjustedNow() const + { + LLSettingsBase::Seconds now(LLDate::now().secondsSinceEpoch()); + + return (now + mCycleOffset); + } + + LLSettingsBase::Seconds getSpanTime(const LLSettingsDay::TrackBound_t &bounds) const + { + LLSettingsBase::Seconds span = mCycleLength * get_wrapping_distance((*bounds.first).first, (*bounds.second).first); + if (span < MINIMUM_SPANLENGTH) // for very short spans set a minimum length. + span = MINIMUM_SPANLENGTH; + return span; + } + + private: + LLSettingsDay::ptr_t mDay; + S32 mTrackNo; + LLSettingsBase::Seconds mCycleLength; + LLSettingsBase::Seconds mCycleOffset; + + void onFinishedSpan() + { + LLSettingsBase::Seconds adjusted_now = getAdjustedNow(); + LLSettingsDay::TrackBound_t next = getBoundingEntries(adjusted_now); + LLSettingsBase::Seconds nextspan = getSpanTime(next); + + reset((*next.first).second, (*next.second).second, nextspan); + + // Recalculate (reinitialize) position. Because: + // - 'delta' from applyTimeDelta accumulates errors (probably should be fixed/changed to absolute time) + // - freezes and lag can result in reset being called too late, so we need to add missed time + // - occasional time corrections can happen + // - some transition switches can happen outside applyTimeDelta thus causing 'desync' from 'delta' (can be fixed by getting rid of delta) + initializeTarget(adjusted_now); + } + }; + + class LLEnvironmentPushDispatchHandler : public LLDispatchHandler + { + public: + virtual bool operator()(const LLDispatcher *, 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() << "LLEnvironmentPushDispatchHandler: Attempted to read parameter data into LLSD but failed:" << llsdRaw << LL_ENDL; + } + } + + message[KEY_EXPERIENCEID] = invoice; + // Object Name + if (it != strings.end()) + { + message[KEY_OBJECTNAME] = *it++; + } + + // parcel Name + if (it != strings.end()) + { + message[KEY_PARCELNAME] = *it++; + } + message[KEY_COUNT] = 1; + + LLEnvironment::instance().handleEnvironmentPush(message); + return true; + } + }; + + LLEnvironmentPushDispatchHandler environment_push_dispatch_handler; + + template<class SETTINGT> + class LLSettingsInjected : public SETTINGT + { + public: + typedef std::shared_ptr<LLSettingsInjected<SETTINGT> > ptr_t; + + LLSettingsInjected(typename SETTINGT::ptr_t source) : + SETTINGT(), + mSource(source), + mLastSourceHash(0), + mLastHash(0) + {} + + virtual ~LLSettingsInjected() {}; + + typename SETTINGT::ptr_t getSource() const { return this->mSource; } + void setSource(const typename SETTINGT::ptr_t &source) + { + if (source.get() == this) // do not set a source to itself. + return; + this->mSource = source; + this->setDirtyFlag(true); + this->mLastSourceHash = 0; + } + + virtual bool isDirty() const override { return SETTINGT::isDirty() || (this->mSource->isDirty()); } + virtual bool isVeryDirty() const override { return SETTINGT::isVeryDirty() || (this->mSource->isVeryDirty()); } + + void injectSetting(const std::string keyname, LLSD value, LLUUID experience_id, F32Seconds transition) + { + if (transition > 0.1) + { + typename Injection::ptr_t injection = std::make_shared<Injection>(transition, keyname, value, true, experience_id); + + mInjections.push_back(injection); + std::stable_sort(mInjections.begin(), mInjections.end(), [](const typename Injection::ptr_t &a, const typename Injection::ptr_t &b) { return a->mTimeRemaining < b->mTimeRemaining; }); + } + else + { + mOverrideValues[keyname] = value; + mOverrideExps[keyname] = experience_id; + this->setDirtyFlag(true); + } + } + + void removeInjection(const std::string keyname, LLUUID experience, LLSettingsBase::Seconds transition) + { + injections_t injections_buf; + for (auto it = mInjections.begin(); it != mInjections.end(); it++) + { + if ((keyname.empty() || ((*it)->mKeyName == keyname)) && + (experience.isNull() || (experience == (*it)->mExperience))) + { + if (transition != LLEnvironment::TRANSITION_INSTANT) + { + typename Injection::ptr_t injection = std::make_shared<Injection>(transition, keyname, (*it)->mLastValue, false, LLUUID::null); + injections_buf.push_front(injection); + } + } + else + { + injections_buf.push_front(*it); + } + } + mInjections.clear(); + mInjections = injections_buf; + + for (auto itexp = mOverrideExps.begin(); itexp != mOverrideExps.end();) + { + if (experience.isNull() || ((*itexp).second == experience)) + { + if (transition != LLEnvironment::TRANSITION_INSTANT) + { + typename Injection::ptr_t injection = std::make_shared<Injection>(transition, (*itexp).first, mOverrideValues[(*itexp).first], false, LLUUID::null); + mInjections.push_front(injection); + } + mOverrideValues.erase((*itexp).first); + mOverrideExps.erase(itexp++); + } + else + ++itexp; + } + std::stable_sort(mInjections.begin(), mInjections.end(), [](const typename Injection::ptr_t &a, const typename Injection::ptr_t &b) { return a->mTimeRemaining < b->mTimeRemaining; }); + } + + void removeInjections(LLUUID experience_id, LLSettingsBase::Seconds transition) + { + removeInjection(std::string(), experience_id, transition); + } + + void injectExperienceValues(LLSD values, LLUUID experience_id, typename LLSettingsBase::Seconds transition) + { + for (auto it = values.beginMap(); it != values.endMap(); ++it) + { + injectSetting((*it).first, (*it).second, experience_id, transition); + } + this->setDirtyFlag(true); + } + + void applyInjections(LLSettingsBase::Seconds delta) + { + this->mSettings = this->mSource->getSettings(); + + for (auto ito = mOverrideValues.beginMap(); ito != mOverrideValues.endMap(); ++ito) + { + this->mSettings[(*ito).first] = (*ito).second; + } + + const LLSettingsBase::stringset_t &slerps = this->getSlerpKeys(); + const LLSettingsBase::stringset_t &skips = this->getSkipInterpolateKeys(); + const LLSettingsBase::stringset_t &specials = this->getSpecialKeys(); + + typename injections_t::iterator it; + for (it = mInjections.begin(); it != mInjections.end(); ++it) + { + std::string key_name = (*it)->mKeyName; + + LLSD value = this->mSettings[key_name]; + LLSD target = (*it)->mValue; + + if ((*it)->mFirstTime) + (*it)->mFirstTime = false; + else + (*it)->mTimeRemaining -= delta; + + typename LLSettingsBase::BlendFactor mix = 1.0f - ((*it)->mTimeRemaining.value() / (*it)->mTransition.value()); + + if (mix >= 1.0) + { + if ((*it)->mBlendIn) + { + mOverrideValues[key_name] = target; + mOverrideExps[key_name] = (*it)->mExperience; + this->mSettings[key_name] = target; + } + else + { + this->mSettings.erase(key_name); + } + } + else if (specials.find(key_name) != specials.end()) + { + updateSpecial(*it, mix); + } + else if (skips.find(key_name) == skips.end()) + { + if (!(*it)->mBlendIn) + mix = 1.0 - mix; + (*it)->mLastValue = this->interpolateSDValue(key_name, value, target, this->getParameterMap(), mix, slerps); + this->mSettings[key_name] = (*it)->mLastValue; + } + } + + size_t hash = this->getHash(); + + if (hash != mLastHash) + { + this->setDirtyFlag(true); + mLastHash = hash; + } + + it = mInjections.begin(); + it = std::find_if(mInjections.begin(), mInjections.end(), [](const typename Injection::ptr_t &a) { return a->mTimeRemaining > 0.0f; }); + + if (it != mInjections.begin()) + { + mInjections.erase(mInjections.begin(), mInjections.end()); + } + + } + + bool hasInjections() const + { + return (!mInjections.empty() || (mOverrideValues.size() > 0)); + } + + protected: + struct Injection + { + Injection(typename LLSettingsBase::Seconds transition, const std::string &keyname, LLSD value, bool blendin, LLUUID experince, S32 index = -1) : + mTransition(transition), + mTimeRemaining(transition), + mKeyName(keyname), + mValue(value), + mExperience(experince), + mIndex(index), + mBlendIn(blendin), + mFirstTime(true) + {} + + typename LLSettingsBase::Seconds mTransition; + typename LLSettingsBase::Seconds mTimeRemaining; + std::string mKeyName; + LLSD mValue; + LLSD mLastValue; + LLUUID mExperience; + S32 mIndex; + bool mBlendIn; + bool mFirstTime; + + typedef std::shared_ptr<Injection> ptr_t; + }; + + + virtual void updateSettings() override + { + static LLFrameTimer timer; + + if (!this->mSource) + return; + + // clears the dirty flag on this object. Need to prevent triggering + // more calls into this updateSettings + LLSettingsBase::updateSettings(); + + resetSpecial(); + + if (this->mSource->isDirty()) + { + this->mSource->updateSettings(); + } + + typename LLSettingsBase::Seconds delta(timer.getElapsedTimeAndResetF32()); + + + SETTINGT::updateSettings(); + + if (!mInjections.empty()) + this->setDirtyFlag(true); + } + + LLSettingsBase::stringset_t getSpecialKeys() const; + void resetSpecial(); + void updateSpecial(const typename Injection::ptr_t &injection, typename LLSettingsBase::BlendFactor mix); + + private: + typedef std::map<std::string, LLUUID> key_to_expid_t; + typedef std::deque<typename Injection::ptr_t> injections_t; + + size_t mLastSourceHash; + size_t mLastHash; + typename SETTINGT::ptr_t mSource; + injections_t mInjections; + LLSD mOverrideValues; + key_to_expid_t mOverrideExps; + }; + + template<> + LLSettingsBase::stringset_t LLSettingsInjected<LLSettingsVOSky>::getSpecialKeys() const + { + static LLSettingsBase::stringset_t specialSet; + + if (specialSet.empty()) + { + specialSet.insert(SETTING_BLOOM_TEXTUREID); + specialSet.insert(SETTING_RAINBOW_TEXTUREID); + specialSet.insert(SETTING_HALO_TEXTUREID); + specialSet.insert(SETTING_CLOUD_TEXTUREID); + specialSet.insert(SETTING_MOON_TEXTUREID); + specialSet.insert(SETTING_SUN_TEXTUREID); + } + return specialSet; + } + + template<> + LLSettingsBase::stringset_t LLSettingsInjected<LLSettingsVOWater>::getSpecialKeys() const + { + static stringset_t specialSet; + + if (specialSet.empty()) + { + specialSet.insert(SETTING_TRANSPARENT_TEXTURE); + specialSet.insert(SETTING_NORMAL_MAP); + } + return specialSet; + } + + template<> + void LLSettingsInjected<LLSettingsVOSky>::resetSpecial() + { + mNextSunTextureId.setNull(); + mNextMoonTextureId.setNull(); + mNextCloudTextureId.setNull(); + mNextBloomTextureId.setNull(); + mNextRainbowTextureId.setNull(); + mNextHaloTextureId.setNull(); + setBlendFactor(0.0f); + } + + template<> + void LLSettingsInjected<LLSettingsVOWater>::resetSpecial() + { + mNextNormalMapID.setNull(); + mNextTransparentTextureID.setNull(); + setBlendFactor(0.0f); + } + + template<> + void LLSettingsInjected<LLSettingsVOSky>::updateSpecial(const typename LLSettingsInjected<LLSettingsVOSky>::Injection::ptr_t &injection, typename LLSettingsBase::BlendFactor mix) + { + if (injection->mKeyName == SETTING_SUN_TEXTUREID) + { + mNextSunTextureId = injection->mValue.asUUID(); + } + else if (injection->mKeyName == SETTING_MOON_TEXTUREID) + { + mNextMoonTextureId = injection->mValue.asUUID(); + } + else if (injection->mKeyName == SETTING_CLOUD_TEXTUREID) + { + mNextCloudTextureId = injection->mValue.asUUID(); + } + else if (injection->mKeyName == SETTING_BLOOM_TEXTUREID) + { + mNextBloomTextureId = injection->mValue.asUUID(); + } + else if (injection->mKeyName == SETTING_RAINBOW_TEXTUREID) + { + mNextRainbowTextureId = injection->mValue.asUUID(); + } + else if (injection->mKeyName == SETTING_HALO_TEXTUREID) + { + mNextHaloTextureId = injection->mValue.asUUID(); + } + + // Unfortunately I don't have a per texture blend factor. We'll just pick the one that is furthest along. + if (getBlendFactor() < mix) + { + setBlendFactor(mix); + } + } + + template<> + void LLSettingsInjected<LLSettingsVOWater>::updateSpecial(const typename LLSettingsInjected<LLSettingsVOWater>::Injection::ptr_t &injection, typename LLSettingsBase::BlendFactor mix) + { + if (injection->mKeyName == SETTING_NORMAL_MAP) + { + mNextNormalMapID = injection->mValue.asUUID(); + } + else if (injection->mKeyName == SETTING_TRANSPARENT_TEXTURE) + { + mNextTransparentTextureID = injection->mValue.asUUID(); + } + + // Unfortunately I don't have a per texture blend factor. We'll just pick the one that is furthest along. + if (getBlendFactor() < mix) + { + setBlendFactor(mix); + } + } + + typedef LLSettingsInjected<LLSettingsVOSky> LLSettingsInjectedSky; + typedef LLSettingsInjected<LLSettingsVOWater> LLSettingsInjectedWater; + + //===================================================================== + class DayInjection : public LLEnvironment::DayInstance + { + friend class InjectedTransition; + + public: + typedef std::shared_ptr<DayInjection> ptr_t; + typedef std::weak_ptr<DayInjection> wptr_t; + + DayInjection(LLEnvironment::EnvSelection_t env); + virtual ~DayInjection(); + + virtual bool applyTimeDelta(const LLSettingsBase::Seconds& delta) override; + + void setInjectedDay(const LLSettingsDay::ptr_t &pday, LLUUID experience_id, LLSettingsBase::Seconds transition); + void setInjectedSky(const LLSettingsSky::ptr_t &psky, LLUUID experience_id, LLSettingsBase::Seconds transition); + void setInjectedWater(const LLSettingsWater::ptr_t &pwater, LLUUID experience_id, LLSettingsBase::Seconds transition); + + void injectSkySettings(LLSD settings, LLUUID experience_id, LLSettingsBase::Seconds transition); + void injectWaterSettings(LLSD settings, LLUUID experience_id, LLSettingsBase::Seconds transition); + + void clearInjections(LLUUID experience_id, LLSettingsBase::Seconds transition_time); + + virtual void animate() override; + + LLEnvironment::DayInstance::ptr_t getBaseDayInstance() const { return mBaseDayInstance; } + void setBaseDayInstance(const LLEnvironment::DayInstance::ptr_t &baseday); + + S32 countExperiencesActive() const { return mActiveExperiences.size(); } + + bool isOverriddenSky() const { return !mSkyExperience.isNull(); } + bool isOverriddenWater() const { return !mWaterExperience.isNull(); } + + bool hasInjections() const; + + void testExperiencesOnParcel(S32 parcel_id); + private: + static void testExperiencesOnParcelCoro(wptr_t that, S32 parcel_id); + + + void animateSkyChange(LLSettingsSky::ptr_t psky, LLSettingsBase::Seconds transition); + void animateWaterChange(LLSettingsWater::ptr_t pwater, LLSettingsBase::Seconds transition); + + void onEnvironmentChanged(LLEnvironment::EnvSelection_t env); + void onParcelChange(); + + void checkExperience(); + + + LLEnvironment::DayInstance::ptr_t mBaseDayInstance; + + LLSettingsInjectedSky::ptr_t mInjectedSky; + LLSettingsInjectedWater::ptr_t mInjectedWater; + std::set<LLUUID> mActiveExperiences; + LLUUID mDayExperience; + LLUUID mSkyExperience; + LLUUID mWaterExperience; + LLEnvironment::connection_t mEnvChangeConnection; + boost::signals2::connection mParcelChangeConnection; + }; + + class InjectedTransition : public LLEnvironment::DayTransition + { + public: + InjectedTransition(const DayInjection::ptr_t &injection, const LLSettingsSky::ptr_t &skystart, const LLSettingsWater::ptr_t &waterstart, DayInstance::ptr_t &end, LLSettingsDay::Seconds time): + LLEnvironment::DayTransition(skystart, waterstart, end, time), + mInjection(injection) + { } + virtual ~InjectedTransition() { }; + + virtual void animate() override; + + protected: + DayInjection::ptr_t mInjection; + }; + +} + +//========================================================================= +const F64Seconds LLEnvironment::TRANSITION_INSTANT(0.0f); +const F64Seconds LLEnvironment::TRANSITION_FAST(1.0f); +const F64Seconds LLEnvironment::TRANSITION_DEFAULT(5.0f); +const F64Seconds LLEnvironment::TRANSITION_SLOW(10.0f); +const F64Seconds LLEnvironment::TRANSITION_ALTITUDE(5.0f); + +const LLUUID LLEnvironment::KNOWN_SKY_SUNRISE("01e41537-ff51-2f1f-8ef7-17e4df760bfb"); +const LLUUID LLEnvironment::KNOWN_SKY_MIDDAY("6c83e853-e7f8-cad7-8ee6-5f31c453721c"); +const LLUUID LLEnvironment::KNOWN_SKY_SUNSET("084e26cd-a900-28e8-08d0-64a9de5c15e2"); +const LLUUID LLEnvironment::KNOWN_SKY_MIDNIGHT("8a01b97a-cb20-c1ea-ac63-f7ea84ad0090"); + +const S32 LLEnvironment::NO_TRACK(-1); +const S32 LLEnvironment::NO_VERSION(-3); // For viewer sided change, like ENV_LOCAL. -3 since -1 and -2 are taken by parcel initial server/viewer version +const S32 LLEnvironment::VERSION_CLEANUP(-4); // for cleanups + +const F32 LLEnvironment::SUN_DELTA_YAW(F_PI); // 180deg + + +const U32 LLEnvironment::DayInstance::NO_ANIMATE_SKY(0x01); +const U32 LLEnvironment::DayInstance::NO_ANIMATE_WATER(0x02); + +std::string env_selection_to_string(LLEnvironment::EnvSelection_t sel) +{ +#define RTNENUM(E) case LLEnvironment::E: return #E + switch (sel){ + RTNENUM(ENV_EDIT); + RTNENUM(ENV_LOCAL); + RTNENUM(ENV_PUSH); + RTNENUM(ENV_PARCEL); + RTNENUM(ENV_REGION); + RTNENUM(ENV_DEFAULT); + RTNENUM(ENV_END); + RTNENUM(ENV_CURRENT); + RTNENUM(ENV_NONE); + default: + return llformat("Unknown(%d)", sel); + } +#undef RTNENUM +} + + +//------------------------------------------------------------------------- +LLEnvironment::LLEnvironment(): + mCloudScrollDelta(), + mCloudScrollPaused(false), + mSelectedSky(), + mSelectedWater(), + mSelectedDay(), + mSelectedEnvironment(LLEnvironment::ENV_LOCAL), + mCurrentTrack(1), + mEditorCounter(0), + mShowSunBeacon(false), + mShowMoonBeacon(false) +{ +} + +void LLEnvironment::initSingleton() +{ + LLSettingsSky::ptr_t p_default_sky = LLSettingsVOSky::buildDefaultSky(); + LLSettingsWater::ptr_t p_default_water = LLSettingsVOWater::buildDefaultWater(); + + mCurrentEnvironment = std::make_shared<DayInstance>(ENV_DEFAULT); + mCurrentEnvironment->setSky(p_default_sky); + mCurrentEnvironment->setWater(p_default_water); + + mEnvironments[ENV_DEFAULT] = mCurrentEnvironment; + + requestRegion(); + + gAgent.addParcelChangedCallback([this]() { onParcelChange(); }); + + //TODO: This frequently results in one more request than we need. It isn't breaking, but should be nicer. + // We need to know new env version to fix this, without it we can only do full re-request + // Happens: on updates, on opening LLFloaterRegionInfo, on region crossing if info floater is open + LLRegionInfoModel::instance().setUpdateCallback([this]() { requestRegion(); }); + gAgent.addRegionChangedCallback([this]() { onRegionChange(); }); + + gAgent.whenPositionChanged([this](const LLVector3 &localpos, const LLVector3d &) { onAgentPositionHasChanged(localpos); }); + + if (!gGenericDispatcher.isHandlerPresent(MESSAGE_PUSHENVIRONMENT)) + { + gGenericDispatcher.addHandler(MESSAGE_PUSHENVIRONMENT, &environment_push_dispatch_handler); + } + + LLEventPumps::instance().obtain(PUMP_EXPERIENCE).listen(LISTENER_NAME, [this](LLSD message) { listenExperiencePump(message); return false; }); +} + +void LLEnvironment::cleanupSingleton() +{ + LLEventPumps::instance().obtain(PUMP_EXPERIENCE).stopListening(LISTENER_NAME); +} + +LLEnvironment::~LLEnvironment() +{ +} + +bool LLEnvironment::canEdit() const +{ + return true; +} + +LLSettingsSky::ptr_t LLEnvironment::getCurrentSky() const +{ + LLSettingsSky::ptr_t psky = mCurrentEnvironment->getSky(); + + if (!psky && mCurrentEnvironment->getEnvironmentSelection() >= ENV_EDIT) + { + for (int idx = 0; idx < ENV_END; ++idx) + { + if (mEnvironments[idx]->getSky()) + { + psky = mEnvironments[idx]->getSky(); + break; + } + } + } + return psky; +} + +LLSettingsWater::ptr_t LLEnvironment::getCurrentWater() const +{ + LLSettingsWater::ptr_t pwater = mCurrentEnvironment->getWater(); + + if (!pwater && mCurrentEnvironment->getEnvironmentSelection() >= ENV_EDIT) + { + for (int idx = 0; idx < ENV_END; ++idx) + { + if (mEnvironments[idx]->getWater()) + { + pwater = mEnvironments[idx]->getWater(); + break; + } + } + } + return pwater; +} + +void LayerConfigToDensityLayer(const LLSD& layerConfig, DensityLayer& layerOut) +{ + layerOut.constant_term = layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM].asReal(); + layerOut.exp_scale = layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR].asReal(); + layerOut.exp_term = layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM].asReal(); + layerOut.linear_term = layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM].asReal(); + layerOut.width = layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH].asReal(); +} + +void LLEnvironment::getAtmosphericModelSettings(AtmosphericModelSettings& settingsOut, const LLSettingsSky::ptr_t &psky) +{ + settingsOut.m_skyBottomRadius = psky->getSkyBottomRadius(); + settingsOut.m_skyTopRadius = psky->getSkyTopRadius(); + settingsOut.m_sunArcRadians = psky->getSunArcRadians(); + settingsOut.m_mieAnisotropy = psky->getMieAnisotropy(); + + LLSD rayleigh = psky->getRayleighConfigs(); + settingsOut.m_rayleighProfile.clear(); + for (LLSD::array_iterator itf = rayleigh.beginArray(); itf != rayleigh.endArray(); ++itf) + { + DensityLayer layer; + LLSD& layerConfig = (*itf); + LayerConfigToDensityLayer(layerConfig, layer); + settingsOut.m_rayleighProfile.push_back(layer); + } + + LLSD mie = psky->getMieConfigs(); + settingsOut.m_mieProfile.clear(); + for (LLSD::array_iterator itf = mie.beginArray(); itf != mie.endArray(); ++itf) + { + DensityLayer layer; + LLSD& layerConfig = (*itf); + LayerConfigToDensityLayer(layerConfig, layer); + settingsOut.m_mieProfile.push_back(layer); + } + settingsOut.m_mieAnisotropy = psky->getMieAnisotropy(); + + LLSD absorption = psky->getAbsorptionConfigs(); + settingsOut.m_absorptionProfile.clear(); + for (LLSD::array_iterator itf = absorption.beginArray(); itf != absorption.endArray(); ++itf) + { + DensityLayer layer; + LLSD& layerConfig = (*itf); + LayerConfigToDensityLayer(layerConfig, layer); + settingsOut.m_absorptionProfile.push_back(layer); + } +} + +bool LLEnvironment::canAgentUpdateParcelEnvironment() const +{ + LLParcel *parcel(LLViewerParcelMgr::instance().getAgentOrSelectedParcel()); + + return canAgentUpdateParcelEnvironment(parcel); +} + + +bool LLEnvironment::canAgentUpdateParcelEnvironment(LLParcel *parcel) const +{ + if (!parcel) + return false; + + if (!LLEnvironment::instance().isExtendedEnvironmentEnabled()) + return false; + + if (gAgent.isGodlike()) + return true; + + if (!parcel->getRegionAllowEnvironmentOverride()) + return false; + + return LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_ALLOW_ENVIRONMENT); +} + +bool LLEnvironment::canAgentUpdateRegionEnvironment() const +{ + if (gAgent.isGodlike()) + return true; + + return gAgent.canManageEstate(); +} + +bool LLEnvironment::isExtendedEnvironmentEnabled() const +{ + return !gAgent.getRegionCapability("ExtEnvironment").empty(); +} + +bool LLEnvironment::isInventoryEnabled() const +{ + return (!gAgent.getRegionCapability("UpdateSettingsAgentInventory").empty() && + !gAgent.getRegionCapability("UpdateSettingsTaskInventory").empty()); +} + +void LLEnvironment::onRegionChange() +{ +// if (gAgent.getRegionCapability("ExperienceQuery").empty()) +// { +// // for now environmental experiences do not survive region crossings + clearExperienceEnvironment(LLUUID::null, TRANSITION_DEFAULT); +// } + + LLViewerRegion* cur_region = gAgent.getRegion(); + if (!cur_region) + { + return; + } + if (!cur_region->capabilitiesReceived()) + { + cur_region->setCapabilitiesReceivedCallback([](const LLUUID ®ion_id, LLViewerRegion* regionp) { LLEnvironment::instance().requestRegion(); }); + return; + } + requestRegion(); +} + +void LLEnvironment::onParcelChange() +{ + S32 parcel_id(INVALID_PARCEL_ID); + LLParcel* parcel = LLViewerParcelMgr::instance().getAgentParcel(); + + if (parcel) + { + parcel_id = parcel->getLocalID(); + } + + requestParcel(parcel_id); +} + +//------------------------------------------------------------------------- +F32 LLEnvironment::getCamHeight() const +{ + return (mCurrentEnvironment->getSky()->getDomeOffset() * mCurrentEnvironment->getSky()->getDomeRadius()); +} + +F32 LLEnvironment::getWaterHeight() const +{ + LLViewerRegion* cur_region = gAgent.getRegion(); + return cur_region ? cur_region->getWaterHeight() : DEFAULT_WATER_HEIGHT; +} + +bool LLEnvironment::getIsSunUp() const +{ + if (!mCurrentEnvironment || !mCurrentEnvironment->getSky()) + return false; + return mCurrentEnvironment->getSky()->getIsSunUp(); +} + +bool LLEnvironment::getIsMoonUp() const +{ + if (!mCurrentEnvironment || !mCurrentEnvironment->getSky()) + return false; + return mCurrentEnvironment->getSky()->getIsMoonUp(); +} + +//------------------------------------------------------------------------- +void LLEnvironment::setSelectedEnvironment(LLEnvironment::EnvSelection_t env, LLSettingsBase::Seconds transition, bool forced) +{ + mSelectedEnvironment = env; + updateEnvironment(transition, forced); + LL_DEBUGS("ENVIRONMENT") << "Setting environment " << env_selection_to_string(env) << " with transition: " << transition << LL_ENDL; +} + +bool LLEnvironment::hasEnvironment(LLEnvironment::EnvSelection_t env) +{ + if ((env < ENV_EDIT) || (env >= ENV_DEFAULT) || (!mEnvironments[env])) + { + return false; + } + + return true; +} + +LLEnvironment::DayInstance::ptr_t LLEnvironment::getEnvironmentInstance(LLEnvironment::EnvSelection_t env, bool create /*= false*/) +{ + DayInstance::ptr_t environment = mEnvironments[env]; + if (create) + { + if (environment) + environment = environment->clone(); + else + { + if (env == ENV_PUSH) + environment = std::make_shared<DayInjection>(env); + else + environment = std::make_shared<DayInstance>(env); + } + mEnvironments[env] = environment; + } + + return environment; +} + + +void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, const LLSettingsDay::ptr_t &pday, LLSettingsDay::Seconds daylength, LLSettingsDay::Seconds dayoffset, S32 env_version) +{ + if ((env < ENV_EDIT) || (env >= ENV_DEFAULT)) + { + LL_WARNS("ENVIRONMENT") << "Attempt to change invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; + return; + } + + logEnvironment(env, pday, env_version); + + DayInstance::ptr_t environment = getEnvironmentInstance(env, true); + + environment->clear(); + environment->setDay(pday, daylength, dayoffset); + environment->setSkyTrack(mCurrentTrack); + environment->animate(); + + if (!mSignalEnvChanged.empty()) + mSignalEnvChanged(env, env_version); +} + + +void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, LLEnvironment::fixedEnvironment_t fixed, S32 env_version) +{ + if ((env < ENV_EDIT) || (env >= ENV_DEFAULT)) + { + LL_WARNS("ENVIRONMENT") << "Attempt to change invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; + return; + } + + DayInstance::ptr_t environment = getEnvironmentInstance(env, true); + + + if (fixed.first) + { + logEnvironment(env, fixed.first, env_version); + environment->setSky(fixed.first); + environment->setFlags(DayInstance::NO_ANIMATE_SKY); + } + else if (!environment->getSky()) + { + if (mCurrentEnvironment->getEnvironmentSelection() != ENV_NONE) + { + // Note: This looks suspicious. Shouldn't we assign whole day if mCurrentEnvironment has whole day? + // and then add water/sky on top + // This looks like it will result in sky using single keyframe instead of whole day if day is present + // when setting static water without static sky + environment->setSky(mCurrentEnvironment->getSky()); + environment->setFlags(DayInstance::NO_ANIMATE_SKY); + } + else + { + // Environment is not properly initialized yet, but we should have environment by this point + DayInstance::ptr_t substitute = getEnvironmentInstance(ENV_PARCEL, true); + if (!substitute || !substitute->getSky()) + { + substitute = getEnvironmentInstance(ENV_REGION, true); + } + if (!substitute || !substitute->getSky()) + { + substitute = getEnvironmentInstance(ENV_DEFAULT, true); + } + + if (substitute && substitute->getSky()) + { + environment->setSky(substitute->getSky()); + environment->setFlags(DayInstance::NO_ANIMATE_SKY); + } + else + { + LL_WARNS("ENVIRONMENT") << "Failed to assign substitute water/sky, environment is not properly initialized" << LL_ENDL; + } + } + } + + if (fixed.second) + { + logEnvironment(env, fixed.second, env_version); + environment->setWater(fixed.second); + environment->setFlags(DayInstance::NO_ANIMATE_WATER); + } + else if (!environment->getWater()) + { + if (mCurrentEnvironment->getEnvironmentSelection() != ENV_NONE) + { + // Note: This looks suspicious. Shouldn't we assign whole day if mCurrentEnvironment has whole day? + // and then add water/sky on top + // This looks like it will result in water using single keyframe instead of whole day if day is present + // when setting static sky without static water + environment->setWater(mCurrentEnvironment->getWater()); + environment->setFlags(DayInstance::NO_ANIMATE_WATER); + } + else + { + // Environment is not properly initialized yet, but we should have environment by this point + DayInstance::ptr_t substitute = getEnvironmentInstance(ENV_PARCEL, true); + if (!substitute || !substitute->getWater()) + { + substitute = getEnvironmentInstance(ENV_REGION, true); + } + if (!substitute || !substitute->getWater()) + { + substitute = getEnvironmentInstance(ENV_DEFAULT, true); + } + + if (substitute && substitute->getWater()) + { + environment->setWater(substitute->getWater()); + environment->setFlags(DayInstance::NO_ANIMATE_WATER); + } + else + { + LL_WARNS("ENVIRONMENT") << "Failed to assign substitute water/sky, environment is not properly initialized" << LL_ENDL; + } + } + } + + if (!mSignalEnvChanged.empty()) + mSignalEnvChanged(env, env_version); +} + +void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, const LLSettingsBase::ptr_t &settings, S32 env_version) +{ + DayInstance::ptr_t environment = getEnvironmentInstance(env); + + if (env == ENV_DEFAULT) + { + LL_WARNS("ENVIRONMENT") << "Attempt to set default environment. Not allowed." << LL_ENDL; + return; + } + + if (!settings) + { + clearEnvironment(env); + return; + } + + if (settings->getSettingsType() == "daycycle") + { + LLSettingsDay::Seconds daylength(LLSettingsDay::DEFAULT_DAYLENGTH); + LLSettingsDay::Seconds dayoffset(LLSettingsDay::DEFAULT_DAYOFFSET); + if (environment) + { + daylength = environment->getDayLength(); + dayoffset = environment->getDayOffset(); + } + setEnvironment(env, std::static_pointer_cast<LLSettingsDay>(settings), daylength, dayoffset); + } + else if (settings->getSettingsType() == "sky") + { + fixedEnvironment_t fixedenv(std::static_pointer_cast<LLSettingsSky>(settings), LLSettingsWater::ptr_t()); + setEnvironment(env, fixedenv); + } + else if (settings->getSettingsType() == "water") + { + fixedEnvironment_t fixedenv(LLSettingsSky::ptr_t(), std::static_pointer_cast<LLSettingsWater>(settings)); + setEnvironment(env, fixedenv); + } +} + +void LLEnvironment::setEnvironment(EnvSelection_t env, const LLUUID &assetId, S32 env_version) +{ + setEnvironment(env, assetId, TRANSITION_DEFAULT, env_version); +} + +void LLEnvironment::setEnvironment(EnvSelection_t env, + const LLUUID &assetId, + LLSettingsBase::Seconds transition, + S32 env_version) +{ + LLSettingsVOBase::getSettingsAsset(assetId, + [this, env, env_version, transition](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) + { + onSetEnvAssetLoaded(env, asset_id, settings, transition, status, env_version); + }); +} + +void LLEnvironment::onSetEnvAssetLoaded(EnvSelection_t env, + LLUUID asset_id, + LLSettingsBase::ptr_t settings, + LLSettingsBase::Seconds transition, + S32 status, + S32 env_version) +{ + if (!settings || status) + { + LLSD args; + args["NAME"] = asset_id.asString(); + LLNotificationsUtil::add("FailedToFindSettings", args); + LL_DEBUGS("ENVIRONMENT") << "Failed to find settings for " << env_selection_to_string(env) << ", asset_id: " << asset_id << LL_ENDL; + return; + } + LL_DEBUGS("ENVIRONMENT") << "Loaded asset: " << asset_id << LL_ENDL; + + setEnvironment(env, settings); + updateEnvironment(transition); +} + +void LLEnvironment::clearEnvironment(LLEnvironment::EnvSelection_t env) +{ + if ((env < ENV_EDIT) || (env >= ENV_DEFAULT)) + { + LL_WARNS("ENVIRONMENT") << "Attempt to change invalid environment selection." << LL_ENDL; + return; + } + + LL_DEBUGS("ENVIRONMENT") << "Cleaning environment " << env_selection_to_string(env) << LL_ENDL; + + mEnvironments[env].reset(); + + if (!mSignalEnvChanged.empty()) + mSignalEnvChanged(env, VERSION_CLEANUP); +} + +void LLEnvironment::logEnvironment(EnvSelection_t env, const LLSettingsBase::ptr_t &settings, S32 env_version) +{ + LL_DEBUGS("ENVIRONMENT") << "Setting Day environment " << env_selection_to_string(env) << " with version(update type): " << env_version << LL_NEWLINE; + // code between LL_DEBUGS and LL_ENDL won't execute unless log is enabled + if (settings) + { + LLUUID asset_id = settings->getAssetId(); + if (asset_id.notNull()) + { + LL_CONT << "Asset id: " << asset_id << LL_NEWLINE; + } + + LLUUID id = settings->getId(); // Not in use? + if (id.notNull()) + { + LL_CONT << "Settings id: " << id << LL_NEWLINE; + } + + LL_CONT << "Name: " << settings->getName() << LL_NEWLINE + << "Type: " << settings->getSettingsType() << LL_NEWLINE + << "Flags: " << settings->getFlags(); // Not in use? + } + else + { + LL_CONT << "Empty settings!"; + } + LL_CONT << LL_ENDL; +} + +LLSettingsDay::ptr_t LLEnvironment::getEnvironmentDay(LLEnvironment::EnvSelection_t env) +{ + if ((env < ENV_EDIT) || (env > ENV_DEFAULT)) + { + LL_WARNS("ENVIRONMENT") << "Attempt to retrieve invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; + return LLSettingsDay::ptr_t(); + } + + DayInstance::ptr_t environment = getEnvironmentInstance(env); + + if (environment) + return environment->getDayCycle(); + + return LLSettingsDay::ptr_t(); +} + +LLSettingsDay::Seconds LLEnvironment::getEnvironmentDayLength(EnvSelection_t env) +{ + if ((env < ENV_EDIT) || (env > ENV_DEFAULT)) + { + LL_WARNS("ENVIRONMENT") << "Attempt to retrieve invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; + return LLSettingsDay::Seconds(0); + } + + DayInstance::ptr_t environment = getEnvironmentInstance(env); + + if (environment) + return environment->getDayLength(); + + return LLSettingsDay::Seconds(0); +} + +LLSettingsDay::Seconds LLEnvironment::getEnvironmentDayOffset(EnvSelection_t env) +{ + if ((env < ENV_EDIT) || (env > ENV_DEFAULT)) + { + LL_WARNS("ENVIRONMENT") << "Attempt to retrieve invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; + return LLSettingsDay::Seconds(0); + } + + DayInstance::ptr_t environment = getEnvironmentInstance(env); + if (environment) + return environment->getDayOffset(); + + return LLSettingsDay::Seconds(0); +} + + +LLEnvironment::fixedEnvironment_t LLEnvironment::getEnvironmentFixed(LLEnvironment::EnvSelection_t env, bool resolve) +{ + if ((env == ENV_CURRENT) || resolve) + { + fixedEnvironment_t fixed; + for (S32 idx = ((resolve) ? env : mSelectedEnvironment); idx < ENV_END; ++idx) + { + if (fixed.first && fixed.second) + break; + + if (idx == ENV_EDIT) + continue; // skip the edit environment. + + DayInstance::ptr_t environment = getEnvironmentInstance(static_cast<EnvSelection_t>(idx)); + if (environment) + { + if (!fixed.first) + fixed.first = environment->getSky(); + if (!fixed.second) + fixed.second = environment->getWater(); + } + } + + if (!fixed.first || !fixed.second) + LL_WARNS("ENVIRONMENT") << "Can not construct complete fixed environment. Missing Sky and/or Water." << LL_ENDL; + + return fixed; + } + + if ((env < ENV_EDIT) || (env > ENV_DEFAULT)) + { + LL_WARNS("ENVIRONMENT") << "Attempt to retrieve invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; + return fixedEnvironment_t(); + } + + DayInstance::ptr_t environment = getEnvironmentInstance(env); + + if (environment) + return fixedEnvironment_t(environment->getSky(), environment->getWater()); + + return fixedEnvironment_t(); +} + +LLEnvironment::DayInstance::ptr_t LLEnvironment::getSelectedEnvironmentInstance() +{ + for (S32 idx = mSelectedEnvironment; idx < ENV_DEFAULT; ++idx) + { + if (mEnvironments[idx]) + return mEnvironments[idx]; + } + + return mEnvironments[ENV_DEFAULT]; +} + +LLEnvironment::DayInstance::ptr_t LLEnvironment::getSharedEnvironmentInstance() +{ + for (S32 idx = ENV_PARCEL; idx < ENV_DEFAULT; ++idx) + { + if (mEnvironments[idx]) + return mEnvironments[idx]; + } + + return mEnvironments[ENV_DEFAULT]; +} + +void LLEnvironment::updateEnvironment(LLSettingsBase::Seconds transition, bool forced) +{ + DayInstance::ptr_t pinstance = getSelectedEnvironmentInstance(); + + if ((mCurrentEnvironment != pinstance) || forced) + { + if (transition != TRANSITION_INSTANT) + { + DayInstance::ptr_t trans = std::make_shared<DayTransition>( + mCurrentEnvironment->getSky(), mCurrentEnvironment->getWater(), pinstance, transition); + + trans->animate(); + + mCurrentEnvironment = trans; + } + else + { + mCurrentEnvironment = pinstance; + } + } +} + +LLVector4 LLEnvironment::toCFR(const LLVector3 vec) const +{ + LLVector4 vec_cfr(vec.mV[1], vec.mV[0], vec.mV[2], 0.0f); + return vec_cfr; +} + +LLVector4 LLEnvironment::toLightNorm(const LLVector3 vec) const +{ + LLVector4 vec_ogl(vec.mV[1], vec.mV[2], vec.mV[0], 0.0f); + return vec_ogl; +} + +LLVector3 LLEnvironment::getLightDirection() const +{ + LLSettingsSky::ptr_t psky = mCurrentEnvironment->getSky(); + if (!psky) + { + return LLVector3(0, 0, 1); + } + return psky->getLightDirection(); +} + +LLVector3 LLEnvironment::getSunDirection() const +{ + LLSettingsSky::ptr_t psky = mCurrentEnvironment->getSky(); + if (!psky) + { + return LLVector3(0, 0, 1); + } + return psky->getSunDirection(); +} + +LLVector3 LLEnvironment::getMoonDirection() const +{ + LLSettingsSky::ptr_t psky = mCurrentEnvironment->getSky(); + if (!psky) + { + return LLVector3(0, 0, -1); + } + return psky->getMoonDirection(); +} + +LLVector4 LLEnvironment::getLightDirectionCFR() const +{ + LLVector3 light_direction = getLightDirection(); + LLVector4 light_direction_cfr = toCFR(light_direction); + return light_direction_cfr; +} + +LLVector4 LLEnvironment::getSunDirectionCFR() const +{ + LLVector3 light_direction = getSunDirection(); + LLVector4 light_direction_cfr = toCFR(light_direction); + return light_direction_cfr; +} + +LLVector4 LLEnvironment::getMoonDirectionCFR() const +{ + LLVector3 light_direction = getMoonDirection(); + LLVector4 light_direction_cfr = toCFR(light_direction); + return light_direction_cfr; +} + +LLVector4 LLEnvironment::getClampedLightNorm() const +{ + LLVector3 light_direction = getLightDirection(); + if (light_direction.mV[2] < -0.1f) + { + light_direction.mV[2] = -0.1f; + } + return toLightNorm(light_direction); +} + +LLVector4 LLEnvironment::getClampedSunNorm() const +{ + LLVector3 light_direction = getSunDirection(); + if (light_direction.mV[2] < -0.1f) + { + light_direction.mV[2] = -0.1f; + } + return toLightNorm(light_direction); +} + +LLVector4 LLEnvironment::getClampedMoonNorm() const +{ + LLVector3 light_direction = getMoonDirection(); + if (light_direction.mV[2] < -0.1f) + { + light_direction.mV[2] = -0.1f; + } + return toLightNorm(light_direction); +} + +LLVector4 LLEnvironment::getRotatedLightNorm() const +{ + LLVector3 light_direction = getLightDirection(); + light_direction *= LLQuaternion(-mLastCamYaw, LLVector3(0.f, 1.f, 0.f)); + return toLightNorm(light_direction); +} + +//------------------------------------------------------------------------- +void LLEnvironment::update(const LLViewerCamera * cam) +{ + LL_RECORD_BLOCK_TIME(FTM_ENVIRONMENT_UPDATE); + //F32Seconds now(LLDate::now().secondsSinceEpoch()); + static LLFrameTimer timer; + + F32Seconds delta(timer.getElapsedTimeAndResetF32()); + + { + DayInstance::ptr_t keeper = mCurrentEnvironment; + // make sure the current environment does not go away until applyTimeDelta is done. + mCurrentEnvironment->applyTimeDelta(delta); + + } + // update clouds, sun, and general + updateCloudScroll(); + + // cache this for use in rotating the rotated light vec for shader param updates later... + mLastCamYaw = cam->getYaw() + SUN_DELTA_YAW; + + stop_glerror(); + + // *TODO: potential optimization - this block may only need to be + // executed some of the time. For example for water shaders only. + { + LLViewerShaderMgr::shader_iter shaders_iter, end_shaders; + end_shaders = LLViewerShaderMgr::instance()->endShaders(); + for (shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter) + { + if ((shaders_iter->mProgramObject != 0) + && (gPipeline.canUseWindLightShaders() + || shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER)) + { + shaders_iter->mUniformsDirty = TRUE; + } + } + } +} + +void LLEnvironment::updateCloudScroll() +{ + // This is a function of the environment rather than the sky, since it should + // persist through sky transitions. + static LLTimer s_cloud_timer; + + F64 delta_t = s_cloud_timer.getElapsedTimeAndResetF64(); + + if (mCurrentEnvironment->getSky() && !mCloudScrollPaused) + { + LLVector2 cloud_delta = static_cast<F32>(delta_t)* (mCurrentEnvironment->getSky()->getCloudScrollRate()) / 100.0; + mCloudScrollDelta += cloud_delta; + } + +} + +// static +void LLEnvironment::updateGLVariablesForSettings(LLGLSLShader *shader, const LLSettingsBase::ptr_t &psetting) +{ + LL_RECORD_BLOCK_TIME(FTM_SHADER_PARAM_UPDATE); + + //_WARNS("RIDER") << "----------------------------------------------------------------" << LL_ENDL; + LLSettingsBase::parammapping_t params = psetting->getParameterMap(); + for (auto &it: params) + { + LLSD value; + // legacy first since it contains ambient color and we prioritize value from legacy, see getAmbientColor() + if (psetting->mSettings.has(LLSettingsSky::SETTING_LEGACY_HAZE) && psetting->mSettings[LLSettingsSky::SETTING_LEGACY_HAZE].has(it.first)) + { + value = psetting->mSettings[LLSettingsSky::SETTING_LEGACY_HAZE][it.first]; + } + else if (psetting->mSettings.has(it.first)) + { + value = psetting->mSettings[it.first]; + } + else + { + // We need to reset shaders, use defaults + value = it.second.getDefaultValue(); + } + + LLSD::Type setting_type = value.type(); + stop_glerror(); + switch (setting_type) + { + case LLSD::TypeInteger: + shader->uniform1i(it.second.getShaderKey(), value.asInteger()); + //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << value << LL_ENDL; + break; + case LLSD::TypeReal: + shader->uniform1f(it.second.getShaderKey(), value.asReal()); + //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << value << LL_ENDL; + break; + + case LLSD::TypeBoolean: + shader->uniform1i(it.second.getShaderKey(), value.asBoolean() ? 1 : 0); + //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << value << LL_ENDL; + break; + + case LLSD::TypeArray: + { + LLVector4 vect4(value); + //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << vect4 << LL_ENDL; + shader->uniform4fv(it.second.getShaderKey(), 1, vect4.mV); + break; + } + + // case LLSD::TypeMap: + // case LLSD::TypeString: + // case LLSD::TypeUUID: + // case LLSD::TypeURI: + // case LLSD::TypeBinary: + // case LLSD::TypeDate: + default: + break; + } + stop_glerror(); + } + //_WARNS("RIDER") << "----------------------------------------------------------------" << LL_ENDL; + + psetting->applySpecial(shader); +} + +void LLEnvironment::updateShaderUniforms(LLGLSLShader *shader) +{ + updateGLVariablesForSettings(shader, mCurrentEnvironment->getWater()); + updateGLVariablesForSettings(shader, mCurrentEnvironment->getSky()); +} + +void LLEnvironment::recordEnvironment(S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envinfo, LLSettingsBase::Seconds transition) +{ + if (!gAgent.getRegion()) + { + return; + } + // mRegionId id can be null, no specification as to why and if it's valid so check valid ids only + if (gAgent.getRegion()->getRegionID() != envinfo->mRegionId && envinfo->mRegionId.notNull()) + { + LL_INFOS("ENVIRONMENT") << "Requested environmend region id: " << envinfo->mRegionId << " agent is on: " << gAgent.getRegion()->getRegionID() << LL_ENDL; + return; + } + + if (envinfo->mParcelId == INVALID_PARCEL_ID) + { + // the returned info applies to an entire region. + if (!envinfo->mDayCycle) + { + clearEnvironment(ENV_PARCEL); + setEnvironment(ENV_REGION, LLSettingsDay::GetDefaultAssetId(), TRANSITION_DEFAULT, envinfo->mEnvVersion); + updateEnvironment(); + } + else if (envinfo->mDayCycle->isTrackEmpty(LLSettingsDay::TRACK_WATER) + || envinfo->mDayCycle->isTrackEmpty(LLSettingsDay::TRACK_GROUND_LEVEL)) + { + LL_WARNS("ENVIRONMENT") << "Invalid day cycle for region" << LL_ENDL; + clearEnvironment(ENV_PARCEL); + setEnvironment(ENV_REGION, LLSettingsDay::GetDefaultAssetId(), TRANSITION_DEFAULT, envinfo->mEnvVersion); + updateEnvironment(); + } + else + { + mTrackAltitudes = envinfo->mAltitudes; + // update track selection based on new altitudes + mCurrentTrack = calculateSkyTrackForAltitude(gAgent.getPositionAgent().mV[VZ]); + + setEnvironment(ENV_REGION, envinfo->mDayCycle, envinfo->mDayLength, envinfo->mDayOffset, envinfo->mEnvVersion); + } + + LL_DEBUGS("ENVIRONMENT") << "Altitudes set to {" << mTrackAltitudes[0] << ", "<< mTrackAltitudes[1] << ", " << mTrackAltitudes[2] << ", " << mTrackAltitudes[3] << LL_ENDL; + } + else + { + LLParcel *parcel = LLViewerParcelMgr::instance().getAgentParcel(); + LL_DEBUGS("ENVIRONMENT") << "Have parcel environment #" << envinfo->mParcelId << LL_ENDL; + if (parcel && (parcel->getLocalID() != parcel_id)) + { + LL_DEBUGS("ENVIRONMENT") << "Requested parcel #" << parcel_id << " agent is on " << parcel->getLocalID() << LL_ENDL; + return; + } + + if (!envinfo->mDayCycle) + { + LL_DEBUGS("ENVIRONMENT") << "Clearing environment on parcel #" << parcel_id << LL_ENDL; + clearEnvironment(ENV_PARCEL); + } + else if (envinfo->mDayCycle->isTrackEmpty(LLSettingsDay::TRACK_WATER) + || envinfo->mDayCycle->isTrackEmpty(LLSettingsDay::TRACK_GROUND_LEVEL)) + { + LL_WARNS("ENVIRONMENT") << "Invalid day cycle for parcel #" << parcel_id << LL_ENDL; + clearEnvironment(ENV_PARCEL); + } + else + { + setEnvironment(ENV_PARCEL, envinfo->mDayCycle, envinfo->mDayLength, envinfo->mDayOffset, envinfo->mEnvVersion); + } + } + + updateEnvironment(transition); +} + +void LLEnvironment::adjustRegionOffset(F32 adjust) +{ + if (isExtendedEnvironmentEnabled()) + { + LL_WARNS("ENVIRONMENT") << "Attempt to adjust region offset on EEP region. Legacy regions only." << LL_ENDL; + } + + if (mEnvironments[ENV_REGION]) + { + F32 day_length = mEnvironments[ENV_REGION]->getDayLength(); + F32 day_offset = mEnvironments[ENV_REGION]->getDayOffset(); + + F32 day_adjustment = adjust * day_length; + + day_offset += day_adjustment; + if (day_offset < 0.0f) + day_offset = day_length + day_offset; + mEnvironments[ENV_REGION]->setDayOffset(LLSettingsBase::Seconds(day_offset)); + } +} + +//========================================================================= +void LLEnvironment::requestRegion(environment_apply_fn cb) +{ + requestParcel(INVALID_PARCEL_ID, cb); +} + +void LLEnvironment::updateRegion(const LLSettingsDay::ptr_t &pday, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + updateParcel(INVALID_PARCEL_ID, pday, day_length, day_offset, altitudes, cb); +} + +void LLEnvironment::updateRegion(const LLUUID &asset_id, std::string display_name, S32 track_num, S32 day_length, S32 day_offset, U32 flags, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + if (!isExtendedEnvironmentEnabled()) + { + LL_WARNS("ENVIRONMENT") << "attempt to apply asset id to region not supporting it." << LL_ENDL; + LLNotificationsUtil::add("NoEnvironmentSettings"); + return; + } + + updateParcel(INVALID_PARCEL_ID, asset_id, display_name, track_num, day_length, day_offset, flags, altitudes, cb); +} + +void LLEnvironment::updateRegion(const LLSettingsSky::ptr_t &psky, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + updateParcel(INVALID_PARCEL_ID, psky, day_length, day_offset, altitudes, cb); +} + +void LLEnvironment::updateRegion(const LLSettingsWater::ptr_t &pwater, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + updateParcel(INVALID_PARCEL_ID, pwater, day_length, day_offset, altitudes, cb); +} + + +void LLEnvironment::resetRegion(environment_apply_fn cb) +{ + resetParcel(INVALID_PARCEL_ID, cb); +} + +void LLEnvironment::requestParcel(S32 parcel_id, environment_apply_fn cb) +{ + if (!isExtendedEnvironmentEnabled()) + { /*TODO: When EEP is live on the entire grid, this can go away. */ + if (parcel_id == INVALID_PARCEL_ID) + { + if (!cb) + { + LLSettingsBase::Seconds transition = LLViewerParcelMgr::getInstance()->getTeleportInProgress() ? TRANSITION_FAST : TRANSITION_DEFAULT; + cb = [this, transition](S32 pid, EnvironmentInfo::ptr_t envinfo) + { + clearEnvironment(ENV_PARCEL); + recordEnvironment(pid, envinfo, transition); + }; + } + + LLEnvironmentRequest::initiate(cb); + } + else if (cb) + cb(parcel_id, EnvironmentInfo::ptr_t()); + return; + } + + if (!cb) + { + LLSettingsBase::Seconds transition = LLViewerParcelMgr::getInstance()->getTeleportInProgress() ? TRANSITION_FAST : TRANSITION_DEFAULT; + cb = [this, transition](S32 pid, EnvironmentInfo::ptr_t envinfo) { recordEnvironment(pid, envinfo, transition); }; + } + + std::string coroname = + LLCoros::instance().launch("LLEnvironment::coroRequestEnvironment", + [this, parcel_id, cb]() { coroRequestEnvironment(parcel_id, cb); }); +} + +void LLEnvironment::updateParcel(S32 parcel_id, const LLUUID &asset_id, std::string display_name, S32 track_num, S32 day_length, S32 day_offset, U32 flags, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + UpdateInfo::ptr_t updates(std::make_shared<UpdateInfo>(asset_id, display_name, day_length, day_offset, altitudes, flags)); + std::string coroname = + LLCoros::instance().launch("LLEnvironment::coroUpdateEnvironment", + [this, parcel_id, track_num, updates, cb]() { coroUpdateEnvironment(parcel_id, track_num, updates, cb); }); +} + +void LLEnvironment::onUpdateParcelAssetLoaded(LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, S32 parcel_id, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes) +{ + if (status) + { + LL_WARNS("ENVIRONMENT") << "Unable to get settings asset with id " << asset_id << "!" << LL_ENDL; + LLNotificationsUtil::add("FailedToLoadSettingsApply"); + return; + } + + LLSettingsDay::ptr_t pday; + + if (settings->getSettingsType() == "daycycle") + pday = std::static_pointer_cast<LLSettingsDay>(settings); + else + { + pday = createDayCycleFromEnvironment( (parcel_id == INVALID_PARCEL_ID) ? ENV_REGION : ENV_PARCEL, settings); + } + + if (!pday) + { + LL_WARNS("ENVIRONMENT") << "Unable to construct day around " << asset_id << "!" << LL_ENDL; + LLNotificationsUtil::add("FailedToBuildSettingsDay"); + return; + } + + updateParcel(parcel_id, pday, day_length, day_offset, altitudes); +} + +void LLEnvironment::updateParcel(S32 parcel_id, const LLSettingsSky::ptr_t &psky, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + LLSettingsDay::ptr_t pday = createDayCycleFromEnvironment((parcel_id == INVALID_PARCEL_ID) ? ENV_REGION : ENV_PARCEL, psky); + pday->setFlag(psky->getFlags()); + updateParcel(parcel_id, pday, day_length, day_offset, altitudes, cb); +} + +void LLEnvironment::updateParcel(S32 parcel_id, const LLSettingsWater::ptr_t &pwater, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + LLSettingsDay::ptr_t pday = createDayCycleFromEnvironment((parcel_id == INVALID_PARCEL_ID) ? ENV_REGION : ENV_PARCEL, pwater); + pday->setFlag(pwater->getFlags()); + updateParcel(parcel_id, pday, day_length, day_offset, altitudes, cb); +} + +void LLEnvironment::updateParcel(S32 parcel_id, const LLSettingsDay::ptr_t &pday, S32 track_num, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + UpdateInfo::ptr_t updates(std::make_shared<UpdateInfo>(pday, day_length, day_offset, altitudes)); + + std::string coroname = + LLCoros::instance().launch("LLEnvironment::coroUpdateEnvironment", + [this, parcel_id, track_num, updates, cb]() { coroUpdateEnvironment(parcel_id, track_num, updates, cb); }); +} + +void LLEnvironment::updateParcel(S32 parcel_id, const LLSettingsDay::ptr_t &pday, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + updateParcel(parcel_id, pday, NO_TRACK, day_length, day_offset, altitudes, cb); +} + + + +void LLEnvironment::resetParcel(S32 parcel_id, environment_apply_fn cb) +{ + std::string coroname = + LLCoros::instance().launch("LLEnvironment::coroResetEnvironment", + [this, parcel_id, cb]() { coroResetEnvironment(parcel_id, NO_TRACK, cb); }); +} + +void LLEnvironment::coroRequestEnvironment(S32 parcel_id, LLEnvironment::environment_apply_fn apply) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("ResetEnvironment", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + std::string url = gAgent.getRegionCapability("ExtEnvironment"); + if (url.empty()) + return; + + LL_DEBUGS("ENVIRONMENT") << "Requesting for parcel_id=" << parcel_id << LL_ENDL; + + if (parcel_id != INVALID_PARCEL_ID) + { + std::stringstream query; + + query << "?parcelid=" << parcel_id; + url += query.str(); + } + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + // results that come back may contain the new settings + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + if (!status) + { + LL_WARNS("ENVIRONMENT") << "Couldn't retrieve environment settings for " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL; + } + else if (LLApp::isExiting()) + { + return; + } + else + { + LLSD environment = result[KEY_ENVIRONMENT]; + if (environment.isDefined() && apply) + { + EnvironmentInfo::ptr_t envinfo = LLEnvironment::EnvironmentInfo::extract(environment); + apply(parcel_id, envinfo); + } + } + +} + +void LLEnvironment::coroUpdateEnvironment(S32 parcel_id, S32 track_no, UpdateInfo::ptr_t updates, environment_apply_fn apply) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("ResetEnvironment", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + std::string url = gAgent.getRegionCapability("ExtEnvironment"); + if (url.empty()) + return; + + LLSD body(LLSD::emptyMap()); + body[KEY_ENVIRONMENT] = LLSD::emptyMap(); + + if (track_no == NO_TRACK) + { // day length and offset are only applicable if we are addressing the entire day cycle. + if (updates->mDayLength > 0) + body[KEY_ENVIRONMENT][KEY_DAYLENGTH] = updates->mDayLength; + if (updates->mDayOffset > 0) + body[KEY_ENVIRONMENT][KEY_DAYOFFSET] = updates->mDayOffset; + + if ((parcel_id == INVALID_PARCEL_ID) && (updates->mAltitudes.size() == 3)) + { // only test for altitude changes if we are changing the region. + body[KEY_ENVIRONMENT][KEY_TRACKALTS] = LLSD::emptyArray(); + for (S32 i = 0; i < 3; ++i) + { + body[KEY_ENVIRONMENT][KEY_TRACKALTS][i] = updates->mAltitudes[i]; + } + } + } + + if (updates->mDayp) + body[KEY_ENVIRONMENT][KEY_DAYCYCLE] = updates->mDayp->getSettings(); + else if (!updates->mSettingsAsset.isNull()) + { + body[KEY_ENVIRONMENT][KEY_DAYASSET] = updates->mSettingsAsset; + if (!updates->mDayName.empty()) + body[KEY_ENVIRONMENT][KEY_DAYNAME] = updates->mDayName; + } + + body[KEY_ENVIRONMENT][KEY_FLAGS] = LLSD::Integer(updates->mFlags); + //_WARNS("ENVIRONMENT") << "Body = " << body << LL_ENDL; + + if ((parcel_id != INVALID_PARCEL_ID) || (track_no != NO_TRACK)) + { + std::stringstream query; + query << "?"; + + if (parcel_id != INVALID_PARCEL_ID) + { + query << "parcelid=" << parcel_id; + + if (track_no != NO_TRACK) + query << "&"; + } + if (track_no != NO_TRACK) + { + query << "trackno=" << track_no; + } + url += query.str(); + } + + LLSD result = httpAdapter->putAndSuspend(httpRequest, url, body); + // results that come back may contain the new settings + + LLSD notify; + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if ((!status) || !result["success"].asBoolean()) + { + LL_WARNS("ENVIRONMENT") << "Couldn't update Windlight settings for " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL; + + notify = LLSD::emptyMap(); + notify["FAIL_REASON"] = result["message"].asString(); + } + else if (LLApp::isExiting()) + { + return; + } + else + { + LLSD environment = result[KEY_ENVIRONMENT]; + if (environment.isDefined() && apply) + { + EnvironmentInfo::ptr_t envinfo = LLEnvironment::EnvironmentInfo::extract(environment); + apply(parcel_id, envinfo); + } + } + + if (!notify.isUndefined()) + { + LLNotificationsUtil::add("WLRegionApplyFail", notify); + //LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false); + } +} + +void LLEnvironment::coroResetEnvironment(S32 parcel_id, S32 track_no, environment_apply_fn apply) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("ResetEnvironment", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + std::string url = gAgent.getRegionCapability("ExtEnvironment"); + if (url.empty()) + return; + + if ((parcel_id != INVALID_PARCEL_ID) || (track_no != NO_TRACK)) + { + std::stringstream query; + query << "?"; + + if (parcel_id != INVALID_PARCEL_ID) + { + query << "parcelid=" << parcel_id; + + if (track_no != NO_TRACK) + query << "&"; + } + if (track_no != NO_TRACK) + { + query << "trackno=" << track_no; + } + url += query.str(); + } + + LLSD result = httpAdapter->deleteAndSuspend(httpRequest, url); + // results that come back may contain the new settings + + LLSD notify; + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if ((!status) || !result["success"].asBoolean()) + { + LL_WARNS("ENVIRONMENT") << "Couldn't reset Windlight settings in " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL; + + notify = LLSD::emptyMap(); + notify["FAIL_REASON"] = result["message"].asString(); + } + else if (LLApp::isExiting()) + { + return; + } + else + { + LLSD environment = result[KEY_ENVIRONMENT]; + if (environment.isDefined() && apply) + { + EnvironmentInfo::ptr_t envinfo = LLEnvironment::EnvironmentInfo::extract(environment); + apply(parcel_id, envinfo); + } + } + + if (!notify.isUndefined()) + { + LLNotificationsUtil::add("WLRegionApplyFail", notify); + //LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false); + } + +} + + +//========================================================================= + +LLEnvironment::EnvironmentInfo::EnvironmentInfo(): + mParcelId(INVALID_PARCEL_ID), + mRegionId(), + mDayLength(0), + mDayOffset(0), + mDayHash(0), + mDayCycle(), + mAltitudes({ { 0.0, 0.0, 0.0, 0.0 } }), + mIsDefault(false), + mIsLegacy(false), + mDayCycleName(), + mNameList(), + mEnvVersion(INVALID_PARCEL_ENVIRONMENT_VERSION) +{ +} + +LLEnvironment::EnvironmentInfo::ptr_t LLEnvironment::EnvironmentInfo::extract(LLSD environment) +{ + ptr_t pinfo = std::make_shared<EnvironmentInfo>(); + + pinfo->mIsDefault = environment.has(KEY_ISDEFAULT) ? environment[KEY_ISDEFAULT].asBoolean() : true; + pinfo->mParcelId = environment.has(KEY_PARCELID) ? environment[KEY_PARCELID].asInteger() : INVALID_PARCEL_ID; + pinfo->mRegionId = environment.has(KEY_REGIONID) ? environment[KEY_REGIONID].asUUID() : LLUUID::null; + pinfo->mIsLegacy = false; + + if (environment.has(KEY_TRACKALTS)) + { + for (int idx = 0; idx < 3; idx++) + { + pinfo->mAltitudes[idx+1] = environment[KEY_TRACKALTS][idx].asReal(); + } + pinfo->mAltitudes[0] = 0; + } + + if (environment.has(KEY_DAYCYCLE)) + { + pinfo->mDayCycle = LLSettingsVODay::buildFromEnvironmentMessage(environment[KEY_DAYCYCLE]); + pinfo->mDayLength = LLSettingsDay::Seconds(environment.has(KEY_DAYLENGTH) ? environment[KEY_DAYLENGTH].asInteger() : -1); + pinfo->mDayOffset = LLSettingsDay::Seconds(environment.has(KEY_DAYOFFSET) ? environment[KEY_DAYOFFSET].asInteger() : -1); + pinfo->mDayHash = environment.has(KEY_DAYHASH) ? environment[KEY_DAYHASH].asInteger() : 0; + } + else + { + pinfo->mDayLength = LLEnvironment::instance().getEnvironmentDayLength(ENV_REGION); + pinfo->mDayOffset = LLEnvironment::instance().getEnvironmentDayOffset(ENV_REGION); + } + + if (environment.has(KEY_DAYASSET)) + { + pinfo->mAssetId = environment[KEY_DAYASSET].asUUID(); + } + + if (environment.has(KEY_DAYNAMES)) + { + LLSD daynames = environment[KEY_DAYNAMES]; + if (daynames.isArray()) + { + pinfo->mDayCycleName.clear(); + for (S32 index = 0; index < pinfo->mNameList.size(); ++index) + { + pinfo->mNameList[index] = daynames[index].asString(); + } + } + else if (daynames.isString()) + { + for (std::string &name: pinfo->mNameList) + { + name.clear(); + } + + pinfo->mDayCycleName = daynames.asString(); + } + } + else if (pinfo->mDayCycle) + { + pinfo->mDayCycleName = pinfo->mDayCycle->getName(); + } + + + if (environment.has(KEY_ENVVERSION)) + { + LLSD version = environment[KEY_ENVVERSION]; + pinfo->mEnvVersion = version.asInteger(); + } + else + { + // can be used for region, but versions should be same + pinfo->mEnvVersion = pinfo->mIsDefault ? UNSET_PARCEL_ENVIRONMENT_VERSION : INVALID_PARCEL_ENVIRONMENT_VERSION; + } + + return pinfo; +} + + +LLEnvironment::EnvironmentInfo::ptr_t LLEnvironment::EnvironmentInfo::extractLegacy(LLSD legacy) +{ + if (!legacy.isArray() || !legacy[0].has("regionID")) + { + LL_WARNS("ENVIRONMENT") << "Invalid legacy settings for environment: " << legacy << LL_ENDL; + return ptr_t(); + } + + ptr_t pinfo = std::make_shared<EnvironmentInfo>(); + + pinfo->mIsDefault = false; + pinfo->mParcelId = INVALID_PARCEL_ID; + pinfo->mRegionId = legacy[0]["regionID"].asUUID(); + pinfo->mIsLegacy = true; + + pinfo->mDayLength = LLSettingsDay::DEFAULT_DAYLENGTH; + pinfo->mDayOffset = LLSettingsDay::DEFAULT_DAYOFFSET; + pinfo->mDayCycle = LLSettingsVODay::buildFromLegacyMessage(pinfo->mRegionId, legacy[1], legacy[2], legacy[3]); + if (pinfo->mDayCycle) + pinfo->mDayHash = pinfo->mDayCycle->getHash(); + + pinfo->mAltitudes[0] = 0; + pinfo->mAltitudes[2] = 10001; + pinfo->mAltitudes[3] = 10002; + pinfo->mAltitudes[4] = 10003; + + return pinfo; +} + +//========================================================================= +LLSettingsWater::ptr_t LLEnvironment::createWaterFromLegacyPreset(const std::string filename, LLSD &messages) +{ + std::string name(gDirUtilp->getBaseFileName(filename, true)); + std::string path(gDirUtilp->getDirName(filename)); + + LLSettingsWater::ptr_t water = LLSettingsVOWater::buildFromLegacyPresetFile(name, path, messages); + + if (!water) + { + messages["NAME"] = name; + messages["FILE"] = filename; + } + return water; +} + +LLSettingsSky::ptr_t LLEnvironment::createSkyFromLegacyPreset(const std::string filename, LLSD &messages) +{ + std::string name(gDirUtilp->getBaseFileName(filename, true)); + std::string path(gDirUtilp->getDirName(filename)); + + LLSettingsSky::ptr_t sky = LLSettingsVOSky::buildFromLegacyPresetFile(name, path, messages); + if (!sky) + { + messages["NAME"] = name; + messages["FILE"] = filename; + } + return sky; +} + +LLSettingsDay::ptr_t LLEnvironment::createDayCycleFromLegacyPreset(const std::string filename, LLSD &messages) +{ + std::string name(gDirUtilp->getBaseFileName(filename, true)); + std::string path(gDirUtilp->getDirName(filename)); + + LLSettingsDay::ptr_t day = LLSettingsVODay::buildFromLegacyPresetFile(name, path, messages); + if (!day) + { + messages["NAME"] = name; + messages["FILE"] = filename; + } + return day; +} + +LLSettingsDay::ptr_t LLEnvironment::createDayCycleFromEnvironment(EnvSelection_t env, LLSettingsBase::ptr_t settings) +{ + std::string type(settings->getSettingsType()); + + if (type == "daycycle") + return std::static_pointer_cast<LLSettingsDay>(settings); + + if ((env != ENV_PARCEL) && (env != ENV_REGION)) + { + LL_WARNS("ENVIRONMENT") << "May only create from parcel or region environment." << LL_ENDL; + return LLSettingsDay::ptr_t(); + } + + LLSettingsDay::ptr_t day = this->getEnvironmentDay(env); + if (!day && (env == ENV_PARCEL)) + { + day = this->getEnvironmentDay(ENV_REGION); + } + + if (!day) + { + LL_WARNS("ENVIRONMENT") << "Could not retrieve existing day settings." << LL_ENDL; + return LLSettingsDay::ptr_t(); + } + + day = day->buildClone(); + + if (type == "sky") + { + for (S32 idx = 1; idx < LLSettingsDay::TRACK_MAX; ++idx) + day->clearCycleTrack(idx); + day->setSettingsAtKeyframe(settings, 0.0f, 1); + } + else if (type == "water") + { + day->clearCycleTrack(LLSettingsDay::TRACK_WATER); + day->setSettingsAtKeyframe(settings, 0.0f, LLSettingsDay::TRACK_WATER); + } + + return day; +} + +void LLEnvironment::onAgentPositionHasChanged(const LLVector3 &localpos) +{ + S32 trackno = calculateSkyTrackForAltitude(localpos.mV[VZ]); + if (trackno == mCurrentTrack) + return; + + mCurrentTrack = trackno; + + LLViewerRegion* cur_region = gAgent.getRegion(); + if (!cur_region || !cur_region->capabilitiesReceived()) + { + // Environment not ready, environment will be updated later, don't cause 'blend' yet. + // But keep mCurrentTrack updated in case we won't get new altitudes for some reason + return; + } + + for (S32 env = ENV_LOCAL; env < ENV_DEFAULT; ++env) + { + if (mEnvironments[env]) + mEnvironments[env]->setSkyTrack(mCurrentTrack); + } +} + +S32 LLEnvironment::calculateSkyTrackForAltitude(F64 altitude) +{ + auto it = std::find_if_not(mTrackAltitudes.begin(), mTrackAltitudes.end(), [altitude](F32 test) { return altitude > test; }); + + if (it == mTrackAltitudes.begin()) + return 1; + else if (it == mTrackAltitudes.end()) + return 4; + + return std::min(static_cast<S32>(std::distance(mTrackAltitudes.begin(), it)), 4); +} + +//------------------------------------------------------------------------- +void LLEnvironment::handleEnvironmentPush(LLSD &message) +{ + // Log the experience message + LLExperienceLog::instance().handleExperienceMessage(message); + + std::string action = message[KEY_ACTION].asString(); + LLUUID experience_id = message[KEY_EXPERIENCEID].asUUID(); + LLSD action_data = message[KEY_ACTIONDATA]; + F32 transition_time = action_data[KEY_TRANSITIONTIME].asReal(); + + //TODO: Check here that the viewer thinks the experience is still valid. + + + if (action == ACTION_CLEARENVIRONMENT) + { + handleEnvironmentPushClear(experience_id, action_data, transition_time); + } + else if (action == ACTION_PUSHFULLENVIRONMENT) + { + handleEnvironmentPushFull(experience_id, action_data, transition_time); + } + else if (action == ACTION_PUSHPARTIALENVIRONMENT) + { + handleEnvironmentPushPartial(experience_id, action_data, transition_time); + } + else + { + LL_WARNS("ENVIRONMENT", "GENERICMESSAGES") << "Unknown environment push action '" << action << "'" << LL_ENDL; + } +} + +void LLEnvironment::handleEnvironmentPushClear(LLUUID experience_id, LLSD &message, F32 transition) +{ + clearExperienceEnvironment(experience_id, LLSettingsBase::Seconds(transition)); +} + +void LLEnvironment::handleEnvironmentPushFull(LLUUID experience_id, LLSD &message, F32 transition) +{ + LLUUID asset_id(message[KEY_ASSETID].asUUID()); + + setExperienceEnvironment(experience_id, asset_id, LLSettingsBase::Seconds(transition)); +} + +void LLEnvironment::handleEnvironmentPushPartial(LLUUID experience_id, LLSD &message, F32 transition) +{ + LLSD settings(message["settings"]); + + if (settings.isUndefined()) + return; + + setExperienceEnvironment(experience_id, settings, LLSettingsBase::Seconds(transition)); +} + +void LLEnvironment::clearExperienceEnvironment(LLUUID experience_id, LLSettingsBase::Seconds transition_time) +{ + DayInjection::ptr_t injection = std::dynamic_pointer_cast<DayInjection>(getEnvironmentInstance(ENV_PUSH)); + if (injection) + { + injection->clearInjections(experience_id, transition_time); + } + +} + +void LLEnvironment::setSharedEnvironment() +{ + clearEnvironment(LLEnvironment::ENV_LOCAL); + setSelectedEnvironment(LLEnvironment::ENV_LOCAL); + updateEnvironment(); +} + +void LLEnvironment::setExperienceEnvironment(LLUUID experience_id, LLUUID asset_id, F32 transition_time) +{ + LLSettingsVOBase::getSettingsAsset(asset_id, + [this, experience_id, transition_time](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) + { + onSetExperienceEnvAssetLoaded(experience_id, settings, transition_time, status); + }); + + +} + +void LLEnvironment::onSetExperienceEnvAssetLoaded(LLUUID experience_id, LLSettingsBase::ptr_t settings, F32 transition_time, S32 status) +{ + DayInjection::ptr_t environment = std::dynamic_pointer_cast<DayInjection>(getEnvironmentInstance(ENV_PUSH)); + bool updateenvironment(false); + + if (!settings || status) + { + LLSD args; + args["NAME"] = experience_id.asString(); + LLNotificationsUtil::add("FailedToFindSettings", args); + return; + } + + if (!environment) + { + environment = std::dynamic_pointer_cast<DayInjection>(getEnvironmentInstance(ENV_PUSH, true)); + updateenvironment = true; + } + + if (settings->getSettingsType() == "daycycle") + { + environment->setInjectedDay(std::static_pointer_cast<LLSettingsDay>(settings), experience_id, LLSettingsBase::Seconds(transition_time)); + } + else if (settings->getSettingsType() == "sky") + { + environment->setInjectedSky(std::static_pointer_cast<LLSettingsSky>(settings), experience_id, LLSettingsBase::Seconds(transition_time)); + } + else if (settings->getSettingsType() == "water") + { + environment->setInjectedWater(std::static_pointer_cast<LLSettingsWater>(settings), experience_id, LLSettingsBase::Seconds(transition_time)); + } + + if (updateenvironment) + updateEnvironment(TRANSITION_INSTANT, true); +} + + +void LLEnvironment::setExperienceEnvironment(LLUUID experience_id, LLSD data, F32 transition_time) +{ + LLSD sky(data["sky"]); + LLSD water(data["water"]); + + if (sky.isUndefined() && water.isUndefined()) + { + clearExperienceEnvironment(experience_id, LLSettingsBase::Seconds(transition_time)); + return; + } + + DayInjection::ptr_t environment = std::dynamic_pointer_cast<DayInjection>(getEnvironmentInstance(ENV_PUSH)); + bool updateenvironment(false); + + if (!environment) + { + environment = std::dynamic_pointer_cast<DayInjection>(getEnvironmentInstance(ENV_PUSH, true)); + updateenvironment = true; + } + + if (!sky.isUndefined()) + { + environment->injectSkySettings(sky, experience_id, LLSettingsBase::Seconds(transition_time)); + } + + if (!water.isUndefined()) + { + environment->injectWaterSettings(sky, experience_id, LLSettingsBase::Seconds(transition_time)); + } + + if (updateenvironment) + updateEnvironment(TRANSITION_INSTANT, true); + +} + +void LLEnvironment::listenExperiencePump(const LLSD &message) +{ + LLUUID experience_id = message["experience"]; + LLSD data = message[experience_id.asString()]; + std::string permission(data["permission"].asString()); + + if ((permission == "Forget") || (permission == "Block")) + { + clearExperienceEnvironment(experience_id, (permission == "Block") ? TRANSITION_INSTANT : TRANSITION_FAST); + } +} + +//========================================================================= +LLEnvironment::DayInstance::DayInstance(EnvSelection_t env) : + mDayCycle(), + mSky(), + mWater(), + mDayLength(LLSettingsDay::DEFAULT_DAYLENGTH), + mDayOffset(LLSettingsDay::DEFAULT_DAYOFFSET), + mBlenderSky(), + mBlenderWater(), + mInitialized(false), + mSkyTrack(1), + mEnv(env), + mAnimateFlags(0) +{ } + + +LLEnvironment::DayInstance::ptr_t LLEnvironment::DayInstance::clone() const +{ + ptr_t environment = std::make_shared<DayInstance>(mEnv); + + environment->mDayCycle = mDayCycle; + environment->mSky = mSky; + environment->mWater = mWater; + environment->mDayLength = mDayLength; + environment->mDayOffset = mDayOffset; + environment->mBlenderSky = mBlenderSky; + environment->mBlenderWater = mBlenderWater; + environment->mInitialized = mInitialized; + environment->mSkyTrack = mSkyTrack; + environment->mAnimateFlags = mAnimateFlags; + + return environment; +} + +bool LLEnvironment::DayInstance::applyTimeDelta(const LLSettingsBase::Seconds& delta) +{ + ptr_t keeper(shared_from_this()); // makes sure that this does not go away while it is being worked on. + + bool changed(false); + if (!mInitialized) + initialize(); + + if (mBlenderSky) + changed |= mBlenderSky->applyTimeDelta(delta); + if (mBlenderWater) + changed |= mBlenderWater->applyTimeDelta(delta); + return changed; +} + +void LLEnvironment::DayInstance::setDay(const LLSettingsDay::ptr_t &pday, LLSettingsDay::Seconds daylength, LLSettingsDay::Seconds dayoffset) +{ + mInitialized = false; + + mAnimateFlags = 0; + + mDayCycle = pday; + mDayLength = daylength; + mDayOffset = dayoffset; + + mBlenderSky.reset(); + mBlenderWater.reset(); + + mSky = LLSettingsVOSky::buildDefaultSky(); + mWater = LLSettingsVOWater::buildDefaultWater(); + + animate(); +} + + +void LLEnvironment::DayInstance::setSky(const LLSettingsSky::ptr_t &psky) +{ + mInitialized = false; + + bool different_sky = mSky != psky; + + mSky = psky; + mSky->mReplaced |= different_sky; + mSky->update(); + mBlenderSky.reset(); + + if (gAtmosphere) + { + AtmosphericModelSettings settings; + LLEnvironment::getAtmosphericModelSettings(settings, psky); + gAtmosphere->configureAtmosphericModel(settings); + } +} + +void LLEnvironment::DayInstance::setWater(const LLSettingsWater::ptr_t &pwater) +{ + mInitialized = false; + + bool different_water = mWater != pwater; + mWater = pwater; + mWater->mReplaced |= different_water; + mWater->update(); + mBlenderWater.reset(); +} + +void LLEnvironment::DayInstance::initialize() +{ + mInitialized = true; + + if (!mWater) + mWater = LLSettingsVOWater::buildDefaultWater(); + if (!mSky) + mSky = LLSettingsVOSky::buildDefaultSky(); +} + +void LLEnvironment::DayInstance::clear() +{ + mDayCycle.reset(); + mSky.reset(); + mWater.reset(); + mDayLength = LLSettingsDay::DEFAULT_DAYLENGTH; + mDayOffset = LLSettingsDay::DEFAULT_DAYOFFSET; + mBlenderSky.reset(); + mBlenderWater.reset(); + mSkyTrack = 1; +} + +void LLEnvironment::DayInstance::setSkyTrack(S32 trackno) +{ + mSkyTrack = trackno; + if (mBlenderSky) + { + mBlenderSky->switchTrack(trackno, 0.0); + } +} + +void LLEnvironment::DayInstance::setBlenders(const LLSettingsBlender::ptr_t &skyblend, const LLSettingsBlender::ptr_t &waterblend) +{ + mBlenderSky = skyblend; + mBlenderWater = waterblend; +} + +LLSettingsBase::TrackPosition LLEnvironment::DayInstance::getProgress() const +{ + LLSettingsBase::Seconds now(LLDate::now().secondsSinceEpoch()); + now += mDayOffset; + + if ((mDayLength <= 0) || !mDayCycle) + return -1.0f; // no actual day cycle. + + return convert_time_to_position(now, mDayLength); +} + +LLSettingsBase::TrackPosition LLEnvironment::DayInstance::secondsToKeyframe(LLSettingsDay::Seconds seconds) +{ + return convert_time_to_position(seconds, mDayLength); +} + +void LLEnvironment::DayInstance::animate() +{ + LLSettingsBase::Seconds now(LLDate::now().secondsSinceEpoch()); + + now += mDayOffset; + + if (!mDayCycle) + return; + + if (!(mAnimateFlags & NO_ANIMATE_WATER)) + { + LLSettingsDay::CycleTrack_t &wtrack = mDayCycle->getCycleTrack(0); + + if (wtrack.empty()) + { + mWater.reset(); + mBlenderWater.reset(); + } + else + { + mWater = LLSettingsVOWater::buildDefaultWater(); + mBlenderWater = std::make_shared<LLTrackBlenderLoopingTime>(mWater, mDayCycle, 0, + mDayLength, mDayOffset, DEFAULT_UPDATE_THRESHOLD); + } + } + + if (!(mAnimateFlags & NO_ANIMATE_SKY)) + { + // sky, initialize to track 1 + LLSettingsDay::CycleTrack_t &track = mDayCycle->getCycleTrack(1); + + if (track.empty()) + { + mSky.reset(); + mBlenderSky.reset(); + } + else + { + mSky = LLSettingsVOSky::buildDefaultSky(); + mBlenderSky = std::make_shared<LLTrackBlenderLoopingTime>(mSky, mDayCycle, 1, + mDayLength, mDayOffset, DEFAULT_UPDATE_THRESHOLD); + mBlenderSky->switchTrack(mSkyTrack, 0.0); + } + } +} + +//------------------------------------------------------------------------- +LLEnvironment::DayTransition::DayTransition(const LLSettingsSky::ptr_t &skystart, + const LLSettingsWater::ptr_t &waterstart, LLEnvironment::DayInstance::ptr_t &end, LLSettingsDay::Seconds time) : + DayInstance(ENV_NONE), + mStartSky(skystart), + mStartWater(waterstart), + mNextInstance(end), + mTransitionTime(time) +{ + +} + +bool LLEnvironment::DayTransition::applyTimeDelta(const LLSettingsBase::Seconds& delta) +{ + bool changed(false); + + changed = mNextInstance->applyTimeDelta(delta); + changed |= DayInstance::applyTimeDelta(delta); + return changed; +} + +void LLEnvironment::DayTransition::animate() +{ + mNextInstance->animate(); + + mWater = mStartWater->buildClone(); + mBlenderWater = std::make_shared<LLSettingsBlenderTimeDelta>(mWater, mStartWater, mNextInstance->getWater(), mTransitionTime); + mBlenderWater->setOnFinished( + [this](LLSettingsBlender::ptr_t blender) { + mBlenderWater.reset(); + + if (!mBlenderSky && !mBlenderWater) + LLEnvironment::instance().mCurrentEnvironment = mNextInstance; + else + setWater(mNextInstance->getWater()); + }); + + mSky = mStartSky->buildClone(); + mBlenderSky = std::make_shared<LLSettingsBlenderTimeDelta>(mSky, mStartSky, mNextInstance->getSky(), mTransitionTime); + mBlenderSky->setOnFinished( + [this](LLSettingsBlender::ptr_t blender) { + mBlenderSky.reset(); + + if (!mBlenderSky && !mBlenderWater) + LLEnvironment::instance().mCurrentEnvironment = mNextInstance; + else + setSky(mNextInstance->getSky()); + }); +} + +void LLEnvironment::saveToSettings() +{ + std::string user_dir = gDirUtilp->getLindenUserDir(); + if (user_dir.empty()) + { + // not logged in + return; + } + bool has_data = false; + + if (gSavedSettings.getBOOL("EnvironmentPersistAcrossLogin")) + { + DayInstance::ptr_t environment = getEnvironmentInstance(ENV_LOCAL); + if (environment) + { + // Environment is 'layered'. No data in ENV_LOCAL means we are using parcel/region + // Store local environment for next session + LLSD env_data; + + LLSettingsDay::ptr_t day = environment->getDayCycle(); + if (day) + { + const std::string name = day->getName(); + const LLUUID asset_id = day->getAssetId(); + if (asset_id.notNull()) + { + // just save the id + env_data["day_id"] = asset_id; + env_data["day_length"] = LLSD::Integer(environment->getDayLength()); + env_data["day_offset"] = LLSD::Integer(environment->getDayOffset()); + has_data = true; + } + else if (!name.empty() && name != LLSettingsBase::DEFAULT_SETTINGS_NAME) + { + // This setting was created locally and was not saved + // The only option is to save the whole thing + env_data["day_llsd"] = day->getSettings(); + env_data["day_length"] = LLSD::Integer(environment->getDayLength()); + env_data["day_offset"] = LLSD::Integer(environment->getDayOffset()); + has_data = true; + } + } + + LLSettingsSky::ptr_t sky = environment->getSky(); + if ((environment->getFlags() & DayInstance::NO_ANIMATE_SKY) && sky) + { + const std::string name = sky->getName(); + const LLUUID asset_id = sky->getAssetId(); + if (asset_id.notNull()) + { + // just save the id + env_data["sky_id"] = asset_id; + has_data = true; + } + else if (!name.empty() && name != LLSettingsBase::DEFAULT_SETTINGS_NAME) + { + // This setting was created locally and was not saved + // The only option is to save the whole thing + env_data["sky_llsd"] = sky->getSettings(); + has_data = true; + } + has_data = true; + } + + LLSettingsWater::ptr_t water = environment->getWater(); + if ((environment->getFlags() & DayInstance::NO_ANIMATE_WATER) && water) + { + const std::string name = water->getName(); + const LLUUID asset_id = water->getAssetId(); + if (asset_id.notNull()) + { + // just save the id + env_data["water_id"] = asset_id; + has_data = true; + } + else if (!name.empty() && name != LLSettingsBase::DEFAULT_SETTINGS_NAME) + { + // This setting was created locally and was not saved + // The only option is to save the whole thing + env_data["water_llsd"] = water->getSettings(); + has_data = true; + } + } + + std::string user_filepath = user_dir + gDirUtilp->getDirDelimiter() + LOCAL_ENV_STORAGE_FILE; + llofstream out(user_filepath.c_str(), std::ios_base::out | std::ios_base::binary); + if (out.good()) + { + LLSDSerialize::toBinary(env_data, out); + out.close(); + } + else + { + LL_WARNS("ENVIRONMENT") << "Unable to open " << user_filepath << " for output." << LL_ENDL; + } + } + } + + if (!has_data) + { + LLFile::remove(user_dir + gDirUtilp->getDirDelimiter() + LOCAL_ENV_STORAGE_FILE, ENOENT); + } +} + +void LLEnvironment::loadSkyWaterFromSettings(const LLSD &env_data, bool &valid, bool &assets_present) +{ + if (env_data.has("sky_id")) + { + // causes asset loaded callback and an update + setEnvironment(ENV_LOCAL, env_data["sky_id"].asUUID()); + valid = true; + assets_present = true; + } + else if (env_data.has("sky_llsd")) + { + LLSettingsSky::ptr_t sky = LLSettingsVOSky::buildSky(env_data["sky_llsd"]); + setEnvironment(ENV_LOCAL, sky); + valid = true; + } + + if (env_data.has("water_id")) + { + // causes asset loaded callback and an update + setEnvironment(ENV_LOCAL, env_data["water_id"].asUUID()); + valid = true; + assets_present = true; + } + else if (env_data.has("water_llsd")) + { + LLSettingsWater::ptr_t sky = LLSettingsVOWater::buildWater(env_data["water_llsd"]); + setEnvironment(ENV_LOCAL, sky); + valid = true; + } +} + +bool LLEnvironment::loadFromSettings() +{ + if (!gSavedSettings.getBOOL("EnvironmentPersistAcrossLogin")) + { + return false; + } + + std::string user_path = gDirUtilp->getLindenUserDir(); + if (user_path.empty()) + { + LL_WARNS("ENVIRONMENT") << "Can't load previous environment, Environment was initialized before user logged in" << LL_ENDL; + return false; + } + std::string user_filepath(user_path + gDirUtilp->getDirDelimiter() + LOCAL_ENV_STORAGE_FILE); + if (!gDirUtilp->fileExists(user_filepath)) + { + // No previous environment + return false; + } + + LLSD env_data; + llifstream file(user_filepath.c_str(), std::ios_base::in | std::ios_base::binary); + if (file.is_open()) + { + LLSDSerialize::fromBinary(env_data, file, LLSDSerialize::SIZE_UNLIMITED); + if (env_data.isUndefined()) + { + LL_WARNS("ENVIRONMENT") << "error loading " << user_filepath << LL_ENDL; + return false; + } + else + { + LL_INFOS("ENVIRONMENT") << "Loaded previous session environment from: " << user_filepath << LL_ENDL; + } + file.close(); + } + else + { + LL_INFOS("ENVIRONMENT") << "Unable to open previous session environment file " << user_filepath << LL_ENDL; + } + + if (!env_data.isMap() || env_data.emptyMap()) + { + LL_DEBUGS("ENVIRONMENT") << "Empty map loaded from: " << user_filepath << LL_ENDL; + return false; + } + + bool valid = false; + bool has_assets = false; + + if (env_data.has("day_id")) + { + LLUUID assetId = env_data["day_id"].asUUID(); + + LLSettingsVOBase::getSettingsAsset(assetId, + [this, env_data](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) + { + // Day should be always applied first, + // otherwise it will override sky or water that was set earlier + // so wait for asset to load before applying sky/water + onSetEnvAssetLoaded(ENV_LOCAL, asset_id, settings, TRANSITION_DEFAULT, status, NO_VERSION); + bool valid = false, has_assets = false; + loadSkyWaterFromSettings(env_data, valid, has_assets); + if (!has_assets && valid) + { + // Settings were loaded from file without having an asset, needs update + // otherwise update will be done by asset callback + updateEnvironment(TRANSITION_DEFAULT, true); + } + }); + // bail early, everything have to be done at callback + return true; + } + else if (env_data.has("day_llsd")) + { + S32 length = env_data["day_length"].asInteger(); + S32 offset = env_data["day_offset"].asInteger(); + LLSettingsDay::ptr_t pday = LLSettingsVODay::buildDay(env_data["day_llsd"]); + setEnvironment(ENV_LOCAL, pday, LLSettingsDay::Seconds(length), LLSettingsDay::Seconds(offset)); + valid = true; + } + + loadSkyWaterFromSettings(env_data, valid, has_assets); + + if (valid && !has_assets) + { + // Settings were loaded from file without having an asset, needs update + // otherwise update will be done by asset callback + updateEnvironment(TRANSITION_DEFAULT, true); + } + return valid; +} + +void LLEnvironment::saveBeaconsState() +{ + if (mEditorCounter == 0) + { + mShowSunBeacon = gSavedSettings.getBOOL("sunbeacon"); + mShowMoonBeacon = gSavedSettings.getBOOL("moonbeacon"); + } + ++mEditorCounter; +} +void LLEnvironment::revertBeaconsState() +{ + --mEditorCounter; + if (mEditorCounter == 0) + { + gSavedSettings.setBOOL("sunbeacon", mShowSunBeacon && gSavedSettings.getBOOL("sunbeacon")); + gSavedSettings.setBOOL("moonbeacon", mShowMoonBeacon && gSavedSettings.getBOOL("moonbeacon")); + } +} + +//========================================================================= +LLTrackBlenderLoopingManual::LLTrackBlenderLoopingManual(const LLSettingsBase::ptr_t &target, const LLSettingsDay::ptr_t &day, S32 trackno) : + LLSettingsBlender(target, LLSettingsBase::ptr_t(), LLSettingsBase::ptr_t()), + mDay(day), + mTrackNo(trackno), + mPosition(0.0) +{ + LLSettingsDay::TrackBound_t initial = getBoundingEntries(mPosition); + + if (initial.first != mEndMarker) + { // No frames in track + mInitial = (*initial.first).second; + mFinal = (*initial.second).second; + + LLSD initSettings = mInitial->getSettings(); + mTarget->replaceSettings(initSettings); + } +} + +LLSettingsBase::BlendFactor LLTrackBlenderLoopingManual::setPosition(const LLSettingsBase::TrackPosition& position) +{ + mPosition = llclamp(position, 0.0f, 1.0f); + + LLSettingsDay::TrackBound_t bounds = getBoundingEntries(mPosition); + + if (bounds.first == mEndMarker) + { // No frames in track. + return 0.0; + } + + mInitial = (*bounds.first).second; + mFinal = (*bounds.second).second; + + F64 spanLength = getSpanLength(bounds); + + F64 spanPos = ((mPosition < (*bounds.first).first) ? (mPosition + 1.0) : mPosition) - (*bounds.first).first; + + if (spanPos > spanLength) + { + // we are clamping position to 0-1 and spanLength is 1 + // so don't account for case of spanPos == spanLength + spanPos = fmod(spanPos, spanLength); + } + + F64 blendf = spanPos / spanLength; + return LLSettingsBlender::setBlendFactor(blendf); +} + +void LLTrackBlenderLoopingManual::switchTrack(S32 trackno, const LLSettingsBase::TrackPosition& position) +{ + mTrackNo = trackno; + + LLSettingsBase::TrackPosition useposition = (position < 0.0) ? mPosition : position; + + setPosition(useposition); +} + +LLSettingsDay::TrackBound_t LLTrackBlenderLoopingManual::getBoundingEntries(F64 position) +{ + LLSettingsDay::CycleTrack_t &wtrack = mDay->getCycleTrack(mTrackNo); + + mEndMarker = wtrack.end(); + + LLSettingsDay::TrackBound_t bounds = get_bounding_entries(wtrack, position); + return bounds; +} + +F64 LLTrackBlenderLoopingManual::getSpanLength(const LLSettingsDay::TrackBound_t &bounds) const +{ + return get_wrapping_distance((*bounds.first).first, (*bounds.second).first); +} + +//========================================================================= +namespace +{ + DayInjection::DayInjection(LLEnvironment::EnvSelection_t env): + LLEnvironment::DayInstance(env), + mBaseDayInstance(), + mInjectedSky(), + mInjectedWater(), + mActiveExperiences(), + mDayExperience(), + mSkyExperience(), + mWaterExperience(), + mEnvChangeConnection(), + mParcelChangeConnection() + { + mInjectedSky = std::make_shared<LLSettingsInjectedSky>(LLEnvironment::instance().getCurrentSky()); + mInjectedWater = std::make_shared<LLSettingsInjectedWater>(LLEnvironment::instance().getCurrentWater()); + mBaseDayInstance = LLEnvironment::instance().getSharedEnvironmentInstance(); + mSky = mInjectedSky; + mWater = mInjectedWater; + + mEnvChangeConnection = LLEnvironment::instance().setEnvironmentChanged([this](LLEnvironment::EnvSelection_t env, S32) { onEnvironmentChanged(env); }); + mParcelChangeConnection = gAgent.addParcelChangedCallback([this]() { onParcelChange(); }); + } + + DayInjection::~DayInjection() + { + if (mEnvChangeConnection.connected()) + mEnvChangeConnection.disconnect(); + if (mParcelChangeConnection.connected()) + mParcelChangeConnection.disconnect(); + } + + + bool DayInjection::applyTimeDelta(const LLSettingsBase::Seconds& delta) + { + bool changed(false); + + if (mBaseDayInstance) + changed |= mBaseDayInstance->applyTimeDelta(delta); + mInjectedSky->applyInjections(delta); + mInjectedWater->applyInjections(delta); + changed |= LLEnvironment::DayInstance::applyTimeDelta(delta); + if (changed) + { + mInjectedSky->setDirtyFlag(true); + mInjectedWater->setDirtyFlag(true); + } + mInjectedSky->update(); + mInjectedWater->update(); + + if (!hasInjections()) + { // There are no injections being managed. This should really go away. + LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_PUSH); + LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); + } + + return changed; + } + + void DayInjection::setBaseDayInstance(const LLEnvironment::DayInstance::ptr_t &baseday) + { + mBaseDayInstance = baseday; + + if (mSkyExperience.isNull()) + mInjectedSky->setSource(mBaseDayInstance->getSky()); + if (mWaterExperience.isNull()) + mInjectedWater->setSource(mBaseDayInstance->getWater()); + } + + + bool DayInjection::hasInjections() const + { + return (!mSkyExperience.isNull() || !mWaterExperience.isNull() || !mDayExperience.isNull() || + mBlenderSky || mBlenderWater || mInjectedSky->hasInjections() || mInjectedWater->hasInjections()); + } + + + void DayInjection::testExperiencesOnParcel(S32 parcel_id) + { + LLCoros::instance().launch("DayInjection::testExperiencesOnParcel", + [this, parcel_id]() { DayInjection::testExperiencesOnParcelCoro(std::static_pointer_cast<DayInjection>(this->shared_from_this()), parcel_id); }); + + } + + void DayInjection::setInjectedDay(const LLSettingsDay::ptr_t &pday, LLUUID experience_id, LLSettingsBase::Seconds transition) + { + mSkyExperience = experience_id; + mWaterExperience = experience_id; + mDayExperience = experience_id; + + mBaseDayInstance = mBaseDayInstance->clone(); + mBaseDayInstance->setEnvironmentSelection(LLEnvironment::ENV_NONE); + mBaseDayInstance->setDay(pday, mBaseDayInstance->getDayLength(), mBaseDayInstance->getDayOffset()); + animateSkyChange(mBaseDayInstance->getSky(), transition); + animateWaterChange(mBaseDayInstance->getWater(), transition); + + mActiveExperiences.insert(experience_id); + } + + void DayInjection::setInjectedSky(const LLSettingsSky::ptr_t &psky, LLUUID experience_id, LLSettingsBase::Seconds transition) + { + mSkyExperience = experience_id; + mActiveExperiences.insert(experience_id); + checkExperience(); + animateSkyChange(psky, transition); + } + + void DayInjection::setInjectedWater(const LLSettingsWater::ptr_t &pwater, LLUUID experience_id, LLSettingsBase::Seconds transition) + { + mWaterExperience = experience_id; + mActiveExperiences.insert(experience_id); + checkExperience(); + animateWaterChange(pwater, transition); + } + + void DayInjection::injectSkySettings(LLSD settings, LLUUID experience_id, LLSettingsBase::Seconds transition) + { + mInjectedSky->injectExperienceValues(settings, experience_id, transition); + mActiveExperiences.insert(experience_id); + } + + void DayInjection::injectWaterSettings(LLSD settings, LLUUID experience_id, LLSettingsBase::Seconds transition) + { + mInjectedWater->injectExperienceValues(settings, experience_id, transition); + mActiveExperiences.insert(experience_id); + } + + void DayInjection::clearInjections(LLUUID experience_id, LLSettingsBase::Seconds transition_time) + { + if ((experience_id.isNull() && !mDayExperience.isNull()) || (experience_id == mDayExperience)) + { + mDayExperience.setNull(); + if (mSkyExperience == experience_id) + mSkyExperience.setNull(); + if (mWaterExperience == experience_id) + mWaterExperience.setNull(); + + mBaseDayInstance = LLEnvironment::instance().getSharedEnvironmentInstance(); + + if (mSkyExperience.isNull()) + animateSkyChange(mBaseDayInstance->getSky(), transition_time); + if (mWaterExperience.isNull()) + animateWaterChange(mBaseDayInstance->getWater(), transition_time); + } + + if ((experience_id.isNull() && !mSkyExperience.isNull()) || (experience_id == mSkyExperience)) + { + mSkyExperience.setNull(); + animateSkyChange(mBaseDayInstance->getSky(), transition_time); + } + if ((experience_id.isNull() && !mWaterExperience.isNull()) || (experience_id == mWaterExperience)) + { + mWaterExperience.setNull(); + animateWaterChange(mBaseDayInstance->getWater(), transition_time); + } + + mInjectedSky->removeInjections(experience_id, transition_time); + mInjectedWater->removeInjections(experience_id, transition_time); + + if (experience_id.isNull()) + mActiveExperiences.clear(); + else + mActiveExperiences.erase(experience_id); + + if ((transition_time == LLEnvironment::TRANSITION_INSTANT) && (countExperiencesActive() == 0)) + { // Only do this if instant and there are no other experiences injecting values. + // (otherwise will be handled after transition) + LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_PUSH); + LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); + } + } + + + void DayInjection::testExperiencesOnParcelCoro(wptr_t that, S32 parcel_id) + { + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("testExperiencesOnParcelCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + std::string url = gAgent.getRegionCapability("ExperienceQuery"); + + if (url.empty()) + { + LL_WARNS("ENVIRONMENT") << "No experience query cap." << LL_ENDL; + return; // no checking in this region. + } + + { + ptr_t thatlock(that); + std::stringstream fullurl; + + if (!thatlock) + return; + + fullurl << url << "?"; + fullurl << "parcelid=" << parcel_id; + + for (auto it = thatlock->mActiveExperiences.begin(); it != thatlock->mActiveExperiences.end(); ++it) + { + if (it != thatlock->mActiveExperiences.begin()) + fullurl << ","; + else + fullurl << "&experiences="; + fullurl << (*it).asString(); + } + url = fullurl.str(); + } + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS() << "Unable to retrieve experience status for parcel." << LL_ENDL; + return; + } + + { + LLParcel* parcel = LLViewerParcelMgr::instance().getAgentParcel(); + if (!parcel) + return; + + if (parcel_id != parcel->getLocalID()) + { + // Agent no longer on queried parcel. + return; + } + } + + + LLSD experiences = result["experiences"]; + { + ptr_t thatlock(that); + if (!thatlock) + return; + + for (LLSD::map_iterator itr = experiences.beginMap(); itr != experiences.endMap(); ++itr) + { + if (!((*itr).second.asBoolean())) + thatlock->clearInjections(LLUUID((*itr).first), LLEnvironment::TRANSITION_FAST); + + } + } + } + + void DayInjection::animateSkyChange(LLSettingsSky::ptr_t psky, LLSettingsBase::Seconds transition) + { + if (mInjectedSky.get() == psky.get()) + { // An attempt to animate to itself... don't do it. + return; + } + if (transition == LLEnvironment::TRANSITION_INSTANT) + { + mBlenderSky.reset(); + mInjectedSky->setSource(psky); + } + else + { + LLSettingsSky::ptr_t start_sky(mInjectedSky->getSource()->buildClone()); + LLSettingsSky::ptr_t target_sky(start_sky->buildClone()); + mInjectedSky->setSource(target_sky); + + mBlenderSky = std::make_shared<LLSettingsBlenderTimeDelta>(target_sky, start_sky, psky, transition); + mBlenderSky->setOnFinished( + [this, psky](LLSettingsBlender::ptr_t blender) + { + mBlenderSky.reset(); + mInjectedSky->setSource(psky); + setSky(mInjectedSky); + if (!mBlenderWater && (countExperiencesActive() == 0)) + { + LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_PUSH); + LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); + } + }); + } + } + + void DayInjection::animateWaterChange(LLSettingsWater::ptr_t pwater, LLSettingsBase::Seconds transition) + { + if (mInjectedWater.get() == pwater.get()) + { // An attempt to animate to itself. Bad idea. + return; + } + if (transition == LLEnvironment::TRANSITION_INSTANT) + { + mBlenderWater.reset(); + mInjectedWater->setSource(pwater); + } + else + { + LLSettingsWater::ptr_t start_Water(mInjectedWater->getSource()->buildClone()); + LLSettingsWater::ptr_t scratch_Water(start_Water->buildClone()); + mInjectedWater->setSource(scratch_Water); + + mBlenderWater = std::make_shared<LLSettingsBlenderTimeDelta>(scratch_Water, start_Water, pwater, transition); + mBlenderWater->setOnFinished( + [this, pwater](LLSettingsBlender::ptr_t blender) + { + mBlenderWater.reset(); + mInjectedWater->setSource(pwater); + setWater(mInjectedWater); + if (!mBlenderSky && (countExperiencesActive() == 0)) + { + LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_PUSH); + LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); + } + }); + } + } + + void DayInjection::onEnvironmentChanged(LLEnvironment::EnvSelection_t env) + { + if (env >= LLEnvironment::ENV_PARCEL) + { + LLEnvironment::EnvSelection_t base_env(mBaseDayInstance->getEnvironmentSelection()); + LLEnvironment::DayInstance::ptr_t nextbase = LLEnvironment::instance().getSharedEnvironmentInstance(); + + if ((base_env == LLEnvironment::ENV_NONE) || (nextbase == mBaseDayInstance) || + (!mSkyExperience.isNull() && !mWaterExperience.isNull())) + { // base instance completely overridden, or not changed no transition will happen + return; + } + + LL_WARNS("PUSHENV", "ENVIRONMENT") << "Underlying environment has changed (" << env << ")! Base env is type " << base_env << LL_ENDL; + + LLEnvironment::DayInstance::ptr_t trans = std::make_shared<InjectedTransition>(std::static_pointer_cast<DayInjection>(shared_from_this()), + mBaseDayInstance->getSky(), mBaseDayInstance->getWater(), nextbase, LLEnvironment::TRANSITION_DEFAULT); + + trans->animate(); + setBaseDayInstance(trans); + } + } + + void DayInjection::onParcelChange() + { + S32 parcel_id(INVALID_PARCEL_ID); + LLParcel* parcel = LLViewerParcelMgr::instance().getAgentParcel(); + + if (!parcel) + return; + + parcel_id = parcel->getLocalID(); + + testExperiencesOnParcel(parcel_id); + } + + void DayInjection::checkExperience() + { + if ((!mDayExperience.isNull()) && (mSkyExperience != mDayExperience) && (mWaterExperience != mDayExperience)) + { // There was a day experience but we've replaced it with a water and a sky experience. + mDayExperience.setNull(); + mBaseDayInstance = LLEnvironment::instance().getSharedEnvironmentInstance(); + } + } + + void DayInjection::animate() + { + + } + + void InjectedTransition::animate() + { + mNextInstance->animate(); + + if (!mInjection->isOverriddenSky()) + { + mSky = mStartSky->buildClone(); + mBlenderSky = std::make_shared<LLSettingsBlenderTimeDelta>(mSky, mStartSky, mNextInstance->getSky(), mTransitionTime); + mBlenderSky->setOnFinished( + [this](LLSettingsBlender::ptr_t blender) { + mBlenderSky.reset(); + + if (!mBlenderSky && !mBlenderSky) + mInjection->setBaseDayInstance(mNextInstance); + else + mInjection->mInjectedSky->setSource(mNextInstance->getSky()); + }); + } + else + { + mSky = mInjection->getSky(); + mBlenderSky.reset(); + } + + if (!mInjection->isOverriddenWater()) + { + mWater = mStartWater->buildClone(); + mBlenderWater = std::make_shared<LLSettingsBlenderTimeDelta>(mWater, mStartWater, mNextInstance->getWater(), mTransitionTime); + mBlenderWater->setOnFinished( + [this](LLSettingsBlender::ptr_t blender) { + mBlenderWater.reset(); + + if (!mBlenderSky && !mBlenderWater) + mInjection->setBaseDayInstance(mNextInstance); + else + mInjection->mInjectedWater->setSource(mNextInstance->getWater()); + }); + } + else + { + mWater = mInjection->getWater(); + mBlenderWater.reset(); + } + + } + +} + diff --git a/indra/newview/llenvironment.h b/indra/newview/llenvironment.h new file mode 100644 index 0000000000..7cbf2d25bb --- /dev/null +++ b/indra/newview/llenvironment.h @@ -0,0 +1,477 @@ +/** + * @file llenvmanager.h + * @brief Declaration of classes managing WindLight and water settings. + * + * $LicenseInfo:firstyear=2009&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_ENVIRONMENT_H +#define LL_ENVIRONMENT_H + +#include "llsingleton.h" +#include "llmemory.h" +#include "llsd.h" + +#include "llsettingsbase.h" +#include "llsettingssky.h" +#include "llsettingswater.h" +#include "llsettingsdaycycle.h" + +#include "llatmosphere.h" + +#include <boost/signals2.hpp> + +//------------------------------------------------------------------------- +class LLViewerCamera; +class LLGLSLShader; +class LLParcel; + +//------------------------------------------------------------------------- +class LLEnvironment : public LLSingleton<LLEnvironment> +{ + LLSINGLETON_C11(LLEnvironment); + LOG_CLASS(LLEnvironment); + +public: + static const F64Seconds TRANSITION_INSTANT; + static const F64Seconds TRANSITION_FAST; + static const F64Seconds TRANSITION_DEFAULT; + static const F64Seconds TRANSITION_SLOW; + static const F64Seconds TRANSITION_ALTITUDE; + + static const LLUUID KNOWN_SKY_SUNRISE; + static const LLUUID KNOWN_SKY_MIDDAY; + static const LLUUID KNOWN_SKY_SUNSET; + static const LLUUID KNOWN_SKY_MIDNIGHT; + + static const S32 NO_TRACK; + static const S32 NO_VERSION; + static const S32 VERSION_CLEANUP; + + struct EnvironmentInfo + { + EnvironmentInfo(); + + typedef std::shared_ptr<EnvironmentInfo> ptr_t; + typedef std::array<std::string, 5> namelist_t; + + S32 mParcelId; + LLUUID mRegionId; + S64Seconds mDayLength; + S64Seconds mDayOffset; + size_t mDayHash; + LLSettingsDay::ptr_t mDayCycle; + std::array<F32, 4> mAltitudes; + bool mIsDefault; + LLUUID mAssetId; + bool mIsLegacy; + std::string mDayCycleName; + namelist_t mNameList; + S32 mEnvVersion; + + static ptr_t extract(LLSD); + static ptr_t extractLegacy(LLSD); + }; + + enum EnvSelection_t + { + ENV_EDIT = 0, + ENV_LOCAL, + ENV_PUSH, + ENV_PARCEL, + ENV_REGION, + ENV_DEFAULT, + ENV_END, + ENV_CURRENT = -1, + ENV_NONE = -2 + }; + + typedef boost::signals2::connection connection_t; + + typedef std::pair<LLSettingsSky::ptr_t, LLSettingsWater::ptr_t> fixedEnvironment_t; + typedef std::function<void(S32, EnvironmentInfo::ptr_t)> environment_apply_fn; + typedef boost::signals2::signal<void(EnvSelection_t, S32)> env_changed_signal_t; + typedef env_changed_signal_t::slot_type env_changed_fn; + typedef std::array<F32, 4> altitude_list_t; + typedef std::vector<F32> altitudes_vect_t; + + virtual ~LLEnvironment(); + + bool canEdit() const; + bool isExtendedEnvironmentEnabled() const; + bool isInventoryEnabled() const; + bool canAgentUpdateParcelEnvironment() const; + bool canAgentUpdateParcelEnvironment(LLParcel *parcel) const; + bool canAgentUpdateRegionEnvironment() const; + + LLSettingsDay::ptr_t getCurrentDay() const { return mCurrentEnvironment->getDayCycle(); } + LLSettingsSky::ptr_t getCurrentSky() const; + LLSettingsWater::ptr_t getCurrentWater() const; + + static void getAtmosphericModelSettings(AtmosphericModelSettings& settingsOut, const LLSettingsSky::ptr_t &psky); + + void update(const LLViewerCamera * cam); + + static void updateGLVariablesForSettings(LLGLSLShader *shader, const LLSettingsBase::ptr_t &psetting); + void updateShaderUniforms(LLGLSLShader *shader); + + void setSelectedEnvironment(EnvSelection_t env, LLSettingsBase::Seconds transition = TRANSITION_DEFAULT, bool forced = false); + EnvSelection_t getSelectedEnvironment() const { return mSelectedEnvironment; } + + bool hasEnvironment(EnvSelection_t env); + void setEnvironment(EnvSelection_t env, const LLSettingsDay::ptr_t &pday, LLSettingsDay::Seconds daylength, LLSettingsDay::Seconds dayoffset, S32 env_version = NO_VERSION); + void setEnvironment(EnvSelection_t env, fixedEnvironment_t fixed, S32 env_version = NO_VERSION); + void setEnvironment(EnvSelection_t env, const LLSettingsBase::ptr_t &fixed, S32 env_version = NO_VERSION); + void setEnvironment(EnvSelection_t env, const LLSettingsSky::ptr_t & fixed, S32 env_version = NO_VERSION) { setEnvironment(env, fixedEnvironment_t(fixed, LLSettingsWater::ptr_t()), env_version); } + void setEnvironment(EnvSelection_t env, const LLSettingsWater::ptr_t & fixed, S32 env_version = NO_VERSION) { setEnvironment(env, fixedEnvironment_t(LLSettingsSky::ptr_t(), fixed), env_version); } + void setEnvironment(EnvSelection_t env, const LLSettingsSky::ptr_t & fixeds, const LLSettingsWater::ptr_t & fixedw, S32 env_version = NO_VERSION) { setEnvironment(env, fixedEnvironment_t(fixeds, fixedw), env_version); } + void setEnvironment(EnvSelection_t env, const LLUUID &assetId, S32 env_version); + void setEnvironment(EnvSelection_t env, const LLUUID &assetId, LLSettingsBase::Seconds transition = TRANSITION_DEFAULT, S32 env_version = NO_VERSION); + + void setSharedEnvironment(); + void clearEnvironment(EnvSelection_t env); + + static void logEnvironment(EnvSelection_t env, const LLSettingsBase::ptr_t &settings, S32 env_version = NO_VERSION); + + + LLSettingsDay::ptr_t getEnvironmentDay(EnvSelection_t env); + LLSettingsDay::Seconds getEnvironmentDayLength(EnvSelection_t env); + LLSettingsDay::Seconds getEnvironmentDayOffset(EnvSelection_t env); + fixedEnvironment_t getEnvironmentFixed(EnvSelection_t env, bool resolve = false); + LLSettingsSky::ptr_t getEnvironmentFixedSky(EnvSelection_t env, bool resolve = false) { return getEnvironmentFixed(env, resolve).first; }; + LLSettingsWater::ptr_t getEnvironmentFixedWater(EnvSelection_t env, bool resolve = false) { return getEnvironmentFixed(env, resolve).second; }; + + void updateEnvironment(LLSettingsBase::Seconds transition = TRANSITION_DEFAULT, bool forced = false); + + inline LLVector2 getCloudScrollDelta() const { return mCloudScrollDelta; } + void pauseCloudScroll() { mCloudScrollPaused = true; } + void resumeCloudScroll() { mCloudScrollPaused = false; } + bool isCloudScrollPaused() const { return mCloudScrollPaused; } + + F32 getCamHeight() const; + F32 getWaterHeight() const; + bool getIsSunUp() const; + bool getIsMoonUp() const; + + void saveToSettings(); + bool loadFromSettings(); + void saveBeaconsState(); + void revertBeaconsState(); + + // Returns either sun or moon direction (depending on which is up and stronger) + // Light direction in +x right, +z up, +y at internal coord sys + LLVector3 getLightDirection() const; // returns sun or moon depending on which is up + LLVector3 getSunDirection() const; + LLVector3 getMoonDirection() const; + + // Returns light direction converted to CFR coord system + LLVector4 getLightDirectionCFR() const; // returns sun or moon depending on which is up + LLVector4 getSunDirectionCFR() const; + LLVector4 getMoonDirectionCFR() const; + + // Returns light direction converted to OGL coord system + // and clamped above -0.1f in Y to avoid render artifacts in sky shaders + LLVector4 getClampedLightNorm() const; // returns sun or moon depending on which is up + LLVector4 getClampedSunNorm() const; + LLVector4 getClampedMoonNorm() const; + + // Returns light direction converted to OGL coord system + // and rotated by last cam yaw needed by water rendering shaders + LLVector4 getRotatedLightNorm() const; + + static LLSettingsWater::ptr_t createWaterFromLegacyPreset(const std::string filename, LLSD &messages); + static LLSettingsSky::ptr_t createSkyFromLegacyPreset(const std::string filename, LLSD &messages); + static LLSettingsDay::ptr_t createDayCycleFromLegacyPreset(const std::string filename, LLSD &messages); + + // Construct a new day cycle based on the environment. Replacing either the water or the sky tracks. + LLSettingsDay::ptr_t createDayCycleFromEnvironment(EnvSelection_t env, LLSettingsBase::ptr_t settings); + + F32 getProgress() const { return (mCurrentEnvironment) ? mCurrentEnvironment->getProgress() : -1.0f; } + F32 getRegionProgress() const { return (mEnvironments[ENV_REGION]) ? mEnvironments[ENV_REGION]->getProgress() : -1.0f; } + void adjustRegionOffset(F32 adjust); // only used on legacy regions, to better sync the viewer with other agents + + //------------------------------------------- + connection_t setEnvironmentChanged(env_changed_fn cb) { return mSignalEnvChanged.connect(cb); } + + void requestRegion(environment_apply_fn cb = environment_apply_fn()); + void updateRegion(const LLUUID &asset_id, std::string display_name, S32 track_num, S32 day_length, S32 day_offset, U32 flags, altitudes_vect_t altitudes = altitudes_vect_t(), environment_apply_fn cb = environment_apply_fn()); + void updateRegion(const LLSettingsDay::ptr_t &pday, S32 day_length, S32 day_offset, altitudes_vect_t altitudes = altitudes_vect_t(), environment_apply_fn cb = environment_apply_fn()); + void updateRegion(const LLSettingsSky::ptr_t &psky, S32 day_length, S32 day_offset, altitudes_vect_t altitudes = altitudes_vect_t(), environment_apply_fn cb = environment_apply_fn()); + void updateRegion(const LLSettingsWater::ptr_t &pwater, S32 day_length, S32 day_offset, altitudes_vect_t altitudes = altitudes_vect_t(), environment_apply_fn cb = environment_apply_fn()); + void resetRegion(environment_apply_fn cb = environment_apply_fn()); + void requestParcel(S32 parcel_id, environment_apply_fn cb = environment_apply_fn()); + void updateParcel(S32 parcel_id, const LLUUID &asset_id, std::string display_name, S32 track_num, S32 day_length, S32 day_offset, U32 flags, altitudes_vect_t altitudes = altitudes_vect_t(), environment_apply_fn cb = environment_apply_fn()); + void updateParcel(S32 parcel_id, const LLSettingsDay::ptr_t &pday, S32 track_num, S32 day_length, S32 day_offset, altitudes_vect_t altitudes = altitudes_vect_t(), environment_apply_fn cb = environment_apply_fn()); + void updateParcel(S32 parcel_id, const LLSettingsDay::ptr_t &pday, S32 day_length, S32 day_offset, altitudes_vect_t altitudes = altitudes_vect_t(), environment_apply_fn cb = environment_apply_fn()); + void updateParcel(S32 parcel_id, const LLSettingsSky::ptr_t &psky, S32 day_length, S32 day_offset, altitudes_vect_t altitudes = altitudes_vect_t(), environment_apply_fn cb = environment_apply_fn()); + void updateParcel(S32 parcel_id, const LLSettingsWater::ptr_t &pwater, S32 day_length, S32 day_offset, altitudes_vect_t altitudes = altitudes_vect_t(), environment_apply_fn cb = environment_apply_fn()); + void resetParcel(S32 parcel_id, environment_apply_fn cb = environment_apply_fn()); + + void selectAgentEnvironment(); + + S32 calculateSkyTrackForAltitude(F64 altitude); + + const altitude_list_t & getRegionAltitudes() const { return mTrackAltitudes; } + + void handleEnvironmentPush(LLSD &message); + + class DayInstance: public std::enable_shared_from_this<DayInstance> + { + public: + typedef std::shared_ptr<DayInstance> ptr_t; + + static const U32 NO_ANIMATE_SKY; + static const U32 NO_ANIMATE_WATER; + + DayInstance(EnvSelection_t env); + virtual ~DayInstance() { }; + + virtual ptr_t clone() const; + + virtual bool applyTimeDelta(const LLSettingsBase::Seconds& delta); + + virtual void setDay(const LLSettingsDay::ptr_t &pday, LLSettingsDay::Seconds daylength, LLSettingsDay::Seconds dayoffset); + virtual void setSky(const LLSettingsSky::ptr_t &psky); + virtual void setWater(const LLSettingsWater::ptr_t &pwater); + + void initialize(); + bool isInitialized(); + + void clear(); + + void setSkyTrack(S32 trackno); + + LLSettingsDay::ptr_t getDayCycle() const { return mDayCycle; } + LLSettingsSky::ptr_t getSky() const { return mSky; } + LLSettingsWater::ptr_t getWater() const { return mWater; } + LLSettingsDay::Seconds getDayLength() const { return mDayLength; } + LLSettingsDay::Seconds getDayOffset() const { return mDayOffset; } + S32 getSkyTrack() const { return mSkyTrack; } + + void setDayOffset(LLSettingsBase::Seconds offset) { mDayOffset = offset; animate(); } + + virtual void animate(); + + void setBlenders(const LLSettingsBlender::ptr_t &skyblend, const LLSettingsBlender::ptr_t &waterblend); + + EnvSelection_t getEnvironmentSelection() const { return mEnv; } + void setEnvironmentSelection(EnvSelection_t env) { mEnv = env; } + + LLSettingsBase::TrackPosition getProgress() const; + + void setFlags(U32 flag) { mAnimateFlags |= flag; } + void clearFlags(U32 flag) { mAnimateFlags &= ~flag; } + U32 getFlags() { return mAnimateFlags; } + + protected: + + + LLSettingsDay::ptr_t mDayCycle; + LLSettingsSky::ptr_t mSky; + LLSettingsWater::ptr_t mWater; + S32 mSkyTrack; + + bool mInitialized; + + LLSettingsDay::Seconds mDayLength; + LLSettingsDay::Seconds mDayOffset; + S32 mLastTrackAltitude; + + LLSettingsBlender::ptr_t mBlenderSky; + LLSettingsBlender::ptr_t mBlenderWater; + + EnvSelection_t mEnv; + + U32 mAnimateFlags; + + LLSettingsBase::TrackPosition secondsToKeyframe(LLSettingsDay::Seconds seconds); + }; + + class DayTransition : public DayInstance + { + public: + DayTransition(const LLSettingsSky::ptr_t &skystart, const LLSettingsWater::ptr_t &waterstart, DayInstance::ptr_t &end, LLSettingsDay::Seconds time); + virtual ~DayTransition() { }; + + virtual bool applyTimeDelta(const LLSettingsBase::Seconds& delta) override; + virtual void animate() override; + + protected: + LLSettingsSky::ptr_t mStartSky; + LLSettingsWater::ptr_t mStartWater; + DayInstance::ptr_t mNextInstance; + LLSettingsDay::Seconds mTransitionTime; + }; + + DayInstance::ptr_t getSelectedEnvironmentInstance(); + DayInstance::ptr_t getSharedEnvironmentInstance(); + +protected: + virtual void initSingleton() override; + virtual void cleanupSingleton() override; + + +private: + LLVector4 toCFR(const LLVector3 vec) const; + LLVector4 toLightNorm(const LLVector3 vec) const; + + typedef std::array<DayInstance::ptr_t, ENV_END> InstanceArray_t; + + struct ExpEnvironmentEntry + { + typedef std::shared_ptr<ExpEnvironmentEntry> ptr_t; + + S32Seconds mTime; + LLUUID mExperienceId; + LLSD mEnvironmentOverrides; + }; + typedef std::deque<ExpEnvironmentEntry::ptr_t> mPushOverrides; + + LLUUID mPushEnvironmentExpId; + + static const F32 SUN_DELTA_YAW; + F32 mLastCamYaw = 0.0f; + + LLVector2 mCloudScrollDelta; // cumulative cloud delta + bool mCloudScrollPaused; + + InstanceArray_t mEnvironments; + + EnvSelection_t mSelectedEnvironment; + DayInstance::ptr_t mCurrentEnvironment; + + LLSettingsSky::ptr_t mSelectedSky; + LLSettingsWater::ptr_t mSelectedWater; + LLSettingsDay::ptr_t mSelectedDay; + + LLSettingsBlender::ptr_t mBlenderSky; + LLSettingsBlender::ptr_t mBlenderWater; + + env_changed_signal_t mSignalEnvChanged; + + S32 mCurrentTrack; + altitude_list_t mTrackAltitudes; + + LLSD mSkyOverrides; + LLSD mWaterOverrides; + typedef std::map<std::string, LLUUID> experience_overrides_t; + experience_overrides_t mExperienceOverrides; + + DayInstance::ptr_t getEnvironmentInstance(EnvSelection_t env, bool create = false); + + void updateCloudScroll(); + + void onRegionChange(); + void onParcelChange(); + + bool mShowSunBeacon; + bool mShowMoonBeacon; + S32 mEditorCounter; + + struct UpdateInfo + { + typedef std::shared_ptr<UpdateInfo> ptr_t; + + UpdateInfo(LLSettingsDay::ptr_t pday, S32 day_length, S32 day_offset, altitudes_vect_t altitudes): + mDayp(pday), + mSettingsAsset(), + mDayLength(day_length), + mDayOffset(day_offset), + mAltitudes(altitudes), + mDayName(), + mFlags(0) + { + if (mDayp) + { + mDayName = mDayp->getName(); + mFlags = mDayp->getFlags(); + } + } + + UpdateInfo(LLUUID settings_asset, std::string name, S32 day_length, S32 day_offset, altitudes_vect_t altitudes, U32 flags) : + mDayp(), + mSettingsAsset(settings_asset), + mDayLength(day_length), + mDayOffset(day_offset), + mAltitudes(altitudes), + mDayName(name), + mFlags(flags) + {} + + LLSettingsDay::ptr_t mDayp; + LLUUID mSettingsAsset; + S32 mDayLength; + S32 mDayOffset; + altitudes_vect_t mAltitudes; + std::string mDayName; + U32 mFlags; + }; + + void coroRequestEnvironment(S32 parcel_id, environment_apply_fn apply); + void coroUpdateEnvironment(S32 parcel_id, S32 track_no, UpdateInfo::ptr_t updates, environment_apply_fn apply); + void coroResetEnvironment(S32 parcel_id, S32 track_no, environment_apply_fn apply); + + void recordEnvironment(S32 parcel_id, EnvironmentInfo::ptr_t environment, LLSettingsBase::Seconds transition); + + void onAgentPositionHasChanged(const LLVector3 &localpos); + + void onSetEnvAssetLoaded(EnvSelection_t env, LLUUID asset_id, LLSettingsBase::ptr_t settings, LLSettingsBase::Seconds transition, S32 status, S32 env_version); + void onUpdateParcelAssetLoaded(LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, S32 parcel_id, S32 day_length, S32 day_offset, altitudes_vect_t altitudes); + + void handleEnvironmentPushClear(LLUUID experience_id, LLSD &message, F32 transition); + void handleEnvironmentPushFull(LLUUID experience_id, LLSD &message, F32 transition); + void handleEnvironmentPushPartial(LLUUID experience_id, LLSD &message, F32 transition); + + void clearExperienceEnvironment(LLUUID experience_id, LLSettingsBase::Seconds transition_time); + void setExperienceEnvironment(LLUUID experience_id, LLUUID asset_id, F32 transition_time); + void setExperienceEnvironment(LLUUID experience_id, LLSD environment, F32 transition_time); + void onSetExperienceEnvAssetLoaded(LLUUID experience_id, LLSettingsBase::ptr_t setting, F32 transition_time, S32 status); + + void listenExperiencePump(const LLSD &message); + void loadSkyWaterFromSettings(const LLSD &env_data, bool &valid, bool &assets_present); // for use in loadFromSettings() + +}; + +class LLTrackBlenderLoopingManual : public LLSettingsBlender +{ +public: + LLTrackBlenderLoopingManual(const LLSettingsBase::ptr_t &target, const LLSettingsDay::ptr_t &day, S32 trackno); + + F64 setPosition(const LLSettingsBase::TrackPosition& position); + virtual void switchTrack(S32 trackno, const LLSettingsBase::TrackPosition& position) override; + S32 getTrack() const { return mTrackNo; } + + typedef std::shared_ptr<LLTrackBlenderLoopingManual> ptr_t; +protected: + LLSettingsDay::TrackBound_t getBoundingEntries(F64 position); + F64 getSpanLength(const LLSettingsDay::TrackBound_t &bounds) const; + +private: + LLSettingsDay::ptr_t mDay; + S32 mTrackNo; + F64 mPosition; + + LLSettingsDay::CycleTrack_t::iterator mEndMarker; +}; + +#endif // LL_ENVIRONMENT_H + diff --git a/indra/newview/llenvmanager.cpp b/indra/newview/llenvmanager.cpp deleted file mode 100644 index fa1c3b983e..0000000000 --- a/indra/newview/llenvmanager.cpp +++ /dev/null @@ -1,721 +0,0 @@ -/** - * @file llenvmanager.cpp - * @brief Implementation of classes managing WindLight and water settings. - * - * $LicenseInfo:firstyear=2009&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 "llenvmanager.h" - -#include "llagent.h" -#include "lldaycyclemanager.h" -#include "llviewercontrol.h" // for gSavedSettings -#include "llviewerregion.h" -#include "llwaterparammanager.h" -#include "llwlhandlers.h" -#include "llwlparammanager.h" -#include "lltrans.h" - -std::string LLWLParamKey::toString() const -{ - switch (scope) - { - case SCOPE_LOCAL: - return name + std::string(" (") + LLTrans::getString("Local") + std::string(")"); - break; - case SCOPE_REGION: - return name + std::string(" (") + LLTrans::getString("Region") + std::string(")"); - break; - default: - return name + " (?)"; - } -} - -std::string LLEnvPrefs::getWaterPresetName() const -{ - if (mWaterPresetName.empty()) - { - LL_WARNS() << "Water preset name is empty" << LL_ENDL; - } - - return mWaterPresetName; -} - -std::string LLEnvPrefs::getSkyPresetName() const -{ - if (mSkyPresetName.empty()) - { - LL_WARNS() << "Sky preset name is empty" << LL_ENDL; - } - - return mSkyPresetName; -} - -std::string LLEnvPrefs::getDayCycleName() const -{ - if (mDayCycleName.empty()) - { - LL_WARNS() << "Day cycle name is empty" << LL_ENDL; - } - - return mDayCycleName; -} - -void LLEnvPrefs::setUseRegionSettings(bool val) -{ - mUseRegionSettings = val; -} - -void LLEnvPrefs::setUseWaterPreset(const std::string& name) -{ - mUseRegionSettings = false; - mWaterPresetName = name; -} - -void LLEnvPrefs::setUseSkyPreset(const std::string& name) -{ - mUseRegionSettings = false; - mUseDayCycle = false; - mSkyPresetName = name; -} - -void LLEnvPrefs::setUseDayCycle(const std::string& name) -{ - mUseRegionSettings = false; - mUseDayCycle = true; - mDayCycleName = name; -} - -//============================================================================= -LLEnvManagerNew::LLEnvManagerNew(): - mInterpNextChangeMessage(true), - mCurRegionUUID(LLUUID::null), - mLastReceivedID(LLUUID::null) -{ - - // Set default environment settings. - mUserPrefs.mUseRegionSettings = true; - mUserPrefs.mUseDayCycle = true; - mUserPrefs.mWaterPresetName = "Default"; - mUserPrefs.mSkyPresetName = "Default"; - mUserPrefs.mDayCycleName = "Default"; - - LL_DEBUGS("Windlight")<<LL_ENDL; - gAgent.addRegionChangedCallback(boost::bind(&LLEnvManagerNew::onRegionChange, this)); -} - -bool LLEnvManagerNew::getUseRegionSettings() const -{ - return mUserPrefs.getUseRegionSettings(); -} - -bool LLEnvManagerNew::getUseDayCycle() const -{ - return mUserPrefs.getUseDayCycle(); -} - -bool LLEnvManagerNew::getUseFixedSky() const -{ - return mUserPrefs.getUseFixedSky(); -} - -std::string LLEnvManagerNew::getWaterPresetName() const -{ - return mUserPrefs.getWaterPresetName(); -} - -std::string LLEnvManagerNew::getSkyPresetName() const -{ - return mUserPrefs.getSkyPresetName(); -} - -std::string LLEnvManagerNew::getDayCycleName() const -{ - return mUserPrefs.getDayCycleName(); -} - -const LLEnvironmentSettings& LLEnvManagerNew::getRegionSettings() const -{ - return !mNewRegionPrefs.isEmpty() ? mNewRegionPrefs : mCachedRegionPrefs; -} - -void LLEnvManagerNew::setRegionSettings(const LLEnvironmentSettings& new_settings) -{ - // Set region settings override that will be used locally - // until user either uploads the changes or goes to another region. - mNewRegionPrefs = new_settings; -} - -bool LLEnvManagerNew::usePrefs() -{ - LL_DEBUGS("Windlight") << "Displaying preferred environment" << LL_ENDL; - updateManagersFromPrefs(false); - return true; -} - -bool LLEnvManagerNew::useDefaults() -{ - bool rslt; - - rslt = useDefaultWater(); - rslt &= useDefaultSky(); - - return rslt; -} - -bool LLEnvManagerNew::useRegionSettings() -{ - bool rslt; - - rslt = useRegionSky(); - rslt &= useRegionWater(); - - return rslt; -} - -bool LLEnvManagerNew::useWaterPreset(const std::string& name) -{ - LL_DEBUGS("Windlight") << "Displaying water preset " << name << LL_ENDL; - LLWaterParamManager& water_mgr = LLWaterParamManager::instance(); - bool rslt = water_mgr.getParamSet(name, water_mgr.mCurParams); - llassert(rslt == true); - return rslt; -} - -bool LLEnvManagerNew::useWaterParams(const LLSD& params) -{ - LL_DEBUGS("Windlight") << "Displaying water params" << LL_ENDL; - LLWaterParamManager::instance().mCurParams.setAll(params); - return true; -} - -bool LLEnvManagerNew::useSkyPreset(const std::string& name) -{ - LLWLParamManager& sky_mgr = LLWLParamManager::instance(); - LLWLParamSet param_set; - - if (!sky_mgr.getParamSet(LLWLParamKey(name, LLEnvKey::SCOPE_LOCAL), param_set)) - { - LL_WARNS() << "No sky preset named " << name << LL_ENDL; - return false; - } - - LL_DEBUGS("Windlight") << "Displaying sky preset " << name << LL_ENDL; - sky_mgr.applySkyParams(param_set.getAll()); - return true; -} - -bool LLEnvManagerNew::useSkyParams(const LLSD& params) -{ - LL_DEBUGS("Windlight") << "Displaying sky params" << LL_ENDL; - LLWLParamManager::instance().applySkyParams(params); - return true; -} - -bool LLEnvManagerNew::useDayCycle(const std::string& name, LLEnvKey::EScope scope) -{ - LLSD params; - - if (scope == LLEnvKey::SCOPE_REGION) - { - LL_DEBUGS("Windlight") << "Displaying region day cycle " << name << LL_ENDL; - params = getRegionSettings().getWLDayCycle(); - } - else - { - LL_DEBUGS("Windlight") << "Displaying local day cycle " << name << LL_ENDL; - - if (!LLDayCycleManager::instance().getPreset(name, params)) - { - LL_WARNS() << "No day cycle named " << name << LL_ENDL; - return false; - } - } - - bool rslt = LLWLParamManager::instance().applyDayCycleParams(params, scope); - llassert(rslt == true); - return rslt; -} - -bool LLEnvManagerNew::useDayCycleParams(const LLSD& params, LLEnvKey::EScope scope, F32 time /* = 0.5*/) -{ - LL_DEBUGS("Windlight") << "Displaying day cycle params" << LL_ENDL; - return LLWLParamManager::instance().applyDayCycleParams(params, scope); -} - -void LLEnvManagerNew::setUseRegionSettings(bool val) -{ - mUserPrefs.setUseRegionSettings(val); - saveUserPrefs(); - updateManagersFromPrefs(false); -} - -void LLEnvManagerNew::setUseWaterPreset(const std::string& name) -{ - // *TODO: make sure the preset exists. - if (name.empty()) - { - LL_WARNS() << "Empty water preset name passed" << LL_ENDL; - return; - } - - mUserPrefs.setUseWaterPreset(name); - saveUserPrefs(); - updateManagersFromPrefs(false); -} - -void LLEnvManagerNew::setUseSkyPreset(const std::string& name) -{ - // *TODO: make sure the preset exists. - if (name.empty()) - { - LL_WARNS() << "Empty sky preset name passed" << LL_ENDL; - return; - } - - mUserPrefs.setUseSkyPreset(name); - saveUserPrefs(); - updateManagersFromPrefs(false); -} - -void LLEnvManagerNew::setUseDayCycle(const std::string& name) -{ - if (!LLDayCycleManager::instance().presetExists(name)) - { - LL_WARNS() << "Invalid day cycle name passed" << LL_ENDL; - return; - } - - mUserPrefs.setUseDayCycle(name); - saveUserPrefs(); - updateManagersFromPrefs(false); -} - -void LLEnvManagerNew::loadUserPrefs() -{ - // operate on members directly to avoid side effects - mUserPrefs.mWaterPresetName = gSavedSettings.getString("WaterPresetName"); - mUserPrefs.mSkyPresetName = gSavedSettings.getString("SkyPresetName"); - mUserPrefs.mDayCycleName = gSavedSettings.getString("DayCycleName"); - - bool use_region_settings = gSavedSettings.getBOOL("EnvironmentPersistAcrossLogin") ? gSavedSettings.getBOOL("UseEnvironmentFromRegion") : true; - mUserPrefs.mUseRegionSettings = use_region_settings; - mUserPrefs.mUseDayCycle = gSavedSettings.getBOOL("UseDayCycle"); - - if (mUserPrefs.mUseRegionSettings) - { - requestRegionSettings(); - } -} - -void LLEnvManagerNew::saveUserPrefs() -{ - gSavedSettings.setString("WaterPresetName", getWaterPresetName()); - gSavedSettings.setString("SkyPresetName", getSkyPresetName()); - gSavedSettings.setString("DayCycleName", getDayCycleName()); - - gSavedSettings.setBOOL("UseEnvironmentFromRegion", getUseRegionSettings()); - gSavedSettings.setBOOL("UseDayCycle", getUseDayCycle()); - - mUsePrefsChangeSignal(); -} - -void LLEnvManagerNew::setUserPrefs( - const std::string& water_preset, - const std::string& sky_preset, - const std::string& day_cycle_preset, - bool use_fixed_sky, - bool use_region_settings) -{ - // operate on members directly to avoid side effects - mUserPrefs.mWaterPresetName = water_preset; - mUserPrefs.mSkyPresetName = sky_preset; - mUserPrefs.mDayCycleName = day_cycle_preset; - - mUserPrefs.mUseRegionSettings = use_region_settings; - mUserPrefs.mUseDayCycle = !use_fixed_sky; - - saveUserPrefs(); - updateManagersFromPrefs(false); -} - -void LLEnvManagerNew::dumpUserPrefs() -{ - LL_DEBUGS("Windlight") << "WaterPresetName: " << gSavedSettings.getString("WaterPresetName") << LL_ENDL; - LL_DEBUGS("Windlight") << "SkyPresetName: " << gSavedSettings.getString("SkyPresetName") << LL_ENDL; - LL_DEBUGS("Windlight") << "DayCycleName: " << gSavedSettings.getString("DayCycleName") << LL_ENDL; - - LL_DEBUGS("Windlight") << "UseEnvironmentFromRegion: " << gSavedSettings.getBOOL("UseEnvironmentFromRegion") << LL_ENDL; - LL_DEBUGS("Windlight") << "UseDayCycle: " << gSavedSettings.getBOOL("UseDayCycle") << LL_ENDL; -} - -void LLEnvManagerNew::dumpPresets() -{ - const LLEnvironmentSettings& region_settings = getRegionSettings(); - std::string region_name = gAgent.getRegion() ? gAgent.getRegion()->getName() : "Unknown region"; - - // Dump water presets. - LL_DEBUGS("Windlight") << "Waters:" << LL_ENDL; - if (region_settings.getWaterParams().size() != 0) - { - LL_DEBUGS("Windlight") << " - " << region_name << LL_ENDL; - } - LLWaterParamManager::preset_name_list_t water_presets; - LLWaterParamManager::instance().getPresetNames(water_presets); - for (LLWaterParamManager::preset_name_list_t::const_iterator it = water_presets.begin(); it != water_presets.end(); ++it) - { - LL_DEBUGS("Windlight") << " - " << *it << LL_ENDL; - } - - // Dump sky presets. - LL_DEBUGS("Windlight") << "Skies:" << LL_ENDL; - LLWLParamManager::preset_key_list_t sky_preset_keys; - LLWLParamManager::instance().getPresetKeys(sky_preset_keys); - for (LLWLParamManager::preset_key_list_t::const_iterator it = sky_preset_keys.begin(); it != sky_preset_keys.end(); ++it) - { - std::string preset_name = it->name; - std::string item_title; - - if (it->scope == LLEnvKey::SCOPE_LOCAL) // local preset - { - item_title = preset_name; - } - else // region preset - { - item_title = preset_name + " (" + region_name + ")"; - } - LL_DEBUGS("Windlight") << " - " << item_title << LL_ENDL; - } - - // Dump day cycles. - LL_DEBUGS("Windlight") << "Days:" << LL_ENDL; - const LLSD& cur_region_dc = region_settings.getWLDayCycle(); - if (cur_region_dc.size() != 0) - { - LL_DEBUGS("Windlight") << " - " << region_name << LL_ENDL; - } - LLDayCycleManager::preset_name_list_t days; - LLDayCycleManager::instance().getPresetNames(days); - for (LLDayCycleManager::preset_name_list_t::const_iterator it = days.begin(); it != days.end(); ++it) - { - LL_DEBUGS("Windlight") << " - " << *it << LL_ENDL; - } -} - -void LLEnvManagerNew::requestRegionSettings() -{ - LL_DEBUGS("Windlight") << LL_ENDL; - LLEnvironmentRequest::initiate(); -} - -bool LLEnvManagerNew::sendRegionSettings(const LLEnvironmentSettings& new_settings) -{ - LLSD metadata; - - metadata["regionID"] = gAgent.getRegion()->getRegionID(); - // add last received update ID to outbound message so simulator can handle concurrent updates - metadata["messageID"] = mLastReceivedID; - - return LLEnvironmentApply::initiateRequest(new_settings.makePacket(metadata)); -} - -boost::signals2::connection LLEnvManagerNew::setPreferencesChangeCallback(const prefs_change_signal_t::slot_type& cb) -{ - return mUsePrefsChangeSignal.connect(cb); -} - -boost::signals2::connection LLEnvManagerNew::setRegionSettingsChangeCallback(const region_settings_change_signal_t::slot_type& cb) -{ - return mRegionSettingsChangeSignal.connect(cb); -} - -boost::signals2::connection LLEnvManagerNew::setRegionSettingsAppliedCallback(const region_settings_applied_signal_t::slot_type& cb) -{ - return mRegionSettingsAppliedSignal.connect(cb); -} - -// static -bool LLEnvManagerNew::canEditRegionSettings() -{ - LLViewerRegion* region = gAgent.getRegion(); - BOOL owner_or_god = gAgent.isGodlike() || (region && region->getOwner() == gAgent.getID()); - BOOL owner_or_god_or_manager = owner_or_god || (region && region->isEstateManager()); - - LL_DEBUGS("Windlight") << "Can edit region settings: " << (bool) owner_or_god_or_manager << LL_ENDL; - return owner_or_god_or_manager; -} - -// static -const std::string LLEnvManagerNew::getScopeString(LLEnvKey::EScope scope) -{ - switch(scope) - { - case LLEnvKey::SCOPE_LOCAL: - return LLTrans::getString("LocalSettings"); - case LLEnvKey::SCOPE_REGION: - return LLTrans::getString("RegionSettings"); - default: - return " (?)"; - } -} - -void LLEnvManagerNew::onRegionSettingsResponse(const LLSD& content) -{ - // If the message was valid, grab the UUID from it and save it for next outbound update message. - mLastReceivedID = content[0]["messageID"].asUUID(); - - // Refresh cached region settings. - LL_DEBUGS("Windlight") << "Received region environment settings: " << content << LL_ENDL; - F32 sun_hour = 0; // *TODO - LLEnvironmentSettings new_settings(content[1], content[2], content[3], sun_hour); - mCachedRegionPrefs = new_settings; - - // Load region sky presets. - LLWLParamManager::instance().refreshRegionPresets(getRegionSettings().getSkyMap()); - - // If using server settings, update managers. - if (getUseRegionSettings()) - { - updateManagersFromPrefs(mInterpNextChangeMessage); - } - - // Let interested parties know about the region settings update. - mRegionSettingsChangeSignal(); - - // reset - mInterpNextChangeMessage = false; -} - -void LLEnvManagerNew::onRegionSettingsApplyResponse(bool ok) -{ - LL_DEBUGS("Windlight") << "Applying region settings " << (ok ? "succeeded" : "failed") << LL_ENDL; - - // Clear locally modified region settings because they have just been uploaded. - mNewRegionPrefs.clear(); - - mRegionSettingsAppliedSignal(ok); -} - -//-- private methods ---------------------------------------------------------- - -// virtual -void LLEnvManagerNew::initSingleton() -{ - LL_DEBUGS("Windlight") << "Initializing LLEnvManagerNew" << LL_ENDL; - - loadUserPrefs(); - - // preferences loaded, can set params - std::string preferred_day = getDayCycleName(); - if (!useDayCycle(preferred_day, LLEnvKey::SCOPE_LOCAL)) - { - LL_WARNS() << "No day cycle named " << preferred_day << ", reverting LLWLParamManager to defaults" << LL_ENDL; - LLWLParamManager::instance().setDefaultDay(); - } - - std::string sky = getSkyPresetName(); - if (!useSkyPreset(sky)) - { - LL_WARNS() << "No sky preset named " << sky << ", falling back to defaults" << LL_ENDL; - LLWLParamManager::instance().setDefaultSky(); - - // *TODO: Fix user preferences accordingly. - } - - LLWLParamManager::instance().resetAnimator(0.5 /*noon*/, getUseDayCycle()); -} - -void LLEnvManagerNew::updateSkyFromPrefs() -{ - bool success = true; - - // Sync sky with user prefs. - if (getUseRegionSettings()) // apply region-wide settings - { - success = useRegionSky(); - } - else // apply user-specified settings - { - if (getUseDayCycle()) - { - success = useDayCycle(getDayCycleName(), LLEnvKey::SCOPE_LOCAL); - } - else - { - success = useSkyPreset(getSkyPresetName()); - } - } - - // If something went wrong, fall back to defaults. - if (!success) - { - // *TODO: fix user prefs - useDefaultSky(); - } -} - -void LLEnvManagerNew::updateWaterFromPrefs(bool interpolate) -{ - LLWaterParamManager& water_mgr = LLWaterParamManager::instance(); - LLSD target_water_params; - - // Determine new water settings based on user prefs. - - { - // Fall back to default water. - LLWaterParamSet default_water; - water_mgr.getParamSet("Default", default_water); - target_water_params = default_water.getAll(); - } - - if (getUseRegionSettings()) - { - // *TODO: make sure whether region settings belong to the current region? - const LLSD& region_water_params = getRegionSettings().getWaterParams(); - if (region_water_params.size() != 0) // region has no water settings - { - LL_DEBUGS("Windlight") << "Applying region water" << LL_ENDL; - target_water_params = region_water_params; - } - else - { - LL_DEBUGS("Windlight") << "Applying default water" << LL_ENDL; - } - } - else - { - std::string water = getWaterPresetName(); - LL_DEBUGS("Windlight") << "Applying water preset [" << water << "]" << LL_ENDL; - LLWaterParamSet params; - if (!water_mgr.getParamSet(water, params)) - { - LL_WARNS() << "No water preset named " << water << ", falling back to defaults" << LL_ENDL; - water_mgr.getParamSet("Default", params); - - // *TODO: Fix user preferences accordingly. - } - target_water_params = params.getAll(); - } - - // Sync water with user prefs. - water_mgr.applyParams(target_water_params, interpolate); -} - -void LLEnvManagerNew::updateManagersFromPrefs(bool interpolate) -{ - LL_DEBUGS("Windlight")<<LL_ENDL; - // Apply water settings. - updateWaterFromPrefs(interpolate); - - // Apply sky settings. - updateSkyFromPrefs(); -} - -bool LLEnvManagerNew::useRegionSky() -{ - const LLEnvironmentSettings& region_settings = getRegionSettings(); - - // If region is set to defaults, - if (region_settings.getSkyMap().size() == 0) - { - // well... apply the default sky settings. - useDefaultSky(); - return true; - } - - // Otherwise apply region day cycle/skies. - LL_DEBUGS("Windlight") << "Applying region sky" << LL_ENDL; - - // *TODO: Support fixed sky from region. Just do sky reset for now. - if (region_settings.getSkyMap().size() == 1) - { - // Region is set to fixed sky. Reset. - useSkyParams(region_settings.getSkyMap().beginMap()->second); - } - return useDayCycleParams( - region_settings.getWLDayCycle(), - LLEnvKey::SCOPE_REGION, - region_settings.getDayTime()); -} - -bool LLEnvManagerNew::useRegionWater() -{ - const LLEnvironmentSettings& region_settings = getRegionSettings(); - const LLSD& region_water = region_settings.getWaterParams(); - - // If region is set to defaults, - if (region_water.size() == 0) - { - // well... apply the default water settings. - return useDefaultWater(); - } - - // Otherwise apply region water. - LL_DEBUGS("Windlight") << "Applying region sky" << LL_ENDL; - return useWaterParams(region_water); -} - -bool LLEnvManagerNew::useDefaultSky() -{ - return useDayCycle("Default", LLEnvKey::SCOPE_LOCAL); -} - -bool LLEnvManagerNew::useDefaultWater() -{ - return useWaterPreset("Default"); -} - - -void LLEnvManagerNew::onRegionChange() -{ - // Avoid duplicating region setting requests - // by checking whether the region is actually changing. - LLViewerRegion* regionp = gAgent.getRegion(); - LLUUID region_uuid = regionp ? regionp->getRegionID() : LLUUID::null; - if (region_uuid != mCurRegionUUID) - { - // 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; - } -} diff --git a/indra/newview/llenvmanager.h b/indra/newview/llenvmanager.h deleted file mode 100644 index 54bbf85e86..0000000000 --- a/indra/newview/llenvmanager.h +++ /dev/null @@ -1,349 +0,0 @@ -/** - * @file llenvmanager.h - * @brief Declaration of classes managing WindLight and water settings. - * - * $LicenseInfo:firstyear=2009&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_LLENVMANAGER_H -#define LL_LLENVMANAGER_H - -#include "llmemory.h" -#include "llsd.h" - -class LLWLParamManager; -class LLWaterParamManager; -class LLWLAnimator; - -// generic key -struct LLEnvKey -{ -public: - // Note: enum ordering is important; for example, a region-level floater (1) will see local and region (all values that are <=) - typedef enum e_scope - { - SCOPE_LOCAL, // 0 - SCOPE_REGION//, // 1 - // SCOPE_ESTATE, // 2 - // etc. - } EScope; -}; - -struct LLWLParamKey : LLEnvKey -{ -public: - // scope and source of a param set (WL sky preset) - std::string name; - EScope scope; - - // for conversion from LLSD - static const int NAME_IDX = 0; - static const int SCOPE_IDX = 1; - - inline LLWLParamKey(const std::string& n, EScope s) - : name(n), scope(s) - { - } - - inline LLWLParamKey(LLSD llsd) - : name(llsd[NAME_IDX].asString()), scope(EScope(llsd[SCOPE_IDX].asInteger())) - { - } - - inline LLWLParamKey() // NOT really valid, just so std::maps can return a default of some sort - : name(""), scope(SCOPE_LOCAL) - { - } - - inline LLWLParamKey(std::string& stringVal) - { - size_t len = stringVal.length(); - if (len > 0) - { - name = stringVal.substr(0, len - 1); - scope = (EScope) atoi(stringVal.substr(len - 1, len).c_str()); - } - } - - inline std::string toStringVal() const - { - std::stringstream str; - str << name << scope; - return str.str(); - } - - inline LLSD toLLSD() const - { - LLSD llsd = LLSD::emptyArray(); - llsd.append(LLSD(name)); - llsd.append(LLSD(scope)); - return llsd; - } - - inline void fromLLSD(const LLSD& llsd) - { - name = llsd[NAME_IDX].asString(); - scope = EScope(llsd[SCOPE_IDX].asInteger()); - } - - inline bool operator <(const LLWLParamKey other) const - { - if (name < other.name) - { - return true; - } - else if (name > other.name) - { - return false; - } - else - { - return scope < other.scope; - } - } - - inline bool operator ==(const LLWLParamKey other) const - { - return (name == other.name) && (scope == other.scope); - } - - std::string toString() const; -}; - -class LLEnvironmentSettings -{ -public: - LLEnvironmentSettings() : - mWLDayCycle(LLSD::emptyMap()), - mSkyMap(LLSD::emptyMap()), - mWaterParams(LLSD::emptyMap()), - mDayTime(0.f) - {} - LLEnvironmentSettings(const LLSD& dayCycle, const LLSD& skyMap, const LLSD& waterParams, F64 dayTime) : - mWLDayCycle(dayCycle), - mSkyMap(skyMap), - mWaterParams(waterParams), - mDayTime(dayTime) - {} - ~LLEnvironmentSettings() {} - - void saveParams(const LLSD& dayCycle, const LLSD& skyMap, const LLSD& waterParams, F64 dayTime) - { - mWLDayCycle = dayCycle; - mSkyMap = skyMap; - mWaterParams = waterParams; - mDayTime = dayTime; - } - - const LLSD& getWLDayCycle() const - { - return mWLDayCycle; - } - - const LLSD& getWaterParams() const - { - return mWaterParams; - } - - const LLSD& getSkyMap() const - { - return mSkyMap; - } - - F64 getDayTime() const - { - return mDayTime; - } - - bool isEmpty() const - { - return mWLDayCycle.size() == 0; - } - - void clear() - { - *this = LLEnvironmentSettings(); - } - - LLSD makePacket(const LLSD& metadata) const - { - LLSD full_packet = LLSD::emptyArray(); - - // 0: metadata - full_packet.append(metadata); - - // 1: day cycle - full_packet.append(mWLDayCycle); - - // 2: map of sky setting names to sky settings (as LLSD) - full_packet.append(mSkyMap); - - // 3: water params - full_packet.append(mWaterParams); - - return full_packet; - } - -private: - LLSD mWLDayCycle, mWaterParams, mSkyMap; - F64 mDayTime; -}; - -/** - * User environment preferences. - */ -class LLEnvPrefs -{ -public: - LLEnvPrefs() : mUseRegionSettings(true), mUseDayCycle(true) {} - - bool getUseRegionSettings() const { return mUseRegionSettings; } - bool getUseDayCycle() const { return mUseDayCycle; } - bool getUseFixedSky() const { return !getUseDayCycle(); } - - std::string getWaterPresetName() const; - std::string getSkyPresetName() const; - std::string getDayCycleName() const; - - void setUseRegionSettings(bool val); - void setUseWaterPreset(const std::string& name); - void setUseSkyPreset(const std::string& name); - void setUseDayCycle(const std::string& name); - - bool mUseRegionSettings; - bool mUseDayCycle; - std::string mWaterPresetName; - std::string mSkyPresetName; - std::string mDayCycleName; -}; - -/** - * Setting: - * 1. Use region settings. - * 2. Use my setting: <water preset> + <fixed_sky>|<day_cycle> - */ -class LLEnvManagerNew : public LLSingleton<LLEnvManagerNew> -{ - LLSINGLETON(LLEnvManagerNew); - LOG_CLASS(LLEnvManagerNew); -public: - typedef boost::signals2::signal<void()> prefs_change_signal_t; - typedef boost::signals2::signal<void()> region_settings_change_signal_t; - typedef boost::signals2::signal<void(bool)> region_settings_applied_signal_t; - - // getters to access user env. preferences - bool getUseRegionSettings() const; - bool getUseDayCycle() const; - bool getUseFixedSky() const; - std::string getWaterPresetName() const; - std::string getSkyPresetName() const; - std::string getDayCycleName() const; - - /// @return cached env. settings of the current region. - const LLEnvironmentSettings& getRegionSettings() const; - - /** - * Set new region settings without uploading them to the region. - * - * The override will be reset when the changes are applied to the region (=uploaded) - * or user teleports to another region. - */ - void setRegionSettings(const LLEnvironmentSettings& new_settings); - - // Change environment w/o changing user preferences. - bool usePrefs(); - bool useDefaults(); - bool useRegionSettings(); - bool useWaterPreset(const std::string& name); - bool useWaterParams(const LLSD& params); - bool useSkyPreset(const std::string& name); - bool useSkyParams(const LLSD& params); - bool useDayCycle(const std::string& name, LLEnvKey::EScope scope); - bool useDayCycleParams(const LLSD& params, LLEnvKey::EScope scope, F32 time = 0.5); - - // setters for user env. preferences - void setUseRegionSettings(bool val); - void setUseWaterPreset(const std::string& name); - void setUseSkyPreset(const std::string& name); - void setUseDayCycle(const std::string& name); - void setUserPrefs( - const std::string& water_preset, - const std::string& sky_preset, - const std::string& day_cycle_preset, - bool use_fixed_sky, - bool use_region_settings); - - // debugging methods - void dumpUserPrefs(); - void dumpPresets(); - - // Misc. - void requestRegionSettings(); - 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 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 onRegionSettingsResponse(const LLSD& content); - void onRegionSettingsApplyResponse(bool ok); - -private: - /*virtual*/ void initSingleton(); - - void loadUserPrefs(); - void saveUserPrefs(); - - void updateSkyFromPrefs(); - void updateWaterFromPrefs(bool interpolate); - void updateManagersFromPrefs(bool interpolate); - - bool useRegionSky(); - bool useRegionWater(); - - bool useDefaultSky(); - bool useDefaultWater(); - - void onRegionChange(); - - /// Emitted when user environment preferences change. - prefs_change_signal_t mUsePrefsChangeSignal; - - /// Emitted when region environment settings update comes. - region_settings_change_signal_t mRegionSettingsChangeSignal; - - /// Emitted when agent region changes. Move to LLAgent? - region_settings_applied_signal_t mRegionSettingsAppliedSignal; - - LLEnvPrefs mUserPrefs; /// User environment preferences. - LLEnvironmentSettings mCachedRegionPrefs; /// Cached region environment settings. - LLEnvironmentSettings mNewRegionPrefs; /// Not-yet-uploaded modified region env. settings. - bool mInterpNextChangeMessage; /// Interpolate env. settings on next region change. - LLUUID mCurRegionUUID; /// To avoid duplicated region env. settings requests. - LLUUID mLastReceivedID; /// Id of last received region env. settings. -}; - -#endif // LL_LLENVMANAGER_H - diff --git a/indra/newview/llestateinfomodel.cpp b/indra/newview/llestateinfomodel.cpp index 95d40be913..4fdb860592 100644 --- a/indra/newview/llestateinfomodel.cpp +++ b/indra/newview/llestateinfomodel.cpp @@ -73,6 +73,7 @@ bool LLEstateInfoModel::getDenyAnonymous() const { return getFlag(REGION_FLAGS bool LLEstateInfoModel::getDenyAgeUnverified() const { return getFlag(REGION_FLAGS_DENY_AGEUNVERIFIED); } bool LLEstateInfoModel::getAllowVoiceChat() const { return getFlag(REGION_FLAGS_ALLOW_VOICE); } bool LLEstateInfoModel::getAllowAccessOverride() const { return getFlag(REGION_FLAGS_ALLOW_ACCESS_OVERRIDE); } +bool LLEstateInfoModel::getAllowEnvironmentOverride() const { return getFlag(REGION_FLAGS_ALLOW_ENVIRONMENT_OVERRIDE); } void LLEstateInfoModel::setUseFixedSun(bool val) { setFlag(REGION_FLAGS_SUN_FIXED, val); } void LLEstateInfoModel::setIsExternallyVisible(bool val) { setFlag(REGION_FLAGS_EXTERNALLY_VISIBLE, val); } @@ -81,6 +82,7 @@ void LLEstateInfoModel::setDenyAnonymous(bool val) { setFlag(REGION_FLAGS_DENY void LLEstateInfoModel::setDenyAgeUnverified(bool val) { setFlag(REGION_FLAGS_DENY_AGEUNVERIFIED, val); } void LLEstateInfoModel::setAllowVoiceChat(bool val) { setFlag(REGION_FLAGS_ALLOW_VOICE, val); } void LLEstateInfoModel::setAllowAccessOverride(bool val) { setFlag(REGION_FLAGS_ALLOW_ACCESS_OVERRIDE, val); } +void LLEstateInfoModel::setAllowEnvironmentOverride(bool val) { setFlag(REGION_FLAGS_ALLOW_ENVIRONMENT_OVERRIDE, val); } void LLEstateInfoModel::update(const strings_t& strings) { @@ -222,6 +224,7 @@ std::string LLEstateInfoModel::getInfoDump() dump["deny_age_unverified" ] = getDenyAgeUnverified(); dump["allow_voice_chat" ] = getAllowVoiceChat(); dump["override_public_access"] = getAllowAccessOverride(); + dump["override_environment"] = getAllowEnvironmentOverride(); std::stringstream dump_str; dump_str << dump; diff --git a/indra/newview/llestateinfomodel.h b/indra/newview/llestateinfomodel.h index 0082b5b1f4..d6f00c573c 100644 --- a/indra/newview/llestateinfomodel.h +++ b/indra/newview/llestateinfomodel.h @@ -56,6 +56,7 @@ public: bool getDenyAgeUnverified() const; bool getAllowVoiceChat() const; bool getAllowAccessOverride() const; + bool getAllowEnvironmentOverride() const; const std::string& getName() const { return mName; } const LLUUID& getOwnerID() const { return mOwnerID; } @@ -70,6 +71,7 @@ public: void setDenyAgeUnverified(bool val); void setAllowVoiceChat(bool val); void setAllowAccessOverride(bool val); + void setAllowEnvironmentOverride(bool val); void setSunHour(F32 sun_hour) { mSunHour = sun_hour; } diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index 5e0f3ab7f9..4b5fd8a758 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -106,6 +106,7 @@ namespace Details LLSD message; message["sender"] = mSenderIp; message["body"] = content["body"]; + LLMessageSystem::dispatch(msg_name, message); } @@ -165,6 +166,14 @@ namespace Details // LL_DEBUGS("LLEventPollImpl::eventPollCoro") << "<" << counter << "> result = " // << LLSDXMLStreamer(result) << LL_ENDL; + if (gDisconnected) + { + // Lost connection or disconnected during quit, don't process sim/region update + // messages, they might populate some cleaned up classes (LLWorld, region and object list) + LL_INFOS("LLEventPollImpl") << "Dropping event messages" << LL_ENDL; + break; + } + LLSD httpResults = result["http_result"]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); @@ -209,7 +218,7 @@ namespace Details llcoro::suspendUntilTimeout(waitToRetry); - if (mDone) + if (mDone || gDisconnected) break; LL_INFOS("LLEventPollImpl") << "<" << counter << "> About to retry request." << LL_ENDL; continue; @@ -241,7 +250,7 @@ namespace Details !result.get("events") || !result.get("id")) { - LL_WARNS("LLEventPollImpl") << " <" << counter << "> received event poll with no events or id key: " << LLSDXMLStreamer(result) << LL_ENDL; + LL_WARNS("LLEventPollImpl") << " <" << counter << "> received event poll with no events or id key: " << result << LL_ENDL; continue; } @@ -254,7 +263,7 @@ namespace Details } // was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG - LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> " << events.size() << "events (id " << LLSDXMLStreamer(acknowledge) << ")" << LL_ENDL; + LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> " << events.size() << "events (id " << acknowledge << ")" << LL_ENDL; LLSD::array_const_iterator i = events.beginArray(); LLSD::array_const_iterator end = events.endArray(); diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp index a03b84daa5..2d332f75f5 100644 --- a/indra/newview/llexpandabletextbox.cpp +++ b/indra/newview/llexpandabletextbox.cpp @@ -97,7 +97,7 @@ public: /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) { mEditor.onCommit(); return TRUE; } /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) { - LLUI::getWindow()->setCursor(UI_CURSOR_HAND); + LLUI::getInstance()->getWindow()->setCursor(UI_CURSOR_HAND); return TRUE; } private: diff --git a/indra/newview/llexperiencelog.h b/indra/newview/llexperiencelog.h index 09e0cd8821..5cc5bf685f 100644 --- a/indra/newview/llexperiencelog.h +++ b/indra/newview/llexperiencelog.h @@ -62,10 +62,9 @@ public: static std::string getPermissionString(const LLSD& message, const std::string& base); void setEventsToSave(LLSD new_events){mEventsToSave = new_events; } bool isNotExpired(std::string& date); -protected: void handleExperienceMessage(LLSD& message); - +protected: void loadEvents(); void saveEvents(); void eraseExpired(); diff --git a/indra/newview/llexternaleditor.cpp b/indra/newview/llexternaleditor.cpp index 776bbf78c2..b66eb754a4 100644 --- a/indra/newview/llexternaleditor.cpp +++ b/indra/newview/llexternaleditor.cpp @@ -184,9 +184,9 @@ std::string LLExternalEditor::findCommand( cmd = override; LL_INFOS() << "Using override" << LL_ENDL; } - else if (!LLUI::sSettingGroups["config"]->getString(sSetting).empty()) + else if (!LLUI::getInstance()->mSettingGroups["config"]->getString(sSetting).empty()) { - cmd = LLUI::sSettingGroups["config"]->getString(sSetting); + cmd = LLUI::getInstance()->mSettingGroups["config"]->getString(sSetting); LL_INFOS() << "Using setting" << LL_ENDL; } else // otherwise use the path specified by the environment variable diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 912bde9986..4a802ad9aa 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -153,7 +153,7 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) } mTEOffset = -1; - mTextureIndex = 255; + mTextureIndex = FACE_DO_NOT_BATCH_TEXTURES; setDrawable(drawablep); mVObjp = objp; @@ -168,7 +168,8 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) mImportanceToCamera = 0.f ; mBoundingSphereRadius = 0.0f ; - mHasMedia = FALSE ; + mHasMedia = false ; + mIsMediaAllowed = true; } void LLFace::destroy() @@ -183,6 +184,7 @@ void LLFace::destroy() if(mTexture[i].notNull()) { mTexture[i]->removeFace(i, this) ; + mTexture[i] = NULL; } } @@ -194,7 +196,7 @@ void LLFace::destroy() if (mDrawPoolp) { - if (this->isState(LLFace::RIGGED) && mDrawPoolp->getType() == LLDrawPool::POOL_AVATAR) + if (this->isState(LLFace::RIGGED) && (mDrawPoolp->getType() == LLDrawPool::POOL_CONTROL_AV || mDrawPoolp->getType() == LLDrawPool::POOL_AVATAR)) { ((LLDrawPoolAvatar*) mDrawPoolp)->removeRiggedFace(this); } @@ -202,7 +204,6 @@ void LLFace::destroy() { mDrawPoolp->removeFace(this); } - mDrawPoolp = NULL; } @@ -211,7 +212,7 @@ void LLFace::destroy() delete mTextureMatrix; mTextureMatrix = NULL; - if (mDrawablep.notNull()) + if (mDrawablep) { LLSpatialGroup* group = mDrawablep->getSpatialGroup(); if (group) @@ -223,17 +224,11 @@ void LLFace::destroy() } setDrawInfo(NULL); - + mDrawablep = NULL; mVObjp = NULL; } - -// static -void LLFace::initClass() -{ -} - void LLFace::setWorldMatrix(const LLMatrix4 &mat) { LL_ERRS() << "Faces on this drawable are not independently modifiable\n" << LL_ENDL; @@ -308,6 +303,11 @@ void LLFace::setDiffuseMap(LLViewerTexture* tex) setTexture(LLRender::DIFFUSE_MAP, tex); } +void LLFace::setAlternateDiffuseMap(LLViewerTexture* tex) +{ + setTexture(LLRender::ALTERNATE_DIFFUSE_MAP, tex); +} + void LLFace::setNormalMap(LLViewerTexture* tex) { setTexture(LLRender::NORMAL_MAP, tex); @@ -456,7 +456,7 @@ void LLFace::setTextureIndex(U8 index) { mTextureIndex = index; - if (mTextureIndex != 255) + if (mTextureIndex != FACE_DO_NOT_BATCH_TEXTURES) { mDrawablep->setState(LLDrawable::REBUILD_POSITION); } @@ -535,7 +535,7 @@ void LLFace::updateCenterAgent() void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) { - if (mDrawablep->getSpatialGroup() == NULL) + if (mDrawablep == NULL || mDrawablep->getSpatialGroup() == NULL) { return; } @@ -543,7 +543,7 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) mDrawablep->getSpatialGroup()->rebuildGeom(); mDrawablep->getSpatialGroup()->rebuildMesh(); - if(mDrawablep.isNull() || mVertexBuffer.isNull()) + if(mVertexBuffer.isNull()) { return; } @@ -1420,17 +1420,16 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (shiny_in_alpha) { - - static const GLfloat alpha[4] = + static const GLfloat SHININESS_TO_ALPHA[4] = { - 0.00f, + 0.0000f, 0.25f, 0.5f, 0.75f }; llassert(tep->getShiny() <= 3); - color.mV[3] = U8 (alpha[tep->getShiny()] * 255); + color.mV[3] = U8 (SHININESS_TO_ALPHA[tep->getShiny()] * 255); } } } @@ -1540,7 +1539,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_VERTEX, mGeomIndex, mGeomCount); - U8 index = mTextureIndex < 255 ? mTextureIndex : 0; + U8 index = mTextureIndex < FACE_DO_NOT_BATCH_TEXTURES ? mTextureIndex : 0; S32 val = 0; U8* vp = (U8*) &val; @@ -1716,7 +1715,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, // 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 moon_ray = gSky.mVOSkyp->getMoon().getDirection(); 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); @@ -2073,7 +2072,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLVector4a texIdx; - S32 index = mTextureIndex < 255 ? mTextureIndex : 0; + S32 index = mTextureIndex < FACE_DO_NOT_BATCH_TEXTURES ? mTextureIndex : 0; F32 val = 0.f; S32* vp = (S32*) &val; @@ -2674,7 +2673,7 @@ S32 LLFace::renderElements(const U16 *index_array) const S32 LLFace::renderIndexed() { - if(mDrawablep.isNull() || mDrawPoolp == NULL) + if(mDrawablep == NULL || mDrawPoolp == NULL) { return 0; } diff --git a/indra/newview/llface.h b/indra/newview/llface.h index a08e730e54..3611539ff8 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -52,6 +52,7 @@ class LLDrawInfo; const F32 MIN_ALPHA_SIZE = 1024.f; const F32 MIN_TEX_ANIM_SIZE = 512.f; +const U8 FACE_DO_NOT_BATCH_TEXTURES = 255; class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16> { @@ -80,8 +81,6 @@ public: PARTICLE = 0x0080, }; - static void initClass(); - static void cacheFaceInVRAM(const LLVolumeFace& vf); public: @@ -106,6 +105,7 @@ public: void setDiffuseMap(LLViewerTexture* tex); void setNormalMap(LLViewerTexture* tex); void setSpecularMap(LLViewerTexture* tex); + void setAlternateDiffuseMap(LLViewerTexture* tex); void switchTexture(U32 ch, LLViewerTexture* new_texture); void dirtyTexture(); LLXformMatrix* getXform() const { return mXform; } @@ -219,6 +219,9 @@ public: void setHasMedia(bool has_media) { mHasMedia = has_media ;} BOOL hasMedia() const ; + void setMediaAllowed(bool is_media_allowed) { mIsMediaAllowed = is_media_allowed; } + BOOL isMediaAllowed() const { return mIsMediaAllowed; } + BOOL switchTexture() ; //vertex buffer tracking @@ -277,8 +280,13 @@ private: LLXformMatrix* mXform; LLPointer<LLViewerTexture> mTexture[LLRender::NUM_TEXTURE_CHANNELS]; - - LLPointer<LLDrawable> mDrawablep; + + // mDrawablep is not supposed to be null, don't use LLPointer because + // mDrawablep owns LLFace and LLPointer is a good way to either cause a + // memory leak or a 'delete each other' situation if something deletes + // drawable wrongly. + LLDrawable* mDrawablep; + // LLViewerObject technically owns drawable, but also it should be strictly managed LLPointer<LLViewerObject> mVObjp; S32 mTEOffset; @@ -294,6 +302,7 @@ private: F32 mImportanceToCamera ; F32 mBoundingSphereRadius ; bool mHasMedia ; + bool mIsMediaAllowed; protected: diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index d90f03b403..239d162101 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -130,7 +130,7 @@ BOOL LLFastTimerView::postBuild() { LLButton& pause_btn = getChildRef<LLButton>("pause_btn"); mScrollBar = getChild<LLScrollbar>("scroll_vert"); - + pause_btn.setCommitCallback(boost::bind(&LLFastTimerView::onPause, this)); return TRUE; } @@ -361,12 +361,12 @@ BOOL LLFastTimerView::handleScrollWheel(S32 x, S32 y, S32 clicks) } else { - setPauseState(true); - mScrollIndex = llclamp(mScrollIndex + clicks, - 0, - llmin((S32)mRecording.getNumRecordedPeriods(), (S32)mRecording.getNumRecordedPeriods() - MAX_VISIBLE_HISTORY)); + setPauseState(true); + mScrollIndex = llclamp( mScrollIndex + clicks, + 0, + llmin((S32)mRecording.getNumRecordedPeriods(), (S32)mRecording.getNumRecordedPeriods() - MAX_VISIBLE_HISTORY)); } - return TRUE; + return TRUE; } static BlockTimerStatHandle FTM_RENDER_TIMER("Timers"); diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 5b4b7789b4..83b5bf3f25 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -38,6 +38,7 @@ #include "lltooltip.h" #include "llagent.h" +#include "llagentpicksinfo.h" #include "llavatarnamecache.h" #include "llclipboard.h" #include "llinventorybridge.h" @@ -384,6 +385,8 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p) mUpdateDropDownItems(true), mRestoreOverflowMenu(false), mGetPrevItems(true), + mMouseX(0), + mMouseY(0), mItemsChangedTimer() { // Register callback for menus with current registrar (will be parent panel's registrar) @@ -399,8 +402,10 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p) //make chevron button LLTextBox::Params more_button_params(p.more_button); mMoreTextBox = LLUICtrlFactory::create<LLTextBox> (more_button_params); - mMoreTextBox->setClickedCallback(boost::bind(&LLFavoritesBarCtrl::showDropDownMenu, this)); + mMoreTextBox->setClickedCallback(boost::bind(&LLFavoritesBarCtrl::onMoreTextBoxClicked, this)); addChild(mMoreTextBox); + LLRect rect = mMoreTextBox->getRect(); + mMoreTextBox->setRect(LLRect(rect.mLeft - rect.getWidth(), rect.mTop, rect.mRight, rect.mBottom)); mDropDownItemsCount = 0; @@ -975,6 +980,12 @@ BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &it return TRUE; } +void LLFavoritesBarCtrl::onMoreTextBoxClicked() +{ + LLUI::getInstance()->getMousePositionScreen(&mMouseX, &mMouseY); + showDropDownMenu(); +} + void LLFavoritesBarCtrl::showDropDownMenu() { if (mOverflowMenuHandle.isDead()) @@ -1130,7 +1141,7 @@ void LLFavoritesBarCtrl::positionAndShowMenu(LLToggleableMenu* menu) } } - LLMenuGL::showPopup(this, menu, menu_x, menu_y); + LLMenuGL::showPopup(this, menu, menu_x, menu_y, mMouseX, mMouseY); } void LLFavoritesBarCtrl::onButtonClick(LLUUID item_id) @@ -1194,6 +1205,10 @@ bool LLFavoritesBarCtrl::enableSelected(const LLSD& userdata) { return isClipboardPasteable(); } + else if (param == "create_pick") + { + return !LLAgentPicksInfo::getInstance()->isPickLimitReached(); + } return false; } @@ -1242,6 +1257,13 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata) LLFloaterReg::showInstance("world_map", "center"); } } + else if (action == "create_pick") + { + LLSD args; + args["type"] = "create_pick"; + args["item_id"] = item->getUUID(); + LLFloaterSidePanelContainer::showPanel("places", args); + } else if (action == "cut") { } @@ -1257,6 +1279,20 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata) { gInventory.removeItem(mSelectedItemID); } + else if (action == "rename") + { + LLSD args; + args["NAME"] = item->getName(); + + LLSD payload; + payload["id"] = mSelectedItemID; + + LLNotificationsUtil::add("RenameLandmark", args, payload, boost::bind(onRenameCommit, _1, _2)); + } + else if (action == "move_to_landmarks") + { + change_item_parent(mSelectedItemID, gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK)); + } // Pop-up the overflow menu again (it gets hidden whenever the user clicks a context menu item). // See EXT-4217 and STORM-207. @@ -1269,6 +1305,28 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata) } } +bool LLFavoritesBarCtrl::onRenameCommit(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LLUUID id = notification["payload"]["id"].asUUID(); + LLInventoryItem *item = gInventory.getItem(id); + std::string landmark_name = response["new_name"].asString(); + LLStringUtil::trim(landmark_name); + + if (!landmark_name.empty() && item && item->getName() != landmark_name) + { + LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); + new_item->rename(landmark_name); + new_item->updateServer(FALSE); + gInventory.updateItem(new_item); + } + } + + return false; +} + BOOL LLFavoritesBarCtrl::isClipboardPasteable() const { if (!LLClipboard::instance().hasContents()) @@ -1493,19 +1551,25 @@ void LLFavoritesOrderStorage::getSLURL(const LLUUID& asset_id) } // static -std::string LLFavoritesOrderStorage::getStoredFavoritesFilename() +std::string LLFavoritesOrderStorage::getStoredFavoritesFilename(const std::string &grid) { - std::string user_dir = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""); + std::string user_dir = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""); return (user_dir.empty() ? "" : gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites_" - + LLGridManager::getInstance()->getGrid() + + grid + ".xml") ); } // static +std::string LLFavoritesOrderStorage::getStoredFavoritesFilename() +{ + return getStoredFavoritesFilename(LLGridManager::getInstance()->getGrid()); +} + +// static void LLFavoritesOrderStorage::destroyClass() { LLFavoritesOrderStorage::instance().cleanup(); @@ -1584,14 +1648,29 @@ void LLFavoritesOrderStorage::load() << (fav_llsd.isMap() ? "" : "un") << "successfully" << LL_ENDL; in_file.close(); - user_llsd = fav_llsd[gAgentUsername]; + if (fav_llsd.isMap() && fav_llsd.has(gAgentUsername)) + { + user_llsd = fav_llsd[gAgentUsername]; - S32 index = 0; - for (LLSD::array_iterator iter = user_llsd.beginArray(); + S32 index = 0; + bool needs_validation = gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"); + for (LLSD::array_iterator iter = user_llsd.beginArray(); iter != user_llsd.endArray(); ++iter) - { - mSortIndexes.insert(std::make_pair(iter->get("id").asUUID(), index)); - index++; + { + // Validation + LLUUID fv_id = iter->get("id").asUUID(); + if (needs_validation + && (fv_id.isNull() + || iter->get("asset_id").asUUID().isNull() + || iter->get("name").asString().empty() + || iter->get("slurl").asString().empty())) + { + mRecreateFavoriteStorage = true; + } + + mSortIndexes.insert(std::make_pair(fv_id, index)); + index++; + } } } else @@ -1602,6 +1681,64 @@ void LLFavoritesOrderStorage::load() } } +// static +void LLFavoritesOrderStorage::removeFavoritesRecordOfUser(const std::string &user, const std::string &grid) +{ + std::string filename = getStoredFavoritesFilename(grid); + if (!filename.empty()) + { + LLSD fav_llsd; + llifstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::fromXML(fav_llsd, file); + file.close(); + + // 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(user)) + { + LLSD user_llsd = fav_llsd[user]; + + if ((user_llsd.beginArray() != user_llsd.endArray()) && user_llsd.beginArray()->has("id")) + { + for (LLSD::array_iterator iter = user_llsd.beginArray(); iter != user_llsd.endArray(); ++iter) + { + LLSD value; + value["id"] = iter->get("id").asUUID(); + iter->assign(value); + } + fav_llsd[user] = user_llsd; + llofstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::toPrettyXML(fav_llsd, file); + file.close(); + } + } + else + { + LL_INFOS("FavoritesBar") << "Removed favorites for " << user << LL_ENDL; + fav_llsd.erase(user); + } + } + + 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(); + } + } + } +} + +// static void LLFavoritesOrderStorage::removeFavoritesRecordOfUser() { std::string filename = getStoredFavoritesFilename(); @@ -1777,6 +1914,8 @@ void LLFavoritesOrderStorage::rearrangeFavoriteLandmarks(const LLUUID& source_it BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed) { + pref_changed |= mRecreateFavoriteStorage; + mRecreateFavoriteStorage = false; LLUUID favorite_folder= gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); if (favorite_folder.isNull()) diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index cac32c7f2a..3bb940948b 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -91,11 +91,14 @@ protected: bool enableSelected(const LLSD& userdata); void doToSelected(const LLSD& userdata); + static bool onRenameCommit(const LLSD& notification, const LLSD& response); BOOL isClipboardPasteable() const; void pasteFromClipboard() const; void showDropDownMenu(); + void onMoreTextBoxClicked(); + LLHandle<LLView> mOverflowMenuHandle; LLHandle<LLView> mContextMenuHandle; @@ -163,6 +166,9 @@ private: BOOL mTabsHighlightEnabled; + S32 mMouseX; + S32 mMouseY; + boost::signals2::connection mEndDragConnection; }; @@ -208,9 +214,15 @@ public: * @see cleanup() */ static void destroyClass(); + static std::string getStoredFavoritesFilename(const std::string &grid); static std::string getStoredFavoritesFilename(); static std::string getSavedOrderFileName(); + // Remove record of specified user's favorites from file on disk. + static void removeFavoritesRecordOfUser(const std::string &user, const std::string &grid); + // Remove record of current user's favorites from file on disk. + static void removeFavoritesRecordOfUser(); + BOOL saveFavoritesRecord(bool pref_changed = false); void showFavoritesOnLoginChanged(BOOL show); @@ -232,9 +244,6 @@ private: void load(); - // 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); @@ -245,6 +254,7 @@ private: slurls_map_t mSLURLs; std::set<LLUUID> mMissingSLURLs; bool mIsDirty; + bool mRecreateFavoriteStorage; struct IsNotInFavorites { @@ -275,7 +285,9 @@ private: inline LLFavoritesOrderStorage::LLFavoritesOrderStorage() : - mIsDirty(false), mUpdateRequired(false) + mIsDirty(false), + mUpdateRequired(false), + mRecreateFavoriteStorage(false) { load(); } #endif // LL_LLFAVORITESBARCTRL_H diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 8d07035b97..e6bbe234b3 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -379,22 +379,6 @@ F32 gpu_benchmark(); #if LL_WINDOWS -static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific - -U32 exception_benchmark_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) -{ - if (code == STATUS_MSC_EXCEPTION) - { - // C++ exception, go on - return EXCEPTION_CONTINUE_SEARCH; - } - else - { - // handle it - return EXCEPTION_EXECUTE_HANDLER; - } -} - F32 logExceptionBenchmark() { // Todo: make a wrapper/class for SEH exceptions @@ -403,7 +387,7 @@ F32 logExceptionBenchmark() { gbps = gpu_benchmark(); } - __except (exception_benchmark_filter(GetExceptionCode(), GetExceptionInformation())) + __except (msc_exception_filter(GetExceptionCode(), GetExceptionInformation())) { // convert to C++ styled exception char integer_string[32]; @@ -522,7 +506,7 @@ void LLFeatureManager::cleanupFeatureTables() mMaskList.clear(); } -void LLFeatureManager::init() +void LLFeatureManager::initSingleton() { // load the tables loadFeatureTables(); @@ -617,36 +601,36 @@ void LLFeatureManager::applyFeatures(bool skipFeatures) void LLFeatureManager::setGraphicsLevel(U32 level, bool skipFeatures) { - LLViewerShaderMgr::sSkipReload = true; + LLViewerShaderMgr::sSkipReload = true; - applyBaseMasks(); + applyBaseMasks(); - // if we're passed an invalid level, default to "Low" - std::string features(isValidGraphicsLevel(level)? getNameForGraphicsLevel(level) : "Low"); - if (features == "Low") - { + // if we're passed an invalid level, default to "Low" + std::string features(isValidGraphicsLevel(level)? getNameForGraphicsLevel(level) : "Low"); + if (features == "Low") + { #if LL_DARWIN - // This Mac-specific change is to insure that we force 'Basic Shaders' for all Mac - // systems which support them instead of falling back to fixed-function unnecessarily - // MAINT-2157 - if (gGLManager.mGLVersion < 2.1f) + // This Mac-specific change is to insure that we force 'Basic Shaders' for all Mac + // systems which support them instead of falling back to fixed-function unnecessarily + // MAINT-2157 + if (gGLManager.mGLVersion < 2.1f) #else - // only use fixed function by default if GL version < 3.0 or this is an intel graphics chip - if (gGLManager.mGLVersion < 3.f || gGLManager.mIsIntel) + // only use fixed function by default if GL version < 3.0 or this is an intel graphics chip + if (gGLManager.mGLVersion < 3.f || gGLManager.mIsIntel) #endif - { + { // same as Low, but with "Basic Shaders" disabled - features = "LowFixedFunction"; - } - } + features = "LowFixedFunction"; + } + } - maskFeatures(features); + maskFeatures(features); - applyFeatures(skipFeatures); + applyFeatures(skipFeatures); - LLViewerShaderMgr::sSkipReload = false; - LLViewerShaderMgr::instance()->setShaders(); - gPipeline.refreshCachedSettings(); + LLViewerShaderMgr::sSkipReload = false; + LLViewerShaderMgr::instance()->setShaders(); + gPipeline.refreshCachedSettings(); } void LLFeatureManager::applyBaseMasks() @@ -771,12 +755,7 @@ void LLFeatureManager::applyBaseMasks() maskFeatures("RAM256MB"); } -#if LL_SOLARIS && defined(__sparc) // even low MHz SPARCs are fast -#error The 800 is hinky. Would something like a LL_MIN_MHZ make more sense here? - if (gSysCPU.getMHz() < 800) -#else if (gSysCPU.getMHz() < 1100) -#endif { maskFeatures("CPUSlow"); } diff --git a/indra/newview/llfeaturemanager.h b/indra/newview/llfeaturemanager.h index f77861a1a7..42a226cd18 100644 --- a/indra/newview/llfeaturemanager.h +++ b/indra/newview/llfeaturemanager.h @@ -100,9 +100,10 @@ class LLFeatureManager : public LLFeatureList, public LLSingleton<LLFeatureManag LLSINGLETON(LLFeatureManager); ~LLFeatureManager() {cleanupFeatureTables();} -public: // initialize this by loading feature table and gpu table - void init(); + void initSingleton(); + +public: void maskCurrentList(const std::string& name); // Mask the current feature list with the named list diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index b6fd70452e..3669fb1eeb 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -40,7 +40,7 @@ #include "llwindowsdl.h" // for some X/GTK utils to help with filepickers #endif // LL_SDL -#if LL_LINUX || LL_SOLARIS +#if LL_LINUX #include "llhttpconstants.h" // file picker uses some of thes constants on Linux #endif @@ -939,7 +939,7 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, } //END LL_DARWIN -#elif LL_LINUX || LL_SOLARIS +#elif LL_LINUX # if LL_GTK @@ -1504,4 +1504,4 @@ BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) return FALSE; } -#endif // LL_LINUX || LL_SOLARIS +#endif // LL_LINUX diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp index 2e1afc68b4..1ce9fe3a7a 100644 --- a/indra/newview/llfirstuse.cpp +++ b/indra/newview/llfirstuse.cpp @@ -41,37 +41,6 @@ // static -std::set<std::string> LLFirstUse::sConfigVariables; - -// static -void LLFirstUse::addConfigVariable(const std::string& var) -{ - sConfigVariables.insert(var); -} - -// static -void LLFirstUse::disableFirstUse() -{ - // Set all first-use warnings to disabled - for (std::set<std::string>::iterator iter = sConfigVariables.begin(); - iter != sConfigVariables.end(); ++iter) - { - gWarningSettings.setBOOL(*iter, FALSE); - } -} - -// static -void LLFirstUse::resetFirstUse() -{ - // Set all first-use warnings to disabled - for (std::set<std::string>::iterator iter = sConfigVariables.begin(); - iter != sConfigVariables.end(); ++iter) - { - gWarningSettings.setBOOL(*iter, TRUE); - } -} - -// static void LLFirstUse::otherAvatarChatFirst(bool enable) { firstUseNotification("FirstOtherChatBeforeUser", enable, "HintChat", LLSD(), LLSD().with("target", "nearby_chat").with("direction", "top_right").with("distance", 24)); diff --git a/indra/newview/llfirstuse.h b/indra/newview/llfirstuse.h index 4c8c9d3cde..80b83580b3 100644 --- a/indra/newview/llfirstuse.h +++ b/indra/newview/llfirstuse.h @@ -78,14 +78,6 @@ class LLNotification; class LLFirstUse { public: - - // Add a config variable to be reset on resetFirstUse() - static void addConfigVariable(const std::string& var); - - // Sets all controls back to show the dialogs. - static void disableFirstUse(); - static void resetFirstUse(); - static void otherAvatarChatFirst(bool enable = true); static void speak(bool enable = true); static void sit(bool enable = true); @@ -100,7 +92,6 @@ public: protected: static void firstUseNotification(const std::string& control_var, bool enable, const std::string& notification_name, LLSD args = LLSD(), LLSD payload = LLSD()); - static std::set<std::string> sConfigVariables; static void init(); static bool processNotification(const LLSD& notify); diff --git a/indra/newview/llflickrconnect.cpp b/indra/newview/llflickrconnect.cpp deleted file mode 100644 index d7d161f239..0000000000 --- a/indra/newview/llflickrconnect.cpp +++ /dev/null @@ -1,538 +0,0 @@ -/** - * @file llflickrconnect.h - * @author Merov, Cho - * @brief Connection to Flickr 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 "llflickrconnect.h" - -#include "llagent.h" -#include "llcallingcard.h" // for LLAvatarTracker -#include "llcommandhandler.h" -#include "llnotificationsutil.h" -#include "llurlaction.h" -#include "llimagepng.h" -#include "llimagejpeg.h" -#include "lltrans.h" -#include "llevents.h" -#include "llviewerregion.h" - -#include "llfloaterwebcontent.h" -#include "llfloaterreg.h" -#include "llcorehttputil.h" - -boost::scoped_ptr<LLEventPump> LLFlickrConnect::sStateWatcher(new LLEventStream("FlickrConnectState")); -boost::scoped_ptr<LLEventPump> LLFlickrConnect::sInfoWatcher(new LLEventStream("FlickrConnectInfo")); -boost::scoped_ptr<LLEventPump> LLFlickrConnect::sContentWatcher(new LLEventStream("FlickrConnectContent")); - -// Local functions -void log_flickr_connect_error(const std::string& request, U32 status, const std::string& reason, const std::string& code, const std::string& description) -{ - // Note: 302 (redirect) is *not* an error that warrants logging - if (status != 302) - { - LL_WARNS("FlickrConnect") << request << " request failed with a " << status << " " << reason << ". Reason: " << code << " (" << description << ")" << LL_ENDL; - } -} - -void toast_user_for_flickr_success() -{ - LLSD args; - args["MESSAGE"] = LLTrans::getString("flickr_post_success"); - LLNotificationsUtil::add("FlickrConnect", args); -} - -/////////////////////////////////////////////////////////////////////////////// -// -void LLFlickrConnect::flickrConnectCoro(std::string requestToken, std::string oauthVerifier) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - - httpOpts->setWantHeaders(true); - httpOpts->setFollowRedirects(false); - - LLSD body; - if (!requestToken.empty()) - body["request_token"] = requestToken; - if (!oauthVerifier.empty()) - body["oauth_verifier"] = oauthVerifier; - - setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS); - - LLSD result = httpAdapter->putAndSuspend(httpRequest, getFlickrConnectURL("/connection"), body, httpOpts); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (!status) - { - if ( status == LLCore::HttpStatus(HTTP_FOUND) ) - { - std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; - if (location.empty()) - { - LL_WARNS("FlickrConnect") << "Missing Location header " << LL_ENDL; - } - else - { - openFlickrWeb(location); - } - } - else - { - LL_WARNS("FlickrConnect") << "Connection failed " << status.toString() << LL_ENDL; - setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED); - log_flickr_connect_error("Connect", status.getStatus(), status.toString(), - result.get("error_code"), result.get("error_description")); - } - } - else - { - LL_DEBUGS("FlickrConnect") << "Connect successful. " << LL_ENDL; - setConnectionState(LLFlickrConnect::FLICKR_CONNECTED); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// -bool LLFlickrConnect::testShareStatus(LLSD &result) -{ - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (status) - return true; - - if (status == LLCore::HttpStatus(HTTP_FOUND)) - { - std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; - if (location.empty()) - { - LL_WARNS("FlickrConnect") << "Missing Location header " << LL_ENDL; - } - else - { - openFlickrWeb(location); - } - } - if (status == LLCore::HttpStatus(HTTP_NOT_FOUND)) - { - LL_DEBUGS("FlickrConnect") << "Not connected. " << LL_ENDL; - connectToFlickr(); - } - else - { - LL_WARNS("FlickrConnect") << "HTTP Status error " << status.toString() << LL_ENDL; - setConnectionState(LLFlickrConnect::FLICKR_POST_FAILED); - log_flickr_connect_error("Share", status.getStatus(), status.toString(), - result.get("error_code"), result.get("error_description")); - } - return false; -} - -void LLFlickrConnect::flickrShareCoro(LLSD share) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - - httpOpts->setWantHeaders(true); - httpOpts->setFollowRedirects(false); - - LLSD result = httpAdapter->postAndSuspend(httpRequest, getFlickrConnectURL("/share/photo", true), share, httpOpts); - - if (testShareStatus(result)) - { - toast_user_for_flickr_success(); - LL_DEBUGS("FlickrConnect") << "Post successful. " << LL_ENDL; - setConnectionState(LLFlickrConnect::FLICKR_POSTED); - } - -} - -void LLFlickrConnect::flickrShareImageCoro(LLPointer<LLImageFormatted> image, std::string title, std::string description, std::string tags, int safetyLevel) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); - LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - - httpOpts->setWantHeaders(true); - httpOpts->setFollowRedirects(false); - - std::string imageFormat; - if (dynamic_cast<LLImagePNG*>(image.get())) - { - imageFormat = "png"; - } - else if (dynamic_cast<LLImageJPEG*>(image.get())) - { - imageFormat = "jpg"; - } - else - { - LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL; - return; - } - - // All this code is mostly copied from LLWebProfile::post() - const std::string boundary = "----------------------------0123abcdefab"; - - std::string contentType = "multipart/form-data; boundary=" + boundary; - httpHeaders->append("Content-Type", contentType.c_str()); - - LLCore::BufferArray::ptr_t raw = LLCore::BufferArray::ptr_t(new LLCore::BufferArray()); // - LLCore::BufferArrayStream body(raw.get()); - - // *NOTE: The order seems to matter. - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"title\"\r\n\r\n" - << title << "\r\n"; - - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"description\"\r\n\r\n" - << description << "\r\n"; - - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"tags\"\r\n\r\n" - << tags << "\r\n"; - - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"safety_level\"\r\n\r\n" - << safetyLevel << "\r\n"; - - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n" - << "Content-Type: image/" << imageFormat << "\r\n\r\n"; - - // Insert the image data. - // *FIX: Treating this as a string will probably screw it up ... - U8* image_data = image->getData(); - for (S32 i = 0; i < image->getDataSize(); ++i) - { - body << image_data[i]; - } - - body << "\r\n--" << boundary << "--\r\n"; - - LLSD result = httpAdapter->postAndSuspend(httpRequest, getFlickrConnectURL("/share/photo", true), raw, httpOpts, httpHeaders); - - if (testShareStatus(result)) - { - toast_user_for_flickr_success(); - LL_DEBUGS("FlickrConnect") << "Post successful. " << LL_ENDL; - setConnectionState(LLFlickrConnect::FLICKR_POSTED); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// -void LLFlickrConnect::flickrDisconnectCoro() -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - - setConnectionState(LLFlickrConnect::FLICKR_DISCONNECTING); - httpOpts->setFollowRedirects(false); - - LLSD result = httpAdapter->deleteAndSuspend(httpRequest, getFlickrConnectURL("/connection"), httpOpts); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (!status && (status != LLCore::HttpStatus(HTTP_NOT_FOUND))) - { - LL_WARNS("FlickrConnect") << "Disconnect failed!" << LL_ENDL; - setConnectionState(LLFlickrConnect::FLICKR_DISCONNECT_FAILED); - - log_flickr_connect_error("Disconnect", status.getStatus(), status.toString(), - result.get("error_code"), result.get("error_description")); - } - else - { - LL_DEBUGS("FlickrConnect") << "Disconnect successful. " << LL_ENDL; - clearInfo(); - setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// -void LLFlickrConnect::flickrConnectedCoro(bool autoConnect) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - - setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS); - - httpOpts->setFollowRedirects(false); - - LLSD result = httpAdapter->getAndSuspend(httpRequest, getFlickrConnectURL("/connection", true), httpOpts); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (!status) - { - if (status == LLCore::HttpStatus(HTTP_NOT_FOUND)) - { - LL_DEBUGS("FlickrConnect") << "Not connected. " << LL_ENDL; - if (autoConnect) - { - connectToFlickr(); - } - else - { - setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED); - } - } - else - { - LL_WARNS("FlickrConnect") << "Failed to test connection:" << status.toTerseString() << LL_ENDL; - - setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED); - log_flickr_connect_error("Connected", status.getStatus(), status.toString(), - result.get("error_code"), result.get("error_description")); - } - } - else - { - LL_DEBUGS("FlickrConnect") << "Connect successful. " << LL_ENDL; - setConnectionState(LLFlickrConnect::FLICKR_CONNECTED); - } - -} - -/////////////////////////////////////////////////////////////////////////////// -// -void LLFlickrConnect::flickrInfoCoro() -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - - httpOpts->setWantHeaders(true); - httpOpts->setFollowRedirects(false); - - LLSD result = httpAdapter->getAndSuspend(httpRequest, getFlickrConnectURL("/info", true), httpOpts); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (status == LLCore::HttpStatus(HTTP_FOUND)) - { - std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; - if (location.empty()) - { - LL_WARNS("FlickrConnect") << "Missing Location header " << LL_ENDL; - } - else - { - openFlickrWeb(location); - } - } - else if (!status) - { - LL_WARNS("FlickrConnect") << "Flickr Info failed: " << status.toString() << LL_ENDL; - log_flickr_connect_error("Info", status.getStatus(), status.toString(), - result.get("error_code"), result.get("error_description")); - } - else - { - LL_INFOS("FlickrConnect") << "Flickr: Info received" << LL_ENDL; - result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); - storeInfo(result); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// -LLFlickrConnect::LLFlickrConnect() -: mConnectionState(FLICKR_NOT_CONNECTED), - mConnected(false), - mInfo(), - mRefreshInfo(false), - mReadFromMaster(false) -{ -} - -void LLFlickrConnect::openFlickrWeb(std::string url) -{ - LLFloaterWebContent::Params p; - p.url(url); - p.show_chrome(true); - p.allow_back_forward_navigation(false); - p.clean_browser(true); - LLFloater *floater = LLFloaterReg::showInstance("flickr_web", p); - //the internal web browser has a bug that prevents it from gaining focus unless a mouse event occurs first (it seems). - //So when showing the internal web browser, set focus to it's containing floater "flickr_web". When a mouse event - //occurs on the "webbrowser" panel part of the floater, a mouse cursor will properly show and the "webbrowser" will gain focus. - //flickr_web floater contains the "webbrowser" panel. JIRA: ACME-744 - gFocusMgr.setKeyboardFocus( floater ); - - //LLUrlAction::openURLExternal(url); -} - -std::string LLFlickrConnect::getFlickrConnectURL(const std::string& route, bool include_read_from_master) -{ - std::string url(""); - LLViewerRegion *regionp = gAgent.getRegion(); - if (regionp) - { - //url = "http://pdp15.lindenlab.com/flickr/agent/" + gAgentID.asString(); // TEMPORARY FOR TESTING - CHO - url = regionp->getCapability("FlickrConnect"); - url += route; - - if (include_read_from_master && mReadFromMaster) - { - url += "?read_from_master=true"; - } - } - return url; -} - -void LLFlickrConnect::connectToFlickr(const std::string& request_token, const std::string& oauth_verifier) -{ - LLCoros::instance().launch("LLFlickrConnect::flickrConnectCoro", - boost::bind(&LLFlickrConnect::flickrConnectCoro, this, request_token, oauth_verifier)); -} - -void LLFlickrConnect::disconnectFromFlickr() -{ - LLCoros::instance().launch("LLFlickrConnect::flickrDisconnectCoro", - boost::bind(&LLFlickrConnect::flickrDisconnectCoro, this)); -} - -void LLFlickrConnect::checkConnectionToFlickr(bool auto_connect) -{ - LLCoros::instance().launch("LLFlickrConnect::flickrConnectedCoro", - boost::bind(&LLFlickrConnect::flickrConnectedCoro, this, auto_connect)); -} - -void LLFlickrConnect::loadFlickrInfo() -{ - if(mRefreshInfo) - { - LLCoros::instance().launch("LLFlickrConnect::flickrInfoCoro", - boost::bind(&LLFlickrConnect::flickrInfoCoro, this)); - } -} - -void LLFlickrConnect::uploadPhoto(const std::string& image_url, const std::string& title, const std::string& description, const std::string& tags, int safety_level) -{ - LLSD body; - body["image"] = image_url; - body["title"] = title; - body["description"] = description; - body["tags"] = tags; - body["safety_level"] = safety_level; - - setConnectionState(LLFlickrConnect::FLICKR_POSTING); - - LLCoros::instance().launch("LLFlickrConnect::flickrShareCoro", - boost::bind(&LLFlickrConnect::flickrShareCoro, this, body)); -} - -void LLFlickrConnect::uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& title, const std::string& description, const std::string& tags, int safety_level) -{ - setConnectionState(LLFlickrConnect::FLICKR_POSTING); - - LLCoros::instance().launch("LLFlickrConnect::flickrShareImageCoro", - boost::bind(&LLFlickrConnect::flickrShareImageCoro, this, image, - title, description, tags, safety_level)); -} - -void LLFlickrConnect::storeInfo(const LLSD& info) -{ - mInfo = info; - mRefreshInfo = false; - - sInfoWatcher->post(info); -} - -const LLSD& LLFlickrConnect::getInfo() const -{ - return mInfo; -} - -void LLFlickrConnect::clearInfo() -{ - mInfo = LLSD(); -} - -void LLFlickrConnect::setDataDirty() -{ - mRefreshInfo = true; -} - -void LLFlickrConnect::setConnectionState(LLFlickrConnect::EConnectionState connection_state) -{ - if(connection_state == FLICKR_CONNECTED) - { - mReadFromMaster = true; - setConnected(true); - setDataDirty(); - } - else if(connection_state == FLICKR_NOT_CONNECTED) - { - setConnected(false); - } - else if(connection_state == FLICKR_POSTED) - { - mReadFromMaster = false; - } - - if (mConnectionState != connection_state) - { - // set the connection state before notifying watchers - mConnectionState = connection_state; - - LLSD state_info; - state_info["enum"] = connection_state; - sStateWatcher->post(state_info); - } -} - -void LLFlickrConnect::setConnected(bool connected) -{ - mConnected = connected; -} diff --git a/indra/newview/llflickrconnect.h b/indra/newview/llflickrconnect.h deleted file mode 100644 index 43cadca708..0000000000 --- a/indra/newview/llflickrconnect.h +++ /dev/null @@ -1,108 +0,0 @@ -/** - * @file llflickrconnect.h - * @author Merov, Cho - * @brief Connection to Flickr 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_LLFLICKRCONNECT_H -#define LL_LLFLICKRCONNECT_H - -#include "llsingleton.h" -#include "llimage.h" -#include "llcoros.h" -#include "lleventcoro.h" - -class LLEventPump; - -/** - * @class LLFlickrConnect - * - * Manages authentication to, and interaction with, a web service allowing the - * the viewer to upload photos to Flickr. - */ -class LLFlickrConnect : public LLSingleton<LLFlickrConnect> -{ - LLSINGLETON(LLFlickrConnect); - ~LLFlickrConnect() {}; - LOG_CLASS(LLFlickrConnect); -public: - enum EConnectionState - { - FLICKR_NOT_CONNECTED = 0, - FLICKR_CONNECTION_IN_PROGRESS = 1, - FLICKR_CONNECTED = 2, - FLICKR_CONNECTION_FAILED = 3, - FLICKR_POSTING = 4, - FLICKR_POSTED = 5, - FLICKR_POST_FAILED = 6, - FLICKR_DISCONNECTING = 7, - FLICKR_DISCONNECT_FAILED = 8 - }; - - void connectToFlickr(const std::string& request_token = "", const std::string& oauth_verifier = ""); // Initiate the complete Flickr connection. Please use checkConnectionToFlickr() in normal use. - void disconnectFromFlickr(); // Disconnect from the Flickr service. - void checkConnectionToFlickr(bool auto_connect = false); // Check if an access token is available on the Flickr service. If not, call connectToFlickr(). - - void loadFlickrInfo(); - void uploadPhoto(const std::string& image_url, const std::string& title, const std::string& description, const std::string& tags, int safety_level); - void uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& title, const std::string& description, const std::string& tags, int safety_level); - - void storeInfo(const LLSD& info); - const LLSD& getInfo() const; - void clearInfo(); - void setDataDirty(); - - void setConnectionState(EConnectionState connection_state); - void setConnected(bool connected); - bool isConnected() { return mConnected; } - bool isTransactionOngoing() { return ((mConnectionState == FLICKR_CONNECTION_IN_PROGRESS) || (mConnectionState == FLICKR_POSTING) || (mConnectionState == FLICKR_DISCONNECTING)); } - EConnectionState getConnectionState() { return mConnectionState; } - - void openFlickrWeb(std::string url); - -private: - - std::string getFlickrConnectURL(const std::string& route = "", bool include_read_from_master = false); - - EConnectionState mConnectionState; - BOOL mConnected; - LLSD mInfo; - bool mRefreshInfo; - bool mReadFromMaster; - - static boost::scoped_ptr<LLEventPump> sStateWatcher; - static boost::scoped_ptr<LLEventPump> sInfoWatcher; - static boost::scoped_ptr<LLEventPump> sContentWatcher; - - bool testShareStatus(LLSD &result); - void flickrConnectCoro(std::string requestToken, std::string oauthVerifier); - void flickrShareCoro(LLSD share); - void flickrShareImageCoro(LLPointer<LLImageFormatted> image, std::string title, std::string description, std::string tags, int safetyLevel); - void flickrDisconnectCoro(); - void flickrConnectedCoro(bool autoConnect); - void flickrInfoCoro(); - -}; - -#endif // LL_LLFLICKRCONNECT_H diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 171858e472..1fbd198019 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -236,6 +236,7 @@ void LLFloaterAbout::fetchServerReleaseNotesCoro(const std::string& cap_url) httpOpts->setWantHeaders(true); httpOpts->setFollowRedirects(false); + httpOpts->setSSLVerifyPeer(false); // We want this data even if SSL verification fails LLSD result = httpAdapter->getAndSuspend(httpRequest, cap_url, httpOpts); diff --git a/indra/newview/llfloateraddpaymentmethod.cpp b/indra/newview/llfloateraddpaymentmethod.cpp new file mode 100644 index 0000000000..3952b48229 --- /dev/null +++ b/indra/newview/llfloateraddpaymentmethod.cpp @@ -0,0 +1,81 @@ +/** + * @file llfloateraddpaymentmethod.cpp + * @brief LLFloaterAddPaymentMethod class implementation + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2020, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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 "llfloateraddpaymentmethod.h" +#include "llnotificationsutil.h" +#include "lluictrlfactory.h" +#include "llweb.h" + + +LLFloaterAddPaymentMethod::LLFloaterAddPaymentMethod(const LLSD& key) + : LLFloater(key) +{ +} + +LLFloaterAddPaymentMethod::~LLFloaterAddPaymentMethod() +{ +} + +BOOL LLFloaterAddPaymentMethod::postBuild() +{ + setCanDrag(FALSE); + getChild<LLButton>("continue_btn")->setCommitCallback(boost::bind(&LLFloaterAddPaymentMethod::onContinueBtn, this)); + getChild<LLButton>("close_btn")->setCommitCallback(boost::bind(&LLFloaterAddPaymentMethod::onCloseBtn, this)); + return TRUE; +} + +void LLFloaterAddPaymentMethod::onOpen(const LLSD& key) +{ + centerOnScreen(); +} + +void LLFloaterAddPaymentMethod::onContinueBtn() +{ + closeFloater(); + LLNotificationsUtil::add("AddPaymentMethod", LLSD(), LLSD(), + [this](const LLSD¬if, const LLSD&resp) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); + if (opt == 0) + { + LLWeb::loadURL(this->getString("continue_url")); + } + }); +} + +void LLFloaterAddPaymentMethod::onCloseBtn() +{ + closeFloater(); +} + +void LLFloaterAddPaymentMethod::centerOnScreen() +{ + LLVector2 window_size = LLUI::getInstance()->getWindowSize(); + centerWithin(LLRect(0, 0, ll_round(window_size.mV[VX]), ll_round(window_size.mV[VY]))); +} + diff --git a/indra/mac_crash_logger/llcrashloggermacdelegate.h b/indra/newview/llfloateraddpaymentmethod.h index c998a8efe2..b3bb624484 100644 --- a/indra/mac_crash_logger/llcrashloggermacdelegate.h +++ b/indra/newview/llfloateraddpaymentmethod.h @@ -1,10 +1,10 @@ /** - * @file llcrashloggermacdelegate.h - * @brief Mac OSX crash logger implementation + * @file llfloateraddpaymentmethod.h + * @brief LLFloaterAddPaymentMethod class definition * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2020, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,29 +24,29 @@ * $/LicenseInfo$ */ -/* -#import <Cocoa/Cocoa.h> +#ifndef LL_FLOATER_ADDPAYMENTMETHOD_H +#define LL_FLOATER_ADDPAYMENTMETHOD_H -@interface LLCrashLoggerMacDelegate : NSObject <NSApplicationDelegate> -{ - IBOutlet NSTextField *crashText; - IBOutlet NSButton *rememberCheck; - - NSWindow *_window; - bool mRemember; - -} +#include "llfloater.h" -- (void)setWindow:(NSWindow *)newWindow; -- (NSWindow *)window; +class LLFloaterAddPaymentMethod: + public LLFloater +{ + friend class LLFloaterReg; +public: + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); -- (IBAction)remember:(id)sender; -- (IBAction)send:(id)sender; -- (IBAction)cancel:(id)sender; +private: + LLFloaterAddPaymentMethod(const LLSD& key); -@property (assign) IBOutlet NSWindow *window; + void centerOnScreen(); -@end -*/ + void onCloseBtn(); + void onContinueBtn(); + + /*virtual*/ ~LLFloaterAddPaymentMethod(); +}; +#endif diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp index 56619e818a..957b2e1e8e 100644 --- a/indra/newview/llfloaterauction.cpp +++ b/indra/newview/llfloaterauction.cpp @@ -182,8 +182,11 @@ void LLFloaterAuction::onClickSnapshot(void* data) BOOL success = gViewerWindow->rawSnapshot(raw, gViewerWindow->getWindowWidthScaled(), gViewerWindow->getWindowHeightScaled(), - TRUE, FALSE, - FALSE, FALSE); + TRUE, + FALSE, + FALSE, //UI + FALSE, //HUD + FALSE); gForceRenderLandFence = FALSE; if (success) diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 33099db1b9..ab95bc06b8 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -361,59 +361,8 @@ void LLFloaterAvatarPicker::populateFriend() 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(GL_CULL_FACE); - gGL.begin(LLRender::QUADS); - { - gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop); - 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.mTop); - gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - - gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * 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, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom); - 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.mBottom); - 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.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.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.vertex2i(origin_rect.mLeft, origin_rect.mBottom); - } - gGL.end(); - } - - if (gFocusMgr.childHasMouseCapture(getDragHandle())) - { - mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLSmoothInterpolation::getInterpolant(mContextConeFadeTime)); - } - else - { - mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(mContextConeFadeTime)); - } - } + static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f); + drawConeToOwner(mContextConeOpacity, max_opacity, mFrustumOrigin.get(), mContextConeFadeTime, mContextConeInAlpha, mContextConeOutAlpha); } void LLFloaterAvatarPicker::draw() diff --git a/indra/newview/llfloateravatartextures.cpp b/indra/newview/llfloateravatartextures.cpp index 8e654a53c4..ebb73fc1f7 100644 --- a/indra/newview/llfloateravatartextures.cpp +++ b/indra/newview/llfloateravatartextures.cpp @@ -55,7 +55,7 @@ BOOL LLFloaterAvatarTextures::postBuild() { for (U32 i=0; i < TEX_NUM_INDICES; i++) { - const std::string tex_name = LLAvatarAppearanceDictionary::getInstance()->getTexture(ETextureIndex(i))->mName; + const std::string tex_name = LLAvatarAppearance::getDictionary()->getTexture(ETextureIndex(i))->mName; mTextures[i] = getChild<LLTextureCtrl>(tex_name); } mTitle = getTitle(); @@ -77,7 +77,7 @@ static void update_texture_ctrl(LLVOAvatar* avatarp, ETextureIndex te) { LLUUID id = IMG_DEFAULT_AVATAR; - const LLAvatarAppearanceDictionary::TextureEntry* tex_entry = LLAvatarAppearanceDictionary::getInstance()->getTexture(te); + const LLAvatarAppearanceDictionary::TextureEntry* tex_entry = LLAvatarAppearance::getDictionary()->getTexture(te); if (tex_entry && tex_entry->mIsLocalTexture) { if (avatarp->isSelf()) @@ -165,14 +165,14 @@ void LLFloaterAvatarTextures::onClickDump(void* data) const LLTextureEntry* te = avatarp->getTE(i); if (!te) continue; - const LLAvatarAppearanceDictionary::TextureEntry* tex_entry = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)(i)); + const LLAvatarAppearanceDictionary::TextureEntry* tex_entry = LLAvatarAppearance::getDictionary()->getTexture((ETextureIndex)(i)); if (!tex_entry) continue; if (LLVOAvatar::isIndexLocalTexture((ETextureIndex)i)) { LLUUID id = IMG_DEFAULT_AVATAR; - LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getInstance()->getTEWearableType((ETextureIndex)i); + LLWearableType::EType wearable_type = LLAvatarAppearance::getDictionary()->getTEWearableType((ETextureIndex)i); if (avatarp->isSelf()) { LLViewerWearable *wearable = gAgentWearables.getViewerWearable(wearable_type, 0); diff --git a/indra/newview/llfloaterbigpreview.h b/indra/newview/llfloaterbigpreview.h index 63c6784d36..513ed8da6e 100644 --- a/indra/newview/llfloaterbigpreview.h +++ b/indra/newview/llfloaterbigpreview.h @@ -1,6 +1,6 @@ /** * @file llfloaterbigpreview.h -* @brief Display of extended (big) preview for snapshots and SL Share +* @brief Display of extended (big) preview for snapshots * @author merov@lindenlab.com * * $LicenseInfo:firstyear=2013&license=viewerlgpl$ diff --git a/indra/newview/llfloaterbulkpermission.cpp b/indra/newview/llfloaterbulkpermission.cpp index f2040bc760..a1a06706bc 100644 --- a/indra/newview/llfloaterbulkpermission.cpp +++ b/indra/newview/llfloaterbulkpermission.cpp @@ -75,6 +75,7 @@ BOOL LLFloaterBulkPermission::postBuild() mBulkChangeIncludeScripts = gSavedSettings.getBOOL("BulkChangeIncludeScripts"); mBulkChangeIncludeSounds = gSavedSettings.getBOOL("BulkChangeIncludeSounds"); mBulkChangeIncludeTextures = gSavedSettings.getBOOL("BulkChangeIncludeTextures"); + mBulkChangeIncludeSettings = gSavedSettings.getBOOL("BulkChangeIncludeSettings"); mBulkChangeShareWithGroup = gSavedSettings.getBOOL("BulkChangeShareWithGroup"); mBulkChangeEveryoneCopy = gSavedSettings.getBOOL("BulkChangeEveryoneCopy"); mBulkChangeNextOwnerModify = gSavedSettings.getBOOL("BulkChangeNextOwnerModify"); @@ -186,6 +187,7 @@ void LLFloaterBulkPermission::onCloseBtn() gSavedSettings.setBOOL("BulkChangeIncludeScripts", mBulkChangeIncludeScripts); gSavedSettings.setBOOL("BulkChangeIncludeSounds", mBulkChangeIncludeSounds); gSavedSettings.setBOOL("BulkChangeIncludeTextures", mBulkChangeIncludeTextures); + gSavedSettings.setBOOL("BulkChangeIncludeSettings", mBulkChangeIncludeSettings); gSavedSettings.setBOOL("BulkChangeShareWithGroup", mBulkChangeShareWithGroup); gSavedSettings.setBOOL("BulkChangeEveryoneCopy", mBulkChangeEveryoneCopy); gSavedSettings.setBOOL("BulkChangeNextOwnerModify", mBulkChangeNextOwnerModify); @@ -281,6 +283,7 @@ void LLFloaterBulkPermission::doCheckUncheckAll(BOOL check) gSavedSettings.setBOOL("BulkChangeIncludeScripts" , check); gSavedSettings.setBOOL("BulkChangeIncludeSounds" , check); gSavedSettings.setBOOL("BulkChangeIncludeTextures" , check); + gSavedSettings.setBOOL("BulkChangeIncludeSettings" , check); } @@ -302,6 +305,7 @@ void LLFloaterBulkPermission::handleInventory(LLViewerObject* viewer_obj, LLInve ( asstype == LLAssetType::AT_OBJECT && gSavedSettings.getBOOL("BulkChangeIncludeObjects" )) || ( asstype == LLAssetType::AT_LSL_TEXT && gSavedSettings.getBOOL("BulkChangeIncludeScripts" )) || ( asstype == LLAssetType::AT_SOUND && gSavedSettings.getBOOL("BulkChangeIncludeSounds" )) || + ( asstype == LLAssetType::AT_SETTINGS && gSavedSettings.getBOOL("BulkChangeIncludeSettings" )) || ( asstype == LLAssetType::AT_TEXTURE && gSavedSettings.getBOOL("BulkChangeIncludeTextures" ))) { LLViewerObject* object = gObjectList.findObject(viewer_obj->getID()); @@ -333,7 +337,12 @@ void LLFloaterBulkPermission::handleInventory(LLViewerObject* viewer_obj, LLInve //|| something else // for next owner perms ) { - perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("BulkChange")); + U32 mask_next = LLFloaterPerms::getNextOwnerPerms("BulkChange"); + if (asstype == LLAssetType::AT_SETTINGS) + { + mask_next |= PERM_COPY; + } + perm.setMaskNext(mask_next); perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("BulkChange")); perm.setMaskGroup(LLFloaterPerms::getGroupPerms("BulkChange")); new_item->setPermissions(perm); // here's the beef diff --git a/indra/newview/llfloaterbulkpermission.h b/indra/newview/llfloaterbulkpermission.h index 0c042c3ee3..1afc876bba 100644 --- a/indra/newview/llfloaterbulkpermission.h +++ b/indra/newview/llfloaterbulkpermission.h @@ -102,6 +102,7 @@ private: bool mBulkChangeIncludeScripts; bool mBulkChangeIncludeSounds; bool mBulkChangeIncludeTextures; + bool mBulkChangeIncludeSettings; bool mBulkChangeShareWithGroup; bool mBulkChangeEveryoneCopy; bool mBulkChangeNextOwnerModify; diff --git a/indra/newview/llfloaterbuy.cpp b/indra/newview/llfloaterbuy.cpp index 5a9cdbba44..ea93d3bfaa 100644 --- a/indra/newview/llfloaterbuy.cpp +++ b/indra/newview/llfloaterbuy.cpp @@ -49,7 +49,8 @@ #include "lltrans.h" LLFloaterBuy::LLFloaterBuy(const LLSD& key) -: LLFloater(key) +: LLFloater(key), + mSelectionUpdateSlot() { } @@ -179,12 +180,19 @@ void LLFloaterBuy::show(const LLSaleInfo& sale_info) floater->getChild<LLUICtrl>("buy_text")->setTextArg("[AMOUNT]", llformat("%d", sale_info.getSalePrice())); floater->getChild<LLUICtrl>("buy_name_text")->setTextArg("[NAME]", owner_name); + floater->showViews(true); + // Must do this after the floater is created, because // sometimes the inventory is already there and // the callback is called immediately. LLViewerObject* obj = selection->getFirstRootObject(); floater->registerVOInventoryListener(obj,NULL); floater->requestVOInventory(); + + if (!floater->mSelectionUpdateSlot.connected()) + { + floater->mSelectionUpdateSlot = LLSelectMgr::getInstance()->mUpdateSignal.connect(boost::bind(&LLFloaterBuy::onSelectionChanged, floater)); + } } void LLFloaterBuy::inventoryChanged(LLViewerObject* obj, @@ -241,7 +249,7 @@ void LLFloaterBuy::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; } @@ -280,6 +288,30 @@ void LLFloaterBuy::inventoryChanged(LLViewerObject* obj, removeVOInventoryListener(); } +void LLFloaterBuy::onSelectionChanged() +{ + + if (LLSelectMgr::getInstance()->getEditSelection()->getRootObjectCount() == 0) + { + removeVOInventoryListener(); + closeFloater(); + } + else if (LLSelectMgr::getInstance()->getEditSelection()->getRootObjectCount() > 1) + { + removeVOInventoryListener(); + showViews(false); + reset(); + setTitle(getString("mupliple_selected")); + } +} + +void LLFloaterBuy::showViews(bool show) +{ + getChild<LLUICtrl>("buy_btn")->setEnabled(show); + getChild<LLUICtrl>("buy_text")->setVisible(show); + getChild<LLUICtrl>("buy_name_text")->setVisible(show); +} + void LLFloaterBuy::onClickBuy() { // Put the items where we put new folders. @@ -303,5 +335,10 @@ void LLFloaterBuy::onClickCancel() // virtual void LLFloaterBuy::onClose(bool app_quitting) { + if (mSelectionUpdateSlot.connected()) + { + mSelectionUpdateSlot.disconnect(); + } + mObjectSelection.clear(); } diff --git a/indra/newview/llfloaterbuy.h b/indra/newview/llfloaterbuy.h index 3ec642dee1..e83b3c6ba6 100644 --- a/indra/newview/llfloaterbuy.h +++ b/indra/newview/llfloaterbuy.h @@ -63,12 +63,17 @@ protected: S32 serial_num, void* data); + void onSelectionChanged(); + void showViews(bool show); + void onClickBuy(); void onClickCancel(); private: LLSafeHandle<LLObjectSelection> mObjectSelection; LLSaleInfo mSaleInfo; + + boost::signals2::connection mSelectionUpdateSlot; }; #endif diff --git a/indra/newview/llfloaterbuycontents.cpp b/indra/newview/llfloaterbuycontents.cpp index 4607b4ac41..440ec06c4e 100644 --- a/indra/newview/llfloaterbuycontents.cpp +++ b/indra/newview/llfloaterbuycontents.cpp @@ -216,7 +216,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 91436e52fe..0cfac166c7 100644 --- a/indra/newview/llfloaterbuycurrency.cpp +++ b/indra/newview/llfloaterbuycurrency.cpp @@ -32,6 +32,8 @@ #include "llcurrencyuimanager.h" #include "llfloater.h" #include "llfloaterreg.h" +#include "lllayoutstack.h" +#include "lliconctrl.h" #include "llnotificationsutil.h" #include "llstatusbar.h" #include "lltextbox.h" @@ -42,7 +44,6 @@ #include "llwindow.h" #include "llappviewer.h" -static const S32 STANDARD_BUY_AMOUNT = 2000; static const S32 MINIMUM_BALANCE_AMOUNT = 0; class LLFloaterBuyCurrencyUI @@ -58,8 +59,8 @@ public: LLCurrencyUIManager mManager; bool mHasTarget; - std::string mTargetName; S32 mTargetPrice; + S32 mRequiredAmount; public: void noTarget(); @@ -68,13 +69,13 @@ public: virtual BOOL postBuild(); void updateUI(); + void collapsePanels(bool collapse); virtual void draw(); virtual BOOL canClose(); void onClickBuy(); void onClickCancel(); - void onClickErrorWeb(); }; LLFloater* LLFloaterBuyCurrency::buildFloater(const LLSD& key) @@ -93,7 +94,9 @@ LLFloater* LLFloaterBuyCurrency::buildFloater(const LLSD& key) LLFloaterBuyCurrencyUI::LLFloaterBuyCurrencyUI(const LLSD& key) : LLFloater(key), mChildren(*this), - mManager(*this) + mManager(*this), + mHasTarget(false), + mTargetPrice(0) { } @@ -105,15 +108,20 @@ LLFloaterBuyCurrencyUI::~LLFloaterBuyCurrencyUI() void LLFloaterBuyCurrencyUI::noTarget() { mHasTarget = false; - mManager.setAmount(STANDARD_BUY_AMOUNT); + mTargetPrice = 0; + mManager.setAmount(0); } void LLFloaterBuyCurrencyUI::target(const std::string& name, S32 price) { mHasTarget = true; - mTargetName = name; mTargetPrice = price; + if (!name.empty()) + { + getChild<LLUICtrl>("target_price_label")->setValue(name); + } + S32 balance = gStatusBar->getBalance(); S32 need = price - balance; if (need < 0) @@ -121,7 +129,8 @@ void LLFloaterBuyCurrencyUI::target(const std::string& name, S32 price) need = 0; } - mManager.setAmount(need + MINIMUM_BALANCE_AMOUNT); + mRequiredAmount = need + MINIMUM_BALANCE_AMOUNT; + mManager.setAmount(0); } @@ -132,7 +141,6 @@ BOOL LLFloaterBuyCurrencyUI::postBuild() getChild<LLUICtrl>("buy_btn")->setCommitCallback( boost::bind(&LLFloaterBuyCurrencyUI::onClickBuy, this)); getChild<LLUICtrl>("cancel_btn")->setCommitCallback( boost::bind(&LLFloaterBuyCurrencyUI::onClickCancel, this)); - getChild<LLUICtrl>("error_web")->setCommitCallback( boost::bind(&LLFloaterBuyCurrencyUI::onClickErrorWeb, this)); center(); @@ -173,42 +181,25 @@ void LLFloaterBuyCurrencyUI::updateUI() // hide most widgets - we'll turn them on as needed next getChildView("info_buying")->setVisible(FALSE); - getChildView("info_cannot_buy")->setVisible(FALSE); getChildView("info_need_more")->setVisible(FALSE); getChildView("purchase_warning_repurchase")->setVisible(FALSE); getChildView("purchase_warning_notenough")->setVisible(FALSE); getChildView("contacting")->setVisible(FALSE); - getChildView("buy_action")->setVisible(FALSE); if (hasError) { // display an error from the server - getChildView("normal_background")->setVisible(FALSE); - getChildView("error_background")->setVisible(TRUE); - getChildView("info_cannot_buy")->setVisible(TRUE); - getChildView("cannot_buy_message")->setVisible(TRUE); - getChildView("balance_label")->setVisible(FALSE); - getChildView("balance_amount")->setVisible(FALSE); - getChildView("buying_label")->setVisible(FALSE); - getChildView("buying_amount")->setVisible(FALSE); - getChildView("total_label")->setVisible(FALSE); - getChildView("total_amount")->setVisible(FALSE); - - LLTextBox* message = getChild<LLTextBox>("cannot_buy_message"); - if (message) - { - message->setText(mManager.errorMessage()); - } - - getChildView("error_web")->setVisible( !mManager.errorURI().empty()); + LLSD args; + args["TITLE"] = getString("info_cannot_buy"); + args["MESSAGE"] = mManager.errorMessage(); + LLNotificationsUtil::add("CouldNotBuyCurrency", args); + mManager.clearError(); + closeFloater(); } else { // display the main Buy L$ interface getChildView("normal_background")->setVisible(TRUE); - getChildView("error_background")->setVisible(FALSE); - getChildView("cannot_buy_message")->setVisible(FALSE); - getChildView("error_web")->setVisible(FALSE); if (mHasTarget) { @@ -227,8 +218,8 @@ void LLFloaterBuyCurrencyUI::updateUI() { if (mHasTarget) { - getChildView("buy_action")->setVisible( true); - getChild<LLUICtrl>("buy_action")->setTextArg("[ACTION]", mTargetName); + getChild<LLUICtrl>("target_price")->setTextArg("[AMT]", llformat("%d", mTargetPrice)); + getChild<LLUICtrl>("required_amount")->setTextArg("[AMT]", llformat("%d", mRequiredAmount)); } } @@ -249,18 +240,40 @@ void LLFloaterBuyCurrencyUI::updateUI() if (mHasTarget) { - if (total >= mTargetPrice) - { - getChildView("purchase_warning_repurchase")->setVisible( true); - } - else - { - getChildView("purchase_warning_notenough")->setVisible( true); - } + getChildView("purchase_warning_repurchase")->setVisible( !getChildView("currency_links")->getVisible()); } } - getChildView("getting_data")->setVisible( !mManager.canBuy() && !hasError); + getChildView("getting_data")->setVisible( !mManager.canBuy() && !hasError && !getChildView("currency_est")->getVisible()); +} + +void LLFloaterBuyCurrencyUI::collapsePanels(bool collapse) +{ + LLLayoutPanel* price_panel = getChild<LLLayoutPanel>("layout_panel_price"); + + if (price_panel->isCollapsed() == collapse) + return; + + LLLayoutStack* outer_stack = getChild<LLLayoutStack>("outer_stack"); + LLLayoutPanel* required_panel = getChild<LLLayoutPanel>("layout_panel_required"); + LLLayoutPanel* msg_panel = getChild<LLLayoutPanel>("layout_panel_msg"); + + S32 delta_height = price_panel->getRect().getHeight() + required_panel->getRect().getHeight() + msg_panel->getRect().getHeight(); + delta_height *= (collapse ? -1 : 1); + + LLIconCtrl* icon = getChild<LLIconCtrl>("normal_background"); + LLRect rect = icon->getRect(); + icon->setRect(rect.setOriginAndSize(rect.mLeft, rect.mBottom - delta_height, rect.getWidth(), rect.getHeight() + delta_height)); + + outer_stack->collapsePanel(price_panel, collapse); + outer_stack->collapsePanel(required_panel, collapse); + outer_stack->collapsePanel(msg_panel, collapse); + + outer_stack->updateLayout(); + + LLRect floater_rect = getRect(); + floater_rect.mBottom -= delta_height; + setShape(floater_rect, false); } void LLFloaterBuyCurrencyUI::onClickBuy() @@ -278,28 +291,72 @@ void LLFloaterBuyCurrencyUI::onClickCancel() LLStatusBar::sendMoneyBalanceRequest(); } -void LLFloaterBuyCurrencyUI::onClickErrorWeb() -{ - LLWeb::loadURL(mManager.errorURI()); - closeFloater(); - // Update L$ balance - LLStatusBar::sendMoneyBalanceRequest(); -} +LLFetchAvatarPaymentInfo* LLFloaterBuyCurrency::sPropertiesRequest = NULL; // static void LLFloaterBuyCurrency::buyCurrency() { - LLFloaterBuyCurrencyUI* ui = LLFloaterReg::showTypedInstance<LLFloaterBuyCurrencyUI>("buy_currency"); - ui->noTarget(); - ui->updateUI(); + delete sPropertiesRequest; + sPropertiesRequest = new LLFetchAvatarPaymentInfo(false); } // static void LLFloaterBuyCurrency::buyCurrency(const std::string& name, S32 price) { - LLFloaterBuyCurrencyUI* ui = LLFloaterReg::showTypedInstance<LLFloaterBuyCurrencyUI>("buy_currency"); - ui->target(name, price); - ui->updateUI(); + delete sPropertiesRequest; + sPropertiesRequest = new LLFetchAvatarPaymentInfo(true, name, price); } +// static +void LLFloaterBuyCurrency::handleBuyCurrency(bool has_piof, bool has_target, const std::string name, S32 price) +{ + delete sPropertiesRequest; + sPropertiesRequest = NULL; + + if (has_piof) + { + LLFloaterBuyCurrencyUI* ui = LLFloaterReg::showTypedInstance<LLFloaterBuyCurrencyUI>("buy_currency"); + if (has_target) + { + ui->target(name, price); + } + else + { + ui->noTarget(); + } + ui->updateUI(); + ui->collapsePanels(!has_target); + } + else + { + LLFloaterReg::showInstance("add_payment_method"); + } +} + +LLFetchAvatarPaymentInfo::LLFetchAvatarPaymentInfo(bool has_target, const std::string& name, S32 price) +: mAvatarID(gAgent.getID()), + mHasTarget(has_target), + mPrice(price), + mName(name) +{ + LLAvatarPropertiesProcessor* processor = LLAvatarPropertiesProcessor::getInstance(); + // register ourselves as an observer + processor->addObserver(mAvatarID, this); + // send a request (duplicates will be suppressed inside the avatar + // properties processor) + processor->sendAvatarPropertiesRequest(mAvatarID); +} + +LLFetchAvatarPaymentInfo::~LLFetchAvatarPaymentInfo() +{ + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarID, this); +} +void LLFetchAvatarPaymentInfo::processProperties(void* data, EAvatarProcessorType type) +{ + if (data && type == APT_PROPERTIES) + { + LLAvatarData* avatar_data = static_cast<LLAvatarData*>(data); + LLFloaterBuyCurrency::handleBuyCurrency(LLAvatarPropertiesProcessor::hasPaymentInfoOnFile(avatar_data), mHasTarget, mName, mPrice); + } +} diff --git a/indra/newview/llfloaterbuycurrency.h b/indra/newview/llfloaterbuycurrency.h index 7ff6c42384..88d3d17cd6 100644 --- a/indra/newview/llfloaterbuycurrency.h +++ b/indra/newview/llfloaterbuycurrency.h @@ -27,15 +27,34 @@ #ifndef LL_LLFLOATERBUYCURRENCY_H #define LL_LLFLOATERBUYCURRENCY_H +#include "llavatarpropertiesprocessor.h" #include "stdtypes.h" - +#include "llagent.h" class LLFloater; +class LLFetchAvatarPaymentInfo : public LLAvatarPropertiesObserver +{ +public: + LLFetchAvatarPaymentInfo(bool has_target, const std::string& name = std::string(), S32 price = 0); + ~LLFetchAvatarPaymentInfo(); + + void processProperties(void* data, EAvatarProcessorType type); + +private: + LLUUID mAvatarID; + bool mHasTarget; + std::string mName; + S32 mPrice; +}; + + class LLFloaterBuyCurrency { public: static void buyCurrency(); static void buyCurrency(const std::string& name, S32 price); + + static void handleBuyCurrency(bool has_piof, bool has_target, const std::string name, S32 price); /* name should be a noun phrase of the object or service being bought: "That object costs" "Trying to give" @@ -44,7 +63,8 @@ public: */ static LLFloater* buildFloater(const LLSD& key); -}; + static LLFetchAvatarPaymentInfo* sPropertiesRequest; +}; #endif diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp index 080d0ed8ea..131d9b077b 100644 --- a/indra/newview/llfloaterbvhpreview.cpp +++ b/indra/newview/llfloaterbvhpreview.cpp @@ -31,13 +31,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" @@ -68,7 +68,8 @@ const S32 PREVIEW_BORDER_WIDTH = 2; const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; -const S32 PREF_BUTTON_HEIGHT = 16; +const S32 PREVIEW_VPAD = 35; +const S32 PREF_BUTTON_HEIGHT = 16 + 35; const S32 PREVIEW_TEXTURE_HEIGHT = 300; const F32 PREVIEW_CAMERA_DISTANCE = 4.f; @@ -203,7 +204,7 @@ BOOL LLFloaterBvhPreview::postBuild() setDefaultBtn(); mPreviewRect.set(PREVIEW_HPAD, - PREVIEW_TEXTURE_HEIGHT, + PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD, getRect().getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); mPreviewImageRect.set(0.f, 1.f, 1.f, 0.f); @@ -403,13 +404,13 @@ void LLFloaterBvhPreview::draw() gGL.begin( LLRender::QUADS ); { gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT); + gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); 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.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); } gGL.end(); @@ -527,7 +528,7 @@ BOOL LLFloaterBvhPreview::handleHover(S32 x, S32 y, MASK mask) mAnimPreview->requestUpdate(); - LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); + LLUI::getInstance()->setMousePositionLocal(this, mLastMouseX, mLastMouseY); } if (!mPreviewRect.pointInRect(x, y) || !mAnimPreview) @@ -1004,16 +1005,18 @@ void LLFloaterBvhPreview::onBtnOK(void* userdata) { std::string name = floaterp->getChild<LLUICtrl>("name_form")->getValue().asString(); std::string desc = floaterp->getChild<LLUICtrl>("description_form")->getValue().asString(); - S32 expected_upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload(); + S32 expected_upload_cost = LLAgentBenefitsMgr::current().getAnimationUploadCost(); - LLResourceUploadInfo::ptr_t assetUpdloadInfo(new LLResourceUploadInfo( + LLResourceUploadInfo::ptr_t assetUploadInfo(new LLResourceUploadInfo( floaterp->mTransactionID, LLAssetType::AT_ANIMATION, name, desc, 0, LLFolderType::FT_NONE, LLInventoryType::IT_ANIMATION, - LLFloaterPerms::getNextOwnerPerms("Uploads"), LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"), + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), expected_upload_cost)); - upload_new_resource(assetUpdloadInfo); + upload_new_resource(assetUploadInfo); } else { diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp index 20d650fa37..3b192ff81b 100644 --- a/indra/newview/llfloatercamera.cpp +++ b/indra/newview/llfloatercamera.cpp @@ -34,6 +34,7 @@ // Viewer includes #include "llagent.h" #include "llagentcamera.h" +#include "llpresetsmanager.h" #include "lljoystickbutton.h" #include "llviewercontrol.h" #include "llviewercamera.h" @@ -42,6 +43,8 @@ #include "llslider.h" #include "llfirstuse.h" #include "llhints.h" +#include "lltabcontainer.h" +#include "llvoavatarself.h" static LLDefaultChildRegistry::Register<LLPanelCameraItem> r("panel_camera_item"); @@ -52,7 +55,6 @@ const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed #define ORBIT "cam_rotate_stick" #define PAN "cam_track_stick" #define ZOOM "zoom" -#define PRESETS "preset_views_list" #define CONTROLS "controls" bool LLFloaterCamera::sFreeCamera = false; @@ -269,13 +271,7 @@ void LLFloaterCamera::onAvatarEditingAppearance(bool editing) void LLFloaterCamera::handleAvatarEditingAppearance(bool editing) { - //camera presets (rear, front, etc.) - getChildView("preset_views_list")->setEnabled(!editing); - getChildView("presets_btn")->setEnabled(!editing); - //camera modes (object view, mouselook view) - getChildView("camera_modes_list")->setEnabled(!editing); - getChildView("avatarview_btn")->setEnabled(!editing); } void LLFloaterCamera::update() @@ -322,6 +318,8 @@ void LLFloaterCamera::onOpen(const LLSD& key) else toPrevMode(); mClosed = FALSE; + + populatePresetCombo(); } void LLFloaterCamera::onClose(bool app_quitting) @@ -351,8 +349,10 @@ LLFloaterCamera::LLFloaterCamera(const LLSD& val) mCurrMode(CAMERA_CTRL_MODE_PAN), mPrevMode(CAMERA_CTRL_MODE_PAN) { - LLHints::registerHintTarget("view_popup", getHandle()); + LLHints::getInstance()->registerHintTarget("view_popup", getHandle()); mCommitCallbackRegistrar.add("CameraPresets.ChangeView", boost::bind(&LLFloaterCamera::onClickCameraItem, _2)); + mCommitCallbackRegistrar.add("CameraPresets.Save", boost::bind(&LLFloaterCamera::onSavePreset, this)); + mCommitCallbackRegistrar.add("CameraPresets.ShowPresetsList", boost::bind(&LLFloaterReg::showInstance, "camera_presets", LLSD(), FALSE)); } // virtual @@ -363,10 +363,14 @@ BOOL LLFloaterCamera::postBuild() mRotate = getChild<LLJoystickCameraRotate>(ORBIT); mZoom = findChild<LLPanelCameraZoom>(ZOOM); mTrack = getChild<LLJoystickCameraTrack>(PAN); + mPresetCombo = getChild<LLComboBox>("preset_combo"); + + getChild<LLTextBox>("precise_ctrs_label")->setShowCursorHand(false); + getChild<LLTextBox>("precise_ctrs_label")->setSoundFlags(LLView::MOUSE_UP); + getChild<LLTextBox>("precise_ctrs_label")->setClickedCallback(boost::bind(&LLFloaterReg::showInstance, "prefs_view_advanced", LLSD(), FALSE)); - assignButton2Mode(CAMERA_CTRL_MODE_MODES, "avatarview_btn"); - assignButton2Mode(CAMERA_CTRL_MODE_PAN, "pan_btn"); - assignButton2Mode(CAMERA_CTRL_MODE_PRESETS, "presets_btn"); + mPresetCombo->setCommitCallback(boost::bind(&LLFloaterCamera::onCustomPresetSelected, this)); + LLPresetsManager::getInstance()->setPresetListChangeCameraCallback(boost::bind(&LLFloaterCamera::populatePresetCombo, this)); update(); @@ -376,6 +380,15 @@ BOOL LLFloaterCamera::postBuild() return LLFloater::postBuild(); } +F32 LLFloaterCamera::getCurrentTransparency() +{ + + static LLCachedControl<F32> camera_opacity(gSavedSettings, "CameraOpacity"); + static LLCachedControl<F32> active_floater_transparency(gSavedSettings, "ActiveFloaterTransparency"); + return llmin(camera_opacity(), active_floater_transparency()); + +} + void LLFloaterCamera::fillFlatlistFromPanel (LLFlatListView* list, LLPanel* panel) { // copying child list and then iterating over a copy, because list itself @@ -444,13 +457,7 @@ void LLFloaterCamera::switchMode(ECameraControlMode mode) switch (mode) { - case CAMERA_CTRL_MODE_MODES: - if(sFreeCamera) - { - switchMode(CAMERA_CTRL_MODE_FREE_CAMERA); - } - break; - + case CAMERA_CTRL_MODE_PRESETS: case CAMERA_CTRL_MODE_PAN: sFreeCamera = false; clear_camera_tool(); @@ -461,49 +468,14 @@ void LLFloaterCamera::switchMode(ECameraControlMode mode) activate_camera_tool(); break; - case CAMERA_CTRL_MODE_PRESETS: - if(sFreeCamera) - { - switchMode(CAMERA_CTRL_MODE_FREE_CAMERA); - } - break; - default: //normally we won't occur here llassert_always(FALSE); } } - -void LLFloaterCamera::onClickBtn(ECameraControlMode mode) -{ - // check for a click on active button - if (mCurrMode == mode) mMode2Button[mode]->setToggleState(TRUE); - - switchMode(mode); - -} - -void LLFloaterCamera::assignButton2Mode(ECameraControlMode mode, const std::string& button_name) -{ - LLButton* button = getChild<LLButton>(button_name); - - button->setClickedCallback(boost::bind(&LLFloaterCamera::onClickBtn, this, mode)); - mMode2Button[mode] = button; -} - void LLFloaterCamera::updateState() { - getChildView(ZOOM)->setVisible(CAMERA_CTRL_MODE_PAN == mCurrMode); - - bool show_presets = (CAMERA_CTRL_MODE_PRESETS == mCurrMode) || (CAMERA_CTRL_MODE_FREE_CAMERA == mCurrMode - && CAMERA_CTRL_MODE_PRESETS == mPrevMode); - getChildView(PRESETS)->setVisible(show_presets); - - bool show_camera_modes = CAMERA_CTRL_MODE_MODES == mCurrMode || (CAMERA_CTRL_MODE_FREE_CAMERA == mCurrMode - && CAMERA_CTRL_MODE_MODES == mPrevMode); - getChildView("camera_modes_list")->setVisible( show_camera_modes); - updateItemsSelection(); if (CAMERA_CTRL_MODE_FREE_CAMERA == mCurrMode) @@ -521,13 +493,13 @@ void LLFloaterCamera::updateState() void LLFloaterCamera::updateItemsSelection() { - ECameraPreset preset = (ECameraPreset) gSavedSettings.getU32("CameraPreset"); + ECameraPreset preset = (ECameraPreset) gSavedSettings.getU32("CameraPresetType"); LLSD argument; - argument["selected"] = preset == CAMERA_PRESET_REAR_VIEW; + argument["selected"] = (preset == CAMERA_PRESET_REAR_VIEW) && !sFreeCamera; getChild<LLPanelCameraItem>("rear_view")->setValue(argument); - argument["selected"] = preset == CAMERA_PRESET_GROUP_VIEW; + argument["selected"] = (preset == CAMERA_PRESET_GROUP_VIEW) && !sFreeCamera; getChild<LLPanelCameraItem>("group_view")->setValue(argument); - argument["selected"] = preset == CAMERA_PRESET_FRONT_VIEW; + argument["selected"] = (preset == CAMERA_PRESET_FRONT_VIEW) && !sFreeCamera; getChild<LLPanelCameraItem>("front_view")->setValue(argument); argument["selected"] = gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK; getChild<LLPanelCameraItem>("mouselook_view")->setValue(argument); @@ -547,19 +519,18 @@ void LLFloaterCamera::onClickCameraItem(const LLSD& param) { LLFloaterCamera* camera_floater = LLFloaterCamera::findInstance(); if (camera_floater) - camera_floater->switchMode(CAMERA_CTRL_MODE_FREE_CAMERA); + { + camera_floater->switchMode(CAMERA_CTRL_MODE_FREE_CAMERA); + camera_floater->updateItemsSelection(); + } } else { + LLFloaterCamera* camera_floater = LLFloaterCamera::findInstance(); + if (camera_floater) + camera_floater->switchMode(CAMERA_CTRL_MODE_PAN); switchToPreset(name); } - - LLFloaterCamera* camera_floater = LLFloaterCamera::findInstance(); - if (camera_floater) - { - camera_floater->updateItemsSelection(); - camera_floater->fromFreeToPresets(); - } } /*static*/ @@ -567,24 +538,85 @@ void LLFloaterCamera::switchToPreset(const std::string& name) { sFreeCamera = false; clear_camera_tool(); - if ("rear_view" == name) + if (PRESETS_REAR_VIEW == name) { gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW); } - else if ("group_view" == name) + else if (PRESETS_SIDE_VIEW == name) { gAgentCamera.switchCameraPreset(CAMERA_PRESET_GROUP_VIEW); } - else if ("front_view" == name) + else if (PRESETS_FRONT_VIEW == name) { gAgentCamera.switchCameraPreset(CAMERA_PRESET_FRONT_VIEW); } + else + { + gAgentCamera.switchCameraPreset(CAMERA_PRESET_CUSTOM); + } + + if (gSavedSettings.getString("PresetCameraActive") != name) + { + LLPresetsManager::getInstance()->loadPreset(PRESETS_CAMERA, name); + } + + if (isAgentAvatarValid() && gAgentAvatarp->getParent()) + { + LLQuaternion sit_rot(gSavedSettings.getLLSD("AvatarSitRotation")); + if (sit_rot != LLQuaternion()) + { + gAgent.rotate(~gAgent.getFrameAgent().getQuaternion()); + gAgent.rotate(sit_rot); + } + else + { + gAgentCamera.rotateToInitSitRot(); + } + } + gAgentCamera.resetCameraZoomFraction(); + + LLFloaterCamera* camera_floater = LLFloaterCamera::findInstance(); + if (camera_floater) + { + camera_floater->updateItemsSelection(); + camera_floater->switchMode(CAMERA_CTRL_MODE_PRESETS); + } +} + +void LLFloaterCamera::populatePresetCombo() +{ + LLPresetsManager::getInstance()->setPresetNamesInComboBox(PRESETS_CAMERA, mPresetCombo, EDefaultOptions::DEFAULT_HIDE); + std::string active_preset_name = gSavedSettings.getString("PresetCameraActive"); + if (active_preset_name.empty()) + { + gSavedSettings.setU32("CameraPresetType", CAMERA_PRESET_CUSTOM); + updateItemsSelection(); + mPresetCombo->setLabel(getString("inactive_combo_text")); + } + else if ((ECameraPreset)gSavedSettings.getU32("CameraPresetType") == CAMERA_PRESET_CUSTOM) + { + mPresetCombo->selectByValue(active_preset_name); + } + else + { + mPresetCombo->setLabel(getString("inactive_combo_text")); + } + updateItemsSelection(); +} + +void LLFloaterCamera::onSavePreset() +{ + LLFloaterReg::hideInstance("delete_pref_preset", PRESETS_CAMERA); + LLFloaterReg::hideInstance("load_pref_preset", PRESETS_CAMERA); + + LLFloaterReg::showInstance("save_camera_preset"); } -void LLFloaterCamera::fromFreeToPresets() +void LLFloaterCamera::onCustomPresetSelected() { - if (!sFreeCamera && mCurrMode == CAMERA_CTRL_MODE_FREE_CAMERA && mPrevMode == CAMERA_CTRL_MODE_PRESETS) + std::string selected_preset = mPresetCombo->getSelectedItemLabel(); + if (getString("inactive_combo_text") != selected_preset) { - switchMode(CAMERA_CTRL_MODE_PRESETS); + switchToPreset(selected_preset); } } diff --git a/indra/newview/llfloatercamera.h b/indra/newview/llfloatercamera.h index 4d6d03f22d..a69b87ad16 100644 --- a/indra/newview/llfloatercamera.h +++ b/indra/newview/llfloatercamera.h @@ -36,10 +36,10 @@ class LLJoystickCameraRotate; class LLJoystickCameraTrack; class LLFloaterReg; class LLPanelCameraZoom; +class LLComboBox; enum ECameraControlMode { - CAMERA_CTRL_MODE_MODES, CAMERA_CTRL_MODE_PAN, CAMERA_CTRL_MODE_FREE_CAMERA, CAMERA_CTRL_MODE_PRESETS @@ -50,7 +50,6 @@ class LLFloaterCamera : public LLFloater friend class LLFloaterReg; public: - /* whether in free camera mode */ static bool inFreeCameraMode(); /* callback for camera items selection changing */ @@ -70,13 +69,14 @@ public: /*switch to one of the camera presets (front, rear, side)*/ static void switchToPreset(const std::string& name); - /* move to CAMERA_CTRL_MODE_PRESETS from CAMERA_CTRL_MODE_FREE_CAMERA if we are on presets panel and - are not in free camera mode*/ - void fromFreeToPresets(); - virtual void onOpen(const LLSD& key); virtual void onClose(bool app_quitting); + void onSavePreset(); + void onCustomPresetSelected(); + + void populatePresetCombo(); + LLJoystickCameraRotate* mRotate; LLPanelCameraZoom* mZoom; LLJoystickCameraTrack* mTrack; @@ -91,6 +91,10 @@ private: /*virtual*/ BOOL postBuild(); + F32 getCurrentTransparency(); + + void onViewButtonClick(const LLSD& user_data); + ECameraControlMode determineMode(); /* resets to the previous mode */ @@ -108,9 +112,6 @@ private: /* update camera modes items selection and camera preset items selection according to the currently selected preset */ void updateItemsSelection(); - void onClickBtn(ECameraControlMode mode); - void assignButton2Mode(ECameraControlMode mode, const std::string& button_name); - // fills flatlist with items from given panel void fillFlatlistFromPanel (LLFlatListView* list, LLPanel* panel); @@ -124,6 +125,8 @@ private: ECameraControlMode mPrevMode; ECameraControlMode mCurrMode; std::map<ECameraControlMode, LLButton*> mMode2Button; + + LLComboBox* mPresetCombo; }; /** diff --git a/indra/newview/llfloatercamerapresets.cpp b/indra/newview/llfloatercamerapresets.cpp new file mode 100644 index 0000000000..300c945a85 --- /dev/null +++ b/indra/newview/llfloatercamerapresets.cpp @@ -0,0 +1,145 @@ +/** +* @file llfloatercamerapresets.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 "llfloatercamerapresets.h" +#include "llfloaterreg.h" +#include "llnotificationsutil.h" +#include "llpresetsmanager.h" +#include "llviewercontrol.h" + +LLFloaterCameraPresets::LLFloaterCameraPresets(const LLSD& key) +: LLFloater(key) +{} + +LLFloaterCameraPresets::~LLFloaterCameraPresets() +{} + +BOOL LLFloaterCameraPresets::postBuild() +{ + mPresetList = getChild<LLFlatListView>("preset_list"); + + LLPresetsManager::getInstance()->setPresetListChangeCameraCallback(boost::bind(&LLFloaterCameraPresets::populateList, this)); + + return TRUE; +} +void LLFloaterCameraPresets::onOpen(const LLSD& key) +{ + populateList(); +} + +void LLFloaterCameraPresets::populateList() +{ + mPresetList->clear(); + + LLPresetsManager* presetsMgr = LLPresetsManager::getInstance(); + std::list<std::string> preset_names; + + presetsMgr->loadPresetNamesFromDir(PRESETS_CAMERA, preset_names, DEFAULT_BOTTOM); + + for (std::list<std::string>::const_iterator it = preset_names.begin(); it != preset_names.end(); ++it) + { + const std::string& name = *it; + bool is_default = presetsMgr->isDefaultCameraPreset(name); + LLCameraPresetFlatItem* item = new LLCameraPresetFlatItem(name, is_default); + item->postBuild(); + mPresetList->addItem(item); + } +} + +LLCameraPresetFlatItem::LLCameraPresetFlatItem(const std::string &preset_name, bool is_default) + : LLPanel(), + mPresetName(preset_name), + mIsDefaultPrest(is_default) +{ + mCommitCallbackRegistrar.add("CameraPresets.Delete", boost::bind(&LLCameraPresetFlatItem::onDeleteBtnClick, this)); + mCommitCallbackRegistrar.add("CameraPresets.Reset", boost::bind(&LLCameraPresetFlatItem::onResetBtnClick, this)); + buildFromFile("panel_camera_preset_item.xml"); +} + +LLCameraPresetFlatItem::~LLCameraPresetFlatItem() +{ +} + +BOOL LLCameraPresetFlatItem::postBuild() +{ + mDeleteBtn = getChild<LLButton>("delete_btn"); + mDeleteBtn->setVisible(false); + + mResetBtn = getChild<LLButton>("reset_btn"); + mResetBtn->setVisible(false); + + LLStyle::Params style; + LLTextBox* name_text = getChild<LLTextBox>("preset_name"); + LLFontDescriptor new_desc(name_text->getFont()->getFontDesc()); + new_desc.setStyle(mIsDefaultPrest ? LLFontGL::ITALIC : LLFontGL::NORMAL); + LLFontGL* new_font = LLFontGL::getFont(new_desc); + style.font = new_font; + name_text->setText(mPresetName, style); + + return true; +} + +void LLCameraPresetFlatItem::onMouseEnter(S32 x, S32 y, MASK mask) +{ + mDeleteBtn->setVisible(!mIsDefaultPrest); + mResetBtn->setVisible(mIsDefaultPrest); + getChildView("hovered_icon")->setVisible(true); + LLPanel::onMouseEnter(x, y, mask); +} + +void LLCameraPresetFlatItem::onMouseLeave(S32 x, S32 y, MASK mask) +{ + mDeleteBtn->setVisible(false); + mResetBtn->setVisible(false); + getChildView("hovered_icon")->setVisible(false); + LLPanel::onMouseLeave(x, y, mask); +} + +void LLCameraPresetFlatItem::setValue(const LLSD& value) +{ + if (!value.isMap()) return;; + if (!value.has("selected")) return; + getChildView("selected_icon")->setVisible(value["selected"]); +} + +void LLCameraPresetFlatItem::onDeleteBtnClick() +{ + if (!LLPresetsManager::getInstance()->deletePreset(PRESETS_CAMERA, mPresetName)) + { + LLSD args; + args["NAME"] = mPresetName; + LLNotificationsUtil::add("PresetNotDeleted", args); + } + else if (gSavedSettings.getString("PresetCameraActive") == mPresetName) + { + gSavedSettings.setString("PresetCameraActive", ""); + } +} + +void LLCameraPresetFlatItem::onResetBtnClick() +{ + LLPresetsManager::getInstance()->resetCameraPreset(mPresetName); +} diff --git a/indra/newview/llfloatercamerapresets.h b/indra/newview/llfloatercamerapresets.h new file mode 100644 index 0000000000..66430fa399 --- /dev/null +++ b/indra/newview/llfloatercamerapresets.h @@ -0,0 +1,73 @@ +/** +* @file llfloatercamerapresets.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 LLFLOATERCAMERAPRESETS_H +#define LLFLOATERCAMERAPRESETS_H + +#include "llfloater.h" +#include "llflatlistview.h" + +class LLFloaterReg; + +class LLFloaterCameraPresets : public LLFloater +{ + friend class LLFloaterReg; + + virtual BOOL postBuild(); + virtual void onOpen(const LLSD& key); + + void populateList(); + +private: + LLFloaterCameraPresets(const LLSD& key); + ~LLFloaterCameraPresets(); + + LLFlatListView* mPresetList; +}; + +class LLCameraPresetFlatItem : public LLPanel +{ +public: + LLCameraPresetFlatItem(const std::string &preset_name, bool is_default); + virtual ~LLCameraPresetFlatItem(); + + void setValue(const LLSD& value); + + virtual BOOL postBuild(); + virtual void onMouseEnter(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); + +private: + void onDeleteBtnClick(); + void onResetBtnClick(); + + LLButton* mDeleteBtn; + LLButton* mResetBtn; + + std::string mPresetName; + bool mIsDefaultPrest; + +}; + +#endif diff --git a/indra/newview/llfloaterchatvoicevolume.cpp b/indra/newview/llfloaterchatvoicevolume.cpp index 3c76a3a43c..45aea00a49 100644 --- a/indra/newview/llfloaterchatvoicevolume.cpp +++ b/indra/newview/llfloaterchatvoicevolume.cpp @@ -35,7 +35,7 @@ LLFloaterChatVoiceVolume::LLFloaterChatVoiceVolume(const LLSD& key) void LLFloaterChatVoiceVolume::onOpen(const LLSD& key) { LLInspect::onOpen(key); - LLUI::positionViewNearMouse(this); + LLUI::getInstance()->positionViewNearMouse(this); } LLFloaterChatVoiceVolume::~LLFloaterChatVoiceVolume() diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp index ec2c9740af..1a784223c2 100644 --- a/indra/newview/llfloatercolorpicker.cpp +++ b/indra/newview/llfloatercolorpicker.cpp @@ -485,56 +485,8 @@ BOOL LLFloaterColorPicker::isColorChanged() // void LLFloaterColorPicker::draw() { - LLRect swatch_rect; - mSwatch->localRectToOtherView(mSwatch->getLocalRect(), &swatch_rect, this); - // draw context cone connecting color picker with color swatch in parent floater - LLRect local_rect = getLocalRect(); - if (hasFocus() && mSwatch->isInVisibleChain() && mContextConeOpacity > 0.001f) - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLEnable(GL_CULL_FACE); - gGL.begin(LLRender::QUADS); - { - gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * 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, mContextConeOutAlpha * 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, mContextConeOutAlpha * 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, mContextConeInAlpha * 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, mContextConeOutAlpha * 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, mContextConeInAlpha * 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, mContextConeOutAlpha * 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, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(swatch_rect.mRight, swatch_rect.mBottom); - gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mBottom); - } - gGL.end(); - } - - if (gFocusMgr.childHasMouseCapture(getDragHandle())) - { - mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), - LLSmoothInterpolation::getInterpolant(mContextConeFadeTime)); - } - else - { - mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(mContextConeFadeTime)); - } + static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f); + drawConeToOwner(mContextConeOpacity, max_opacity, mSwatch, mContextConeFadeTime, mContextConeInAlpha, mContextConeOutAlpha); mPipetteBtn->setToggleState(LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance()); mApplyImmediateCheck->setEnabled(mActive && mCanApplyImmediately); diff --git a/indra/newview/llfloaterconversationpreview.cpp b/indra/newview/llfloaterconversationpreview.cpp index 66198b3bf6..580a3f2610 100644 --- a/indra/newview/llfloaterconversationpreview.cpp +++ b/indra/newview/llfloaterconversationpreview.cpp @@ -50,6 +50,7 @@ LLFloaterConversationPreview::LLFloaterConversationPreview(const LLSD& session_i mShowHistory(false), mMessages(NULL), mHistoryThreadsBusy(false), + mIsGroup(false), mOpened(false) { } @@ -75,6 +76,7 @@ BOOL LLFloaterConversationPreview::postBuild() { name = conv->getConversationName(); file = conv->getHistoryFileName(); + mIsGroup = (LLIMModel::LLIMSession::GROUP_SESSION == conv->getConversationType()); } else { @@ -82,6 +84,10 @@ BOOL LLFloaterConversationPreview::postBuild() file = "chat"; } mChatHistoryFileName = file; + if (mIsGroup && !LLStringUtil::endsWith(mChatHistoryFileName, GROUP_CHAT_SUFFIX)) + { + mChatHistoryFileName += GROUP_CHAT_SUFFIX; + } LLStringUtil::format_map_t args; args["[NAME]"] = name; std::string title = getString("Title", args); @@ -111,7 +117,7 @@ void LLFloaterConversationPreview::setPages(std::list<LLSD>* messages, const std getChild<LLTextBox>("page_num_label")->setValue(total_page_num); mShowHistory = true; } - LLLoadHistoryThread* loadThread = LLLogChat::getLoadHistoryThread(mSessionID); + LLLoadHistoryThread* loadThread = LLLogChat::getInstance()->getLoadHistoryThread(mSessionID); if (loadThread) { loadThread->removeLoadEndSignal(boost::bind(&LLFloaterConversationPreview::setPages, this, _1, _2)); @@ -135,7 +141,7 @@ void LLFloaterConversationPreview::onOpen(const LLSD& key) return; } mOpened = true; - if (!LLLogChat::historyThreadsFinished(mSessionID)) + if (!LLLogChat::getInstance()->historyThreadsFinished(mSessionID)) { LLNotificationsUtil::add("ChatHistoryIsBusyAlert"); mHistoryThreadsBusy = true; @@ -145,6 +151,7 @@ void LLFloaterConversationPreview::onOpen(const LLSD& key) LLSD load_params; load_params["load_all_history"] = true; load_params["cut_off_todays_date"] = false; + load_params["is_group"] = mIsGroup; // The temporary message list with "Loading..." text // Will be deleted upon loading completion in setPages() method @@ -165,15 +172,16 @@ void LLFloaterConversationPreview::onOpen(const LLSD& key) // LLDeleteHistoryThread is started in destructor std::list<LLSD>* messages = new std::list<LLSD>(); - LLLogChat::cleanupHistoryThreads(); + LLLogChat *log_chat_inst = LLLogChat::getInstance(); + log_chat_inst->cleanupHistoryThreads(); LLLoadHistoryThread* loadThread = new LLLoadHistoryThread(mChatHistoryFileName, messages, load_params); loadThread->setLoadEndSignal(boost::bind(&LLFloaterConversationPreview::setPages, this, _1, _2)); loadThread->start(); - LLLogChat::addLoadHistoryThread(mSessionID, loadThread); + log_chat_inst->addLoadHistoryThread(mSessionID, loadThread); LLDeleteHistoryThread* deleteThread = new LLDeleteHistoryThread(messages, loadThread); - LLLogChat::addDeleteHistoryThread(mSessionID, deleteThread); + log_chat_inst->addDeleteHistoryThread(mSessionID, deleteThread); mShowHistory = true; } @@ -183,7 +191,7 @@ void LLFloaterConversationPreview::onClose(bool app_quitting) mOpened = false; if (!mHistoryThreadsBusy) { - LLDeleteHistoryThread* deleteThread = LLLogChat::getDeleteHistoryThread(mSessionID); + LLDeleteHistoryThread* deleteThread = LLLogChat::getInstance()->getDeleteHistoryThread(mSessionID); if (deleteThread) { deleteThread->start(); @@ -221,7 +229,7 @@ void LLFloaterConversationPreview::showHistory() else { std::string legacy_name = gCacheName->buildLegacyName(from); - from_id = LLAvatarNameCache::findIdByName(legacy_name); + from_id = LLAvatarNameCache::getInstance()->findIdByName(legacy_name); } LLChat chat; diff --git a/indra/newview/llfloaterconversationpreview.h b/indra/newview/llfloaterconversationpreview.h index a8dbbc9ffe..7ca4ee6945 100644 --- a/indra/newview/llfloaterconversationpreview.h +++ b/indra/newview/llfloaterconversationpreview.h @@ -66,6 +66,7 @@ private: bool mShowHistory; bool mHistoryThreadsBusy; bool mOpened; + bool mIsGroup; }; #endif /* LLFLOATERCONVERSATIONPREVIEW_H_ */ diff --git a/indra/newview/llfloatercreatelandmark.cpp b/indra/newview/llfloatercreatelandmark.cpp new file mode 100644 index 0000000000..6b1d9306fb --- /dev/null +++ b/indra/newview/llfloatercreatelandmark.cpp @@ -0,0 +1,323 @@ +/** + * @file llfloatercreatelandmark.cpp + * @brief LLFloaterCreateLandmark class implementation + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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 "llfloatercreatelandmark.h" + +#include "llagent.h" +#include "llagentui.h" +#include "llcombobox.h" +#include "llinventoryfunctions.h" +#include "llinventoryobserver.h" +#include "lllandmarkactions.h" +#include "llnotificationsutil.h" +#include "llpanellandmarkinfo.h" +#include "llparcel.h" +#include "lltextbox.h" +#include "lltexteditor.h" +#include "lluictrlfactory.h" +#include "llviewermessage.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" + +typedef std::pair<LLUUID, std::string> folder_pair_t; + +class LLLandmarksInventoryObserver : public LLInventoryAddedObserver +{ +public: + LLLandmarksInventoryObserver(LLFloaterCreateLandmark* create_landmark_floater) : + mFloater(create_landmark_floater) + {} + +protected: + /*virtual*/ void done() + { + mFloater->setItem(gInventory.getAddedIDs()); + } + +private: + LLFloaterCreateLandmark* mFloater; +}; + +LLFloaterCreateLandmark::LLFloaterCreateLandmark(const LLSD& key) + : LLFloater("add_landmark"), + mItem(NULL) +{ + mInventoryObserver = new LLLandmarksInventoryObserver(this); +} + +LLFloaterCreateLandmark::~LLFloaterCreateLandmark() +{ + removeObserver(); +} + +BOOL LLFloaterCreateLandmark::postBuild() +{ + mFolderCombo = getChild<LLComboBox>("folder_combo"); + mLandmarkTitleEditor = getChild<LLLineEditor>("title_editor"); + mNotesEditor = getChild<LLTextEditor>("notes_editor"); + + getChild<LLTextBox>("new_folder_textbox")->setURLClickedCallback(boost::bind(&LLFloaterCreateLandmark::onCreateFolderClicked, this)); + getChild<LLButton>("ok_btn")->setClickedCallback(boost::bind(&LLFloaterCreateLandmark::onSaveClicked, this)); + getChild<LLButton>("cancel_btn")->setClickedCallback(boost::bind(&LLFloaterCreateLandmark::onCancelClicked, this)); + + mLandmarksID = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); + + return TRUE; +} + +void LLFloaterCreateLandmark::removeObserver() +{ + if (gInventory.containsObserver(mInventoryObserver)) + gInventory.removeObserver(mInventoryObserver); +} + +void LLFloaterCreateLandmark::onOpen(const LLSD& key) +{ + LLUUID dest_folder = LLUUID(); + if (key.has("dest_folder")) + { + dest_folder = key["dest_folder"].asUUID(); + } + mItem = NULL; + gInventory.addObserver(mInventoryObserver); + setLandmarkInfo(dest_folder); + populateFoldersList(dest_folder); +} + +void LLFloaterCreateLandmark::setLandmarkInfo(const LLUUID &folder_id) +{ + LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance(); + LLParcel* parcel = parcel_mgr->getAgentParcel(); + std::string name = parcel->getName(); + LLVector3 agent_pos = gAgent.getPositionAgent(); + + if (name.empty()) + { + S32 region_x = ll_round(agent_pos.mV[VX]); + S32 region_y = ll_round(agent_pos.mV[VY]); + S32 region_z = ll_round(agent_pos.mV[VZ]); + + std::string region_name; + LLViewerRegion* region = parcel_mgr->getSelectionRegion(); + if (region) + { + region_name = region->getName(); + } + else + { + std::string desc; + LLAgentUI::buildLocationString(desc, LLAgentUI::LOCATION_FORMAT_NORMAL, agent_pos); + region_name = desc; + } + + mLandmarkTitleEditor->setText(llformat("%s (%d, %d, %d)", + region_name.c_str(), region_x, region_y, region_z)); + } + else + { + mLandmarkTitleEditor->setText(name); + } + + LLLandmarkActions::createLandmarkHere(name, "", folder_id.notNull() ? folder_id : gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE)); +} + +bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right) +{ + return left.second < right.second; +} + +void LLFloaterCreateLandmark::populateFoldersList(const LLUUID &folder_id) +{ + // Collect all folders that can contain landmarks. + LLInventoryModel::cat_array_t cats; + LLPanelLandmarkInfo::collectLandmarkFolders(cats); + + mFolderCombo->removeall(); + + // Put the "My Favorites" folder first in list. + LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + LLViewerInventoryCategory* favorites_cat = gInventory.getCategory(favorites_id); + if (!favorites_cat) + { + LL_WARNS() << "Cannot find the favorites folder" << LL_ENDL; + } + else + { + mFolderCombo->add(getString("favorites_bar"), favorites_cat->getUUID()); + } + + // Add the "Landmarks" category. + const LLViewerInventoryCategory* lmcat = gInventory.getCategory(mLandmarksID); + if (!lmcat) + { + LL_WARNS() << "Cannot find the landmarks folder" << LL_ENDL; + } + else + { + std::string cat_full_name = LLPanelLandmarkInfo::getFullFolderName(lmcat); + mFolderCombo->add(cat_full_name, lmcat->getUUID()); + } + + typedef std::vector<folder_pair_t> folder_vec_t; + folder_vec_t folders; + // Sort the folders by their full name. + for (S32 i = 0; i < cats.size(); i++) + { + const LLViewerInventoryCategory* cat = cats.at(i); + std::string cat_full_name = LLPanelLandmarkInfo::getFullFolderName(cat); + folders.push_back(folder_pair_t(cat->getUUID(), cat_full_name)); + } + sort(folders.begin(), folders.end(), cmp_folders); + + // Finally, populate the combobox. + for (folder_vec_t::const_iterator it = folders.begin(); it != folders.end(); it++) + mFolderCombo->add(it->second, LLSD(it->first)); + + if (folder_id.notNull()) + { + mFolderCombo->setCurrentByID(folder_id); + } +} + +void LLFloaterCreateLandmark::onCreateFolderClicked() +{ + LLNotificationsUtil::add("CreateLandmarkFolder", LLSD(), LLSD(), + [this](const LLSD¬if, const LLSD&resp) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); + if (opt == 0) + { + std::string folder_name = resp["message"].asString(); + if (!folder_name.empty()) + { + inventory_func_type func = boost::bind(&LLFloaterCreateLandmark::folderCreatedCallback, this, _1); + gInventory.createNewCategory(mLandmarksID, LLFolderType::FT_NONE, folder_name, func); + gInventory.notifyObservers(); + } + } + }); +} + +void LLFloaterCreateLandmark::folderCreatedCallback(LLUUID folder_id) +{ + populateFoldersList(folder_id); +} + +void LLFloaterCreateLandmark::onSaveClicked() +{ + if (mItem.isNull()) + { + closeFloater(); + return; + } + + + std::string current_title_value = mLandmarkTitleEditor->getText(); + std::string item_title_value = mItem->getName(); + std::string current_notes_value = mNotesEditor->getText(); + std::string item_notes_value = mItem->getDescription(); + + LLStringUtil::trim(current_title_value); + LLStringUtil::trim(current_notes_value); + + LLUUID item_id = mItem->getUUID(); + LLUUID folder_id = mFolderCombo->getValue().asUUID(); + bool change_parent = folder_id != mItem->getParentUUID(); + + LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(mItem); + + if (!current_title_value.empty() && + (item_title_value != current_title_value || item_notes_value != current_notes_value)) + { + new_item->rename(current_title_value); + new_item->setDescription(current_notes_value); + LLPointer<LLInventoryCallback> cb; + if (change_parent) + { + cb = new LLUpdateLandmarkParent(new_item, folder_id); + } + LLInventoryModel::LLCategoryUpdate up(mItem->getParentUUID(), 0); + gInventory.accountForUpdate(up); + update_inventory_item(new_item, cb); + } + else if (change_parent) + { + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(mItem->getParentUUID(),-1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(folder_id, 1); + update.push_back(new_folder); + gInventory.accountForUpdate(update); + + new_item->setParent(folder_id); + new_item->updateParentOnServer(FALSE); + } + + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + + closeFloater(); +} + +void LLFloaterCreateLandmark::onCancelClicked() +{ + if (!mItem.isNull()) + { + LLUUID item_id = mItem->getUUID(); + remove_inventory_item(item_id, NULL); + } + closeFloater(); +} + + +void LLFloaterCreateLandmark::setItem(const uuid_set_t& items) +{ + for (uuid_set_t::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) + { + const LLUUID& item_id = (*item_iter); + if(!highlight_offered_object(item_id)) + { + continue; + } + + LLInventoryItem* item = gInventory.getItem(item_id); + + llassert(item); + if (item && (LLAssetType::AT_LANDMARK == item->getType()) ) + { + if(!getItem()) + { + removeObserver(); + mItem = item; + break; + } + } + } +} diff --git a/indra/newview/llfloatercreatelandmark.h b/indra/newview/llfloatercreatelandmark.h new file mode 100644 index 0000000000..74ac5e651c --- /dev/null +++ b/indra/newview/llfloatercreatelandmark.h @@ -0,0 +1,74 @@ +/** + * @file llfloatercreatelandmark.h + * @brief LLFloaterCreateLandmark class definition + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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_LLFLOATERCREATELANDMARK_H +#define LL_LLFLOATERCREATELANDMARK_H + +#include "llfloater.h" + +class LLComboBox; +class LLInventoryItem; +class LLLineEditor; +class LLTextEditor; +class LLLandmarksInventoryObserver; + +class LLFloaterCreateLandmark: + public LLFloater +{ + friend class LLFloaterReg; + +public: + + LLFloaterCreateLandmark(const LLSD& key); + ~LLFloaterCreateLandmark(); + + BOOL postBuild(); + void onOpen(const LLSD& key); + + void setItem(const uuid_set_t& items); + + LLInventoryItem* getItem() { return mItem; } + +private: + void setLandmarkInfo(const LLUUID &folder_id); + void removeObserver(); + void populateFoldersList(const LLUUID &folder_id = LLUUID::null); + void onCreateFolderClicked(); + void onSaveClicked(); + void onCancelClicked(); + + void folderCreatedCallback(LLUUID folder_id); + + LLComboBox* mFolderCombo; + LLLineEditor* mLandmarkTitleEditor; + LLTextEditor* mNotesEditor; + LLUUID mLandmarksID; + + LLLandmarksInventoryObserver* mInventoryObserver; + LLPointer<LLInventoryItem> mItem; +}; + +#endif diff --git a/indra/newview/llfloaterdeleteenvpreset.cpp b/indra/newview/llfloaterdeleteenvpreset.cpp deleted file mode 100644 index bb11c813b4..0000000000 --- a/indra/newview/llfloaterdeleteenvpreset.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/** - * @file llfloaterdeleteenvpreset.cpp - * @brief Floater to delete a water / sky / day cycle preset. - * - * $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 "llfloaterdeleteenvpreset.h" - -// libs -#include "llbutton.h" -#include "llcombobox.h" -#include "llnotificationsutil.h" - -// newview -#include "lldaycyclemanager.h" -#include "llwaterparammanager.h" - -static bool confirmation_callback(const LLSD& notification, const LLSD& response, boost::function<void()> cb) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) - { - cb(); - } - return false; - -} - -LLFloaterDeleteEnvPreset::LLFloaterDeleteEnvPreset(const LLSD &key) -: LLFloater(key) -, mPresetCombo(NULL) -{ -} - -// virtual -BOOL LLFloaterDeleteEnvPreset::postBuild() -{ - mPresetCombo = getChild<LLComboBox>("preset_combo"); - mPresetCombo->setCommitCallback(boost::bind(&LLFloaterDeleteEnvPreset::postPopulate, this)); - - getChild<LLButton>("delete")->setCommitCallback(boost::bind(&LLFloaterDeleteEnvPreset::onBtnDelete, this)); - getChild<LLButton>("cancel")->setCommitCallback(boost::bind(&LLFloaterDeleteEnvPreset::onBtnCancel, this)); - - // Listen to user preferences change, in which case we need to rebuild the presets list - // to disable the [new] current preset. - LLEnvManagerNew::instance().setPreferencesChangeCallback(boost::bind(&LLFloaterDeleteEnvPreset::populatePresetsList, this)); - - // Listen to presets addition/removal. - LLDayCycleManager::instance().setModifyCallback(boost::bind(&LLFloaterDeleteEnvPreset::populateDayCyclesList, this)); - LLWLParamManager::instance().setPresetListChangeCallback(boost::bind(&LLFloaterDeleteEnvPreset::populateSkyPresetsList, this)); - LLWaterParamManager::instance().setPresetListChangeCallback(boost::bind(&LLFloaterDeleteEnvPreset::populateWaterPresetsList, this)); - - return TRUE; -} - -// virtual -void LLFloaterDeleteEnvPreset::onOpen(const LLSD& key) -{ - std::string param = key.asString(); - std::string floater_title = getString(std::string("title_") + param); - std::string combo_label = getString(std::string("label_" + param)); - - // Update floater title. - setTitle(floater_title); - - // Update the combobox label. - getChild<LLUICtrl>("label")->setValue(combo_label); - - // Populate the combobox. - populatePresetsList(); -} - -void LLFloaterDeleteEnvPreset::onBtnDelete() -{ - std::string param = mKey.asString(); - std::string preset_name = mPresetCombo->getValue().asString(); - boost::function<void()> confirm_cb; - - if (param == "water") - { - // Don't allow deleting system presets. - if (LLWaterParamManager::instance().isSystemPreset(preset_name)) - { - LLNotificationsUtil::add("WLNoEditDefault"); - return; - } - - confirm_cb = boost::bind(&LLFloaterDeleteEnvPreset::onDeleteWaterPresetConfirmation, this); - } - else if (param == "sky") - { - // Don't allow deleting presets referenced by local day cycles. - if (LLDayCycleManager::instance().isSkyPresetReferenced(preset_name)) - { - LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", getString("msg_sky_is_referenced"))); - return; - } - - LLWLParamManager& wl_mgr = LLWLParamManager::instance(); - - // Don't allow deleting system presets. - if (wl_mgr.isSystemPreset(preset_name)) - { - LLNotificationsUtil::add("WLNoEditDefault"); - return; - } - - confirm_cb = boost::bind(&LLFloaterDeleteEnvPreset::onDeleteSkyPresetConfirmation, this); - } - else if (param == "day_cycle") - { - LLDayCycleManager& day_mgr = LLDayCycleManager::instance(); - - // Don't allow deleting system presets. - if (day_mgr.isSystemPreset(preset_name)) - { - LLNotificationsUtil::add("WLNoEditDefault"); - return; - } - - confirm_cb = boost::bind(&LLFloaterDeleteEnvPreset::onDeleteDayCycleConfirmation, this); - } - else - { - LL_WARNS() << "Unrecognized key" << LL_ENDL; - } - - LLSD args; - args["MESSAGE"] = getString("msg_confirm_deletion"); - LLNotificationsUtil::add("GenericAlertYesCancel", args, LLSD(), - boost::bind(&confirmation_callback, _1, _2, confirm_cb)); -} - -void LLFloaterDeleteEnvPreset::onBtnCancel() -{ - closeFloater(); -} - -void LLFloaterDeleteEnvPreset::populatePresetsList() -{ - std::string param = mKey.asString(); - - if (param == "water") - { - populateWaterPresetsList(); - } - else if (param == "sky") - { - populateSkyPresetsList(); - } - else if (param == "day_cycle") - { - populateDayCyclesList(); - } - else - { - LL_WARNS() << "Unrecognized key" << LL_ENDL; - } -} - -void LLFloaterDeleteEnvPreset::populateWaterPresetsList() -{ - if (mKey.asString() != "water") return; - - mPresetCombo->removeall(); - - std::string cur_preset; - LLEnvManagerNew& env_mgr = LLEnvManagerNew::instance(); - if (!env_mgr.getUseRegionSettings()) - { - cur_preset = env_mgr.getWaterPresetName(); - } - - LLWaterParamManager::preset_name_list_t presets; - LLWaterParamManager::instance().getUserPresetNames(presets); // list only user presets - for (LLWaterParamManager::preset_name_list_t::const_iterator it = presets.begin(); it != presets.end(); ++it) - { - std::string name = *it; - - bool enabled = (name != cur_preset); // don't allow deleting current preset - mPresetCombo->add(name, ADD_BOTTOM, enabled); - } - - postPopulate(); -} - -void LLFloaterDeleteEnvPreset::populateSkyPresetsList() -{ - if (mKey.asString() != "sky") return; - - mPresetCombo->removeall(); - - std::string cur_preset; - LLEnvManagerNew& env_mgr = LLEnvManagerNew::instance(); - if (!env_mgr.getUseRegionSettings() && env_mgr.getUseFixedSky()) - { - cur_preset = env_mgr.getSkyPresetName(); - } - - LLWLParamManager::preset_name_list_t user_presets; - LLWLParamManager::instance().getUserPresetNames(user_presets); - for (LLWLParamManager::preset_name_list_t::const_iterator it = user_presets.begin(); it != user_presets.end(); ++it) - { - const std::string& name = *it; - mPresetCombo->add(name, ADD_BOTTOM, /*enabled = */ name != cur_preset); - } - - postPopulate(); -} - -void LLFloaterDeleteEnvPreset::populateDayCyclesList() -{ - if (mKey.asString() != "day_cycle") return; - - mPresetCombo->removeall(); - - std::string cur_day; - LLEnvManagerNew& env_mgr = LLEnvManagerNew::instance(); - if (!env_mgr.getUseRegionSettings() && env_mgr.getUseDayCycle()) - { - cur_day = env_mgr.getDayCycleName(); - } - - LLDayCycleManager& day_mgr = LLDayCycleManager::instance(); - LLDayCycleManager::preset_name_list_t user_days; - day_mgr.getUserPresetNames(user_days); // list only user presets - for (LLDayCycleManager::preset_name_list_t::const_iterator it = user_days.begin(); it != user_days.end(); ++it) - { - const std::string& name = *it; - mPresetCombo->add(name, ADD_BOTTOM, name != cur_day); - } - - postPopulate(); -} - -void LLFloaterDeleteEnvPreset::postPopulate() -{ - // Handle empty list and empty selection. - bool has_selection = mPresetCombo->getItemCount() > 0 && mPresetCombo->getSelectedValue().isDefined(); - - if (!has_selection) - { - mPresetCombo->setLabel(getString("combo_label")); - } - - getChild<LLButton>("delete")->setEnabled(has_selection); -} - -void LLFloaterDeleteEnvPreset::onDeleteDayCycleConfirmation() -{ - LLDayCycleManager::instance().deletePreset(mPresetCombo->getValue().asString()); -} - -void LLFloaterDeleteEnvPreset::onDeleteSkyPresetConfirmation() -{ - LLWLParamKey key(mPresetCombo->getValue().asString(), LLEnvKey::SCOPE_LOCAL); - LLWLParamManager::instance().removeParamSet(key, true); -} - -void LLFloaterDeleteEnvPreset::onDeleteWaterPresetConfirmation() -{ - LLWaterParamManager::instance().removeParamSet(mPresetCombo->getValue().asString(), true); -} diff --git a/indra/newview/llfloaterdeleteprefpreset.cpp b/indra/newview/llfloaterdeleteprefpreset.cpp index 7dedbbf984..819b2bcee2 100644 --- a/indra/newview/llfloaterdeleteprefpreset.cpp +++ b/indra/newview/llfloaterdeleteprefpreset.cpp @@ -59,14 +59,25 @@ BOOL LLFloaterDeletePrefPreset::postBuild() void LLFloaterDeletePrefPreset::onOpen(const LLSD& key) { mSubdirectory = key.asString(); - std::string floater_title = getString(std::string("title_") + mSubdirectory); - - setTitle(floater_title); + std::string title_type = std::string("title_") + mSubdirectory; + if (hasString(title_type)) + { + std::string floater_title = getString(title_type); + setTitle(floater_title); + } + else + { + LL_WARNS() << title_type << " not found" << LL_ENDL; + setTitle(title_type); + } LLComboBox* combo = getChild<LLComboBox>("preset_combo"); - EDefaultOptions option = DEFAULT_HIDE; - LLPresetsManager::getInstance()->setPresetNamesInComboBox(mSubdirectory, combo, option); + bool action; + action = LLPresetsManager::getInstance()->setPresetNamesInComboBox(mSubdirectory, combo, option); + + LLButton* delete_btn = getChild<LLButton>("delete"); + delete_btn->setEnabled(action); } void LLFloaterDeletePrefPreset::onBtnDelete() @@ -80,6 +91,13 @@ void LLFloaterDeletePrefPreset::onBtnDelete() args["NAME"] = name; LLNotificationsUtil::add("PresetNotDeleted", args); } + else if (mSubdirectory == PRESETS_CAMERA) + { + if (gSavedSettings.getString("PresetCameraActive") == name) + { + gSavedSettings.setString("PresetCameraActive", ""); + } + } closeFloater(); } @@ -87,12 +105,10 @@ void LLFloaterDeletePrefPreset::onBtnDelete() void LLFloaterDeletePrefPreset::onPresetsListChange() { LLComboBox* combo = getChild<LLComboBox>("preset_combo"); - LLButton* delete_btn = getChild<LLButton>("delete"); EDefaultOptions option = DEFAULT_HIDE; - LLPresetsManager::getInstance()->setPresetNamesInComboBox(mSubdirectory, combo, option); - delete_btn->setEnabled(0 != combo->getItemCount()); + LLPresetsManager::getInstance()->setPresetNamesInComboBox(mSubdirectory, combo, option); } void LLFloaterDeletePrefPreset::onBtnCancel() diff --git a/indra/newview/llfloatereditdaycycle.cpp b/indra/newview/llfloatereditdaycycle.cpp deleted file mode 100644 index 5c0991b0b3..0000000000 --- a/indra/newview/llfloatereditdaycycle.cpp +++ /dev/null @@ -1,825 +0,0 @@ -/** - * @file llfloatereditdaycycle.cpp - * @brief Floater to create or edit a day cycle - * - * $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 "llfloatereditdaycycle.h" - -// libs -#include "llbutton.h" -#include "llcheckboxctrl.h" -#include "llcombobox.h" -#include "llloadingindicator.h" -#include "llmultisliderctrl.h" -#include "llnotifications.h" -#include "llnotificationsutil.h" -#include "llspinctrl.h" -#include "lltimectrl.h" - -// newview -#include "llagent.h" -#include "lldaycyclemanager.h" -#include "llenvmanager.h" -#include "llregioninfomodel.h" -#include "llviewerregion.h" -#include "llwlparammanager.h" - -const F32 LLFloaterEditDayCycle::sHoursPerDay = 24.0f; - -LLFloaterEditDayCycle::LLFloaterEditDayCycle(const LLSD &key) -: LLFloater(key) -, mDayCycleNameEditor(NULL) -, mDayCyclesCombo(NULL) -, mTimeSlider(NULL) -, mKeysSlider(NULL) -, mSkyPresetsCombo(NULL) -, mTimeCtrl(NULL) -, mMakeDefaultCheckBox(NULL) -, mSaveButton(NULL) -{ -} - -// virtual -BOOL LLFloaterEditDayCycle::postBuild() -{ - mDayCycleNameEditor = getChild<LLLineEditor>("day_cycle_name"); - mDayCyclesCombo = getChild<LLComboBox>("day_cycle_combo"); - - mTimeSlider = getChild<LLMultiSliderCtrl>("WLTimeSlider"); - mKeysSlider = getChild<LLMultiSliderCtrl>("WLDayCycleKeys"); - mSkyPresetsCombo = getChild<LLComboBox>("WLSkyPresets"); - mTimeCtrl = getChild<LLTimeCtrl>("time"); - mSaveButton = getChild<LLButton>("save"); - mMakeDefaultCheckBox = getChild<LLCheckBoxCtrl>("make_default_cb"); - - initCallbacks(); - - // add the time slider - mTimeSlider->addSlider(); - - return TRUE; -} - -// virtual -void LLFloaterEditDayCycle::onOpen(const LLSD& key) -{ - bool new_day = isNewDay(); - std::string param = key.asString(); - std::string floater_title = getString(std::string("title_") + param); - std::string hint = getString(std::string("hint_" + param)); - - // Update floater title. - setTitle(floater_title); - - // Update the hint at the top. - getChild<LLUICtrl>("hint")->setValue(hint); - - // Hide the hint to the right of the combo if we're invoked to create a new preset. - getChildView("note")->setVisible(!new_day); - - // Switch between the day cycle presets combobox and day cycle name input field. - mDayCyclesCombo->setVisible(!new_day); - mDayCycleNameEditor->setVisible(new_day); - - // TODO: Make sure only one instance of the floater exists? - - reset(); -} - -// virtual -void LLFloaterEditDayCycle::onClose(bool app_quitting) -{ - if (!app_quitting) // there's no point to change environment if we're quitting - { - LLEnvManagerNew::instance().usePrefs(); // revert changes made to current day cycle - } -} - -// virtual -void LLFloaterEditDayCycle::draw() -{ - syncTimeSlider(); - LLFloater::draw(); -} - -void LLFloaterEditDayCycle::initCallbacks(void) -{ - mDayCycleNameEditor->setKeystrokeCallback(boost::bind(&LLFloaterEditDayCycle::onDayCycleNameEdited, this), NULL); - mDayCyclesCombo->setCommitCallback(boost::bind(&LLFloaterEditDayCycle::onDayCycleSelected, this)); - mDayCyclesCombo->setTextEntryCallback(boost::bind(&LLFloaterEditDayCycle::onDayCycleNameEdited, this)); - mTimeSlider->setCommitCallback(boost::bind(&LLFloaterEditDayCycle::onTimeSliderMoved, this)); - mKeysSlider->setCommitCallback(boost::bind(&LLFloaterEditDayCycle::onKeyTimeMoved, this)); - mTimeCtrl->setCommitCallback(boost::bind(&LLFloaterEditDayCycle::onKeyTimeChanged, this)); - mSkyPresetsCombo->setCommitCallback(boost::bind(&LLFloaterEditDayCycle::onKeyPresetChanged, this)); - - getChild<LLButton>("WLAddKey")->setClickedCallback(boost::bind(&LLFloaterEditDayCycle::onAddKey, this)); - getChild<LLButton>("WLDeleteKey")->setClickedCallback(boost::bind(&LLFloaterEditDayCycle::onDeleteKey, this)); - - mSaveButton->setCommitCallback(boost::bind(&LLFloaterEditDayCycle::onBtnSave, this)); - mSaveButton->setRightMouseDownCallback(boost::bind(&LLFloaterEditDayCycle::dumpTrack, this)); - getChild<LLButton>("cancel")->setCommitCallback(boost::bind(&LLFloaterEditDayCycle::onBtnCancel, this)); - - // Connect to env manager events. - LLEnvManagerNew& env_mgr = LLEnvManagerNew::instance(); - env_mgr.setRegionSettingsChangeCallback(boost::bind(&LLFloaterEditDayCycle::onRegionSettingsChange, this)); - gAgent.addRegionChangedCallback(boost::bind(&LLFloaterEditDayCycle::onRegionChange, this)); - env_mgr.setRegionSettingsAppliedCallback(boost::bind(&LLFloaterEditDayCycle::onRegionSettingsApplied, this, _1)); - - // Connect to day cycle manager events. - LLDayCycleManager::instance().setModifyCallback(boost::bind(&LLFloaterEditDayCycle::onDayCycleListChange, this)); - - // Connect to sky preset list changes. - LLWLParamManager::instance().setPresetListChangeCallback(boost::bind(&LLFloaterEditDayCycle::onSkyPresetListChange, this)); - - // Connect to region info updates. - LLRegionInfoModel::instance().setUpdateCallback(boost::bind(&LLFloaterEditDayCycle::onRegionInfoUpdate, this)); -} - -void LLFloaterEditDayCycle::syncTimeSlider() -{ - // set time - mTimeSlider->setCurSliderValue((F32)LLWLParamManager::getInstance()->mAnimator.getDayTime() * sHoursPerDay); -} - -void LLFloaterEditDayCycle::loadTrack() -{ - // clear the slider - mKeysSlider->clear(); - mSliderToKey.clear(); - - // add sliders - - LL_DEBUGS() << "Adding " << LLWLParamManager::getInstance()->mDay.mTimeMap.size() << " keys to slider" << LL_ENDL; - - LLWLDayCycle& cur_dayp = LLWLParamManager::instance().mDay; - for (std::map<F32, LLWLParamKey>::iterator it = cur_dayp.mTimeMap.begin(); it != cur_dayp.mTimeMap.end(); ++it) - { - addSliderKey(it->first * sHoursPerDay, it->second); - } - - // set drop-down menu to match preset of currently-selected keyframe (one is automatically selected initially) - const std::string& cur_sldr = mKeysSlider->getCurSlider(); - if (strlen(cur_sldr.c_str()) > 0) // only do this if there is a curSldr, otherwise we put an invalid entry into the map - { - mSkyPresetsCombo->selectByValue(mSliderToKey[cur_sldr].keyframe.toStringVal()); - } - - syncTimeSlider(); -} - -void LLFloaterEditDayCycle::applyTrack() -{ - LL_DEBUGS() << "Applying track (" << mSliderToKey.size() << ")" << LL_ENDL; - - // if no keys, do nothing - if (mSliderToKey.size() == 0) - { - LL_DEBUGS() << "No keys, not syncing" << LL_ENDL; - return; - } - - llassert_always(mSliderToKey.size() == mKeysSlider->getValue().size()); - - // create a new animation track - LLWLParamManager::getInstance()->mDay.clearKeyframes(); - - // add the keys one by one - for (std::map<std::string, SliderKey>::iterator it = mSliderToKey.begin(); - it != mSliderToKey.end(); ++it) - { - LLWLParamManager::getInstance()->mDay.addKeyframe(it->second.time / sHoursPerDay, - it->second.keyframe); - } - - // set the param manager's track to the new one - LLWLParamManager::getInstance()->resetAnimator( - mTimeSlider->getCurSliderValue() / sHoursPerDay, false); - - LLWLParamManager::getInstance()->mAnimator.update( - LLWLParamManager::getInstance()->mCurParams); -} - -void LLFloaterEditDayCycle::refreshSkyPresetsList() -{ - // Don't allow selecting region skies for a local day cycle, - // because thus we may end up with invalid day cycle. - bool include_region_skies = getSelectedDayCycle().scope == LLEnvKey::SCOPE_REGION; - - mSkyPresetsCombo->removeall(); - - 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 (include_region_skies) - { - // Add region presets. - for (LLWLParamManager::preset_name_list_t::const_iterator it = region_presets.begin(); it != region_presets.end(); ++it) - { - std::string preset_name = *it; - std::string item_title = preset_name + " (" + getRegionName() + ")"; - mSkyPresetsCombo->add(preset_name, LLWLParamKey(*it, LLEnvKey::SCOPE_REGION).toStringVal()); - } - - if (!region_presets.empty()) - { - mSkyPresetsCombo->addSeparator(); - } - } - - // Add user presets. - for (LLWLParamManager::preset_name_list_t::const_iterator it = user_presets.begin(); it != user_presets.end(); ++it) - { - mSkyPresetsCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toStringVal()); - } - - if (!user_presets.empty()) - { - mSkyPresetsCombo->addSeparator(); - } - - // Add system presets. - for (LLWLParamManager::preset_name_list_t::const_iterator it = sys_presets.begin(); it != sys_presets.end(); ++it) - { - mSkyPresetsCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toStringVal()); - } - - // set defaults on combo boxes - mSkyPresetsCombo->selectFirstItem(); -} - -void LLFloaterEditDayCycle::refreshDayCyclesList() -{ - llassert(isNewDay() == false); - - mDayCyclesCombo->removeall(); - -#if 0 // Disable editing existing day cycle until the workflow is clear enough. - const LLSD& region_day = LLEnvManagerNew::instance().getRegionSettings().getWLDayCycle(); - if (region_day.size() > 0) - { - LLWLParamKey key(getRegionName(), LLEnvKey::SCOPE_REGION); - mDayCyclesCombo->add(key.name, key.toLLSD()); - mDayCyclesCombo->addSeparator(); - } -#endif - - LLDayCycleManager::preset_name_list_t user_days, sys_days; - LLDayCycleManager::instance().getPresetNames(user_days, sys_days); - - // Add user days. - for (LLDayCycleManager::preset_name_list_t::const_iterator it = user_days.begin(); it != user_days.end(); ++it) - { - mDayCyclesCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toLLSD()); - } - - if (user_days.size() > 0) - { - mDayCyclesCombo->addSeparator(); - } - - // Add system days. - for (LLDayCycleManager::preset_name_list_t::const_iterator it = sys_days.begin(); it != sys_days.end(); ++it) - { - mDayCyclesCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toLLSD()); - } - - mDayCyclesCombo->setLabel(getString("combo_label")); -} - -void LLFloaterEditDayCycle::onTimeSliderMoved() -{ - /// get the slider value - F32 val = mTimeSlider->getCurSliderValue() / sHoursPerDay; - - // set the value, turn off animation - LLWLParamManager::getInstance()->mAnimator.setDayTime((F64)val); - LLWLParamManager::getInstance()->mAnimator.deactivate(); - - // then call update once - LLWLParamManager::getInstance()->mAnimator.update( - LLWLParamManager::getInstance()->mCurParams); -} - -void LLFloaterEditDayCycle::onKeyTimeMoved() -{ - if (mKeysSlider->getValue().size() == 0) - { - return; - } - - // make sure we have a slider - const std::string& cur_sldr = mKeysSlider->getCurSlider(); - if (cur_sldr == "") - { - return; - } - - F32 time24 = mKeysSlider->getCurSliderValue(); - - // check to see if a key exists - LLWLParamKey key = mSliderToKey[cur_sldr].keyframe; - LL_DEBUGS() << "Setting key time: " << time24 << LL_ENDL; - mSliderToKey[cur_sldr].time = time24; - - // if it exists, turn on check box - mSkyPresetsCombo->selectByValue(key.toStringVal()); - - mTimeCtrl->setTime24(time24); - - applyTrack(); -} - -void LLFloaterEditDayCycle::onKeyTimeChanged() -{ - // if no keys, skipped - if (mSliderToKey.size() == 0) - { - return; - } - - F32 time24 = mTimeCtrl->getTime24(); - - const std::string& cur_sldr = mKeysSlider->getCurSlider(); - mKeysSlider->setCurSliderValue(time24, TRUE); - F32 time = mKeysSlider->getCurSliderValue() / sHoursPerDay; - - // now set the key's time in the sliderToKey map - LL_DEBUGS() << "Setting key time: " << time << LL_ENDL; - mSliderToKey[cur_sldr].time = time; - - applyTrack(); -} - -void LLFloaterEditDayCycle::onKeyPresetChanged() -{ - // do nothing if no sliders - if (mKeysSlider->getValue().size() == 0) - { - return; - } - - // change the map - - std::string stringVal = mSkyPresetsCombo->getSelectedValue().asString(); - LLWLParamKey new_key(stringVal); - llassert(!new_key.name.empty()); - const std::string& cur_sldr = mKeysSlider->getCurSlider(); - - // if null, don't use - if (cur_sldr == "") - { - return; - } - - mSliderToKey[cur_sldr].keyframe = new_key; - - // Apply changes to current day cycle. - applyTrack(); -} - -void LLFloaterEditDayCycle::onAddKey() -{ - llassert_always(mSliderToKey.size() == mKeysSlider->getValue().size()); - - S32 max_sliders; - LLEnvKey::EScope scope = LLEnvKey::SCOPE_LOCAL; // *TODO: editing region day cycle - switch (scope) - { - case LLEnvKey::SCOPE_LOCAL: - max_sliders = 20; // *HACK this should be LLWLPacketScrubber::MAX_LOCAL_KEY_FRAMES; - break; - case LLEnvKey::SCOPE_REGION: - max_sliders = 12; // *HACK this should be LLWLPacketScrubber::MAX_REGION_KEY_FRAMES; - break; - default: - max_sliders = (S32) mKeysSlider->getMaxValue(); - break; - } - - if ((S32)mSliderToKey.size() >= max_sliders) - { - LLSD args; - args["SCOPE"] = LLEnvManagerNew::getScopeString(scope); - args["MAX"] = max_sliders; - LLNotificationsUtil::add("DayCycleTooManyKeyframes", args, LLSD(), LLNotificationFunctorRegistry::instance().DONOTHING); - return; - } - - // add the slider key - std::string key_val = mSkyPresetsCombo->getSelectedValue().asString(); - LLWLParamKey sky_params(key_val); - llassert(!sky_params.name.empty()); - - F32 time = mTimeSlider->getCurSliderValue(); - addSliderKey(time, sky_params); - - // apply the change to current day cycles - applyTrack(); -} - -void LLFloaterEditDayCycle::addSliderKey(F32 time, LLWLParamKey keyframe) -{ - // make a slider - const std::string& sldr_name = mKeysSlider->addSlider(time); - if (sldr_name.empty()) - { - return; - } - - // set the key - SliderKey newKey(keyframe, mKeysSlider->getCurSliderValue()); - - llassert_always(sldr_name != LLStringUtil::null); - - // add to map - mSliderToKey.insert(std::pair<std::string, SliderKey>(sldr_name, newKey)); - - llassert_always(mSliderToKey.size() == mKeysSlider->getValue().size()); -} - -LLWLParamKey LLFloaterEditDayCycle::getSelectedDayCycle() -{ - LLWLParamKey dc_key; - - if (mDayCycleNameEditor->getVisible()) - { - dc_key.name = mDayCycleNameEditor->getText(); - dc_key.scope = LLEnvKey::SCOPE_LOCAL; - } - else - { - LLSD combo_val = mDayCyclesCombo->getValue(); - - if (!combo_val.isArray()) // manually typed text - { - dc_key.name = combo_val.asString(); - dc_key.scope = LLEnvKey::SCOPE_LOCAL; - } - else - { - dc_key.fromLLSD(combo_val); - } - } - - return dc_key; -} - -bool LLFloaterEditDayCycle::isNewDay() const -{ - return mKey.asString() == "new"; -} - -void LLFloaterEditDayCycle::dumpTrack() -{ - LL_DEBUGS("Windlight") << "Dumping day cycle" << LL_ENDL; - - LLWLDayCycle& cur_dayp = LLWLParamManager::instance().mDay; - for (std::map<F32, LLWLParamKey>::iterator it = cur_dayp.mTimeMap.begin(); it != cur_dayp.mTimeMap.end(); ++it) - { - F32 time = it->first * 24.0f; - S32 h = (S32) time; - S32 m = (S32) ((time - h) * 60.0f); - LL_DEBUGS("Windlight") << llformat("(%.3f) %02d:%02d", time, h, m) << " => " << it->second.name << LL_ENDL; - } -} - -void LLFloaterEditDayCycle::enableEditing(bool enable) -{ - mSkyPresetsCombo->setEnabled(enable); - mTimeCtrl->setEnabled(enable); - getChild<LLPanel>("day_cycle_slider_panel")->setCtrlsEnabled(enable); - mSaveButton->setEnabled(enable); - mMakeDefaultCheckBox->setEnabled(enable); -} - -void LLFloaterEditDayCycle::reset() -{ - // clear the slider - mKeysSlider->clear(); - mSliderToKey.clear(); - - refreshSkyPresetsList(); - - if (isNewDay()) - { - mDayCycleNameEditor->setValue(LLSD()); - F32 time = 0.5f * sHoursPerDay; - mSaveButton->setEnabled(FALSE); // will be enabled as soon as users enters a name - mTimeSlider->setCurSliderValue(time); - - addSliderKey(time, LLWLParamKey("Default", LLEnvKey::SCOPE_LOCAL)); - onKeyTimeMoved(); // update the time control and sky sky combo - - applyTrack(); - } - else - { - refreshDayCyclesList(); - - // Disable controls until a day cycle to edit is selected. - enableEditing(false); - } -} - -void LLFloaterEditDayCycle::saveRegionDayCycle() -{ - LLEnvManagerNew& env_mgr = LLEnvManagerNew::instance(); - LLWLDayCycle& cur_dayp = LLWLParamManager::instance().mDay; // the day cycle being edited - - // Get current day cycle and the sky preset it references. - LLSD day_cycle = cur_dayp.asLLSD(); - LLSD sky_map; - cur_dayp.getSkyMap(sky_map); - - // Apply it to the region. - LLEnvironmentSettings new_region_settings; - new_region_settings.saveParams(day_cycle, sky_map, env_mgr.getRegionSettings().getWaterParams(), 0.0f); - -#if 1 - LLEnvManagerNew::instance().setRegionSettings(new_region_settings); -#else // Temporary disabled ability to upload new region settings from the Day Cycle Editor. - if (!LLEnvManagerNew::instance().sendRegionSettings(new_region_settings)) - { - LL_WARNS() << "Error applying region environment settings" << LL_ENDL; - return; - } - - setApplyProgress(true); -#endif -} - -void LLFloaterEditDayCycle::setApplyProgress(bool started) -{ - LLLoadingIndicator* indicator = getChild<LLLoadingIndicator>("progress_indicator"); - - indicator->setVisible(started); - - if (started) - { - indicator->start(); - } - else - { - indicator->stop(); - } -} - -bool LLFloaterEditDayCycle::getApplyProgress() const -{ - return getChild<LLLoadingIndicator>("progress_indicator")->getVisible(); -} - -void LLFloaterEditDayCycle::onDeleteKey() -{ - if (mSliderToKey.size() == 0) - { - return; - } - else if (mSliderToKey.size() == 1) - { - LLNotifications::instance().add("EnvCannotDeleteLastDayCycleKey", LLSD(), LLSD()); - return; - } - - // delete from map - const std::string& sldr_name = mKeysSlider->getCurSlider(); - std::map<std::string, SliderKey>::iterator mIt = mSliderToKey.find(sldr_name); - mSliderToKey.erase(mIt); - - mKeysSlider->deleteCurSlider(); - - if (mSliderToKey.size() == 0) - { - return; - } - - const std::string& name = mKeysSlider->getCurSlider(); - mSkyPresetsCombo->selectByValue(mSliderToKey[name].keyframe.toStringVal()); - F32 time24 = mSliderToKey[name].time; - - mTimeCtrl->setTime24(time24); - - applyTrack(); -} - -void LLFloaterEditDayCycle::onRegionSettingsChange() -{ - LL_DEBUGS("Windlight") << "Region settings changed" << LL_ENDL; - - if (getApplyProgress()) // our region settings have being applied - { - setApplyProgress(false); - - // Change preference if requested. - if (mMakeDefaultCheckBox->getValue()) - { - LL_DEBUGS("Windlight") << "Changed environment preference to region settings" << LL_ENDL; - LLEnvManagerNew::instance().setUseRegionSettings(true); - } - - closeFloater(); - } -} - -void LLFloaterEditDayCycle::onRegionChange() -{ - LL_DEBUGS("Windlight") << "Region changed" << LL_ENDL; - - // If we're editing the region day cycle - if (getSelectedDayCycle().scope == LLEnvKey::SCOPE_REGION) - { - reset(); // undoes all unsaved changes - } -} - -void LLFloaterEditDayCycle::onRegionSettingsApplied(bool success) -{ - LL_DEBUGS("Windlight") << "Region settings applied: " << success << LL_ENDL; - - if (!success) - { - // stop progress indicator - setApplyProgress(false); - } -} - -void LLFloaterEditDayCycle::onRegionInfoUpdate() -{ - LL_DEBUGS("Windlight") << "Region info updated" << LL_ENDL; - bool can_edit = true; - - // If we've selected the region day cycle for editing. - if (getSelectedDayCycle().scope == LLEnvKey::SCOPE_REGION) - { - // check whether we have the access - can_edit = LLEnvManagerNew::canEditRegionSettings(); - } - - enableEditing(can_edit); -} - -void LLFloaterEditDayCycle::onDayCycleNameEdited() -{ - // Disable saving a day cycle having empty name. - LLWLParamKey key = getSelectedDayCycle(); - mSaveButton->setEnabled(!key.name.empty()); -} - -void LLFloaterEditDayCycle::onDayCycleSelected() -{ - LLSD day_data; - LLWLParamKey dc_key = getSelectedDayCycle(); - bool can_edit = true; - - if (dc_key.scope == LLEnvKey::SCOPE_LOCAL) - { - if (!LLDayCycleManager::instance().getPreset(dc_key.name, day_data)) - { - LL_WARNS() << "No day cycle named " << dc_key.name << LL_ENDL; - return; - } - } - else - { - day_data = LLEnvManagerNew::instance().getRegionSettings().getWLDayCycle(); - if (day_data.size() == 0) - { - LL_WARNS() << "Empty region day cycle" << LL_ENDL; - llassert(day_data.size() > 0); - return; - } - - can_edit = LLEnvManagerNew::canEditRegionSettings(); - } - - // We may need to add or remove region skies from the list. - refreshSkyPresetsList(); - - F32 slider_time = mTimeSlider->getCurSliderValue() / sHoursPerDay; - LLWLParamManager::instance().applyDayCycleParams(day_data, dc_key.scope, slider_time); - loadTrack(); - - enableEditing(can_edit); -} - -void LLFloaterEditDayCycle::onBtnSave() -{ - LLDayCycleManager& day_mgr = LLDayCycleManager::instance(); - LLWLParamKey selected_day = getSelectedDayCycle(); - - if (selected_day.scope == LLEnvKey::SCOPE_REGION) - { - saveRegionDayCycle(); - closeFloater(); - return; - } - - std::string name = selected_day.name; - if (name.empty()) - { - // *TODO: show an alert - LL_WARNS() << "Empty day cycle name" << LL_ENDL; - return; - } - - // Don't allow overwriting system presets. - if (day_mgr.isSystemPreset(name)) - { - LLNotificationsUtil::add("WLNoEditDefault"); - return; - } - - // Save, ask for confirmation for overwriting an existing preset. - if (day_mgr.presetExists(name)) - { - LLNotificationsUtil::add("WLSavePresetAlert", LLSD(), LLSD(), boost::bind(&LLFloaterEditDayCycle::onSaveAnswer, this, _1, _2)); - } - else - { - // new preset, hence no confirmation needed - onSaveConfirmed(); - } -} - -void LLFloaterEditDayCycle::onBtnCancel() -{ - closeFloater(); -} - -bool LLFloaterEditDayCycle::onSaveAnswer(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - // If they choose save, do it. Otherwise, don't do anything - if (option == 0) - { - onSaveConfirmed(); - } - - return false; -} - -void LLFloaterEditDayCycle::onSaveConfirmed() -{ - std::string name = getSelectedDayCycle().name; - - // Save preset. - LLSD data = LLWLParamManager::instance().mDay.asLLSD(); - LL_DEBUGS("Windlight") << "Saving day cycle " << name << ": " << data << LL_ENDL; - LLDayCycleManager::instance().savePreset(name, data); - - // Change preference if requested. - if (mMakeDefaultCheckBox->getValue()) - { - LL_DEBUGS("Windlight") << name << " is now the new preferred day cycle" << LL_ENDL; - LLEnvManagerNew::instance().setUseDayCycle(name); - } - - closeFloater(); -} - -void LLFloaterEditDayCycle::onDayCycleListChange() -{ - if (!isNewDay()) - { - refreshDayCyclesList(); - } -} - -void LLFloaterEditDayCycle::onSkyPresetListChange() -{ - refreshSkyPresetsList(); - - // Refresh sliders from the currently visible day cycle. - loadTrack(); -} - -// static -std::string LLFloaterEditDayCycle::getRegionName() -{ - return gAgent.getRegion() ? gAgent.getRegion()->getName() : LLTrans::getString("Unknown"); -} diff --git a/indra/newview/llfloatereditdaycycle.h b/indra/newview/llfloatereditdaycycle.h deleted file mode 100644 index e6e4fe39c1..0000000000 --- a/indra/newview/llfloatereditdaycycle.h +++ /dev/null @@ -1,137 +0,0 @@ -/** - * @file llfloatereditdaycycle.h - * @brief Floater to create or edit a day cycle - * - * $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_LLFLOATEREDITDAYCYCLE_H -#define LL_LLFLOATEREDITDAYCYCLE_H - -#include "llfloater.h" - -#include "llwlparammanager.h" // for LLWLParamKey - -class LLCheckBoxCtrl; -class LLComboBox; -class LLLineEditor; -class LLMultiSliderCtrl; -class LLTimeCtrl; - -/** - * Floater for creating or editing a day cycle. - */ -class LLFloaterEditDayCycle : public LLFloater -{ - LOG_CLASS(LLFloaterEditDayCycle); - -public: - LLFloaterEditDayCycle(const LLSD &key); - - /*virtual*/ BOOL postBuild(); - /*virtual*/ void onOpen(const LLSD& key); - /*virtual*/ void onClose(bool app_quitting); - /*virtual*/ void draw(); - -private: - - /// sync the time slider with day cycle structure - void syncTimeSlider(); - - // makes sure key slider has what's in day cycle - void loadTrack(); - - /// makes sure day cycle data structure has what's in menu - void applyTrack(); - - /// refresh the sky presets combobox - void refreshSkyPresetsList(); - - /// refresh the day cycle combobox - void refreshDayCyclesList(); - - /// add a slider to the track - void addSliderKey(F32 time, LLWLParamKey keyframe); - - void initCallbacks(); - LLWLParamKey getSelectedDayCycle(); - bool isNewDay() const; - void dumpTrack(); - void enableEditing(bool enable); - void reset(); - void saveRegionDayCycle(); - - void setApplyProgress(bool started); - bool getApplyProgress() const; - - void onTimeSliderMoved(); /// time slider moved - void onKeyTimeMoved(); /// a key frame moved - void onKeyTimeChanged(); /// a key frame's time changed - void onKeyPresetChanged(); /// sky preset selected - void onAddKey(); /// new key added on slider - void onDeleteKey(); /// a key frame deleted - - void onRegionSettingsChange(); - void onRegionChange(); - void onRegionSettingsApplied(bool success); - void onRegionInfoUpdate(); - - void onDayCycleNameEdited(); - void onDayCycleSelected(); - void onBtnSave(); - void onBtnCancel(); - - bool onSaveAnswer(const LLSD& notification, const LLSD& response); - void onSaveConfirmed(); - - void onDayCycleListChange(); - void onSkyPresetListChange(); - - static std::string getRegionName(); - - /// convenience class for holding keyframes mapped to sliders - struct SliderKey - { - public: - SliderKey(LLWLParamKey kf, F32 t) : keyframe(kf), time(t) {} - SliderKey() : keyframe(), time(0.f) {} // Don't use this default constructor - - LLWLParamKey keyframe; - F32 time; - }; - - static const F32 sHoursPerDay; - - LLLineEditor* mDayCycleNameEditor; - LLComboBox* mDayCyclesCombo; - LLMultiSliderCtrl* mTimeSlider; - LLMultiSliderCtrl* mKeysSlider; - LLComboBox* mSkyPresetsCombo; - LLTimeCtrl* mTimeCtrl; - LLCheckBoxCtrl* mMakeDefaultCheckBox; - LLButton* mSaveButton; - - // map of sliders to parameters - std::map<std::string, SliderKey> mSliderToKey; -}; - -#endif // LL_LLFLOATEREDITDAYCYCLE_H diff --git a/indra/newview/llfloatereditenvironmentbase.cpp b/indra/newview/llfloatereditenvironmentbase.cpp new file mode 100644 index 0000000000..2850951668 --- /dev/null +++ b/indra/newview/llfloatereditenvironmentbase.cpp @@ -0,0 +1,479 @@ +/** + * @file llfloatereditenvironmentbase.cpp + * @brief Floaters to create and edit fixed settings for sky and water. + * + * $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 "llfloatereditenvironmentbase.h" + +#include <boost/make_shared.hpp> + +// libs +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llfilepicker.h" +#include "llsettingspicker.h" +#include "llviewerparcelmgr.h" + +// newview +#include "llsettingssky.h" +#include "llsettingswater.h" + +#include "llenvironment.h" +#include "llagent.h" +#include "llparcel.h" + +#include "llsettingsvo.h" +#include "llinventorymodel.h" + +namespace +{ + const std::string ACTION_APPLY_LOCAL("apply_local"); + const std::string ACTION_APPLY_PARCEL("apply_parcel"); + const std::string ACTION_APPLY_REGION("apply_region"); +} + +//========================================================================= +const std::string LLFloaterEditEnvironmentBase::KEY_INVENTORY_ID("inventory_id"); + + +//========================================================================= + +class LLFixedSettingCopiedCallback : public LLInventoryCallback +{ +public: + LLFixedSettingCopiedCallback(LLHandle<LLFloater> handle) : mHandle(handle) {} + + virtual void fire(const LLUUID& inv_item_id) + { + if (!mHandle.isDead()) + { + LLViewerInventoryItem* item = gInventory.getItem(inv_item_id); + if (item) + { + LLFloaterEditEnvironmentBase* floater = (LLFloaterEditEnvironmentBase*)mHandle.get(); + floater->onInventoryCreated(item->getAssetUUID(), inv_item_id); + } + } + } + +private: + LLHandle<LLFloater> mHandle; +}; + +//========================================================================= +LLFloaterEditEnvironmentBase::LLFloaterEditEnvironmentBase(const LLSD &key) : + LLFloater(key), + mInventoryId(), + mInventoryItem(nullptr), + mIsDirty(false), + mCanCopy(false), + mCanMod(false), + mCanTrans(false), + mCanSave(false) +{ +} + +LLFloaterEditEnvironmentBase::~LLFloaterEditEnvironmentBase() +{ +} + +void LLFloaterEditEnvironmentBase::onFocusReceived() +{ + if (isInVisibleChain()) + { + updateEditEnvironment(); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_EDIT, LLEnvironment::TRANSITION_FAST); + } +} + +void LLFloaterEditEnvironmentBase::onFocusLost() +{ +} + +void LLFloaterEditEnvironmentBase::loadInventoryItem(const LLUUID &inventoryId, bool can_trans) +{ + if (inventoryId.isNull()) + { + mInventoryItem = nullptr; + mInventoryId.setNull(); + mCanMod = true; + mCanCopy = true; + mCanTrans = true; + return; + } + + mInventoryId = inventoryId; + LL_INFOS("SETTINGS") << "Setting edit inventory item to " << mInventoryId << "." << LL_ENDL; + mInventoryItem = gInventory.getItem(mInventoryId); + + if (!mInventoryItem) + { + LL_WARNS("SETTINGS") << "Could not find inventory item with Id = " << mInventoryId << LL_ENDL; + LLNotificationsUtil::add("CantFindInvItem"); + closeFloater(); + + mInventoryId.setNull(); + mInventoryItem = nullptr; + return; + } + + if (mInventoryItem->getAssetUUID().isNull()) + { + LL_WARNS("ENVIRONMENT") << "Asset ID in inventory item is NULL (" << mInventoryId << ")" << LL_ENDL; + LLNotificationsUtil::add("UnableEditItem"); + closeFloater(); + + mInventoryId.setNull(); + mInventoryItem = nullptr; + return; + } + + mCanSave = true; + mCanCopy = mInventoryItem->getPermissions().allowCopyBy(gAgent.getID()); + mCanMod = mInventoryItem->getPermissions().allowModifyBy(gAgent.getID()); + mCanTrans = can_trans && mInventoryItem->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()); + + mExpectingAssetId = mInventoryItem->getAssetUUID(); + LLSettingsVOBase::getSettingsAsset(mInventoryItem->getAssetUUID(), + [this](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) { onAssetLoaded(asset_id, settings, status); }); +} + + +void LLFloaterEditEnvironmentBase::checkAndConfirmSettingsLoss(LLFloaterEditEnvironmentBase::on_confirm_fn cb) +{ + if (isDirty()) + { + LLSD args(LLSDMap("TYPE", getEditSettings()->getSettingsType()) + ("NAME", getEditSettings()->getName())); + + // create and show confirmation textbox + LLNotificationsUtil::add("SettingsConfirmLoss", args, LLSD(), + [cb](const LLSD¬if, const LLSD&resp) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); + if (opt == 0) + cb(); + }); + } + else if (cb) + { + cb(); + } +} + +void LLFloaterEditEnvironmentBase::onAssetLoaded(LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status) +{ + if (asset_id != mExpectingAssetId) + { + LL_WARNS("ENVDAYEDIT") << "Expecting {" << mExpectingAssetId << "} got {" << asset_id << "} - throwing away." << LL_ENDL; + return; + } + mExpectingAssetId.setNull(); + clearDirtyFlag(); + + if (!settings || status) + { + LLSD args; + args["NAME"] = (mInventoryItem) ? mInventoryItem->getName() : asset_id.asString(); + LLNotificationsUtil::add("FailedToFindSettings", args); + closeFloater(); + return; + } + + if (settings->getFlag(LLSettingsBase::FLAG_NOSAVE)) + { + mCanSave = false; + mCanCopy = false; + mCanMod = false; + mCanTrans = false; + } + else + { + if (mInventoryItem) + settings->setName(mInventoryItem->getName()); + + if (mCanCopy) + settings->clearFlag(LLSettingsBase::FLAG_NOCOPY); + else + settings->setFlag(LLSettingsBase::FLAG_NOCOPY); + + if (mCanMod) + settings->clearFlag(LLSettingsBase::FLAG_NOMOD); + else + settings->setFlag(LLSettingsBase::FLAG_NOMOD); + + if (mCanTrans) + settings->clearFlag(LLSettingsBase::FLAG_NOTRANS); + else + settings->setFlag(LLSettingsBase::FLAG_NOTRANS); + } + + setEditSettingsAndUpdate(settings); +} + +void LLFloaterEditEnvironmentBase::onButtonImport() +{ + checkAndConfirmSettingsLoss([this](){ doImportFromDisk(); }); +} + +void LLFloaterEditEnvironmentBase::onSaveAsCommit(const LLSD& notification, const LLSD& response, const LLSettingsBase::ptr_t &settings) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + std::string settings_name = response["message"].asString(); + + LLInventoryObject::correctInventoryName(settings_name); + if (settings_name.empty()) + { + // Ideally notification should disable 'OK' button if name won't fit our requirements, + // for now either display notification, or use some default name + settings_name = "Unnamed"; + } + + if (mCanMod) + { + doApplyCreateNewInventory(settings_name, settings); + } + else if (mInventoryItem) + { + const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + LLUUID parent_id = mInventoryItem->getParentUUID(); + if (marketplacelistings_id == parent_id || gInventory.isObjectDescendentOf(mInventoryItem->getUUID(), gInventory.getLibraryRootFolderID())) + { + parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS); + } + + LLPointer<LLInventoryCallback> cb = new LLFixedSettingCopiedCallback(getHandle()); + copy_inventory_item( + gAgent.getID(), + mInventoryItem->getPermissions().getOwner(), + mInventoryItem->getUUID(), + parent_id, + settings_name, + cb); + } + else + { + LL_WARNS() << "Failed to copy fixed env setting" << LL_ENDL; + } + } +} + +void LLFloaterEditEnvironmentBase::onClickCloseBtn(bool app_quitting) +{ + if (!app_quitting) + checkAndConfirmSettingsLoss([this](){ closeFloater(); clearDirtyFlag(); }); + else + closeFloater(); +} + +void LLFloaterEditEnvironmentBase::doApplyCreateNewInventory(std::string settings_name, const LLSettingsBase::ptr_t &settings) +{ + if (mInventoryItem) + { + LLUUID parent_id = mInventoryItem->getParentUUID(); + U32 next_owner_perm = mInventoryItem->getPermissions().getMaskNextOwner(); + LLSettingsVOBase::createInventoryItem(settings, next_owner_perm, parent_id, settings_name, + [this](LLUUID asset_id, LLUUID inventory_id, LLUUID, LLSD results) { onInventoryCreated(asset_id, inventory_id, results); }); + } + else + { + LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS); + // This method knows what sort of settings object to create. + LLSettingsVOBase::createInventoryItem(settings, parent_id, settings_name, + [this](LLUUID asset_id, LLUUID inventory_id, LLUUID, LLSD results) { onInventoryCreated(asset_id, inventory_id, results); }); + } +} + +void LLFloaterEditEnvironmentBase::doApplyUpdateInventory(const LLSettingsBase::ptr_t &settings) +{ + LL_DEBUGS("ENVEDIT") << "Update inventory for " << mInventoryId << LL_ENDL; + if (mInventoryId.isNull()) + { + LLSettingsVOBase::createInventoryItem(settings, gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS), std::string(), + [this](LLUUID asset_id, LLUUID inventory_id, LLUUID, LLSD results) { onInventoryCreated(asset_id, inventory_id, results); }); + } + else + { + LLSettingsVOBase::updateInventoryItem(settings, mInventoryId, + [this](LLUUID asset_id, LLUUID inventory_id, LLUUID, LLSD results) { onInventoryUpdated(asset_id, inventory_id, results); }); + } +} + +void LLFloaterEditEnvironmentBase::doApplyEnvironment(const std::string &where, const LLSettingsBase::ptr_t &settings) +{ + U32 flags(0); + + if (mInventoryItem) + { + if (!mInventoryItem->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID())) + flags |= LLSettingsBase::FLAG_NOMOD; + if (!mInventoryItem->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID())) + flags |= LLSettingsBase::FLAG_NOTRANS; + } + + flags |= settings->getFlags(); + settings->setFlag(flags); + + if (where == ACTION_APPLY_LOCAL) + { + settings->setName("Local"); // To distinguish and make sure there is a name. Safe, because this is a copy. + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, settings); + } + else if (where == ACTION_APPLY_PARCEL) + { + LLParcel *parcel(LLViewerParcelMgr::instance().getAgentOrSelectedParcel()); + + if ((!parcel) || (parcel->getLocalID() == INVALID_PARCEL_ID)) + { + LL_WARNS("ENVIRONMENT") << "Can not identify parcel. Not applying." << LL_ENDL; + LLNotificationsUtil::add("WLParcelApplyFail"); + return; + } + + if (mInventoryItem && !isDirty()) + { + LLEnvironment::instance().updateParcel(parcel->getLocalID(), mInventoryItem->getAssetUUID(), mInventoryItem->getName(), LLEnvironment::NO_TRACK, -1, -1, flags); + } + else if (settings->getSettingsType() == "sky") + { + LLEnvironment::instance().updateParcel(parcel->getLocalID(), std::static_pointer_cast<LLSettingsSky>(settings), -1, -1); + } + else if (settings->getSettingsType() == "water") + { + LLEnvironment::instance().updateParcel(parcel->getLocalID(), std::static_pointer_cast<LLSettingsWater>(settings), -1, -1); + } + else if (settings->getSettingsType() == "day") + { + LLEnvironment::instance().updateParcel(parcel->getLocalID(), std::static_pointer_cast<LLSettingsDay>(settings), -1, -1); + } + } + else if (where == ACTION_APPLY_REGION) + { + if (mInventoryItem && !isDirty()) + { + LLEnvironment::instance().updateRegion(mInventoryItem->getAssetUUID(), mInventoryItem->getName(), LLEnvironment::NO_TRACK, -1, -1, flags); + } + else if (settings->getSettingsType() == "sky") + { + LLEnvironment::instance().updateRegion(std::static_pointer_cast<LLSettingsSky>(settings), -1, -1); + } + else if (settings->getSettingsType() == "water") + { + LLEnvironment::instance().updateRegion(std::static_pointer_cast<LLSettingsWater>(settings), -1, -1); + } + else if (settings->getSettingsType() == "day") + { + LLEnvironment::instance().updateRegion(std::static_pointer_cast<LLSettingsDay>(settings), -1, -1); + } + } + else + { + LL_WARNS("ENVIRONMENT") << "Unknown apply '" << where << "'" << LL_ENDL; + return; + } + +} + +void LLFloaterEditEnvironmentBase::doCloseInventoryFloater(bool quitting) +{ + LLFloater* floaterp = mInventoryFloater.get(); + + if (floaterp) + { + floaterp->closeFloater(quitting); + } +} + +void LLFloaterEditEnvironmentBase::onInventoryCreated(LLUUID asset_id, LLUUID inventory_id, LLSD results) +{ + LL_WARNS("ENVIRONMENT") << "Inventory item " << inventory_id << " has been created with asset " << asset_id << " results are:" << results << LL_ENDL; + + if (inventory_id.isNull() || !results["success"].asBoolean()) + { + LLNotificationsUtil::add("CantCreateInventory"); + return; + } + onInventoryCreated(asset_id, inventory_id); +} + +void LLFloaterEditEnvironmentBase::onInventoryCreated(LLUUID asset_id, LLUUID inventory_id) +{ + bool can_trans = true; + if (mInventoryItem) + { + LLPermissions perms = mInventoryItem->getPermissions(); + + LLInventoryItem *created_item = gInventory.getItem(mInventoryId); + + if (created_item) + { + can_trans = perms.allowOperationBy(PERM_TRANSFER, gAgent.getID()); + created_item->setPermissions(perms); + created_item->updateServer(false); + } + } + + clearDirtyFlag(); + setFocus(TRUE); // Call back the focus... + loadInventoryItem(inventory_id, can_trans); +} + +void LLFloaterEditEnvironmentBase::onInventoryUpdated(LLUUID asset_id, LLUUID inventory_id, LLSD results) +{ + LL_WARNS("ENVIRONMENT") << "Inventory item " << inventory_id << " has been updated with asset " << asset_id << " results are:" << results << LL_ENDL; + + clearDirtyFlag(); + if (inventory_id != mInventoryId) + { + loadInventoryItem(inventory_id); + } +} + +void LLFloaterEditEnvironmentBase::onPanelDirtyFlagChanged(bool value) +{ + if (value) + setDirtyFlag(); +} + +//------------------------------------------------------------------------- +bool LLFloaterEditEnvironmentBase::canUseInventory() const +{ + return LLEnvironment::instance().isInventoryEnabled(); +} + +bool LLFloaterEditEnvironmentBase::canApplyRegion() const +{ + return gAgent.canManageEstate(); +} + +bool LLFloaterEditEnvironmentBase::canApplyParcel() const +{ + return LLEnvironment::instance().canAgentUpdateParcelEnvironment(); +} + +//========================================================================= diff --git a/indra/newview/llfloatereditenvironmentbase.h b/indra/newview/llfloatereditenvironmentbase.h new file mode 100644 index 0000000000..7c7cf5bdcd --- /dev/null +++ b/indra/newview/llfloatereditenvironmentbase.h @@ -0,0 +1,148 @@ +/** + * @file llfloatereditenvironmentbase.h + * @brief Floaters to create and edit fixed settings for sky and water. + * + * $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_FLOATEREDITENVIRONMENTBASE_H +#define LL_FLOATEREDITENVIRONMENTBASE_H + +#include "llfloater.h" +#include "llsettingsbase.h" +#include "llflyoutcombobtn.h" +#include "llinventory.h" + +#include "boost/signals2.hpp" + +class LLTabContainer; +class LLButton; +class LLLineEditor; +class LLFloaterSettingsPicker; +class LLFixedSettingCopiedCallback; + +class LLFloaterEditEnvironmentBase : public LLFloater +{ + LOG_CLASS(LLFloaterEditEnvironmentBase); + + friend class LLFixedSettingCopiedCallback; + +public: + static const std::string KEY_INVENTORY_ID; + + LLFloaterEditEnvironmentBase(const LLSD &key); + ~LLFloaterEditEnvironmentBase(); + + virtual void onFocusReceived() override; + virtual void onFocusLost() override; + + virtual LLSettingsBase::ptr_t getEditSettings() const = 0; + + virtual BOOL isDirty() const override { return getIsDirty(); } + +protected: + typedef std::function<void()> on_confirm_fn; + + virtual void setEditSettingsAndUpdate(const LLSettingsBase::ptr_t &settings) = 0; + virtual void updateEditEnvironment() = 0; + + virtual LLFloaterSettingsPicker *getSettingsPicker() = 0; + + void loadInventoryItem(const LLUUID &inventoryId, bool can_trans = true); + + void checkAndConfirmSettingsLoss(on_confirm_fn cb); + + virtual void doImportFromDisk() = 0; + virtual void doApplyCreateNewInventory(std::string settings_name, const LLSettingsBase::ptr_t &settings); + virtual void doApplyUpdateInventory(const LLSettingsBase::ptr_t &settings); + virtual void doApplyEnvironment(const std::string &where, const LLSettingsBase::ptr_t &settings); + void doCloseInventoryFloater(bool quitting = false); + + bool canUseInventory() const; + bool canApplyRegion() const; + bool canApplyParcel() const; + + LLUUID mInventoryId; + LLInventoryItem * mInventoryItem; + LLHandle<LLFloater> mInventoryFloater; + bool mCanCopy; + bool mCanMod; + bool mCanTrans; + bool mCanSave; + + bool mIsDirty; + + void onInventoryCreated(LLUUID asset_id, LLUUID inventory_id); + void onInventoryCreated(LLUUID asset_id, LLUUID inventory_id, LLSD results); + void onInventoryUpdated(LLUUID asset_id, LLUUID inventory_id, LLSD results); + + bool getIsDirty() const { return mIsDirty; } + void setDirtyFlag() { mIsDirty = true; } + virtual void clearDirtyFlag() = 0; + + void onPanelDirtyFlagChanged(bool); + + virtual void onClickCloseBtn(bool app_quitting = false) override; + void onSaveAsCommit(const LLSD& notification, const LLSD& response, const LLSettingsBase::ptr_t &settings); + void onButtonImport(); + + void onAssetLoaded(LLUUID asset_id, LLSettingsBase::ptr_t settins, S32 status); + +private: + LLUUID mExpectingAssetId; // for asset load confirmation +}; + +class LLSettingsEditPanel : public LLPanel +{ +public: + virtual void setSettings(const LLSettingsBase::ptr_t &) = 0; + + typedef boost::signals2::signal<void(LLPanel *, bool)> on_dirty_charged_sg; + typedef boost::signals2::connection connection_t; + + inline bool getIsDirty() const { return mIsDirty; } + inline void setIsDirty() { mIsDirty = true; if (!mOnDirtyChanged.empty()) mOnDirtyChanged(this, mIsDirty); } + inline void clearIsDirty() { mIsDirty = false; if (!mOnDirtyChanged.empty()) mOnDirtyChanged(this, mIsDirty); } + + inline bool getCanChangeSettings() const { return mCanEdit; } + inline void setCanChangeSettings(bool flag) { mCanEdit = flag; } + + inline connection_t setOnDirtyFlagChanged(on_dirty_charged_sg::slot_type cb) { return mOnDirtyChanged.connect(cb); } + + +protected: + LLSettingsEditPanel() : + LLPanel(), + mIsDirty(false), + mOnDirtyChanged() + {} + +private: + void onTextureChanged(LLUUID &inventory_item_id); + + bool mIsDirty; + bool mCanEdit; + + on_dirty_charged_sg mOnDirtyChanged; +}; + +#endif // LL_FLOATERENVIRONMENTBASE_H diff --git a/indra/newview/llfloatereditextdaycycle.cpp b/indra/newview/llfloatereditextdaycycle.cpp new file mode 100644 index 0000000000..0501c287ad --- /dev/null +++ b/indra/newview/llfloatereditextdaycycle.cpp @@ -0,0 +1,1801 @@ +/** + * @file llfloatereditextdaycycle.cpp + * @brief Floater to create or edit a day cycle + * + * $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 "llfloatereditextdaycycle.h" + +// libs +#include "llbutton.h" +#include "llcallbacklist.h" +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llloadingindicator.h" +#include "lllocalbitmaps.h" +#include "llmultisliderctrl.h" +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llspinctrl.h" +#include "lltimectrl.h" +#include "lltabcontainer.h" +#include "llfilepicker.h" + +#include "llsettingsvo.h" +#include "llinventorymodel.h" +#include "llviewerparcelmgr.h" + +#include "llsettingspicker.h" +#include "lltrackpicker.h" + +// newview +#include "llagent.h" +#include "llappviewer.h" //gDisconected +#include "llparcel.h" +#include "llflyoutcombobtn.h" //Todo: make a proper UI element/button/panel instead +#include "llregioninfomodel.h" +#include "llviewermenufile.h" // LLFilePickerReplyThread +#include "llviewerregion.h" +#include "llpaneleditwater.h" +#include "llpaneleditsky.h" + +#include "llui.h" + +#include "llenvironment.h" +#include "lltrans.h" + +extern LLControlGroup gSavedSettings; + +//========================================================================= +namespace { + const std::string track_tabs[] = { + "water_track", + "sky1_track", + "sky2_track", + "sky3_track", + "sky4_track", + }; + + const std::string ICN_LOCK_EDIT("icn_lock_edit"); + const std::string BTN_SAVE("save_btn"); + const std::string BTN_FLYOUT("btn_flyout"); + const std::string BTN_CANCEL("cancel_btn"); + const std::string BTN_ADDFRAME("add_frame"); + const std::string BTN_DELFRAME("delete_frame"); + const std::string BTN_IMPORT("btn_import"); + const std::string BTN_LOADFRAME("btn_load_frame"); + const std::string BTN_CLONETRACK("copy_track"); + const std::string BTN_LOADTRACK("load_track"); + const std::string BTN_CLEARTRACK("clear_track"); + const std::string SLDR_TIME("WLTimeSlider"); + const std::string SLDR_KEYFRAMES("WLDayCycleFrames"); + const std::string VIEW_SKY_SETTINGS("frame_settings_sky"); + const std::string VIEW_WATER_SETTINGS("frame_settings_water"); + const std::string LBL_CURRENT_TIME("current_time"); + const std::string TXT_DAY_NAME("day_cycle_name"); + const std::string TABS_SKYS("sky_tabs"); + const std::string TABS_WATER("water_tabs"); + + const std::string EVNT_DAYTRACK("DayCycle.Track"); + const std::string EVNT_PLAY("DayCycle.PlayActions"); + + const std::string ACTION_PLAY("play"); + const std::string ACTION_PAUSE("pause"); + const std::string ACTION_FORWARD("forward"); + const std::string ACTION_BACK("back"); + + // For flyout + const std::string XML_FLYOUTMENU_FILE("menu_save_settings.xml"); + // From menu_save_settings.xml, consider moving into flyout since it should be supported by flyout either way + const std::string ACTION_SAVE("save_settings"); + const std::string ACTION_SAVEAS("save_as_new_settings"); + const std::string ACTION_COMMIT("commit_changes"); + const std::string ACTION_APPLY_LOCAL("apply_local"); + const std::string ACTION_APPLY_PARCEL("apply_parcel"); + const std::string ACTION_APPLY_REGION("apply_region"); + + const F32 DAY_CYCLE_PLAY_TIME_SECONDS = 60; + + const std::string STR_COMMIT_PARCEL("commit_parcel"); + const std::string STR_COMMIT_REGION("commit_region"); + //--------------------------------------------------------------------- + +} + +//========================================================================= +const std::string LLFloaterEditExtDayCycle::KEY_EDIT_CONTEXT("edit_context"); +const std::string LLFloaterEditExtDayCycle::KEY_DAY_LENGTH("day_length"); +const std::string LLFloaterEditExtDayCycle::KEY_CANMOD("canmod"); + +const std::string LLFloaterEditExtDayCycle::VALUE_CONTEXT_INVENTORY("inventory"); +const std::string LLFloaterEditExtDayCycle::VALUE_CONTEXT_PARCEL("parcel"); +const std::string LLFloaterEditExtDayCycle::VALUE_CONTEXT_REGION("region"); +/* +//========================================================================= + +class LLDaySettingCopiedCallback : public LLInventoryCallback +{ +public: + LLDaySettingCopiedCallback(LLHandle<LLFloater> handle) : mHandle(handle) {} + + virtual void fire(const LLUUID& inv_item_id) + { + if (!mHandle.isDead()) + { + LLViewerInventoryItem* item = gInventory.getItem(inv_item_id); + if (item) + { + LLFloaterEditExtDayCycle* floater = (LLFloaterEditExtDayCycle*)mHandle.get(); + floater->onInventoryCreated(item->getAssetUUID(), inv_item_id); + } + } + } + +private: + LLHandle<LLFloater> mHandle; +};*/ + +//========================================================================= + +LLFloaterEditExtDayCycle::LLFloaterEditExtDayCycle(const LLSD &key) : + LLFloaterEditEnvironmentBase(key), + mFlyoutControl(nullptr), + mDayLength(0), + mCurrentTrack(1), + mShiftCopyEnabled(false), + mTimeSlider(nullptr), + mFramesSlider(nullptr), + mCurrentTimeLabel(nullptr), + mImportButton(nullptr), + mLoadFrame(nullptr), + mSkyBlender(), + mWaterBlender(), + mScratchSky(), + mScratchWater(), + mIsPlaying(false), + mCloneTrack(nullptr), + mLoadTrack(nullptr), + mClearTrack(nullptr) +{ + + mCommitCallbackRegistrar.add(EVNT_DAYTRACK, [this](LLUICtrl *ctrl, const LLSD &data) { onTrackSelectionCallback(data); }); + mCommitCallbackRegistrar.add(EVNT_PLAY, [this](LLUICtrl *ctrl, const LLSD &data) { onPlayActionCallback(data); }); + + mScratchSky = LLSettingsVOSky::buildDefaultSky(); + mScratchWater = LLSettingsVOWater::buildDefaultWater(); + + mEditSky = mScratchSky; + mEditWater = mScratchWater; +} + +LLFloaterEditExtDayCycle::~LLFloaterEditExtDayCycle() +{ + // Todo: consider remaking mFlyoutControl into full view class that initializes intself with floater, + // complete with postbuild, e t c... + delete mFlyoutControl; +} + +// virtual +BOOL LLFloaterEditExtDayCycle::postBuild() +{ + getChild<LLLineEditor>(TXT_DAY_NAME)->setKeystrokeCallback(boost::bind(&LLFloaterEditExtDayCycle::onCommitName, this, _1, _2), NULL); + + mAddFrameButton = getChild<LLButton>(BTN_ADDFRAME, true); + mDeleteFrameButton = getChild<LLButton>(BTN_DELFRAME, true); + mTimeSlider = getChild<LLMultiSliderCtrl>(SLDR_TIME); + mFramesSlider = getChild<LLMultiSliderCtrl>(SLDR_KEYFRAMES); + mSkyTabLayoutContainer = getChild<LLView>(VIEW_SKY_SETTINGS, true); + mWaterTabLayoutContainer = getChild<LLView>(VIEW_WATER_SETTINGS, true); + mCurrentTimeLabel = getChild<LLTextBox>(LBL_CURRENT_TIME, true); + mImportButton = getChild<LLButton>(BTN_IMPORT, true); + mLoadFrame = getChild<LLButton>(BTN_LOADFRAME, true); + mCloneTrack = getChild<LLButton>(BTN_CLONETRACK, true); + mLoadTrack = getChild<LLButton>(BTN_LOADTRACK, true); + mClearTrack = getChild<LLButton>(BTN_CLEARTRACK, true); + + mFlyoutControl = new LLFlyoutComboBtnCtrl(this, BTN_SAVE, BTN_FLYOUT, XML_FLYOUTMENU_FILE, false); + mFlyoutControl->setAction([this](LLUICtrl *ctrl, const LLSD &data) { onButtonApply(ctrl, data); }); + + getChild<LLButton>(BTN_CANCEL, true)->setCommitCallback([this](LLUICtrl *ctrl, const LLSD &data) { onClickCloseBtn(); }); + mTimeSlider->setCommitCallback([this](LLUICtrl *ctrl, const LLSD &data) { onTimeSliderCallback(); }); + mAddFrameButton->setCommitCallback([this](LLUICtrl *ctrl, const LLSD &data) { onAddFrame(); }); + mDeleteFrameButton->setCommitCallback([this](LLUICtrl *ctrl, const LLSD &data) { onRemoveFrame(); }); + mImportButton->setCommitCallback([this](LLUICtrl *, const LLSD &){ onButtonImport(); }); + mLoadFrame->setCommitCallback([this](LLUICtrl *, const LLSD &){ onButtonLoadFrame(); }); + + mCloneTrack->setCommitCallback([this](LLUICtrl *, const LLSD&){ onCloneTrack(); }); + mLoadTrack->setCommitCallback([this](LLUICtrl *, const LLSD&){ onLoadTrack();}); + mClearTrack->setCommitCallback([this](LLUICtrl *, const LLSD&){ onClearTrack(); }); + + + mFramesSlider->setCommitCallback([this](LLUICtrl *, const LLSD &data) { onFrameSliderCallback(data); }); + mFramesSlider->setDoubleClickCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask){ onFrameSliderDoubleClick(x, y, mask); }); + mFramesSlider->setMouseDownCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask){ onFrameSliderMouseDown(x, y, mask); }); + mFramesSlider->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask){ onFrameSliderMouseUp(x, y, mask); }); + + mTimeSlider->addSlider(0); + + LLTabContainer* tab_container = mSkyTabLayoutContainer->getChild<LLTabContainer>("sky_tabs"); + S32 tab_count = tab_container->getTabCount(); + + LLSettingsEditPanel *panel = nullptr; + + for (S32 idx = 0; idx < tab_count; ++idx) + { + panel = static_cast<LLSettingsEditPanel *>(tab_container->getPanelByIndex(idx)); + if (panel) + panel->setOnDirtyFlagChanged([this](LLPanel *, bool val) { onPanelDirtyFlagChanged(val); }); + } + + tab_container = mWaterTabLayoutContainer->getChild<LLTabContainer>("water_tabs"); + tab_count = tab_container->getTabCount(); + + for (S32 idx = 0; idx < tab_count; ++idx) + { + LLSettingsEditPanel *panel = static_cast<LLSettingsEditPanel *>(tab_container->getPanelByIndex(idx)); + if (panel) + panel->setOnDirtyFlagChanged([this](LLPanel *, bool val) { onPanelDirtyFlagChanged(val); }); + } + + return TRUE; +} + +void LLFloaterEditExtDayCycle::onOpen(const LLSD& key) +{ + if (!mEditDay) + { + LLEnvironment::instance().saveBeaconsState(); + } + mEditDay.reset(); + mEditContext = CONTEXT_UNKNOWN; + if (key.has(KEY_EDIT_CONTEXT)) + { + std::string context = key[KEY_EDIT_CONTEXT].asString(); + + if (context == VALUE_CONTEXT_INVENTORY) + mEditContext = CONTEXT_INVENTORY; + else if (context == VALUE_CONTEXT_PARCEL) + mEditContext = CONTEXT_PARCEL; + else if (context == VALUE_CONTEXT_REGION) + mEditContext = CONTEXT_REGION; + } + + if (key.has(KEY_CANMOD)) + { + mCanMod = key[KEY_CANMOD].asBoolean(); + } + + if (mEditContext == CONTEXT_UNKNOWN) + { + LL_WARNS("ENVDAYEDIT") << "Unknown editing context!" << LL_ENDL; + } + + if (key.has(KEY_INVENTORY_ID)) + { + loadInventoryItem(key[KEY_INVENTORY_ID].asUUID()); + } + else + { + mCanSave = true; + mCanCopy = true; + mCanMod = true; + mCanTrans = true; + setEditDefaultDayCycle(); + } + + mDayLength.value(0); + if (key.has(KEY_DAY_LENGTH)) + { + mDayLength.value(key[KEY_DAY_LENGTH].asReal()); + } + + // Time&Percentage labels + mCurrentTimeLabel->setTextArg("[PRCNT]", std::string("0")); + const S32 max_elm = 5; + if (mDayLength.value() != 0) + { + S32Hours hrs; + S32Minutes minutes; + LLSettingsDay::Seconds total; + LLUIString formatted_label = getString("time_label"); + for (int i = 0; i < max_elm; i++) + { + total = ((mDayLength / (max_elm - 1)) * i); + hrs = total; + minutes = total - hrs; + + formatted_label.setArg("[HH]", llformat("%d", hrs.value())); + formatted_label.setArg("[MM]", llformat("%d", abs(minutes.value()))); + getChild<LLTextBox>("p" + llformat("%d", i), true)->setTextArg("[DSC]", formatted_label.getString()); + } + hrs = mDayLength; + minutes = mDayLength - hrs; + formatted_label.setArg("[HH]", llformat("%d", hrs.value())); + formatted_label.setArg("[MM]", llformat("%d", abs(minutes.value()))); + mCurrentTimeLabel->setTextArg("[DSC]", formatted_label.getString()); + } + else + { + for (int i = 0; i < max_elm; i++) + { + getChild<LLTextBox>("p" + llformat("%d", i), true)->setTextArg("[DSC]", std::string()); + } + mCurrentTimeLabel->setTextArg("[DSC]", std::string()); + } + + // Adjust Time&Percentage labels' location according to length + LLRect label_rect = getChild<LLTextBox>("p0", true)->getRect(); + F32 slider_width = mFramesSlider->getRect().getWidth(); + for (int i = 1; i < max_elm; i++) + { + LLTextBox *pcnt_label = getChild<LLTextBox>("p" + llformat("%d", i), true); + LLRect new_rect = pcnt_label->getRect(); + new_rect.mLeft = label_rect.mLeft + (S32)(slider_width * (F32)i / (F32)(max_elm - 1)) - (S32)(pcnt_label->getTextPixelWidth() / 2); + pcnt_label->setRect(new_rect); + } + + // Altitudes&Track labels + LLUIString formatted_label = getString("sky_track_label"); + const LLEnvironment::altitude_list_t &altitudes = LLEnvironment::instance().getRegionAltitudes(); + bool extended_env = LLEnvironment::instance().isExtendedEnvironmentEnabled(); + bool use_altitudes = extended_env + && altitudes.size() > 0 + && ((mEditContext == CONTEXT_PARCEL) || (mEditContext == CONTEXT_REGION)); + for (S32 idx = 1; idx < 4; ++idx) + { + std::ostringstream convert; + if (use_altitudes) + { + convert << altitudes[idx] << "m"; + } + else + { + convert << (idx + 1); + } + formatted_label.setArg("[ALT]", convert.str()); + getChild<LLButton>(track_tabs[idx + 1], true)->setLabel(formatted_label.getString()); + } + + for (U32 i = 2; i < LLSettingsDay::TRACK_MAX; i++) //skies #2 through #4 + { + getChild<LLButton>(track_tabs[i])->setEnabled(extended_env); + } + + if (mEditContext == CONTEXT_INVENTORY) + { + mFlyoutControl->setShownBtnEnabled(true); + mFlyoutControl->setSelectedItem(ACTION_SAVE); + } + else if ((mEditContext == CONTEXT_REGION) || (mEditContext == CONTEXT_PARCEL)) + { + std::string commit_str = (mEditContext == CONTEXT_PARCEL) ? STR_COMMIT_PARCEL : STR_COMMIT_REGION; + mFlyoutControl->setMenuItemLabel(ACTION_COMMIT, getString(commit_str)); + mFlyoutControl->setShownBtnEnabled(true); + mFlyoutControl->setSelectedItem(ACTION_COMMIT); + } + else + { + mFlyoutControl->setShownBtnEnabled(false); + } +} + +void LLFloaterEditExtDayCycle::onClose(bool app_quitting) +{ + doCloseInventoryFloater(app_quitting); + doCloseTrackFloater(app_quitting); + // there's no point to change environment if we're quitting + // or if we already restored environment + stopPlay(); + LLEnvironment::instance().revertBeaconsState(); + if (!app_quitting) + { + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_FAST); + LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_EDIT); + mEditDay.reset(); + } +} + + +void LLFloaterEditExtDayCycle::onVisibilityChange(BOOL new_visibility) +{ +} + +void LLFloaterEditExtDayCycle::refresh() +{ + if (mEditDay) + { + LLLineEditor* name_field = getChild<LLLineEditor>(TXT_DAY_NAME); + name_field->setText(mEditDay->getName()); + name_field->setEnabled(mCanMod); + } + + + bool is_inventory_avail = canUseInventory(); + + bool show_commit = ((mEditContext == CONTEXT_PARCEL) || (mEditContext == CONTEXT_REGION)); + bool show_apply = (mEditContext == CONTEXT_INVENTORY); + + if (show_commit) + { + std::string commit_text; + if (mEditContext == CONTEXT_PARCEL) + commit_text = getString(STR_COMMIT_PARCEL); + else + commit_text = getString(STR_COMMIT_REGION); + + mFlyoutControl->setMenuItemLabel(ACTION_COMMIT, commit_text); + } + + mFlyoutControl->setMenuItemVisible(ACTION_COMMIT, show_commit); + mFlyoutControl->setMenuItemVisible(ACTION_SAVE, is_inventory_avail); + mFlyoutControl->setMenuItemVisible(ACTION_SAVEAS, is_inventory_avail); + mFlyoutControl->setMenuItemVisible(ACTION_APPLY_LOCAL, true); + mFlyoutControl->setMenuItemVisible(ACTION_APPLY_PARCEL, show_apply); + mFlyoutControl->setMenuItemVisible(ACTION_APPLY_REGION, show_apply); + + mFlyoutControl->setMenuItemEnabled(ACTION_COMMIT, show_commit && !mCommitSignal.empty()); + mFlyoutControl->setMenuItemEnabled(ACTION_SAVE, is_inventory_avail && mCanMod && !mInventoryId.isNull() && mCanSave); + mFlyoutControl->setMenuItemEnabled(ACTION_SAVEAS, is_inventory_avail && mCanCopy && mCanSave); + mFlyoutControl->setMenuItemEnabled(ACTION_APPLY_LOCAL, true); + mFlyoutControl->setMenuItemEnabled(ACTION_APPLY_PARCEL, canApplyParcel() && show_apply); + mFlyoutControl->setMenuItemEnabled(ACTION_APPLY_REGION, canApplyRegion() && show_apply); + + mImportButton->setEnabled(mCanMod); + + LLFloater::refresh(); +} + +void LLFloaterEditExtDayCycle::setEditSettingsAndUpdate(const LLSettingsBase::ptr_t &settings) +{ + setEditDayCycle(std::dynamic_pointer_cast<LLSettingsDay>(settings)); +} + +void LLFloaterEditExtDayCycle::setEditDayCycle(const LLSettingsDay::ptr_t &pday) +{ + mExpectingAssetId.setNull(); + mEditDay = pday->buildDeepCloneAndUncompress(); + + if (mEditDay->isTrackEmpty(LLSettingsDay::TRACK_WATER)) + { + LL_WARNS("ENVDAYEDIT") << "No water frames found, generating replacement" << LL_ENDL; + mEditDay->setWaterAtKeyframe(LLSettingsVOWater::buildDefaultWater(), .5f); + } + + if (mEditDay->isTrackEmpty(LLSettingsDay::TRACK_GROUND_LEVEL)) + { + LL_WARNS("ENVDAYEDIT") << "No sky frames found, generating replacement" << LL_ENDL; + mEditDay->setSkyAtKeyframe(LLSettingsVOSky::buildDefaultSky(), .5f, LLSettingsDay::TRACK_GROUND_LEVEL); + } + + mCanSave = !pday->getFlag(LLSettingsBase::FLAG_NOSAVE); + mCanCopy = !pday->getFlag(LLSettingsBase::FLAG_NOCOPY) && mCanSave; + mCanMod = !pday->getFlag(LLSettingsBase::FLAG_NOMOD) && mCanSave; + mCanTrans = !pday->getFlag(LLSettingsBase::FLAG_NOTRANS) && mCanSave; + + updateEditEnvironment(); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_EDIT, LLEnvironment::TRANSITION_INSTANT); + LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); + synchronizeTabs(); + updateTabs(); + refresh(); +} + + +void LLFloaterEditExtDayCycle::setEditDefaultDayCycle() +{ + mInventoryItem = nullptr; + mInventoryId.setNull(); + mExpectingAssetId = LLSettingsDay::GetDefaultAssetId(); + LLSettingsVOBase::getSettingsAsset(LLSettingsDay::GetDefaultAssetId(), + [this](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) { onAssetLoaded(asset_id, settings, status); }); +} + +std::string LLFloaterEditExtDayCycle::getEditName() const +{ + if (mEditDay) + return mEditDay->getName(); + return "new"; +} + +void LLFloaterEditExtDayCycle::setEditName(const std::string &name) +{ + if (mEditDay) + mEditDay->setName(name); + getChild<LLLineEditor>(TXT_DAY_NAME)->setText(name); +} + +/* virtual */ +BOOL LLFloaterEditExtDayCycle::handleKeyUp(KEY key, MASK mask, BOOL called_from_parent) +{ + if (!mEditDay) + { + mShiftCopyEnabled = false; + } + else if (mask == MASK_SHIFT && mShiftCopyEnabled) + { + mShiftCopyEnabled = false; + std::string curslider = mFramesSlider->getCurSlider(); + if (!curslider.empty()) + { + F32 sliderpos = mFramesSlider->getCurSliderValue(); + + keymap_t::iterator it = mSliderKeyMap.find(curslider); + if (it != mSliderKeyMap.end()) + { + if (mEditDay->moveTrackKeyframe(mCurrentTrack, (*it).second.mFrame, sliderpos)) + { + (*it).second.mFrame = sliderpos; + } + else + { + mFramesSlider->setCurSliderValue((*it).second.mFrame); + } + } + else + { + LL_WARNS("ENVDAYEDIT") << "Failed to find frame " << sliderpos << " for slider " << curslider << LL_ENDL; + } + } + } + return LLFloater::handleKeyUp(key, mask, called_from_parent); +} + +void LLFloaterEditExtDayCycle::onButtonApply(LLUICtrl *ctrl, const LLSD &data) +{ + std::string ctrl_action = ctrl->getName(); + + if (!mEditDay) + { + LL_WARNS("ENVDAYEDIT") << "mEditDay is null! This should never happen! Something is very very wrong" << LL_ENDL; + LLNotificationsUtil::add("EnvironmentApplyFailed"); + closeFloater(); + return; + } + + LLSettingsDay::ptr_t dayclone = mEditDay->buildClone(); // create a compressed copy + + if (!dayclone) + { + LL_WARNS("ENVDAYEDIT") << "Unable to clone daycylce from editor." << LL_ENDL; + return; + } + + // brute-force local texture scan + for (U32 i = 0; i <= LLSettingsDay::TRACK_MAX; i++) + { + LLSettingsDay::CycleTrack_t &day_track = dayclone->getCycleTrack(i); + + LLSettingsDay::CycleTrack_t::iterator iter = day_track.begin(); + LLSettingsDay::CycleTrack_t::iterator end = day_track.end(); + S32 frame_num = 0; + + while (iter != end) + { + frame_num++; + std::string desc; + bool is_local = false; // because getString can be empty + if (i == LLSettingsDay::TRACK_WATER) + { + LLSettingsWater::ptr_t water = std::static_pointer_cast<LLSettingsWater>(iter->second); + if (water) + { + // LLViewerFetchedTexture and check for FTT_LOCAL_FILE or check LLLocalBitmapMgr + if (LLLocalBitmapMgr::getInstance()->isLocal(water->getNormalMapID())) + { + desc = LLTrans::getString("EnvironmentNormalMap"); + is_local = true; + } + else if (LLLocalBitmapMgr::getInstance()->isLocal(water->getTransparentTextureID())) + { + desc = LLTrans::getString("EnvironmentTransparent"); + is_local = true; + } + } + } + else + { + LLSettingsSky::ptr_t sky = std::static_pointer_cast<LLSettingsSky>(iter->second); + if (sky) + { + if (LLLocalBitmapMgr::getInstance()->isLocal(sky->getSunTextureId())) + { + desc = LLTrans::getString("EnvironmentSun"); + is_local = true; + } + else if (LLLocalBitmapMgr::getInstance()->isLocal(sky->getMoonTextureId())) + { + desc = LLTrans::getString("EnvironmentMoon"); + is_local = true; + } + else if (LLLocalBitmapMgr::getInstance()->isLocal(sky->getCloudNoiseTextureId())) + { + desc = LLTrans::getString("EnvironmentCloudNoise"); + is_local = true; + } + else if (LLLocalBitmapMgr::getInstance()->isLocal(sky->getBloomTextureId())) + { + desc = LLTrans::getString("EnvironmentBloom"); + is_local = true; + } + } + } + + if (is_local) + { + LLSD args; + LLButton* button = getChild<LLButton>(track_tabs[i], true); + args["TRACK"] = button->getCurrentLabel(); + args["FRAME"] = iter->first * 100; // % + args["FIELD"] = desc; + args["FRAMENO"] = frame_num; + LLNotificationsUtil::add("WLLocalTextureDayBlock", args); + return; + } + iter++; + } + } + + if (ctrl_action == ACTION_SAVE) + { + doApplyUpdateInventory(dayclone); + } + else if (ctrl_action == ACTION_SAVEAS) + { + LLSD args; + args["DESC"] = dayclone->getName(); + LLNotificationsUtil::add("SaveSettingAs", args, LLSD(), boost::bind(&LLFloaterEditExtDayCycle::onSaveAsCommit, this, _1, _2, dayclone)); + } + else if ((ctrl_action == ACTION_APPLY_LOCAL) || + (ctrl_action == ACTION_APPLY_PARCEL) || + (ctrl_action == ACTION_APPLY_REGION)) + { + doApplyEnvironment(ctrl_action, dayclone); + } + else if (ctrl_action == ACTION_COMMIT) + { + doApplyCommit(dayclone); + } + else + { + LL_WARNS("ENVDAYEDIT") << "Unknown settings action '" << ctrl_action << "'" << LL_ENDL; + } +} + +void LLFloaterEditExtDayCycle::onButtonLoadFrame() +{ + doOpenInventoryFloater((mCurrentTrack == LLSettingsDay::TRACK_WATER) ? LLSettingsType::ST_WATER : LLSettingsType::ST_SKY, LLUUID::null); +} + +void LLFloaterEditExtDayCycle::onAddFrame() +{ + LLSettingsBase::Seconds frame(mTimeSlider->getCurSliderValue()); + LLSettingsBase::ptr_t setting; + if (!mEditDay) + { + LL_WARNS("ENVDAYEDIT") << "Attempt to add new frame while waiting for day(asset) to load." << LL_ENDL; + return; + } + if ((mEditDay->getSettingsNearKeyframe(frame, mCurrentTrack, LLSettingsDay::DEFAULT_FRAME_SLOP_FACTOR)).second) + { + LL_WARNS("ENVDAYEDIT") << "Attempt to add new frame too close to existing frame." << LL_ENDL; + return; + } + if (!mFramesSlider->canAddSliders()) + { + // Shouldn't happen, button should be disabled + LL_WARNS("ENVDAYEDIT") << "Attempt to add new frame when slider is full." << LL_ENDL; + return; + } + + if (mCurrentTrack == LLSettingsDay::TRACK_WATER) + { + // scratch water should always have the current water settings. + LLSettingsWater::ptr_t water(mScratchWater->buildClone()); + setting = water; + mEditDay->setWaterAtKeyframe( std::static_pointer_cast<LLSettingsWater>(setting), frame); + } + else + { + // scratch sky should always have the current sky settings. + LLSettingsSky::ptr_t sky(mScratchSky->buildClone()); + setting = sky; + mEditDay->setSkyAtKeyframe(sky, frame, mCurrentTrack); + } + setDirtyFlag(); + addSliderFrame(frame, setting); + updateTabs(); +} + +void LLFloaterEditExtDayCycle::onRemoveFrame() +{ + std::string sldr_key = mFramesSlider->getCurSlider(); + if (sldr_key.empty()) + { + return; + } + setDirtyFlag(); + removeCurrentSliderFrame(); + updateTabs(); +} + + +void LLFloaterEditExtDayCycle::onCloneTrack() +{ + if (!mEditDay) + { + LL_WARNS("ENVDAYEDIT") << "Attempt to copy track while waiting for day(asset) to load." << LL_ENDL; + return; + } + const LLEnvironment::altitude_list_t &altitudes = LLEnvironment::instance().getRegionAltitudes(); + bool use_altitudes = altitudes.size() > 0 && ((mEditContext == CONTEXT_PARCEL) || (mEditContext == CONTEXT_REGION)); + + LLSD args = LLSD::emptyArray(); + + S32 populated_counter = 0; + for (U32 i = 1; i < LLSettingsDay::TRACK_MAX; i++) + { + LLSD track; + track["id"] = LLSD::Integer(i); + bool populated = (!mEditDay->isTrackEmpty(i)) && (i != mCurrentTrack); + track["enabled"] = populated; + if (populated) + { + populated_counter++; + } + if (use_altitudes) + { + track["altitude"] = altitudes[i - 1]; + } + args.append(track); + } + + if (populated_counter > 0) + { + doOpenTrackFloater(args); + } + else + { + // Should not happen + LL_WARNS("ENVDAYEDIT") << "Tried to copy tracks, but there are no available sources" << LL_ENDL; + } +} + + +void LLFloaterEditExtDayCycle::onLoadTrack() +{ + LLUUID curitemId = mInventoryId; + + if (mCurrentEdit && curitemId.notNull()) + { + curitemId = LLFloaterSettingsPicker::findItemID(mCurrentEdit->getAssetId(), false, false); + } + + doOpenInventoryFloater(LLSettingsType::ST_DAYCYCLE, curitemId); +} + + +void LLFloaterEditExtDayCycle::onClearTrack() +{ + if (!mEditDay) + { + LL_WARNS("ENVDAYEDIT") << "Attempt to clear track while waiting for day(asset) to load." << LL_ENDL; + return; + } + + if (mCurrentTrack > 1) + mEditDay->getCycleTrack(mCurrentTrack).clear(); + else + { + LLSettingsDay::CycleTrack_t &track(mEditDay->getCycleTrack(mCurrentTrack)); + + auto first = track.begin(); + auto last = track.end(); + ++first; + track.erase(first, last); + } + + updateEditEnvironment(); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_EDIT, LLEnvironment::TRANSITION_INSTANT); + LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); + synchronizeTabs(); + updateTabs(); + refresh(); +} + +void LLFloaterEditExtDayCycle::onCommitName(class LLLineEditor* caller, void* user_data) +{ + if (!mEditDay) + { + LL_WARNS("ENVDAYEDIT") << "Attempt to rename day while waiting for day(asset) to load." << LL_ENDL; + return; + } + + mEditDay->setName(caller->getText()); +} + +void LLFloaterEditExtDayCycle::onTrackSelectionCallback(const LLSD& user_data) +{ + U32 track_index = user_data.asInteger(); // 1-5 + selectTrack(track_index); +} + +void LLFloaterEditExtDayCycle::onPlayActionCallback(const LLSD& user_data) +{ + std::string action = user_data.asString(); + + F32 frame = mTimeSlider->getCurSliderValue(); + + if (action == ACTION_PLAY) + { + startPlay(); + } + else if (action == ACTION_PAUSE) + { + stopPlay(); + } + else if (mSliderKeyMap.size() != 0) + { + F32 new_frame = 0; + if (action == ACTION_FORWARD) + { + new_frame = mEditDay->getUpperBoundFrame(mCurrentTrack, frame + (mTimeSlider->getIncrement() / 2)); + } + else if (action == ACTION_BACK) + { + new_frame = mEditDay->getLowerBoundFrame(mCurrentTrack, frame - (mTimeSlider->getIncrement() / 2)); + } + selectFrame(new_frame, 0.0f); + stopPlay(); + } +} + +void LLFloaterEditExtDayCycle::onFrameSliderCallback(const LLSD &data) +{ + std::string curslider = mFramesSlider->getCurSlider(); + + if (!curslider.empty() && mEditDay) + { + F32 sliderpos = mFramesSlider->getCurSliderValue(); + + keymap_t::iterator it = mSliderKeyMap.find(curslider); + if (it != mSliderKeyMap.end()) + { + if (gKeyboard->currentMask(TRUE) == MASK_SHIFT && mShiftCopyEnabled && mCanMod) + { + // don't move the point/frame as long as shift is pressed and user is attempting to copy + // handleKeyUp will do the move if user releases key too early. + if (!(mEditDay->getSettingsNearKeyframe(sliderpos, mCurrentTrack, LLSettingsDay::DEFAULT_FRAME_SLOP_FACTOR)).second) + { + LL_DEBUGS("ENVDAYEDIT") << "Copying frame from " << it->second.mFrame << " to " << sliderpos << LL_ENDL; + LLSettingsBase::ptr_t new_settings; + + // mEditDay still remembers old position, add copy at new position + if (mCurrentTrack == LLSettingsDay::TRACK_WATER) + { + LLSettingsWaterPtr_t water_ptr = std::dynamic_pointer_cast<LLSettingsWater>(it->second.pSettings)->buildClone(); + mEditDay->setWaterAtKeyframe(water_ptr, sliderpos); + new_settings = water_ptr; + } + else + { + LLSettingsSkyPtr_t sky_ptr = std::dynamic_pointer_cast<LLSettingsSky>(it->second.pSettings)->buildClone(); + mEditDay->setSkyAtKeyframe(sky_ptr, sliderpos, mCurrentTrack); + new_settings = sky_ptr; + } + // mSliderKeyMap still remembers old position, for simplicity, just move it to be identical to slider + F32 old_frame = it->second.mFrame; + it->second.mFrame = sliderpos; + // slider already moved old frame, create new one in old place + addSliderFrame(old_frame, new_settings, false /*because we are going to reselect new one*/); + // reselect new frame + mFramesSlider->setCurSlider(it->first); + mShiftCopyEnabled = false; + setDirtyFlag(); + } + } + else + { + // slider rounds values to nearest increments, changes can be substanntial (half increment) + if (abs(mFramesSlider->getNearestIncrement((*it).second.mFrame) - sliderpos) < F_APPROXIMATELY_ZERO) + { + // same value + mFramesSlider->setCurSliderValue((*it).second.mFrame); + } + else if (mEditDay->moveTrackKeyframe(mCurrentTrack, (*it).second.mFrame, sliderpos) && mCanMod) + { + (*it).second.mFrame = sliderpos; + setDirtyFlag(); + } + else + { + // same value, wrong track, no such value, no mod + mFramesSlider->setCurSliderValue((*it).second.mFrame); + } + + mShiftCopyEnabled = false; + } + } + } +} + +void LLFloaterEditExtDayCycle::onFrameSliderDoubleClick(S32 x, S32 y, MASK mask) +{ + stopPlay(); + onAddFrame(); +} + +void LLFloaterEditExtDayCycle::onFrameSliderMouseDown(S32 x, S32 y, MASK mask) +{ + stopPlay(); + F32 sliderpos = mFramesSlider->getSliderValueFromPos(x, y); + + std::string slidername = mFramesSlider->getCurSlider(); + + mShiftCopyEnabled = !slidername.empty() && gKeyboard->currentMask(TRUE) == MASK_SHIFT; + + if (!slidername.empty()) + { + LLRect thumb_rect = mFramesSlider->getSliderThumbRect(slidername); + if ((x >= thumb_rect.mRight) || (x <= thumb_rect.mLeft)) + { + mFramesSlider->resetCurSlider(); + } + } + + mTimeSlider->setCurSliderValue(sliderpos); + + updateTabs(); + LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); +} + +void LLFloaterEditExtDayCycle::onFrameSliderMouseUp(S32 x, S32 y, MASK mask) +{ + // Only happens when clicking on empty space of frameslider, not on specific frame + F32 sliderpos = mFramesSlider->getSliderValueFromPos(x, y); + + mTimeSlider->setCurSliderValue(sliderpos); + selectFrame(sliderpos, LLSettingsDay::DEFAULT_FRAME_SLOP_FACTOR); +} + +void LLFloaterEditExtDayCycle::onTimeSliderCallback() +{ + stopPlay(); + selectFrame(mTimeSlider->getCurSliderValue(), LLSettingsDay::DEFAULT_FRAME_SLOP_FACTOR); +} + +void LLFloaterEditExtDayCycle::cloneTrack(U32 source_index, U32 dest_index) +{ + cloneTrack(mEditDay, source_index, dest_index); +} + +void LLFloaterEditExtDayCycle::cloneTrack(const LLSettingsDay::ptr_t &source_day, U32 source_index, U32 dest_index) +{ + if ((source_index == LLSettingsDay::TRACK_WATER || dest_index == LLSettingsDay::TRACK_WATER) && (source_index != dest_index)) + { // one of the tracks is a water track, the other is not + LLSD args; + + LL_WARNS() << "Can not import water track into sky track or vice versa" << LL_ENDL; + + LLButton* button = getChild<LLButton>(track_tabs[source_index], true); + args["TRACK1"] = button->getCurrentLabel(); + button = getChild<LLButton>(track_tabs[dest_index], true); + args["TRACK2"] = button->getCurrentLabel(); + + LLNotificationsUtil::add("TrackLoadMismatch", args); + return; + } + + // don't use replaceCycleTrack because we will end up with references, but we need to clone + + // hold on to a backup of the + LLSettingsDay::CycleTrack_t backup_track = mEditDay->getCycleTrack(dest_index); + + mEditDay->clearCycleTrack(dest_index); // because source can be empty + LLSettingsDay::CycleTrack_t source_track = source_day->getCycleTrack(source_index); + S32 addcount(0); + for (auto &track_frame : source_track) + { + LLSettingsBase::ptr_t pframe = track_frame.second; + LLSettingsBase::ptr_t pframeclone = pframe->buildDerivedClone(); + if (pframeclone) + { + ++addcount; + mEditDay->setSettingsAtKeyframe(pframeclone, track_frame.first, dest_index); + } + } + + if (!addcount) + { // nothing was actually added. Restore the old track and issue a warning. + mEditDay->replaceCycleTrack(dest_index, backup_track); + + LLSD args; + LLButton* button = getChild<LLButton>(track_tabs[dest_index], true); + args["TRACK"] = button->getCurrentLabel(); + + LLNotificationsUtil::add("TrackLoadFailed", args); + } + setDirtyFlag(); + + updateSlider(); + updateTabs(); + updateButtons(); +} + +void LLFloaterEditExtDayCycle::selectTrack(U32 track_index, bool force ) +{ + if (track_index < LLSettingsDay::TRACK_MAX) + mCurrentTrack = track_index; + + LLButton* button = getChild<LLButton>(track_tabs[mCurrentTrack], true); + if (button->getToggleState() && !force) + { + return; + } + + for (U32 i = 0; i < LLSettingsDay::TRACK_MAX; i++) // use max value + { + getChild<LLButton>(track_tabs[i], true)->setToggleState(i == mCurrentTrack); + } + + bool show_water = (mCurrentTrack == LLSettingsDay::TRACK_WATER); + mSkyTabLayoutContainer->setVisible(!show_water); + mWaterTabLayoutContainer->setVisible(show_water); + + updateSlider(); + updateLabels(); +} + +void LLFloaterEditExtDayCycle::selectFrame(F32 frame, F32 slop_factor) +{ + mFramesSlider->resetCurSlider(); + + keymap_t::iterator iter = mSliderKeyMap.begin(); + keymap_t::iterator end_iter = mSliderKeyMap.end(); + while (iter != end_iter) + { + F32 keyframe = iter->second.mFrame; + F32 frame_dif = fabs(keyframe - frame); + if (frame_dif <= slop_factor) + { + keymap_t::iterator next_iter = std::next(iter); + if ((frame_dif != 0) && (next_iter != end_iter)) + { + if (fabs(next_iter->second.mFrame - frame) < frame_dif) + { + mFramesSlider->setCurSlider(next_iter->first); + frame = next_iter->second.mFrame; + break; + } + } + mFramesSlider->setCurSlider(iter->first); + frame = iter->second.mFrame; + break; + } + iter++; + } + + mTimeSlider->setCurSliderValue(frame); + // block or update tabs according to new selection + updateTabs(); +// LLEnvironment::instance().updateEnvironment(); +} + +void LLFloaterEditExtDayCycle::clearTabs() +{ + // Note: If this doesn't look good, init panels with default settings. It might be better looking + if (mCurrentTrack == LLSettingsDay::TRACK_WATER) + { + const LLSettingsWaterPtr_t p_water = LLSettingsWaterPtr_t(NULL); + updateWaterTabs(p_water); + } + else + { + const LLSettingsSkyPtr_t p_sky = LLSettingsSkyPtr_t(NULL); + updateSkyTabs(p_sky); + } + updateButtons(); + updateTimeAndLabel(); +} + +void LLFloaterEditExtDayCycle::updateTabs() +{ + reblendSettings(); + synchronizeTabs(); + + updateButtons(); + updateTimeAndLabel(); +} + +void LLFloaterEditExtDayCycle::updateWaterTabs(const LLSettingsWaterPtr_t &p_water) +{ + LLView* tab_container = mWaterTabLayoutContainer->getChild<LLView>(TABS_WATER); //can't extract panels directly, since it is in 'tuple' + LLPanelSettingsWaterMainTab* panel = dynamic_cast<LLPanelSettingsWaterMainTab*>(tab_container->findChildView("water_panel")); + if (panel) + { + panel->setWater(p_water); + } +} + +void LLFloaterEditExtDayCycle::updateSkyTabs(const LLSettingsSkyPtr_t &p_sky) +{ + LLTabContainer* tab_container = mSkyTabLayoutContainer->getChild<LLTabContainer>(TABS_SKYS); //can't extract panels directly, since they are in 'tuple' + + LLPanelSettingsSky* panel; + panel = dynamic_cast<LLPanelSettingsSky*>(tab_container->findChildView("atmosphere_panel")); + if (panel) + { + panel->setSky(p_sky); + } + panel = dynamic_cast<LLPanelSettingsSky*>(tab_container->findChildView("clouds_panel")); + if (panel) + { + panel->setSky(p_sky); + } + panel = dynamic_cast<LLPanelSettingsSky*>(tab_container->findChildView("moon_panel")); + if (panel) + { + panel->setSky(p_sky); + } +} + +void LLFloaterEditExtDayCycle::updateLabels() +{ + std::string label_arg = (mCurrentTrack == LLSettingsDay::TRACK_WATER) ? "water_label" : "sky_label"; + + mAddFrameButton->setLabelArg("[FRAME]", getString(label_arg)); + mDeleteFrameButton->setLabelArg("[FRAME]", getString(label_arg)); + mLoadFrame->setLabelArg("[FRAME]", getString(label_arg)); +} + +void LLFloaterEditExtDayCycle::updateButtons() +{ + // This logic appears to work in reverse, the add frame button + // is only enabled when you're on an existing frame and disabled + // in all the interim positions where you'd want to add a frame... + + bool can_manipulate = mEditDay && !mIsPlaying && mCanMod; + bool can_clone(false); + bool can_clear(false); + + if (can_manipulate) + { + if (mCurrentTrack == 0) + { + can_clone = false; + } + else + { + for (S32 track = 1; track < LLSettingsDay::TRACK_MAX; ++track) + { + if (track == mCurrentTrack) + continue; + can_clone |= !mEditDay->getCycleTrack(track).empty(); + } + } + + can_clear = (mCurrentTrack > 1) ? (!mEditDay->getCycleTrack(mCurrentTrack).empty()) : (mEditDay->getCycleTrack(mCurrentTrack).size() > 1); + } + + mCloneTrack->setEnabled(can_clone); + mLoadTrack->setEnabled(can_manipulate); + mClearTrack->setEnabled(can_clear); + mAddFrameButton->setEnabled(can_manipulate && isAddingFrameAllowed()); + mDeleteFrameButton->setEnabled(can_manipulate && isRemovingFrameAllowed()); + mLoadFrame->setEnabled(can_manipulate); + + // update track buttons + bool extended_env = LLEnvironment::instance().isExtendedEnvironmentEnabled(); + for (S32 track = 0; track < LLSettingsDay::TRACK_MAX; ++track) + { + LLButton* button = getChild<LLButton>(track_tabs[track], true); + button->setEnabled(extended_env); + button->setToggleState(track == mCurrentTrack); + } +} + +void LLFloaterEditExtDayCycle::updateSlider() +{ + F32 frame_position = mTimeSlider->getCurSliderValue(); + mFramesSlider->clear(); + mSliderKeyMap.clear(); + + if (!mEditDay) + { + // floater is waiting for asset + return; + } + + LLSettingsDay::CycleTrack_t track = mEditDay->getCycleTrack(mCurrentTrack); + for (auto &track_frame : track) + { + addSliderFrame(track_frame.first, track_frame.second, false); + } + + if (mSliderKeyMap.size() > 0) + { + // update positions + mLastFrameSlider = mFramesSlider->getCurSlider(); + } + else + { + // disable panels + clearTabs(); + mLastFrameSlider.clear(); + } + + selectFrame(frame_position, LLSettingsDay::DEFAULT_FRAME_SLOP_FACTOR); +} + +void LLFloaterEditExtDayCycle::updateTimeAndLabel() +{ + F32 time = mTimeSlider->getCurSliderValue(); + mCurrentTimeLabel->setTextArg("[PRCNT]", llformat("%.0f", time * 100)); + if (mDayLength.value() != 0) + { + LLUIString formatted_label = getString("time_label"); + + LLSettingsDay::Seconds total = (mDayLength * time); + S32Hours hrs = total; + S32Minutes minutes = total - hrs; + + formatted_label.setArg("[HH]", llformat("%d", hrs.value())); + formatted_label.setArg("[MM]", llformat("%d", abs(minutes.value()))); + mCurrentTimeLabel->setTextArg("[DSC]", formatted_label.getString()); + } + else + { + mCurrentTimeLabel->setTextArg("[DSC]", std::string()); + } + + // Update blender here: +} + +void LLFloaterEditExtDayCycle::addSliderFrame(F32 frame, const LLSettingsBase::ptr_t &setting, bool update_ui) +{ + // multi slider distinguishes elements by key/name in string format + // store names to map to be able to recall dependencies + std::string new_slider = mFramesSlider->addSlider(frame); + if (!new_slider.empty()) + { + mSliderKeyMap[new_slider] = FrameData(frame, setting); + + if (update_ui) + { + mLastFrameSlider = new_slider; + mTimeSlider->setCurSliderValue(frame); + updateTabs(); + } + } +} + +void LLFloaterEditExtDayCycle::removeCurrentSliderFrame() +{ + std::string sldr = mFramesSlider->getCurSlider(); + if (sldr.empty()) + { + return; + } + mFramesSlider->deleteCurSlider(); + keymap_t::iterator iter = mSliderKeyMap.find(sldr); + if (iter != mSliderKeyMap.end()) + { + LL_DEBUGS("ENVDAYEDIT") << "Removing frame from " << iter->second.mFrame << LL_ENDL; + LLSettingsBase::Seconds seconds(iter->second.mFrame); + mEditDay->removeTrackKeyframe(mCurrentTrack, seconds); + mSliderKeyMap.erase(iter); + } + + mLastFrameSlider = mFramesSlider->getCurSlider(); + mTimeSlider->setCurSliderValue(mFramesSlider->getCurSliderValue()); + updateTabs(); +} + +void LLFloaterEditExtDayCycle::removeSliderFrame(F32 frame) +{ + keymap_t::iterator it = std::find_if(mSliderKeyMap.begin(), mSliderKeyMap.end(), + [frame](const keymap_t::value_type &value) { return fabs(value.second.mFrame - frame) < LLSettingsDay::DEFAULT_FRAME_SLOP_FACTOR; }); + + if (it != mSliderKeyMap.end()) + { + mFramesSlider->deleteSlider((*it).first); + mSliderKeyMap.erase(it); + } + +} + +//------------------------------------------------------------------------- + +LLFloaterEditExtDayCycle::connection_t LLFloaterEditExtDayCycle::setEditCommitSignal(LLFloaterEditExtDayCycle::edit_commit_signal_t::slot_type cb) +{ + return mCommitSignal.connect(cb); +} + +void LLFloaterEditExtDayCycle::updateEditEnvironment(void) +{ + if (!mEditDay) + return; + S32 skytrack = (mCurrentTrack) ? mCurrentTrack : 1; + mSkyBlender = std::make_shared<LLTrackBlenderLoopingManual>(mScratchSky, mEditDay, skytrack); + mWaterBlender = std::make_shared<LLTrackBlenderLoopingManual>(mScratchWater, mEditDay, LLSettingsDay::TRACK_WATER); + + if (LLEnvironment::instance().isExtendedEnvironmentEnabled()) + { + selectTrack(LLSettingsDay::TRACK_MAX, true); + } + else + { + selectTrack(1, true); + } + + reblendSettings(); + + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_EDIT, mEditSky, mEditWater); + LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); +} + +void LLFloaterEditExtDayCycle::synchronizeTabs() +{ + // This should probably get moved into "updateTabs" + std::string curslider = mFramesSlider->getCurSlider(); + bool canedit(false); + + LLSettingsWater::ptr_t psettingW; + LLTabContainer * tabs = mWaterTabLayoutContainer->getChild<LLTabContainer>(TABS_WATER); + if (mCurrentTrack == LLSettingsDay::TRACK_WATER) + { + if (!mEditDay) + { + canedit = false; + } + else if (!curslider.empty()) + { + canedit = !mIsPlaying; + // either search mEditDay or retrieve from mSliderKeyMap + keymap_t::iterator slider_it = mSliderKeyMap.find(curslider); + if (slider_it != mSliderKeyMap.end()) + { + psettingW = std::static_pointer_cast<LLSettingsWater>(slider_it->second.pSettings); + } + } + mCurrentEdit = psettingW; + if (!psettingW) + { + canedit = false; + psettingW = mScratchWater; + } + + getChild<LLUICtrl>(ICN_LOCK_EDIT)->setVisible(!canedit); + } + else + { + psettingW = mScratchWater; + } + mEditWater = psettingW; + + setTabsData(tabs, psettingW, canedit); + + LLSettingsSky::ptr_t psettingS; + canedit = false; + tabs = mSkyTabLayoutContainer->getChild<LLTabContainer>(TABS_SKYS); + if (mCurrentTrack != LLSettingsDay::TRACK_WATER) + { + if (!mEditDay) + { + canedit = false; + } + else if (!curslider.empty()) + { + canedit = !mIsPlaying; + // either search mEditDay or retrieve from mSliderKeyMap + keymap_t::iterator slider_it = mSliderKeyMap.find(curslider); + if (slider_it != mSliderKeyMap.end()) + { + psettingS = std::static_pointer_cast<LLSettingsSky>(slider_it->second.pSettings); + } + } + mCurrentEdit = psettingS; + if (!psettingS) + { + canedit = false; + psettingS = mScratchSky; + } + + getChild<LLUICtrl>(ICN_LOCK_EDIT)->setVisible(!canedit); + } + else + { + psettingS = mScratchSky; + } + mEditSky = psettingS; + + doCloseInventoryFloater(); + doCloseTrackFloater(); + + setTabsData(tabs, psettingS, canedit); + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_EDIT, mEditSky, mEditWater); + LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); +} + +void LLFloaterEditExtDayCycle::setTabsData(LLTabContainer * tabcontainer, const LLSettingsBase::ptr_t &settings, bool editable) +{ + S32 count = tabcontainer->getTabCount(); + for (S32 idx = 0; idx < count; ++idx) + { + LLSettingsEditPanel *panel = static_cast<LLSettingsEditPanel *>(tabcontainer->getPanelByIndex(idx)); + if (panel) + { + panel->setCanChangeSettings(editable & mCanMod); + panel->setSettings(settings); + } + } +} + + +void LLFloaterEditExtDayCycle::reblendSettings() +{ + F64 position = mTimeSlider->getCurSliderValue(); + + if ((mSkyBlender->getTrack() != mCurrentTrack) && (mCurrentTrack != LLSettingsDay::TRACK_WATER)) + { + mSkyBlender->switchTrack(mCurrentTrack, position); + } + else + mSkyBlender->setPosition(position); + + mWaterBlender->setPosition(position); +} + +void LLFloaterEditExtDayCycle::doApplyCommit(LLSettingsDay::ptr_t day) +{ + if (!mCommitSignal.empty()) + { + mCommitSignal(day); + + closeFloater(); + } +} + +bool LLFloaterEditExtDayCycle::isRemovingFrameAllowed() +{ + if (mFramesSlider->getCurSlider().empty()) return false; + + if (mCurrentTrack <= LLSettingsDay::TRACK_GROUND_LEVEL) + { + return (mSliderKeyMap.size() > 1); + } + else + { + return (mSliderKeyMap.size() > 0); + } +} + +bool LLFloaterEditExtDayCycle::isAddingFrameAllowed() +{ + if (!mFramesSlider->getCurSlider().empty() || !mEditDay) return false; + + LLSettingsBase::Seconds frame(mTimeSlider->getCurSliderValue()); + if ((mEditDay->getSettingsNearKeyframe(frame, mCurrentTrack, LLSettingsDay::DEFAULT_FRAME_SLOP_FACTOR)).second) + { + return false; + } + return mFramesSlider->canAddSliders(); +} + +void LLFloaterEditExtDayCycle::doImportFromDisk() +{ // Load a a legacy Windlight XML from disk. + (new LLFilePickerReplyThread(boost::bind(&LLFloaterEditExtDayCycle::loadSettingFromFile, this, _1), LLFilePicker::FFLOAD_XML, false))->getFile(); +} + +void LLFloaterEditExtDayCycle::loadSettingFromFile(const std::vector<std::string>& filenames) +{ + LLSD messages; + if (filenames.size() < 1) return; + std::string filename = filenames[0]; + LL_DEBUGS("ENVDAYEDIT") << "Selected file: " << filename << LL_ENDL; + LLSettingsDay::ptr_t legacyday = LLEnvironment::createDayCycleFromLegacyPreset(filename, messages); + + if (!legacyday) + { + LLNotificationsUtil::add("WLImportFail", messages); + return; + } + + loadInventoryItem(LLUUID::null); + + mCurrentTrack = 1; + setDirtyFlag(); + setEditDayCycle(legacyday); +} + +void LLFloaterEditExtDayCycle::startPlay() +{ + doCloseInventoryFloater(); + doCloseTrackFloater(); + + mIsPlaying = true; + mFramesSlider->resetCurSlider(); + mPlayTimer.reset(); + mPlayTimer.start(); + gIdleCallbacks.addFunction(onIdlePlay, this); + mPlayStartFrame = mTimeSlider->getCurSliderValue(); + + getChild<LLView>("play_layout", true)->setVisible(FALSE); + getChild<LLView>("pause_layout", true)->setVisible(TRUE); +} + +void LLFloaterEditExtDayCycle::stopPlay() +{ + if (!mIsPlaying) + return; + + mIsPlaying = false; + gIdleCallbacks.deleteFunction(onIdlePlay, this); + mPlayTimer.stop(); + F32 frame = mTimeSlider->getCurSliderValue(); + selectFrame(frame, LLSettingsDay::DEFAULT_FRAME_SLOP_FACTOR); + + getChild<LLView>("play_layout", true)->setVisible(TRUE); + getChild<LLView>("pause_layout", true)->setVisible(FALSE); +} + +//static +void LLFloaterEditExtDayCycle::onIdlePlay(void* user_data) +{ + if (!gDisconnected) + { + LLFloaterEditExtDayCycle* self = (LLFloaterEditExtDayCycle*)user_data; + + F32 prcnt_played = self->mPlayTimer.getElapsedTimeF32() / DAY_CYCLE_PLAY_TIME_SECONDS; + F32 new_frame = fmod(self->mPlayStartFrame + prcnt_played, 1.f); + + self->mTimeSlider->setCurSliderValue(new_frame); // will do the rounding + self->mSkyBlender->setPosition(new_frame); + self->mWaterBlender->setPosition(new_frame); + self->synchronizeTabs(); + self->updateTimeAndLabel(); + self->updateButtons(); + } +} + + +void LLFloaterEditExtDayCycle::clearDirtyFlag() +{ + mIsDirty = false; + + LLTabContainer* tab_container = mSkyTabLayoutContainer->getChild<LLTabContainer>("sky_tabs"); + S32 tab_count = tab_container->getTabCount(); + + for (S32 idx = 0; idx < tab_count; ++idx) + { + LLSettingsEditPanel *panel = static_cast<LLSettingsEditPanel *>(tab_container->getPanelByIndex(idx)); + if (panel) + panel->clearIsDirty(); + } + + tab_container = mWaterTabLayoutContainer->getChild<LLTabContainer>("water_tabs"); + tab_count = tab_container->getTabCount(); + + for (S32 idx = 0; idx < tab_count; ++idx) + { + LLSettingsEditPanel *panel = static_cast<LLSettingsEditPanel *>(tab_container->getPanelByIndex(idx)); + if (panel) + panel->clearIsDirty(); + } + +} + +void LLFloaterEditExtDayCycle::doOpenTrackFloater(const LLSD &args) +{ + LLFloaterTrackPicker *picker = static_cast<LLFloaterTrackPicker *>(mTrackFloater.get()); + + // Show the dialog + if (!picker) + { + picker = new LLFloaterTrackPicker(this); + + mTrackFloater = picker->getHandle(); + + picker->setCommitCallback([this](LLUICtrl *, const LLSD &data){ onPickerCommitTrackId(data.asInteger()); }); + } + + picker->showPicker(args); +} + +void LLFloaterEditExtDayCycle::doCloseTrackFloater(bool quitting) +{ + LLFloater* floaterp = mTrackFloater.get(); + + if (floaterp) + { + floaterp->closeFloater(quitting); + } +} + +LLFloaterSettingsPicker * LLFloaterEditExtDayCycle::getSettingsPicker() +{ + LLFloaterSettingsPicker *picker = static_cast<LLFloaterSettingsPicker *>(mInventoryFloater.get()); + + // Show the dialog + if (!picker) + { + picker = new LLFloaterSettingsPicker(this, + LLUUID::null); + + mInventoryFloater = picker->getHandle(); + + picker->setCommitCallback([this](LLUICtrl *, const LLSD &data){ onPickerCommitSetting(data["ItemId"].asUUID(), data["Track"].asInteger()); }); + } + return picker; +} + +void LLFloaterEditExtDayCycle::onPickerCommitTrackId(U32 track_id) +{ + cloneTrack(track_id, mCurrentTrack); +} + +void LLFloaterEditExtDayCycle::doOpenInventoryFloater(LLSettingsType::type_e type, LLUUID curritem) +{ + LLFloaterSettingsPicker *picker = getSettingsPicker(); + picker->setSettingsFilter(type); + picker->setSettingsItemId(curritem); + if (type == LLSettingsType::ST_DAYCYCLE) + { + picker->setTrackMode((mCurrentTrack == LLSettingsDay::TRACK_WATER) ? LLFloaterSettingsPicker::TRACK_WATER : LLFloaterSettingsPicker::TRACK_SKY); + } + else + { + picker->setTrackMode(LLFloaterSettingsPicker::TRACK_NONE); + } + picker->openFloater(); + picker->setFocus(TRUE); +} + +void LLFloaterEditExtDayCycle::onPickerCommitSetting(LLUUID item_id, S32 track) +{ + LLSettingsBase::TrackPosition frame(mTimeSlider->getCurSliderValue()); + LLViewerInventoryItem *itemp = gInventory.getItem(item_id); + if (itemp) + { + LLSettingsVOBase::getSettingsAsset(itemp->getAssetUUID(), + [this, track, frame, item_id](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) { onAssetLoadedForInsertion(item_id, asset_id, settings, status, track, mCurrentTrack, frame); }); + } +} + +void LLFloaterEditExtDayCycle::onAssetLoadedForInsertion(LLUUID item_id, LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, S32 source_track, S32 dest_track, LLSettingsBase::TrackPosition frame) +{ + std::function<void()> cb = [this, settings, frame, source_track, dest_track]() + { + if (settings->getSettingsType() == "daycycle") + { + // Load full track + LLSettingsDay::ptr_t pday = std::dynamic_pointer_cast<LLSettingsDay>(settings); + if (dest_track == LLSettingsDay::TRACK_WATER) + { + cloneTrack(pday, LLSettingsDay::TRACK_WATER, LLSettingsDay::TRACK_WATER); + } + else + { + cloneTrack(pday, source_track, dest_track); + } + } + else + { + if (!mFramesSlider->canAddSliders()) + { + LL_WARNS("ENVDAYEDIT") << "Attempt to add new frame when slider is full." << LL_ENDL; + return; + } + + // load or replace single frame + LLSettingsDay::CycleTrack_t::value_type nearest = mEditDay->getSettingsNearKeyframe(frame, dest_track, LLSettingsDay::DEFAULT_FRAME_SLOP_FACTOR); + if (nearest.first != LLSettingsDay::INVALID_TRACKPOS) + { // There is already a frame near the target location. Remove it so we can put the new one in its place. + mEditDay->removeTrackKeyframe(dest_track, nearest.first); + removeSliderFrame(nearest.first); + } + + // Don't forget to clone (we might reuse/load it couple times) + if (settings->getSettingsType() == "sky") + { + // Load sky to frame + if (dest_track != LLSettingsDay::TRACK_WATER) + { + mEditDay->setSettingsAtKeyframe(settings->buildDerivedClone(), frame, dest_track); + addSliderFrame(frame, settings, false); + } + else + { + LL_WARNS("ENVDAYEDIT") << "Trying to load day settings as sky" << LL_ENDL; + } + } + else if (settings->getSettingsType() == "water") + { + // Load water to frame + if (dest_track == LLSettingsDay::TRACK_WATER) + { + mEditDay->setSettingsAtKeyframe(settings->buildDerivedClone(), frame, dest_track); + addSliderFrame(frame, settings, false); + } + else + { + LL_WARNS("ENVDAYEDIT") << "Trying to load water settings as sky" << LL_ENDL; + } + } + } + reblendSettings(); + synchronizeTabs(); + }; + + if (!settings || status) + { + LL_WARNS("ENVDAYEDIT") << "Could not load asset " << asset_id << " into frame. status=" << status << LL_ENDL; + return; + } + + if (!mEditDay) + { + // day got reset while we were waiting for response + return; + } + + LLInventoryItem *inv_item = gInventory.getItem(item_id); + + if (inv_item + && (!inv_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()) + || !inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()))) + { + // Need to check if item is already no-transfer, otherwise make it no-transfer + bool no_transfer = false; + if (mInventoryItem) + { + no_transfer = !mInventoryItem->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()); + } + else + { + no_transfer = mEditDay->getFlag(LLSettingsBase::FLAG_NOTRANS); + } + + if (!no_transfer) + { + LLSD args; + + // create and show confirmation textbox + LLNotificationsUtil::add("SettingsMakeNoTrans", args, LLSD(), + [this, cb](const LLSD¬if, const LLSD&resp) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); + if (opt == 0) + { + mCanTrans = false; + mEditDay->setFlag(LLSettingsBase::FLAG_NOTRANS); + cb(); + } + }); + return; + } + } + + cb(); +} diff --git a/indra/newview/llfloatereditextdaycycle.h b/indra/newview/llfloatereditextdaycycle.h new file mode 100644 index 0000000000..9a30fb199f --- /dev/null +++ b/indra/newview/llfloatereditextdaycycle.h @@ -0,0 +1,244 @@ +/** + * @file llfloatereditextdaycycle.h + * @brief Floater to create or edit a day cycle + * + * $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_LLFLOATEREDITEXTDAYCYCLE_H +#define LL_LLFLOATEREDITEXTDAYCYCLE_H + +#include "llfloater.h" +#include "llsettingsdaycycle.h" +#include <boost/signals2.hpp> + +#include "llenvironment.h" +#include "llfloatereditenvironmentbase.h" + +class LLCheckBoxCtrl; +class LLComboBox; +class LLFlyoutComboBtnCtrl; +class LLLineEditor; +class LLMultiSliderCtrl; +class LLTextBox; +class LLTimeCtrl; +class LLTabContainer; + +class LLInventoryItem; +class LLDaySettingCopiedCallback; + +typedef std::shared_ptr<LLSettingsBase> LLSettingsBasePtr_t; + +/** + * Floater for creating or editing a day cycle. + */ +class LLFloaterEditExtDayCycle : public LLFloaterEditEnvironmentBase +{ + LOG_CLASS(LLFloaterEditExtDayCycle); + + friend class LLDaySettingCopiedCallback; + +public: + static const std::string KEY_EDIT_CONTEXT; + static const std::string KEY_DAY_LENGTH; + static const std::string KEY_CANMOD; + + static const std::string VALUE_CONTEXT_INVENTORY; + static const std::string VALUE_CONTEXT_PARCEL; + static const std::string VALUE_CONTEXT_REGION; + + enum edit_context_t { + CONTEXT_UNKNOWN, + CONTEXT_INVENTORY, + CONTEXT_PARCEL, + CONTEXT_REGION + }; + + typedef boost::signals2::signal<void(LLSettingsDay::ptr_t)> edit_commit_signal_t; + typedef boost::signals2::connection connection_t; + + LLFloaterEditExtDayCycle(const LLSD &key); + virtual ~LLFloaterEditExtDayCycle(); + + virtual BOOL postBuild() override; + virtual void onOpen(const LLSD& key) override; + virtual void onClose(bool app_quitting) override; + //virtual void onFocusReceived() override; + //virtual void onFocusLost() override; + virtual void onVisibilityChange(BOOL new_visibility) override; + + connection_t setEditCommitSignal(edit_commit_signal_t::slot_type cb); + + virtual void refresh() override; + + void setEditDayCycle(const LLSettingsDay::ptr_t &pday); + void setEditDefaultDayCycle(); + std::string getEditName() const; + void setEditName(const std::string &name); + LLUUID getEditingAssetId() { return mEditDay ? mEditDay->getAssetId() : LLUUID::null; } + LLUUID getEditingInventoryId() { return mInventoryId; } + + virtual LLSettingsBase::ptr_t getEditSettings() const override { return mEditDay; } + + + BOOL handleKeyUp(KEY key, MASK mask, BOOL called_from_parent) override; + +protected: + virtual void setEditSettingsAndUpdate(const LLSettingsBase::ptr_t &settings) override; + +private: + typedef std::function<void()> on_confirm_fn; + F32 getCurrentFrame() const; + + // flyout response/click + void onButtonApply(LLUICtrl *ctrl, const LLSD &data); + //virtual void onClickCloseBtn(bool app_quitting = false) override; + //void onButtonImport(); + void onButtonLoadFrame(); + void onAddFrame(); + void onRemoveFrame(); + void onCloneTrack(); + void onLoadTrack(); + void onClearTrack(); + void onCommitName(class LLLineEditor* caller, void* user_data); + void onTrackSelectionCallback(const LLSD& user_data); + void onPlayActionCallback(const LLSD& user_data); + // time slider clicked + void onTimeSliderCallback(); + // a frame moved or frame selection changed + void onFrameSliderCallback(const LLSD &); + void onFrameSliderDoubleClick(S32 x, S32 y, MASK mask); + void onFrameSliderMouseDown(S32 x, S32 y, MASK mask); + void onFrameSliderMouseUp(S32 x, S32 y, MASK mask); + + void cloneTrack(U32 source_index, U32 dest_index); + void cloneTrack(const LLSettingsDay::ptr_t &source_day, U32 source_index, U32 dest_index); + void selectTrack(U32 track_index, bool force = false); + void selectFrame(F32 frame, F32 slop_factor); + void clearTabs(); + void updateTabs(); + void updateWaterTabs(const LLSettingsWaterPtr_t &p_water); + void updateSkyTabs(const LLSettingsSkyPtr_t &p_sky); + void updateButtons(); + void updateLabels(); + void updateSlider(); //generate sliders from current track + void updateTimeAndLabel(); + void addSliderFrame(F32 frame, const LLSettingsBase::ptr_t &setting, bool update_ui = true); + void removeCurrentSliderFrame(); + void removeSliderFrame(F32 frame); + + virtual void doImportFromDisk() override; + void loadSettingFromFile(const std::vector<std::string>& filenames); + void doApplyCommit(LLSettingsDay::ptr_t day); + void onInventoryCreated(LLUUID asset_id, LLUUID inventory_id); + void onInventoryCreated(LLUUID asset_id, LLUUID inventory_id, LLSD results); + void onInventoryUpdated(LLUUID asset_id, LLUUID inventory_id, LLSD results); + + + void doOpenTrackFloater(const LLSD &args); + void doCloseTrackFloater(bool quitting = false); + virtual LLFloaterSettingsPicker* getSettingsPicker() override; + void onPickerCommitTrackId(U32 track_id); + + void doOpenInventoryFloater(LLSettingsType::type_e type, LLUUID curritem); + //void doCloseInventoryFloater(bool quitting = false); + void onPickerCommitSetting(LLUUID item_id, S32 track); + void onAssetLoadedForInsertion(LLUUID item_id, + LLUUID asset_id, + LLSettingsBase::ptr_t settings, + S32 status, + S32 source_track, + S32 dest_track, + LLSettingsBase::TrackPosition dest_frame); + + virtual void updateEditEnvironment() override; + void synchronizeTabs(); + void reblendSettings(); + + void setTabsData(LLTabContainer * tabcontainer, const LLSettingsBase::ptr_t &settings, bool editable); + + // play functions + void startPlay(); + void stopPlay(); + static void onIdlePlay(void *); + + bool getIsDirty() const { return mIsDirty; } + void setDirtyFlag() { mIsDirty = true; } + virtual void clearDirtyFlag() override; + + bool isRemovingFrameAllowed(); + bool isAddingFrameAllowed(); + + LLSettingsDay::ptr_t mEditDay; // edited copy + LLSettingsDay::Seconds mDayLength; + U32 mCurrentTrack; + std::string mLastFrameSlider; + bool mShiftCopyEnabled; + + LLUUID mExpectingAssetId; + + LLButton* mAddFrameButton; + LLButton* mDeleteFrameButton; + LLButton* mImportButton; + LLButton* mLoadFrame; + LLButton * mCloneTrack; + LLButton * mLoadTrack; + LLButton * mClearTrack; + LLMultiSliderCtrl* mTimeSlider; + LLMultiSliderCtrl* mFramesSlider; + LLView* mSkyTabLayoutContainer; + LLView* mWaterTabLayoutContainer; + LLTextBox* mCurrentTimeLabel; + LLFlyoutComboBtnCtrl * mFlyoutControl; + + LLHandle<LLFloater> mTrackFloater; + + LLTrackBlenderLoopingManual::ptr_t mSkyBlender; + LLTrackBlenderLoopingManual::ptr_t mWaterBlender; + LLSettingsSky::ptr_t mScratchSky; + LLSettingsWater::ptr_t mScratchWater; + LLSettingsBase::ptr_t mCurrentEdit; + LLSettingsSky::ptr_t mEditSky; + LLSettingsWater::ptr_t mEditWater; + + LLFrameTimer mPlayTimer; + F32 mPlayStartFrame; // an env frame + bool mIsPlaying; + + edit_commit_signal_t mCommitSignal; + + edit_context_t mEditContext; + + // For map of sliders to parameters + class FrameData + { + public: + FrameData() : mFrame(0) {}; + FrameData(F32 frame, LLSettingsBase::ptr_t settings) : mFrame(frame), pSettings(settings) {}; + F32 mFrame; + LLSettingsBase::ptr_t pSettings; + }; + typedef std::map<std::string, FrameData> keymap_t; + keymap_t mSliderKeyMap; //slider's keys vs old_frames&settings, shadows mFramesSlider +}; + +#endif // LL_LLFloaterEditExtDayCycle_H diff --git a/indra/newview/llfloatereditsky.cpp b/indra/newview/llfloatereditsky.cpp index d809211ea7..6bdc5ee823 100644 --- a/indra/newview/llfloatereditsky.cpp +++ b/indra/newview/llfloatereditsky.cpp @@ -28,6 +28,8 @@ #include "llfloatereditsky.h" +#include <boost/make_shared.hpp> + // libs #include "llbutton.h" #include "llcheckboxctrl.h" @@ -38,6 +40,7 @@ #include "llsliderctrl.h" #include "lltabcontainer.h" #include "lltimectrl.h" +#include "lljoystickbutton.h" // newview #include "llagent.h" @@ -45,15 +48,18 @@ #include "llregioninfomodel.h" #include "llviewerregion.h" -static const F32 WL_SUN_AMBIENT_SLIDER_SCALE = 3.0f; -static const F32 WL_BLUE_HORIZON_DENSITY_SCALE = 2.0f; -static const F32 WL_CLOUD_SLIDER_SCALE = 1.0f; +#include "v3colorutil.h" +#include "llenvironment.h" +#include "llenvadapters.h" -static F32 sun_pos_to_time24(F32 sun_pos) +namespace { - return fmodf(sun_pos * 24.0f + 6, 24.0f); + const F32 WL_SUN_AMBIENT_SLIDER_SCALE(3.0f); + const F32 WL_BLUE_HORIZON_DENSITY_SCALE(2.0f); + const F32 WL_CLOUD_SLIDER_SCALE(1.0f); } + static F32 time24_to_sun_pos(F32 time24) { F32 sun_pos = fmodf((time24 - 6) / 24.0f, 1.0f); @@ -61,12 +67,13 @@ static F32 time24_to_sun_pos(F32 time24) return sun_pos; } -LLFloaterEditSky::LLFloaterEditSky(const LLSD &key) -: LLFloater(key) -, mSkyPresetNameEditor(NULL) -, mSkyPresetCombo(NULL) -, mMakeDefaultCheckBox(NULL) -, mSaveButton(NULL) +LLFloaterEditSky::LLFloaterEditSky(const LLSD &key): + LLFloater(key), + mSkyPresetNameEditor(NULL), + mSkyPresetCombo(NULL), + mMakeDefaultCheckBox(NULL), + mSaveButton(NULL), + mSkyAdapter() { } @@ -77,11 +84,14 @@ BOOL LLFloaterEditSky::postBuild() mSkyPresetCombo = getChild<LLComboBox>("sky_preset_combo"); mMakeDefaultCheckBox = getChild<LLCheckBoxCtrl>("make_default_cb"); mSaveButton = getChild<LLButton>("save"); + mSkyAdapter = boost::make_shared<LLSkySettingsAdapter>(); + + LLEnvironment::instance().setSkyListChange(boost::bind(&LLFloaterEditSky::onSkyPresetListChange, this)); initCallbacks(); - // Create the sun position scrubber on the slider. - getChild<LLMultiSliderCtrl>("WLSunPos")->addSlider(12.f); +// // Create the sun position scrubber on the slider. +// getChild<LLMultiSliderCtrl>("WLSunPos")->addSlider(12.f); return TRUE; } @@ -115,7 +125,8 @@ void LLFloaterEditSky::onClose(bool app_quitting) { if (!app_quitting) // there's no point to change environment if we're quitting { - LLEnvManagerNew::instance().usePrefs(); // revert changes made to current environment + LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_EDIT); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL); } } @@ -137,71 +148,47 @@ void LLFloaterEditSky::initCallbacks(void) mSaveButton->setCommitCallback(boost::bind(&LLFloaterEditSky::onBtnSave, this)); getChild<LLButton>("cancel")->setCommitCallback(boost::bind(&LLFloaterEditSky::onBtnCancel, this)); - LLEnvManagerNew::instance().setRegionSettingsChangeCallback(boost::bind(&LLFloaterEditSky::onRegionSettingsChange, this)); - LLWLParamManager::instance().setPresetListChangeCallback(boost::bind(&LLFloaterEditSky::onSkyPresetListChange, this)); - // Connect to region info updates. LLRegionInfoModel::instance().setUpdateCallback(boost::bind(&LLFloaterEditSky::onRegionInfoUpdate, this)); - //------------------------------------------------------------------------- - - LLWLParamManager& param_mgr = LLWLParamManager::instance(); - - // blue horizon - getChild<LLUICtrl>("WLBlueHorizon")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlMoved, this, _1, ¶m_mgr.mBlueHorizon)); - - // haze density, horizon, mult, and altitude - getChild<LLUICtrl>("WLHazeDensity")->setCommitCallback(boost::bind(&LLFloaterEditSky::onFloatControlMoved, this, _1, ¶m_mgr.mHazeDensity)); - getChild<LLUICtrl>("WLHazeHorizon")->setCommitCallback(boost::bind(&LLFloaterEditSky::onFloatControlMoved, this, _1, ¶m_mgr.mHazeHorizon)); - getChild<LLUICtrl>("WLDensityMult")->setCommitCallback(boost::bind(&LLFloaterEditSky::onFloatControlMoved, this, _1, ¶m_mgr.mDensityMult)); - getChild<LLUICtrl>("WLMaxAltitude")->setCommitCallback(boost::bind(&LLFloaterEditSky::onFloatControlMoved, this, _1, ¶m_mgr.mMaxAlt)); - - // blue density - getChild<LLUICtrl>("WLBlueDensity")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlMoved, this, _1, ¶m_mgr.mBlueDensity)); - - // Lighting - // sunlight - getChild<LLUICtrl>("WLSunlight")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlMoved, this, _1, ¶m_mgr.mSunlight)); + getChild<LLUICtrl>("WLSunlight")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlMoved, this, _1, &mSkyAdapter->mSunlight)); // glow - getChild<LLUICtrl>("WLGlowR")->setCommitCallback(boost::bind(&LLFloaterEditSky::onGlowRMoved, this, _1, ¶m_mgr.mGlow)); - getChild<LLUICtrl>("WLGlowB")->setCommitCallback(boost::bind(&LLFloaterEditSky::onGlowBMoved, this, _1, ¶m_mgr.mGlow)); - - // ambient - getChild<LLUICtrl>("WLAmbient")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlMoved, this, _1, ¶m_mgr.mAmbient)); + getChild<LLUICtrl>("WLGlowR")->setCommitCallback(boost::bind(&LLFloaterEditSky::onGlowRMoved, this, _1, &mSkyAdapter->mGlow)); + getChild<LLUICtrl>("WLGlowB")->setCommitCallback(boost::bind(&LLFloaterEditSky::onGlowBMoved, this, _1, &mSkyAdapter->mGlow)); // time of day - getChild<LLUICtrl>("WLSunPos")->setCommitCallback(boost::bind(&LLFloaterEditSky::onSunMoved, this, _1, ¶m_mgr.mLightnorm)); // multi-slider - getChild<LLTimeCtrl>("WLDayTime")->setCommitCallback(boost::bind(&LLFloaterEditSky::onTimeChanged, this)); // time ctrl - getChild<LLUICtrl>("WLEastAngle")->setCommitCallback(boost::bind(&LLFloaterEditSky::onSunMoved, this, _1, ¶m_mgr.mLightnorm)); +// getChild<LLUICtrl>("WLSunPos")->setCommitCallback(boost::bind(&LLFloaterEditSky::onSunMoved, this, _1, &mSkyAdapter->mLightnorm)); // multi-slider +// getChild<LLTimeCtrl>("WLDayTime")->setCommitCallback(boost::bind(&LLFloaterEditSky::onTimeChanged, this)); // time ctrl +// getChild<LLUICtrl>("WLEastAngle")->setCommitCallback(boost::bind(&LLFloaterEditSky::onSunMoved, this, _1, &mSkyAdapter->mLightnorm)); + getChild<LLJoystickQuaternion>("WLSunRotation")->setCommitCallback(boost::bind(&LLFloaterEditSky::onSunRotationChanged, this)); + getChild<LLJoystickQuaternion>("WLMoonRotation")->setCommitCallback(boost::bind(&LLFloaterEditSky::onMoonRotationChanged, this)); // Clouds // Cloud Color - getChild<LLUICtrl>("WLCloudColor")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlMoved, this, _1, ¶m_mgr.mCloudColor)); + getChild<LLUICtrl>("WLCloudColor")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlMoved, this, _1, &mSkyAdapter->mCloudColor)); // Cloud - getChild<LLUICtrl>("WLCloudX")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlRMoved, this, _1, ¶m_mgr.mCloudMain)); - getChild<LLUICtrl>("WLCloudY")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlGMoved, this, _1, ¶m_mgr.mCloudMain)); - getChild<LLUICtrl>("WLCloudDensity")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlBMoved, this, _1, ¶m_mgr.mCloudMain)); + getChild<LLUICtrl>("WLCloudX")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlRMoved, this, _1, &mSkyAdapter->mCloudMain)); + getChild<LLUICtrl>("WLCloudY")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlGMoved, this, _1, &mSkyAdapter->mCloudMain)); + getChild<LLUICtrl>("WLCloudDensity")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlBMoved, this, _1, &mSkyAdapter->mCloudMain)); // Cloud Detail - getChild<LLUICtrl>("WLCloudDetailX")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlRMoved, this, _1, ¶m_mgr.mCloudDetail)); - getChild<LLUICtrl>("WLCloudDetailY")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlGMoved, this, _1, ¶m_mgr.mCloudDetail)); - getChild<LLUICtrl>("WLCloudDetailDensity")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlBMoved, this, _1, ¶m_mgr.mCloudDetail)); + getChild<LLUICtrl>("WLCloudDetailX")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlRMoved, this, _1, &mSkyAdapter->mCloudDetail)); + getChild<LLUICtrl>("WLCloudDetailY")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlGMoved, this, _1, &mSkyAdapter->mCloudDetail)); + getChild<LLUICtrl>("WLCloudDetailDensity")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlBMoved, this, _1, &mSkyAdapter->mCloudDetail)); // Cloud extras - getChild<LLUICtrl>("WLCloudCoverage")->setCommitCallback(boost::bind(&LLFloaterEditSky::onFloatControlMoved, this, _1, ¶m_mgr.mCloudCoverage)); - getChild<LLUICtrl>("WLCloudScale")->setCommitCallback(boost::bind(&LLFloaterEditSky::onFloatControlMoved, this, _1, ¶m_mgr.mCloudScale)); - getChild<LLUICtrl>("WLCloudLockX")->setCommitCallback(boost::bind(&LLFloaterEditSky::onCloudScrollXToggled, this, _1)); - getChild<LLUICtrl>("WLCloudLockY")->setCommitCallback(boost::bind(&LLFloaterEditSky::onCloudScrollYToggled, this, _1)); + getChild<LLUICtrl>("WLCloudCoverage")->setCommitCallback(boost::bind(&LLFloaterEditSky::onFloatControlMoved, this, _1, &mSkyAdapter->mCloudCoverage)); + getChild<LLUICtrl>("WLCloudScale")->setCommitCallback(boost::bind(&LLFloaterEditSky::onFloatControlMoved, this, _1, &mSkyAdapter->mCloudScale)); getChild<LLUICtrl>("WLCloudScrollX")->setCommitCallback(boost::bind(&LLFloaterEditSky::onCloudScrollXMoved, this, _1)); getChild<LLUICtrl>("WLCloudScrollY")->setCommitCallback(boost::bind(&LLFloaterEditSky::onCloudScrollYMoved, this, _1)); - getChild<LLUICtrl>("WLDistanceMult")->setCommitCallback(boost::bind(&LLFloaterEditSky::onFloatControlMoved, this, _1, ¶m_mgr.mDistanceMult)); + // Dome - getChild<LLUICtrl>("WLGamma")->setCommitCallback(boost::bind(&LLFloaterEditSky::onFloatControlMoved, this, _1, ¶m_mgr.mWLGamma)); + getChild<LLUICtrl>("WLGamma")->setCommitCallback(boost::bind(&LLFloaterEditSky::onFloatControlMoved, this, _1, &mSkyAdapter->mWLGamma)); getChild<LLUICtrl>("WLStarAlpha")->setCommitCallback(boost::bind(&LLFloaterEditSky::onStarAlphaMoved, this, _1)); } @@ -209,320 +196,229 @@ void LLFloaterEditSky::initCallbacks(void) void LLFloaterEditSky::syncControls() { - bool err; - - LLWLParamManager * param_mgr = LLWLParamManager::getInstance(); - - LLWLParamSet& cur_params = param_mgr->mCurParams; + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + mEditSettings = psky; - // blue horizon - param_mgr->mBlueHorizon = cur_params.getVector(param_mgr->mBlueHorizon.mName, err); - setColorSwatch("WLBlueHorizon", param_mgr->mBlueHorizon, WL_BLUE_HORIZON_DENSITY_SCALE); + std::string name = psky->getName(); - // haze density, horizon, mult, and altitude - param_mgr->mHazeDensity = cur_params.getFloat(param_mgr->mHazeDensity.mName, err); - childSetValue("WLHazeDensity", (F32) param_mgr->mHazeDensity); - param_mgr->mHazeHorizon = cur_params.getFloat(param_mgr->mHazeHorizon.mName, err); - childSetValue("WLHazeHorizon", (F32) param_mgr->mHazeHorizon); - param_mgr->mDensityMult = cur_params.getFloat(param_mgr->mDensityMult.mName, err); - childSetValue("WLDensityMult", ((F32) param_mgr->mDensityMult) * param_mgr->mDensityMult.mult); - param_mgr->mMaxAlt = cur_params.getFloat(param_mgr->mMaxAlt.mName, err); - childSetValue("WLMaxAltitude", (F32) param_mgr->mMaxAlt); - - // blue density - param_mgr->mBlueDensity = cur_params.getVector(param_mgr->mBlueDensity.mName, err); - setColorSwatch("WLBlueDensity", param_mgr->mBlueDensity, WL_BLUE_HORIZON_DENSITY_SCALE); + mSkyPresetNameEditor->setText(name); + mSkyPresetCombo->setValue(name); // Lighting // sunlight - param_mgr->mSunlight = cur_params.getVector(param_mgr->mSunlight.mName, err); - setColorSwatch("WLSunlight", param_mgr->mSunlight, WL_SUN_AMBIENT_SLIDER_SCALE); + mSkyAdapter->mSunlight.setColor3( psky->getSunlightColor() ); + setColorSwatch("WLSunlight", mSkyAdapter->mSunlight, WL_SUN_AMBIENT_SLIDER_SCALE); // glow - param_mgr->mGlow = cur_params.getVector(param_mgr->mGlow.mName, err); - childSetValue("WLGlowR", 2 - param_mgr->mGlow.r / 20.0f); - childSetValue("WLGlowB", -param_mgr->mGlow.b / 5.0f); - - // ambient - param_mgr->mAmbient = cur_params.getVector(param_mgr->mAmbient.mName, err); - setColorSwatch("WLAmbient", param_mgr->mAmbient, WL_SUN_AMBIENT_SLIDER_SCALE); - - F32 time24 = sun_pos_to_time24(param_mgr->mCurParams.getFloat("sun_angle",err) / F_TWO_PI); - getChild<LLMultiSliderCtrl>("WLSunPos")->setCurSliderValue(time24, TRUE); - getChild<LLTimeCtrl>("WLDayTime")->setTime24(time24); - childSetValue("WLEastAngle", param_mgr->mCurParams.getFloat("east_angle",err) / F_TWO_PI); + mSkyAdapter->mGlow.setColor3( psky->getGlow() ); + childSetValue("WLGlowR", 2 - mSkyAdapter->mGlow.getRed() / 20.0f); + childSetValue("WLGlowB", -mSkyAdapter->mGlow.getBlue() / 5.0f); + +// LLSettingsSky::azimalt_t azal = psky->getSunRotationAzAl(); +// +// F32 time24 = sun_pos_to_time24(azal.second / F_TWO_PI); +// getChild<LLMultiSliderCtrl>("WLSunPos")->setCurSliderValue(time24, TRUE); +// getChild<LLTimeCtrl>("WLDayTime")->setTime24(time24); +// childSetValue("WLEastAngle", azal.first / F_TWO_PI); + getChild<LLJoystickQuaternion>("WLSunRotation")->setRotation(psky->getSunRotation()); + getChild<LLJoystickQuaternion>("WLMoonRotation")->setRotation(psky->getMoonRotation()); // Clouds // Cloud Color - param_mgr->mCloudColor = cur_params.getVector(param_mgr->mCloudColor.mName, err); - setColorSwatch("WLCloudColor", param_mgr->mCloudColor, WL_CLOUD_SLIDER_SCALE); + mSkyAdapter->mCloudColor.setColor3( psky->getCloudColor() ); + setColorSwatch("WLCloudColor", mSkyAdapter->mCloudColor, WL_CLOUD_SLIDER_SCALE); // Cloud - param_mgr->mCloudMain = cur_params.getVector(param_mgr->mCloudMain.mName, err); - childSetValue("WLCloudX", param_mgr->mCloudMain.r); - childSetValue("WLCloudY", param_mgr->mCloudMain.g); - childSetValue("WLCloudDensity", param_mgr->mCloudMain.b); + mSkyAdapter->mCloudMain.setColor3( psky->getCloudPosDensity1() ); + childSetValue("WLCloudX", mSkyAdapter->mCloudMain.getRed()); + childSetValue("WLCloudY", mSkyAdapter->mCloudMain.getGreen()); + childSetValue("WLCloudDensity", mSkyAdapter->mCloudMain.getBlue()); // Cloud Detail - param_mgr->mCloudDetail = cur_params.getVector(param_mgr->mCloudDetail.mName, err); - childSetValue("WLCloudDetailX", param_mgr->mCloudDetail.r); - childSetValue("WLCloudDetailY", param_mgr->mCloudDetail.g); - childSetValue("WLCloudDetailDensity", param_mgr->mCloudDetail.b); + mSkyAdapter->mCloudDetail.setColor3( psky->getCloudPosDensity2() ); + childSetValue("WLCloudDetailX", mSkyAdapter->mCloudDetail.getRed()); + childSetValue("WLCloudDetailY", mSkyAdapter->mCloudDetail.getGreen()); + childSetValue("WLCloudDetailDensity", mSkyAdapter->mCloudDetail.getBlue()); // Cloud extras - param_mgr->mCloudCoverage = cur_params.getFloat(param_mgr->mCloudCoverage.mName, err); - param_mgr->mCloudScale = cur_params.getFloat(param_mgr->mCloudScale.mName, err); - childSetValue("WLCloudCoverage", (F32) param_mgr->mCloudCoverage); - childSetValue("WLCloudScale", (F32) param_mgr->mCloudScale); + mSkyAdapter->mCloudCoverage = psky->getCloudShadow(); + mSkyAdapter->mCloudScale = psky->getCloudScale(); + childSetValue("WLCloudCoverage", (F32) mSkyAdapter->mCloudCoverage); + childSetValue("WLCloudScale", (F32) mSkyAdapter->mCloudScale); // cloud scrolling - bool lockX = !param_mgr->mCurParams.getEnableCloudScrollX(); - bool lockY = !param_mgr->mCurParams.getEnableCloudScrollY(); - childSetValue("WLCloudLockX", lockX); - childSetValue("WLCloudLockY", lockY); + LLVector2 scroll_rate = psky->getCloudScrollRate(); + + // LAPRAS: These should go away... + childDisable("WLCloudLockX"); + childDisable("WLCloudLockY"); // disable if locked, enable if not - if (lockX) - { - childDisable("WLCloudScrollX"); - } - else - { - childEnable("WLCloudScrollX"); - } - if (lockY) - { - childDisable("WLCloudScrollY"); - } - else - { - childEnable("WLCloudScrollY"); - } + childEnable("WLCloudScrollX"); + childEnable("WLCloudScrollY"); // *HACK cloud scrolling is off my an additive of 10 - childSetValue("WLCloudScrollX", param_mgr->mCurParams.getCloudScrollX() - 10.0f); - childSetValue("WLCloudScrollY", param_mgr->mCurParams.getCloudScrollY() - 10.0f); - - param_mgr->mDistanceMult = cur_params.getFloat(param_mgr->mDistanceMult.mName, err); - childSetValue("WLDistanceMult", (F32) param_mgr->mDistanceMult); + childSetValue("WLCloudScrollX", scroll_rate[0] - 10.0f); + childSetValue("WLCloudScrollY", scroll_rate[1] - 10.0f); // Tweak extras - param_mgr->mWLGamma = cur_params.getFloat(param_mgr->mWLGamma.mName, err); - childSetValue("WLGamma", (F32) param_mgr->mWLGamma); + mSkyAdapter->mWLGamma = psky->getGamma(); + childSetValue("WLGamma", (F32) mSkyAdapter->mWLGamma); - childSetValue("WLStarAlpha", param_mgr->mCurParams.getStarBrightness()); + childSetValue("WLStarAlpha", psky->getStarBrightness()); } void LLFloaterEditSky::setColorSwatch(const std::string& name, const WLColorControl& from_ctrl, F32 k) { // Set the value, dividing it by <k> first. - LLVector4 color_vec = from_ctrl; - getChild<LLColorSwatchCtrl>(name)->set(LLColor4(color_vec / k)); + LLColor4 color = from_ctrl.getColor4(); + getChild<LLColorSwatchCtrl>(name)->set(color / k); } // color control callbacks void LLFloaterEditSky::onColorControlMoved(LLUICtrl* ctrl, WLColorControl* color_ctrl) { - LLWLParamManager::getInstance()->mAnimator.deactivate(); - LLColorSwatchCtrl* swatch = static_cast<LLColorSwatchCtrl*>(ctrl); - LLVector4 color_vec(swatch->get().mV); - - // Set intensity to maximum of the RGB values. - color_vec.mV[3] = llmax(color_vec.mV[0], llmax(color_vec.mV[1], color_vec.mV[2])); + LLColor4 color_vec(swatch->get().mV); // Multiply RGB values by the appropriate factor. F32 k = WL_CLOUD_SLIDER_SCALE; - if (color_ctrl->isSunOrAmbientColor) + if (color_ctrl->getIsSunOrAmbientColor()) { k = WL_SUN_AMBIENT_SLIDER_SCALE; } - if (color_ctrl->isBlueHorizonOrDensity) + else if (color_ctrl->getIsBlueHorizonOrDensity()) { k = WL_BLUE_HORIZON_DENSITY_SCALE; } color_vec *= k; // intensity isn't affected by the multiplication + // Set intensity to maximum of the RGB values. + color_vec.mV[3] = color_max(color_vec); + // Apply the new RGBI value. - *color_ctrl = color_vec; - color_ctrl->update(LLWLParamManager::getInstance()->mCurParams); - LLWLParamManager::getInstance()->propagateParameters(); + color_ctrl->setColor4(color_vec); + color_ctrl->update(mEditSettings); } void LLFloaterEditSky::onColorControlRMoved(LLUICtrl* ctrl, void* userdata) { - LLWLParamManager::getInstance()->mAnimator.deactivate(); - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); WLColorControl* color_ctrl = static_cast<WLColorControl *>(userdata); - color_ctrl->r = sldr_ctrl->getValueF32(); - if (color_ctrl->isSunOrAmbientColor) - { - color_ctrl->r *= WL_SUN_AMBIENT_SLIDER_SCALE; - } - if (color_ctrl->isBlueHorizonOrDensity) + F32 red_value = sldr_ctrl->getValueF32(); + F32 k = 1.0f; + + if (color_ctrl->getIsSunOrAmbientColor()) { - color_ctrl->r *= WL_BLUE_HORIZON_DENSITY_SCALE; + k = WL_SUN_AMBIENT_SLIDER_SCALE; } - - // move i if it's the max - if (color_ctrl->r >= color_ctrl->g && color_ctrl->r >= color_ctrl->b && color_ctrl->hasSliderName) + if (color_ctrl->getIsBlueHorizonOrDensity()) { - color_ctrl->i = color_ctrl->r; - 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); - } + k = WL_BLUE_HORIZON_DENSITY_SCALE; } + color_ctrl->setRed(red_value * k); - color_ctrl->update(LLWLParamManager::getInstance()->mCurParams); - - LLWLParamManager::getInstance()->propagateParameters(); + adjustIntensity(color_ctrl, red_value, k); + color_ctrl->update(mEditSettings); } void LLFloaterEditSky::onColorControlGMoved(LLUICtrl* ctrl, void* userdata) { - LLWLParamManager::getInstance()->mAnimator.deactivate(); + LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); + WLColorControl* color_ctrl = static_cast<WLColorControl *>(userdata); - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - WLColorControl* color_ctrl = static_cast<WLColorControl *>(userdata); + F32 green_value = sldr_ctrl->getValueF32(); + F32 k = 1.0f; - color_ctrl->g = sldr_ctrl->getValueF32(); - if (color_ctrl->isSunOrAmbientColor) - { - color_ctrl->g *= WL_SUN_AMBIENT_SLIDER_SCALE; - } - if (color_ctrl->isBlueHorizonOrDensity) - { - color_ctrl->g *= WL_BLUE_HORIZON_DENSITY_SCALE; - } + if (color_ctrl->getIsSunOrAmbientColor()) + { + k = WL_SUN_AMBIENT_SLIDER_SCALE; + } + if (color_ctrl->getIsBlueHorizonOrDensity()) + { + k = WL_BLUE_HORIZON_DENSITY_SCALE; + } + color_ctrl->setGreen(green_value * k); - // move i if it's the max - if (color_ctrl->g >= color_ctrl->r && color_ctrl->g >= color_ctrl->b && color_ctrl->hasSliderName) - { - color_ctrl->i = color_ctrl->g; - std::string name = color_ctrl->mSliderName; - name.append("I"); - - if (color_ctrl->isSunOrAmbientColor) - { - childSetValue(name, color_ctrl->g / WL_SUN_AMBIENT_SLIDER_SCALE); - } - else if (color_ctrl->isBlueHorizonOrDensity) - { - childSetValue(name, color_ctrl->g / WL_BLUE_HORIZON_DENSITY_SCALE); - } - else - { - childSetValue(name, color_ctrl->g); - } - } - - color_ctrl->update(LLWLParamManager::getInstance()->mCurParams); - - LLWLParamManager::getInstance()->propagateParameters(); + adjustIntensity(color_ctrl, green_value, k); + color_ctrl->update(mEditSettings); } void LLFloaterEditSky::onColorControlBMoved(LLUICtrl* ctrl, void* userdata) { - LLWLParamManager::getInstance()->mAnimator.deactivate(); + LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); + WLColorControl* color_ctrl = static_cast<WLColorControl *>(userdata); - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - WLColorControl* color_ctrl = static_cast<WLColorControl *>(userdata); + F32 blue_value = sldr_ctrl->getValueF32(); + F32 k = 1.0f; - color_ctrl->b = sldr_ctrl->getValueF32(); - if (color_ctrl->isSunOrAmbientColor) - { - color_ctrl->b *= WL_SUN_AMBIENT_SLIDER_SCALE; - } - if (color_ctrl->isBlueHorizonOrDensity) - { - color_ctrl->b *= WL_BLUE_HORIZON_DENSITY_SCALE; - } + if (color_ctrl->getIsSunOrAmbientColor()) + { + k = WL_SUN_AMBIENT_SLIDER_SCALE; + } + if (color_ctrl->getIsBlueHorizonOrDensity()) + { + k = WL_BLUE_HORIZON_DENSITY_SCALE; + } + color_ctrl->setBlue(blue_value * k); - // move i if it's the max - if (color_ctrl->b >= color_ctrl->r && color_ctrl->b >= color_ctrl->g && color_ctrl->hasSliderName) - { - color_ctrl->i = color_ctrl->b; - std::string name = color_ctrl->mSliderName; - name.append("I"); - - if (color_ctrl->isSunOrAmbientColor) - { - childSetValue(name, color_ctrl->b / WL_SUN_AMBIENT_SLIDER_SCALE); - } - else if (color_ctrl->isBlueHorizonOrDensity) - { - childSetValue(name, color_ctrl->b / WL_BLUE_HORIZON_DENSITY_SCALE); - } - else - { - childSetValue(name, color_ctrl->b); - } - } + adjustIntensity(color_ctrl, blue_value, k); + color_ctrl->update(mEditSettings); +} - color_ctrl->update(LLWLParamManager::getInstance()->mCurParams); +void LLFloaterEditSky::adjustIntensity(WLColorControl *ctrl, F32 val, F32 scale) +{ + if (ctrl->getHasSliderName()) + { + LLColor4 color = ctrl->getColor4(); + F32 i = color_max(color) / scale; + ctrl->setIntensity(i); + std::string name = ctrl->getSliderName(); + name.append("I"); - LLWLParamManager::getInstance()->propagateParameters(); + childSetValue(name, i); + } } + /// GLOW SPECIFIC CODE void LLFloaterEditSky::onGlowRMoved(LLUICtrl* ctrl, void* userdata) { - LLWLParamManager::getInstance()->mAnimator.deactivate(); LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); WLColorControl* color_ctrl = static_cast<WLColorControl *>(userdata); // scaled by 20 - color_ctrl->r = (2 - sldr_ctrl->getValueF32()) * 20; + color_ctrl->setRed((2 - sldr_ctrl->getValueF32()) * 20); - color_ctrl->update(LLWLParamManager::getInstance()->mCurParams); - LLWLParamManager::getInstance()->propagateParameters(); + color_ctrl->update(mEditSettings); } /// \NOTE that we want NEGATIVE (-) B void LLFloaterEditSky::onGlowBMoved(LLUICtrl* ctrl, void* userdata) { - LLWLParamManager::getInstance()->mAnimator.deactivate(); - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); WLColorControl* color_ctrl = static_cast<WLColorControl *>(userdata); /// \NOTE that we want NEGATIVE (-) B and NOT by 20 as 20 is too big - color_ctrl->b = -sldr_ctrl->getValueF32() * 5; + color_ctrl->setBlue(-sldr_ctrl->getValueF32() * 5); - color_ctrl->update(LLWLParamManager::getInstance()->mCurParams); - LLWLParamManager::getInstance()->propagateParameters(); + color_ctrl->update(mEditSettings); } void LLFloaterEditSky::onFloatControlMoved(LLUICtrl* ctrl, void* userdata) { - LLWLParamManager::getInstance()->mAnimator.deactivate(); - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); WLFloatControl * floatControl = static_cast<WLFloatControl *>(userdata); - floatControl->x = sldr_ctrl->getValueF32() / floatControl->mult; + floatControl->setValue(sldr_ctrl->getValueF32() / floatControl->getMult()); - floatControl->update(LLWLParamManager::getInstance()->mCurParams); - LLWLParamManager::getInstance()->propagateParameters(); + floatControl->update(mEditSettings); } @@ -531,8 +427,6 @@ void LLFloaterEditSky::onFloatControlMoved(LLUICtrl* ctrl, void* userdata) // time of day void LLFloaterEditSky::onSunMoved(LLUICtrl* ctrl, void* userdata) { - LLWLParamManager::getInstance()->mAnimator.deactivate(); - LLMultiSliderCtrl* sun_msldr = getChild<LLMultiSliderCtrl>("WLSunPos"); LLSliderCtrl* east_sldr = getChild<LLSliderCtrl>("WLEastAngle"); LLTimeCtrl* time_ctrl = getChild<LLTimeCtrl>("WLDayTime"); @@ -542,99 +436,60 @@ void LLFloaterEditSky::onSunMoved(LLUICtrl* ctrl, void* userdata) time_ctrl->setTime24(time24); // sync the time ctrl with the new sun position // get the two angles - LLWLParamManager * param_mgr = LLWLParamManager::getInstance(); - - param_mgr->mCurParams.setSunAngle(F_TWO_PI * time24_to_sun_pos(time24)); - param_mgr->mCurParams.setEastAngle(F_TWO_PI * east_sldr->getValueF32()); + F32 azimuth = F_TWO_PI * east_sldr->getValueF32(); + F32 altitude = F_TWO_PI * time24_to_sun_pos(time24); + mEditSettings->setSunRotation(azimuth, altitude); + mEditSettings->setMoonRotation(azimuth + F_PI, -altitude); - // set the sun vector - color_ctrl->r = -sin(param_mgr->mCurParams.getEastAngle()) * - cos(param_mgr->mCurParams.getSunAngle()); - color_ctrl->g = sin(param_mgr->mCurParams.getSunAngle()); - color_ctrl->b = cos(param_mgr->mCurParams.getEastAngle()) * - cos(param_mgr->mCurParams.getSunAngle()); - color_ctrl->i = 1.f; + LLVector4 sunnorm( mEditSettings->getSunDirection(), 1.f ); - color_ctrl->update(param_mgr->mCurParams); - param_mgr->propagateParameters(); + color_ctrl->update(mEditSettings); } void LLFloaterEditSky::onTimeChanged() { F32 time24 = getChild<LLTimeCtrl>("WLDayTime")->getTime24(); getChild<LLMultiSliderCtrl>("WLSunPos")->setCurSliderValue(time24, TRUE); - onSunMoved(getChild<LLUICtrl>("WLSunPos"), &LLWLParamManager::instance().mLightnorm); + onSunMoved(getChild<LLUICtrl>("WLSunPos"), &(mSkyAdapter->mLightnorm)); } -void LLFloaterEditSky::onStarAlphaMoved(LLUICtrl* ctrl) +void LLFloaterEditSky::onSunRotationChanged() { - LLWLParamManager::getInstance()->mAnimator.deactivate(); - - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); + LLJoystickQuaternion* sun_spinner = getChild<LLJoystickQuaternion>("WLSunRotation"); + LLQuaternion sunrot(sun_spinner->getRotation()); - LLWLParamManager::getInstance()->mCurParams.setStarBrightness(sldr_ctrl->getValueF32()); + mEditSettings->setSunRotation(sunrot); } -// Clouds -void LLFloaterEditSky::onCloudScrollXMoved(LLUICtrl* ctrl) +void LLFloaterEditSky::onMoonRotationChanged() { - LLWLParamManager::getInstance()->mAnimator.deactivate(); + LLJoystickQuaternion* moon_spinner = getChild<LLJoystickQuaternion>("WLMoonRotation"); + LLQuaternion moonrot(moon_spinner->getRotation()); - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - // *HACK all cloud scrolling is off by an additive of 10. - LLWLParamManager::getInstance()->mCurParams.setCloudScrollX(sldr_ctrl->getValueF32() + 10.0f); + mEditSettings->setMoonRotation(moonrot); } -void LLFloaterEditSky::onCloudScrollYMoved(LLUICtrl* ctrl) +void LLFloaterEditSky::onStarAlphaMoved(LLUICtrl* ctrl) { - LLWLParamManager::getInstance()->mAnimator.deactivate(); - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - // *HACK all cloud scrolling is off by an additive of 10. - LLWLParamManager::getInstance()->mCurParams.setCloudScrollY(sldr_ctrl->getValueF32() + 10.0f); + mEditSettings->setStarBrightness(sldr_ctrl->getValueF32()); } -void LLFloaterEditSky::onCloudScrollXToggled(LLUICtrl* ctrl) +// Clouds +void LLFloaterEditSky::onCloudScrollXMoved(LLUICtrl* ctrl) { - LLWLParamManager::getInstance()->mAnimator.deactivate(); - - LLCheckBoxCtrl* cb_ctrl = static_cast<LLCheckBoxCtrl*>(ctrl); - - bool lock = cb_ctrl->get(); - LLWLParamManager::getInstance()->mCurParams.setEnableCloudScrollX(!lock); - - LLSliderCtrl* sldr = getChild<LLSliderCtrl>("WLCloudScrollX"); - - if (cb_ctrl->get()) - { - sldr->setEnabled(false); - } - else - { - sldr->setEnabled(true); - } - + LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); + // *HACK all cloud scrolling is off by an additive of 10. + mEditSettings->setCloudScrollRateX(sldr_ctrl->getValueF32() + 10.0f); } -void LLFloaterEditSky::onCloudScrollYToggled(LLUICtrl* ctrl) +void LLFloaterEditSky::onCloudScrollYMoved(LLUICtrl* ctrl) { - LLWLParamManager::getInstance()->mAnimator.deactivate(); - - LLCheckBoxCtrl* cb_ctrl = static_cast<LLCheckBoxCtrl*>(ctrl); - bool lock = cb_ctrl->get(); - LLWLParamManager::getInstance()->mCurParams.setEnableCloudScrollY(!lock); - - LLSliderCtrl* sldr = getChild<LLSliderCtrl>("WLCloudScrollY"); + LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - if (cb_ctrl->get()) - { - sldr->setEnabled(false); - } - else - { - sldr->setEnabled(true); - } + // *HACK all cloud scrolling is off by an additive of 10. + mEditSettings->setCloudScrollRateY(sldr_ctrl->getValueF32() + 10.0f); } //================================================================================================= @@ -664,38 +519,12 @@ void LLFloaterEditSky::refreshSkyPresetsList() { mSkyPresetCombo->removeall(); - LLWLParamManager::preset_name_list_t region_presets, user_presets, sys_presets; - LLWLParamManager::instance().getPresetNames(region_presets, user_presets, sys_presets); + LLEnvironment::list_name_id_t list = LLEnvironment::instance().getSkyList(); -#if 0 // Disable editing region skies until the workflow is clear enough. - // 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) - { - std::string item_title = *it + " (" + region_name + ")"; - mSkyPresetCombo->add(item_title, LLWLParamKey(*it, LLEnvKey::SCOPE_REGION).toLLSD()); - } - if (region_presets.size() > 0) - { - mSkyPresetCombo->addSeparator(); - } -#endif - - // Add user presets. - for (LLWLParamManager::preset_name_list_t::const_iterator it = user_presets.begin(); it != user_presets.end(); ++it) - { - mSkyPresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toLLSD()); - } - if (user_presets.size() > 0) - { - mSkyPresetCombo->addSeparator(); - } - - // Add system presets. - for (LLWLParamManager::preset_name_list_t::const_iterator it = sys_presets.begin(); it != sys_presets.end(); ++it) - { - mSkyPresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toLLSD()); - } + for (LLEnvironment::list_name_id_t::iterator it = list.begin(); it != list.end(); ++it) + { + mSkyPresetCombo->add((*it).first, LLSDArray((*it).first)((*it).second)); + } mSkyPresetCombo->setLabel(getString("combo_label")); } @@ -718,6 +547,7 @@ void LLFloaterEditSky::enableEditing(bool enable) void LLFloaterEditSky::saveRegionSky() { +#if 0 LLWLParamKey key(getSelectedSkyPreset()); llassert(key.scope == LLEnvKey::SCOPE_REGION); @@ -728,61 +558,55 @@ void LLFloaterEditSky::saveRegionSky() // *TODO: save to cached region settings. LL_WARNS("Windlight") << "Saving region sky is not fully implemented yet" << LL_ENDL; +#endif } -LLWLParamKey LLFloaterEditSky::getSelectedSkyPreset() +std::string LLFloaterEditSky::getSelectedPresetName() const { - LLWLParamKey key; - - if (mSkyPresetNameEditor->getVisible()) - { - key.name = mSkyPresetNameEditor->getText(); - key.scope = LLEnvKey::SCOPE_LOCAL; - } - else - { - LLSD combo_val = mSkyPresetCombo->getValue(); - - if (!combo_val.isArray()) // manually typed text - { - key.name = combo_val.asString(); - key.scope = LLEnvKey::SCOPE_LOCAL; - } - else - { - key.fromLLSD(combo_val); - } - } + std::string name; + if (mSkyPresetNameEditor->getVisible()) + { + name = mSkyPresetNameEditor->getText(); + } + else + { + LLSD combo_val = mSkyPresetCombo->getValue(); + name = combo_val[0].asString(); + } - return key; + return name; } void LLFloaterEditSky::onSkyPresetNameEdited() { - // Disable saving a sky preset having empty name. - LLWLParamKey key = getSelectedSkyPreset(); - mSaveButton->setEnabled(!key.name.empty()); + std::string name = mSkyPresetNameEditor->getText(); + LLSettingsWater::ptr_t psky = LLEnvironment::instance().getCurrentWater(); + + psky->setName(name); } void LLFloaterEditSky::onSkyPresetSelected() { - LLWLParamKey key = getSelectedSkyPreset(); - LLWLParamSet sky_params; + std::string name; - if (!LLWLParamManager::instance().getParamSet(key, sky_params)) - { - // Manually entered string? - LL_WARNS("Windlight") << "No sky preset named " << key.toString() << LL_ENDL; - return; - } + name = getSelectedPresetName(); - LLEnvManagerNew::instance().useSkyParams(sky_params.getAll()); - //syncControls(); + LLSettingsSky::ptr_t psky = LLEnvironment::instance().findSkyByName(name); - bool can_edit = (key.scope == LLEnvKey::SCOPE_LOCAL || LLEnvManagerNew::canEditRegionSettings()); - enableEditing(can_edit); + if (!psky) + { + LL_WARNS("WATEREDIT") << "Could not find water preset" << LL_ENDL; + enableEditing(false); + return; + } + + psky = psky->buildClone(); + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_EDIT, psky); + mEditSettings = psky; + + syncControls(); + enableEditing(true); - mMakeDefaultCheckBox->setEnabled(key.scope == LLEnvKey::SCOPE_LOCAL); } bool LLFloaterEditSky::onSaveAnswer(const LLSD& notification, const LLSD& response) @@ -800,69 +624,29 @@ bool LLFloaterEditSky::onSaveAnswer(const LLSD& notification, const LLSD& respon void LLFloaterEditSky::onSaveConfirmed() { - // Save current params to the selected preset. - LLWLParamKey key(getSelectedSkyPreset()); + // Save currently displayed water params to the selected preset. + std::string name = mEditSettings->getName(); - LL_DEBUGS("Windlight") << "Saving sky preset " << key.name << LL_ENDL; - LLWLParamManager& wl_mgr = LLWLParamManager::instance(); - if (wl_mgr.hasParamSet(key)) - { - wl_mgr.setParamSet(key, wl_mgr.mCurParams); - } - else - { - wl_mgr.addParamSet(key, wl_mgr.mCurParams); - } + LL_DEBUGS("Windlight") << "Saving sky preset " << name << LL_ENDL; - wl_mgr.savePreset(key); + LLEnvironment::instance().addSky(mEditSettings); - // Change preference if requested. - if (mMakeDefaultCheckBox->getValue()) - { - LL_DEBUGS("Windlight") << key.name << " is now the new preferred sky preset" << LL_ENDL; - LLEnvManagerNew::instance().setUseSkyPreset(key.name); - } + // Change preference if requested. + if (mMakeDefaultCheckBox->getEnabled() && mMakeDefaultCheckBox->getValue()) + { + LL_DEBUGS("Windlight") << name << " is now the new preferred sky preset" << LL_ENDL; + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, mEditSettings); + } - closeFloater(); + closeFloater(); } void LLFloaterEditSky::onBtnSave() { - LLWLParamKey selected_sky = getSelectedSkyPreset(); - LLWLParamManager& wl_mgr = LLWLParamManager::instance(); - - if (selected_sky.scope == LLEnvKey::SCOPE_REGION) - { - saveRegionSky(); - closeFloater(); - return; - } + LLEnvironment::instance().addSky(mEditSettings); + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, mEditSettings); - std::string name = selected_sky.name; - if (name.empty()) - { - // *TODO: show an alert - LL_WARNS() << "Empty sky preset name" << LL_ENDL; - return; - } - - // Don't allow overwriting system presets. - if (wl_mgr.isSystemPreset(name)) - { - LLNotificationsUtil::add("WLNoEditDefault"); - return; - } - - // Save, ask for confirmation for overwriting an existing preset. - if (wl_mgr.hasParamSet(selected_sky)) - { - LLNotificationsUtil::add("WLSavePresetAlert", LLSD(), LLSD(), boost::bind(&LLFloaterEditSky::onSaveAnswer, this, _1, _2)); - } - else - { - // new preset, hence no confirmation needed - onSaveConfirmed(); - } + closeFloater(); } void LLFloaterEditSky::onBtnCancel() @@ -872,22 +656,12 @@ void LLFloaterEditSky::onBtnCancel() void LLFloaterEditSky::onSkyPresetListChange() { - LLWLParamKey key = getSelectedSkyPreset(); // preset being edited - if (!LLWLParamManager::instance().hasParamSet(key)) - { - // Preset we've been editing doesn't exist anymore. Close the floater. - closeFloater(false); - } - else - { - // A new preset has been added. - // Refresh the presets list, though it may not make sense as the floater is about to be closed. - refreshSkyPresetsList(); - } + refreshSkyPresetsList(); } void LLFloaterEditSky::onRegionSettingsChange() { +#if 0 // If creating a new sky, don't bother. if (isNewPreset()) { @@ -905,10 +679,12 @@ void LLFloaterEditSky::onRegionSettingsChange() { refreshSkyPresetsList(); } +#endif } void LLFloaterEditSky::onRegionInfoUpdate() { +#if 0 bool can_edit = true; // If we've selected a region sky preset for editing. @@ -919,4 +695,5 @@ void LLFloaterEditSky::onRegionInfoUpdate() } enableEditing(can_edit); +#endif } diff --git a/indra/newview/llfloatereditsky.h b/indra/newview/llfloatereditsky.h deleted file mode 100644 index a06c4fc5fa..0000000000 --- a/indra/newview/llfloatereditsky.h +++ /dev/null @@ -1,113 +0,0 @@ -/** - * @file llfloatereditsky.h - * @brief Floater to create or edit a sky preset - * - * $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_LLFLOATEREDITSKY_H -#define LL_LLFLOATEREDITSKY_H - -#include "llfloater.h" -#include "llwlparammanager.h" - -class LLButton; -class LLCheckBoxCtrl; -class LLComboBox; -class LLLineEditor; - -/** - * Floater for creating or editing a sky preset. - */ -class LLFloaterEditSky : public LLFloater -{ - LOG_CLASS(LLFloaterEditSky); - -public: - LLFloaterEditSky(const LLSD &key); - - /*virtual*/ BOOL postBuild(); - /*virtual*/ void onOpen(const LLSD& key); - /*virtual*/ void onClose(bool app_quitting); - /*virtual*/ void draw(); - -private: - void initCallbacks(void); - - //-- WL stuff begins ------------------------------------------------------ - - void syncControls(); /// sync up sliders with parameters - - void setColorSwatch(const std::string& name, const WLColorControl& from_ctrl, F32 k); - - // general purpose callbacks for dealing with color controllers - void onColorControlMoved(LLUICtrl* ctrl, WLColorControl* color_ctrl); - void onColorControlRMoved(LLUICtrl* ctrl, void* userdata); - void onColorControlGMoved(LLUICtrl* ctrl, void* userdata); - void onColorControlBMoved(LLUICtrl* ctrl, void* userdata); - void onFloatControlMoved(LLUICtrl* ctrl, void* userdata); - - // lighting callbacks for glow - void onGlowRMoved(LLUICtrl* ctrl, void* userdata); - void onGlowBMoved(LLUICtrl* ctrl, void* userdata); - - // lighting callbacks for sun - void onSunMoved(LLUICtrl* ctrl, void* userdata); - void onTimeChanged(); - - // for handling when the star slider is moved to adjust the alpha - void onStarAlphaMoved(LLUICtrl* ctrl); - - // handle cloud scrolling - void onCloudScrollXMoved(LLUICtrl* ctrl); - void onCloudScrollYMoved(LLUICtrl* ctrl); - void onCloudScrollXToggled(LLUICtrl* ctrl); - void onCloudScrollYToggled(LLUICtrl* ctrl); - - //-- WL stuff ends -------------------------------------------------------- - - void reset(); /// reset the floater to its initial state - bool isNewPreset() const; - void refreshSkyPresetsList(); - void enableEditing(bool enable); - void saveRegionSky(); - LLWLParamKey getSelectedSkyPreset(); - - void onSkyPresetNameEdited(); - void onSkyPresetSelected(); - bool onSaveAnswer(const LLSD& notification, const LLSD& response); - void onSaveConfirmed(); - - void onBtnSave(); - void onBtnCancel(); - - void onSkyPresetListChange(); - void onRegionSettingsChange(); - void onRegionInfoUpdate(); - - LLLineEditor* mSkyPresetNameEditor; - LLComboBox* mSkyPresetCombo; - LLCheckBoxCtrl* mMakeDefaultCheckBox; - LLButton* mSaveButton; -}; - -#endif // LL_LLFLOATEREDITSKY_H diff --git a/indra/newview/llfloatereditwater.cpp b/indra/newview/llfloatereditwater.cpp index 43b44eae37..6e7b777e70 100644 --- a/indra/newview/llfloatereditwater.cpp +++ b/indra/newview/llfloatereditwater.cpp @@ -28,6 +28,8 @@ #include "llfloatereditwater.h" +#include <boost/make_shared.hpp> + // libs #include "llbutton.h" #include "llcheckboxctrl.h" @@ -42,16 +44,22 @@ #include "llagent.h" #include "llregioninfomodel.h" #include "llviewerregion.h" -#include "llwaterparammanager.h" + +#include "llenvironment.h" +#include "llsettingswater.h" +#include "llenvadapters.h" + +#include "v3colorutil.h" #undef max // Fixes a Windows compiler error -LLFloaterEditWater::LLFloaterEditWater(const LLSD &key) -: LLFloater(key) -, mWaterPresetNameEditor(NULL) -, mWaterPresetCombo(NULL) -, mMakeDefaultCheckBox(NULL) -, mSaveButton(NULL) +LLFloaterEditWater::LLFloaterEditWater(const LLSD &key): + LLFloater(key), + mWaterPresetNameEditor(NULL), + mWaterPresetCombo(NULL), + mMakeDefaultCheckBox(NULL), + mSaveButton(NULL), + mWaterAdapter() { } @@ -63,6 +71,10 @@ BOOL LLFloaterEditWater::postBuild() mMakeDefaultCheckBox = getChild<LLCheckBoxCtrl>("make_default_cb"); mSaveButton = getChild<LLButton>("save"); + mWaterAdapter = boost::make_shared<LLWatterSettingsAdapter>(); + + LLEnvironment::instance().setWaterListChange(boost::bind(&LLFloaterEditWater::onWaterPresetListChange, this)); + initCallbacks(); refreshWaterPresetsList(); syncControls(); @@ -99,7 +111,8 @@ void LLFloaterEditWater::onClose(bool app_quitting) { if (!app_quitting) // there's no point to change environment if we're quitting { - LLEnvManagerNew::instance().usePrefs(); // revert changes made to current environment + LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_EDIT); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL); } } @@ -119,44 +132,38 @@ void LLFloaterEditWater::initCallbacks(void) mSaveButton->setCommitCallback(boost::bind(&LLFloaterEditWater::onBtnSave, this)); getChild<LLButton>("cancel")->setCommitCallback(boost::bind(&LLFloaterEditWater::onBtnCancel, this)); - LLEnvManagerNew::instance().setRegionSettingsChangeCallback(boost::bind(&LLFloaterEditWater::onRegionSettingsChange, this)); - LLWaterParamManager::instance().setPresetListChangeCallback(boost::bind(&LLFloaterEditWater::onWaterPresetListChange, this)); - // Connect to region info updates. LLRegionInfoModel::instance().setUpdateCallback(boost::bind(&LLFloaterEditWater::onRegionInfoUpdate, this)); //------------------------------------------------------------------------- - LLWaterParamManager& water_mgr = LLWaterParamManager::instance(); - - getChild<LLUICtrl>("WaterFogColor")->setCommitCallback(boost::bind(&LLFloaterEditWater::onWaterFogColorMoved, this, _1, &water_mgr.mFogColor)); - //getChild<LLUICtrl>("WaterGlow")->setCommitCallback(boost::bind(&LLFloaterEditWater::onColorControlAMoved, this, _1, &water_mgr.mFogColor)); + getChild<LLUICtrl>("WaterFogColor")->setCommitCallback(boost::bind(&LLFloaterEditWater::onColorControlMoved, this, _1, &mWaterAdapter->mFogColor)); // fog density - getChild<LLUICtrl>("WaterFogDensity")->setCommitCallback(boost::bind(&LLFloaterEditWater::onExpFloatControlMoved, this, _1, &water_mgr.mFogDensity)); - getChild<LLUICtrl>("WaterUnderWaterFogMod")->setCommitCallback(boost::bind(&LLFloaterEditWater::onFloatControlMoved, this, _1, &water_mgr.mUnderWaterFogMod)); + getChild<LLUICtrl>("WaterFogDensity")->setCommitCallback(boost::bind(&LLFloaterEditWater::onExpFloatControlMoved, this, _1, &mWaterAdapter->mFogDensity)); + getChild<LLUICtrl>("WaterUnderWaterFogMod")->setCommitCallback(boost::bind(&LLFloaterEditWater::onFloatControlMoved, this, _1, &mWaterAdapter->mUnderWaterFogMod)); // blue density - getChild<LLUICtrl>("WaterNormalScaleX")->setCommitCallback(boost::bind(&LLFloaterEditWater::onVector3ControlXMoved, this, _1, &water_mgr.mNormalScale)); - getChild<LLUICtrl>("WaterNormalScaleY")->setCommitCallback(boost::bind(&LLFloaterEditWater::onVector3ControlYMoved, this, _1, &water_mgr.mNormalScale)); - getChild<LLUICtrl>("WaterNormalScaleZ")->setCommitCallback(boost::bind(&LLFloaterEditWater::onVector3ControlZMoved, this, _1, &water_mgr.mNormalScale)); + getChild<LLUICtrl>("WaterNormalScaleX")->setCommitCallback(boost::bind(&LLFloaterEditWater::onVector3ControlXMoved, this, _1, &mWaterAdapter->mNormalScale)); + getChild<LLUICtrl>("WaterNormalScaleY")->setCommitCallback(boost::bind(&LLFloaterEditWater::onVector3ControlYMoved, this, _1, &mWaterAdapter->mNormalScale)); + getChild<LLUICtrl>("WaterNormalScaleZ")->setCommitCallback(boost::bind(&LLFloaterEditWater::onVector3ControlZMoved, this, _1, &mWaterAdapter->mNormalScale)); // fresnel - getChild<LLUICtrl>("WaterFresnelScale")->setCommitCallback(boost::bind(&LLFloaterEditWater::onFloatControlMoved, this, _1, &water_mgr.mFresnelScale)); - getChild<LLUICtrl>("WaterFresnelOffset")->setCommitCallback(boost::bind(&LLFloaterEditWater::onFloatControlMoved, this, _1, &water_mgr.mFresnelOffset)); + getChild<LLUICtrl>("WaterFresnelScale")->setCommitCallback(boost::bind(&LLFloaterEditWater::onFloatControlMoved, this, _1, &mWaterAdapter->mFresnelScale)); + getChild<LLUICtrl>("WaterFresnelOffset")->setCommitCallback(boost::bind(&LLFloaterEditWater::onFloatControlMoved, this, _1, &mWaterAdapter->mFresnelOffset)); // scale above/below - getChild<LLUICtrl>("WaterScaleAbove")->setCommitCallback(boost::bind(&LLFloaterEditWater::onFloatControlMoved, this, _1, &water_mgr.mScaleAbove)); - getChild<LLUICtrl>("WaterScaleBelow")->setCommitCallback(boost::bind(&LLFloaterEditWater::onFloatControlMoved, this, _1, &water_mgr.mScaleBelow)); + getChild<LLUICtrl>("WaterScaleAbove")->setCommitCallback(boost::bind(&LLFloaterEditWater::onFloatControlMoved, this, _1, &mWaterAdapter->mScaleAbove)); + getChild<LLUICtrl>("WaterScaleBelow")->setCommitCallback(boost::bind(&LLFloaterEditWater::onFloatControlMoved, this, _1, &mWaterAdapter->mScaleBelow)); // blur mult - getChild<LLUICtrl>("WaterBlurMult")->setCommitCallback(boost::bind(&LLFloaterEditWater::onFloatControlMoved, this, _1, &water_mgr.mBlurMultiplier)); + getChild<LLUICtrl>("WaterBlurMult")->setCommitCallback(boost::bind(&LLFloaterEditWater::onFloatControlMoved, this, _1, &mWaterAdapter->mBlurMultiplier)); // wave direction - getChild<LLUICtrl>("WaterWave1DirX")->setCommitCallback(boost::bind(&LLFloaterEditWater::onVector2ControlXMoved, this, _1, &water_mgr.mWave1Dir)); - getChild<LLUICtrl>("WaterWave1DirY")->setCommitCallback(boost::bind(&LLFloaterEditWater::onVector2ControlYMoved, this, _1, &water_mgr.mWave1Dir)); - getChild<LLUICtrl>("WaterWave2DirX")->setCommitCallback(boost::bind(&LLFloaterEditWater::onVector2ControlXMoved, this, _1, &water_mgr.mWave2Dir)); - getChild<LLUICtrl>("WaterWave2DirY")->setCommitCallback(boost::bind(&LLFloaterEditWater::onVector2ControlYMoved, this, _1, &water_mgr.mWave2Dir)); + getChild<LLUICtrl>("WaterWave1DirX")->setCommitCallback(boost::bind(&LLFloaterEditWater::onVector2ControlXMoved, this, _1, &mWaterAdapter->mWave1Dir)); + getChild<LLUICtrl>("WaterWave1DirY")->setCommitCallback(boost::bind(&LLFloaterEditWater::onVector2ControlYMoved, this, _1, &mWaterAdapter->mWave1Dir)); + getChild<LLUICtrl>("WaterWave2DirX")->setCommitCallback(boost::bind(&LLFloaterEditWater::onVector2ControlXMoved, this, _1, &mWaterAdapter->mWave2Dir)); + getChild<LLUICtrl>("WaterWave2DirY")->setCommitCallback(boost::bind(&LLFloaterEditWater::onVector2ControlYMoved, this, _1, &mWaterAdapter->mWave2Dir)); LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("WaterNormalMap"); texture_ctrl->setDefaultImageAssetID(DEFAULT_WATER_NORMAL); @@ -169,304 +176,132 @@ void LLFloaterEditWater::syncControls() { // *TODO: Eliminate slow getChild() calls. - bool err; - - LLWaterParamManager& water_mgr = LLWaterParamManager::instance(); - - LLWaterParamSet& current_params = water_mgr.mCurParams; + LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater(); + mEditSettings = pwater; - // blue horizon - water_mgr.mFogColor = current_params.getVector4(water_mgr.mFogColor.mName, err); + std::string name = pwater->getName(); + mWaterPresetNameEditor->setText(name); + mWaterPresetCombo->setValue(name); - LLColor4 col = water_mgr.getFogColor(); //getChild<LLUICtrl>("WaterGlow")->setValue(col.mV[3]); - col.mV[3] = 1.0f; - getChild<LLColorSwatchCtrl>("WaterFogColor")->set(col); + getChild<LLColorSwatchCtrl>("WaterFogColor")->set(LLColor4(pwater->getWaterFogColor())); // fog and wavelets - water_mgr.mFogDensity.mExp = - log(current_params.getFloat(water_mgr.mFogDensity.mName, err)) / - log(water_mgr.mFogDensity.mBase); - water_mgr.setDensitySliderValue(water_mgr.mFogDensity.mExp); - getChild<LLUICtrl>("WaterFogDensity")->setValue(water_mgr.mFogDensity.mExp); + mWaterAdapter->mFogDensity = pwater->getWaterFogDensity(); + getChild<LLUICtrl>("WaterFogDensity")->setValue(mWaterAdapter->mFogDensity.getExp()); - water_mgr.mUnderWaterFogMod.mX = - current_params.getFloat(water_mgr.mUnderWaterFogMod.mName, err); - getChild<LLUICtrl>("WaterUnderWaterFogMod")->setValue(water_mgr.mUnderWaterFogMod.mX); + mWaterAdapter->mUnderWaterFogMod = pwater->getFogMod(); + getChild<LLUICtrl>("WaterUnderWaterFogMod")->setValue(static_cast<F32>(mWaterAdapter->mUnderWaterFogMod)); - water_mgr.mNormalScale = current_params.getVector3(water_mgr.mNormalScale.mName, err); - getChild<LLUICtrl>("WaterNormalScaleX")->setValue(water_mgr.mNormalScale.mX); - getChild<LLUICtrl>("WaterNormalScaleY")->setValue(water_mgr.mNormalScale.mY); - getChild<LLUICtrl>("WaterNormalScaleZ")->setValue(water_mgr.mNormalScale.mZ); + mWaterAdapter->mNormalScale = pwater->getNormalScale(); + getChild<LLUICtrl>("WaterNormalScaleX")->setValue(mWaterAdapter->mNormalScale.getX()); + getChild<LLUICtrl>("WaterNormalScaleY")->setValue(mWaterAdapter->mNormalScale.getY()); + getChild<LLUICtrl>("WaterNormalScaleZ")->setValue(mWaterAdapter->mNormalScale.getZ()); // Fresnel - water_mgr.mFresnelScale.mX = current_params.getFloat(water_mgr.mFresnelScale.mName, err); - getChild<LLUICtrl>("WaterFresnelScale")->setValue(water_mgr.mFresnelScale.mX); - water_mgr.mFresnelOffset.mX = current_params.getFloat(water_mgr.mFresnelOffset.mName, err); - getChild<LLUICtrl>("WaterFresnelOffset")->setValue(water_mgr.mFresnelOffset.mX); + mWaterAdapter->mFresnelScale = pwater->getFresnelScale(); + getChild<LLUICtrl>("WaterFresnelScale")->setValue(static_cast<F32>(mWaterAdapter->mFresnelScale)); + mWaterAdapter->mFresnelOffset = pwater->getFresnelOffset(); + getChild<LLUICtrl>("WaterFresnelOffset")->setValue(static_cast<F32>(mWaterAdapter->mFresnelOffset)); // Scale Above/Below - water_mgr.mScaleAbove.mX = current_params.getFloat(water_mgr.mScaleAbove.mName, err); - getChild<LLUICtrl>("WaterScaleAbove")->setValue(water_mgr.mScaleAbove.mX); - water_mgr.mScaleBelow.mX = current_params.getFloat(water_mgr.mScaleBelow.mName, err); - getChild<LLUICtrl>("WaterScaleBelow")->setValue(water_mgr.mScaleBelow.mX); + mWaterAdapter->mScaleAbove = pwater->getScaleAbove(); + getChild<LLUICtrl>("WaterScaleAbove")->setValue(static_cast<F32>(mWaterAdapter->mScaleAbove)); + mWaterAdapter->mScaleBelow = pwater->getScaleBelow(); + getChild<LLUICtrl>("WaterScaleBelow")->setValue(static_cast<F32>(mWaterAdapter->mScaleBelow)); // blur mult - water_mgr.mBlurMultiplier.mX = current_params.getFloat(water_mgr.mBlurMultiplier.mName, err); - getChild<LLUICtrl>("WaterBlurMult")->setValue(water_mgr.mBlurMultiplier.mX); + mWaterAdapter->mBlurMultiplier = pwater->getBlurMultiplier(); + getChild<LLUICtrl>("WaterBlurMult")->setValue(static_cast<F32>(mWaterAdapter->mBlurMultiplier)); // wave directions - water_mgr.mWave1Dir = current_params.getVector2(water_mgr.mWave1Dir.mName, err); - getChild<LLUICtrl>("WaterWave1DirX")->setValue(water_mgr.mWave1Dir.mX); - getChild<LLUICtrl>("WaterWave1DirY")->setValue(water_mgr.mWave1Dir.mY); + mWaterAdapter->mWave1Dir = pwater->getWave1Dir(); + getChild<LLUICtrl>("WaterWave1DirX")->setValue(mWaterAdapter->mWave1Dir.getU()); + getChild<LLUICtrl>("WaterWave1DirY")->setValue(mWaterAdapter->mWave1Dir.getV()); - water_mgr.mWave2Dir = current_params.getVector2(water_mgr.mWave2Dir.mName, err); - getChild<LLUICtrl>("WaterWave2DirX")->setValue(water_mgr.mWave2Dir.mX); - getChild<LLUICtrl>("WaterWave2DirY")->setValue(water_mgr.mWave2Dir.mY); + mWaterAdapter->mWave2Dir = pwater->getWave2Dir(); + getChild<LLUICtrl>("WaterWave2DirX")->setValue(mWaterAdapter->mWave2Dir.getU()); + getChild<LLUICtrl>("WaterWave2DirY")->setValue(mWaterAdapter->mWave2Dir.getV()); LLTextureCtrl* textCtrl = getChild<LLTextureCtrl>("WaterNormalMap"); - textCtrl->setImageAssetID(water_mgr.getNormalMapID()); -} - -// color control callbacks -void LLFloaterEditWater::onColorControlRMoved(LLUICtrl* ctrl, WaterColorControl* color_ctrl) -{ - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - - color_ctrl->mR = sldr_ctrl->getValueF32(); - - // move i if it's the max - if (color_ctrl->mR >= color_ctrl->mG - && color_ctrl->mR >= color_ctrl->mB - && color_ctrl->mHasSliderName) - { - color_ctrl->mI = color_ctrl->mR; - std::string name = color_ctrl->mSliderName; - name.append("I"); - - getChild<LLUICtrl>(name)->setValue(color_ctrl->mR); - } - - color_ctrl->update(LLWaterParamManager::getInstance()->mCurParams); - - LLWaterParamManager::getInstance()->propagateParameters(); -} - -void LLFloaterEditWater::onColorControlGMoved(LLUICtrl* ctrl, WaterColorControl* color_ctrl) -{ - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - - color_ctrl->mG = sldr_ctrl->getValueF32(); - - // move i if it's the max - if (color_ctrl->mG >= color_ctrl->mR - && color_ctrl->mG >= color_ctrl->mB - && color_ctrl->mHasSliderName) - { - color_ctrl->mI = color_ctrl->mG; - std::string name = color_ctrl->mSliderName; - name.append("I"); - - getChild<LLUICtrl>(name)->setValue(color_ctrl->mG); - - } - - color_ctrl->update(LLWaterParamManager::getInstance()->mCurParams); - - LLWaterParamManager::getInstance()->propagateParameters(); -} - -void LLFloaterEditWater::onColorControlBMoved(LLUICtrl* ctrl, WaterColorControl* color_ctrl) -{ - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - - color_ctrl->mB = sldr_ctrl->getValueF32(); - - // move i if it's the max - if (color_ctrl->mB >= color_ctrl->mR - && color_ctrl->mB >= color_ctrl->mG - && color_ctrl->mHasSliderName) - { - color_ctrl->mI = color_ctrl->mB; - std::string name = color_ctrl->mSliderName; - name.append("I"); - - getChild<LLUICtrl>(name)->setValue(color_ctrl->mB); - } - - color_ctrl->update(LLWaterParamManager::getInstance()->mCurParams); - - LLWaterParamManager::getInstance()->propagateParameters(); -} - -void LLFloaterEditWater::onColorControlAMoved(LLUICtrl* ctrl, WaterColorControl* color_ctrl) -{ - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - - color_ctrl->mA = sldr_ctrl->getValueF32(); - - color_ctrl->update(LLWaterParamManager::getInstance()->mCurParams); - - LLWaterParamManager::getInstance()->propagateParameters(); + textCtrl->setImageAssetID(pwater->getNormalMapID()); } -void LLFloaterEditWater::onColorControlIMoved(LLUICtrl* ctrl, WaterColorControl* color_ctrl) -{ - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - - color_ctrl->mI = sldr_ctrl->getValueF32(); - - // only for sliders where we pass a name - if (color_ctrl->mHasSliderName) - { - // set it to the top - F32 maxVal = std::max(std::max(color_ctrl->mR, color_ctrl->mG), color_ctrl->mB); - F32 iVal; - - iVal = color_ctrl->mI; - - // get the names of the other sliders - std::string rName = color_ctrl->mSliderName; - rName.append("R"); - std::string gName = color_ctrl->mSliderName; - gName.append("G"); - std::string bName = color_ctrl->mSliderName; - bName.append("B"); - - // handle if at 0 - if (iVal == 0) - { - color_ctrl->mR = 0; - color_ctrl->mG = 0; - color_ctrl->mB = 0; - - // if all at the start - // set them all to the intensity - } - else if (maxVal == 0) - { - color_ctrl->mR = iVal; - color_ctrl->mG = iVal; - color_ctrl->mB = iVal; - } - else - { - // add delta amounts to each - F32 delta = (iVal - maxVal) / maxVal; - color_ctrl->mR *= (1.0f + delta); - color_ctrl->mG *= (1.0f + delta); - color_ctrl->mB *= (1.0f + delta); - } - - // set the sliders to the new vals - getChild<LLUICtrl>(rName)->setValue(color_ctrl->mR); - getChild<LLUICtrl>(gName)->setValue(color_ctrl->mG); - getChild<LLUICtrl>(bName)->setValue(color_ctrl->mB); - } - - // now update the current parameters and send them to shaders - color_ctrl->update(LLWaterParamManager::getInstance()->mCurParams); - LLWaterParamManager::getInstance()->propagateParameters(); -} - // vector control callbacks -void LLFloaterEditWater::onVector3ControlXMoved(LLUICtrl* ctrl, WaterVector3Control* vector_ctrl) +void LLFloaterEditWater::onVector3ControlXMoved(LLUICtrl* ctrl, WLVect3Control* vector_ctrl) { LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - vector_ctrl->mX = sldr_ctrl->getValueF32(); - - vector_ctrl->update(LLWaterParamManager::getInstance()->mCurParams); - - LLWaterParamManager::getInstance()->propagateParameters(); + vector_ctrl->setX( sldr_ctrl->getValueF32() ); + vector_ctrl->update(mEditSettings); } // vector control callbacks -void LLFloaterEditWater::onVector3ControlYMoved(LLUICtrl* ctrl, WaterVector3Control* vector_ctrl) +void LLFloaterEditWater::onVector3ControlYMoved(LLUICtrl* ctrl, WLVect3Control* vector_ctrl) { LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - vector_ctrl->mY = sldr_ctrl->getValueF32(); - - vector_ctrl->update(LLWaterParamManager::getInstance()->mCurParams); - - LLWaterParamManager::getInstance()->propagateParameters(); + vector_ctrl->setY(sldr_ctrl->getValueF32()); + vector_ctrl->update(mEditSettings); } // vector control callbacks -void LLFloaterEditWater::onVector3ControlZMoved(LLUICtrl* ctrl, WaterVector3Control* vector_ctrl) +void LLFloaterEditWater::onVector3ControlZMoved(LLUICtrl* ctrl, WLVect3Control* vector_ctrl) { - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - - vector_ctrl->mZ = sldr_ctrl->getValueF32(); - - vector_ctrl->update(LLWaterParamManager::getInstance()->mCurParams); + LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - LLWaterParamManager::getInstance()->propagateParameters(); + vector_ctrl->setZ(sldr_ctrl->getValueF32()); + vector_ctrl->update(mEditSettings); } // vector control callbacks -void LLFloaterEditWater::onVector2ControlXMoved(LLUICtrl* ctrl, WaterVector2Control* vector_ctrl) +void LLFloaterEditWater::onVector2ControlXMoved(LLUICtrl* ctrl, WLVect2Control* vector_ctrl) { - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - - vector_ctrl->mX = sldr_ctrl->getValueF32(); + LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - vector_ctrl->update(LLWaterParamManager::getInstance()->mCurParams); - - LLWaterParamManager::getInstance()->propagateParameters(); + vector_ctrl->setU(sldr_ctrl->getValueF32()); + vector_ctrl->update(mEditSettings); } // vector control callbacks -void LLFloaterEditWater::onVector2ControlYMoved(LLUICtrl* ctrl, WaterVector2Control* vector_ctrl) +void LLFloaterEditWater::onVector2ControlYMoved(LLUICtrl* ctrl, WLVect2Control* vector_ctrl) { - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); + LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - vector_ctrl->mY = sldr_ctrl->getValueF32(); - - vector_ctrl->update(LLWaterParamManager::getInstance()->mCurParams); - - LLWaterParamManager::getInstance()->propagateParameters(); + vector_ctrl->setV(sldr_ctrl->getValueF32()); + vector_ctrl->update(mEditSettings); } -void LLFloaterEditWater::onFloatControlMoved(LLUICtrl* ctrl, WaterFloatControl* floatControl) +void LLFloaterEditWater::onFloatControlMoved(LLUICtrl* ctrl, WLFloatControl* floatControl) { - LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); + LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - floatControl->mX = sldr_ctrl->getValueF32() / floatControl->mMult; - - floatControl->update(LLWaterParamManager::getInstance()->mCurParams); - LLWaterParamManager::getInstance()->propagateParameters(); + floatControl->setValue(sldr_ctrl->getValueF32()); + floatControl->update(mEditSettings); } -void LLFloaterEditWater::onExpFloatControlMoved(LLUICtrl* ctrl, WaterExpFloatControl* expFloatControl) +void LLFloaterEditWater::onExpFloatControlMoved(LLUICtrl* ctrl, WLXFloatControl* expFloatControl) { LLSliderCtrl* sldr_ctrl = static_cast<LLSliderCtrl*>(ctrl); - F32 val = sldr_ctrl->getValueF32(); - expFloatControl->mExp = val; - LLWaterParamManager::getInstance()->setDensitySliderValue(val); - - expFloatControl->update(LLWaterParamManager::getInstance()->mCurParams); - LLWaterParamManager::getInstance()->propagateParameters(); + expFloatControl->setExp(sldr_ctrl->getValueF32()); + expFloatControl->update(mEditSettings); } -void LLFloaterEditWater::onWaterFogColorMoved(LLUICtrl* ctrl, WaterColorControl* color_ctrl) +void LLFloaterEditWater::onColorControlMoved(LLUICtrl* ctrl, WLColorControl* color_ctrl) { LLColorSwatchCtrl* swatch = static_cast<LLColorSwatchCtrl*>(ctrl); - *color_ctrl = swatch->get(); - - color_ctrl->update(LLWaterParamManager::getInstance()->mCurParams); - LLWaterParamManager::getInstance()->propagateParameters(); + color_ctrl->setColor4( swatch->get() ); + color_ctrl->update(mEditSettings); } void LLFloaterEditWater::onNormalMapPicked(LLUICtrl* ctrl) { LLTextureCtrl* textCtrl = static_cast<LLTextureCtrl*>(ctrl); LLUUID textID = textCtrl->getImageAssetID(); - LLWaterParamManager::getInstance()->setNormalMapID(textID); + mEditSettings->setNormalMapID(textID); } //============================================================================= @@ -496,38 +331,12 @@ void LLFloaterEditWater::refreshWaterPresetsList() { mWaterPresetCombo->removeall(); -#if 0 // *TODO: enable when we have a clear workflow to edit existing region environment - // 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, LLSD().with(0, region_name).with(1, LLEnvKey::SCOPE_REGION)); - mWaterPresetCombo->addSeparator(); - } -#endif - - std::list<std::string> user_presets, system_presets; - LLWaterParamManager::instance().getPresetNames(user_presets, system_presets); + LLEnvironment::list_name_id_t list = LLEnvironment::instance().getWaterList(); - // Add local user presets first. - for (std::list<std::string>::const_iterator it = user_presets.begin(); it != user_presets.end(); ++it) - { - const std::string& name = *it; - mWaterPresetCombo->add(name, LLSD().with(0, name).with(1, LLEnvKey::SCOPE_LOCAL)); // [<name>, <scope>] - } - - if (user_presets.size() > 0) - { - mWaterPresetCombo->addSeparator(); - } - - // Add local system presets. - for (std::list<std::string>::const_iterator it = system_presets.begin(); it != system_presets.end(); ++it) - { - const std::string& name = *it; - mWaterPresetCombo->add(name, LLSD().with(0, name).with(1, LLEnvKey::SCOPE_LOCAL)); // [<name>, <scope>] - } + for (LLEnvironment::list_name_id_t::iterator it = list.begin(); it != list.end(); ++it) + { + mWaterPresetCombo->add((*it).first, LLSDArray((*it).first)((*it).second)); + } mWaterPresetCombo->setLabel(getString("combo_label")); } @@ -544,6 +353,7 @@ void LLFloaterEditWater::enableEditing(bool enable) void LLFloaterEditWater::saveRegionWater() { +#if 0 llassert(getCurrentScope() == LLEnvKey::SCOPE_REGION); // make sure we're editing region water LL_DEBUGS("Windlight") << "Saving region water preset" << LL_ENDL; @@ -552,8 +362,10 @@ void LLFloaterEditWater::saveRegionWater() // *TODO: save to cached region settings. LL_WARNS("Windlight") << "Saving region water is not fully implemented yet" << LL_ENDL; +#endif } +#if 0 std::string LLFloaterEditWater::getCurrentPresetName() const { std::string name; @@ -561,7 +373,9 @@ std::string LLFloaterEditWater::getCurrentPresetName() const getSelectedPreset(name, scope); return name; } +#endif +#if 0 LLEnvKey::EScope LLFloaterEditWater::getCurrentScope() const { std::string name; @@ -569,71 +383,62 @@ LLEnvKey::EScope LLFloaterEditWater::getCurrentScope() const getSelectedPreset(name, scope); return scope; } +#endif -void LLFloaterEditWater::getSelectedPreset(std::string& name, LLEnvKey::EScope& scope) const +std::string LLFloaterEditWater::getSelectedPresetName() const { + std::string name; if (mWaterPresetNameEditor->getVisible()) { name = mWaterPresetNameEditor->getText(); - scope = LLEnvKey::SCOPE_LOCAL; } else { LLSD combo_val = mWaterPresetCombo->getValue(); - - if (!combo_val.isArray()) // manually typed text - { - name = combo_val.asString(); - scope = LLEnvKey::SCOPE_LOCAL; - } - else - { - name = combo_val[0].asString(); - scope = (LLEnvKey::EScope) combo_val[1].asInteger(); - } + name = combo_val[0].asString(); } + + return name; } void LLFloaterEditWater::onWaterPresetNameEdited() { + std::string name = mWaterPresetNameEditor->getText(); + LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater(); + + pwater->setName(name); +#if 0 // Disable saving a water preset having empty name. mSaveButton->setEnabled(!getCurrentPresetName().empty()); +#endif } void LLFloaterEditWater::onWaterPresetSelected() { - LLWaterParamSet water_params; std::string name; - LLEnvKey::EScope scope; - getSelectedPreset(name, scope); + name = getSelectedPresetName(); - // Display selected preset. - if (scope == LLEnvKey::SCOPE_REGION) - { - water_params.setAll(LLEnvManagerNew::instance().getRegionSettings().getWaterParams()); - } - else // local preset selected - { - if (!LLWaterParamManager::instance().getParamSet(name, water_params)) - { - // Manually entered string? - LL_WARNS("Windlight") << "No water preset named " << name << LL_ENDL; - return; - } - } + LLSettingsWater::ptr_t pwater = LLEnvironment::instance().findWaterByName(name); - LLEnvManagerNew::instance().useWaterParams(water_params.getAll()); + if (!pwater) + { + LL_WARNS("WATEREDIT") << "Could not find water preset" << LL_ENDL; + enableEditing(false); + return; + } - bool can_edit = (scope == LLEnvKey::SCOPE_LOCAL || LLEnvManagerNew::canEditRegionSettings()); - enableEditing(can_edit); + pwater = pwater->buildClone(); + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_EDIT, pwater); + mEditSettings = pwater; - mMakeDefaultCheckBox->setEnabled(scope == LLEnvKey::SCOPE_LOCAL); + syncControls(); + enableEditing(true); } bool LLFloaterEditWater::onSaveAnswer(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); // If they choose save, do it. Otherwise, don't do anything if (option == 0) @@ -641,32 +446,23 @@ bool LLFloaterEditWater::onSaveAnswer(const LLSD& notification, const LLSD& resp onSaveConfirmed(); } - return false; + return false; } void LLFloaterEditWater::onSaveConfirmed() { // Save currently displayed water params to the selected preset. - std::string name = getCurrentPresetName(); + std::string name = mEditSettings->getName(); LL_DEBUGS("Windlight") << "Saving sky preset " << name << LL_ENDL; - LLWaterParamManager& water_mgr = LLWaterParamManager::instance(); - if (water_mgr.hasParamSet(name)) - { - water_mgr.setParamSet(name, water_mgr.mCurParams); - } - else - { - water_mgr.addParamSet(name, water_mgr.mCurParams); - } - water_mgr.savePreset(name); + LLEnvironment::instance().addWater(mEditSettings); // Change preference if requested. if (mMakeDefaultCheckBox->getEnabled() && mMakeDefaultCheckBox->getValue()) { LL_DEBUGS("Windlight") << name << " is now the new preferred water preset" << LL_ENDL; - LLEnvManagerNew::instance().setUseWaterPreset(name); + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, mEditSettings); } closeFloater(); @@ -674,42 +470,10 @@ void LLFloaterEditWater::onSaveConfirmed() void LLFloaterEditWater::onBtnSave() { - LLEnvKey::EScope scope; - std::string name; - getSelectedPreset(name, scope); - - if (scope == LLEnvKey::SCOPE_REGION) - { - saveRegionWater(); - closeFloater(); - return; - } - - if (name.empty()) - { - // *TODO: show an alert - LL_WARNS() << "Empty water preset name" << LL_ENDL; - return; - } - - // Don't allow overwriting system presets. - LLWaterParamManager& water_mgr = LLWaterParamManager::instance(); - if (water_mgr.isSystemPreset(name)) - { - LLNotificationsUtil::add("WLNoEditDefault"); - return; - } + LLEnvironment::instance().addWater(mEditSettings); + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, mEditSettings); - // Save, ask for confirmation for overwriting an existing preset. - if (water_mgr.hasParamSet(name)) - { - LLNotificationsUtil::add("WLSavePresetAlert", LLSD(), LLSD(), boost::bind(&LLFloaterEditWater::onSaveAnswer, this, _1, _2)); - } - else - { - // new preset, hence no confirmation needed - onSaveConfirmed(); - } + closeFloater(); } void LLFloaterEditWater::onBtnCancel() @@ -719,25 +483,12 @@ void LLFloaterEditWater::onBtnCancel() void LLFloaterEditWater::onWaterPresetListChange() { - std::string name; - LLEnvKey::EScope scope; - getSelectedPreset(name, scope); // preset being edited - - if (scope == LLEnvKey::SCOPE_LOCAL && !LLWaterParamManager::instance().hasParamSet(name)) - { - // Preset we've been editing doesn't exist anymore. Close the floater. - closeFloater(false); - } - else - { - // A new preset has been added. - // Refresh the presets list, though it may not make sense as the floater is about to be closed. - refreshWaterPresetsList(); - } + refreshWaterPresetsList(); } void LLFloaterEditWater::onRegionSettingsChange() { +#if 0 // If creating a new preset, don't bother. if (isNewPreset()) { @@ -755,10 +506,12 @@ void LLFloaterEditWater::onRegionSettingsChange() { refreshWaterPresetsList(); } +#endif } void LLFloaterEditWater::onRegionInfoUpdate() { +#if 0 bool can_edit = true; // If we've selected the region water for editing. @@ -769,4 +522,5 @@ void LLFloaterEditWater::onRegionInfoUpdate() } enableEditing(can_edit); +#endif } diff --git a/indra/newview/llfloatereditwater.h b/indra/newview/llfloatereditwater.h deleted file mode 100644 index 2211bca59f..0000000000 --- a/indra/newview/llfloatereditwater.h +++ /dev/null @@ -1,115 +0,0 @@ -/** - * @file llfloatereditwater.h - * @brief Floater to create or edit a water preset - * - * $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_LLFLOATEREDITWATER_H -#define LL_LLFLOATEREDITWATER_H - -#include "llfloater.h" -#include "llenvmanager.h" // for LLEnvKey - -class LLButton; -class LLCheckBoxCtrl; -class LLComboBox; -class LLLineEditor; - -struct WaterVector2Control; -struct WaterVector3Control; -struct WaterColorControl; -struct WaterFloatControl; -struct WaterExpFloatControl; - -class LLFloaterEditWater : public LLFloater -{ - LOG_CLASS(LLFloaterEditWater); - -public: - LLFloaterEditWater(const LLSD &key); - - /*virtual*/ BOOL postBuild(); - /*virtual*/ void onOpen(const LLSD& key); - /*virtual*/ void onClose(bool app_quitting); - /*virtual*/ void draw(); - -private: - void initCallbacks(void); - - //-- WL stuff begins ------------------------------------------------------ - - void syncControls(); /// sync up sliders with parameters - - // general purpose callbacks for dealing with color controllers - void onColorControlRMoved(LLUICtrl* ctrl, WaterColorControl* color_ctrl); - void onColorControlGMoved(LLUICtrl* ctrl, WaterColorControl* color_ctrl); - void onColorControlBMoved(LLUICtrl* ctrl, WaterColorControl* color_ctrl); - void onColorControlAMoved(LLUICtrl* ctrl, WaterColorControl* color_ctrl); - void onColorControlIMoved(LLUICtrl* ctrl, WaterColorControl* color_ctrl); - - void onVector3ControlXMoved(LLUICtrl* ctrl, WaterVector3Control* vector_ctrl); - void onVector3ControlYMoved(LLUICtrl* ctrl, WaterVector3Control* vector_ctrl); - void onVector3ControlZMoved(LLUICtrl* ctrl, WaterVector3Control* vector_ctrl); - - void onVector2ControlXMoved(LLUICtrl* ctrl, WaterVector2Control* vector_ctrl); - void onVector2ControlYMoved(LLUICtrl* ctrl, WaterVector2Control* vector_ctrl); - - void onFloatControlMoved(LLUICtrl* ctrl, WaterFloatControl* floatControl); - - void onExpFloatControlMoved(LLUICtrl* ctrl, WaterExpFloatControl* expFloatControl); - - void onWaterFogColorMoved(LLUICtrl* ctrl, WaterColorControl* color_ctrl); - - void onNormalMapPicked(LLUICtrl* ctrl); /// handle if they choose a new normal map - - //-- WL stuff ends -------------------------------------------------------- - - void reset(); - bool isNewPreset() const; - void refreshWaterPresetsList(); - void enableEditing(bool enable); - void saveRegionWater(); - - std::string getCurrentPresetName() const; - LLEnvKey::EScope getCurrentScope() const; - void getSelectedPreset(std::string& name, LLEnvKey::EScope& scope) const; - - void onWaterPresetNameEdited(); - void onWaterPresetSelected(); - bool onSaveAnswer(const LLSD& notification, const LLSD& response); - void onSaveConfirmed(); - - void onBtnSave(); - void onBtnCancel(); - - void onWaterPresetListChange(); - void onRegionSettingsChange(); - void onRegionInfoUpdate(); - - LLLineEditor* mWaterPresetNameEditor; - LLComboBox* mWaterPresetCombo; - LLCheckBoxCtrl* mMakeDefaultCheckBox; - LLButton* mSaveButton; -}; - -#endif // LL_LLFLOATEREDITWATER_H diff --git a/indra/newview/llfloaterenvironmentadjust.cpp b/indra/newview/llfloaterenvironmentadjust.cpp new file mode 100644 index 0000000000..95d6a2d652 --- /dev/null +++ b/indra/newview/llfloaterenvironmentadjust.cpp @@ -0,0 +1,482 @@ +/** + * @file llfloaterfixedenvironment.cpp + * @brief Floaters to create and edit fixed settings for sky and water. + * + * $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 "llfloaterenvironmentadjust.h" + +#include "llnotificationsutil.h" +#include "llslider.h" +#include "llsliderctrl.h" +#include "llcolorswatch.h" +#include "lltexturectrl.h" +#include "llvirtualtrackball.h" +#include "llenvironment.h" +#include "llviewercontrol.h" + +//========================================================================= +namespace +{ + const std::string FIELD_SKY_AMBIENT_LIGHT("ambient_light"); + const std::string FIELD_SKY_BLUE_HORIZON("blue_horizon"); + const std::string FIELD_SKY_BLUE_DENSITY("blue_density"); + const std::string FIELD_SKY_SUN_COLOR("sun_color"); + const std::string FIELD_SKY_CLOUD_COLOR("cloud_color"); + const std::string FIELD_SKY_HAZE_HORIZON("haze_horizon"); + const std::string FIELD_SKY_HAZE_DENSITY("haze_density"); + const std::string FIELD_SKY_CLOUD_COVERAGE("cloud_coverage"); + const std::string FIELD_SKY_CLOUD_MAP("cloud_map"); + const std::string FIELD_WATER_NORMAL_MAP("water_normal_map"); + const std::string FIELD_SKY_CLOUD_SCALE("cloud_scale"); + const std::string FIELD_SKY_SCENE_GAMMA("scene_gamma"); + const std::string FIELD_SKY_SUN_ROTATION("sun_rotation"); + const std::string FIELD_SKY_SUN_AZIMUTH("sun_azimuth"); + const std::string FIELD_SKY_SUN_ELEVATION("sun_elevation"); + const std::string FIELD_SKY_SUN_SCALE("sun_scale"); + const std::string FIELD_SKY_GLOW_FOCUS("glow_focus"); + const std::string FIELD_SKY_GLOW_SIZE("glow_size"); + const std::string FIELD_SKY_STAR_BRIGHTNESS("star_brightness"); + const std::string FIELD_SKY_MOON_ROTATION("moon_rotation"); + const std::string FIELD_SKY_MOON_AZIMUTH("moon_azimuth"); + const std::string FIELD_SKY_MOON_ELEVATION("moon_elevation"); + const std::string BTN_RESET("btn_reset"); + + const F32 SLIDER_SCALE_SUN_AMBIENT(3.0f); + const F32 SLIDER_SCALE_BLUE_HORIZON_DENSITY(2.0f); + const F32 SLIDER_SCALE_GLOW_R(20.0f); + const F32 SLIDER_SCALE_GLOW_B(-5.0f); + //const F32 SLIDER_SCALE_DENSITY_MULTIPLIER(0.001f); + + const S32 FLOATER_ENVIRONMENT_UPDATE(-2); +} + +//========================================================================= +LLFloaterEnvironmentAdjust::LLFloaterEnvironmentAdjust(const LLSD &key): + LLFloater(key) +{} + +LLFloaterEnvironmentAdjust::~LLFloaterEnvironmentAdjust() +{} + +//------------------------------------------------------------------------- +BOOL LLFloaterEnvironmentAdjust::postBuild() +{ + getChild<LLUICtrl>(FIELD_SKY_AMBIENT_LIGHT)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onAmbientLightChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_BLUE_HORIZON)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onBlueHorizonChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_BLUE_DENSITY)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onBlueDensityChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_HAZE_HORIZON)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onHazeHorizonChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_HAZE_DENSITY)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onHazeDensityChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_SCENE_GAMMA)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onSceneGammaChanged(); }); + + getChild<LLUICtrl>(FIELD_SKY_CLOUD_COLOR)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onCloudColorChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_COVERAGE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onCloudCoverageChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_SCALE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onCloudScaleChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_SUN_COLOR)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onSunColorChanged(); }); + + getChild<LLUICtrl>(FIELD_SKY_GLOW_FOCUS)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onGlowChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_GLOW_SIZE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onGlowChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_STAR_BRIGHTNESS)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onStarBrightnessChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_SUN_ROTATION)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onSunRotationChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_SUN_AZIMUTH)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onSunAzimElevChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_SUN_ELEVATION)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onSunAzimElevChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_SUN_SCALE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onSunScaleChanged(); }); + + getChild<LLUICtrl>(FIELD_SKY_MOON_ROTATION)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMoonRotationChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_MOON_AZIMUTH)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMoonAzimElevChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_MOON_ELEVATION)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMoonAzimElevChanged(); }); + getChild<LLUICtrl>(BTN_RESET)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onButtonReset(); }); + + getChild<LLTextureCtrl>(FIELD_SKY_CLOUD_MAP)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onCloudMapChanged(); }); + getChild<LLTextureCtrl>(FIELD_SKY_CLOUD_MAP)->setDefaultImageAssetID(LLSettingsSky::GetDefaultCloudNoiseTextureId()); + getChild<LLTextureCtrl>(FIELD_SKY_CLOUD_MAP)->setAllowNoTexture(TRUE); + + getChild<LLTextureCtrl>(FIELD_WATER_NORMAL_MAP)->setDefaultImageAssetID(LLSettingsWater::GetDefaultWaterNormalAssetId()); + getChild<LLTextureCtrl>(FIELD_WATER_NORMAL_MAP)->setBlankImageAssetID(LLUUID(gSavedSettings.getString("DefaultBlankNormalTexture"))); + getChild<LLTextureCtrl>(FIELD_WATER_NORMAL_MAP)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onWaterMapChanged(); }); + + refresh(); + return TRUE; +} + +void LLFloaterEnvironmentAdjust::onOpen(const LLSD& key) +{ + if (!mLiveSky) + { + LLEnvironment::instance().saveBeaconsState(); + } + captureCurrentEnvironment(); + + mEventConnection = LLEnvironment::instance().setEnvironmentChanged([this](LLEnvironment::EnvSelection_t env, S32 version){ onEnvironmentUpdated(env, version); }); + + LLFloater::onOpen(key); + refresh(); +} + +void LLFloaterEnvironmentAdjust::onClose(bool app_quitting) +{ + LLEnvironment::instance().revertBeaconsState(); + mEventConnection.disconnect(); + mLiveSky.reset(); + mLiveWater.reset(); + LLFloater::onClose(app_quitting); +} + + +//------------------------------------------------------------------------- +void LLFloaterEnvironmentAdjust::refresh() +{ + if (!mLiveSky || !mLiveWater) + { + setAllChildrenEnabled(FALSE); + return; + } + + setEnabled(TRUE); + setAllChildrenEnabled(TRUE); + + getChild<LLColorSwatchCtrl>(FIELD_SKY_AMBIENT_LIGHT)->set(mLiveSky->getAmbientColor() / SLIDER_SCALE_SUN_AMBIENT); + getChild<LLColorSwatchCtrl>(FIELD_SKY_BLUE_HORIZON)->set(mLiveSky->getBlueHorizon() / SLIDER_SCALE_BLUE_HORIZON_DENSITY); + getChild<LLColorSwatchCtrl>(FIELD_SKY_BLUE_DENSITY)->set(mLiveSky->getBlueDensity() / SLIDER_SCALE_BLUE_HORIZON_DENSITY); + getChild<LLUICtrl>(FIELD_SKY_HAZE_HORIZON)->setValue(mLiveSky->getHazeHorizon()); + getChild<LLUICtrl>(FIELD_SKY_HAZE_DENSITY)->setValue(mLiveSky->getHazeDensity()); + getChild<LLUICtrl>(FIELD_SKY_SCENE_GAMMA)->setValue(mLiveSky->getGamma()); + getChild<LLColorSwatchCtrl>(FIELD_SKY_CLOUD_COLOR)->set(mLiveSky->getCloudColor()); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_COVERAGE)->setValue(mLiveSky->getCloudShadow()); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_SCALE)->setValue(mLiveSky->getCloudScale()); + getChild<LLColorSwatchCtrl>(FIELD_SKY_SUN_COLOR)->set(mLiveSky->getSunlightColor() / SLIDER_SCALE_SUN_AMBIENT); + + getChild<LLTextureCtrl>(FIELD_SKY_CLOUD_MAP)->setValue(mLiveSky->getCloudNoiseTextureId()); + getChild<LLTextureCtrl>(FIELD_WATER_NORMAL_MAP)->setValue(mLiveWater->getNormalMapID()); + + LLColor3 glow(mLiveSky->getGlow()); + + // takes 40 - 0.2 range -> 0 - 1.99 UI range + getChild<LLUICtrl>(FIELD_SKY_GLOW_SIZE)->setValue(2.0 - (glow.mV[0] / SLIDER_SCALE_GLOW_R)); + getChild<LLUICtrl>(FIELD_SKY_GLOW_FOCUS)->setValue(glow.mV[2] / SLIDER_SCALE_GLOW_B); + getChild<LLUICtrl>(FIELD_SKY_STAR_BRIGHTNESS)->setValue(mLiveSky->getStarBrightness()); + getChild<LLUICtrl>(FIELD_SKY_SUN_SCALE)->setValue(mLiveSky->getSunScale()); + + // Sun rotation + LLQuaternion quat = mLiveSky->getSunRotation(); + F32 azimuth; + F32 elevation; + LLVirtualTrackball::getAzimuthAndElevationDeg(quat, azimuth, elevation); + + getChild<LLUICtrl>(FIELD_SKY_SUN_AZIMUTH)->setValue(azimuth); + getChild<LLUICtrl>(FIELD_SKY_SUN_ELEVATION)->setValue(elevation); + getChild<LLVirtualTrackball>(FIELD_SKY_SUN_ROTATION)->setRotation(quat); + + // Moon rotation + quat = mLiveSky->getMoonRotation(); + LLVirtualTrackball::getAzimuthAndElevationDeg(quat, azimuth, elevation); + + getChild<LLUICtrl>(FIELD_SKY_MOON_AZIMUTH)->setValue(azimuth); + getChild<LLUICtrl>(FIELD_SKY_MOON_ELEVATION)->setValue(elevation); + getChild<LLVirtualTrackball>(FIELD_SKY_MOON_ROTATION)->setRotation(quat); +} + + +void LLFloaterEnvironmentAdjust::captureCurrentEnvironment() +{ + LLEnvironment &environment(LLEnvironment::instance()); + bool updatelocal(false); + + if (environment.hasEnvironment(LLEnvironment::ENV_LOCAL)) + { + if (environment.getEnvironmentDay(LLEnvironment::ENV_LOCAL)) + { // We have a full day cycle in the local environment. Freeze the sky + mLiveSky = environment.getEnvironmentFixedSky(LLEnvironment::ENV_LOCAL)->buildClone(); + mLiveWater = environment.getEnvironmentFixedWater(LLEnvironment::ENV_LOCAL)->buildClone(); + updatelocal = true; + } + else + { // otherwise we can just use the sky. + mLiveSky = environment.getEnvironmentFixedSky(LLEnvironment::ENV_LOCAL); + mLiveWater = environment.getEnvironmentFixedWater(LLEnvironment::ENV_LOCAL); + } + } + else + { + mLiveSky = environment.getEnvironmentFixedSky(LLEnvironment::ENV_PARCEL, true)->buildClone(); + mLiveWater = environment.getEnvironmentFixedWater(LLEnvironment::ENV_PARCEL, true)->buildClone(); + updatelocal = true; + } + + if (updatelocal) + { + environment.setEnvironment(LLEnvironment::ENV_LOCAL, mLiveSky, FLOATER_ENVIRONMENT_UPDATE); + environment.setEnvironment(LLEnvironment::ENV_LOCAL, mLiveWater, FLOATER_ENVIRONMENT_UPDATE); + } + environment.setSelectedEnvironment(LLEnvironment::ENV_LOCAL); + environment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT); + +} + +void LLFloaterEnvironmentAdjust::onButtonReset() +{ + LLNotificationsUtil::add("PersonalSettingsConfirmReset", LLSD(), LLSD(), + [this](const LLSD¬if, const LLSD&resp) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); + if (opt == 0) + { + this->closeFloater(); + LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_LOCAL); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL); + LLEnvironment::instance().updateEnvironment(); + } + }); + +} +//------------------------------------------------------------------------- +void LLFloaterEnvironmentAdjust::onAmbientLightChanged() +{ + if (!mLiveSky) + return; + mLiveSky->setAmbientColor(LLColor3(getChild<LLColorSwatchCtrl>(FIELD_SKY_AMBIENT_LIGHT)->get() * SLIDER_SCALE_SUN_AMBIENT)); + mLiveSky->update(); +} + +void LLFloaterEnvironmentAdjust::onBlueHorizonChanged() +{ + if (!mLiveSky) + return; + mLiveSky->setBlueHorizon(LLColor3(getChild<LLColorSwatchCtrl>(FIELD_SKY_BLUE_HORIZON)->get() * SLIDER_SCALE_BLUE_HORIZON_DENSITY)); + mLiveSky->update(); +} + +void LLFloaterEnvironmentAdjust::onBlueDensityChanged() +{ + if (!mLiveSky) + return; + mLiveSky->setBlueDensity(LLColor3(getChild<LLColorSwatchCtrl>(FIELD_SKY_BLUE_DENSITY)->get() * SLIDER_SCALE_BLUE_HORIZON_DENSITY)); + mLiveSky->update(); +} + +void LLFloaterEnvironmentAdjust::onHazeHorizonChanged() +{ + if (!mLiveSky) + return; + mLiveSky->setHazeHorizon(getChild<LLUICtrl>(FIELD_SKY_HAZE_HORIZON)->getValue().asReal()); + mLiveSky->update(); +} + +void LLFloaterEnvironmentAdjust::onHazeDensityChanged() +{ + if (!mLiveSky) + return; + mLiveSky->setHazeDensity(getChild<LLUICtrl>(FIELD_SKY_HAZE_DENSITY)->getValue().asReal()); + mLiveSky->update(); +} + +void LLFloaterEnvironmentAdjust::onSceneGammaChanged() +{ + if (!mLiveSky) + return; + mLiveSky->setGamma(getChild<LLUICtrl>(FIELD_SKY_SCENE_GAMMA)->getValue().asReal()); + mLiveSky->update(); +} + +void LLFloaterEnvironmentAdjust::onCloudColorChanged() +{ + if (!mLiveSky) + return; + mLiveSky->setCloudColor(LLColor3(getChild<LLColorSwatchCtrl>(FIELD_SKY_CLOUD_COLOR)->get())); + mLiveSky->update(); +} + +void LLFloaterEnvironmentAdjust::onCloudCoverageChanged() +{ + if (!mLiveSky) + return; + mLiveSky->setCloudShadow(getChild<LLUICtrl>(FIELD_SKY_CLOUD_COVERAGE)->getValue().asReal()); + mLiveSky->update(); +} + +void LLFloaterEnvironmentAdjust::onCloudScaleChanged() +{ + if (!mLiveSky) + return; + mLiveSky->setCloudScale(getChild<LLUICtrl>(FIELD_SKY_CLOUD_SCALE)->getValue().asReal()); + mLiveSky->update(); +} + +void LLFloaterEnvironmentAdjust::onGlowChanged() +{ + if (!mLiveSky) + return; + LLColor3 glow(getChild<LLUICtrl>(FIELD_SKY_GLOW_SIZE)->getValue().asReal(), 0.0f, getChild<LLUICtrl>(FIELD_SKY_GLOW_FOCUS)->getValue().asReal()); + + // takes 0 - 1.99 UI range -> 40 -> 0.2 range + glow.mV[0] = (2.0f - glow.mV[0]) * SLIDER_SCALE_GLOW_R; + glow.mV[2] *= SLIDER_SCALE_GLOW_B; + + mLiveSky->setGlow(glow); + mLiveSky->update(); +} + +void LLFloaterEnvironmentAdjust::onStarBrightnessChanged() +{ + if (!mLiveSky) + return; + mLiveSky->setStarBrightness(getChild<LLUICtrl>(FIELD_SKY_STAR_BRIGHTNESS)->getValue().asReal()); + mLiveSky->update(); +} + +void LLFloaterEnvironmentAdjust::onSunRotationChanged() +{ + LLQuaternion quat = getChild<LLVirtualTrackball>(FIELD_SKY_SUN_ROTATION)->getRotation(); + F32 azimuth; + F32 elevation; + LLVirtualTrackball::getAzimuthAndElevationDeg(quat, azimuth, elevation); + getChild<LLUICtrl>(FIELD_SKY_SUN_AZIMUTH)->setValue(azimuth); + getChild<LLUICtrl>(FIELD_SKY_SUN_ELEVATION)->setValue(elevation); + if (mLiveSky) + { + mLiveSky->setSunRotation(quat); + mLiveSky->update(); + } +} + +void LLFloaterEnvironmentAdjust::onSunAzimElevChanged() +{ + F32 azimuth = getChild<LLUICtrl>(FIELD_SKY_SUN_AZIMUTH)->getValue().asReal(); + F32 elevation = getChild<LLUICtrl>(FIELD_SKY_SUN_ELEVATION)->getValue().asReal(); + LLQuaternion quat; + + azimuth *= DEG_TO_RAD; + elevation *= DEG_TO_RAD; + + if (is_approx_zero(elevation)) + { + elevation = F_APPROXIMATELY_ZERO; + } + + quat.setAngleAxis(-elevation, 0, 1, 0); + LLQuaternion az_quat; + az_quat.setAngleAxis(F_TWO_PI - azimuth, 0, 0, 1); + quat *= az_quat; + + getChild<LLVirtualTrackball>(FIELD_SKY_SUN_ROTATION)->setRotation(quat); + + if (mLiveSky) + { + mLiveSky->setSunRotation(quat); + mLiveSky->update(); + } +} + +void LLFloaterEnvironmentAdjust::onSunScaleChanged() +{ + if (!mLiveSky) + return; + mLiveSky->setSunScale((getChild<LLUICtrl>(FIELD_SKY_SUN_SCALE)->getValue().asReal())); + mLiveSky->update(); +} + +void LLFloaterEnvironmentAdjust::onMoonRotationChanged() +{ + LLQuaternion quat = getChild<LLVirtualTrackball>(FIELD_SKY_MOON_ROTATION)->getRotation(); + F32 azimuth; + F32 elevation; + LLVirtualTrackball::getAzimuthAndElevationDeg(quat, azimuth, elevation); + getChild<LLUICtrl>(FIELD_SKY_MOON_AZIMUTH)->setValue(azimuth); + getChild<LLUICtrl>(FIELD_SKY_MOON_ELEVATION)->setValue(elevation); + if (mLiveSky) + { + mLiveSky->setMoonRotation(quat); + mLiveSky->update(); + } +} + +void LLFloaterEnvironmentAdjust::onMoonAzimElevChanged() +{ + F32 azimuth = getChild<LLUICtrl>(FIELD_SKY_MOON_AZIMUTH)->getValue().asReal(); + F32 elevation = getChild<LLUICtrl>(FIELD_SKY_MOON_ELEVATION)->getValue().asReal(); + LLQuaternion quat; + + azimuth *= DEG_TO_RAD; + elevation *= DEG_TO_RAD; + + if (is_approx_zero(elevation)) + { + elevation = F_APPROXIMATELY_ZERO; + } + + quat.setAngleAxis(-elevation, 0, 1, 0); + LLQuaternion az_quat; + az_quat.setAngleAxis(F_TWO_PI - azimuth, 0, 0, 1); + quat *= az_quat; + + getChild<LLVirtualTrackball>(FIELD_SKY_MOON_ROTATION)->setRotation(quat); + + if (mLiveSky) + { + mLiveSky->setMoonRotation(quat); + mLiveSky->update(); + } +} + +void LLFloaterEnvironmentAdjust::onCloudMapChanged() +{ + if (!mLiveSky) + return; + mLiveSky->setCloudNoiseTextureId(getChild<LLTextureCtrl>(FIELD_SKY_CLOUD_MAP)->getValue().asUUID()); + mLiveSky->update(); +} + +void LLFloaterEnvironmentAdjust::onWaterMapChanged() +{ + if (!mLiveWater) + return; + mLiveWater->setNormalMapID(getChild<LLTextureCtrl>(FIELD_WATER_NORMAL_MAP)->getValue().asUUID()); + mLiveWater->update(); +} + +void LLFloaterEnvironmentAdjust::onSunColorChanged() +{ + if (!mLiveSky) + return; + LLColor3 color(getChild<LLColorSwatchCtrl>(FIELD_SKY_SUN_COLOR)->get()); + + color *= SLIDER_SCALE_SUN_AMBIENT; + + mLiveSky->setSunlightColor(color); + mLiveSky->update(); +} + + +void LLFloaterEnvironmentAdjust::onEnvironmentUpdated(LLEnvironment::EnvSelection_t env, S32 version) +{ + if (env == LLEnvironment::ENV_LOCAL) + { // a new local environment has been applied + if (version != FLOATER_ENVIRONMENT_UPDATE) + { // not by this floater + captureCurrentEnvironment(); + refresh(); + } + } +} diff --git a/indra/newview/llfloaterenvironmentadjust.h b/indra/newview/llfloaterenvironmentadjust.h new file mode 100644 index 0000000000..05ff011be5 --- /dev/null +++ b/indra/newview/llfloaterenvironmentadjust.h @@ -0,0 +1,94 @@ +/** + * @file llfloaterenvironmentadjust.h + * @brief Floaters to create and edit fixed settings for sky and water. + * + * $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_FLOATERENVIRONMENTADJUST_H +#define LL_FLOATERENVIRONMENTADJUST_H + +#include "llfloater.h" +#include "llsettingsbase.h" +#include "llsettingssky.h" +#include "llenvironment.h" + +#include "boost/signals2.hpp" + +class LLButton; +class LLLineEditor; + +/** + * Floater container for taking a snapshot of the current environment and making minor adjustments. + */ +class LLFloaterEnvironmentAdjust : public LLFloater +{ + LOG_CLASS(LLFloaterEnvironmentAdjust); + +public: + LLFloaterEnvironmentAdjust(const LLSD &key); + virtual ~LLFloaterEnvironmentAdjust(); + + + virtual BOOL postBuild() override; + virtual void onOpen(const LLSD& key) override; + virtual void onClose(bool app_quitting) override; + + virtual void refresh() override; + +private: + void captureCurrentEnvironment(); + + void onAmbientLightChanged(); + void onBlueHorizonChanged(); + void onBlueDensityChanged(); + void onHazeHorizonChanged(); + void onHazeDensityChanged(); + void onSceneGammaChanged(); + + void onCloudColorChanged(); + void onCloudCoverageChanged(); + void onCloudScaleChanged(); + void onSunColorChanged(); + + void onGlowChanged(); + void onStarBrightnessChanged(); + void onSunRotationChanged(); + void onSunAzimElevChanged(); + void onSunScaleChanged(); + + void onMoonRotationChanged(); + void onMoonAzimElevChanged(); + + void onCloudMapChanged(); + void onWaterMapChanged(); + + void onButtonReset(); + + void onEnvironmentUpdated(LLEnvironment::EnvSelection_t env, S32 version); + + LLSettingsSky::ptr_t mLiveSky; + LLSettingsWater::ptr_t mLiveWater; + LLEnvironment::connection_t mEventConnection; +}; + +#endif // LL_FLOATERFIXEDENVIRONMENT_H diff --git a/indra/newview/llfloaterenvironmentsettings.cpp b/indra/newview/llfloaterenvironmentsettings.cpp deleted file mode 100644 index 4dbc8cdee0..0000000000 --- a/indra/newview/llfloaterenvironmentsettings.cpp +++ /dev/null @@ -1,282 +0,0 @@ -/** - * @file llfloaterenvironmentsettings.cpp - * @brief LLFloaterEnvironmentSettings class 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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llfloaterenvironmentsettings.h" - -#include "llcombobox.h" -#include "llradiogroup.h" - -#include "lldaycyclemanager.h" -#include "llenvmanager.h" -#include "llwaterparammanager.h" -#include "llwlparamset.h" -#include "llwlparammanager.h" - -LLFloaterEnvironmentSettings::LLFloaterEnvironmentSettings(const LLSD &key) -: LLFloater(key) - ,mRegionSettingsRadioGroup(NULL) - ,mDayCycleSettingsRadioGroup(NULL) - ,mWaterPresetCombo(NULL) - ,mSkyPresetCombo(NULL) - ,mDayCyclePresetCombo(NULL) -{ -} - -// virtual -BOOL LLFloaterEnvironmentSettings::postBuild() -{ - mRegionSettingsRadioGroup = getChild<LLRadioGroup>("region_settings_radio_group"); - mRegionSettingsRadioGroup->setCommitCallback(boost::bind(&LLFloaterEnvironmentSettings::onSwitchRegionSettings, this)); - - mDayCycleSettingsRadioGroup = getChild<LLRadioGroup>("sky_dayc_settings_radio_group"); - mDayCycleSettingsRadioGroup->setCommitCallback(boost::bind(&LLFloaterEnvironmentSettings::onSwitchDayCycle, this)); - - mWaterPresetCombo = getChild<LLComboBox>("water_settings_preset_combo"); - mWaterPresetCombo->setCommitCallback(boost::bind(&LLFloaterEnvironmentSettings::onSelectWaterPreset, this)); - - mSkyPresetCombo = getChild<LLComboBox>("sky_settings_preset_combo"); - mSkyPresetCombo->setCommitCallback(boost::bind(&LLFloaterEnvironmentSettings::onSelectSkyPreset, this)); - - mDayCyclePresetCombo = getChild<LLComboBox>("dayc_settings_preset_combo"); - mDayCyclePresetCombo->setCommitCallback(boost::bind(&LLFloaterEnvironmentSettings::onSelectDayCyclePreset, this)); - - childSetCommitCallback("ok_btn", boost::bind(&LLFloaterEnvironmentSettings::onBtnOK, this), NULL); - getChild<LLUICtrl>("ok_btn")->setRightMouseDownCallback(boost::bind(&LLEnvManagerNew::dumpUserPrefs, LLEnvManagerNew::getInstance())); - childSetCommitCallback("cancel_btn", boost::bind(&LLFloaterEnvironmentSettings::onBtnCancel, this), NULL); - getChild<LLUICtrl>("cancel_btn")->setRightMouseDownCallback(boost::bind(&LLEnvManagerNew::dumpPresets, LLEnvManagerNew::getInstance())); - - setCloseCallback(boost::bind(&LLFloaterEnvironmentSettings::cancel, this)); - - LLEnvManagerNew::instance().setPreferencesChangeCallback(boost::bind(&LLFloaterEnvironmentSettings::refresh, this)); - LLDayCycleManager::instance().setModifyCallback(boost::bind(&LLFloaterEnvironmentSettings::populateDayCyclePresetsList, this)); - LLWLParamManager::instance().setPresetListChangeCallback(boost::bind(&LLFloaterEnvironmentSettings::populateSkyPresetsList, this)); - LLWaterParamManager::instance().setPresetListChangeCallback(boost::bind(&LLFloaterEnvironmentSettings::populateWaterPresetsList, this)); - - return TRUE; -} - -// virtual -void LLFloaterEnvironmentSettings::onOpen(const LLSD& key) -{ - refresh(); -} - -void LLFloaterEnvironmentSettings::onSwitchRegionSettings() -{ - getChild<LLView>("user_environment_settings")->setEnabled(mRegionSettingsRadioGroup->getSelectedIndex() != 0); - - apply(); -} - -void LLFloaterEnvironmentSettings::onSwitchDayCycle() -{ - bool is_fixed_sky = mDayCycleSettingsRadioGroup->getSelectedIndex() == 0; - - mSkyPresetCombo->setEnabled(is_fixed_sky); - mDayCyclePresetCombo->setEnabled(!is_fixed_sky); - - apply(); -} - -void LLFloaterEnvironmentSettings::onSelectWaterPreset() -{ - apply(); -} - -void LLFloaterEnvironmentSettings::onSelectSkyPreset() -{ - apply(); -} - -void LLFloaterEnvironmentSettings::onSelectDayCyclePreset() -{ - apply(); -} - -void LLFloaterEnvironmentSettings::onBtnOK() -{ - // Save and apply new user preferences. - bool use_region_settings = mRegionSettingsRadioGroup->getSelectedIndex() == 0; - bool use_fixed_sky = mDayCycleSettingsRadioGroup->getSelectedIndex() == 0; - std::string water_preset = mWaterPresetCombo->getValue().asString(); - std::string sky_preset = mSkyPresetCombo->getValue().asString(); - std::string day_cycle = mDayCyclePresetCombo->getValue().asString(); - - LLEnvManagerNew::instance().setUserPrefs( - water_preset, - sky_preset, - day_cycle, - use_fixed_sky, - use_region_settings); - - // *TODO: This triggers applying user preferences again, which is suboptimal. - closeFloater(); -} - -void LLFloaterEnvironmentSettings::onBtnCancel() -{ - closeFloater(); -} - -void LLFloaterEnvironmentSettings::refresh() -{ - LLEnvManagerNew& env_mgr = LLEnvManagerNew::instance(); - - bool use_region_settings = env_mgr.getUseRegionSettings(); - bool use_fixed_sky = env_mgr.getUseFixedSky(); - - // Set up radio buttons according to user preferences. - mRegionSettingsRadioGroup->setSelectedIndex(use_region_settings ? 0 : 1); - mDayCycleSettingsRadioGroup->setSelectedIndex(use_fixed_sky ? 0 : 1); - - // Populate the combo boxes with appropriate lists of available presets. - populateWaterPresetsList(); - populateSkyPresetsList(); - populateDayCyclePresetsList(); - - // Enable/disable other controls based on user preferences. - getChild<LLView>("user_environment_settings")->setEnabled(!use_region_settings); - mSkyPresetCombo->setEnabled(use_fixed_sky); - mDayCyclePresetCombo->setEnabled(!use_fixed_sky); - - // Select the current presets in combo boxes. - mWaterPresetCombo->selectByValue(env_mgr.getWaterPresetName()); - mSkyPresetCombo->selectByValue(env_mgr.getSkyPresetName()); - mDayCyclePresetCombo->selectByValue(env_mgr.getDayCycleName()); -} - -void LLFloaterEnvironmentSettings::apply() -{ - // Update environment with the user choice. - bool use_region_settings = mRegionSettingsRadioGroup->getSelectedIndex() == 0; - bool use_fixed_sky = mDayCycleSettingsRadioGroup->getSelectedIndex() == 0; - std::string water_preset = mWaterPresetCombo->getValue().asString(); - std::string sky_preset = mSkyPresetCombo->getValue().asString(); - std::string day_cycle = mDayCyclePresetCombo->getValue().asString(); - - LLEnvManagerNew& env_mgr = LLEnvManagerNew::instance(); - if (use_region_settings) - { - env_mgr.useRegionSettings(); - } - else - { - if (use_fixed_sky) - { - env_mgr.useSkyPreset(sky_preset); - } - else - { - env_mgr.useDayCycle(day_cycle, LLEnvKey::SCOPE_LOCAL); - } - - env_mgr.useWaterPreset(water_preset); - } -} - -void LLFloaterEnvironmentSettings::cancel() -{ - // Revert environment to user preferences. - LLEnvManagerNew::instance().usePrefs(); -} - -void LLFloaterEnvironmentSettings::populateWaterPresetsList() -{ - mWaterPresetCombo->removeall(); - - std::list<std::string> user_presets, system_presets; - LLWaterParamManager::instance().getPresetNames(user_presets, system_presets); - - // Add user presets first. - for (std::list<std::string>::const_iterator it = user_presets.begin(); it != user_presets.end(); ++it) - { - mWaterPresetCombo->add(*it); - } - - if (user_presets.size() > 0) - { - mWaterPresetCombo->addSeparator(); - } - - // Add system presets. - for (std::list<std::string>::const_iterator it = system_presets.begin(); it != system_presets.end(); ++it) - { - mWaterPresetCombo->add(*it); - } -} - -void LLFloaterEnvironmentSettings::populateSkyPresetsList() -{ - mSkyPresetCombo->removeall(); - - LLWLParamManager::preset_name_list_t region_presets; // unused as we don't list region presets here - LLWLParamManager::preset_name_list_t user_presets, sys_presets; - LLWLParamManager::instance().getPresetNames(region_presets, user_presets, sys_presets); - - // Add user presets. - for (LLWLParamManager::preset_name_list_t::const_iterator it = user_presets.begin(); it != user_presets.end(); ++it) - { - mSkyPresetCombo->add(*it); - } - - if (!user_presets.empty()) - { - mSkyPresetCombo->addSeparator(); - } - - // Add system presets. - for (LLWLParamManager::preset_name_list_t::const_iterator it = sys_presets.begin(); it != sys_presets.end(); ++it) - { - mSkyPresetCombo->add(*it); - } -} - -void LLFloaterEnvironmentSettings::populateDayCyclePresetsList() -{ - mDayCyclePresetCombo->removeall(); - - LLDayCycleManager::preset_name_list_t user_days, sys_days; - LLDayCycleManager::instance().getPresetNames(user_days, sys_days); - - // Add user days. - for (LLDayCycleManager::preset_name_list_t::const_iterator it = user_days.begin(); it != user_days.end(); ++it) - { - mDayCyclePresetCombo->add(*it); - } - - if (user_days.size() > 0) - { - mDayCyclePresetCombo->addSeparator(); - } - - // Add system days. - for (LLDayCycleManager::preset_name_list_t::const_iterator it = sys_days.begin(); it != sys_days.end(); ++it) - { - mDayCyclePresetCombo->add(*it); - } -} diff --git a/indra/newview/llfloaterenvironmentsettings.h b/indra/newview/llfloaterenvironmentsettings.h deleted file mode 100644 index 0ab458a0f6..0000000000 --- a/indra/newview/llfloaterenvironmentsettings.h +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @file llfloaterenvironmentsettings.h - * @brief LLFloaterEnvironmentSettings class 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_LLFLOATERENVIRONMENTSETTINGS_H -#define LL_LLFLOATERENVIRONMENTSETTINGS_H - -#include "llfloater.h" - -class LLComboBox; -class LLRadioGroup; - -class LLFloaterEnvironmentSettings : public LLFloater -{ - LOG_CLASS(LLFloaterEnvironmentSettings); - -public: - LLFloaterEnvironmentSettings(const LLSD &key); - /*virtual*/ BOOL postBuild(); - /*virtual*/ void onOpen(const LLSD& key); - -private: - void onSwitchRegionSettings(); - void onSwitchDayCycle(); - - void onSelectWaterPreset(); - void onSelectSkyPreset(); - void onSelectDayCyclePreset(); - - void onBtnOK(); - void onBtnCancel(); - - void refresh(); /// update controls with user prefs - void apply(); - void cancel(); - - void populateWaterPresetsList(); - void populateSkyPresetsList(); - void populateDayCyclePresetsList(); - - LLRadioGroup* mRegionSettingsRadioGroup; - LLRadioGroup* mDayCycleSettingsRadioGroup; - - LLComboBox* mWaterPresetCombo; - LLComboBox* mSkyPresetCombo; - LLComboBox* mDayCyclePresetCombo; -}; - -#endif // LL_LLFLOATERENVIRONMENTSETTINGS_H diff --git a/indra/newview/llfloaterevent.cpp b/indra/newview/llfloaterevent.cpp index 3e303e0932..a6640cc073 100644 --- a/indra/newview/llfloaterevent.cpp +++ b/indra/newview/llfloaterevent.cpp @@ -110,7 +110,7 @@ void LLFloaterEvent::setEventID(const U32 event_id) // get the search URL and expand all of the substitutions // (also adds things like [LANGUAGE], [VERSION], [OS], etc.) std::ostringstream url; - url << gSavedSettings.getString("EventURL") << event_id << "/" << std::endl; + url << gSavedSettings.getString("EventURL") << event_id << std::endl; // and load the URL in the web view mBrowser->navigateTo(url.str()); diff --git a/indra/newview/llfloaterexperiencepicker.cpp b/indra/newview/llfloaterexperiencepicker.cpp index bb54c57baf..c642da7b83 100644 --- a/indra/newview/llfloaterexperiencepicker.cpp +++ b/indra/newview/llfloaterexperiencepicker.cpp @@ -74,59 +74,8 @@ LLFloaterExperiencePicker* LLFloaterExperiencePicker::show( select_callback_t ca 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(GL_CULL_FACE); - gGL.begin(LLRender::QUADS); - { - gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop); - 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.mTop); - gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - - gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * 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, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom); - 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.mBottom); - 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.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.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.vertex2i(origin_rect.mLeft, origin_rect.mBottom); - } - gGL.end(); - } - - if (gFocusMgr.childHasMouseCapture(getDragHandle())) - { - mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(mContextConeFadeTime)); - } - else - { - mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(mContextConeFadeTime)); - } - } + static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f); + drawConeToOwner(mContextConeOpacity, max_opacity, mFrustumOrigin.get(), mContextConeFadeTime, mContextConeInAlpha, mContextConeOutAlpha); } void LLFloaterExperiencePicker::draw() diff --git a/indra/newview/llfloaterexperienceprofile.cpp b/indra/newview/llfloaterexperienceprofile.cpp index 2c9a8e64b7..a99a096ea7 100644 --- a/indra/newview/llfloaterexperienceprofile.cpp +++ b/indra/newview/llfloaterexperienceprofile.cpp @@ -211,6 +211,20 @@ bool LLFloaterExperienceProfile::experiencePermission( LLHandle<LLFloaterExperie return false; } +bool LLFloaterExperienceProfile::matchesKey(const LLSD& key) +{ + if (key.has("experience_id")) + { + return mExperienceId == key["experience_id"].asUUID(); + } + else if (key.isUUID()) + { + return mExperienceId == key.asUUID(); + } + // Assume NULL uuid + return mExperienceId.isNull(); +} + void LLFloaterExperienceProfile::onClickEdit() { diff --git a/indra/newview/llfloaterexperienceprofile.h b/indra/newview/llfloaterexperienceprofile.h index 1394418d91..f9b6e2e2eb 100644 --- a/indra/newview/llfloaterexperienceprofile.h +++ b/indra/newview/llfloaterexperienceprofile.h @@ -51,6 +51,8 @@ public: LLFloaterExperienceProfile(const LLSD& data); virtual ~LLFloaterExperienceProfile(); + + /* virtual */ bool matchesKey(const LLSD& key); LLUUID getExperienceId() const { return mExperienceId; } void setPreferences( const LLSD& content ); diff --git a/indra/newview/llfloaterexperiences.cpp b/indra/newview/llfloaterexperiences.cpp index fdc1b47334..184e39402a 100644 --- a/indra/newview/llfloaterexperiences.cpp +++ b/indra/newview/llfloaterexperiences.cpp @@ -74,10 +74,6 @@ BOOL LLFloaterExperiences::postBuild() getChild<LLTabContainer>("xp_tabs")->addTabPanel(new LLPanelExperienceLog()); resizeToTabs(); - - LLEventPumps::instance().obtain("experience_permission").listen("LLFloaterExperiences", - boost::bind(&LLFloaterExperiences::updatePermissions, this, _1)); - return TRUE; } @@ -163,6 +159,10 @@ void LLFloaterExperiences::refreshContents() void LLFloaterExperiences::onOpen( const LLSD& key ) { + 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) { diff --git a/indra/newview/llfloaterfixedenvironment.cpp b/indra/newview/llfloaterfixedenvironment.cpp new file mode 100644 index 0000000000..4f2c36f45b --- /dev/null +++ b/indra/newview/llfloaterfixedenvironment.cpp @@ -0,0 +1,554 @@ +/** + * @file llfloaterfixedenvironment.cpp + * @brief Floaters to create and edit fixed settings for sky and water. + * + * $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 "llfloaterfixedenvironment.h" + +#include <boost/make_shared.hpp> + +// libs +#include "llbutton.h" +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llsliderctrl.h" +#include "lltabcontainer.h" +#include "llfilepicker.h" +#include "lllocalbitmaps.h" +#include "llsettingspicker.h" +#include "llviewermenufile.h" // LLFilePickerReplyThread +#include "llviewerparcelmgr.h" + +// newview +#include "llpaneleditwater.h" +#include "llpaneleditsky.h" + +#include "llsettingssky.h" +#include "llsettingswater.h" + +#include "llenvironment.h" +#include "llagent.h" +#include "llparcel.h" +#include "lltrans.h" + +#include "llsettingsvo.h" +#include "llinventorymodel.h" + +extern LLControlGroup gSavedSettings; + +namespace +{ + const std::string FIELD_SETTINGS_NAME("settings_name"); + + const std::string CONTROL_TAB_AREA("tab_settings"); + + const std::string BUTTON_NAME_IMPORT("btn_import"); + const std::string BUTTON_NAME_COMMIT("btn_commit"); + const std::string BUTTON_NAME_CANCEL("btn_cancel"); + const std::string BUTTON_NAME_FLYOUT("btn_flyout"); + const std::string BUTTON_NAME_LOAD("btn_load"); + + const std::string ACTION_SAVE("save_settings"); + const std::string ACTION_SAVEAS("save_as_new_settings"); + const std::string ACTION_COMMIT("commit_changes"); + const std::string ACTION_APPLY_LOCAL("apply_local"); + const std::string ACTION_APPLY_PARCEL("apply_parcel"); + const std::string ACTION_APPLY_REGION("apply_region"); + + const std::string XML_FLYOUTMENU_FILE("menu_save_settings.xml"); +} + + +//========================================================================= +LLFloaterFixedEnvironment::LLFloaterFixedEnvironment(const LLSD &key) : + LLFloaterEditEnvironmentBase(key), + mFlyoutControl(nullptr) +{ +} + +LLFloaterFixedEnvironment::~LLFloaterFixedEnvironment() +{ + delete mFlyoutControl; +} + +BOOL LLFloaterFixedEnvironment::postBuild() +{ + mTab = getChild<LLTabContainer>(CONTROL_TAB_AREA); + mTxtName = getChild<LLLineEditor>(FIELD_SETTINGS_NAME); + + mTxtName->setCommitOnFocusLost(TRUE); + mTxtName->setCommitCallback([this](LLUICtrl *, const LLSD &) { onNameChanged(mTxtName->getValue().asString()); }); + + getChild<LLButton>(BUTTON_NAME_IMPORT)->setClickedCallback([this](LLUICtrl *, const LLSD &) { onButtonImport(); }); + getChild<LLButton>(BUTTON_NAME_CANCEL)->setClickedCallback([this](LLUICtrl *, const LLSD &) { onClickCloseBtn(); }); + getChild<LLButton>(BUTTON_NAME_LOAD)->setClickedCallback([this](LLUICtrl *, const LLSD &) { onButtonLoad(); }); + + mFlyoutControl = new LLFlyoutComboBtnCtrl(this, BUTTON_NAME_COMMIT, BUTTON_NAME_FLYOUT, XML_FLYOUTMENU_FILE, false); + mFlyoutControl->setAction([this](LLUICtrl *ctrl, const LLSD &data) { onButtonApply(ctrl, data); }); + mFlyoutControl->setMenuItemVisible(ACTION_COMMIT, false); + + return TRUE; +} + +void LLFloaterFixedEnvironment::onOpen(const LLSD& key) +{ + LLUUID invid; + + if (key.has(KEY_INVENTORY_ID)) + { + invid = key[KEY_INVENTORY_ID].asUUID(); + } + + loadInventoryItem(invid); + LL_INFOS("SETTINGS") << "Setting edit inventory item to " << mInventoryId << "." << LL_ENDL; + + updateEditEnvironment(); + syncronizeTabs(); + refresh(); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_EDIT, LLEnvironment::TRANSITION_INSTANT); + +} + +void LLFloaterFixedEnvironment::onClose(bool app_quitting) +{ + doCloseInventoryFloater(app_quitting); + + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL); + LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_EDIT); + + mSettings.reset(); + syncronizeTabs(); +} + +void LLFloaterFixedEnvironment::refresh() +{ + if (!mSettings) + { + // disable everything. + return; + } + + bool is_inventory_avail = canUseInventory(); + + mFlyoutControl->setMenuItemEnabled(ACTION_SAVE, is_inventory_avail && mCanMod && !mInventoryId.isNull()); + mFlyoutControl->setMenuItemEnabled(ACTION_SAVEAS, is_inventory_avail && mCanCopy); + mFlyoutControl->setMenuItemEnabled(ACTION_APPLY_PARCEL, canApplyParcel()); + mFlyoutControl->setMenuItemEnabled(ACTION_APPLY_REGION, canApplyRegion()); + + mTxtName->setValue(mSettings->getName()); + mTxtName->setEnabled(mCanMod); + + S32 count = mTab->getTabCount(); + + for (S32 idx = 0; idx < count; ++idx) + { + LLSettingsEditPanel *panel = static_cast<LLSettingsEditPanel *>(mTab->getPanelByIndex(idx)); + if (panel) + { + panel->setCanChangeSettings(mCanMod); + panel->refresh(); + } + } +} + +void LLFloaterFixedEnvironment::setEditSettingsAndUpdate(const LLSettingsBase::ptr_t &settings) +{ + mSettings = settings; // shouldn't this do buildDeepCloneAndUncompress() ? + updateEditEnvironment(); + syncronizeTabs(); + refresh(); + LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); +} + +void LLFloaterFixedEnvironment::syncronizeTabs() +{ + S32 count = mTab->getTabCount(); + + for (S32 idx = 0; idx < count; ++idx) + { + LLSettingsEditPanel *panel = static_cast<LLSettingsEditPanel *>(mTab->getPanelByIndex(idx)); + if (panel) + panel->setSettings(mSettings); + } +} + +LLFloaterSettingsPicker * LLFloaterFixedEnvironment::getSettingsPicker() +{ + LLFloaterSettingsPicker *picker = static_cast<LLFloaterSettingsPicker *>(mInventoryFloater.get()); + + // Show the dialog + if (!picker) + { + picker = new LLFloaterSettingsPicker(this, + LLUUID::null); + + mInventoryFloater = picker->getHandle(); + + picker->setCommitCallback([this](LLUICtrl *, const LLSD &data){ onPickerCommitSetting(data["ItemId"].asUUID() /*data["Track"]*/); }); + } + + return picker; +} + +void LLFloaterFixedEnvironment::onPickerCommitSetting(LLUUID item_id) +{ + loadInventoryItem(item_id); +} + +void LLFloaterFixedEnvironment::onNameChanged(const std::string &name) +{ + mSettings->setName(name); + setDirtyFlag(); +} + +void LLFloaterFixedEnvironment::onButtonImport() +{ + checkAndConfirmSettingsLoss([this](){ doImportFromDisk(); }); +} + +void LLFloaterFixedEnvironment::onButtonApply(LLUICtrl *ctrl, const LLSD &data) +{ + std::string ctrl_action = ctrl->getName(); + + std::string local_desc; + LLSettingsBase::ptr_t setting_clone; + bool is_local = false; // because getString can be empty + if (mSettings->getSettingsType() == "water") + { + LLSettingsWater::ptr_t water = std::static_pointer_cast<LLSettingsWater>(mSettings); + if (water) + { + setting_clone = water->buildClone(); + // LLViewerFetchedTexture and check for FTT_LOCAL_FILE or check LLLocalBitmapMgr + if (LLLocalBitmapMgr::getInstance()->isLocal(water->getNormalMapID())) + { + local_desc = LLTrans::getString("EnvironmentNormalMap"); + is_local = true; + } + else if (LLLocalBitmapMgr::getInstance()->isLocal(water->getTransparentTextureID())) + { + local_desc = LLTrans::getString("EnvironmentTransparent"); + is_local = true; + } + } + } + else if (mSettings->getSettingsType() == "sky") + { + LLSettingsSky::ptr_t sky = std::static_pointer_cast<LLSettingsSky>(mSettings); + if (sky) + { + setting_clone = sky->buildClone(); + if (LLLocalBitmapMgr::getInstance()->isLocal(sky->getSunTextureId())) + { + local_desc = LLTrans::getString("EnvironmentSun"); + is_local = true; + } + else if (LLLocalBitmapMgr::getInstance()->isLocal(sky->getMoonTextureId())) + { + local_desc = LLTrans::getString("EnvironmentMoon"); + is_local = true; + } + else if (LLLocalBitmapMgr::getInstance()->isLocal(sky->getCloudNoiseTextureId())) + { + local_desc = LLTrans::getString("EnvironmentCloudNoise"); + is_local = true; + } + else if (LLLocalBitmapMgr::getInstance()->isLocal(sky->getBloomTextureId())) + { + local_desc = LLTrans::getString("EnvironmentBloom"); + is_local = true; + } + } + } + + if (is_local) + { + LLSD args; + args["FIELD"] = local_desc; + LLNotificationsUtil::add("WLLocalTextureFixedBlock", args); + return; + } + + if (ctrl_action == ACTION_SAVE) + { + doApplyUpdateInventory(setting_clone); + } + else if (ctrl_action == ACTION_SAVEAS) + { + LLSD args; + args["DESC"] = mSettings->getName(); + LLNotificationsUtil::add("SaveSettingAs", args, LLSD(), boost::bind(&LLFloaterFixedEnvironment::onSaveAsCommit, this, _1, _2, setting_clone)); + } + else if ((ctrl_action == ACTION_APPLY_LOCAL) || + (ctrl_action == ACTION_APPLY_PARCEL) || + (ctrl_action == ACTION_APPLY_REGION)) + { + doApplyEnvironment(ctrl_action, setting_clone); + } + else + { + LL_WARNS("ENVIRONMENT") << "Unknown settings action '" << ctrl_action << "'" << LL_ENDL; + } +} + +void LLFloaterFixedEnvironment::onClickCloseBtn(bool app_quitting) +{ + if (!app_quitting) + checkAndConfirmSettingsLoss([this](){ closeFloater(); clearDirtyFlag(); }); + else + closeFloater(); +} + +void LLFloaterFixedEnvironment::onButtonLoad() +{ + checkAndConfirmSettingsLoss([this](){ doSelectFromInventory(); }); +} + +void LLFloaterFixedEnvironment::onInventoryCreated(LLUUID asset_id, LLUUID inventory_id, LLSD results) +{ + LL_WARNS("ENVIRONMENT") << "Inventory item " << inventory_id << " has been created with asset " << asset_id << " results are:" << results << LL_ENDL; + + if (inventory_id.isNull() || !results["success"].asBoolean()) + { + LLNotificationsUtil::add("CantCreateInventory"); + return; + } + onInventoryCreated(asset_id, inventory_id); +} + +void LLFloaterFixedEnvironment::onInventoryCreated(LLUUID asset_id, LLUUID inventory_id) +{ + bool can_trans = true; + if (mInventoryItem) + { + LLPermissions perms = mInventoryItem->getPermissions(); + + LLInventoryItem *created_item = gInventory.getItem(mInventoryId); + + if (created_item) + { + can_trans = perms.allowOperationBy(PERM_TRANSFER, gAgent.getID()); + created_item->setPermissions(perms); + created_item->updateServer(false); + } + } + clearDirtyFlag(); + setFocus(TRUE); // Call back the focus... + loadInventoryItem(inventory_id, can_trans); +} + +void LLFloaterFixedEnvironment::onInventoryUpdated(LLUUID asset_id, LLUUID inventory_id, LLSD results) +{ + LL_WARNS("ENVIRONMENT") << "Inventory item " << inventory_id << " has been updated with asset " << asset_id << " results are:" << results << LL_ENDL; + + clearDirtyFlag(); + if (inventory_id != mInventoryId) + { + loadInventoryItem(inventory_id); + } +} + + +void LLFloaterFixedEnvironment::clearDirtyFlag() +{ + mIsDirty = false; + + S32 count = mTab->getTabCount(); + + for (S32 idx = 0; idx < count; ++idx) + { + LLSettingsEditPanel *panel = static_cast<LLSettingsEditPanel *>(mTab->getPanelByIndex(idx)); + if (panel) + panel->clearIsDirty(); + } + +} + +void LLFloaterFixedEnvironment::doSelectFromInventory() +{ + LLFloaterSettingsPicker *picker = getSettingsPicker(); + + picker->setSettingsFilter(mSettings->getSettingsTypeValue()); + picker->openFloater(); + picker->setFocus(TRUE); +} + +//========================================================================= +LLFloaterFixedEnvironmentWater::LLFloaterFixedEnvironmentWater(const LLSD &key): + LLFloaterFixedEnvironment(key) +{} + +BOOL LLFloaterFixedEnvironmentWater::postBuild() +{ + if (!LLFloaterFixedEnvironment::postBuild()) + return FALSE; + + LLPanelSettingsWater * panel; + panel = new LLPanelSettingsWaterMainTab; + panel->buildFromFile("panel_settings_water.xml"); + panel->setWater(std::static_pointer_cast<LLSettingsWater>(mSettings)); + panel->setOnDirtyFlagChanged( [this] (LLPanel *, bool value) { onPanelDirtyFlagChanged(value); }); + mTab->addTabPanel(LLTabContainer::TabPanelParams().panel(panel).select_tab(true)); + + return TRUE; +} + +void LLFloaterFixedEnvironmentWater::updateEditEnvironment(void) +{ + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_EDIT, + std::static_pointer_cast<LLSettingsWater>(mSettings)); +} + +void LLFloaterFixedEnvironmentWater::onOpen(const LLSD& key) +{ + if (!mSettings) + { + // Initialize the settings, take a snapshot of the current water. + mSettings = LLEnvironment::instance().getEnvironmentFixedWater(LLEnvironment::ENV_CURRENT)->buildClone(); + mSettings->setName("Snapshot water (new)"); + + // TODO: Should we grab sky and keep it around for reference? + } + + LLFloaterFixedEnvironment::onOpen(key); +} + +void LLFloaterFixedEnvironmentWater::doImportFromDisk() +{ // Load a a legacy Windlight XML from disk. + (new LLFilePickerReplyThread(boost::bind(&LLFloaterFixedEnvironmentWater::loadWaterSettingFromFile, this, _1), LLFilePicker::FFLOAD_XML, false))->getFile(); +} + +void LLFloaterFixedEnvironmentWater::loadWaterSettingFromFile(const std::vector<std::string>& filenames) +{ + LLSD messages; + if (filenames.size() < 1) return; + std::string filename = filenames[0]; + LL_DEBUGS("ENVEDIT") << "Selected file: " << filename << LL_ENDL; + LLSettingsWater::ptr_t legacywater = LLEnvironment::createWaterFromLegacyPreset(filename, messages); + + if (!legacywater) + { + LLNotificationsUtil::add("WLImportFail", messages); + return; + } + + loadInventoryItem(LLUUID::null); + + setDirtyFlag(); + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_EDIT, legacywater); + setEditSettings(legacywater); + LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT, true); +} + +//========================================================================= +LLFloaterFixedEnvironmentSky::LLFloaterFixedEnvironmentSky(const LLSD &key) : + LLFloaterFixedEnvironment(key) +{} + +BOOL LLFloaterFixedEnvironmentSky::postBuild() +{ + if (!LLFloaterFixedEnvironment::postBuild()) + return FALSE; + + LLPanelSettingsSky * panel; + panel = new LLPanelSettingsSkyAtmosTab; + panel->buildFromFile("panel_settings_sky_atmos.xml"); + panel->setSky(std::static_pointer_cast<LLSettingsSky>(mSettings)); + panel->setOnDirtyFlagChanged([this](LLPanel *, bool value) { onPanelDirtyFlagChanged(value); }); + mTab->addTabPanel(LLTabContainer::TabPanelParams().panel(panel).select_tab(true)); + + panel = new LLPanelSettingsSkyCloudTab; + panel->buildFromFile("panel_settings_sky_clouds.xml"); + panel->setSky(std::static_pointer_cast<LLSettingsSky>(mSettings)); + panel->setOnDirtyFlagChanged([this](LLPanel *, bool value) { onPanelDirtyFlagChanged(value); }); + mTab->addTabPanel(LLTabContainer::TabPanelParams().panel(panel).select_tab(false)); + + panel = new LLPanelSettingsSkySunMoonTab; + panel->buildFromFile("panel_settings_sky_sunmoon.xml"); + panel->setSky(std::static_pointer_cast<LLSettingsSky>(mSettings)); + panel->setOnDirtyFlagChanged([this](LLPanel *, bool value) { onPanelDirtyFlagChanged(value); }); + mTab->addTabPanel(LLTabContainer::TabPanelParams().panel(panel).select_tab(false)); + + return TRUE; +} + +void LLFloaterFixedEnvironmentSky::updateEditEnvironment(void) +{ + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_EDIT, + std::static_pointer_cast<LLSettingsSky>(mSettings)); +} + +void LLFloaterFixedEnvironmentSky::onOpen(const LLSD& key) +{ + if (!mSettings) + { + // Initialize the settings, take a snapshot of the current water. + mSettings = LLEnvironment::instance().getEnvironmentFixedSky(LLEnvironment::ENV_CURRENT)->buildClone(); + mSettings->setName("Snapshot sky (new)"); + LLEnvironment::instance().saveBeaconsState(); + // TODO: Should we grab water and keep it around for reference? + } + + LLFloaterFixedEnvironment::onOpen(key); +} + +void LLFloaterFixedEnvironmentSky::onClose(bool app_quitting) +{ + LLEnvironment::instance().revertBeaconsState(); + + LLFloaterFixedEnvironment::onClose(app_quitting); +} + +void LLFloaterFixedEnvironmentSky::doImportFromDisk() +{ // Load a a legacy Windlight XML from disk. + (new LLFilePickerReplyThread(boost::bind(&LLFloaterFixedEnvironmentSky::loadSkySettingFromFile, this, _1), LLFilePicker::FFLOAD_XML, false))->getFile(); +} + +void LLFloaterFixedEnvironmentSky::loadSkySettingFromFile(const std::vector<std::string>& filenames) +{ + if (filenames.size() < 1) return; + std::string filename = filenames[0]; + LLSD messages; + + LL_DEBUGS("ENVEDIT") << "Selected file: " << filename << LL_ENDL; + LLSettingsSky::ptr_t legacysky = LLEnvironment::createSkyFromLegacyPreset(filename, messages); + + if (!legacysky) + { + LLNotificationsUtil::add("WLImportFail", messages); + + return; + } + + loadInventoryItem(LLUUID::null); + + setDirtyFlag(); + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_EDIT, legacysky); + setEditSettings(legacysky); + LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT, true); +} + +//========================================================================= diff --git a/indra/newview/llfloaterfixedenvironment.h b/indra/newview/llfloaterfixedenvironment.h new file mode 100644 index 0000000000..f35f4a4368 --- /dev/null +++ b/indra/newview/llfloaterfixedenvironment.h @@ -0,0 +1,138 @@ +/** + * @file llfloaterfixedenvironment.h + * @brief Floaters to create and edit fixed settings for sky and water. + * + * $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_FLOATERFIXEDENVIRONMENT_H +#define LL_FLOATERFIXEDENVIRONMENT_H + +#include "llfloatereditenvironmentbase.h" +#include "llsettingsbase.h" +#include "llflyoutcombobtn.h" +#include "llinventory.h" + +#include "boost/signals2.hpp" + +class LLTabContainer; +class LLButton; +class LLLineEditor; +class LLFloaterSettingsPicker; +class LLFixedSettingCopiedCallback; + +/** + * Floater container for creating and editing fixed environment settings. + */ +class LLFloaterFixedEnvironment : public LLFloaterEditEnvironmentBase +{ + LOG_CLASS(LLFloaterFixedEnvironment); +public: + LLFloaterFixedEnvironment(const LLSD &key); + ~LLFloaterFixedEnvironment(); + + virtual BOOL postBuild() override; + virtual void onOpen(const LLSD& key) override; + virtual void onClose(bool app_quitting) override; + + void setEditSettings(const LLSettingsBase::ptr_t &settings) { mSettings = settings; clearDirtyFlag(); syncronizeTabs(); refresh(); } + virtual LLSettingsBase::ptr_t getEditSettings() const override { return mSettings; } + +protected: + typedef std::function<void()> on_confirm_fn; + + virtual void refresh() override; + void setEditSettingsAndUpdate(const LLSettingsBase::ptr_t &settings) override; + virtual void syncronizeTabs(); + + virtual LLFloaterSettingsPicker *getSettingsPicker() override; + + LLTabContainer * mTab; + LLLineEditor * mTxtName; + + LLSettingsBase::ptr_t mSettings; + + LLFlyoutComboBtnCtrl * mFlyoutControl; + + void onInventoryCreated(LLUUID asset_id, LLUUID inventory_id); + void onInventoryCreated(LLUUID asset_id, LLUUID inventory_id, LLSD results); + void onInventoryUpdated(LLUUID asset_id, LLUUID inventory_id, LLSD results); + + virtual void clearDirtyFlag() override; + void updatePermissionFlags(); + + void doSelectFromInventory(); + + virtual void onClickCloseBtn(bool app_quitting = false) override; + +private: + void onNameChanged(const std::string &name); + + void onButtonImport(); + void onButtonApply(LLUICtrl *ctrl, const LLSD &data); + void onButtonLoad(); + + void onPickerCommitSetting(LLUUID item_id); +}; + +class LLFloaterFixedEnvironmentWater : public LLFloaterFixedEnvironment +{ + LOG_CLASS(LLFloaterFixedEnvironmentWater); + +public: + LLFloaterFixedEnvironmentWater(const LLSD &key); + + BOOL postBuild() override; + + virtual void onOpen(const LLSD& key) override; + +protected: + virtual void updateEditEnvironment() override; + + virtual void doImportFromDisk() override; + void loadWaterSettingFromFile(const std::vector<std::string>& filenames); + +private: +}; + +class LLFloaterFixedEnvironmentSky : public LLFloaterFixedEnvironment +{ + LOG_CLASS(LLFloaterFixedEnvironmentSky); + +public: + LLFloaterFixedEnvironmentSky(const LLSD &key); + + BOOL postBuild() override; + + virtual void onOpen(const LLSD& key) override; + virtual void onClose(bool app_quitting) override; + +protected: + virtual void updateEditEnvironment() override; + + virtual void doImportFromDisk() override; + void loadSkySettingFromFile(const std::vector<std::string>& filenames); + +private: +}; + +#endif // LL_FLOATERFIXEDENVIRONMENT_H diff --git a/indra/newview/llfloaterflickr.cpp b/indra/newview/llfloaterflickr.cpp deleted file mode 100644 index 69a92b2b54..0000000000 --- a/indra/newview/llfloaterflickr.cpp +++ /dev/null @@ -1,787 +0,0 @@ -/** -* @file llfloaterflickr.cpp -* @brief Implementation of llfloaterflickr -* @author cho@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 "llfloaterflickr.h" - -#include "llagent.h" -#include "llagentui.h" -#include "llcheckboxctrl.h" -#include "llcombobox.h" -#include "llflickrconnect.h" -#include "llfloaterreg.h" -#include "lliconctrl.h" -#include "llimagefiltersmanager.h" -#include "llresmgr.h" // LLLocale -#include "llsdserialize.h" -#include "llloadingindicator.h" -#include "llslurl.h" -#include "lltrans.h" -#include "llsnapshotlivepreview.h" -#include "llfloaterbigpreview.h" -#include "llviewerregion.h" -#include "llviewercontrol.h" -#include "llviewermedia.h" -#include "lltabcontainer.h" -#include "llviewerparcelmgr.h" -#include "llviewerregion.h" -#include <boost/regex.hpp> -static LLPanelInjector<LLFlickrPhotoPanel> t_panel_photo("llflickrphotopanel"); -static LLPanelInjector<LLFlickrAccountPanel> t_panel_account("llflickraccountpanel"); - -const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=flickr&utm_medium=photo&utm_campaign=slshare"; -const std::string DEFAULT_TAG_TEXT = "secondlife "; -const std::string FLICKR_MACHINE_TAGS_NAMESPACE = "secondlife"; - -/////////////////////////// -//LLFlickrPhotoPanel/////// -/////////////////////////// - -LLFlickrPhotoPanel::LLFlickrPhotoPanel() : -mResolutionComboBox(NULL), -mRefreshBtn(NULL), -mBtnPreview(NULL), -mWorkingLabel(NULL), -mThumbnailPlaceholder(NULL), -mTitleTextBox(NULL), -mDescriptionTextBox(NULL), -mLocationCheckbox(NULL), -mTagsTextBox(NULL), -mRatingComboBox(NULL), -mBigPreviewFloater(NULL), -mPostButton(NULL) -{ - mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", boost::bind(&LLFlickrPhotoPanel::onSend, this)); - mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", boost::bind(&LLFlickrPhotoPanel::onClickNewSnapshot, this)); - mCommitCallbackRegistrar.add("SocialSharing.BigPreview", boost::bind(&LLFlickrPhotoPanel::onClickBigPreview, this)); -} - -LLFlickrPhotoPanel::~LLFlickrPhotoPanel() -{ - if(mPreviewHandle.get()) - { - mPreviewHandle.get()->die(); - } -} - -BOOL LLFlickrPhotoPanel::postBuild() -{ - setVisibleCallback(boost::bind(&LLFlickrPhotoPanel::onVisibilityChange, this, _2)); - - mResolutionComboBox = getChild<LLUICtrl>("resolution_combobox"); - mResolutionComboBox->setCommitCallback(boost::bind(&LLFlickrPhotoPanel::updateResolution, this, TRUE)); - mFilterComboBox = getChild<LLUICtrl>("filters_combobox"); - mFilterComboBox->setCommitCallback(boost::bind(&LLFlickrPhotoPanel::updateResolution, this, TRUE)); - mRefreshBtn = getChild<LLUICtrl>("new_snapshot_btn"); - mBtnPreview = getChild<LLButton>("big_preview_btn"); - mWorkingLabel = getChild<LLUICtrl>("working_lbl"); - mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder"); - mTitleTextBox = getChild<LLUICtrl>("photo_title"); - mDescriptionTextBox = getChild<LLUICtrl>("photo_description"); - mLocationCheckbox = getChild<LLUICtrl>("add_location_cb"); - mTagsTextBox = getChild<LLUICtrl>("photo_tags"); - mTagsTextBox->setValue(DEFAULT_TAG_TEXT); - mRatingComboBox = getChild<LLUICtrl>("rating_combobox"); - mPostButton = getChild<LLUICtrl>("post_photo_btn"); - mCancelButton = getChild<LLUICtrl>("cancel_photo_btn"); - mBigPreviewFloater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview")); - - // Update filter list - std::vector<std::string> filter_list = LLImageFiltersManager::getInstance()->getFiltersList(); - LLComboBox* filterbox = static_cast<LLComboBox *>(mFilterComboBox); - for (U32 i = 0; i < filter_list.size(); i++) - { - filterbox->add(filter_list[i]); - } - - return LLPanel::postBuild(); -} - -// virtual -S32 LLFlickrPhotoPanel::notify(const LLSD& info) -{ - if (info.has("snapshot-updating")) - { - // Disable the Post button and whatever else while the snapshot is not updated - // updateControls(); - return 1; - } - - if (info.has("snapshot-updated")) - { - // Enable the send/post/save buttons. - updateControls(); - - // The refresh button is initially hidden. We show it after the first update, - // i.e. after snapshot is taken - LLUICtrl * refresh_button = getRefreshBtn(); - if (!refresh_button->getVisible()) - { - refresh_button->setVisible(true); - } - return 1; - } - - return 0; -} - -void LLFlickrPhotoPanel::draw() -{ - LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get()); - - // Enable interaction only if no transaction with the service is on-going (prevent duplicated posts) - bool no_ongoing_connection = !(LLFlickrConnect::instance().isTransactionOngoing()); - mCancelButton->setEnabled(no_ongoing_connection); - mTitleTextBox->setEnabled(no_ongoing_connection); - mDescriptionTextBox->setEnabled(no_ongoing_connection); - mTagsTextBox->setEnabled(no_ongoing_connection); - mRatingComboBox->setEnabled(no_ongoing_connection); - mResolutionComboBox->setEnabled(no_ongoing_connection); - mFilterComboBox->setEnabled(no_ongoing_connection); - mRefreshBtn->setEnabled(no_ongoing_connection); - mBtnPreview->setEnabled(no_ongoing_connection); - mLocationCheckbox->setEnabled(no_ongoing_connection); - - // Reassign the preview floater if we have the focus and the preview exists - if (hasFocus() && isPreviewVisible()) - { - attachPreview(); - } - - // Toggle the button state as appropriate - bool preview_active = (isPreviewVisible() && mBigPreviewFloater->isFloaterOwner(getParentByType<LLFloater>())); - mBtnPreview->setToggleState(preview_active); - - // Display the preview if one is available - if (previewp && previewp->getThumbnailImage()) - { - const LLRect& thumbnail_rect = mThumbnailPlaceholder->getRect(); - const S32 thumbnail_w = previewp->getThumbnailWidth(); - const S32 thumbnail_h = previewp->getThumbnailHeight(); - - // calc preview offset within the preview rect - const S32 local_offset_x = (thumbnail_rect.getWidth() - thumbnail_w) / 2 ; - const S32 local_offset_y = (thumbnail_rect.getHeight() - thumbnail_h) / 2 ; - S32 offset_x = thumbnail_rect.mLeft + local_offset_x; - S32 offset_y = thumbnail_rect.mBottom + local_offset_y; - - gGL.matrixMode(LLRender::MM_MODELVIEW); - // Apply floater transparency to the texture unless the floater is focused. - F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency(); - LLColor4 color = LLColor4::white; - gl_draw_scaled_image(offset_x, offset_y, - thumbnail_w, thumbnail_h, - previewp->getThumbnailImage(), color % alpha); - } - - // Update the visibility of the working (computing preview) label - mWorkingLabel->setVisible(!(previewp && previewp->getSnapshotUpToDate())); - - // Enable Post if we have a preview to send and no on going connection being processed - mPostButton->setEnabled(no_ongoing_connection && (previewp && previewp->getSnapshotUpToDate())); - - // Draw the rest of the panel on top of it - LLPanel::draw(); -} - -LLSnapshotLivePreview* LLFlickrPhotoPanel::getPreviewView() -{ - LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)mPreviewHandle.get(); - return previewp; -} - -void LLFlickrPhotoPanel::onVisibilityChange(BOOL visible) -{ - if (visible) - { - if (mPreviewHandle.get()) - { - LLSnapshotLivePreview* preview = getPreviewView(); - if(preview) - { - LL_DEBUGS() << "opened, updating snapshot" << LL_ENDL; - preview->updateSnapshot(TRUE); - } - } - else - { - LLRect full_screen_rect = getRootView()->getRect(); - LLSnapshotLivePreview::Params p; - p.rect(full_screen_rect); - LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p); - mPreviewHandle = previewp->getHandle(); - - previewp->setContainer(this); - previewp->setSnapshotType(LLSnapshotModel::SNAPSHOT_WEB); - previewp->setSnapshotFormat(LLSnapshotModel::SNAPSHOT_FORMAT_PNG); - previewp->setThumbnailSubsampled(TRUE); // We want the preview to reflect the *saved* image - previewp->setAllowRenderUI(FALSE); // We do not want the rendered UI in our snapshots - previewp->setAllowFullScreenPreview(FALSE); // No full screen preview in SL Share mode - previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect()); - - updateControls(); - } - } -} - -void LLFlickrPhotoPanel::onClickNewSnapshot() -{ - LLSnapshotLivePreview* previewp = getPreviewView(); - if (previewp) - { - previewp->updateSnapshot(TRUE); - } -} - -void LLFlickrPhotoPanel::onClickBigPreview() -{ - // Toggle the preview - if (isPreviewVisible()) - { - LLFloaterReg::hideInstance("big_preview"); - } - else - { - attachPreview(); - LLFloaterReg::showInstance("big_preview"); - } -} - -bool LLFlickrPhotoPanel::isPreviewVisible() -{ - return (mBigPreviewFloater && mBigPreviewFloater->getVisible()); -} - -void LLFlickrPhotoPanel::attachPreview() -{ - if (mBigPreviewFloater) - { - LLSnapshotLivePreview* previewp = getPreviewView(); - mBigPreviewFloater->setPreview(previewp); - mBigPreviewFloater->setFloaterOwner(getParentByType<LLFloater>()); - } -} - -void LLFlickrPhotoPanel::onSend() -{ - LLEventPumps::instance().obtain("FlickrConnectState").stopListening("LLFlickrPhotoPanel"); // just in case it is already listening - LLEventPumps::instance().obtain("FlickrConnectState").listen("LLFlickrPhotoPanel", boost::bind(&LLFlickrPhotoPanel::onFlickrConnectStateChange, this, _1)); - - // Connect to Flickr if necessary and then post - if (LLFlickrConnect::instance().isConnected()) - { - sendPhoto(); - } - else - { - LLFlickrConnect::instance().checkConnectionToFlickr(true); - } -} - -bool LLFlickrPhotoPanel::onFlickrConnectStateChange(const LLSD& data) -{ - switch (data.get("enum").asInteger()) - { - case LLFlickrConnect::FLICKR_CONNECTED: - sendPhoto(); - break; - - case LLFlickrConnect::FLICKR_POSTED: - LLEventPumps::instance().obtain("FlickrConnectState").stopListening("LLFlickrPhotoPanel"); - clearAndClose(); - break; - } - - return false; -} - -void LLFlickrPhotoPanel::sendPhoto() -{ - // Get the title, description, and tags - std::string title = mTitleTextBox->getValue().asString(); - std::string description = mDescriptionTextBox->getValue().asString(); - std::string tags = mTagsTextBox->getValue().asString(); - - // Add the location if required - bool add_location = mLocationCheckbox->getValue().asBoolean(); - if (add_location) - { - // Get the SLURL for the location - LLSLURL slurl; - LLAgentUI::buildSLURL(slurl); - std::string slurl_string = slurl.getSLURLString(); - - // Add query parameters so Google Analytics can track incoming clicks! - slurl_string += DEFAULT_PHOTO_QUERY_PARAMETERS; - - std::string photo_link_text = "Visit this location";// at [] in Second Life"; - std::string parcel_name = LLViewerParcelMgr::getInstance()->getAgentParcelName(); - if (!parcel_name.empty()) - { - boost::regex pattern = boost::regex("\\S\\.[a-zA-Z]{2,}"); - boost::match_results<std::string::const_iterator> matches; - if(!boost::regex_search(parcel_name, matches, pattern)) - { - photo_link_text += " at " + parcel_name; - } - } - photo_link_text += " in Second Life"; - - slurl_string = "<a href=\"" + slurl_string + "\">" + photo_link_text + "</a>"; - - // Add it to the description (pretty crude, but we don't have a better option with photos) - if (description.empty()) - description = slurl_string; - else - description = description + "\n\n" + slurl_string; - - // Also add special "machine tags" with location metadata - const LLVector3& agent_pos_region = gAgent.getPositionAgent(); - LLViewerRegion* region = gAgent.getRegion(); - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (region && parcel) - { - S32 pos_x = S32(agent_pos_region.mV[VX]); - S32 pos_y = S32(agent_pos_region.mV[VY]); - S32 pos_z = S32(agent_pos_region.mV[VZ]); - - std::string parcel_name = LLViewerParcelMgr::getInstance()->getAgentParcelName(); - std::string region_name = region->getName(); - - if (!region_name.empty()) - { - tags += llformat(" \"%s:region=%s\"", FLICKR_MACHINE_TAGS_NAMESPACE.c_str(), region_name.c_str()); - } - if (!parcel_name.empty()) - { - tags += llformat(" \"%s:parcel=%s\"", FLICKR_MACHINE_TAGS_NAMESPACE.c_str(), parcel_name.c_str()); - } - tags += llformat(" \"%s:x=%d\"", FLICKR_MACHINE_TAGS_NAMESPACE.c_str(), pos_x); - tags += llformat(" \"%s:y=%d\"", FLICKR_MACHINE_TAGS_NAMESPACE.c_str(), pos_y); - tags += llformat(" \"%s:z=%d\"", FLICKR_MACHINE_TAGS_NAMESPACE.c_str(), pos_z); - } - } - - // Get the content rating - int content_rating = mRatingComboBox->getValue().asInteger(); - - // Get the image - LLSnapshotLivePreview* previewp = getPreviewView(); - - // Post to Flickr - LLFlickrConnect::instance().uploadPhoto(previewp->getFormattedImage(), title, description, tags, content_rating); - - updateControls(); -} - -void LLFlickrPhotoPanel::clearAndClose() -{ - mTitleTextBox->setValue(""); - mDescriptionTextBox->setValue(""); - - LLFloater* floater = getParentByType<LLFloater>(); - if (floater) - { - floater->closeFloater(); - if (mBigPreviewFloater) - { - mBigPreviewFloater->closeOnFloaterOwnerClosing(floater); - } - } -} - -void LLFlickrPhotoPanel::updateControls() -{ - LLSnapshotLivePreview* previewp = getPreviewView(); - BOOL got_snap = previewp && previewp->getSnapshotUpToDate(); - - // *TODO: Separate maximum size for Web images from postcards - LL_DEBUGS() << "Is snapshot up-to-date? " << got_snap << LL_ENDL; - - updateResolution(FALSE); -} - -void LLFlickrPhotoPanel::updateResolution(BOOL do_update) -{ - LLComboBox* combobox = static_cast<LLComboBox *>(mResolutionComboBox); - LLComboBox* filterbox = static_cast<LLComboBox *>(mFilterComboBox); - - std::string sdstring = combobox->getSelectedValue(); - LLSD sdres; - std::stringstream sstream(sdstring); - LLSDSerialize::fromNotation(sdres, sstream, sdstring.size()); - - S32 width = sdres[0]; - S32 height = sdres[1]; - - // Note : index 0 of the filter drop down is assumed to be "No filter" in whichever locale - std::string filter_name = (filterbox->getCurrentIndex() ? filterbox->getSimple() : ""); - - LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get()); - if (previewp && combobox->getCurrentIndex() >= 0) - { - S32 original_width = 0 , original_height = 0 ; - previewp->getSize(original_width, original_height) ; - - if (width == 0 || height == 0) - { - // take resolution from current window size - LL_DEBUGS() << "Setting preview res from window: " << gViewerWindow->getWindowWidthRaw() << "x" << gViewerWindow->getWindowHeightRaw() << LL_ENDL; - previewp->setSize(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw()); - } - else - { - // use the resolution from the selected pre-canned drop-down choice - LL_DEBUGS() << "Setting preview res selected from combo: " << width << "x" << height << LL_ENDL; - previewp->setSize(width, height); - } - - checkAspectRatio(width); - - previewp->getSize(width, height); - if ((original_width != width) || (original_height != height)) - { - previewp->setSize(width, height); - if (do_update) - { - previewp->updateSnapshot(TRUE); - updateControls(); - } - } - // Get the old filter, compare to the current one "filter_name" and set if changed - std::string original_filter = previewp->getFilter(); - if (original_filter != filter_name) - { - previewp->setFilter(filter_name); - if (do_update) - { - previewp->updateSnapshot(FALSE, TRUE); - updateControls(); - } - } - } -} - -void LLFlickrPhotoPanel::checkAspectRatio(S32 index) -{ - LLSnapshotLivePreview *previewp = getPreviewView() ; - - BOOL keep_aspect = FALSE; - - if (0 == index) // current window size - { - keep_aspect = TRUE; - } - else // predefined resolution - { - keep_aspect = FALSE; - } - - if (previewp) - { - previewp->mKeepAspectRatio = keep_aspect; - } -} - -LLUICtrl* LLFlickrPhotoPanel::getRefreshBtn() -{ - return mRefreshBtn; -} - -/////////////////////////// -//LLFlickrAccountPanel////// -/////////////////////////// - -LLFlickrAccountPanel::LLFlickrAccountPanel() : -mAccountCaptionLabel(NULL), -mAccountNameLabel(NULL), -mPanelButtons(NULL), -mConnectButton(NULL), -mDisconnectButton(NULL) -{ - mCommitCallbackRegistrar.add("SocialSharing.Connect", boost::bind(&LLFlickrAccountPanel::onConnect, this)); - mCommitCallbackRegistrar.add("SocialSharing.Disconnect", boost::bind(&LLFlickrAccountPanel::onDisconnect, this)); - - setVisibleCallback(boost::bind(&LLFlickrAccountPanel::onVisibilityChange, this, _2)); -} - -BOOL LLFlickrAccountPanel::postBuild() -{ - mAccountCaptionLabel = getChild<LLTextBox>("account_caption_label"); - mAccountNameLabel = getChild<LLTextBox>("account_name_label"); - mPanelButtons = getChild<LLUICtrl>("panel_buttons"); - mConnectButton = getChild<LLUICtrl>("connect_btn"); - mDisconnectButton = getChild<LLUICtrl>("disconnect_btn"); - - return LLPanel::postBuild(); -} - -void LLFlickrAccountPanel::draw() -{ - LLFlickrConnect::EConnectionState connection_state = LLFlickrConnect::instance().getConnectionState(); - - //Disable the 'disconnect' button and the 'use another account' button when disconnecting in progress - bool disconnecting = connection_state == LLFlickrConnect::FLICKR_DISCONNECTING; - mDisconnectButton->setEnabled(!disconnecting); - - //Disable the 'connect' button when a connection is in progress - bool connecting = connection_state == LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS; - mConnectButton->setEnabled(!connecting); - - LLPanel::draw(); -} - -void LLFlickrAccountPanel::onVisibilityChange(BOOL visible) -{ - if(visible) - { - LLEventPumps::instance().obtain("FlickrConnectState").stopListening("LLFlickrAccountPanel"); - LLEventPumps::instance().obtain("FlickrConnectState").listen("LLFlickrAccountPanel", boost::bind(&LLFlickrAccountPanel::onFlickrConnectStateChange, this, _1)); - - LLEventPumps::instance().obtain("FlickrConnectInfo").stopListening("LLFlickrAccountPanel"); - LLEventPumps::instance().obtain("FlickrConnectInfo").listen("LLFlickrAccountPanel", boost::bind(&LLFlickrAccountPanel::onFlickrConnectInfoChange, this)); - - //Connected - if(LLFlickrConnect::instance().isConnected()) - { - showConnectedLayout(); - } - //Check if connected (show disconnected layout in meantime) - else - { - showDisconnectedLayout(); - } - if ((LLFlickrConnect::instance().getConnectionState() == LLFlickrConnect::FLICKR_NOT_CONNECTED) || - (LLFlickrConnect::instance().getConnectionState() == LLFlickrConnect::FLICKR_CONNECTION_FAILED)) - { - LLFlickrConnect::instance().checkConnectionToFlickr(); - } - } - else - { - LLEventPumps::instance().obtain("FlickrConnectState").stopListening("LLFlickrAccountPanel"); - LLEventPumps::instance().obtain("FlickrConnectInfo").stopListening("LLFlickrAccountPanel"); - } -} - -bool LLFlickrAccountPanel::onFlickrConnectStateChange(const LLSD& data) -{ - if(LLFlickrConnect::instance().isConnected()) - { - //In process of disconnecting so leave the layout as is - if(data.get("enum").asInteger() != LLFlickrConnect::FLICKR_DISCONNECTING) - { - showConnectedLayout(); - } - } - else - { - showDisconnectedLayout(); - } - - return false; -} - -bool LLFlickrAccountPanel::onFlickrConnectInfoChange() -{ - LLSD info = LLFlickrConnect::instance().getInfo(); - std::string clickable_name; - - //Strings of format [http://www.somewebsite.com Click Me] become clickable text - if(info.has("link") && info.has("name")) - { - clickable_name = "[" + info["link"].asString() + " " + info["name"].asString() + "]"; - } - - mAccountNameLabel->setText(clickable_name); - - return false; -} - -void LLFlickrAccountPanel::showConnectButton() -{ - if(!mConnectButton->getVisible()) - { - mConnectButton->setVisible(TRUE); - mDisconnectButton->setVisible(FALSE); - } -} - -void LLFlickrAccountPanel::hideConnectButton() -{ - if(mConnectButton->getVisible()) - { - mConnectButton->setVisible(FALSE); - mDisconnectButton->setVisible(TRUE); - } -} - -void LLFlickrAccountPanel::showDisconnectedLayout() -{ - mAccountCaptionLabel->setText(getString("flickr_disconnected")); - mAccountNameLabel->setText(std::string("")); - showConnectButton(); -} - -void LLFlickrAccountPanel::showConnectedLayout() -{ - LLFlickrConnect::instance().loadFlickrInfo(); - - mAccountCaptionLabel->setText(getString("flickr_connected")); - hideConnectButton(); -} - -void LLFlickrAccountPanel::onConnect() -{ - LLFlickrConnect::instance().checkConnectionToFlickr(true); -} - -void LLFlickrAccountPanel::onDisconnect() -{ - LLFlickrConnect::instance().disconnectFromFlickr(); -} - -//////////////////////// -//LLFloaterFlickr/////// -//////////////////////// - -LLFloaterFlickr::LLFloaterFlickr(const LLSD& key) : LLFloater(key), - mFlickrPhotoPanel(NULL), - mStatusErrorText(NULL), - mStatusLoadingText(NULL), - mStatusLoadingIndicator(NULL) -{ - mCommitCallbackRegistrar.add("SocialSharing.Cancel", boost::bind(&LLFloaterFlickr::onCancel, this)); -} - -void LLFloaterFlickr::onClose(bool app_quitting) -{ - LLFloaterBigPreview* big_preview_floater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview")); - if (big_preview_floater) - { - big_preview_floater->closeOnFloaterOwnerClosing(this); - } - LLFloater::onClose(app_quitting); -} - -void LLFloaterFlickr::onCancel() -{ - LLFloaterBigPreview* big_preview_floater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview")); - if (big_preview_floater) - { - big_preview_floater->closeOnFloaterOwnerClosing(this); - } - closeFloater(); -} - -BOOL LLFloaterFlickr::postBuild() -{ - // Keep tab of the Photo Panel - mFlickrPhotoPanel = static_cast<LLFlickrPhotoPanel*>(getChild<LLUICtrl>("panel_flickr_photo")); - // Connection status widgets - mStatusErrorText = getChild<LLTextBox>("connection_error_text"); - mStatusLoadingText = getChild<LLTextBox>("connection_loading_text"); - mStatusLoadingIndicator = getChild<LLUICtrl>("connection_loading_indicator"); - return LLFloater::postBuild(); -} - -void LLFloaterFlickr::showPhotoPanel() -{ - LLTabContainer* parent = dynamic_cast<LLTabContainer*>(mFlickrPhotoPanel->getParent()); - if (!parent) - { - LL_WARNS() << "Cannot find panel container" << LL_ENDL; - return; - } - - parent->selectTabPanel(mFlickrPhotoPanel); -} - -void LLFloaterFlickr::draw() -{ - if (mStatusErrorText && mStatusLoadingText && mStatusLoadingIndicator) - { - mStatusErrorText->setVisible(false); - mStatusLoadingText->setVisible(false); - mStatusLoadingIndicator->setVisible(false); - LLFlickrConnect::EConnectionState connection_state = LLFlickrConnect::instance().getConnectionState(); - std::string status_text; - - switch (connection_state) - { - case LLFlickrConnect::FLICKR_NOT_CONNECTED: - // No status displayed when first opening the panel and no connection done - case LLFlickrConnect::FLICKR_CONNECTED: - // When successfully connected, no message is displayed - case LLFlickrConnect::FLICKR_POSTED: - // No success message to show since we actually close the floater after successful posting completion - break; - case LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS: - // Connection loading indicator - mStatusLoadingText->setVisible(true); - status_text = LLTrans::getString("SocialFlickrConnecting"); - mStatusLoadingText->setValue(status_text); - mStatusLoadingIndicator->setVisible(true); - break; - case LLFlickrConnect::FLICKR_POSTING: - // Posting indicator - mStatusLoadingText->setVisible(true); - status_text = LLTrans::getString("SocialFlickrPosting"); - mStatusLoadingText->setValue(status_text); - mStatusLoadingIndicator->setVisible(true); - break; - case LLFlickrConnect::FLICKR_CONNECTION_FAILED: - // Error connecting to the service - mStatusErrorText->setVisible(true); - status_text = LLTrans::getString("SocialFlickrErrorConnecting"); - mStatusErrorText->setValue(status_text); - break; - case LLFlickrConnect::FLICKR_POST_FAILED: - // Error posting to the service - mStatusErrorText->setVisible(true); - status_text = LLTrans::getString("SocialFlickrErrorPosting"); - mStatusErrorText->setValue(status_text); - break; - case LLFlickrConnect::FLICKR_DISCONNECTING: - // Disconnecting loading indicator - mStatusLoadingText->setVisible(true); - status_text = LLTrans::getString("SocialFlickrDisconnecting"); - mStatusLoadingText->setValue(status_text); - mStatusLoadingIndicator->setVisible(true); - break; - case LLFlickrConnect::FLICKR_DISCONNECT_FAILED: - // Error disconnecting from the service - mStatusErrorText->setVisible(true); - status_text = LLTrans::getString("SocialFlickrErrorDisconnecting"); - mStatusErrorText->setValue(status_text); - break; - } - } - LLFloater::draw(); -} - diff --git a/indra/newview/llfloaterflickr.h b/indra/newview/llfloaterflickr.h deleted file mode 100644 index 74da3bcea9..0000000000 --- a/indra/newview/llfloaterflickr.h +++ /dev/null @@ -1,134 +0,0 @@ -/** -* @file llfloaterflickr.h -* @brief Header file for llfloaterflickr -* @author cho@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_LLFLOATERFLICKR_H -#define LL_LLFLOATERFLICKR_H - -#include "llfloater.h" -#include "lltextbox.h" -#include "llviewertexture.h" - -class LLIconCtrl; -class LLCheckBoxCtrl; -class LLSnapshotLivePreview; -class LLFloaterBigPreview; - -class LLFlickrPhotoPanel : public LLPanel -{ -public: - LLFlickrPhotoPanel(); - ~LLFlickrPhotoPanel(); - - BOOL postBuild(); - S32 notify(const LLSD& info); - void draw(); - - LLSnapshotLivePreview* getPreviewView(); - void onVisibilityChange(BOOL new_visibility); - void onClickNewSnapshot(); - void onClickBigPreview(); - void onSend(); - bool onFlickrConnectStateChange(const LLSD& data); - - void sendPhoto(); - void clearAndClose(); - - void updateControls(); - void updateResolution(BOOL do_update); - void checkAspectRatio(S32 index); - LLUICtrl* getRefreshBtn(); - -private: - bool isPreviewVisible(); - void attachPreview(); - - LLHandle<LLView> mPreviewHandle; - - LLUICtrl * mResolutionComboBox; - LLUICtrl * mFilterComboBox; - LLUICtrl * mRefreshBtn; - LLUICtrl * mWorkingLabel; - LLUICtrl * mThumbnailPlaceholder; - LLUICtrl * mTitleTextBox; - LLUICtrl * mDescriptionTextBox; - LLUICtrl * mLocationCheckbox; - LLUICtrl * mTagsTextBox; - LLUICtrl * mRatingComboBox; - LLUICtrl * mPostButton; - LLUICtrl * mCancelButton; - LLButton * mBtnPreview; - - LLFloaterBigPreview * mBigPreviewFloater; -}; - -class LLFlickrAccountPanel : public LLPanel -{ -public: - LLFlickrAccountPanel(); - BOOL postBuild(); - void draw(); - -private: - void onVisibilityChange(BOOL new_visibility); - bool onFlickrConnectStateChange(const LLSD& data); - bool onFlickrConnectInfoChange(); - void onConnect(); - void onUseAnotherAccount(); - void onDisconnect(); - - void showConnectButton(); - void hideConnectButton(); - void showDisconnectedLayout(); - void showConnectedLayout(); - - LLTextBox * mAccountCaptionLabel; - LLTextBox * mAccountNameLabel; - LLUICtrl * mPanelButtons; - LLUICtrl * mConnectButton; - LLUICtrl * mDisconnectButton; -}; - - -class LLFloaterFlickr : public LLFloater -{ -public: - LLFloaterFlickr(const LLSD& key); - BOOL postBuild(); - void draw(); - void onClose(bool app_quitting); - void onCancel(); - - void showPhotoPanel(); - -private: - LLFlickrPhotoPanel* mFlickrPhotoPanel; - LLTextBox* mStatusErrorText; - LLTextBox* mStatusLoadingText; - LLUICtrl* mStatusLoadingIndicator; -}; - -#endif // LL_LLFLOATERFLICKR_H - diff --git a/indra/newview/llfloaterforgetuser.cpp b/indra/newview/llfloaterforgetuser.cpp new file mode 100644 index 0000000000..97b022699f --- /dev/null +++ b/indra/newview/llfloaterforgetuser.cpp @@ -0,0 +1,348 @@ +/** + * @file llfloaterforgetuser.cpp + * @brief LLFloaterForgetUser class definition. + * + * $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 "llfloaterforgetuser.h" + +#include "llappviewer.h" +#include "llcheckboxctrl.h" +#include "llfavoritesbar.h" +#include "llnotificationsutil.h" +#include "llpanellogin.h" // for helper function getUserName() and to repopulate list if nessesary +#include "llscrolllistctrl.h" +#include "llsecapi.h" +#include "llstartup.h" +#include "llviewercontrol.h" +#include "llviewernetwork.h" + + +LLFloaterForgetUser::LLFloaterForgetUser(const LLSD &key) + : LLFloater("floater_forget_user"), + mLoginPanelDirty(false) +{ + +} + +LLFloaterForgetUser::~LLFloaterForgetUser() +{ + if (mLoginPanelDirty) + { + LLPanelLogin::resetFields(); + } +} + +BOOL LLFloaterForgetUser::postBuild() +{ + mScrollList = getChild<LLScrollListCtrl>("user_list"); + + + bool show_grid_marks = gSavedSettings.getBOOL("ForceShowGrid"); + show_grid_marks |= !LLGridManager::getInstance()->isInProductionGrid(); + + std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(); + + if (!show_grid_marks) + { + // Figure out if there are records for more than one grid in storage + for (std::map<std::string, std::string>::iterator grid_iter = known_grids.begin(); + grid_iter != known_grids.end(); + grid_iter++) + { + if (!grid_iter->first.empty() + && grid_iter->first != MAINGRID) // a workaround since 'mIsInProductionGrid' might not be set + { + if (!gSecAPIHandler->emptyCredentialMap("login_list", grid_iter->first)) + { + show_grid_marks = true; + break; + } + + // "Legacy" viewer support + LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(grid_iter->first); + if (cred.notNull()) + { + const LLSD &ident = cred->getIdentifier(); + if (ident.isMap() && ident.has("type")) + { + show_grid_marks = true; + break; + } + } + } + } + } + + mUserGridsCount.clear(); + if (!show_grid_marks) + { + // just load maingrid + loadGridToList(MAINGRID, false); + } + else + { + for (std::map<std::string, std::string>::iterator grid_iter = known_grids.begin(); + grid_iter != known_grids.end(); + grid_iter++) + { + if (!grid_iter->first.empty()) + { + loadGridToList(grid_iter->first, true); + } + } + } + + mScrollList->selectFirstItem(); + bool enable_button = mScrollList->getFirstSelectedIndex() != -1; + LLCheckBoxCtrl *chk_box = getChild<LLCheckBoxCtrl>("delete_data"); + chk_box->setEnabled(enable_button); + chk_box->set(FALSE); + LLButton *button = getChild<LLButton>("forget"); + button->setEnabled(enable_button); + button->setCommitCallback(boost::bind(&LLFloaterForgetUser::onForgetClicked, this)); + + return TRUE; +} + +void LLFloaterForgetUser::onForgetClicked() +{ + LLScrollListCtrl *scroll_list = getChild<LLScrollListCtrl>("user_list"); + LLSD user_data = scroll_list->getSelectedValue(); + const std::string user_id = user_data["user_id"]; + + LLCheckBoxCtrl *chk_box = getChild<LLCheckBoxCtrl>("delete_data"); + BOOL delete_data = chk_box->getValue(); + + if (delete_data && mUserGridsCount[user_id] > 1) + { + // more than 1 grid uses this id + LLNotificationsUtil::add("LoginRemoveMultiGridUserData", LLSD(), LLSD(), boost::bind(&LLFloaterForgetUser::onConfirmForget, this, _1, _2)); + return; + } + + processForgetUser(); +} + +bool LLFloaterForgetUser::onConfirmForget(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + processForgetUser(); + } + return false; +} + +// static +bool LLFloaterForgetUser::onConfirmLogout(const LLSD& notification, const LLSD& response, const std::string &fav_id, const std::string &grid) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + // Remove creds + gSecAPIHandler->removeFromCredentialMap("login_list", grid, LLStartUp::getUserId()); + + LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(grid); + if (cred.notNull() && cred->userID() == LLStartUp::getUserId()) + { + gSecAPIHandler->deleteCredential(cred); + } + + // Clean favorites + LLFavoritesOrderStorage::removeFavoritesRecordOfUser(fav_id, grid); + + // mark data for removal + LLAppViewer::instance()->purgeUserDataOnExit(); + LLAppViewer::instance()->requestQuit(); + } + return false; +} + +void LLFloaterForgetUser::processForgetUser() +{ + LLScrollListCtrl *scroll_list = getChild<LLScrollListCtrl>("user_list"); + LLCheckBoxCtrl *chk_box = getChild<LLCheckBoxCtrl>("delete_data"); + BOOL delete_data = chk_box->getValue(); + LLSD user_data = scroll_list->getSelectedValue(); + const std::string user_id = user_data["user_id"]; + const std::string grid = user_data["grid"]; + const std::string user_name = user_data["label"]; // for favorites + + if (delete_data && user_id == LLStartUp::getUserId() && LLStartUp::getStartupState() > STATE_LOGIN_WAIT) + { + // we can't delete data for user that is currently logged in + // we need to pass grid because we are deleting data universal to grids, but specific grid's user + LLNotificationsUtil::add("LoginCantRemoveCurUsername", LLSD(), LLSD(), boost::bind(onConfirmLogout, _1, _2, user_name, grid)); + return; + } + + // key is used for name of user's folder and in credencials + // user_name is edentical to favorite's username + forgetUser(user_id, user_name, grid, delete_data); + mLoginPanelDirty = true; + if (delete_data) + { + mUserGridsCount[user_id] = 0; //no data left to care about + } + else + { + mUserGridsCount[user_id]--; + } + + // Update UI + scroll_list->deleteSelectedItems(); + scroll_list->selectFirstItem(); + if (scroll_list->getFirstSelectedIndex() == -1) + { + LLButton *button = getChild<LLButton>("forget"); + button->setEnabled(false); + chk_box->setEnabled(false); + } +} + +//static +void LLFloaterForgetUser::forgetUser(const std::string &userid, const std::string &fav_id, const std::string &grid, bool delete_data) +{ + // Remove creds + gSecAPIHandler->removeFromCredentialMap("login_list", grid, userid); + + LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(grid); + if (cred.notNull() && cred->userID() == userid) + { + gSecAPIHandler->deleteCredential(cred); + } + + // Clean data + if (delete_data) + { + std::string user_path = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter() + userid; + gDirUtilp->deleteDirAndContents(user_path); + + // Clean favorites + LLFavoritesOrderStorage::removeFavoritesRecordOfUser(fav_id, grid); + + // Note: we do not clean user-related files from cache because there are id dependent (inventory) + // files and cache has separate cleaning mechanism either way. + // Also this only cleans user from current grid, not all of them. + } +} + +void LLFloaterForgetUser::loadGridToList(const std::string &grid, bool show_grid_name) +{ + std::string grid_label; + if (show_grid_name) + { + grid_label = LLGridManager::getInstance()->getGridId(grid); //login id (shortened label) + } + if (gSecAPIHandler->hasCredentialMap("login_list", grid)) + { + LLSecAPIHandler::credential_map_t credencials; + gSecAPIHandler->loadCredentialMap("login_list", grid, credencials); + + LLSecAPIHandler::credential_map_t::iterator cr_iter = credencials.begin(); + LLSecAPIHandler::credential_map_t::iterator cr_end = credencials.end(); + while (cr_iter != cr_end) + { + if (cr_iter->second.notNull()) // basic safety + { + std::string user_label = LLPanelLogin::getUserName(cr_iter->second); + LLSD user_data; + user_data["user_id"] = cr_iter->first; + user_data["label"] = user_label; + user_data["grid"] = grid; + + if (show_grid_name) + { + user_label += " (" + grid_label + ")"; + } + + LLScrollListItem::Params item_params; + item_params.value(user_data); + item_params.columns.add() + .value(user_label) + .column("user") + .font(LLFontGL::getFontSansSerifSmall()); + mScrollList->addRow(item_params, ADD_BOTTOM); + + // Add one to grid count + std::map<std::string, S32>::iterator found = mUserGridsCount.find(cr_iter->first); + if (found != mUserGridsCount.end()) + { + found->second++; + } + else + { + mUserGridsCount[cr_iter->first] = 1; + } + } + cr_iter++; + } + } + else + { + // "Legacy" viewer support + LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(grid); + if (cred.notNull()) + { + const LLSD &ident = cred->getIdentifier(); + if (ident.isMap() && ident.has("type")) + { + std::string user_label = LLPanelLogin::getUserName(cred); + LLSD user_data; + user_data["user_id"] = cred->userID(); + user_data["label"] = user_label; + user_data["grid"] = grid; + + if (show_grid_name) + { + user_label += " (" + grid_label + ")"; + } + + LLScrollListItem::Params item_params; + item_params.value(user_data); + item_params.columns.add() + .value(user_label) + .column("user") + .font(LLFontGL::getFontSansSerifSmall()); + mScrollList->addRow(item_params, ADD_BOTTOM); + + // Add one to grid count + std::map<std::string, S32>::iterator found = mUserGridsCount.find(cred->userID()); + if (found != mUserGridsCount.end()) + { + found->second++; + } + else + { + mUserGridsCount[cred->userID()] = 1; + } + } + } + } +} + + diff --git a/indra/newview/llfloaterforgetuser.h b/indra/newview/llfloaterforgetuser.h new file mode 100644 index 0000000000..801fcbb412 --- /dev/null +++ b/indra/newview/llfloaterforgetuser.h @@ -0,0 +1,56 @@ +/** + * @file llfloaterforgetuser.h + * @brief LLFloaterForgetUser class declaration. + * + * $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_LLFLOATERFORGETUSER_H +#define LL_LLFLOATERFORGETUSER_H + +#include "llfloater.h" + +class LLScrollListCtrl; + +class LLFloaterForgetUser : public LLFloater +{ +public: + LLFloaterForgetUser(const LLSD &key); + ~LLFloaterForgetUser(); + + BOOL postBuild(); + void onForgetClicked(); + +private: + bool onConfirmForget(const LLSD& notification, const LLSD& response); + static bool onConfirmLogout(const LLSD& notification, const LLSD& response, const std::string &favorites_id, const std::string &grid); + void processForgetUser(); + static void forgetUser(const std::string &userid, const std::string &fav_id, const std::string &grid, bool delete_data); + void loadGridToList(const std::string &grid, bool show_grid_name); + + LLScrollListCtrl *mScrollList; + + bool mLoginPanelDirty; + std::map<std::string, S32> mUserGridsCount; +}; + +#endif diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index b840d37c4d..c4e0dd483f 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -41,6 +41,7 @@ #include "llkeyboard.h" #include "llmenugl.h" #include "llmultigesture.h" +#include "llnotificationsutil.h" #include "llpreviewgesture.h" #include "llscrolllistctrl.h" #include "lltrans.h" @@ -125,6 +126,7 @@ LLFloaterGesture::LLFloaterGesture(const LLSD& key) mCommitCallbackRegistrar.add("Gesture.Action.ShowPreview", boost::bind(&LLFloaterGesture::onClickEdit, this)); mCommitCallbackRegistrar.add("Gesture.Action.CopyPaste", boost::bind(&LLFloaterGesture::onCopyPasteAction, this, _2)); mCommitCallbackRegistrar.add("Gesture.Action.SaveToCOF", boost::bind(&LLFloaterGesture::addToCurrentOutFit, this)); + mCommitCallbackRegistrar.add("Gesture.Action.Rename", boost::bind(&LLFloaterGesture::onRenameSelected, this)); mEnableCallbackRegistrar.add("Gesture.EnableAction", boost::bind(&LLFloaterGesture::isActionEnabled, this, _2)); } @@ -430,6 +432,19 @@ bool LLFloaterGesture::isActionEnabled(const LLSD& command) { return mGestureList->getAllSelected().size() == 1; } + else if ("rename_gesture" == command_name) + { + if (mGestureList->getAllSelected().size() == 1) + { + LLViewerInventoryItem* item = gInventory.getItem(mGestureList->getCurrentID()); + + if (item && item->getPermissions().allowModifyBy(gAgentID)) + { + return true; + } + } + return false; + } return true; } @@ -470,7 +485,7 @@ void LLFloaterGesture::onClickNew() "", LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, - NOT_WEARABLE, + NO_INV_SUBTYPE, PERM_MOVE | LLFloaterPerms::getNextOwnerPerms("Gestures"), cb); } @@ -514,6 +529,44 @@ void LLFloaterGesture::onActivateBtnClick() } } +void LLFloaterGesture::onRenameSelected() +{ + LLViewerInventoryItem* gesture = gInventory.getItem(mGestureList->getCurrentID()); + if (!gesture) + { + return; + } + + LLSD args; + args["NAME"] = gesture->getName(); + + LLSD payload; + payload["gesture_id"] = mGestureList->getCurrentID(); + + LLNotificationsUtil::add("RenameGesture", args, payload, boost::bind(onGestureRename, _1, _2)); + +} + +void LLFloaterGesture::onGestureRename(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) return; // canceled + + std::string new_name = response["new_name"].asString(); + LLInventoryObject::correctInventoryName(new_name); + if (!new_name.empty()) + { + LLUUID item_id = notification["payload"]["gesture_id"].asUUID(); + LLViewerInventoryItem* gesture = gInventory.getItem(item_id); + if (gesture && (gesture->getName() != new_name)) + { + LLSD updates; + updates["name"] = new_name; + update_inventory_item(item_id, updates, NULL); + } + } +} + void LLFloaterGesture::onCopyPasteAction(const LLSD& command) { std::string command_name = command.asString(); diff --git a/indra/newview/llfloatergesture.h b/indra/newview/llfloatergesture.h index 8efb3e6461..1d702c6704 100644 --- a/indra/newview/llfloatergesture.h +++ b/indra/newview/llfloatergesture.h @@ -95,6 +95,9 @@ private: void onCommitList(); void onCopyPasteAction(const LLSD& command); void onDeleteSelected(); + void onRenameSelected(); + + static void onGestureRename(const LLSD& notification, const LLSD& response); LLUUID mSelectedID; LLUUID mGestureFolderID; diff --git a/indra/newview/llfloatergridstatus.cpp b/indra/newview/llfloatergridstatus.cpp index c47ff1c1d9..9745e17bbb 100644 --- a/indra/newview/llfloatergridstatus.cpp +++ b/indra/newview/llfloatergridstatus.cpp @@ -39,7 +39,7 @@ #include "llxmltree.h" std::map<std::string, std::string> LLFloaterGridStatus::sItemsMap; -const std::string DEFAULT_GRID_STATUS_URL = "http://secondlife-status.statuspage.io/"; +const std::string DEFAULT_GRID_STATUS_URL = "http://status.secondlifegrid.net/"; LLFloaterGridStatus::LLFloaterGridStatus(const Params& key) : LLFloaterWebContent(key), @@ -95,6 +95,7 @@ void LLFloaterGridStatus::getGridStatusRSSCoro() LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + httpOpts->setSSLVerifyPeer(false); // We want this data even if SSL fails httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML); std::string url = gSavedSettings.getString("GridStatusRSS"); diff --git a/indra/newview/llfloatergroupinvite.cpp b/indra/newview/llfloatergroupinvite.cpp index 7fdba8734a..30c90ac184 100644 --- a/indra/newview/llfloatergroupinvite.cpp +++ b/indra/newview/llfloatergroupinvite.cpp @@ -108,7 +108,7 @@ LLFloaterGroupInvite::~LLFloaterGroupInvite() } // static -void LLFloaterGroupInvite::showForGroup(const LLUUID& group_id, uuid_vec_t *agent_ids) +void LLFloaterGroupInvite::showForGroup(const LLUUID& group_id, uuid_vec_t *agent_ids, bool request_update) { const LLFloater::Params& floater_params = LLFloater::getDefaultParams(); S32 floater_header_size = floater_params.header_height; @@ -126,9 +126,12 @@ void LLFloaterGroupInvite::showForGroup(const LLUUID& group_id, uuid_vec_t *agen group_id, (LLFloaterGroupInvite*)NULL); - // refresh group information - gAgent.sendAgentDataUpdateRequest(); - LLGroupMgr::getInstance()->clearGroupData(group_id); + if (request_update) + { + // refresh group information + gAgent.sendAgentDataUpdateRequest(); + LLGroupMgr::getInstance()->clearGroupData(group_id); + } if (!fgi) diff --git a/indra/newview/llfloatergroupinvite.h b/indra/newview/llfloatergroupinvite.h index f6a3ca5550..657e5711f0 100644 --- a/indra/newview/llfloatergroupinvite.h +++ b/indra/newview/llfloatergroupinvite.h @@ -37,7 +37,7 @@ class LLFloaterGroupInvite public: virtual ~LLFloaterGroupInvite(); - static void showForGroup(const LLUUID &group_id, uuid_vec_t *agent_ids = NULL); + static void showForGroup(const LLUUID &group_id, uuid_vec_t *agent_ids = NULL, bool request_update = true); protected: LLFloaterGroupInvite(const LLUUID& group_id = LLUUID::null); diff --git a/indra/newview/llfloatergroups.cpp b/indra/newview/llfloatergroups.cpp index dbe7fee108..f341e2ebcb 100644 --- a/indra/newview/llfloatergroups.cpp +++ b/indra/newview/llfloatergroups.cpp @@ -38,6 +38,7 @@ #include "roles_constants.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llbutton.h" #include "llgroupactions.h" #include "llscrolllistctrl.h" @@ -172,7 +173,7 @@ void LLPanelGroups::reset() group_list->operateOnAll(LLCtrlListInterface::OP_DELETE); } getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d",gAgent.mGroups.size())); - getChild<LLUICtrl>("groupcount")->setTextArg("[MAX]", llformat("%d",gMaxAgentGroups)); + getChild<LLUICtrl>("groupcount")->setTextArg("[MAX]", llformat("%d",LLAgentBenefitsMgr::current().getGroupMembershipLimit())); init_group_list(getChild<LLScrollListCtrl>("group list"), gAgent.getGroupID()); enableButtons(); @@ -183,7 +184,7 @@ BOOL LLPanelGroups::postBuild() childSetCommitCallback("group list", onGroupList, this); getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d",gAgent.mGroups.size())); - getChild<LLUICtrl>("groupcount")->setTextArg("[MAX]", llformat("%d",gMaxAgentGroups)); + getChild<LLUICtrl>("groupcount")->setTextArg("[MAX]", llformat("%d",LLAgentBenefitsMgr::current().getGroupMembershipLimit())); LLScrollListCtrl *list = getChild<LLScrollListCtrl>("group list"); if (list) diff --git a/indra/newview/llfloaterhandler.cpp b/indra/newview/llfloaterhandler.cpp index e2160498e9..8ebb14149c 100644 --- a/indra/newview/llfloaterhandler.cpp +++ b/indra/newview/llfloaterhandler.cpp @@ -26,6 +26,7 @@ #include "llfloater.h" #include "llmediactrl.h" +#include "llfloaterreg.h" // register with dispatch via global object LLFloaterHandler gFloaterHandler; @@ -50,9 +51,15 @@ LLFloater* get_parent_floater(LLView* view) bool LLFloaterHandler::handle(const LLSD ¶ms, const LLSD &query_map, LLMediaCtrl *web) { - if (params.size() < 2) return false; + if (params.size() < 1) return false; LLFloater* floater = NULL; // *TODO: implement floater lookup by name + + if (params[0].asString() == "destinations") + { + LLFloaterReg::toggleInstanceOrBringToFront("destinations"); + return true; + } if (params[0].asString() == "self") { if (web) diff --git a/indra/newview/llfloaterhowto.cpp b/indra/newview/llfloaterhowto.cpp new file mode 100644 index 0000000000..a359fb7c7d --- /dev/null +++ b/indra/newview/llfloaterhowto.cpp @@ -0,0 +1,92 @@ +/** + * @file llfloaterhowto.cpp + * @brief A variant of web floater meant to open guidebook + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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 "llfloaterhowto.h" + +#include "llfloaterreg.h" +#include "llviewercontrol.h" +#include "llweb.h" + + +const S32 STACK_WIDTH = 300; +const S32 STACK_HEIGHT = 505; // content will be 500 + +LLFloaterHowTo::LLFloaterHowTo(const Params& key) : + LLFloaterWebContent(key) +{ + mShowPageTitle = false; +} + +BOOL LLFloaterHowTo::postBuild() +{ + LLFloaterWebContent::postBuild(); + + return TRUE; +} + +void LLFloaterHowTo::onOpen(const LLSD& key) +{ + LLFloaterWebContent::Params p(key); + if (!p.url.isProvided() || p.url.getValue().empty()) + { + std::string url = gSavedSettings.getString("GuidebookURL"); + p.url = LLWeb::expandURLSubstitutions(url, LLSD()); + } + p.show_chrome = false; + + LLFloaterWebContent::onOpen(p); + + if (p.preferred_media_size().isEmpty()) + { + // Elements from LLFloaterWebContent did not pick up restored size (save_rect) of LLFloaterHowTo + // set the stack size and position (alternative to preferred_media_size) + LLLayoutStack *stack = getChild<LLLayoutStack>("stack1"); + LLRect stack_rect = stack->getRect(); + stack->reshape(STACK_WIDTH, STACK_HEIGHT); + stack->setOrigin(stack_rect.mLeft, stack_rect.mTop - STACK_HEIGHT); + stack->updateLayout(); + } +} + +LLFloaterHowTo* LLFloaterHowTo::getInstance() +{ + return LLFloaterReg::getTypedInstance<LLFloaterHowTo>("guidebook"); +} + +BOOL LLFloaterHowTo::handleKeyHere(KEY key, MASK mask) +{ + BOOL handled = FALSE; + + if (KEY_F1 == key ) + { + closeFloater(); + handled = TRUE; + } + + return handled; +} diff --git a/indra/newview/llfloaterhowto.h b/indra/newview/llfloaterhowto.h new file mode 100644 index 0000000000..d8da355600 --- /dev/null +++ b/indra/newview/llfloaterhowto.h @@ -0,0 +1,58 @@ +/** + * @file llfloaterhowto.h + * @brief A variant of web floater meant to open guidebook + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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_LLFLOATERHOWTO_H +#define LL_LLFLOATERHOWTO_H + +#include "llfloaterwebcontent.h" + +class LLMediaCtrl; + + +class LLFloaterHowTo : + public LLFloaterWebContent +{ +public: + LOG_CLASS(LLFloaterHowTo); + + typedef LLFloaterWebContent::Params Params; + + LLFloaterHowTo(const Params& key); + + void onOpen(const LLSD& key) override; + + BOOL handleKeyHere(KEY key, MASK mask) override; + + static LLFloaterHowTo* getInstance(); + + bool matchesKey(const LLSD& key) override { return true; /*single instance*/ }; + +private: + BOOL postBuild() override; +}; + +#endif // LL_LLFLOATERHOWTO_H + diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 3c428a70f3..028c922a4d 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -35,6 +35,7 @@ #include "llagent.h" #include "llbutton.h" +#include "llcheckboxctrl.h" #include "llcombobox.h" #include "lldrawable.h" #include "lldrawpoolavatar.h" @@ -63,8 +64,8 @@ const S32 PREVIEW_BORDER_WIDTH = 2; const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; -const S32 PREVIEW_VPAD = -24; // yuk, hard coded -const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; +const S32 PREVIEW_VPAD = -24 + 35; // yuk, hard coded +const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16 + 35; const S32 PREVIEW_TEXTURE_HEIGHT = 320; //----------------------------------------------------------------------------- @@ -115,8 +116,14 @@ BOOL LLFloaterImagePreview::postBuild() mSculptedPreview = new LLImagePreviewSculpted(256, 256); mSculptedPreview->setPreviewTarget(mRawImagep, 2.0f); - if (mRawImagep->getWidth() * mRawImagep->getHeight () <= LL_IMAGE_REZ_LOSSLESS_CUTOFF * LL_IMAGE_REZ_LOSSLESS_CUTOFF) - getChildView("lossless_check")->setEnabled(TRUE); + if (mRawImagep->getWidth() * mRawImagep->getHeight() <= LL_IMAGE_REZ_LOSSLESS_CUTOFF * LL_IMAGE_REZ_LOSSLESS_CUTOFF) + { + // We want "lossless_check" to be unchecked when it is disabled, regardless of + // LosslessJ2CUpload state, so only assign control when enabling checkbox + LLCheckBoxCtrl* check_box = getChild<LLCheckBoxCtrl>("lossless_check"); + check_box->setEnabled(TRUE); + check_box->setControlVariable(gSavedSettings.getControl("LosslessJ2CUpload")); + } } else { @@ -503,7 +510,7 @@ BOOL LLFloaterImagePreview::handleHover(S32 x, S32 y, MASK mask) mSculptedPreview->refresh(); } - LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); + LLUI::getInstance()->setMousePositionLocal(this, mLastMouseX, mLastMouseY); } if (!mPreviewRect.pointInRect(x, y) || !mAvatarPreview || !mSculptedPreview) diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 30d05ae287..9c84fa1991 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -54,9 +54,15 @@ #include "llcallbacklist.h" #include "llworld.h" #include "llsdserialize.h" +#include "llviewermenu.h" // is_agent_mappable #include "llviewerobjectlist.h" #include "boost/foreach.hpp" + +const S32 EVENTS_PER_IDLE_LOOP_CURRENT_SESSION = 80; +const S32 EVENTS_PER_IDLE_LOOP_BACKGROUND = 40; +const F32 EVENTS_PER_IDLE_LOOP_MIN_PERCENTAGE = 0.01f; // process a minimum of 1% of total events per frame + // // LLFloaterIMContainer // @@ -66,7 +72,8 @@ LLFloaterIMContainer::LLFloaterIMContainer(const LLSD& seed, const Params& param mConversationsRoot(NULL), mConversationsEventStream("ConversationsEvents"), mInitialized(false), - mIsFirstLaunch(true) + mIsFirstLaunch(true), + mConversationEventQueue() { mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLFloaterIMContainer::isActionChecked, this, _2)); mCommitCallbackRegistrar.add("IMFloaterContainer.Action", boost::bind(&LLFloaterIMContainer::onCustomAction, this, _2)); @@ -237,7 +244,7 @@ BOOL LLFloaterIMContainer::postBuild() collapseMessagesPane(gSavedPerAccountSettings.getBOOL("ConversationsMessagePaneCollapsed")); collapseConversationsPane(gSavedPerAccountSettings.getBOOL("ConversationsListPaneCollapsed"), false); - LLAvatarNameCache::addUseDisplayNamesCallback(boost::bind(&LLFloaterIMSessionTab::processChatHistoryStyleUpdate, false)); + LLAvatarNameCache::getInstance()->addUseDisplayNamesCallback(boost::bind(&LLFloaterIMSessionTab::processChatHistoryStyleUpdate, false)); mMicroChangedSignal = LLVoiceClient::getInstance()->MicroChangedCallback(boost::bind(&LLFloaterIMContainer::updateSpeakBtnState, this)); if (! mMessagesPane->isCollapsed() && ! mConversationsPane->isCollapsed()) @@ -267,7 +274,7 @@ BOOL LLFloaterIMContainer::postBuild() // We'll take care of view updates on idle gIdleCallbacks.addFunction(idle, this); // When display name option change, we need to reload all participant names - LLAvatarNameCache::addUseDisplayNamesCallback(boost::bind(&LLFloaterIMContainer::processParticipantsStyleUpdate, this)); + LLAvatarNameCache::getInstance()->addUseDisplayNamesCallback(boost::bind(&LLFloaterIMContainer::processParticipantsStyleUpdate, this)); mParticipantRefreshTimer.setTimerExpirySec(0); mParticipantRefreshTimer.start(); @@ -304,12 +311,15 @@ void LLFloaterIMContainer::addFloater(LLFloater* floaterp, LLIconCtrl* icon = 0; + bool is_in_group = gAgent.isInGroup(session_id, TRUE); + LLUUID icon_id; - if(gAgent.isInGroup(session_id, TRUE)) + if (is_in_group) { LLGroupIconCtrl::Params icon_params; icon_params.group_id = session_id; icon = LLUICtrlFactory::instance().create<LLGroupIconCtrl>(icon_params); + icon_id = session_id; mSessions[session_id] = floaterp; floaterp->mCloseSignal.connect(boost::bind(&LLFloaterIMContainer::onCloseFloater, this, session_id)); @@ -321,11 +331,18 @@ void LLFloaterIMContainer::addFloater(LLFloater* floaterp, LLAvatarIconCtrl::Params icon_params; icon_params.avatar_id = avatar_id; icon = LLUICtrlFactory::instance().create<LLAvatarIconCtrl>(icon_params); + icon_id = avatar_id; mSessions[session_id] = floaterp; floaterp->mCloseSignal.connect(boost::bind(&LLFloaterIMContainer::onCloseFloater, this, session_id)); } + LLFloaterIMSessionTab* floater = LLFloaterIMSessionTab::getConversation(session_id); + if (floater) + { + floater->updateChatIcon(icon_id); + } + // forced resize of the floater LLRect wrapper_rect = this->mTabContainer->getLocalRect(); floaterp->setRect(wrapper_rect); @@ -411,8 +428,11 @@ void LLFloaterIMContainer::processParticipantsStyleUpdate() while (current_participant_model != end_participant_model) { LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model); - // Get the avatar name for this participant id from the cache and update the model - participant_model->updateName(); + if (participant_model) + { + // Get the avatar name for this participant id from the cache and update the model + participant_model->updateName(); + } // Next participant current_participant_model++; } @@ -424,7 +444,9 @@ void LLFloaterIMContainer::idle(void* user_data) { LLFloaterIMContainer* self = static_cast<LLFloaterIMContainer*>(user_data); - if (!self->getVisible() || self->isMinimized()) + self->idleProcessEvents(); + + if (!self->getVisible() || self->isMinimized()) { return; } @@ -447,19 +469,26 @@ void LLFloaterIMContainer::idleUpdate() const LLConversationItem *current_session = getCurSelectedViewModelItem(); if (current_session) { - // Update moderator options visibility - LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = current_session->getChildrenBegin(); - LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = current_session->getChildrenEnd(); - bool is_moderator = isGroupModerator(); - bool can_ban = haveAbilityToBan(); - while (current_participant_model != end_participant_model) + if (current_session->getType() == LLConversationItem::CONV_SESSION_GROUP) { - LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model); - participant_model->setModeratorOptionsVisible(is_moderator && participant_model->getUUID() != gAgentID); - participant_model->setGroupBanVisible(can_ban && participant_model->getUUID() != gAgentID); - - current_participant_model++; + // Update moderator options visibility + LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = current_session->getChildrenBegin(); + LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = current_session->getChildrenEnd(); + bool is_moderator = isGroupModerator(); + bool can_ban = haveAbilityToBan(); + while (current_participant_model != end_participant_model) + { + LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model); + if (participant_model) + { + participant_model->setModeratorOptionsVisible(is_moderator); + participant_model->setGroupBanVisible(can_ban && participant_model->getUUID() != gAgentID); + } + + current_participant_model++; + } } + // Update floater's title as required by the currently selected session or use the default title LLFloaterIMSession * conversation_floaterp = LLFloaterIMSession::findInstance(current_session->getUUID()); setTitle(conversation_floaterp && conversation_floaterp->needsTitleOverwrite() ? conversation_floaterp->getTitle() : mGeneralTitle); @@ -485,13 +514,57 @@ void LLFloaterIMContainer::idleUpdate() } } +void LLFloaterIMContainer::idleProcessEvents() +{ + LLUUID current_session_id = getSelectedSession(); + conversations_items_deque::iterator iter = mConversationEventQueue.begin(); + conversations_items_deque::iterator end = mConversationEventQueue.end(); + while (iter != end) + { + std::deque<LLSD> &events = iter->second; + if (!events.empty()) + { + S32 events_to_handle; + S32 query_size = (S32)events.size(); + if (current_session_id == iter->first) + { + events_to_handle = EVENTS_PER_IDLE_LOOP_CURRENT_SESSION; + } + else + { + events_to_handle = EVENTS_PER_IDLE_LOOP_BACKGROUND; + } + + if (events_to_handle <= query_size) + { + // Some groups can be very large and can generate huge amount of updates, scale processing up to keep up + events_to_handle = llmax(events_to_handle, (S32)(query_size * EVENTS_PER_IDLE_LOOP_MIN_PERCENTAGE)); + } + else + { + events_to_handle = query_size; + } + + for (S32 i = 0; i < events_to_handle; i++) + { + handleConversationModelEvent(events.back()); + events.pop_back(); + } + } + iter++; + } +} + bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event) { - // For debug only - //std::ostringstream llsd_value; - //llsd_value << LLSDOStreamer<LLSDNotationFormatter>(event) << std::endl; - //LL_INFOS() << "LLFloaterIMContainer::onConversationModelEvent, event = " << llsd_value.str() << LL_ENDL; - // end debug + LLUUID id = event.get("session_uuid").asUUID(); + mConversationEventQueue[id].push_front(event); + return true; +} + + +void LLFloaterIMContainer::handleConversationModelEvent(const LLSD& event) +{ // Note: In conversations, the model is not responsible for creating the view, which is a good thing. This means that // the model could change substantially and the view could echo only a portion of this model (though currently the @@ -508,7 +581,7 @@ bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event) if (!session_view) { // We skip events that are not associated with a session - return false; + return; } LLConversationViewParticipant* participant_view = session_view->findParticipant(participant_id); LLFloaterIMSessionTab *conversation_floater = (session_id.isNull() ? @@ -535,9 +608,9 @@ bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event) { LLConversationItemSession* session_model = dynamic_cast<LLConversationItemSession*>(mConversationsItems[session_id]); LLConversationItemParticipant* participant_model = (session_model ? session_model->findParticipant(participant_id) : NULL); + LLIMModel::LLIMSession * im_sessionp = LLIMModel::getInstance()->findIMSession(session_id); if (!participant_view && session_model && participant_model) - { - LLIMModel::LLIMSession * im_sessionp = LLIMModel::getInstance()->findIMSession(session_id); + { if (session_id.isNull() || (im_sessionp && !im_sessionp->isP2PSessionType())) { participant_view = createConversationViewParticipant(participant_model); @@ -548,7 +621,8 @@ bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event) // Add a participant view to the conversation floater if (conversation_floater && participant_model) { - conversation_floater->addConversationViewParticipant(participant_model); + bool skip_updating = im_sessionp && im_sessionp->isGroupChat(); + conversation_floater->addConversationViewParticipant(participant_model, !skip_updating); } } else if (type == "update_participant") @@ -571,12 +645,6 @@ bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event) mConversationViewModel.requestSortAll(); mConversationsRoot->arrangeAll(); - if (conversation_floater) - { - conversation_floater->refreshConversation(); - } - - return false; } void LLFloaterIMContainer::draw() @@ -1409,12 +1477,21 @@ bool LLFloaterIMContainer::enableContextMenuItem(const std::string& item, uuid_v { return is_single_select; } - - // Beyond that point, if only the user agent is selected, everything is disabled - if (is_single_select && (single_id == gAgentID)) - { - return false; - } + + bool is_moderator_option = ("can_moderate_voice" == item) || ("can_allow_text_chat" == item) || ("can_mute" == item) || ("can_unmute" == item); + + // Beyond that point, if only the user agent is selected, everything is disabled + if (is_single_select && (single_id == gAgentID)) + { + if (is_moderator_option) + { + return enableModerateContextMenuItem(item, true); + } + else + { + return false; + } + } // If the user agent is selected with others, everything is disabled for (uuid_vec_t::const_iterator id = uuids.begin(); id != uuids.end(); ++id) @@ -1480,11 +1557,11 @@ bool LLFloaterIMContainer::enableContextMenuItem(const std::string& item, uuid_v { return canBanSelectedMember(single_id); } - else if (("can_moderate_voice" == item) || ("can_allow_text_chat" == item) || ("can_mute" == item) || ("can_unmute" == item)) - { - // *TODO : get that out of here... - return enableModerateContextMenuItem(item); - } + else if (is_moderator_option) + { + // *TODO : get that out of here... + return enableModerateContextMenuItem(item); + } // By default, options that not explicitely disabled are enabled return true; @@ -1786,12 +1863,16 @@ bool LLFloaterIMContainer::removeConversationListItem(const LLUUID& uuid, bool c { new_selection = mConversationsRoot->getPreviousFromChild(widget, FALSE); } + + // Will destroy views and delete models that are not assigned to any views widget->destroyView(); } // Suppress the conversation items and widgets from their respective maps mConversationsItems.erase(uuid); mConversationsWidgets.erase(uuid); + // Clear event query (otherwise reopening session in some way can bombard session with stale data) + mConversationEventQueue.erase(uuid); // Don't let the focus fall IW, select and refocus on the first conversation in the list if (change_focus) @@ -1854,7 +1935,7 @@ LLConversationViewParticipant* LLFloaterIMContainer::createConversationViewParti return LLUICtrlFactory::create<LLConversationViewParticipant>(params); } -bool LLFloaterIMContainer::enableModerateContextMenuItem(const std::string& userdata) +bool LLFloaterIMContainer::enableModerateContextMenuItem(const std::string& userdata, bool is_self) { // only group moderators can perform actions related to this "enable callback" if (!isGroupModerator()) @@ -1874,7 +1955,7 @@ bool LLFloaterIMContainer::enableModerateContextMenuItem(const std::string& user { return voice_channel; } - else if ("can_mute" == userdata) + else if (("can_mute" == userdata) && !is_self) { return voice_channel && !isMuted(getCurSelectedViewModelItem()->getUUID()); } @@ -1884,7 +1965,7 @@ bool LLFloaterIMContainer::enableModerateContextMenuItem(const std::string& user } // The last invoke is used to check whether the "can_allow_text_chat" will enabled - return LLVoiceClient::getInstance()->isParticipantAvatar(getCurSelectedViewModelItem()->getUUID()); + return LLVoiceClient::getInstance()->isParticipantAvatar(getCurSelectedViewModelItem()->getUUID()) && !is_self; } bool LLFloaterIMContainer::isGroupModerator() diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h index 78b3572111..b4a9d377ab 100644 --- a/indra/newview/llfloaterimcontainer.h +++ b/indra/newview/llfloaterimcontainer.h @@ -164,7 +164,7 @@ private: void doToSelectedGroup(const LLSD& userdata); static void confirmMuteAllCallback(const LLSD& notification, const LLSD& response); - bool enableModerateContextMenuItem(const std::string& userdata); + bool enableModerateContextMenuItem(const std::string& userdata, bool is_self = false); LLSpeaker * getSpeakerOfSelectedParticipant(LLSpeakerMgr * speaker_managerp); LLSpeakerMgr * getSpeakerMgrForSelectedParticipant(); bool isGroupModerator(); @@ -181,6 +181,7 @@ private: bool isParticipantListExpanded(); void idleUpdate(); // for convenience (self) from static idle + void idleProcessEvents(); LLButton* mExpandCollapseBtn; LLButton* mStubCollapseBtn; @@ -220,6 +221,7 @@ private: LLConversationViewSession* createConversationItemWidget(LLConversationItem* item); LLConversationViewParticipant* createConversationViewParticipant(LLConversationItem* item); bool onConversationModelEvent(const LLSD& event); + void handleConversationModelEvent(const LLSD& event); // Conversation list data LLPanel* mConversationsListPanel; // This is the main widget we add conversation widget to @@ -227,7 +229,10 @@ private: conversations_widgets_map mConversationsWidgets; LLConversationViewModel mConversationViewModel; LLFolderView* mConversationsRoot; - LLEventStream mConversationsEventStream; + LLEventStream mConversationsEventStream; + + typedef std::map<LLUUID, std::deque<LLSD> > conversations_items_deque; + conversations_items_deque mConversationEventQueue; LLTimer mParticipantRefreshTimer; }; diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index f9efd13608..3a850d4b68 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -67,6 +67,7 @@ #include "llviewerchat.h" #include "lltranslate.h" #include "llautoreplace.h" +#include "lluiusage.h" S32 LLFloaterIMNearbyChat::sLastSpecialChatChannel = 0; @@ -228,7 +229,7 @@ void LLFloaterIMNearbyChat::loadHistory() else { std::string legacy_name = gCacheName->buildLegacyName(from); - from_id = LLAvatarNameCache::findIdByName(legacy_name); + from_id = LLAvatarNameCache::getInstance()->findIdByName(legacy_name); } LLChat chat; @@ -697,6 +698,7 @@ void LLFloaterIMNearbyChat::sendChatFromViewer(const std::string &utf8text, ECha void LLFloaterIMNearbyChat::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL animate) { + LLUIUsage::instance().logCommand("Chat.Send"); // pseuo-command // Look for "/20 foo" channel chats. S32 channel = 0; LLWString out_text = stripChannelNumber(wtext, &channel); diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp index a4ab1af9a8..48e2b8dc14 100644 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -160,7 +160,6 @@ void LLFloaterIMSession::onClickCloseBtn(bool) else { LL_WARNS() << "Empty session with id: " << (mSessionID.asString()) << LL_ENDL; - return; } LLFloaterIMSessionTab::onClickCloseBtn(); diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index 3aee08482b..7541bb5efe 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -32,6 +32,8 @@ #include "llagent.h" #include "llagentcamera.h" #include "llavataractions.h" +#include "llavatariconctrl.h" +#include "llgroupiconctrl.h" #include "llchatentry.h" #include "llchathistory.h" #include "llchiclet.h" @@ -45,6 +47,9 @@ #include "llfloaterimnearbychat.h" const F32 REFRESH_INTERVAL = 1.0f; +const std::string ICN_GROUP("group_chat_icon"); +const std::string ICN_NEARBY("nearby_chat_icon"); +const std::string ICN_AVATAR("avatar_icon"); void cb_group_do_nothing() { @@ -465,9 +470,10 @@ void LLFloaterIMSessionTab::appendMessage(const LLChat& chat, const LLSD &args) } } - +static LLTrace::BlockTimerStatHandle FTM_BUILD_CONVERSATION_VIEW_PARTICIPANT("Build Conversation View"); void LLFloaterIMSessionTab::buildConversationViewParticipant() { + LL_RECORD_BLOCK_TIME(FTM_BUILD_CONVERSATION_VIEW_PARTICIPANT); // Clear the widget list since we are rebuilding afresh from the model conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin(); while (widget_it != mConversationsWidgets.end()) @@ -491,19 +497,28 @@ void LLFloaterIMSessionTab::buildConversationViewParticipant() while (current_participant_model != end_participant_model) { LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>(*current_participant_model); - addConversationViewParticipant(participant_model); + if (participant_model) + { + addConversationViewParticipant(participant_model); + } current_participant_model++; } } -void LLFloaterIMSessionTab::addConversationViewParticipant(LLConversationItem* participant_model) +void LLFloaterIMSessionTab::addConversationViewParticipant(LLConversationItem* participant_model, bool update_view) { + if (!participant_model) + { + // Nothing to do if the model is inexistent + return; + } + // Check if the model already has an associated view LLUUID uuid = participant_model->getUUID(); LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,uuid); // If not already present, create the participant view and attach it to the root, otherwise, just refresh it - if (widget) + if (widget && update_view) { updateConversationViewParticipant(uuid); // overkill? } @@ -522,10 +537,9 @@ void LLFloaterIMSessionTab::removeConversationViewParticipant(const LLUUID& part LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,participant_id); if (widget) { - mConversationsRoot->extractItem(widget); - delete widget; - mConversationsWidgets.erase(participant_id); + widget->destroyView(); } + mConversationsWidgets.erase(participant_id); } void LLFloaterIMSessionTab::updateConversationViewParticipant(const LLUUID& participant_id) @@ -693,6 +707,39 @@ void LLFloaterIMSessionTab::updateSessionName(const std::string& name) mInputEditor->setLabel(LLTrans::getString("IM_to_label") + " " + name); } +void LLFloaterIMSessionTab::updateChatIcon(const LLUUID& id) +{ + if (mSession) + { + if (mSession->isP2PSessionType()) + { + LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>(ICN_AVATAR); + icon->setVisible(true); + icon->setValue(id); + } + if (mSession->isAdHocSessionType()) + { + LLGroupIconCtrl* icon = getChild<LLGroupIconCtrl>(ICN_GROUP); + icon->setVisible(true); + } + if (mSession->isGroupSessionType()) + { + LLGroupIconCtrl* icon = getChild<LLGroupIconCtrl>(ICN_GROUP); + icon->setVisible(true); + icon->setValue(id); + } + } + else + { + if (mIsNearbyChat) + { + LLIconCtrl* icon = getChild<LLIconCtrl>(ICN_NEARBY); + icon->setVisible(true); + } + } + +} + void LLFloaterIMSessionTab::hideAllStandardButtons() { for (S32 i = 0; i < BUTTON_COUNT; i++) diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h index 1b4922fd73..375461cfc1 100644 --- a/indra/newview/llfloaterimsessiontab.h +++ b/indra/newview/llfloaterimsessiontab.h @@ -84,7 +84,7 @@ public: /*virtual*/ void setFocus(BOOL focus); // Handle the left hand participant list widgets - void addConversationViewParticipant(LLConversationItem* item); + void addConversationViewParticipant(LLConversationItem* item, bool update_view = true); void removeConversationViewParticipant(const LLUUID& participant_id); void updateConversationViewParticipant(const LLUUID& participant_id); void refreshConversation(); @@ -103,6 +103,8 @@ public: void restoreFloater(); void saveCollapsedState(); + void updateChatIcon(const LLUUID& id); + LLView* getChatHistory(); protected: diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp index ee3d633dd0..93a26f31cc 100644 --- a/indra/newview/llfloaterjoystick.cpp +++ b/indra/newview/llfloaterjoystick.cpp @@ -40,7 +40,17 @@ #include "llviewercontrol.h" #include "llappviewer.h" #include "llviewerjoystick.h" +#include "llviewerwindow.h" +#include "llwindow.h" #include "llcheckboxctrl.h" +#include "llcombobox.h" + +#if LL_WINDOWS && !LL_MESA_HEADLESS +// Require DirectInput version 8 +#define DIRECTINPUT_VERSION 0x0800 + +#include <dinput.h> +#endif static LLTrace::SampleStatHandle<> sJoystickAxis0("Joystick axis 0"), sJoystickAxis1("Joystick axis 1"), @@ -58,22 +68,51 @@ static LLTrace::SampleStatHandle<>* sJoystickAxes[6] = &sJoystickAxis5 }; + +#if LL_WINDOWS && !LL_MESA_HEADLESS + +BOOL CALLBACK di8_list_devices_callback(LPCDIDEVICEINSTANCE device_instance_ptr, LPVOID pvRef) +{ + // Note: If a single device can function as more than one DirectInput + // device type, it is enumerated as each device type that it supports. + // Capable of detecting devices like Oculus Rift + if (device_instance_ptr && pvRef) + { + std::string product_name = utf16str_to_utf8str(llutf16string(device_instance_ptr->tszProductName)); + S32 size = sizeof(GUID); + LLSD::Binary data; //just an std::vector + data.resize(size); + memcpy(&data[0], &device_instance_ptr->guidInstance /*POD _GUID*/, size); + + LLFloaterJoystick * floater = (LLFloaterJoystick*)pvRef; + LLSD value = data; + floater->addDevice(product_name, value); + } + return DIENUM_CONTINUE; +} +#endif + LLFloaterJoystick::LLFloaterJoystick(const LLSD& data) - : LLFloater(data) + : LLFloater(data), + mHasDeviceList(false) { + if (!LLViewerJoystick::getInstance()->isJoystickInitialized()) + { + LLViewerJoystick::getInstance()->init(false); + } + initFromSettings(); } void LLFloaterJoystick::draw() { - bool joystick_inited = LLViewerJoystick::getInstance()->isJoystickInitialized(); - getChildView("enable_joystick")->setEnabled(joystick_inited); - getChildView("joystick_type")->setEnabled(joystick_inited); - std::string desc = LLViewerJoystick::getInstance()->getDescription(); - if (desc.empty()) desc = getString("NoDevice"); - getChild<LLUICtrl>("joystick_type")->setValue(desc); - - LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); + LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); + bool joystick_inited = joystick->isJoystickInitialized(); + if (joystick_inited != mHasDeviceList) + { + refreshListOfDevices(); + } + for (U32 i = 0; i < 6; i++) { F32 value = joystick->getJoystickAxis(i); @@ -110,8 +149,8 @@ BOOL LLFloaterJoystick::postBuild() } } - mCheckJoystickEnabled = getChild<LLCheckBoxCtrl>("enable_joystick"); - childSetCommitCallback("enable_joystick",onCommitJoystickEnabled,this); + mJoysticksCombo = getChild<LLComboBox>("joystick_combo"); + childSetCommitCallback("joystick_combo",onCommitJoystickEnabled,this); mCheckFlycamEnabled = getChild<LLCheckBoxCtrl>("JoystickFlycamEnabled"); childSetCommitCallback("JoystickFlycamEnabled",onCommitJoystickEnabled,this); @@ -120,6 +159,7 @@ BOOL LLFloaterJoystick::postBuild() childSetAction("ok_btn", onClickOK, this); refresh(); + refreshListOfDevices(); return TRUE; } @@ -136,6 +176,7 @@ void LLFloaterJoystick::apply() void LLFloaterJoystick::initFromSettings() { mJoystickEnabled = gSavedSettings.getBOOL("JoystickEnabled"); + mJoystickId = gSavedSettings.getLLSD("JoystickDeviceUUID"); mJoystickAxis[0] = gSavedSettings.getS32("JoystickAxis0"); mJoystickAxis[1] = gSavedSettings.getS32("JoystickAxis1"); @@ -205,12 +246,80 @@ void LLFloaterJoystick::initFromSettings() void LLFloaterJoystick::refresh() { LLFloater::refresh(); + initFromSettings(); } +void LLFloaterJoystick::addDevice(std::string &name, LLSD& value) +{ + mJoysticksCombo->add(name, value, ADD_BOTTOM, 1); +} + +void LLFloaterJoystick::refreshListOfDevices() +{ + mJoysticksCombo->removeall(); + std::string no_device = getString("JoystickDisabled"); + LLSD value = LLSD::Integer(0); + addDevice(no_device, value); + + mHasDeviceList = false; + + // di8_devices_callback callback is immediate and happens in scope of getInputDevices() +#if LL_WINDOWS && !LL_MESA_HEADLESS + // space navigator is marked as DI8DEVCLASS_GAMECTRL in ndof lib + U32 device_type = DI8DEVCLASS_GAMECTRL; + void* callback = &di8_list_devices_callback; +#else + // MAC doesn't support device search yet + // On MAC there is an ndof_idsearch and it is possible to specify product + // and manufacturer in NDOF_Device for ndof_init_first to pick specific one + U32 device_type = 0; + void* callback = NULL; +#endif + if (gViewerWindow->getWindow()->getInputDevices(device_type, callback, this)) + { + mHasDeviceList = true; + } + + bool is_device_id_set = LLViewerJoystick::getInstance()->isDeviceUUIDSet(); + + if (LLViewerJoystick::getInstance()->isJoystickInitialized() && + (!mHasDeviceList || !is_device_id_set)) + { +#if LL_WINDOWS && !LL_MESA_HEADLESS + LL_WARNS() << "NDOF connected to device without using SL provided handle" << LL_ENDL; +#endif + std::string desc = LLViewerJoystick::getInstance()->getDescription(); + if (!desc.empty()) + { + LLSD value = LLSD::Integer(0); + addDevice(desc, value); + mHasDeviceList = true; + } + } + + if (gSavedSettings.getBOOL("JoystickEnabled") && mHasDeviceList) + { + if (is_device_id_set) + { + LLSD guid = LLViewerJoystick::getInstance()->getDeviceUUID(); + mJoysticksCombo->selectByValue(guid); + } + else + { + mJoysticksCombo->selectByValue(LLSD::Integer(1)); + } + } + else + { + mJoysticksCombo->selectByValue(LLSD::Integer(0)); + } +} + void LLFloaterJoystick::cancel() { gSavedSettings.setBOOL("JoystickEnabled", mJoystickEnabled); + gSavedSettings.setLLSD("JoystickDeviceUUID", mJoystickId); gSavedSettings.setS32("JoystickAxis0", mJoystickAxis[0]); gSavedSettings.setS32("JoystickAxis1", mJoystickAxis[1]); @@ -280,7 +389,21 @@ void LLFloaterJoystick::cancel() void LLFloaterJoystick::onCommitJoystickEnabled(LLUICtrl*, void *joy_panel) { LLFloaterJoystick* self = (LLFloaterJoystick*)joy_panel; - BOOL joystick_enabled = self->mCheckJoystickEnabled->get(); + + LLSD value = self->mJoysticksCombo->getValue(); + bool joystick_enabled = true; + if (value.isInteger()) + { + // ndof already has a device selected, we are just setting it enabled or disabled + joystick_enabled = value.asInteger(); + } + else + { + LLViewerJoystick::getInstance()->initDevice(value); + // else joystick is enabled, because combobox holds id of device + joystick_enabled = true; + } + gSavedSettings.setBOOL("JoystickEnabled", joystick_enabled); BOOL flycam_enabled = self->mCheckFlycamEnabled->get(); if (!joystick_enabled || !flycam_enabled) @@ -292,6 +415,12 @@ void LLFloaterJoystick::onCommitJoystickEnabled(LLUICtrl*, void *joy_panel) joystick->toggleFlycam(); } } + + std::string device_id = LLViewerJoystick::getInstance()->getDeviceUUIDString(); + gSavedSettings.setString("JoystickDeviceUUID", device_id); + LL_DEBUGS("Joystick") << "Selected " << device_id << " as joystick." << LL_ENDL; + + self->refreshListOfDevices(); } void LLFloaterJoystick::onClickRestoreSNDefaults(void *joy_panel) diff --git a/indra/newview/llfloaterjoystick.h b/indra/newview/llfloaterjoystick.h index a1b5951389..1d46efd3f6 100644 --- a/indra/newview/llfloaterjoystick.h +++ b/indra/newview/llfloaterjoystick.h @@ -31,6 +31,7 @@ #include "llstatview.h" class LLCheckBoxCtrl; +class LLComboBox; class LLFloaterJoystick : public LLFloater { @@ -45,8 +46,11 @@ public: virtual void draw(); static void setSNDefaults(); + void addDevice(std::string &name, LLSD& value); + protected: + void refreshListOfDevices(); void onClose(bool app_quitting); void onClickCloseBtn(bool app_quitting); @@ -65,6 +69,7 @@ private: private: // Device prefs bool mJoystickEnabled; + LLSD mJoystickId; S32 mJoystickAxis[7]; bool m3DCursor; bool mAutoLeveling; @@ -85,8 +90,10 @@ private: F32 mFlycamFeathering; // Controls that can disable the flycam - LLCheckBoxCtrl *mCheckJoystickEnabled; LLCheckBoxCtrl *mCheckFlycamEnabled; + LLComboBox *mJoysticksCombo; + + bool mHasDeviceList; // stats view LLStatBar* mAxisStatsBar[6]; diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 3098c6d118..af0e56e448 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -79,9 +79,11 @@ #include "lltrans.h" #include "llpanelexperiencelisteditor.h" #include "llpanelexperiencepicker.h" +#include "llpanelenvironment.h" #include "llexperiencecache.h" #include "llgroupactions.h" +#include "llenvironment.h" const F64 COVENANT_REFRESH_TIME_SEC = 60.0f; @@ -139,6 +141,38 @@ protected: LLPanelExperienceListEditor* mBlocked; }; + +class LLPanelLandEnvironment + : public LLPanelEnvironmentInfo +{ +public: + LLPanelLandEnvironment(LLSafeHandle<LLParcelSelection>& parcelp); + + virtual bool isRegion() const override { return false; } + virtual bool isLargeEnough() override + { + LLParcel *parcelp = mParcel->getParcel(); + return ((parcelp) ? (parcelp->getArea() >= MINIMUM_PARCEL_SIZE) : false); + } + + virtual BOOL postBuild() override; + virtual void refresh() override; + + virtual LLParcel * getParcel() override; + + virtual bool canEdit() override; + virtual S32 getParcelId() override; + +protected: + virtual void refreshFromSource() override; + + bool isSameRegion(); + + LLSafeHandle<LLParcelSelection> & mParcel; + S32 mLastParcelId; +}; + + // inserts maturity info(icon and text) into target textbox // names_floater - pointer to floater which contains strings with maturity icons filenames // str_to_parse is string in format "txt1[MATURITY]txt2" where maturity icon and text will be inserted instead of [MATURITY] @@ -227,7 +261,7 @@ LLPanelLandCovenant* LLFloaterLand::getCurrentPanelLandCovenant() // static void LLFloaterLand::refreshAll() { - LLFloaterLand* land_instance = LLFloaterReg::getTypedInstance<LLFloaterLand>("about_land"); + LLFloaterLand* land_instance = LLFloaterReg::findTypedInstance<LLFloaterLand>("about_land"); if(land_instance) { land_instance->refresh(); @@ -278,6 +312,7 @@ LLFloaterLand::LLFloaterLand(const LLSD& seed) mFactoryMap["land_media_panel"] = LLCallbackMap(createPanelLandMedia, this); mFactoryMap["land_access_panel"] = LLCallbackMap(createPanelLandAccess, this); mFactoryMap["land_experiences_panel"] = LLCallbackMap(createPanelLandExperiences, this); + mFactoryMap["land_environment_panel"] = LLCallbackMap(createPanelLandEnvironment, this); sObserver = new LLParcelSelectionObserver(); LLViewerParcelMgr::getInstance()->addObserver( sObserver ); @@ -319,6 +354,7 @@ void LLFloaterLand::refresh() mPanelAccess->refresh(); mPanelCovenant->refresh(); mPanelExperiences->refresh(); + mPanelEnvironment->refresh(); } @@ -387,6 +423,14 @@ void* LLFloaterLand::createPanelLandExperiences(void* data) return self->mPanelExperiences; } +//static +void* LLFloaterLand::createPanelLandEnvironment(void* data) +{ + LLFloaterLand* self = (LLFloaterLand*)data; + self->mPanelEnvironment = new LLPanelLandEnvironment(self->mParcel); + return self->mPanelEnvironment; +} + //--------------------------------------------------------------------------- // LLPanelLandGeneral @@ -2209,7 +2253,7 @@ void LLPanelLandOptions::refreshSearch() // effort to reduce search spam from small parcels. See also // the search crawler "grid-crawl.py" in secondlife.com/doc/app/search/ JC const S32 MIN_PARCEL_AREA_FOR_SEARCH = 128; - bool large_enough = parcel->getArea() > MIN_PARCEL_AREA_FOR_SEARCH; + bool large_enough = parcel->getArea() >= MIN_PARCEL_AREA_FOR_SEARCH; if (large_enough) { if (can_change) @@ -3268,3 +3312,144 @@ void LLPanelLandExperiences::refresh() refreshPanel(mAllowed, EXPERIENCE_KEY_TYPE_ALLOWED); refreshPanel(mBlocked, EXPERIENCE_KEY_TYPE_BLOCKED); } + +//========================================================================= + +LLPanelLandEnvironment::LLPanelLandEnvironment(LLParcelSelectionHandle& parcel) : + LLPanelEnvironmentInfo(), + mParcel(parcel), + mLastParcelId(INVALID_PARCEL_ID) +{ +} + +BOOL LLPanelLandEnvironment::postBuild() +{ + if (!LLPanelEnvironmentInfo::postBuild()) + return FALSE; + + getChild<LLUICtrl>(BTN_USEDEFAULT)->setLabelArg("[USEDEFAULT]", getString(STR_LABEL_USEREGION)); + getChild<LLUICtrl>(CHK_ALLOWOVERRIDE)->setVisible(FALSE); + getChild<LLUICtrl>(PNL_REGION_MSG)->setVisible(FALSE); + getChild<LLUICtrl>(PNL_ENVIRONMENT_ALTITUDES)->setVisible(TRUE); + + return TRUE; +} + +void LLPanelLandEnvironment::refresh() +{ + if (gDisconnected) + return; + + commitDayLenOffsetChanges(false); // commit unsaved changes if any + + if (!isSameRegion()) + { + setCrossRegion(true); + mCurrentEnvironment.reset(); + mLastParcelId = INVALID_PARCEL_ID; + mCurEnvVersion = INVALID_PARCEL_ENVIRONMENT_VERSION; + setControlsEnabled(false); + return; + } + + if (mLastParcelId != getParcelId()) + { + mCurEnvVersion = INVALID_PARCEL_ENVIRONMENT_VERSION; + mCurrentEnvironment.reset(); + } + + if (!mCurrentEnvironment && mCurEnvVersion <= INVALID_PARCEL_ENVIRONMENT_VERSION) + { + refreshFromSource(); + return; + } + + LLPanelEnvironmentInfo::refresh(); +} + +void LLPanelLandEnvironment::refreshFromSource() +{ + LLParcel *parcel = getParcel(); + + if (!LLEnvironment::instance().isExtendedEnvironmentEnabled()) + { + setNoEnvironmentSupport(true); + setControlsEnabled(false); + mCurEnvVersion = INVALID_PARCEL_ENVIRONMENT_VERSION; + return; + } + setNoEnvironmentSupport(false); + + if (!parcel) + { + setNoSelection(true); + setControlsEnabled(false); + mCurEnvVersion = INVALID_PARCEL_ENVIRONMENT_VERSION; + return; + } + + setNoSelection(false); + if (isSameRegion()) + { + LL_DEBUGS("ENVIRONMENT") << "Requesting environment for parcel " << parcel->getLocalID() << ", known version " << mCurEnvVersion << LL_ENDL; + setCrossRegion(false); + + LLHandle<LLPanel> that_h = getHandle(); + + if (mCurEnvVersion < UNSET_PARCEL_ENVIRONMENT_VERSION) + { + // to mark as requesting + mCurEnvVersion = parcel->getParcelEnvironmentVersion(); + } + mLastParcelId = parcel->getLocalID(); + + LLEnvironment::instance().requestParcel(parcel->getLocalID(), + [that_h](S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envifo) + { + LLPanelLandEnvironment *that = (LLPanelLandEnvironment*)that_h.get(); + if (!that) return; + that->mLastParcelId = parcel_id; + that->onEnvironmentReceived(parcel_id, envifo); + }); + } + else + { + setCrossRegion(true); + mCurrentEnvironment.reset(); + mLastParcelId = INVALID_PARCEL_ID; + mCurEnvVersion = INVALID_PARCEL_ENVIRONMENT_VERSION; + } + setControlsEnabled(false); +} + + +bool LLPanelLandEnvironment::isSameRegion() +{ + LLViewerRegion* regionp = LLViewerParcelMgr::instance().getSelectionRegion(); + + return (!regionp || (regionp->getRegionID() == gAgent.getRegion()->getRegionID())); +} + +LLParcel *LLPanelLandEnvironment::getParcel() +{ + return mParcel->getParcel(); +} + + +bool LLPanelLandEnvironment::canEdit() +{ + LLParcel *parcel = getParcel(); + if (!parcel) + return false; + + return LLEnvironment::instance().canAgentUpdateParcelEnvironment(parcel) && mAllowOverride; +} + +S32 LLPanelLandEnvironment::getParcelId() +{ + LLParcel *parcel = getParcel(); + if (!parcel) + return INVALID_PARCEL_ID; + + return parcel->getLocalID(); +} diff --git a/indra/newview/llfloaterland.h b/indra/newview/llfloaterland.h index 0c49d78a20..5d9b411f04 100644 --- a/indra/newview/llfloaterland.h +++ b/indra/newview/llfloaterland.h @@ -67,6 +67,7 @@ class LLPanelLandRenters; class LLPanelLandCovenant; class LLParcel; class LLPanelLandExperiences; +class LLPanelLandEnvironment; class LLFloaterLand : public LLFloater @@ -103,6 +104,7 @@ protected: static void* createPanelLandMedia(void* data); static void* createPanelLandAccess(void* data); static void* createPanelLandExperiences(void* data); + static void* createPanelLandEnvironment(void* data); static void* createPanelLandBan(void* data); @@ -119,6 +121,7 @@ protected: LLPanelLandAccess* mPanelAccess; LLPanelLandCovenant* mPanelCovenant; LLPanelLandExperiences* mPanelExperiences; + LLPanelLandEnvironment *mPanelEnvironment; LLSafeHandle<LLParcelSelection> mParcel; diff --git a/indra/newview/llfloaterlandholdings.cpp b/indra/newview/llfloaterlandholdings.cpp index f34760a6bf..749a3d2686 100644 --- a/indra/newview/llfloaterlandholdings.cpp +++ b/indra/newview/llfloaterlandholdings.cpp @@ -51,6 +51,9 @@ #include "llgroupactions.h" +const std::string LINDEN_HOMES_SKU = "131"; +bool LLFloaterLandHoldings::sHasLindenHome = false; + // protected LLFloaterLandHoldings::LLFloaterLandHoldings(const LLSD& key) : LLFloater(key), @@ -148,10 +151,24 @@ void LLFloaterLandHoldings::refresh() void LLFloaterLandHoldings::processPlacesReply(LLMessageSystem* msg, void**) { LLFloaterLandHoldings* self = LLFloaterReg::findTypedInstance<LLFloaterLandHoldings>("land_holdings"); - - // Is this packet from an old, closed window? + S32 count = msg->getNumberOfBlocks("QueryData"); + std::string land_sku; + sHasLindenHome = false; if (!self) { + for (S32 i = 0; i < count; i++) + { + if ( msg->getSizeFast(_PREHASH_QueryData, i, _PREHASH_ProductSKU) > 0 ) + { + msg->getStringFast( _PREHASH_QueryData, _PREHASH_ProductSKU, land_sku, i); + + if (LINDEN_HOMES_SKU == land_sku) + { + sHasLindenHome = true; + return; + } + } + } return; } @@ -174,12 +191,9 @@ void LLFloaterLandHoldings::processPlacesReply(LLMessageSystem* msg, void**) F32 global_x; F32 global_y; std::string sim_name; - std::string land_sku; std::string land_type; - S32 i; - S32 count = msg->getNumberOfBlocks("QueryData"); - for (i = 0; i < count; i++) + for (S32 i = 0; i < count; i++) { msg->getUUID("QueryData", "OwnerID", owner_id, i); msg->getString("QueryData", "Name", name, i); @@ -196,6 +210,10 @@ void LLFloaterLandHoldings::processPlacesReply(LLMessageSystem* msg, void**) msg->getStringFast( _PREHASH_QueryData, _PREHASH_ProductSKU, land_sku, i); LL_INFOS() << "Land sku: " << land_sku << LL_ENDL; land_type = LLProductInfoRequestManager::instance().getDescriptionForSku(land_sku); + if (LINDEN_HOMES_SKU == land_sku) + { + sHasLindenHome = true; + } } else { diff --git a/indra/newview/llfloaterlandholdings.h b/indra/newview/llfloaterlandholdings.h index d1d510bb40..90e75b1062 100644 --- a/indra/newview/llfloaterlandholdings.h +++ b/indra/newview/llfloaterlandholdings.h @@ -57,6 +57,8 @@ public: static void onGrantList(void* data); + static bool sHasLindenHome; + protected: void refreshAggregates(); diff --git a/indra/newview/llfloaterlinkreplace.cpp b/indra/newview/llfloaterlinkreplace.cpp index 10cce3bd22..595d584799 100644 --- a/indra/newview/llfloaterlinkreplace.cpp +++ b/indra/newview/llfloaterlinkreplace.cpp @@ -32,6 +32,8 @@ #include "llagent.h" #include "llappearancemgr.h" #include "lllineeditor.h" +#include "llnotificationsutil.h" +#include "llnotifications.h" #include "lltextbox.h" #include "llviewercontrol.h" @@ -142,37 +144,72 @@ void LLFloaterLinkReplace::onStartClicked() LL_WARNS() << "Cannot replace. Source and target are identical." << LL_ENDL; return; } + + const LLUUID& source_item_id = gInventory.getLinkedItemID(mSourceUUID); + LLViewerInventoryItem *source_item = gInventory.getItem(source_item_id); + const LLUUID& target_item_id = gInventory.getLinkedItemID(mTargetUUID); + LLViewerInventoryItem *target_item = gInventory.getItem(target_item_id); - LLInventoryModel::cat_array_t cat_array; - LLLinkedItemIDMatches is_linked_item_match(mSourceUUID); - gInventory.collectDescendentsIf(gInventory.getRootFolderID(), - cat_array, - mRemainingInventoryItems, - LLInventoryModel::INCLUDE_TRASH, - is_linked_item_match); - LL_INFOS() << "Found " << mRemainingInventoryItems.size() << " inventory links that need to be replaced." << LL_ENDL; - if (mRemainingInventoryItems.size() > 0) + LLNotification::Params params("ConfirmReplaceLink"); + params.functor.function(boost::bind(&LLFloaterLinkReplace::onStartClickedResponse, this, _1, _2)); + if (source_item && source_item->isWearableType() && source_item->getWearableType() <= LLWearableType::WT_EYES) { - LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); - if (target_item) + if(target_item && target_item->isWearableType() && source_item->getWearableType() == target_item->getWearableType()) { - mRemainingItems = (U32)mRemainingInventoryItems.size(); - - LLStringUtil::format_map_t args; - args["NUM"] = llformat("%d", mRemainingItems); - mStatusText->setText(getString("ItemsRemaining", args)); - - mStartBtn->setEnabled(FALSE); - mRefreshBtn->setEnabled(FALSE); - - mEventTimer.start(); - tick(); + LLNotifications::instance().forceResponse(params, 0); } else { - mStatusText->setText(getString("TargetNotFound")); - LL_WARNS() << "Link replace target not found." << LL_ENDL; + LLSD args; + args["TYPE"] = LLWearableType::getTypeName(source_item->getWearableType()); + params.substitutions(args); + LLNotifications::instance().add(params); + } + } + else + { + LLNotifications::instance().forceResponse(params, 0); + } +} + +void LLFloaterLinkReplace::onStartClickedResponse(const LLSD& notification, const LLSD& response) +{ + + if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) + { + + LLInventoryModel::cat_array_t cat_array; + LLLinkedItemIDMatches is_linked_item_match(mSourceUUID); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cat_array, + mRemainingInventoryItems, + LLInventoryModel::INCLUDE_TRASH, + is_linked_item_match); + LL_INFOS() << "Found " << mRemainingInventoryItems.size() << " inventory links that need to be replaced." << LL_ENDL; + + if (mRemainingInventoryItems.size() > 0) + { + LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); + if (target_item) + { + mRemainingItems = (U32)mRemainingInventoryItems.size(); + + LLStringUtil::format_map_t args; + args["NUM"] = llformat("%d", mRemainingItems); + mStatusText->setText(getString("ItemsRemaining", args)); + + mStartBtn->setEnabled(FALSE); + mRefreshBtn->setEnabled(FALSE); + + mEventTimer.start(); + tick(); + } + else + { + mStatusText->setText(getString("TargetNotFound")); + LL_WARNS() << "Link replace target not found." << LL_ENDL; + } } } } diff --git a/indra/newview/llfloaterlinkreplace.h b/indra/newview/llfloaterlinkreplace.h index dd5c301206..060773f93e 100644 --- a/indra/newview/llfloaterlinkreplace.h +++ b/indra/newview/llfloaterlinkreplace.h @@ -94,6 +94,7 @@ public: private: void checkEnableStart(); void onStartClicked(); + void onStartClickedResponse(const LLSD& notification, const LLSD& response); void decreaseOpenItemCount(); void updateFoundLinks(); void processBatch(LLInventoryModel::item_array_t items); diff --git a/indra/newview/llfloaterloadprefpreset.cpp b/indra/newview/llfloaterloadprefpreset.cpp index 403db35cc0..8ed76b1df4 100644 --- a/indra/newview/llfloaterloadprefpreset.cpp +++ b/indra/newview/llfloaterloadprefpreset.cpp @@ -42,7 +42,8 @@ LLFloaterLoadPrefPreset::LLFloaterLoadPrefPreset(const LLSD &key) // virtual BOOL LLFloaterLoadPrefPreset::postBuild() -{ LLFloaterPreference* preferences = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences"); +{ + LLFloaterPreference* preferences = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences"); if (preferences) { preferences->addDependentFloater(this); @@ -57,14 +58,27 @@ BOOL LLFloaterLoadPrefPreset::postBuild() void LLFloaterLoadPrefPreset::onOpen(const LLSD& key) { mSubdirectory = key.asString(); - std::string floater_title = getString(std::string("title_") + mSubdirectory); - - setTitle(floater_title); + std::string title_type = std::string("title_") + mSubdirectory; + if (hasString(title_type)) + { + std::string floater_title = getString(title_type); + setTitle(floater_title); + } + else + { + LL_WARNS() << title_type << " not found" << LL_ENDL; + setTitle(title_type); + } LLComboBox* combo = getChild<LLComboBox>("preset_combo"); EDefaultOptions option = DEFAULT_TOP; LLPresetsManager::getInstance()->setPresetNamesInComboBox(mSubdirectory, combo, option); + std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive"); + if (!preset_graphic_active.empty()) + { + combo->setSimple(preset_graphic_active); + } } void LLFloaterLoadPrefPreset::onPresetsListChange() @@ -73,6 +87,11 @@ void LLFloaterLoadPrefPreset::onPresetsListChange() EDefaultOptions option = DEFAULT_TOP; LLPresetsManager::getInstance()->setPresetNamesInComboBox(mSubdirectory, combo, option); + std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive"); + if (!preset_graphic_active.empty()) + { + combo->setSimple(preset_graphic_active); + } } void LLFloaterLoadPrefPreset::onBtnCancel() diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp index 889d017389..524162ba51 100644 --- a/indra/newview/llfloatermarketplacelistings.cpp +++ b/indra/newview/llfloatermarketplacelistings.cpp @@ -103,14 +103,17 @@ void LLPanelMarketplaceListings::buildAllPanels() panel = buildInventoryPanel("Active Items", "panel_marketplace_listings_listed.xml"); panel->getFilter().setFilterMarketplaceActiveFolders(); panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems"); + panel->getFilter().setDefaultEmptyLookupMessage("MarketplaceNoListing"); panel->getFilter().markDefault(); panel = buildInventoryPanel("Inactive Items", "panel_marketplace_listings_unlisted.xml"); panel->getFilter().setFilterMarketplaceInactiveFolders(); panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems"); + panel->getFilter().setDefaultEmptyLookupMessage("MarketplaceNoListing"); panel->getFilter().markDefault(); panel = buildInventoryPanel("Unassociated Items", "panel_marketplace_listings_unassociated.xml"); panel->getFilter().setFilterMarketplaceUnassociatedFolders(); panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems"); + panel->getFilter().setDefaultEmptyLookupMessage("MarketplaceNoListing"); panel->getFilter().markDefault(); // Set the tab panel diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index cb58cfdd0a..d9edd4dc30 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -27,7 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "llmodelloader.h" -#include "lldaeloader.h" +#include "llmodelpreview.h" #include "llfloatermodelpreview.h" @@ -40,16 +40,7 @@ #include "llagent.h" #include "llbutton.h" #include "llcombobox.h" -#include "lldatapacker.h" -#include "lldrawable.h" -#include "llrender.h" -#include "llface.h" -#include "lleconomy.h" #include "llfocusmgr.h" -#include "llfloaterperms.h" -#include "lliconctrl.h" -#include "llmatrix4a.h" -#include "llmenubutton.h" #include "llmeshrepository.h" #include "llnotificationsutil.h" #include "llsdutil_math.h" @@ -57,44 +48,26 @@ #include "lltextbox.h" #include "lltoolmgr.h" #include "llui.h" -#include "llvector4a.h" -#include "llviewercamera.h" #include "llviewerwindow.h" -#include "llvoavatar.h" -#include "llvoavatarself.h" #include "pipeline.h" -#include "lluictrlfactory.h" #include "llviewercontrol.h" -#include "llviewermenu.h" -#include "llviewermenufile.h" -#include "llviewerregion.h" -#include "llviewertexturelist.h" +#include "llviewermenufile.h" //LLFilePickerThread #include "llstring.h" #include "llbutton.h" #include "llcheckboxctrl.h" -#include "llradiogroup.h" -#include "llsdserialize.h" #include "llsliderctrl.h" #include "llspinctrl.h" -#include "lltoggleablemenu.h" +#include "lltabcontainer.h" #include "lltrans.h" -#include "llvfile.h" -#include "llvfs.h" #include "llcallbacklist.h" -#include "llviewerobjectlist.h" -#include "llanimationstates.h" +#include "llviewertexteditor.h" #include "llviewernetwork.h" -#include "llviewershadermgr.h" -#include "glod/glod.h" -#include <boost/algorithm/string.hpp> //static S32 LLFloaterModelPreview::sUploadAmount = 10; LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; -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 // should be represented by Retain spinner with values from 1 to 100 by 1. @@ -107,110 +80,20 @@ const double RETAIN_COEFFICIENT = 100; // should be represented by Smooth combobox with only 10 values. // So this const is used as a size of Smooth combobox list. const S32 SMOOTH_VALUES_NUMBER = 10; +const S32 PREVIEW_RENDER_SIZE = 1024; +const F32 PREVIEW_CAMERA_DISTANCE = 16.f; -void drawBoxOutline(const LLVector3& pos, const LLVector3& size); - - -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+1] = +class LLMeshFilePicker : public LLFilePickerThread { - "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+1] = -{ - "lowest_vertices", - "low_vertices", - "medium_vertices", - "high_vertices", - "I went off the end of the lod_vertices_name array. Me so smart." -}; +public: + LLMeshFilePicker(LLModelPreview* mp, S32 lod); + virtual void notify(const std::vector<std::string>& filenames); -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." +private: + LLModelPreview* mMP; + S32 mLOD; }; -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+1] = -{ - "ModelImport_Status_Good", - "ModelImport_Status_Warning", - "ModelImport_Status_Error", - "I went off the end of the lod_status_image array. Me so smart." -}; - -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." -}; - -BOOL stop_gloderror() -{ - GLuint error = glodGetError(); - - if (error != GLOD_NO_ERROR) - { - LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL; - return TRUE; - } - - return FALSE; -} - -LLViewerFetchedTexture* bindMaterialDiffuseTexture(const LLImportMaterial& material) -{ - LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_PREVIEW); - - if (texture) - { - if (texture->getDiscardLevel() > -1) - { - gGL.getTexUnit(0)->bind(texture, true); - return texture; - } - } - - return NULL; -} - -std::string stripSuffix(std::string name) -{ - if ((name.find("_LOD") != -1) || (name.find("_PHYS") != -1)) - { - return name.substr(0, name.rfind('_')); - } - return name; -} - LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) { @@ -220,6 +103,11 @@ LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) void LLMeshFilePicker::notify(const std::vector<std::string>& filenames) { + if(LLAppViewer::instance()->quitRequested()) + { + return; + } + if (filenames.size() > 0) { mMP->loadModel(filenames[0], mLOD); @@ -231,37 +119,16 @@ void LLMeshFilePicker::notify(const std::vector<std::string>& filenames) } } -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++; - } -} - //----------------------------------------------------------------------------- // LLFloaterModelPreview() //----------------------------------------------------------------------------- LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : LLFloaterModelUploadBase(key), mUploadBtn(NULL), -mCalculateBtn(NULL) +mCalculateBtn(NULL), +mUploadLogText(NULL), +mTabContainer(NULL), +mAvatarTabIndex(0) { sInstance = this; mLastMouseX = 0; @@ -304,10 +171,11 @@ BOOL LLFloaterModelPreview::postBuild() getChild<LLSpinCtrl>("lod_triangle_limit_" + lod_name[lod])->setCommitCallback(boost::bind(&LLFloaterModelPreview::onLODParamCommit, this, lod, true)); } - childSetCommitCallback("upload_skin", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL); - childSetCommitCallback("upload_joints", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL); - childSetCommitCallback("lock_scale_if_joint_position", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL); - childSetCommitCallback("upload_textures", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL); + // Upload/avatar options, they need to refresh errors/notifications + childSetCommitCallback("upload_skin", boost::bind(&LLFloaterModelPreview::onUploadOptionChecked, this, _1), NULL); + childSetCommitCallback("upload_joints", boost::bind(&LLFloaterModelPreview::onUploadOptionChecked, this, _1), NULL); + childSetCommitCallback("lock_scale_if_joint_position", boost::bind(&LLFloaterModelPreview::onUploadOptionChecked, this, _1), NULL); + childSetCommitCallback("upload_textures", boost::bind(&LLFloaterModelPreview::onUploadOptionChecked, this, _1), NULL); childSetTextArg("status", "[STATUS]", getString("status_idle")); @@ -318,10 +186,6 @@ BOOL LLFloaterModelPreview::postBuild() childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); - childSetCommitCallback("upload_skin", onUploadSkinCommit, this); - childSetCommitCallback("upload_joints", onUploadJointsCommit, this); - childSetCommitCallback("lock_scale_if_joint_position", onUploadJointsCommit, this); - childSetCommitCallback("import_scale", onImportScaleCommit, this); childSetCommitCallback("pelvis_offset", onPelvisOffsetCommit, this); @@ -330,13 +194,20 @@ BOOL LLFloaterModelPreview::postBuild() getChild<LLCheckBoxCtrl>("show_edges")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1)); getChild<LLCheckBoxCtrl>("show_physics")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1)); getChild<LLCheckBoxCtrl>("show_textures")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1)); - getChild<LLCheckBoxCtrl>("show_skin_weight")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1)); + getChild<LLCheckBoxCtrl>("show_skin_weight")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onShowSkinWeightChecked, this, _1)); + getChild<LLCheckBoxCtrl>("show_joint_overrides")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1)); getChild<LLCheckBoxCtrl>("show_joint_positions")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1)); childDisable("upload_skin"); childDisable("upload_joints"); childDisable("lock_scale_if_joint_position"); + childSetVisible("skin_too_many_joints", false); + childSetVisible("skin_unknown_joint", false); + + childSetVisible("warning_title", false); + childSetVisible("warning_message", false); + initDecompControls(); LLView* preview_panel = getChild<LLView>("preview_panel"); @@ -392,6 +263,12 @@ BOOL LLFloaterModelPreview::postBuild() mUploadBtn = getChild<LLButton>("ok_btn"); mCalculateBtn = getChild<LLButton>("calculate_btn"); + mUploadLogText = getChild<LLViewerTextEditor>("log_text"); + mTabContainer = getChild<LLTabContainer>("import_tab"); + + LLPanel *panel = mTabContainer->getPanelByName("rigging_panel"); + mAvatarTabIndex = mTabContainer->getIndexForPanel(panel); + panel->getChild<LLScrollListCtrl>("joints_list")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onJointListSelection, this)); if (LLConvexDecomposition::getInstance() != NULL) { @@ -408,6 +285,24 @@ BOOL LLFloaterModelPreview::postBuild() } //----------------------------------------------------------------------------- +// reshape() +//----------------------------------------------------------------------------- + +void LLFloaterModelPreview::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + LLFloaterModelUploadBase::reshape(width, height, called_from_parent); + + LLView* preview_panel = getChild<LLView>("preview_panel"); + LLRect rect = preview_panel->getRect(); + + if (rect != mPreviewRect) + { + mModelPreview->refresh(); + mPreviewRect = preview_panel->getRect(); + } +} + +//----------------------------------------------------------------------------- // LLFloaterModelPreview() //----------------------------------------------------------------------------- LLFloaterModelPreview::~LLFloaterModelPreview() @@ -430,18 +325,95 @@ void LLFloaterModelPreview::initModelPreview() delete mModelPreview; } - mModelPreview = new LLModelPreview(512, 512, this ); - mModelPreview->setPreviewTarget(16.f); + S32 tex_width = 512; + S32 tex_height = 512; + + S32 max_width = llmin(PREVIEW_RENDER_SIZE, (S32)gPipeline.mScreenWidth); + S32 max_height = llmin(PREVIEW_RENDER_SIZE, (S32)gPipeline.mScreenHeight); + + while ((tex_width << 1) < max_width) + { + tex_width <<= 1; + } + while ((tex_height << 1) < max_height) + { + tex_height <<= 1; + } + + mModelPreview = new LLModelPreview(tex_width, tex_height, this); + mModelPreview->setPreviewTarget(PREVIEW_CAMERA_DISTANCE); mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5)); - mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, _1)); + mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelPreview::modelUpdated, this, _1)); +} + +void LLFloaterModelPreview::onUploadOptionChecked(LLUICtrl* ctrl) +{ + if (mModelPreview) + { + auto name = ctrl->getName(); + bool value = ctrl->getValue().asBoolean(); + // update the option and notifications + // (this is a bit convoluted, because of the current structure of mModelPreview) + if (name == "upload_skin") + { + childSetValue("show_skin_weight", value); + mModelPreview->mViewOption["show_skin_weight"] = value; + if (!value) + { + mModelPreview->mViewOption["show_joint_overrides"] = false; + mModelPreview->mViewOption["show_joint_positions"] = false; + childSetValue("show_joint_overrides", false); + childSetValue("show_joint_positions", false); + } + } + else if (name == "upload_joints") + { + if (mModelPreview->mViewOption["show_skin_weight"]) + { + childSetValue("show_joint_overrides", value); + mModelPreview->mViewOption["show_joint_overrides"] = value; + } + } + else if (name == "upload_textures") + { + childSetValue("show_textures", value); + mModelPreview->mViewOption["show_textures"] = value; + } + else if (name == "lock_scale_if_joint_position") + { + mModelPreview->mViewOption["lock_scale_if_joint_position"] = value; + } + + mModelPreview->refresh(); // a 'dirty' flag for render + mModelPreview->resetPreviewTarget(); + mModelPreview->clearBuffers(); + mModelPreview->mDirty = true; + } + // set the button visible, it will be refreshed later + toggleCalculateButton(true); +} + +void LLFloaterModelPreview::onShowSkinWeightChecked(LLUICtrl* ctrl) +{ + if (mModelPreview) + { + mModelPreview->mCameraOffset.clearVec(); + onViewOptionChecked(ctrl); + } } void LLFloaterModelPreview::onViewOptionChecked(LLUICtrl* ctrl) { if (mModelPreview) { - mModelPreview->mViewOption[ctrl->getName()] = !mModelPreview->mViewOption[ctrl->getName()]; - + auto name = ctrl->getName(); + mModelPreview->mViewOption[name] = !mModelPreview->mViewOption[name]; + if (name == "show_physics") + { + auto enabled = mModelPreview->mViewOption[name]; + childSetEnabled("physics_explode", enabled); + childSetVisible("physics_explode", enabled); + } mModelPreview->refresh(); } } @@ -476,6 +448,12 @@ void LLFloaterModelPreview::disableViewOption(const std::string& option) setViewOptionEnabled(option, false); } +void LLFloaterModelPreview::loadHighLodModel() +{ + mModelPreview->mLookUpLodFiles = true; + loadModel(3); +} + void LLFloaterModelPreview::loadModel(S32 lod) { mModelPreview->mLoading = true; @@ -497,20 +475,16 @@ void LLFloaterModelPreview::loadModel(S32 lod, const std::string& file_name, boo void LLFloaterModelPreview::onClickCalculateBtn() { + clearLogTab(); + addStringToLog("Calculating model data.", false); mModelPreview->rebuildUploadData(); bool upload_skinweights = childGetValue("upload_skin").asBoolean(); bool upload_joint_positions = childGetValue("upload_joints").asBoolean(); bool lock_scale_if_joint_position = childGetValue("lock_scale_if_joint_position").asBoolean(); - if (upload_joint_positions) - { - // Diagnostic message showing list of joints for which joint offsets are defined. - // FIXME - given time, would be much better to put this in the UI, in updateStatusMessages(). - mModelPreview->getPreviewAvatar()->showAttachmentOverrides(); - } - - mUploadModelUrl.clear(); + mUploadModelUrl.clear(); + mModelPhysicsFee.clear(); gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale, childGetValue("upload_textures").asBoolean(), @@ -522,6 +496,132 @@ void LLFloaterModelPreview::onClickCalculateBtn() mUploadBtn->setEnabled(false); } +// Modified cell_params, make sure to clear values if you have to reuse cell_params outside of this function +void add_row_to_list(LLScrollListCtrl *listp, + LLScrollListCell::Params &cell_params, + const LLSD &item_value, + const std::string &name, + const LLSD &vx, + const LLSD &vy, + const LLSD &vz) +{ + LLScrollListItem::Params item_params; + item_params.value = item_value; + + cell_params.column = "model_name"; + cell_params.value = name; + + item_params.columns.add(cell_params); + + cell_params.column = "axis_x"; + cell_params.value = vx; + item_params.columns.add(cell_params); + + cell_params.column = "axis_y"; + cell_params.value = vy; + item_params.columns.add(cell_params); + + cell_params.column = "axis_z"; + cell_params.value = vz; + + item_params.columns.add(cell_params); + + listp->addRow(item_params); +} + +void populate_list_with_overrides(LLScrollListCtrl *listp, const LLJointOverrideData &data, bool include_overrides) +{ + if (data.mModelsNoOverrides.empty() && data.mPosOverrides.empty()) + { + return; + } + + static const std::string no_override_placeholder = "-"; + + S32 count = 0; + LLScrollListCell::Params cell_params; + cell_params.font = LLFontGL::getFontSansSerif(); + // Start out right justifying numeric displays + cell_params.font_halign = LLFontGL::HCENTER; + + std::map<std::string, LLVector3>::const_iterator map_iter = data.mPosOverrides.begin(); + std::map<std::string, LLVector3>::const_iterator map_end = data.mPosOverrides.end(); + while (map_iter != map_end) + { + if (include_overrides) + { + add_row_to_list(listp, + cell_params, + LLSD::Integer(count), + map_iter->first, + LLSD::Real(map_iter->second.mV[VX]), + LLSD::Real(map_iter->second.mV[VY]), + LLSD::Real(map_iter->second.mV[VZ])); + } + else + { + add_row_to_list(listp, + cell_params, + LLSD::Integer(count), + map_iter->first, + no_override_placeholder, + no_override_placeholder, + no_override_placeholder); + } + count++; + map_iter++; + } + + std::set<std::string>::const_iterator set_iter = data.mModelsNoOverrides.begin(); + std::set<std::string>::const_iterator set_end = data.mModelsNoOverrides.end(); + while (set_iter != set_end) + { + add_row_to_list(listp, + cell_params, + LLSD::Integer(count), + *set_iter, + no_override_placeholder, + no_override_placeholder, + no_override_placeholder); + count++; + set_iter++; + } +} + +void LLFloaterModelPreview::onJointListSelection() +{ + S32 display_lod = mModelPreview->mPreviewLOD; + LLPanel *panel = mTabContainer->getPanelByName("rigging_panel"); + LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); + LLScrollListCtrl *joints_pos = panel->getChild<LLScrollListCtrl>("pos_overrides_list"); + LLScrollListCtrl *joints_scale = panel->getChild<LLScrollListCtrl>("scale_overrides_list"); + LLTextBox *joint_pos_descr = panel->getChild<LLTextBox>("pos_overrides_descr"); + + joints_pos->deleteAllItems(); + joints_scale->deleteAllItems(); + + LLScrollListItem *selected = joints_list->getFirstSelected(); + if (selected) + { + std::string label = selected->getValue().asString(); + LLJointOverrideData &data = mJointOverrides[display_lod][label]; + bool upload_joint_positions = childGetValue("upload_joints").asBoolean(); + populate_list_with_overrides(joints_pos, data, upload_joint_positions); + + joint_pos_descr->setTextArg("[JOINT]", label); + mSelectedJointName = label; + } + else + { + // temporary value (shouldn't happen) + std::string label = "mPelvis"; + joint_pos_descr->setTextArg("[JOINT]", label); + mSelectedJointName.clear(); + } + + // Note: We can make a version of renderBones() to highlight selected joint +} + void LLFloaterModelPreview::onDescriptionKeystroke(LLUICtrl* ctrl) { // Workaround for SL-4186, server doesn't allow name changes after 'calculate' stage @@ -566,33 +666,6 @@ void LLFloaterModelPreview::onPelvisOffsetCommit( LLUICtrl*, void* userdata ) } //static -void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - fp->mModelPreview->refresh(); - fp->mModelPreview->resetPreviewTarget(); - fp->mModelPreview->clearBuffers(); -} - -//static void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) { LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; @@ -622,6 +695,7 @@ void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userda void LLFloaterModelPreview::toggleGenarateNormals() { bool enabled = childGetValue("gen_normals").asBoolean(); + mModelPreview->mViewOption["gen_normals"] = enabled; childSetEnabled("crease_angle", enabled); if(enabled) { mModelPreview->generateNormals(); @@ -665,6 +739,27 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) } } +void LLFloaterModelPreview::draw3dPreview() +{ + gGL.color3f(1.f, 1.f, 1.f); + + gGL.getTexUnit(0)->bind(mModelPreview); + + gGL.begin( LLRender::QUADS ); + { + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2i(mPreviewRect.mLeft+1, mPreviewRect.mTop-1); + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2i(mPreviewRect.mLeft+1, mPreviewRect.mBottom+1); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mBottom+1); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mTop-1); + } + gGL.end(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +} //----------------------------------------------------------------------------- // draw() @@ -711,36 +806,9 @@ void LLFloaterModelPreview::draw() childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); - if (mModelPreview->lodsReady()) + if (!isMinimized() && mModelPreview->lodsReady()) { - gGL.color3f(1.f, 1.f, 1.f); - - gGL.getTexUnit(0)->bind(mModelPreview); - - - LLView* preview_panel = getChild<LLView>("preview_panel"); - - LLRect rect = preview_panel->getRect(); - if (rect != mPreviewRect) - { - mModelPreview->refresh(); - mPreviewRect = preview_panel->getRect(); - } - - gGL.begin( LLRender::QUADS ); - { - 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.end(); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + draw3dPreview(); } } @@ -806,7 +874,7 @@ BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) mModelPreview->refresh(); - LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); + LLUI::getInstance()->setMousePositionLocal(this, mLastMouseX, mLastMouseY); } if (!mPreviewRect.pointInRect(x, y) || !mModelPreview) @@ -839,7 +907,10 @@ BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) mModelPreview->zoom((F32)clicks * -0.2f); mModelPreview->refresh(); } - + else + { + LLFloaterModelUploadBase::handleScrollWheel(x, y, clicks); + } return TRUE; } @@ -1100,7 +1171,8 @@ void LLFloaterModelPreview::initDecompControls() float max = param[i].mDetails.mRange.mHigh.mFloat; float delta = param[i].mDetails.mRange.mDelta.mFloat; - if ("Cosine%" == name) + bool is_smooth_cb = ("Cosine%" == name); + if (is_smooth_cb) { createSmoothComboBox(combo_box, min, max); } @@ -1111,10 +1183,8 @@ void LLFloaterModelPreview::initDecompControls() std::string label = llformat("%.1f", value); combo_box->add(label, value, ADD_BOTTOM, true); } - combo_box->setValue(param[i].mDefault.mFloat); - } - + combo_box->setValue(is_smooth_cb ? 0: param[i].mDefault.mFloat); combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); } } @@ -1186,7 +1256,7 @@ void LLFloaterModelPreview::initDecompControls() //LL_INFOS() << "-----------------------------" << LL_ENDL; } } - + mDefaultDecompParams = mDecompParams; childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this); } @@ -1216,3083 +1286,280 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl } //----------------------------------------------------------------------------- -// LLModelPreview +// addStringToLog() //----------------------------------------------------------------------------- - -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 ) +//static +void LLFloaterModelPreview::addStringToLog(const std::string& message, const LLSD& args, bool flash, S32 lod) { - 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) + if (sInstance && sInstance->hasString(message)) { - 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(); - - createPreviewAvatar(); -} - -LLModelPreview::~LLModelPreview() + std::string str; + switch (lod) { - // 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) - { - mModelLoader->shutdown(); - } + case LLModel::LOD_IMPOSTOR: str = "LOD0 "; break; + case LLModel::LOD_LOW: str = "LOD1 "; break; + case LLModel::LOD_MEDIUM: str = "LOD2 "; break; + case LLModel::LOD_PHYSICS: str = "PHYS "; break; + case LLModel::LOD_HIGH: str = "LOD3 "; break; + default: break; } -U32 LLModelPreview::calcResourceCost() + LLStringUtil::format_map_t args_msg; + LLSD::map_const_iterator iter = args.beginMap(); + LLSD::map_const_iterator end = args.endMap(); + for (; iter != end; ++iter) { - 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"); + args_msg[iter->first] = iter->second.asString(); } + str += sInstance->getString(message, args_msg); + sInstance->addStringToLogTab(str, flash); } - - std::set<LLModel*> 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() ) - { - // 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 ); } - F32 streaming_cost = 0.f; - F32 physics_cost = 0.f; - for (U32 i = 0; i < mUploadData.size(); ++i) +// static +void LLFloaterModelPreview::addStringToLog(const std::string& str, bool flash) { - LLModelInstance& instance = mUploadData[i]; - - if (accounted.find(instance.mModel) == accounted.end()) + if (sInstance) { - 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; + sInstance->addStringToLogTab(str, flash); } } - 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(), - mFMP->childGetValue("lock_scale_if_joint_position").asBoolean(), - TRUE, - FALSE, - instance.mModel->mSubmodelID); - - num_hulls += decomp.mHull.size(); - for (U32 i = 0; i < decomp.mHull.size(); ++i) +// static +void LLFloaterModelPreview::addStringToLog(const std::ostringstream& strm, bool flash) { - num_points += decomp.mHull[i].size(); - } - - //calculate streaming cost - LLMatrix4 transformation = instance.mTransform; - - 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; - LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; - F32 x_length = x_transformed.normalize(); - F32 y_length = y_transformed.normalize(); - F32 z_length = z_transformed.normalize(); - LLVector3 scale = LLVector3(x_length, y_length, z_length); - - F32 radius = scale.length()*0.5f*debug_scale; - - LLMeshCostData costs; - if (gMeshRepo.getCostData(ret, costs)) + if (sInstance) { - streaming_cost += costs.getRadiusBasedStreamingCost(radius); + sInstance->addStringToLogTab(strm.str(), flash); } } - } - - F32 scale = mFMP ? mFMP->childGetValue("import_scale").asReal()*2.f : 2.f; - - mDetailsSignal(mPreviewScale[0]*scale, mPreviewScale[1]*scale, mPreviewScale[2]*scale, streaming_cost, physics_cost); - - updateStatusMessages(); - return (U32) streaming_cost; -} - -void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost) +void LLFloaterModelPreview::clearAvatarTab() { - assert_main_thread(); - childSetTextArg("import_dimensions", "[X]", llformat("%.3f", x)); - childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", y)); - childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", z)); -} + LLPanel *panel = mTabContainer->getPanelByName("rigging_panel"); + LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); + joints_list->deleteAllItems(); + LLScrollListCtrl *joints_pos = panel->getChild<LLScrollListCtrl>("pos_overrides_list"); + joints_pos->deleteAllItems(); mSelectedJointName.clear(); -void LLFloaterModelPreview::setPreviewLOD(S32 lod) + for (U32 i = 0; i < LLModel::NUM_LODS; ++i) { - if (mModelPreview) - { - mModelPreview->setPreviewLOD(lod); + mJointOverrides[i].clear(); } -} - - -void LLModelPreview::rebuildUploadData() -{ - assert_main_thread(); - mUploadData.clear(); - mTextureSet.clear(); + LLTextBox *joint_total_descr = panel->getChild<LLTextBox>("conflicts_description"); + joint_total_descr->setTextArg("[CONFLICTS]", llformat("%d", 0)); + joint_total_descr->setTextArg("[JOINTS_COUNT]", llformat("%d", 0)); - //fill uploaddata instance vectors from scene data - std::string requested_name = mFMP->getChild<LLUICtrl>("description_form")->getValue().asString(); - - LLSpinCtrl* scale_spinner = mFMP->getChild<LLSpinCtrl>("import_scale"); - - F32 scale = scale_spinner->getValue().asReal(); - - LLMatrix4 scale_mat; - scale_mat.initScale(LLVector3(scale, scale, scale)); - - F32 max_scale = 0.f; - - 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; - - // compute position - LLVector3 position = LLVector3(0, 0, 0) * mat; - - // compute scale - LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; - LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; - LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position; - F32 x_length = x_transformed.normalize(); - F32 y_length = y_transformed.normalize(); - F32 z_length = z_transformed.normalize(); - - max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); - - mat *= scale_mat; - - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end();) - { //for each instance with said transform applied - LLModelInstance instance = *model_iter++; - - LLModel* base_model = instance.mModel; - - if (base_model && !requested_name.empty()) - { - base_model->mRequestedLabel = requested_name; + LLTextBox *joint_pos_descr = panel->getChild<LLTextBox>("pos_overrides_descr"); + joint_pos_descr->setTextArg("[JOINT]", std::string("mPelvis")); // Might be better to hide it } - for (int i = LLModel::NUM_LODS - 1; i >= LLModel::LOD_IMPOSTOR; i--) +void LLFloaterModelPreview::updateAvatarTab(bool highlight_overrides) { - LLModel* lod_model = NULL; - if (!legacyMatching) + S32 display_lod = mModelPreview->mPreviewLOD; + if (mModelPreview->mModel[display_lod].empty()) { - // 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; + mSelectedJointName.clear(); + return; } - std::string toAdd; - switch (extensionLOD) + // Joints will be listed as long as they are listed in mAlternateBindMatrix + // even if they are for some reason identical to defaults. + // Todo: Are overrides always identical for all lods? They normally are, but there might be situations where they aren't. + if (mJointOverrides[display_lod].empty()) { - 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) == -1) + // populate map + for (LLModelLoader::scene::iterator iter = mModelPreview->mScene[display_lod].begin(); iter != mModelPreview->mScene[display_lod].end(); ++iter) { - name_to_match += toAdd; - } - - FindModel(mScene[i], name_to_match, lod_model, transform); - - if (!lod_model && i != LLModel::LOD_PHYSICS) + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) { - if (importerDebug) + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + const LLMeshSkinInfo *skin = &model->mSkinInfo; + U32 joint_count = LLSkinningUtil::getMeshJointCount(skin); + U32 bind_count = highlight_overrides ? skin->mAlternateBindMatrix.size() : 0; // simply do not include overrides if data is not needed + if (bind_count > 0 && bind_count != joint_count) { - LL_INFOS() << "Search of" << name_to_match << " in LOD" << i << " list failed. Searching for alternative among LOD lists." << LL_ENDL; + std::ostringstream out; + out << "Invalid joint overrides for model " << model->getName(); + out << ". Amount of joints " << joint_count; + out << ", is different from amount of overrides " << bind_count; + LL_INFOS() << out.str() << LL_ENDL; + addStringToLog(out.str(), true); + // Disable overrides for this model + bind_count = 0; } - - int searchLOD = (i > LLModel::LOD_HIGH) ? LLModel::LOD_HIGH : i; - while ((searchLOD <= LLModel::LOD_HIGH) && !lod_model) + if (bind_count > 0) { - std::string name_to_match = instance.mLabel; - llassert(!name_to_match.empty()); - - std::string toAdd; - switch (searchLOD) + for (U32 j = 0; j < joint_count; ++j) { - 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; - } + const LLVector3& joint_pos = skin->mAlternateBindMatrix[j].getTranslation(); + LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j]]; - if (name_to_match.find(toAdd) == -1) + LLJoint* pJoint = LLModelPreview::lookupJointByName(skin->mJointNames[j], mModelPreview); + if (pJoint) { - 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 + // see how voavatar uses aboveJointPosThreshold + if (pJoint->aboveJointPosThreshold(joint_pos)) { - // Use old method of index-based association - U32 idx = 0; - for (idx = 0; idx < mBaseModel.size(); ++idx) + // valid override + if (data.mPosOverrides.size() > 0 + && (data.mPosOverrides.begin()->second - joint_pos).lengthSquared() > (LL_JOINT_TRESHOLD_POS_OFFSET * LL_JOINT_TRESHOLD_POS_OFFSET)) { - // 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; + // File contains multiple meshes with conflicting joint offsets + // preview may be incorrect, upload result might wary (depends onto + // mesh_id that hasn't been generated yet). + data.mHasConflicts = true; } - break; - } - } - - // If the model list for the current LOD includes that index... - // - if (mModel[i].size() > 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 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; + data.mPosOverrides[model->getName()] = joint_pos; } else { - LL_INFOS() << "Assigning LOD" << i << " for " << instance.mLabel << " to found match " << lod_model->mLabel << LL_ENDL; - } + // default value, it won't be accounted for by avatar + data.mModelsNoOverrides.insert(model->getName()); } - 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++) + for (U32 j = 0; j < joint_count; ++j) { - int refFaceCnt = 0; - int modelFaceCnt = 0; - llassert(instance.mLOD[i]); - if (instance.mLOD[i] && !instance.mLOD[i]->matchMaterialOrder(high_lod_model, refFaceCnt, modelFaceCnt ) ) - { - 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.01)) - { - 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 ); + LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j]]; + data.mModelsNoOverrides.insert(model->getName()); } } } - 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" ); - } } } - F32 max_import_scale = (DEFAULT_MAX_PRIM_SCALE-0.1f)/max_scale; - - F32 max_axis = llmax(mPreviewScale.mV[0], mPreviewScale.mV[1]); - max_axis = llmax(max_axis, mPreviewScale.mV[2]); - 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); - - scale_spinner->setMaxValue(max_import_scale); + LLPanel *panel = mTabContainer->getPanelByName("rigging_panel"); + LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); - if (max_import_scale < scale) + if (joints_list->isEmpty()) { - scale_spinner->setValue(max_import_scale); - } - -} - -void LLModelPreview::saveUploadData(bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position) -{ - if (!mLODFile[LLModel::LOD_HIGH].empty()) - { - std::string filename = mLODFile[LLModel::LOD_HIGH]; - std::string slm_filename; - - if (LLModelLoader::getSLMFilename(filename, slm_filename)) - { - saveUploadData(slm_filename, save_skinweights, save_joint_positions, lock_scale_if_joint_position); - } - } -} - -void LLModelPreview::saveUploadData(const std::string& filename, - bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position) -{ - - std::set<LLPointer<LLModel> > meshes; - std::map<LLModel*, std::string> mesh_binary; - - LLModel::hull empty_hull; - - LLSD data; - - data["version"] = SLM_SUPPORTED_VERSION; - if (!mBaseModel.empty()) - { - data["name"] = mBaseModel[0]->getName(); - } - - S32 mesh_id = 0; - - //build list of unique models and initialize local id - for (U32 i = 0; i < mUploadData.size(); ++i) - { - LLModelInstance& instance = mUploadData[i]; - - if (meshes.find(instance.mModel) == meshes.end()) - { - instance.mModel->mLocalID = mesh_id++; - meshes.insert(instance.mModel); - - std::stringstream str; - LLModel::Decomposition& decomp = - instance.mLOD[LLModel::LOD_PHYSICS].notNull() ? - instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics : - instance.mModel->mPhysics; - - LLModel::writeModel(str, - instance.mLOD[LLModel::LOD_PHYSICS], - instance.mLOD[LLModel::LOD_HIGH], - instance.mLOD[LLModel::LOD_MEDIUM], - instance.mLOD[LLModel::LOD_LOW], - instance.mLOD[LLModel::LOD_IMPOSTOR], - decomp, - save_skinweights, - save_joint_positions, - lock_scale_if_joint_position, - FALSE, TRUE, instance.mModel->mSubmodelID); - - data["mesh"][instance.mModel->mLocalID] = str.str(); - } - - data["instance"][i] = instance.asLLSD(); - } - - llofstream out(filename.c_str(), std::ios_base::out | std::ios_base::binary); - LLSDSerialize::toBinary(data, out); - out.flush(); - out.close(); -} - -void LLModelPreview::clearModel(S32 lod) -{ - if (lod < 0 || lod > LLModel::LOD_PHYSICS) - { - return; - } - - mVertexBuffer[lod].clear(); - mModel[lod].clear(); - 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<std::string> cv_names, attach_names; - av->getSortedJointNames(1, cv_names); - av->getSortedJointNames(2, attach_names); - for (std::vector<std::string>::iterator it = cv_names.begin(); it != cv_names.end(); ++it) - { - joint_map[*it] = *it; - } - for (std::vector<std::string>::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(); - - LLMutexLock lock(this); - - if (lod < LLModel::LOD_IMPOSTOR || lod > LLModel::NUM_LODS - 1) - { - LL_WARNS() << "Invalid level of detail: " << lod << LL_ENDL; - assert(lod >= LLModel::LOD_IMPOSTOR && lod < LLModel::NUM_LODS); - return; - } - - // This triggers if you bring up the file picker and then hit CANCEL. - // Just use the previous model (if any) and ignore that you brought up - // the file picker. - - if (filename.empty()) - { - if (mBaseModel.empty()) - { - // this is the initial file picking. Close the whole floater - // if we don't have a base model to show for high LOD. - mFMP->closeFloater(false); - } - mLoading = false; - return; - } - - if (mModelLoader) - { - LL_WARNS() << "Incompleted model load operation pending." << LL_ENDL; - return; - } - - mLODFile[lod] = filename; - - if (lod == LLModel::LOD_HIGH) - { - clearGLODGroup(); - } + // Populate table std::map<std::string, std::string> joint_alias_map; - getJointAliases(joint_alias_map); + mModelPreview->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) + S32 conflicts = 0; + joint_override_data_map_t::iterator joint_iter = mJointOverrides[display_lod].begin(); + joint_override_data_map_t::iterator joint_end = mJointOverrides[display_lod].end(); + while (joint_iter != joint_end) { - mModelLoader->mTrySLM = false; - } - else - { - // For MAINT-6647, we have set force_disable_slm to true, - // which means this code path will never be taken. Trying to - // re-use SLM files has never worked properly; in particular, - // it tends to force the UI into strange checkbox options - // which cannot be altered. + const std::string& listName = joint_iter->first; - //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")); - - setPreviewLOD(lod); + LLScrollListItem::Params item_params; + item_params.value(listName); - if ( getLoadState() >= LLModelLoader::ERROR_PARSING ) + LLScrollListCell::Params cell_params; + cell_params.font = LLFontGL::getFontSansSerif(); + cell_params.value = listName; + if (joint_alias_map.find(listName) == joint_alias_map.end()) { - mFMP->childDisable("ok_btn"); - mFMP->childDisable( "calculate_btn" ); + // Missing names + cell_params.color = LLColor4::red; } - - if (lod == mPreviewLOD) + if (joint_iter->second.mHasConflicts) { - mFMP->childSetValue("lod_file_" + lod_name[lod], mLODFile[lod]); + // Conflicts + cell_params.color = LLColor4::orange; + conflicts++; } - else if (lod == LLModel::LOD_PHYSICS) + if (highlight_overrides && joint_iter->second.mPosOverrides.size() > 0) { - mFMP->childSetValue("physics_file", mLODFile[lod]); + cell_params.font.style = "BOLD"; } - mFMP->openFloater(); -} - -void LLModelPreview::setPhysicsFromLOD(S32 lod) -{ - assert_main_thread(); + item_params.columns.add(cell_params); - if (lod >= 0 && lod <= 3) - { - mPhysicsSearchLOD = lod; - mModel[LLModel::LOD_PHYSICS] = mModel[lod]; - mScene[LLModel::LOD_PHYSICS] = mScene[lod]; - mLODFile[LLModel::LOD_PHYSICS].clear(); - mFMP->childSetValue("physics_file", mLODFile[LLModel::LOD_PHYSICS]); - mVertexBuffer[LLModel::LOD_PHYSICS].clear(); - rebuildUploadData(); - refresh(); - updateStatusMessages(); + joints_list->addRow(item_params, ADD_BOTTOM); + joint_iter++; } -} - -void LLModelPreview::clearIncompatible(S32 lod) + joints_list->selectFirstItem(); + LLScrollListItem *selected = joints_list->getFirstSelected(); + if (selected) { - //Don't discard models if specified model is the physic rep - if ( lod == LLModel::LOD_PHYSICS ) - { - return; + mSelectedJointName = selected->getValue().asString(); } - // 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 - if (i != lod) - { - if (countRootModels(mModel[i]) != lod_size) - { - mModel[i].clear(); - mScene[i].clear(); - mVertexBuffer[i].clear(); - - if (i == LLModel::LOD_HIGH) - { - mBaseModel = mModel[lod]; - clearGLODGroup(); - mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); - } - } + LLTextBox *joint_conf_descr = panel->getChild<LLTextBox>("conflicts_description"); + joint_conf_descr->setTextArg("[CONFLICTS]", llformat("%d", conflicts)); + joint_conf_descr->setTextArg("[JOINTS_COUNT]", llformat("%d", mJointOverrides[display_lod].size())); } } -} -void LLModelPreview::clearGLODGroup() +//----------------------------------------------------------------------------- +// addStringToLogTab() +//----------------------------------------------------------------------------- +void LLFloaterModelPreview::addStringToLogTab(const std::string& str, bool flash) { - if (mGroup) - { - for (std::map<LLPointer<LLModel>, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) + if (str.empty()) { - glodDeleteObject(iter->second); - stop_gloderror(); - } - mObject.clear(); - - glodDeleteGroup(mGroup); - stop_gloderror(); - mGroup = 0; - } -} - -void LLModelPreview::loadModelCallback(S32 loaded_lod) -{ - assert_main_thread(); - - LLMutexLock lock(this); - if (!mModelLoader) - { - mLoading = false ; return; } - if(getLoadState() >= LLModelLoader::ERROR_PARSING) - { - mLoading = false ; - 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" ); - } - - // Copy determinations about rig so UI will reflect them - // - setRigValidForJointPositionUpload(mModelLoader->isRigValidForJointPositionUpload()); - setLegacyRigValid(mModelLoader->isLegacyRigValid()); - - mModelLoader->loadTextures() ; - - if (loaded_lod == -1) - { //populate all LoDs from model loader scene - mBaseModel.clear(); - mBaseScene.clear(); - - bool skin_weights = false; - bool joint_positions = false; - bool lock_scale_if_joint_position = false; - - for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { //for each LoD - - //clear scene and model info - mScene[lod].clear(); - mModel[lod].clear(); - mVertexBuffer[lod].clear(); - - if (mModelLoader->mScene.begin()->second[0].mLOD[lod].notNull()) - { //if this LoD exists in the loaded scene - - //copy scene to current LoD - mScene[lod] = mModelLoader->mScene; - - //touch up copied scene to look like current LoD - for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) - { - LLModelLoader::model_instance_list& list = iter->second; - - for (LLModelLoader::model_instance_list::iterator list_iter = list.begin(); list_iter != list.end(); ++list_iter) - { - //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; - if (mModel[lod].size() <= idx) - { //stretch model list to fit model at given index - mModel[lod].resize(idx+1); - } - - mModel[lod][idx] = list_iter->mModel; - if (!list_iter->mModel->mSkinWeights.empty()) - { - skin_weights = true; - - if (!list_iter->mModel->mSkinInfo.mAlternateBindMatrix.empty()) - { - joint_positions = true; - } - if (list_iter->mModel->mSkinInfo.mLockScaleIfJointPosition) - { - lock_scale_if_joint_position = true; - } - } - } - } - } - } - - if (mFMP) - { - LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) mFMP; - - if (skin_weights) - { //enable uploading/previewing of skin weights if present in .slm file - fmp->enableViewOption("show_skin_weight"); - mViewOption["show_skin_weight"] = true; - fmp->childSetValue("upload_skin", true); - } - - if (joint_positions) - { - fmp->enableViewOption("show_joint_positions"); - mViewOption["show_joint_positions"] = true; - fmp->childSetValue("upload_joints", true); - } - - if (lock_scale_if_joint_position) - { - fmp->enableViewOption("lock_scale_if_joint_position"); - mViewOption["lock_scale_if_joint_position"] = true; - fmp->childSetValue("lock_scale_if_joint_position", true); - } - } - - //copy high lod to base scene for LoD generation - mBaseScene = mScene[LLModel::LOD_HIGH]; - mBaseModel = mModel[LLModel::LOD_HIGH]; - - mDirty = true; - resetPreviewTarget(); - } - else - { //only replace given LoD - mModel[loaded_lod] = mModelLoader->mModelList; - mScene[loaded_lod] = mModelLoader->mScene; - mVertexBuffer[loaded_lod].clear(); - - setPreviewLOD(loaded_lod); - - 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 - mGenLOD = true; - } - - mBaseModel = mModel[loaded_lod]; - clearGLODGroup(); - - 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(loaded_lod); - - mDirty = true; - - if (loaded_lod == LLModel::LOD_HIGH) + LLWString text = utf8str_to_wstring(str); + S32 add_text_len = text.length() + 1; // newline + S32 editor_max_len = mUploadLogText->getMaxTextLength(); + if (add_text_len > editor_max_len) { - resetPreviewTarget(); - } - } - - mLoading = false; - if (mFMP) - { - mFMP->getChild<LLCheckBoxCtrl>("confirm_checkbox")->set(FALSE); - if (!mBaseModel.empty()) - { - const std::string& model_name = mBaseModel[0]->getName(); - LLLineEditor* description_form = mFMP->getChild<LLLineEditor>("description_form"); - if (description_form->getText().empty()) - { - description_form->setText(model_name); - } - } - } - refresh(); - - mModelLoadedSignal(); - - mModelLoader = NULL; -} - -void LLModelPreview::resetPreviewTarget() -{ - if ( mModelLoader ) - { - mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; - mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; - } - - setPreviewTarget(mPreviewScale.magVec()*10.f); -} - -void LLModelPreview::generateNormals() -{ - assert_main_thread(); - - S32 which_lod = mPreviewLOD; - - if (which_lod > 4 || which_lod < 0 || - mModel[which_lod].empty()) - { return; } - F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal(); - - mRequestedCreaseAngle[which_lod] = angle_cutoff; - - angle_cutoff *= DEG_TO_RAD; - - if (which_lod == 3 && !mBaseModel.empty()) + // Make sure we have space for new string + S32 editor_text_len = mUploadLogText->getLength(); + if (editor_max_len < (editor_text_len + add_text_len) + && mUploadLogText->getLineCount() <= 0) { - 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); + mUploadLogText->getTextBoundingRect();// forces a reflow() to fix line count } - } - - for (LLModelLoader::model_list::iterator it = mBaseModel.begin(), itE = mBaseModel.end(); it != itE; ++it) + while (editor_max_len < (editor_text_len + add_text_len)) { - (*it)->generateNormals(angle_cutoff); - } - - mVertexBuffer[5].clear(); - } - - 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) + S32 shift = mUploadLogText->removeFirstLine(); + if (shift > 0) { - 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(); + // removed a line + editor_text_len -= shift; } - -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(); -} - -void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit) -{ - // Allow LoD from -1 to LLModel::LOD_PHYSICS - if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1) - { - LL_WARNS() << "Invalid level of detail: " << which_lod << LL_ENDL; - assert(which_lod >= -1 && which_lod < LLModel::NUM_LODS); - return; - } - - if (mBaseModel.empty()) - { - return; - } - - LLVertexBuffer::unbind(); - - bool no_ff = LLGLSLShader::sNoFixedFunction; - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - LLGLSLShader::sNoFixedFunction = false; - - if (shader) - { - shader->unbind(); - } - - stop_gloderror(); - static U32 cur_name = 1; - - S32 limit = -1; - - U32 triangle_count = 0; - - 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) - { - for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance) - { - 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; - - U32 lod_mode = 0; - - F32 lod_error_threshold = 0; - - // The LoD should be in range from Lowest to High - if (which_lod > -1 && which_lod < NUM_LOD) - { - LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[which_lod]); - if (iface) - { - lod_mode = iface->getFirstSelectedIndex(); - } - - lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[which_lod]).asReal(); - } - - if (which_lod != -1) - { - mRequestedLoDMode[which_lod] = lod_mode; - } - - if (lod_mode == 0) - { - lod_mode = GLOD_TRIANGLE_BUDGET; - - // The LoD should be in range from Lowest to High - 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 { - lod_mode = GLOD_ERROR_THRESHOLD; - } - - bool object_dirty = false; - - if (mGroup == 0) - { - object_dirty = true; - mGroup = cur_name++; - glodNewGroup(mGroup); - } - - if (object_dirty) - { - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { //build GLOD objects for each model in base model list - LLModel* mdl = *iter; - - if (mObject[mdl] != 0) - { - glodDeleteObject(mObject[mdl]); - } - - mObject[mdl] = cur_name++; - - glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE); - stop_gloderror(); - - if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) - { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation - mVertexBuffer[5].clear(); - } - - if (mVertexBuffer[5].empty()) - { - genBuffers(5, false); - } - - U32 tri_count = 0; - for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) - { - LLVertexBuffer* buff = mVertexBuffer[5][mdl][i]; - buff->setBuffer(type_mask & buff->getTypeMask()); - - U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); - if (num_indices > 2) - { - glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, (U8*) mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); - } - tri_count += num_indices/3; - stop_gloderror(); - } - - glodBuildObject(mObject[mdl]); - stop_gloderror(); - } - } - - - S32 start = LLModel::LOD_HIGH; - S32 end = 0; - - if (which_lod != -1) - { - start = end = which_lod; - } - - mMaxTriangleLimit = base_triangle_count; - - for (S32 lod = start; lod >= end; --lod) - { - if (which_lod == -1) - { - if (lod < start) - { - triangle_count /= decimation; - } - } - else - { - if (enforce_tri_limit) - { - triangle_count = limit; - } - else - { - for (S32 j=LLModel::LOD_HIGH; j>which_lod; --j) - { - triangle_count /= decimation; - } - } - } - - mModel[lod].clear(); - mModel[lod].resize(mBaseModel.size()); - mVertexBuffer[lod].clear(); - - U32 actual_tris = 0; - U32 actual_verts = 0; - U32 submeshes = 0; - - mRequestedTriangleCount[lod] = (S32) ( (F32) triangle_count / triangle_ratio ); - mRequestedErrorThreshold[lod] = lod_error_threshold; - - glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); - stop_gloderror(); - - glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); - stop_gloderror(); - - glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); - stop_gloderror(); - - if (lod_mode != GLOD_TRIANGLE_BUDGET) - { - glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, 0); - } - else - { - //SH-632: always add 1 to desired amount to avoid decimating below desired amount - glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count+1); - } - - stop_gloderror(); - glodAdaptGroup(mGroup); - stop_gloderror(); - - for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) - { - LLModel* base = mBaseModel[mdl_idx]; - - GLint patch_count = 0; - glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); - stop_gloderror(); - - LLVolumeParams volume_params; - 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(); - - GLint* names = new GLint[patch_count]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); - stop_gloderror(); - - mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); - - LLModel* target_model = mModel[lod][mdl_idx]; - - for (GLint i = 0; i < patch_count; ++i) - { - type_mask = mVertexBuffer[5][base][i]->getTypeMask(); - - LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0); - - if (sizes[i*2+1] > 0 && sizes[i*2] > 0) - { - if (!buff->allocateBuffer(sizes[i * 2 + 1], sizes[i * 2], true)) - { - // Todo: find a way to stop preview in this case instead of crashing - LL_ERRS() << "Failed buffer allocation during preview LOD generation." - << " Vertices: " << sizes[i * 2 + 1] - << " Indices: " << sizes[i * 2] << LL_ENDL; - } - buff->setBuffer(type_mask); - glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, (U8*) buff->getIndicesPointer()); - stop_gloderror(); - } - else - { - // This face was eliminated or we failed to allocate buffer, - // attempt to create a dummy triangle (one vertex, 3 indices, all 0) - buff->allocateBuffer(1, 3, true); - memset((U8*) buff->getMappedData(), 0, buff->getSize()); - memset((U8*) buff->getIndicesPointer(), 0, buff->getIndicesSize()); - } - - buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0); - - LLStrider<LLVector3> pos; - LLStrider<LLVector3> norm; - LLStrider<LLVector2> tc; - LLStrider<U16> index; - - buff->getVertexStrider(pos); - if (type_mask & LLVertexBuffer::MAP_NORMAL) - { - buff->getNormalStrider(norm); - } - if (type_mask & LLVertexBuffer::MAP_TEXCOORD0) - { - buff->getTexCoord0Strider(tc); - } - - buff->getIndexStrider(index); - - target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); - actual_tris += buff->getNumIndices()/3; - actual_verts += buff->getNumVerts(); - ++submeshes; - - if (!validate_face(target_model->getVolumeFace(names[i]))) - { - LL_ERRS() << "Invalid face generated during LOD generation." << LL_ENDL; - } - } - - //blind copy skin weights and just take closest skin weight to point on - //decimated mesh for now (auto-generating LODs with skin weights is still a bit - //of an open problem). - target_model->mPosition = base->mPosition; - target_model->mSkinWeights = base->mSkinWeights; - target_model->mSkinInfo = base->mSkinInfo; - //copy material list - target_model->mMaterialList = base->mMaterialList; - - if (!validate_model(target_model)) - { - LL_ERRS() << "Invalid model generated when creating LODs" << LL_ENDL; - } - - delete [] sizes; - delete [] names; - } - - //rebuild scene based on mBaseScene - mScene[lod].clear(); - mScene[lod] = mBaseScene; - - for (U32 i = 0; i < mBaseModel.size(); ++i) - { - LLModel* mdl = mBaseModel[i]; - LLModel* target = mModel[lod][i]; - if (target) - { - for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) - { - for (U32 j = 0; j < iter->second.size(); ++j) - { - if (iter->second[j].mModel == mdl) - { - iter->second[j].mModel = target; - } - } - } - } - } - } - - mResourceCost = calcResourceCost(); - - LLVertexBuffer::unbind(); - LLGLSLShader::sNoFixedFunction = no_ff; - if (shader) - { - shader->bind(); - } -} - -void LLModelPreview::updateStatusMessages() -{ - assert_main_thread(); - - //triangle/vertex/submesh count for each mesh asset for each lod - std::vector<S32> tris[LLModel::NUM_LODS]; - std::vector<S32> verts[LLModel::NUM_LODS]; - std::vector<S32> submeshes[LLModel::NUM_LODS]; - - //total triangle/vertex/submesh count for each lod - S32 total_tris[LLModel::NUM_LODS]; - S32 total_verts[LLModel::NUM_LODS]; - S32 total_submeshes[LLModel::NUM_LODS]; - - 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) - { - 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" ); - } - else - { - //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; - } - - 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) - { - mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; - } - - bool has_degenerate = false; - - {//check for degenerate triangles in physics mesh - 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] && 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 - LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); - for (S32 k = 0; (k < face.mNumIndices) && !has_degenerate; ) - { - U16 index_a = face.mIndices[k+0]; - U16 index_b = face.mIndices[k+1]; - U16 index_c = face.mIndices[k+2]; - - 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; - } - } - } - } - } - } - - 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]; - - mModelNoErrors = true; - - 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; - - std::string message = "mesh_status_good"; - - if (total_tris[lod] > 0) - { - mFMP->childSetValue(lod_triangles_name[lod], llformat("%d", total_tris[lod])); - mFMP->childSetValue(lod_vertices_name[lod], llformat("%d", total_verts[lod])); - } - else - { - if (lod == lod_high) - { - upload_status[lod] = 2; - message = "mesh_status_missing_lod"; - } - else - { - for (S32 i = lod-1; i >= 0; --i) - { - if (total_tris[i] > 0) - { - upload_status[lod] = 2; - message = "mesh_status_missing_lod"; - } - } - } - - mFMP->childSetValue(lod_triangles_name[lod], mesh_status_na); - mFMP->childSetValue(lod_vertices_name[lod], mesh_status_na); - } - - if (lod != lod_high) - { - if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) - { //number of submeshes is different - 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"; - upload_status[lod] = 2; - } - else if (!verts[lod].empty()) - { - S32 sum_verts_higher_lod = 0; - S32 sum_verts_this_lod = 0; - for (U32 i = 0; i < verts[lod].size(); ++i) - { - sum_verts_higher_lod += ((i < verts[lod+1].size()) ? verts[lod+1][i] : 0); - sum_verts_this_lod += verts[lod][i]; - } - - if ((sum_verts_higher_lod > 0) && - (sum_verts_this_lod > sum_verts_higher_lod)) - { - //too many vertices in this lod - message = "mesh_status_too_many_vertices"; - upload_status[lod] = 1; - } - } - } - - LLIconCtrl* icon = mFMP->getChild<LLIconCtrl>(lod_icon_name[lod]); - LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]); - icon->setVisible(true); - icon->setImage(img); - - if (upload_status[lod] >= 2) - { - mModelNoErrors = false; - } - - if (lod == mPreviewLOD) - { - mFMP->childSetValue("lod_status_message_text", mFMP->getString(message)); - icon = mFMP->getChild<LLIconCtrl>("lod_status_message_icon"); - icon->setImage(img); - } - - updateLodControls(lod); - } - - - //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]; - - if (mdl) - { - for (U32 j = 0; j < mdl->mPhysics.mHull.size(); ++j) - { - if (mdl->mPhysics.mHull[j].size() > 256) - { - physExceededVertexLimit = TRUE; - LL_INFOS() << "Physical model " << mdl->mLabel << " exceeds vertex per hull limitations." << LL_ENDL; + //nothing to remove? + LL_WARNS() << "Failed to clear log lines" << LL_ENDL; break; } } - } - } - mFMP->childSetVisible("physics_status_message_text", physExceededVertexLimit); - LLIconCtrl* physStatusIcon = mFMP->getChild<LLIconCtrl>("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); - } - - if (getLoadState() >= LLModelLoader::ERROR_PARSING) - { - mModelNoErrors = false; - LL_INFOS() << "Loader returned errors, model can't be uploaded" << LL_ENDL; - } - - bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean(); - bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean(); - - if ( uploadingSkin ) - { - if ( uploadingJointPositions && !isRigValidForJointPositionUpload() ) - { - mModelNoErrors = false; - LL_INFOS() << "Invalid rig, there might be issues with uploading Joint positions" << LL_ENDL; - } - } - - if(mModelNoErrors && mModelLoader) - { - if(!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean()) - { - // Some textures are still loading, prevent upload until they are done - mModelNoErrors = false; - } - } - - // 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 phys_tris = 0; - S32 phys_hulls = 0; - S32 phys_points = 0; - - //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) - { - LLModel* model = instance->mModel; - if (model) - { - 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; - } - } - } - } - } - - if (phys_tris > 0) - { - mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris)); - } - else - { - mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na); - } - - if (phys_hulls > 0) - { - mFMP->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls)); - mFMP->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points)); - } - else - { - mFMP->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na); - mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); - } - - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - if (fmp) - { - if (phys_tris > 0 || phys_hulls > 0) - { - if (!fmp->isViewOptionEnabled("show_physics")) - { - fmp->enableViewOption("show_physics"); - mViewOption["show_physics"] = true; - fmp->childSetValue("show_physics", true); - } - } - else - { - fmp->disableViewOption("show_physics"); - mViewOption["show_physics"] = false; - fmp->childSetValue("show_physics", false); - - } - - //bool use_hull = fmp->childGetValue("physics_use_hull").asBoolean(); - - //fmp->childSetEnabled("physics_optimize", !use_hull); - - bool enable = (phys_tris > 0 || phys_hulls > 0) && fmp->mCurRequest.empty(); - //enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean(); - - //enable/disable "analysis" UI - LLPanel* panel = fmp->getChild<LLPanel>("physics analysis"); - LLView* child = panel->getFirstChild(); - while (child) - { - child->setEnabled(enable); - child = panel->findNextSibling(child); - } - - enable = phys_hulls > 0 && fmp->mCurRequest.empty(); - //enable/disable "simplification" UI - panel = fmp->getChild<LLPanel>("physics simplification"); - child = panel->getFirstChild(); - while (child) - { - child->setEnabled(enable); - child = panel->findNextSibling(child); - } - - if (fmp->mCurRequest.empty()) - { - fmp->childSetVisible("Simplify", true); - fmp->childSetVisible("simplify_cancel", false); - fmp->childSetVisible("Decompose", true); - fmp->childSetVisible("decompose_cancel", false); - - if (phys_hulls > 0) - { - fmp->childEnable("Simplify"); - } - - if (phys_tris || phys_hulls > 0) - { - fmp->childEnable("Decompose"); - } - } - else - { - fmp->childEnable("simplify_cancel"); - fmp->childEnable("decompose_cancel"); - } - } - - - LLCtrlSelectionInterface* iface = fmp->childGetSelectionInterface("physics_lod_combo"); - S32 which_mode = 0; - S32 file_mode = 1; - if (iface) - { - which_mode = iface->getFirstSelectedIndex(); - file_mode = iface->getItemCount() - 1; - } - - if (which_mode == file_mode) - { - mFMP->childEnable("physics_file"); - mFMP->childEnable("physics_browse"); - } - else - { - mFMP->childDisable("physics_file"); - mFMP->childDisable("physics_browse"); - } - - LLSpinCtrl* crease = mFMP->getChild<LLSpinCtrl>("crease_angle"); - - if (mRequestedCreaseAngle[mPreviewLOD] == -1.f) - { - mFMP->childSetColor("crease_label", LLColor4::grey); - crease->forceSetValue(75.f); - } - else - { - mFMP->childSetColor("crease_label", LLColor4::white); - crease->forceSetValue(mRequestedCreaseAngle[mPreviewLOD]); - } - - mModelUpdatedSignal(true); - -} - -void LLModelPreview::updateLodControls(S32 lod) -{ - if (lod < LLModel::LOD_IMPOSTOR || lod > LLModel::LOD_HIGH) - { - LL_WARNS() << "Invalid level of detail: " << lod << LL_ENDL; - assert(lod >= LLModel::LOD_IMPOSTOR && lod <= LLModel::LOD_HIGH); - return; - } - - const char* lod_controls[] = - { - "lod_mode_", - "lod_triangle_limit_", - "lod_error_threshold_" - }; - const U32 num_lod_controls = sizeof(lod_controls)/sizeof(char*); - - const char* file_controls[] = - { - "lod_browse_", - "lod_file_", - }; - const U32 num_file_controls = sizeof(file_controls)/sizeof(char*); - - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - if (!fmp) return; - LLComboBox* lod_combo = mFMP->findChild<LLComboBox>("lod_source_" + lod_name[lod]); - if (!lod_combo) return; + mUploadLogText->appendText(str, true); - S32 lod_mode = lod_combo->getCurrentIndex(); - if (lod_mode == LOD_FROM_FILE) // LoD from file + if (flash) { - fmp->mLODMode[lod] = 0; - for (U32 i = 0; i < num_file_controls; ++i) + LLPanel* panel = mTabContainer->getPanelByName("logs_panel"); + if (mTabContainer->getCurrentPanel() != panel) { - mFMP->childSetVisible(file_controls[i] + lod_name[lod], true); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childSetVisible(lod_controls[i] + lod_name[lod], false); + mTabContainer->setTabPanelFlashing(panel, true); } } - else if (lod_mode == USE_LOD_ABOVE) // use LoD above - { - fmp->mLODMode[lod] = 2; - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->childSetVisible(file_controls[i] + lod_name[lod], false); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childSetVisible(lod_controls[i] + lod_name[lod], false); - } - - if (lod < LLModel::LOD_HIGH) - { - mModel[lod] = mModel[lod + 1]; - mScene[lod] = mScene[lod + 1]; - mVertexBuffer[lod].clear(); - - // Also update lower LoD - if (lod > LLModel::LOD_IMPOSTOR) - { - updateLodControls(lod - 1); - } - } - } - else // auto generate, the default case for all LoDs except High - { - fmp->mLODMode[lod] = 1; - - //don't actually regenerate lod when refreshing UI - mLODFrozen = true; - - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->getChildView(file_controls[i] + lod_name[lod])->setVisible(false); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->getChildView(lod_controls[i] + lod_name[lod])->setVisible(true); - } - - - LLSpinCtrl* threshold = mFMP->getChild<LLSpinCtrl>("lod_error_threshold_" + lod_name[lod]); - LLSpinCtrl* limit = mFMP->getChild<LLSpinCtrl>("lod_triangle_limit_" + lod_name[lod]); - - limit->setMaxValue(mMaxTriangleLimit); - limit->forceSetValue(mRequestedTriangleCount[lod]); - - threshold->forceSetValue(mRequestedErrorThreshold[lod]); - - mFMP->getChild<LLComboBox>("lod_mode_" + lod_name[lod])->selectNthItem(mRequestedLoDMode[lod]); - - if (mRequestedLoDMode[lod] == 0) - { - limit->setVisible(true); - threshold->setVisible(false); - - limit->setMaxValue(mMaxTriangleLimit); - limit->setIncrement(mMaxTriangleLimit/32); - } - else - { - limit->setVisible(false); - threshold->setVisible(true); - } - - mLODFrozen = false; - } -} - -void LLModelPreview::setPreviewTarget(F32 distance) -{ - mCameraDistance = distance; - mCameraZoom = 1.f; - mCameraPitch = 0.f; - mCameraYaw = 0.f; - mCameraOffset.clearVec(); -} - -void LLModelPreview::clearBuffers() -{ - for (U32 i = 0; i < 6; i++) - { - mVertexBuffer[i].clear(); } -} - -void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) -{ - U32 tri_count = 0; - U32 vertex_count = 0; - U32 mesh_count = 0; - - - LLModelLoader::model_list* model = NULL; - - if (lod < 0 || lod > 4) - { - model = &mBaseModel; - lod = 5; - } - else - { - model = &(mModel[lod]); - } - - if (!mVertexBuffer[lod].empty()) - { - mVertexBuffer[lod].clear(); - } - - mVertexBuffer[lod].clear(); - - LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); - - for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) - { - LLModel* mdl = *iter; - if (!mdl) - { - continue; - } - - LLModel* base_mdl = *base_iter; - base_iter++; - - S32 num_faces = mdl->getNumVolumeFaces(); - for (S32 i = 0; i < num_faces; ++i) - { - const LLVolumeFace &vf = mdl->getVolumeFace(i); - U32 num_vertices = vf.mNumVertices; - U32 num_indices = vf.mNumIndices; - - if (!num_vertices || ! num_indices) - { - continue; - } - - LLVertexBuffer* vb = NULL; - - bool skinned = include_skin_weights && !mdl->mSkinWeights.empty(); - - U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0 ; - - if (skinned) - { - mask |= LLVertexBuffer::MAP_WEIGHT4; - } - - vb = new LLVertexBuffer(mask, 0); - - if (!vb->allocateBuffer(num_vertices, num_indices, TRUE)) - { - // We are likely to crash due this failure, if this happens, find a way to gracefully stop preview - LL_WARNS() << "Failed to allocate Vertex Buffer for model preview " - << num_vertices << " vertices and " - << num_indices << " indices" << LL_ENDL; - } - - LLStrider<LLVector3> vertex_strider; - LLStrider<LLVector3> normal_strider; - LLStrider<LLVector2> tc_strider; - LLStrider<U16> index_strider; - LLStrider<LLVector4> weights_strider; - - vb->getVertexStrider(vertex_strider); - vb->getIndexStrider(index_strider); - - if (skinned) - { - vb->getWeight4Strider(weights_strider); - } - - LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); - - if (vf.mTexCoords) - { - vb->getTexCoord0Strider(tc_strider); - S32 tex_size = (num_vertices*2*sizeof(F32)+0xF) & ~0xF; - LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, tex_size); - } - - if (vf.mNormals) - { - vb->getNormalStrider(normal_strider); - LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); - } - - if (skinned) - { - for (U32 i = 0; i < num_vertices; i++) - { - //find closest weight to vf.mVertices[i].mPosition - LLVector3 pos(vf.mPositions[i].getF32ptr()); - - const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); - llassert(weight_list.size()>0 && weight_list.size() <= 4); // LLModel::loadModel() should guarantee this - - LLVector4 w(0,0,0,0); - - for (U32 i = 0; i < weight_list.size(); ++i) - { - 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; - } - } - - // build indices - for (U32 i = 0; i < num_indices; i++) - { - *(index_strider++) = vf.mIndices[i]; - } - - mVertexBuffer[lod][mdl].push_back(vb); - - vertex_count += num_vertices; - tri_count += num_indices/3; - ++mesh_count; - - } - } -} - -void LLModelPreview::update() -{ - 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(); - } -} - -//----------------------------------------------------------------------------- -// createPreviewAvatar -//----------------------------------------------------------------------------- -void LLModelPreview::createPreviewAvatar( void ) -{ - mPreviewAvatar = (LLVOAvatar*)gObjectList.createObjectViewer( LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR ); - if ( mPreviewAvatar ) - { - mPreviewAvatar->createDrawable( &gPipeline ); - mPreviewAvatar->mSpecialRenderMode = 1; - mPreviewAvatar->startMotion( ANIM_AGENT_STAND ); - mPreviewAvatar->hideSkirt(); - } - else - { - LL_INFOS() << "Failed to create preview avatar for upload model window" << LL_ENDL; - } -} -//static -U32 LLModelPreview::countRootModels(LLModelLoader::model_list models) -{ - U32 root_models = 0; - model_list::iterator model_iter = models.begin(); - while (model_iter != models.end()) - { - LLModel* mdl = *model_iter; - if (mdl && mdl->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 ) -{ - U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - - LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0); - - buff->allocateBuffer(1, 3, true); - memset( (U8*) buff->getMappedData(), 0, buff->getSize() ); - memset( (U8*) buff->getIndicesPointer(), 0, buff->getIndicesSize() ); - - buff->validateRange( 0, buff->getNumVerts()-1, buff->getNumIndices(), 0 ); - - LLStrider<LLVector3> pos; - LLStrider<LLVector3> norm; - LLStrider<LLVector2> tc; - LLStrider<U16> index; - - buff->getVertexStrider(pos); - - if ( type_mask & LLVertexBuffer::MAP_NORMAL ) - { - buff->getNormalStrider(norm); - } - if ( type_mask & LLVertexBuffer::MAP_TEXCOORD0 ) - { - buff->getTexCoord0Strider(tc); - } - - buff->getIndexStrider(index); - - //resize face array - int faceCnt = pTarget->getNumVolumeFaces(); - pTarget->setNumVolumeFaces( faceCnt+1 ); - pTarget->setVolumeFaceData( faceCnt+1, pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices() ); - -} - -//----------------------------------------------------------------------------- -// render() -//----------------------------------------------------------------------------- -BOOL LLModelPreview::render() +void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost) { assert_main_thread(); - - LLMutexLock lock(this); - mNeedsUpdate = FALSE; - - bool use_shaders = LLGLSLShader::sNoFixedFunction; - - bool edges = mViewOption["show_edges"]; - bool joint_positions = mViewOption["show_joint_positions"]; - bool skin_weight = mViewOption["show_skin_weight"]; - bool textures = mViewOption["show_textures"]; - bool physics = mViewOption["show_physics"]; - - S32 width = getWidth(); - S32 height = getHeight(); - - LLGLSUIDefault def; - LLGLDisable no_blend(GL_BLEND); - LLGLEnable cull(GL_CULL_FACE); - LLGLDepthTest depth(GL_TRUE); - LLGLDisable fog(GL_FOG); - - { - if (use_shaders) - { - gUIProgram.bind(); - } - //clear background to blue - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.ortho(0.0f, width, 0.0f, height, -1.0f, 1.0f); - - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - gGL.loadIdentity(); - - gGL.color4f(0.169f, 0.169f, 0.169f, 1.f); - - gl_rect_2d_simple( width, height ); - - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.popMatrix(); - - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - if (use_shaders) - { - gUIProgram.unbind(); - } - } - - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - - bool has_skin_weights = false; - bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); - bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); - - if ( upload_joints != mLastJointUpdate ) - { - mLastJointUpdate = upload_joints; - } - - 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) - { - LLModelInstance& instance = *model_iter; - LLModel* model = instance.mModel; - model->mPelvisOffset = mPelvisZOffset; - if (!model->mSkinWeights.empty()) - { - has_skin_weights = true; - } + childSetTextArg("import_dimensions", "[X]", llformat("%.3f", x)); + childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", y)); + childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", z)); } - } - if (has_skin_weights && lodsReady()) - { //model has skin weights, enable view options for skin weights and joint positions - if (fmp && isLegacyRigValid() ) - { - fmp->enableViewOption("show_skin_weight"); - fmp->setViewOptionEnabled("show_joint_positions", skin_weight); - mFMP->childEnable("upload_skin"); - mFMP->childSetValue("show_skin_weight", skin_weight); - } - } - else - { - mFMP->childDisable("upload_skin"); - if (fmp) +void LLFloaterModelPreview::setPreviewLOD(S32 lod) { - 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); - } - } - - if (upload_skin && !has_skin_weights) - { //can't upload skin weights if model has no skin weights - mFMP->childSetValue("upload_skin", false); - upload_skin = false; - } - - if (!upload_skin && upload_joints) - { //can't upload joints if not uploading skin weights - mFMP->childSetValue("upload_joints", false); - upload_joints = false; - } - - if (upload_skin && upload_joints) - { - mFMP->childEnable("lock_scale_if_joint_position"); - } - else - { - mFMP->childDisable("lock_scale_if_joint_position"); - mFMP->childSetValue("lock_scale_if_joint_position", false); - } - - //Only enable joint offsets if it passed the earlier critiquing - if ( isRigValidForJointPositionUpload() ) - { - mFMP->childSetEnabled("upload_joints", upload_skin); - } - - F32 explode = mFMP->childGetValue("physics_explode").asReal(); - - glClear(GL_DEPTH_BUFFER_BIT); - - LLRect preview_rect; - - preview_rect = mFMP->getChildView("preview_panel")->getRect(); - - F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight(); - - LLViewerCamera::getInstance()->setAspect(aspect); - - LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); - - LLVector3 offset = mCameraOffset; - LLVector3 target_pos = mPreviewTarget+offset; - - F32 z_near = 0.001f; - F32 z_far = mCameraDistance*10.0f+mPreviewScale.magVec()+mCameraOffset.magVec(); - - if (skin_weight) - { - target_pos = getPreviewAvatar()->getPositionAgent(); - z_near = 0.01f; - z_far = 1024.f; - mCameraDistance = 16.f; - - //render avatar previews every frame - refresh(); - } - - if (use_shaders) - { - gObjectPreviewProgram.bind(); - } - - gGL.loadIdentity(); - gPipeline.enableLightsPreview(); - - LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * - LLQuaternion(mCameraYaw, LLVector3::z_axis); - - LLQuaternion av_rot = camera_rot; - LLViewerCamera::getInstance()->setOriginAndLookAt( - target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest - - - z_near = llclamp(z_far * 0.001f, 0.001f, 0.1f); - - LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); - - stop_glerror(); - - gGL.pushMatrix(); - const F32 BRIGHTNESS = 0.9f; - gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); - - const U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - - LLGLEnable normalize(GL_NORMALIZE); - - if (!mBaseModel.empty() && mVertexBuffer[5].empty()) - { - genBuffers(-1, skin_weight); - //genBuffers(3); - //genLODs(); - } - - if (!mModel[mPreviewLOD].empty()) + if (mModelPreview) { - mFMP->childEnable("reset_btn"); - - bool regen = mVertexBuffer[mPreviewLOD].empty(); - if (!regen) - { - const std::vector<LLPointer<LLVertexBuffer> >& vb_vec = mVertexBuffer[mPreviewLOD].begin()->second; - if (!vb_vec.empty()) - { - const LLVertexBuffer* buff = vb_vec[0]; - regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight; - } - else - { - LL_INFOS() << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL; - regen = TRUE; - } - } - - if (regen) - { - genBuffers(mPreviewLOD, skin_weight); - } - - if (!skin_weight) - { - for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) - { - LLModelInstance& instance = *iter; - - LLModel* model = instance.mLOD[mPreviewLOD]; - - if (!model) - { - continue; - } - - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; - - gGL.multMatrix((GLfloat*) mat.mMatrix); - - - U32 num_models = mVertexBuffer[mPreviewLOD][model].size(); - for (U32 i = 0; i < num_models; ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - buffer->setBuffer(type_mask & buffer->getTypeMask()); - - if (textures) - { - int 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); - - // Find the tex for this material, bind it, and add it to our set - // - LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material); - if (tex) - { - mTextureSet.insert(tex); - } - } - } - else - { - gGL.diffuseColor4f(1,1,1,1); - } - - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.diffuseColor3f(0.4f, 0.4f, 0.4f); - - if (edges) - { - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - gGL.popMatrix(); - } - - if (physics) - { - glClear(GL_DEPTH_BUFFER_BIT); - - for (U32 i = 0; i < 2; i++) - { - if (i == 0) - { //depth only pass - gGL.setColorMask(false, false); - } - else - { - gGL.setColorMask(true, true); - } - - //enable alpha blending on second pass but not first pass - LLGLState blend(GL_BLEND, i); - - gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA); - - for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) - { - LLModelInstance& instance = *iter; - - LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; - - if (!model) - { - continue; - } - - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; - - gGL.multMatrix((GLfloat*) mat.mMatrix); - - - bool render_mesh = true; - - LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; - if (decomp) - { - LLMutexLock(decomp->mMutex); - - LLModel::Decomposition& physics = model->mPhysics; - - if (!physics.mHull.empty()) - { - render_mesh = false; - - if (physics.mMesh.empty()) - { //build vertex buffer for physics mesh - gMeshRepo.buildPhysicsMesh(physics); - } - - if (!physics.mMesh.empty()) - { //render hull instead of mesh - for (U32 i = 0; i < physics.mMesh.size(); ++i) - { - if (explode > 0.f) - { - gGL.pushMatrix(); - - LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; - offset *= explode; - - gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); - } - - static std::vector<LLColor4U> hull_colors; - - if (i+1 >= hull_colors.size()) - { - hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 128)); - } - - gGL.diffuseColor4ubv(hull_colors[i].mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals); - - if (explode > 0.f) - { - gGL.popMatrix(); - } - } - } - } - } - - if (render_mesh) - { - if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) - { - genBuffers(LLModel::LOD_PHYSICS, false); - } - - 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.diffuseColor4f(0.4f, 0.4f, 0.0f, 0.4f); - - buffer->setBuffer(type_mask & buffer->getTypeMask()); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - - gGL.diffuseColor3f(1.f, 1.f, 0.f); - - glLineWidth(2.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - - gGL.popMatrix(); - } - - glLineWidth(3.f); - glPointSize(8.f); - gPipeline.enableLightsFullbright(LLColor4::white); - //show degenerate triangles - LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); - LLGLDisable cull(GL_CULL_FACE); - gGL.diffuseColor4f(1.f,0.f,0.f,1.f); - const LLVector4a scale(0.5f); - - for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) - { - LLModelInstance& instance = *iter; - - LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; - - if (!model) - { - continue; - } - - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; - - gGL.multMatrix((GLfloat*) mat.mMatrix); - - - LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; - if (decomp) - { - LLMutexLock(decomp->mMutex); - - LLModel::Decomposition& physics = model->mPhysics; - - if (physics.mHull.empty()) - { - 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]; - - buffer->setBuffer(type_mask & buffer->getTypeMask()); - - LLStrider<LLVector3> pos_strider; - buffer->getVertexStrider(pos_strider, 0); - LLVector4a* pos = (LLVector4a*) pos_strider.get(); - - LLStrider<U16> idx; - buffer->getIndexStrider(idx, 0); - - for (U32 i = 0; i < buffer->getNumIndices(); i += 3) - { - LLVector4a v1; v1.setMul(pos[*idx++], scale); - LLVector4a v2; v2.setMul(pos[*idx++], scale); - LLVector4a v3; v3.setMul(pos[*idx++], scale); - - if (ll_is_degenerate(v1,v2,v3)) - { - buffer->draw(LLRender::LINE_LOOP, 3, i); - buffer->draw(LLRender::POINTS, 3, i); - } - } + mModelPreview->setPreviewLOD(lod); } } - } - - gGL.popMatrix(); - } - glLineWidth(1.f); - glPointSize(1.f); - gPipeline.enableLightsPreview(); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - } - } - } - else - { - target_pos = getPreviewAvatar()->getPositionAgent(); - - LLViewerCamera::getInstance()->setOriginAndLookAt( - target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest - - 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) - { - LLModelInstance& instance = *model_iter; - LLModel* model = instance.mModel; - - if (!model->mSkinWeights.empty()) - { - for (U32 i = 0, e = mVertexBuffer[mPreviewLOD][model].size(); i < e; ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - const LLVolumeFace& face = model->getVolumeFace(i); - - LLStrider<LLVector3> position; - buffer->getVertexStrider(position); - - LLStrider<LLVector4> weight; - buffer->getWeight4Strider(weight); - - //quick 'n dirty software vertex skinning - - //build matrix palette - - LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; - const LLMeshSkinInfo *skin = &model->mSkinInfo; - U32 count = LLSkinningUtil::getMeshJointCount(skin); - LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, - skin, getPreviewAvatar()); - LLMatrix4a bind_shape_matrix; - bind_shape_matrix.loadu(skin->mBindShapeMatrix); - U32 max_joints = LLSkinningUtil::getMaxJointCount(); - for (U32 j = 0; j < buffer->getNumVerts(); ++j) - { - LLMatrix4a final_mat; - F32 *wptr = weight[j].mV; - LLSkinningUtil::getPerVertexSkinMatrix(wptr, mat, true, final_mat, max_joints); - - //VECTORIZE THIS - LLVector4a& v = face.mPositions[j]; - - LLVector4a t; - LLVector4a dst; - bind_shape_matrix.affineTransform(v, t); - final_mat.affineTransform(t, dst); - - position[j][0] = dst[0]; - position[j][1] = dst[1]; - position[j][2] = dst[2]; - } - - llassert(model->mMaterialList.size() > i); - const std::string& binding = instance.mModel->mMaterialList[i]; - const LLImportMaterial& material = instance.mMaterial[binding]; - - buffer->setBuffer(type_mask & buffer->getTypeMask()); - gGL.diffuseColor4fv(material.mDiffuseColor.mV); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - // Find the tex for this material, bind it, and add it to our set - // - LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material); - if (tex) - { - 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); - buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - } - } - } - - if (joint_positions) - { - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - if (shader) - { - gDebugProgram.bind(); - } - getPreviewAvatar()->renderCollisionVolumes(); - getPreviewAvatar()->renderBones(); - if (shader) - { - shader->bind(); - } - } - - } - } - - if (use_shaders) - { - gObjectPreviewProgram.unbind(); - } - - gGL.popMatrix(); - - return TRUE; -} - -//----------------------------------------------------------------------------- -// refresh() -//----------------------------------------------------------------------------- -void LLModelPreview::refresh() -{ - mNeedsUpdate = TRUE; -} - -//----------------------------------------------------------------------------- -// rotate() -//----------------------------------------------------------------------------- -void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) -{ - mCameraYaw = mCameraYaw + yaw_radians; - - mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); -} - -//----------------------------------------------------------------------------- -// zoom() -//----------------------------------------------------------------------------- -void LLModelPreview::zoom(F32 zoom_amt) -{ - F32 new_zoom = mCameraZoom+zoom_amt; - - mCameraZoom = llclamp(new_zoom, 1.f, 10.f); -} - -void LLModelPreview::pan(F32 right, F32 up) -{ - mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f); - mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f); -} - -void LLModelPreview::setPreviewLOD(S32 lod) -{ - lod = llclamp(lod, 0, (S32) LLModel::LOD_HIGH); - - if (lod != mPreviewLOD) - { - mPreviewLOD = lod; - - LLComboBox* combo_box = mFMP->getChild<LLComboBox>("preview_lod_combo"); - combo_box->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order - mFMP->childSetValue("lod_file_" + lod_name[mPreviewLOD], mLODFile[mPreviewLOD]); - - LLComboBox* combo_box2 = mFMP->getChild<LLComboBox>("preview_lod_combo2"); - combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order - - LLComboBox* combo_box3 = mFMP->getChild<LLComboBox>("preview_lod_combo3"); - combo_box3->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order - - LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); - LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); - - for (S32 i = 0; i <= LLModel::LOD_HIGH; ++i) - { - const LLColor4& color = (i == lod) ? highlight_color : normal_color; - - mFMP->childSetColor(lod_status_name[i], color); - mFMP->childSetColor(lod_label_name[i], color); - mFMP->childSetColor(lod_triangles_name[i], color); - mFMP->childSetColor(lod_vertices_name[i], color); - } - } - refresh(); - updateStatusMessages(); -} void LLFloaterModelPreview::onBrowseLOD(S32 lod) { @@ -4306,12 +1573,16 @@ void LLFloaterModelPreview::onReset(void* user_data) { assert_main_thread(); + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data; fmp->childDisable("reset_btn"); + fmp->clearLogTab(); + fmp->clearAvatarTab(); LLModelPreview* mp = fmp->mModelPreview; std::string filename = mp->mLODFile[LLModel::LOD_HIGH]; fmp->resetDisplayOptions(); + fmp->resetUploadOptions(); //reset model preview fmp->initModelPreview(); @@ -4325,6 +1596,7 @@ void LLFloaterModelPreview::onUpload(void* user_data) assert_main_thread(); LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->clearLogTab(); mp->mUploadBtn->setEnabled(false); @@ -4353,70 +1625,36 @@ void LLFloaterModelPreview::refresh() sInstance->mModelPreview->mDirty = true; } -//static -void LLModelPreview::textureLoadedCallback( - BOOL success, - LLViewerFetchedTexture *src_vi, - LLImageRaw* src, - LLImageRaw* src_aux, - S32 discard_level, - BOOL final, - void* userdata ) +LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) { - LLModelPreview* preview = (LLModelPreview*) userdata; - preview->refresh(); + mStage = stage; + mContinue = 1; + mModel = mdl; + mDecompID = &mdl->mDecompID; + mParams = sInstance->mDecompParams; - if(final && preview->mModelLoader) - { - if(preview->mModelLoader->mNumOfFetchingTextures > 0) - { - preview->mModelLoader->mNumOfFetchingTextures-- ; - } - } + //copy out positions and indices + assignData(mdl) ; } -// static -bool LLModelPreview::lodQueryCallback() +void LLFloaterModelPreview::setCtrlLoadFromFile(S32 lod) { - // 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 && fmp->mModelPreview) + if (lod == LLModel::LOD_PHYSICS) { - LLModelPreview* preview = fmp->mModelPreview; - if (preview->mLodsQuery.size() > 0) + LLComboBox* lod_combo = findChild<LLComboBox>("physics_lod_combo"); + if (lod_combo) { - S32 lod = preview->mLodsQuery.back(); - preview->mLodsQuery.pop_back(); - preview->genLODs(lod); - - // return false to continue cycle - return false; + lod_combo->setCurrentByIndex(5); } } - // nothing to process - return true; -} - -void LLModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) + else { - if (!mLODFrozen) + LLComboBox* lod_combo = findChild<LLComboBox>("lod_source_" + lod_name[lod]); + if (lod_combo) { - genLODs(lod, 3, enforce_tri_limit); - refresh(); + lod_combo->setCurrentByIndex(0); } } - -LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) -{ - mStage = stage; - mContinue = 1; - mModel = mdl; - mDecompID = &mdl->mDecompID; - mParams = sInstance->mDecompParams; - - //copy out positions and indices - assignData(mdl) ; } void LLFloaterModelPreview::setStatusMessage(const std::string& msg) @@ -4430,6 +1668,12 @@ void LLFloaterModelPreview::toggleCalculateButton() toggleCalculateButton(true); } +void LLFloaterModelPreview::modelUpdated(bool calculate_visible) +{ + mModelPhysicsFee.clear(); + toggleCalculateButton(calculate_visible); +} + void LLFloaterModelPreview::toggleCalculateButton(bool visible) { mCalculateBtn->setVisible(visible); @@ -4455,12 +1699,19 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible) childSetTextArg("download_weight", "[ST]", tbd); childSetTextArg("server_weight", "[SIM]", tbd); childSetTextArg("physics_weight", "[PH]", tbd); - childSetTextArg("upload_fee", "[FEE]", tbd); - childSetTextArg("price_breakdown", "[STREAMING]", tbd); - childSetTextArg("price_breakdown", "[PHYSICS]", tbd); - childSetTextArg("price_breakdown", "[INSTANCES]", tbd); - childSetTextArg("price_breakdown", "[TEXTURES]", tbd); - childSetTextArg("price_breakdown", "[MODEL]", tbd); + if (!mModelPhysicsFee.isMap() || mModelPhysicsFee.emptyMap()) + { + childSetTextArg("upload_fee", "[FEE]", tbd); + } + std::string dashes = hasString("--") ? getString("--") : "--"; + childSetTextArg("price_breakdown", "[STREAMING]", dashes); + childSetTextArg("price_breakdown", "[PHYSICS]", dashes); + childSetTextArg("price_breakdown", "[INSTANCES]", dashes); + childSetTextArg("price_breakdown", "[TEXTURES]", dashes); + childSetTextArg("price_breakdown", "[MODEL]", dashes); + childSetTextArg("physics_breakdown", "[PCH]", dashes); + childSetTextArg("physics_breakdown", "[PM]", dashes); + childSetTextArg("physics_breakdown", "[PHU]", dashes); } } @@ -4487,6 +1738,44 @@ void LLFloaterModelPreview::resetDisplayOptions() } } +void LLFloaterModelPreview::resetUploadOptions() +{ + childSetValue("import_scale", 1); + childSetValue("pelvis_offset", 0); + childSetValue("physics_explode", 0); + childSetValue("physics_file", ""); + childSetVisible("Retain%", false); + childSetVisible("Retain%_label", false); + childSetVisible("Detail Scale", true); + childSetVisible("Detail Scale label", true); + + getChild<LLComboBox>("lod_source_" + lod_name[NUM_LOD - 1])->setCurrentByIndex(LLModelPreview::LOD_FROM_FILE); + for (S32 lod = 0; lod < NUM_LOD - 1; ++lod) + { + getChild<LLComboBox>("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::GENERATE); + childSetValue("lod_file_" + lod_name[lod], ""); + } + + for(auto& p : mDefaultDecompParams) + { + std::string ctrl_name(p.first); + LLUICtrl* ctrl = getChild<LLUICtrl>(ctrl_name); + if (ctrl) + { + ctrl->setValue(p.second); + } + } + getChild<LLComboBox>("physics_lod_combo")->setCurrentByIndex(0); + getChild<LLComboBox>("Cosine%")->setCurrentByIndex(0); +} + +void LLFloaterModelPreview::clearLogTab() +{ + mUploadLogText->clear(); + LLPanel* panel = mTabContainer->getPanelByName("logs_panel"); + mTabContainer->setTabPanelFlashing(panel, false); +} + void LLFloaterModelPreview::onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) { mModelPhysicsFee = result; @@ -4510,15 +1799,40 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived() childSetTextArg("price_breakdown", "[INSTANCES]", llformat("%d", result["upload_price_breakdown"]["mesh_instance"].asInteger())); childSetTextArg("price_breakdown", "[TEXTURES]", llformat("%d", result["upload_price_breakdown"]["texture"].asInteger())); childSetTextArg("price_breakdown", "[MODEL]", llformat("%d", result["upload_price_breakdown"]["model"].asInteger())); + + childSetTextArg("physics_breakdown", "[PCH]", llformat("%0.3f", result["model_physics_cost"]["hull"].asReal())); + childSetTextArg("physics_breakdown", "[PM]", llformat("%0.3f", result["model_physics_cost"]["mesh"].asReal())); + childSetTextArg("physics_breakdown", "[PHU]", llformat("%0.3f", result["model_physics_cost"]["decomposition"].asReal())); + childSetTextArg("streaming_breakdown", "[STR_TOTAL]", llformat("%d", result["streaming_cost"].asInteger())); + childSetTextArg("streaming_breakdown", "[STR_HIGH]", llformat("%d", result["streaming_params"]["high_lod"].asInteger())); + childSetTextArg("streaming_breakdown", "[STR_MED]", llformat("%d", result["streaming_params"]["medium_lod"].asInteger())); + childSetTextArg("streaming_breakdown", "[STR_LOW]", llformat("%d", result["streaming_params"]["low_lod"].asInteger())); + childSetTextArg("streaming_breakdown", "[STR_LOWEST]", llformat("%d", result["streaming_params"]["lowest_lod"].asInteger())); + childSetVisible("upload_fee", true); childSetVisible("price_breakdown", true); mUploadBtn->setEnabled(isModelUploadAllowed()); } -void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) +void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason, const LLSD& result) { - LL_WARNS() << "LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(" << status << " : " << reason << ")" << LL_ENDL; + std::ostringstream out; + out << "LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(" << status; + out << " : " << reason << ")"; + LL_WARNS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); doOnIdleOneTime(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, true)); + + if (result.has("upload_price")) + { + mModelPhysicsFee = result; + childSetTextArg("upload_fee", "[FEE]", llformat("%d", result["upload_price"].asInteger())); + childSetVisible("upload_fee", true); + } + else + { + mModelPhysicsFee.clear(); + } } /*virtual*/ diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index edc90d1695..8a01b0c307 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -28,36 +28,26 @@ #define LL_LLFLOATERMODELPREVIEW_H #include "llfloaternamedesc.h" - -#include "lldynamictexture.h" -#include "llquaternion.h" -#include "llmeshrepository.h" -#include "llmodel.h" -#include "llthread.h" -#include "llviewermenufile.h" #include "llfloatermodeluploadbase.h" - -#include "lldaeloader.h" +#include "llmeshrepository.h" class LLComboBox; class LLJoint; -class LLViewerJointMesh; -class LLVOAvatar; -class LLTextBox; -class LLVertexBuffer; +class LLMeshFilePicker; class LLModelPreview; -class LLFloaterModelPreview; -class DAE; -class daeElement; -class domProfile_COMMON; -class domInstance_geometry; -class domNode; -class domTranslate; -class domController; -class domSkin; -class domMesh; -class LLMenuButton; -class LLToggleableMenu; +class LLTabContainer; +class LLViewerTextEditor; + + +class LLJointOverrideData +{ +public: + LLJointOverrideData() : mHasConflicts(false) {}; + std::map<std::string, LLVector3> mPosOverrides; // models with overrides + std::set<std::string> mModelsNoOverrides; // models without defined overrides + bool mHasConflicts; +}; +typedef std::map<std::string, LLJointOverrideData> joint_override_data_map_t; class LLFloaterModelPreview : public LLFloaterModelUploadBase { @@ -80,6 +70,7 @@ public: virtual ~LLFloaterModelPreview(); virtual BOOL postBuild(); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); void initModelPreview(); @@ -93,6 +84,11 @@ public: static void onMouseCaptureLostModelPreview(LLMouseHandler*); static void setUploadAmount(S32 amount) { sUploadAmount = amount; } + static void addStringToLog(const std::string& message, const LLSD& args, bool flash, S32 lod = -1); + static void addStringToLog(const std::string& str, bool flash); + static void addStringToLog(const std::ostringstream& strm, bool flash); + void clearAvatarTab(); // clears table + void updateAvatarTab(bool highlight_overrides); // populates table and data as nessesary void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost); void setPreviewLOD(S32 lod); @@ -107,13 +103,17 @@ public: void loadModel(S32 lod); void loadModel(S32 lod, const std::string& file_name, bool force_disable_slm = false); + + void loadHighLodModel(); void onViewOptionChecked(LLUICtrl* ctrl); + void onUploadOptionChecked(LLUICtrl* ctrl); bool isViewOptionChecked(const LLSD& userdata); bool isViewOptionEnabled(const LLSD& userdata); void setViewOptionEnabled(const std::string& option, bool enabled); void enableViewOption(const std::string& option); void disableViewOption(const std::string& option); + void onShowSkinWeightChecked(LLUICtrl* ctrl); bool isModelLoading(); @@ -125,7 +125,7 @@ public: /*virtual*/ void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url); void handleModelPhysicsFeeReceived(); - /*virtual*/ void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason); + /*virtual*/ void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason, const LLSD& result); /*virtual*/ void onModelUploadSuccess(); @@ -142,8 +142,6 @@ protected: static void onImportScaleCommit(LLUICtrl*, void*); static void onPelvisOffsetCommit(LLUICtrl*, void*); - static void onUploadJointsCommit(LLUICtrl*,void*); - static void onUploadSkinCommit(LLUICtrl*,void*); static void onPreviewLODCommit(LLUICtrl*,void*); @@ -154,6 +152,7 @@ protected: static void onAutoFillCommit(LLUICtrl*,void*); void onLODParamCommit(S32 lod, bool enforce_tri_limit); + void draw3dPreview(); static void onExplodeCommit(LLUICtrl*, void*); @@ -175,11 +174,15 @@ protected: // FIXME - this function and mStatusMessage have no visible effect, and the // actual status messages are managed by directly manipulation of // the UI element. - void setStatusMessage(const std::string& msg); + void setStatusMessage(const std::string& msg); + void addStringToLogTab(const std::string& str, bool flash); + + void setCtrlLoadFromFile(S32 lod); LLModelPreview* mModelPreview; LLPhysicsDecomp::decomp_params mDecompParams; + LLPhysicsDecomp::decomp_params mDefaultDecompParams; S32 mLastMouseX; S32 mLastMouseY; @@ -203,221 +206,34 @@ protected: LLSD mModelPhysicsFee; private: - void onClickCalculateBtn(); - void toggleCalculateButton(); + void onClickCalculateBtn(); + void onJointListSelection(); void onLoDSourceCommit(S32 lod); + void modelUpdated(bool calculate_visible); + // Toggles between "Calculate weights & fee" and "Upload" buttons. + void toggleCalculateButton(); void toggleCalculateButton(bool visible); // resets display options of model preview to their defaults. void resetDisplayOptions(); + void resetUploadOptions(); + void clearLogTab(); + void createSmoothComboBox(LLComboBox* combo_box, float min, float max); LLButton* mUploadBtn; LLButton* mCalculateBtn; -}; - -class LLMeshFilePicker : public LLFilePickerThread -{ -public: - LLMeshFilePicker(LLModelPreview* mp, S32 lod); - virtual void notify(const std::vector<std::string>& filenames); - -private: - LLModelPreview* mMP; - S32 mLOD; -}; - - -class LLModelPreview : public LLViewerDynamicTexture, public LLMutex -{ - typedef boost::signals2::signal<void (F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost)> details_signal_t; - typedef boost::signals2::signal<void (void)> model_loaded_signal_t; - typedef boost::signals2::signal<void (bool)> 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 resetPreviewTarget(); - void setPreviewTarget(F32 distance); - void setTexture(U32 name) { mTextureName = name; } - - void setPhysicsFromLOD(S32 lod); - BOOL render(); - void update(); - void genBuffers(S32 lod, bool skinned); - void clearBuffers(); - void refresh(); - void rotate(F32 yaw_radians, F32 pitch_radians); - void zoom(F32 zoom_amt); - void pan(F32 right, F32 up); - 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 generateNormals(); - void restoreNormals(); - U32 calcResourceCost(); - void rebuildUploadData(); - void saveUploadData(bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position); - void saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position); - void clearIncompatible(S32 lod); - void updateStatusMessages(); - void updateLodControls(S32 lod); - void clearGLODGroup(); - void onLODParamCommit(S32 lod, bool enforce_tri_limit); - void addEmptyFace( LLModel* pTarget ); - - const bool getModelPivot( void ) const { return mHasPivot; } - void setHasPivot( bool val ) { mHasPivot = val; } - void setModelPivot( const LLVector3& pivot ) { mModelPivot = pivot; } - - //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; } - - //Accessors for the legacy rigs - 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; } - - static bool sIgnoreLoadedCallback; - std::vector<S32> mLodsQuery; - std::vector<S32> mLodsWithParsingError; - -protected: - - static void loadedCallback(LLModelLoader::scene& scene,LLModelLoader::model_list& model_list, S32 lod, void* opaque); - static void stateChangedCallback(U32 state, void* opaque); - - 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 ); - //Creates the dummy avatar for the preview window - void createPreviewAvatar( void ); - //Accessor for the dummy avatar - LLVOAvatar* getPreviewAvatar( void ) { return mPreviewAvatar; } - // Count amount of original models, excluding sub-models - static U32 countRootModels(LLModelLoader::model_list models); - - protected: - friend class LLModelLoader; - friend class LLFloaterModelPreview; - friend class LLFloaterModelPreview::DecompRequest; - friend class LLPhysicsDecomp; - - LLFloater* mFMP; - - BOOL mNeedsUpdate; - bool mDirty; - bool mGenLOD; - U32 mTextureName; - F32 mCameraDistance; - F32 mCameraYaw; - F32 mCameraPitch; - F32 mCameraZoom; - LLVector3 mCameraOffset; - LLVector3 mPreviewTarget; - LLVector3 mPreviewScale; - S32 mPreviewLOD; - S32 mPhysicsSearchLOD; - U32 mResourceCost; - std::string mLODFile[LLModel::NUM_LODS]; - bool mLoading; - U32 mLoadState; - bool mResetJoints; - bool mModelNoErrors; - - std::map<std::string, bool> mViewOption; - - //GLOD object parameters (must rebuild object if these change) - bool mLODFrozen; - F32 mBuildShareTolerance; - U32 mBuildQueueMode; - U32 mBuildOperator; - U32 mBuildBorderMode; - U32 mRequestedLoDMode[LLModel::NUM_LODS]; - S32 mRequestedTriangleCount[LLModel::NUM_LODS]; - F32 mRequestedErrorThreshold[LLModel::NUM_LODS]; - U32 mRequestedBuildOperator[LLModel::NUM_LODS]; - U32 mRequestedQueueMode[LLModel::NUM_LODS]; - U32 mRequestedBorderMode[LLModel::NUM_LODS]; - F32 mRequestedShareTolerance[LLModel::NUM_LODS]; - F32 mRequestedCreaseAngle[LLModel::NUM_LODS]; - - LLModelLoader* mModelLoader; - - LLModelLoader::scene mScene[LLModel::NUM_LODS]; - LLModelLoader::scene mBaseScene; - - LLModelLoader::model_list mModel[LLModel::NUM_LODS]; - LLModelLoader::model_list mBaseModel; - - typedef std::vector<LLVolumeFace> v_LLVolumeFace_t; - typedef std::vector<v_LLVolumeFace_t> vv_LLVolumeFace_t; - - vv_LLVolumeFace_t mModelFacesCopy[LLModel::NUM_LODS]; - vv_LLVolumeFace_t mBaseModelFacesCopy; - - U32 mGroup; - std::map<LLPointer<LLModel>, U32> mObject; - U32 mMaxTriangleLimit; - - LLMeshUploadThread::instance_list mUploadData; - std::set<LLViewerFetchedTexture * > mTextureSet; - - //map of vertex buffers to models (one vertex buffer in vector per face in model - std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[LLModel::NUM_LODS+1]; - - details_signal_t mDetailsSignal; - model_loaded_signal_t mModelLoadedSignal; - model_updated_signal_t mModelUpdatedSignal; - - LLVector3 mModelPivot; - bool mHasPivot; - - float mPelvisZOffset; - - bool mRigValidJointUpload; - bool mLegacyRigValid; - - bool mLastJointUpdate; + LLViewerTextEditor* mUploadLogText; + LLTabContainer* mTabContainer; - JointNameSet mJointsFromNode; - JointTransformMap mJointTransformMap; + S32 mAvatarTabIndex; // just to avoid any issues in case of xml changes + std::string mSelectedJointName; - LLPointer<LLVOAvatar> mPreviewAvatar; + joint_override_data_map_t mJointOverrides[LLModel::NUM_LODS]; }; #endif // LL_LLFLOATERMODELPREVIEW_H diff --git a/indra/newview/llfloatermodeluploadbase.h b/indra/newview/llfloatermodeluploadbase.h index 0d4c834122..721fce059e 100644 --- a/indra/newview/llfloatermodeluploadbase.h +++ b/indra/newview/llfloatermodeluploadbase.h @@ -45,7 +45,7 @@ public: virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0; - virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) = 0; + virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason, const LLSD& result) = 0; virtual void onModelUploadSuccess() {}; diff --git a/indra/newview/llfloatermyenvironment.cpp b/indra/newview/llfloatermyenvironment.cpp new file mode 100644 index 0000000000..21d106c8b1 --- /dev/null +++ b/indra/newview/llfloatermyenvironment.cpp @@ -0,0 +1,459 @@ +/** + * @file llfloatergesture.cpp + * @brief LLFloaterMyEnvironment class implementation + * + * $LicenseInfo:firstyear=2002&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 "llfloatermyenvironment.h" + +#include "llinventory.h" +#include "llinventorybridge.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" + +#include "llagent.h" +#include "llclipboard.h" +#include "llcheckboxctrl.h" +#include "llviewerinventory.h" +#include "llenvironment.h" +#include "llparcel.h" +#include "llviewerparcelmgr.h" + +//========================================================================= +namespace +{ + const std::string CHECK_DAYS("chk_days"); + const std::string CHECK_SKIES("chk_skies"); + const std::string CHECK_WATER("chk_water"); + const std::string FLT_SEARCH("flt_search"); + const std::string PANEL_SETTINGS("pnl_settings"); + const std::string CHECK_SHOWFOLDERS("chk_showfolders"); + const std::string BUTTON_NEWSETTINGS("btn_gear"); + const std::string BUTTON_GEAR("btn_newsettings"); + const std::string BUTTON_DELETE("btn_del"); + + + const std::string ACTION_DOCREATE("MyEnvironments.DoCreate"); + const std::string ACTION_DOEDIT("MyEnvironments.DoEdit"); + const std::string ACTION_DOAPPLY("MyEnvironments.DoApply"); + const std::string ACTION_COPYPASTE("MyEnvironments.CopyPaste"); + const std::string ENABLE_ACTION("MyEnvironments.EnableAction"); + const std::string ENABLE_CANAPPLY("MyEnvironments.CanApply"); + const std::string ENABLE_ENVIRONMENT("MyEnvironments.EnvironmentEnabled"); + + const std::string PARAMETER_REGION("region"); + const std::string PARAMETER_PARCEL("parcel"); + const std::string PARAMETER_LOCAL("local"); + + const std::string PARAMETER_EDIT("edit"); + const std::string PARAMETER_COPY("copy"); + const std::string PARAMETER_PASTE("paste"); + const std::string PARAMETER_COPYUUID("copy_uuid"); +} + +//========================================================================= +LLFloaterMyEnvironment::LLFloaterMyEnvironment(const LLSD& key) : + LLFloater(key), + mInventoryList(nullptr), + mShowFolders(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS), + mTypeFilter((0x01 << static_cast<U64>(LLSettingsType::ST_DAYCYCLE)) | (0x01 << static_cast<U64>(LLSettingsType::ST_SKY)) | (0x01 << static_cast<U64>(LLSettingsType::ST_WATER))), + mSelectedAsset() +{ + mCommitCallbackRegistrar.add(ACTION_DOCREATE, [this](LLUICtrl *, const LLSD &userdata) { onDoCreate(userdata); }); + mCommitCallbackRegistrar.add(ACTION_DOEDIT, [this](LLUICtrl *, const LLSD &userdata) { mInventoryList->openSelected(); }); + mCommitCallbackRegistrar.add(ACTION_DOAPPLY, [this](LLUICtrl *, const LLSD &userdata) { onDoApply(userdata.asString()); }); + mCommitCallbackRegistrar.add(ACTION_COPYPASTE, [this](LLUICtrl *, const LLSD &userdata) { mInventoryList->doToSelected(userdata.asString()); }); + + mEnableCallbackRegistrar.add(ENABLE_ACTION, [this](LLUICtrl *, const LLSD &userdata) { return canAction(userdata.asString()); }); + mEnableCallbackRegistrar.add(ENABLE_CANAPPLY, [this](LLUICtrl *, const LLSD &userdata) { return canApply(userdata.asString()); }); + mEnableCallbackRegistrar.add(ENABLE_ENVIRONMENT, [](LLUICtrl *, const LLSD &) { return LLEnvironment::instance().isInventoryEnabled(); }); + +} + +LLFloaterMyEnvironment::~LLFloaterMyEnvironment() +{ +} + + +BOOL LLFloaterMyEnvironment::postBuild() +{ + mInventoryList = getChild<LLInventoryPanel>(PANEL_SETTINGS); + + if (mInventoryList) + { + U32 filter_types = 0x0; + filter_types |= 0x1 << LLInventoryType::IT_SETTINGS; + + mInventoryList->setFilterTypes(filter_types); + + mInventoryList->setSelectCallback([this](const std::deque<LLFolderViewItem*>&, BOOL) { onSelectionChange(); }); + mInventoryList->setShowFolderState(mShowFolders); + mInventoryList->setFilterSettingsTypes(mTypeFilter); + } + + childSetCommitCallback(CHECK_DAYS, [this](LLUICtrl*, void*) { onFilterCheckChange(); }, nullptr); + childSetCommitCallback(CHECK_SKIES, [this](LLUICtrl*, void*) { onFilterCheckChange(); }, nullptr); + childSetCommitCallback(CHECK_WATER, [this](LLUICtrl*, void*) { onFilterCheckChange(); }, nullptr); + childSetCommitCallback(CHECK_SHOWFOLDERS, [this](LLUICtrl*, void*) { onShowFoldersChange(); }, nullptr); + + mFilterEdit = getChild<LLFilterEditor>(FLT_SEARCH); + mFilterEdit->setCommitCallback([this](LLUICtrl*, const LLSD& param){ onFilterEdit(param.asString()); }); + + childSetCommitCallback(BUTTON_DELETE, [this](LLUICtrl *, void*) { onDeleteSelected(); }, nullptr); + mSavedFolderState.setApply(FALSE); + return TRUE; +} + +void LLFloaterMyEnvironment::refresh() +{ + getChild<LLCheckBoxCtrl>(CHECK_SHOWFOLDERS)->setValue(LLSD::Boolean(mShowFolders == LLInventoryFilter::SHOW_ALL_FOLDERS)); + + getChild<LLCheckBoxCtrl>(CHECK_DAYS)->setValue(LLSD::Boolean(mTypeFilter & (0x01 << static_cast<U64>(LLSettingsType::ST_DAYCYCLE)))); + getChild<LLCheckBoxCtrl>(CHECK_SKIES)->setValue(LLSD::Boolean(mTypeFilter & (0x01 << static_cast<U64>(LLSettingsType::ST_SKY)))); + getChild<LLCheckBoxCtrl>(CHECK_WATER)->setValue(LLSD::Boolean(mTypeFilter & (0x01 << static_cast<U64>(LLSettingsType::ST_WATER)))); + + refreshButtonStates(); + +} + +void LLFloaterMyEnvironment::onOpen(const LLSD& key) +{ + LLFloater::onOpen(key); + + if (key.has("asset_id") && mInventoryList) + { + mSelectedAsset = key["asset_id"].asUUID(); + + if (!mSelectedAsset.isNull()) + { + LLUUID obj_id = findItemByAssetId(mSelectedAsset, false, false); + if (!obj_id.isNull()) + mInventoryList->setSelection(obj_id, false); + } + } + else + { + mSelectedAsset.setNull(); + } + + refresh(); +} + +//------------------------------------------------------------------------- +void LLFloaterMyEnvironment::onShowFoldersChange() +{ + bool show_check(getChild<LLCheckBoxCtrl>(CHECK_SHOWFOLDERS)->getValue().asBoolean()); + + mShowFolders = (show_check) ? LLInventoryFilter::SHOW_ALL_FOLDERS : LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS; + + if (mInventoryList) + mInventoryList->setShowFolderState(mShowFolders); +} + +void LLFloaterMyEnvironment::onFilterCheckChange() +{ + mTypeFilter = 0x0; + + if (getChild<LLCheckBoxCtrl>(CHECK_DAYS)->getValue().asBoolean()) + mTypeFilter |= 0x01 << static_cast<U64>(LLSettingsType::ST_DAYCYCLE); + if (getChild<LLCheckBoxCtrl>(CHECK_SKIES)->getValue().asBoolean()) + mTypeFilter |= 0x01 << static_cast<U64>(LLSettingsType::ST_SKY); + if (getChild<LLCheckBoxCtrl>(CHECK_WATER)->getValue().asBoolean()) + mTypeFilter |= 0x01 << static_cast<U64>(LLSettingsType::ST_WATER); + + if (mInventoryList) + mInventoryList->setFilterSettingsTypes(mTypeFilter); +} + +void LLFloaterMyEnvironment::onSelectionChange() +{ + refreshButtonStates(); +} + +void LLFloaterMyEnvironment::onFilterEdit(const std::string& search_string) +{ + std::string upper_case_search_string = search_string; + LLStringUtil::toUpper(upper_case_search_string); + + if (upper_case_search_string.empty()) + { + if (mInventoryList->getFilterSubString().empty()) + { + // current filter and new filter empty, do nothing + return; + } + + mSavedFolderState.setApply(TRUE); + mInventoryList->getRootFolder()->applyFunctorRecursively(mSavedFolderState); + // add folder with current item to list of previously opened folders + LLOpenFoldersWithSelection opener; + mInventoryList->getRootFolder()->applyFunctorRecursively(opener); + mInventoryList->getRootFolder()->scrollToShowSelection(); + + } + else if (mInventoryList->getFilterSubString().empty()) + { + // first letter in search term, save existing folder open state + mSavedFolderState.setApply(FALSE); + mInventoryList->getRootFolder()->applyFunctorRecursively(mSavedFolderState); + } + + mInventoryList->setFilterSubString(search_string); +} + +void LLFloaterMyEnvironment::onDeleteSelected() +{ + uuid_vec_t selected; + + getSelectedIds(selected); + if (selected.empty()) + return; + + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + for (const LLUUID& itemid: selected) + { + LLInventoryItem* inv_item = gInventory.getItem(itemid); + + if (inv_item && inv_item->getInventoryType() == LLInventoryType::IT_SETTINGS) + { + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(inv_item->getParentUUID(), -1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(trash_id, 1); + update.push_back(new_folder); + gInventory.accountForUpdate(update); + + LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(inv_item); + new_item->setParent(trash_id); + new_item->updateParentOnServer(FALSE); + gInventory.updateItem(new_item); + } + } + gInventory.notifyObservers(); +} + + +void LLFloaterMyEnvironment::onDoCreate(const LLSD &data) +{ + menu_create_inventory_item(mInventoryList, NULL, data); +} + +void LLFloaterMyEnvironment::onDoApply(const std::string &context) +{ + uuid_vec_t selected; + getSelectedIds(selected); + + if (selected.size() != 1) // Exactly one item selected. + return; + + LLUUID item_id(selected.front()); + + LLInventoryItem* itemp = gInventory.getItem(item_id); + + if (itemp && itemp->getInventoryType() == LLInventoryType::IT_SETTINGS) + { + LLUUID asset_id = itemp->getAssetUUID(); + std::string name = itemp->getName(); + + U32 flags(0); + + if (!itemp->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID())) + flags |= LLSettingsBase::FLAG_NOMOD; + if (!itemp->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID())) + flags |= LLSettingsBase::FLAG_NOTRANS; + + if (context == PARAMETER_REGION) + { + LLEnvironment::instance().updateRegion(asset_id, name, LLEnvironment::NO_TRACK, -1, -1, flags); + LLEnvironment::instance().setSharedEnvironment(); + } + else if (context == PARAMETER_PARCEL) + { + LLParcel *parcel(LLViewerParcelMgr::instance().getAgentOrSelectedParcel()); + if (!parcel) + { + LL_WARNS("ENVIRONMENT") << "Unable to determine parcel." << LL_ENDL; + return; + } + LLEnvironment::instance().updateParcel(parcel->getLocalID(), asset_id, name, LLEnvironment::NO_TRACK, -1, -1, flags); + LLEnvironment::instance().setSharedEnvironment(); + } + else if (context == PARAMETER_LOCAL) + { + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, asset_id); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL); + } + } +} + +bool LLFloaterMyEnvironment::canAction(const std::string &context) +{ + uuid_vec_t selected; + getSelectedIds(selected); + + if (selected.empty()) + return false; + + if (context == PARAMETER_EDIT) + { + return (selected.size() == 1) && isSettingSelected(selected.front()); + } + else if (context == PARAMETER_COPY) + { + for (std::vector<LLUUID>::iterator it = selected.begin(); it != selected.end(); it++) + { + if(!isSettingSelected(*it)) + { + return false; + } + } + return true; + } + else if (context == PARAMETER_PASTE) + { + if (!LLClipboard::instance().hasContents()) + return false; + + std::vector<LLUUID> ids; + LLClipboard::instance().pasteFromClipboard(ids); + for (std::vector<LLUUID>::iterator it = ids.begin(); it != ids.end(); it++) + { + if (!isSettingSelected(*it)) + { + return false; + } + } + return (selected.size() == 1); + } + else if (context == PARAMETER_COPYUUID) + { + return (selected.size() == 1) && isSettingSelected(selected.front()); + } + + return false; +} + +bool LLFloaterMyEnvironment::canApply(const std::string &context) +{ + uuid_vec_t selected; + getSelectedIds(selected); + + if (selected.size() != 1) // Exactly one item selected. + return false; + + if (context == PARAMETER_REGION) + { + return LLEnvironment::instance().canAgentUpdateRegionEnvironment(); + } + else if (context == PARAMETER_PARCEL) + { + return LLEnvironment::instance().canAgentUpdateParcelEnvironment(); + } + else + { + return (context == PARAMETER_LOCAL); + } +} + +//------------------------------------------------------------------------- +void LLFloaterMyEnvironment::refreshButtonStates() +{ + bool settings_ok = LLEnvironment::instance().isInventoryEnabled(); + + uuid_vec_t selected; + getSelectedIds(selected); + + getChild<LLUICtrl>(BUTTON_GEAR)->setEnabled(settings_ok); + getChild<LLUICtrl>(BUTTON_NEWSETTINGS)->setEnabled(true); + getChild<LLUICtrl>(BUTTON_DELETE)->setEnabled(settings_ok && !selected.empty()); +} + +//------------------------------------------------------------------------- +LLUUID LLFloaterMyEnvironment::findItemByAssetId(LLUUID asset_id, bool copyable_only, bool ignore_library) +{ + /*TODO: Rider: Move this to gInventory? */ + + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(asset_id); + + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + + if (!items.empty()) + { + // search for copyable version first + for (auto & item : items) + { + const LLPermissions& item_permissions = item->getPermissions(); + if (item_permissions.allowCopyBy(gAgent.getID(), gAgent.getGroupID())) + { + if(!ignore_library || !gInventory.isObjectDescendentOf(item->getUUID(),gInventory.getLibraryRootFolderID())) + { + return item->getUUID(); + } + } + } + // otherwise just return first instance, unless copyable requested + if (copyable_only) + { + return LLUUID::null; + } + else + { + if(!ignore_library || !gInventory.isObjectDescendentOf(items[0]->getUUID(),gInventory.getLibraryRootFolderID())) + { + return items[0]->getUUID(); + } + } + } + + return LLUUID::null; +} + +bool LLFloaterMyEnvironment::isSettingSelected(LLUUID item_id) +{ + LLInventoryItem* itemp = gInventory.getItem(item_id); + + if (itemp && itemp->getInventoryType() == LLInventoryType::IT_SETTINGS) + { + return true; + } + return false; +} + +void LLFloaterMyEnvironment::getSelectedIds(uuid_vec_t& ids) const +{ + LLInventoryPanel::selected_items_t items = mInventoryList->getSelectedItems(); + + for (auto itemview : items) + { + LLFolderViewModelItemInventory* itemp = static_cast<LLFolderViewModelItemInventory*>(itemview->getViewModelItem()); + ids.push_back(itemp->getUUID()); + } +} diff --git a/indra/newview/llfloatermyenvironment.h b/indra/newview/llfloatermyenvironment.h new file mode 100644 index 0000000000..fea0981590 --- /dev/null +++ b/indra/newview/llfloatermyenvironment.h @@ -0,0 +1,78 @@ +/** + * @file llfloatermyenvironment.h + * @brief LLFloaterMyEnvironment class header file + * + * $LicenseInfo:firstyear=2002&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_LLFLOATERMYENVIRONMENT_H +#define LL_LLFLOATERMYENVIRONMENT_H +#include <vector> + +#include "llfloater.h" +#include "llinventoryobserver.h" +#include "llinventoryfilter.h" +#include "llfiltereditor.h" + +class LLInventoryPanel; + +class LLFloaterMyEnvironment +: public LLFloater, LLInventoryFetchDescendentsObserver +{ + LOG_CLASS(LLFloaterMyEnvironment); +public: + LLFloaterMyEnvironment(const LLSD& key); + virtual ~LLFloaterMyEnvironment(); + + virtual BOOL postBuild() override; + virtual void refresh() override; + + virtual void onOpen(const LLSD& key) override; + +private: + LLInventoryPanel * mInventoryList; + LLFilterEditor * mFilterEdit; + U64 mTypeFilter; + LLInventoryFilter::EFolderShow mShowFolders; + LLUUID mSelectedAsset; + LLSaveFolderState mSavedFolderState; + + void onShowFoldersChange(); + void onFilterCheckChange(); + void onFilterEdit(const std::string& search_string); + void onSelectionChange(); + void onDeleteSelected(); + void onDoCreate(const LLSD &data); + void onDoApply(const std::string &context); + bool canAction(const std::string &context); + bool canApply(const std::string &context); + + void getSelectedIds(uuid_vec_t& ids) const; + void refreshButtonStates(); + + bool isSettingSelected(LLUUID item_id); + + static LLUUID findItemByAssetId(LLUUID asset_id, bool copyable_only, bool ignore_library); +}; + + +#endif diff --git a/indra/newview/llfloaternamedesc.cpp b/indra/newview/llfloaternamedesc.cpp index c9a689281e..1e9549a04e 100644 --- a/indra/newview/llfloaternamedesc.cpp +++ b/indra/newview/llfloaternamedesc.cpp @@ -46,12 +46,13 @@ #include "llnotificationsutil.h" #include "lluictrlfactory.h" #include "llstring.h" -#include "lleconomy.h" #include "llpermissions.h" +#include "lltrans.h" // linden includes #include "llassetstorage.h" #include "llinventorytype.h" +#include "llagentbenefits.h" const S32 PREVIEW_LINE_HEIGHT = 19; const S32 PREVIEW_BORDER_WIDTH = 2; @@ -123,13 +124,39 @@ BOOL LLFloaterNameDesc::postBuild() // Cancel button getChild<LLUICtrl>("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterNameDesc::onBtnCancel, this)); - getChild<LLUICtrl>("ok_btn")->setLabelArg("[AMOUNT]", llformat("%d", LLGlobalEconomy::getInstance()->getPriceUpload() )); + S32 expected_upload_cost = getExpectedUploadCost(); + getChild<LLUICtrl>("ok_btn")->setLabelArg("[AMOUNT]", llformat("%d", expected_upload_cost)); + + LLTextBox* info_text = getChild<LLTextBox>("info_text"); + if (info_text) + { + info_text->setValue(LLTrans::getString("UploadFeeInfo")); + } setDefaultBtn("ok_btn"); return TRUE; } +S32 LLFloaterNameDesc::getExpectedUploadCost() const +{ + std::string exten = gDirUtilp->getExtension(mFilename); + LLAssetType::EType asset_type; + S32 upload_cost = -1; + if (LLResourceUploadInfo::findAssetTypeOfExtension(exten, asset_type)) + { + 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() //----------------------------------------------------------------------------- @@ -161,15 +188,14 @@ void LLFloaterNameDesc::onBtnOK( ) { getChildView("ok_btn")->setEnabled(FALSE); // don't allow inadvertent extra uploads - LLAssetStorage::LLStoreAssetCallback callback = NULL; - S32 expected_upload_cost = LLGlobalEconomy::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). - + LLAssetStorage::LLStoreAssetCallback callback; + S32 expected_upload_cost = getExpectedUploadCost(); if (can_afford_transaction(expected_upload_cost)) { void *nruserdata = NULL; std::string display_name = LLStringUtil::null; - LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo( + LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLNewFileResourceUploadInfo>( mFilenameAndPath, getChild<LLUICtrl>("name_form")->getValue().asString(), getChild<LLUICtrl>("description_form")->getValue().asString(), 0, @@ -185,7 +211,7 @@ void LLFloaterNameDesc::onBtnOK( ) { LLSD args; args["COST"] = llformat("%d", expected_upload_cost); - LLNotificationsUtil::add("ErrorTextureCannotAfford", args); + LLNotificationsUtil::add("ErrorCannotAffordUpload", args); } closeFloater(false); diff --git a/indra/newview/llfloaternamedesc.h b/indra/newview/llfloaternamedesc.h index 41643681ac..589f470e82 100644 --- a/indra/newview/llfloaternamedesc.h +++ b/indra/newview/llfloaternamedesc.h @@ -30,6 +30,7 @@ #include "llfloater.h" #include "llresizehandle.h" #include "llstring.h" +#include "llassettype.h" class LLLineEditor; class LLButton; @@ -45,6 +46,8 @@ public: void onBtnOK(); void onBtnCancel(); void doCommit(); + + S32 getExpectedUploadCost() const; protected: virtual void onCommit(); diff --git a/indra/newview/llfloateroutfitsnapshot.cpp b/indra/newview/llfloateroutfitsnapshot.cpp index bfcd1b8b47..dccef88e41 100644 --- a/indra/newview/llfloateroutfitsnapshot.cpp +++ b/indra/newview/llfloateroutfitsnapshot.cpp @@ -31,8 +31,6 @@ #include "llagent.h" #include "llfloaterreg.h" -#include "llfloaterflickr.h" -#include "llfloatertwitter.h" #include "llimagefiltersmanager.h" #include "llcheckboxctrl.h" #include "llcombobox.h" diff --git a/indra/newview/llfloaterperms.cpp b/indra/newview/llfloaterperms.cpp index 2281ea1496..649a107d74 100644 --- a/indra/newview/llfloaterperms.cpp +++ b/indra/newview/llfloaterperms.cpp @@ -121,7 +121,8 @@ const std::string LLFloaterPermsDefault::sCategoryNames[CAT_LAST] = "Scripts", "Notecards", "Gestures", - "Wearables" + "Wearables", + "Settings" }; BOOL LLFloaterPermsDefault::postBuild() @@ -177,7 +178,6 @@ void LLFloaterPermsDefault::sendInitialPerms() if(!mCapSent) { updateCap(); - setCapSent(true); } } @@ -239,7 +239,7 @@ void LLFloaterPermsDefault::updateCapCoro(std::string url) { const std::string& reason = status.toString(); // Do not display the same error more than once in a row - if (reason != previousReason) + if ((reason != previousReason) && mCapSent) { previousReason = reason; LLSD args; diff --git a/indra/newview/llfloaterperms.h b/indra/newview/llfloaterperms.h index e866b6de7d..02359a256e 100644 --- a/indra/newview/llfloaterperms.h +++ b/indra/newview/llfloaterperms.h @@ -74,6 +74,7 @@ enum Categories CAT_NOTECARDS, CAT_GESTURES, CAT_WEARABLES, + CAT_SETTINGS, CAT_LAST }; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 64961fc99c..6bf2136f60 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -71,8 +71,9 @@ #include "lltrans.h" #include "llviewercontrol.h" #include "llviewercamera.h" -#include "llviewerwindow.h" +#include "llviewereventrecorder.h" #include "llviewermessage.h" +#include "llviewerwindow.h" #include "llviewershadermgr.h" #include "llviewerthrottle.h" #include "llvoavatarself.h" @@ -124,7 +125,9 @@ char const* const VISIBILITY_DEFAULT = "default"; char const* const VISIBILITY_HIDDEN = "hidden"; //control value for middle mouse as talk2push button -const static std::string MIDDLE_MOUSE_CV = "MiddleMouse"; +const static std::string MIDDLE_MOUSE_CV = "MiddleMouse"; // for voice client and redability +const static std::string MOUSE_BUTTON_4_CV = "MouseButton4"; +const static std::string MOUSE_BUTTON_5_CV = "MouseButton5"; /// This must equal the maximum value set for the IndirectMaxComplexity slider in panel_preferences_graphics1.xml static const U32 INDIRECT_MAX_ARC_OFF = 101; // all the way to the right == disabled @@ -157,67 +160,6 @@ struct LabelTable : public LLInitParam::Block<LabelTable> {} }; -class LLVoiceSetKeyDialog : public LLModalDialog -{ -public: - LLVoiceSetKeyDialog(const LLSD& key); - ~LLVoiceSetKeyDialog(); - - /*virtual*/ BOOL postBuild(); - - void setParent(LLFloaterPreference* parent) { mParent = parent; } - - BOOL handleKeyHere(KEY key, MASK mask); - static void onCancel(void* user_data); - -private: - LLFloaterPreference* mParent; -}; - -LLVoiceSetKeyDialog::LLVoiceSetKeyDialog(const LLSD& key) - : LLModalDialog(key), - mParent(NULL) -{ -} - -//virtual -BOOL LLVoiceSetKeyDialog::postBuild() -{ - childSetAction("Cancel", onCancel, this); - getChild<LLUICtrl>("Cancel")->setFocus(TRUE); - - gFocusMgr.setKeystrokesOnly(TRUE); - - return TRUE; -} - -LLVoiceSetKeyDialog::~LLVoiceSetKeyDialog() -{ -} - -BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask) -{ - BOOL result = TRUE; - - if (key == 'Q' && mask == MASK_CONTROL) - { - result = FALSE; - } - else if (mParent) - { - mParent->setKey(key); - } - closeFloater(); - return result; -} - -//static -void LLVoiceSetKeyDialog::onCancel(void* user_data) -{ - LLVoiceSetKeyDialog* self = (LLVoiceSetKeyDialog*)user_data; - self->closeFloater(); -} - // global functions @@ -254,8 +196,8 @@ bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response if ( option == 0 ) // YES { // clean web - LLViewerMedia::clearAllCaches(); - LLViewerMedia::clearAllCookies(); + LLViewerMedia::getInstance()->clearAllCaches(); + LLViewerMedia::getInstance()->clearAllCookies(); // clean nav bar history LLNavigationBar::getInstance()->clearHistoryCache(); @@ -278,13 +220,13 @@ bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response void handleNameTagOptionChanged(const LLSD& newvalue) { - LLAvatarNameCache::setUseUsernames(gSavedSettings.getBOOL("NameTagShowUsernames")); + LLAvatarNameCache::getInstance()->setUseUsernames(gSavedSettings.getBOOL("NameTagShowUsernames")); LLVOAvatar::invalidateNameTags(); } void handleDisplayNamesOptionChanged(const LLSD& newvalue) { - LLAvatarNameCache::setUseDisplayNames(newvalue.asBoolean()); + LLAvatarNameCache::getInstance()->setUseDisplayNames(newvalue.asBoolean()); LLVOAvatar::invalidateNameTags(); } @@ -297,37 +239,6 @@ void handleAppearanceCameraMovementChanged(const LLSD& newvalue) } } -/*bool callback_skip_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option && floater ) - { - if ( floater ) - { - floater->setAllIgnored(); - // LLFirstUse::disableFirstUse(); - floater->buildPopupLists(); - } - } - return false; -} - -bool callback_reset_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if ( 0 == option && floater ) - { - if ( floater ) - { - floater->resetAllIgnored(); - //LLFirstUse::resetFirstUse(); - floater->buildPopupLists(); - } - } - return false; -} -*/ - void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator) { numerator = 0; @@ -352,8 +263,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mGotPersonalInfo(false), mOriginalIMViaEmail(false), mLanguageChanged(false), - mAvatarDataInitialized(false), - mClickActionDirty(false) + mAvatarDataInitialized(false) { LLConversationLog::instance().addObserver(this); @@ -362,7 +272,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) static bool registered_dialog = false; if (!registered_dialog) { - LLFloaterReg::add("voice_set_key", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLVoiceSetKeyDialog>); + LLFloaterReg::add("keybind_dialog", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLSetKeyBindDialog>); registered_dialog = true; } @@ -375,8 +285,6 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.ResetCache", boost::bind(&LLFloaterPreference::onClickResetCache, this)); mCommitCallbackRegistrar.add("Pref.ClickSkin", boost::bind(&LLFloaterPreference::onClickSkin, this,_1, _2)); mCommitCallbackRegistrar.add("Pref.SelectSkin", boost::bind(&LLFloaterPreference::onSelectSkin, this)); - mCommitCallbackRegistrar.add("Pref.VoiceSetKey", boost::bind(&LLFloaterPreference::onClickSetKey, this)); - mCommitCallbackRegistrar.add("Pref.VoiceSetMiddleMouse", boost::bind(&LLFloaterPreference::onClickSetMiddleMouse, this)); mCommitCallbackRegistrar.add("Pref.SetSounds", boost::bind(&LLFloaterPreference::onClickSetSounds, this)); mCommitCallbackRegistrar.add("Pref.ClickEnablePopup", boost::bind(&LLFloaterPreference::onClickEnablePopup, this)); mCommitCallbackRegistrar.add("Pref.ClickDisablePopup", boost::bind(&LLFloaterPreference::onClickDisablePopup, this)); @@ -385,7 +293,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.HardwareDefaults", boost::bind(&LLFloaterPreference::setHardwareDefaults, this)); mCommitCallbackRegistrar.add("Pref.AvatarImpostorsEnable", boost::bind(&LLFloaterPreference::onAvatarImpostorsEnable, this)); mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreference::updateMaxComplexity, this)); - mCommitCallbackRegistrar.add("Pref.VertexShaderEnable", boost::bind(&LLFloaterPreference::onVertexShaderEnable, this)); + mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", boost::bind(&LLFloaterPreference::onRenderOptionEnable, this)); mCommitCallbackRegistrar.add("Pref.WindowedMod", boost::bind(&LLFloaterPreference::onCommitWindowedMode, this)); mCommitCallbackRegistrar.add("Pref.UpdateSliderText", boost::bind(&LLFloaterPreference::refreshUI,this)); mCommitCallbackRegistrar.add("Pref.QualityPerformance", boost::bind(&LLFloaterPreference::onChangeQuality, this, _2)); @@ -397,6 +305,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.TranslationSettings", boost::bind(&LLFloaterPreference::onClickTranslationSettings, this)); mCommitCallbackRegistrar.add("Pref.AutoReplace", boost::bind(&LLFloaterPreference::onClickAutoReplace, this)); mCommitCallbackRegistrar.add("Pref.PermsDefault", boost::bind(&LLFloaterPreference::onClickPermsDefault, this)); + mCommitCallbackRegistrar.add("Pref.RememberedUsernames", boost::bind(&LLFloaterPreference::onClickRememberedUsernames, this)); mCommitCallbackRegistrar.add("Pref.SpellChecker", boost::bind(&LLFloaterPreference::onClickSpellChecker, this)); mCommitCallbackRegistrar.add("Pref.Advanced", boost::bind(&LLFloaterPreference::onClickAdvanced, this)); @@ -523,7 +432,7 @@ BOOL LLFloaterPreference::postBuild() // set 'enable' property for 'Clear log...' button changed(); - LLLogChat::setSaveHistorySignal(boost::bind(&LLFloaterPreference::onLogChatHistorySaved, this)); + LLLogChat::getInstance()->setSaveHistorySignal(boost::bind(&LLFloaterPreference::onLogChatHistorySaved, this)); LLSliderCtrl* fov_slider = getChild<LLSliderCtrl>("camera_fov"); fov_slider->setMinValue(LLViewerCamera::getInstance()->getMinView()); @@ -635,14 +544,14 @@ void LLFloaterPreference::apply() std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); setCacheLocation(cache_location); - LLViewerMedia::setCookiesEnabled(getChild<LLUICtrl>("cookies_enabled")->getValue()); + LLViewerMedia::getInstance()->setCookiesEnabled(getChild<LLUICtrl>("cookies_enabled")->getValue()); if (hasChild("web_proxy_enabled", TRUE) &&hasChild("web_proxy_editor", TRUE) && hasChild("web_proxy_port", TRUE)) { bool proxy_enable = getChild<LLUICtrl>("web_proxy_enabled")->getValue(); std::string proxy_address = getChild<LLUICtrl>("web_proxy_editor")->getValue(); int proxy_port = getChild<LLUICtrl>("web_proxy_port")->getValue(); - LLViewerMedia::setProxyConfig(proxy_enable, proxy_address, proxy_port); + LLViewerMedia::getInstance()->setProxyConfig(proxy_enable, proxy_address, proxy_port); } if (mGotPersonalInfo) @@ -670,12 +579,6 @@ void LLFloaterPreference::apply() } saveAvatarProperties(); - - if (mClickActionDirty) - { - updateClickActionSettings(); - mClickActionDirty = false; - } } void LLFloaterPreference::cancel() @@ -702,17 +605,13 @@ void LLFloaterPreference::cancel() // hide spellchecker settings folder LLFloaterReg::hideInstance("prefs_spellchecker"); - // hide advancede floater + // hide advanced graphics floater LLFloaterReg::hideInstance("prefs_graphics_advanced"); // reverts any changes to current skin gSavedSettings.setString("SkinCurrent", sSkin); - if (mClickActionDirty) - { - updateClickActionControls(); - mClickActionDirty = false; - } + updateClickActionViews(); LLFloaterPreferenceProxy * advanced_proxy_settings = LLFloaterReg::findTypedInstance<LLFloaterPreferenceProxy>("prefs_proxy"); if (advanced_proxy_settings) @@ -797,7 +696,7 @@ void LLFloaterPreference::onOpen(const LLSD& key) onChangeAnimationFolder(); // Load (double-)click to walk/teleport settings. - updateClickActionControls(); + updateClickActionViews(); // Enabled/disabled popups, might have been changed by user actions // while preferences floater was closed. @@ -821,7 +720,8 @@ void LLFloaterPreference::onOpen(const LLSD& key) saveSettings(); // Make sure there is a default preference file - LLPresetsManager::getInstance()->createMissingDefault(); + LLPresetsManager::getInstance()->createMissingDefault(PRESETS_CAMERA); + LLPresetsManager::getInstance()->createMissingDefault(PRESETS_GRAPHIC); bool started = (LLStartUp::getStartupState() == STATE_STARTED); @@ -830,12 +730,15 @@ void LLFloaterPreference::onOpen(const LLSD& key) LLButton* delete_btn = findChild<LLButton>("PrefDeleteButton"); LLButton* exceptions_btn = findChild<LLButton>("RenderExceptionsButton"); - load_btn->setEnabled(started); - save_btn->setEnabled(started); - delete_btn->setEnabled(started); - exceptions_btn->setEnabled(started); + if (load_btn && save_btn && delete_btn && exceptions_btn) + { + load_btn->setEnabled(started); + save_btn->setEnabled(started); + delete_btn->setEnabled(started); + exceptions_btn->setEnabled(started); + } - collectSearchableItems(); + collectSearchableItems(); if (!mFilterEdit->getText().empty()) { mFilterEdit->setText(LLStringExplicit("")); @@ -843,12 +746,23 @@ void LLFloaterPreference::onOpen(const LLSD& key) } } -void LLFloaterPreference::onVertexShaderEnable() +void LLFloaterPreference::onRenderOptionEnable() +{ + refreshEnabledGraphics(); +} + +void LLFloaterPreferenceGraphicsAdvanced::onRenderOptionEnable() { + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->refresh(); + } + refreshEnabledGraphics(); } -void LLFloaterPreferenceGraphicsAdvanced::onVertexShaderEnable() +void LLFloaterPreferenceGraphicsAdvanced::onAdvancedAtmosphericsEnable() { LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); if (instance) @@ -1056,6 +970,7 @@ void LLFloaterPreference::onBtnCancel(const LLSD& userdata) if (userdata.asString() == "closeadvanced") { LLFloaterReg::hideInstance("prefs_graphics_advanced"); + updateMaxComplexity(); } else { @@ -1219,7 +1134,7 @@ void LLFloaterPreference::buildPopupLists() LLNotificationFormPtr formp = templatep->mForm; LLNotificationForm::EIgnoreType ignore = formp->getIgnoreType(); - if (ignore == LLNotificationForm::IGNORE_NO) + if (ignore <= LLNotificationForm::IGNORE_NO) continue; LLSD row; @@ -1234,7 +1149,7 @@ void LLFloaterPreference::buildPopupLists() { if (ignore == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) { - LLSD last_response = LLUI::sSettingGroups["config"]->getLLSD("Default" + templatep->mName); + LLSD last_response = LLUI::getInstance()->mSettingGroups["config"]->getLLSD("Default" + templatep->mName); if (!last_response.isUndefined()) { for (LLSD::map_const_iterator it = last_response.beginMap(); @@ -1244,12 +1159,12 @@ void LLFloaterPreference::buildPopupLists() if (it->second.asBoolean()) { row["columns"][1]["value"] = formp->getElement(it->first)["ignore"].asString(); + row["columns"][1]["font"] = "SANSSERIF_SMALL"; + row["columns"][1]["width"] = 360; break; } } } - row["columns"][1]["font"] = "SANSSERIF_SMALL"; - row["columns"][1]["width"] = 360; } item = disabled_popups.addElement(row); } @@ -1271,22 +1186,23 @@ void LLFloaterPreference::refreshEnabledState() LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders"); // if vertex shaders off, disable all shader related products - if (!LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable") || - !LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders")) + if (!LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders")) { ctrl_wind_light->setEnabled(FALSE); ctrl_wind_light->setValue(FALSE); } else { - ctrl_wind_light->setEnabled(gSavedSettings.getBOOL("VertexShaderEnable")); + ctrl_wind_light->setEnabled(TRUE); } //Deferred/SSAO/Shadows BOOL bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump") && gSavedSettings.getBOOL("RenderObjectBump"); - BOOL shaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders") && gSavedSettings.getBOOL("VertexShaderEnable"); + BOOL transparent_water = LLFeatureManager::getInstance()->isFeatureAvailable("RenderTransparentWater") && gSavedSettings.getBOOL("RenderTransparentWater"); + BOOL shaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders"); BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && bumpshiny && + transparent_water && shaders && gGLManager.mHasFramebufferObject && gSavedSettings.getBOOL("RenderAvatarVP") && @@ -1306,12 +1222,13 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() LLTextBox* reflections_text = getChild<LLTextBox>("ReflectionsText"); // Reflections - BOOL reflections = gSavedSettings.getBOOL("VertexShaderEnable") - && gGLManager.mHasCubeMap - && LLCubeMap::sUseCubeMaps; + BOOL reflections = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps; ctrl_reflections->setEnabled(reflections); reflections_text->setEnabled(reflections); - + + // Transparent Water + LLCheckBoxCtrl* transparent_water_ctrl = getChild<LLCheckBoxCtrl>("TransparentWater"); + // Bump & Shiny LLCheckBoxCtrl* bumpshiny_ctrl = getChild<LLCheckBoxCtrl>("BumpShiny"); bool bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump"); @@ -1332,59 +1249,42 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() ctrl_avatar_vp->setEnabled(avatar_vp_enabled); - if (gSavedSettings.getBOOL("VertexShaderEnable") == FALSE || - gSavedSettings.getBOOL("RenderAvatarVP") == FALSE) - { - ctrl_avatar_cloth->setEnabled(FALSE); - } - else - { - ctrl_avatar_cloth->setEnabled(TRUE); - } - - // Vertex Shaders - // Global Shader Enable - LLCheckBoxCtrl* ctrl_shader_enable = getChild<LLCheckBoxCtrl>("BasicShaders"); - LLSliderCtrl* terrain_detail = getChild<LLSliderCtrl>("TerrainDetail"); // can be linked with control var - LLTextBox* terrain_text = getChild<LLTextBox>("TerrainDetailText"); + if (gSavedSettings.getBOOL("RenderAvatarVP") == FALSE) + { + ctrl_avatar_cloth->setEnabled(FALSE); + } + else + { + ctrl_avatar_cloth->setEnabled(TRUE); + } - ctrl_shader_enable->setEnabled(LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable")); - - BOOL shaders = ctrl_shader_enable->get(); - if (shaders) - { - terrain_detail->setEnabled(FALSE); - terrain_text->setEnabled(FALSE); - } - else - { - terrain_detail->setEnabled(TRUE); - terrain_text->setEnabled(TRUE); - } - - // WindLight - LLCheckBoxCtrl* ctrl_wind_light = getChild<LLCheckBoxCtrl>("WindLightUseAtmosShaders"); - LLSliderCtrl* sky = getChild<LLSliderCtrl>("SkyMeshDetail"); - LLTextBox* sky_text = getChild<LLTextBox>("SkyMeshDetailText"); + // Vertex Shaders, Global Shader Enable + // SL-12594 Basic shaders are always enabled. DJH TODO clean up now-orphaned state handling code + LLSliderCtrl* terrain_detail = getChild<LLSliderCtrl>("TerrainDetail"); // can be linked with control var + LLTextBox* terrain_text = getChild<LLTextBox>("TerrainDetailText"); - // *HACK just checks to see if we can use shaders... - // maybe some cards that use shaders, but don't support windlight - ctrl_wind_light->setEnabled(ctrl_shader_enable->getEnabled() && shaders); + terrain_detail->setEnabled(FALSE); + terrain_text->setEnabled(FALSE); - sky->setEnabled(ctrl_wind_light->get() && shaders); - sky_text->setEnabled(ctrl_wind_light->get() && shaders); + // WindLight + LLCheckBoxCtrl* ctrl_wind_light = getChild<LLCheckBoxCtrl>("WindLightUseAtmosShaders"); + LLSliderCtrl* sky = getChild<LLSliderCtrl>("SkyMeshDetail"); + LLTextBox* sky_text = getChild<LLTextBox>("SkyMeshDetailText"); + ctrl_wind_light->setEnabled(TRUE); + sky->setEnabled(TRUE); + sky_text->setEnabled(TRUE); - //Deferred/SSAO/Shadows - LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders"); - - BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && - ((bumpshiny_ctrl && bumpshiny_ctrl->get()) ? TRUE : FALSE) && - shaders && - gGLManager.mHasFramebufferObject && - gSavedSettings.getBOOL("RenderAvatarVP") && - (ctrl_wind_light->get()) ? TRUE : FALSE; + //Deferred/SSAO/Shadows + LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders"); + + BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && + ((bumpshiny_ctrl && bumpshiny_ctrl->get()) ? TRUE : FALSE) && + ((transparent_water_ctrl && transparent_water_ctrl->get()) ? TRUE : FALSE) && + gGLManager.mHasFramebufferObject && + gSavedSettings.getBOOL("RenderAvatarVP") && + (ctrl_wind_light->get()) ? TRUE : FALSE; - ctrl_deferred->setEnabled(enabled); + ctrl_deferred->setEnabled(enabled); LLCheckBoxCtrl* ctrl_ssao = getChild<LLCheckBoxCtrl>("UseSSAO"); LLCheckBoxCtrl* ctrl_dof = getChild<LLCheckBoxCtrl>("UseDoF"); @@ -1455,7 +1355,7 @@ void LLAvatarComplexityControls::setIndirectMaxNonImpostors() { U32 max_non_impostors = gSavedSettings.getU32("RenderAvatarMaxNonImpostors"); // for this one, we just need to make zero, which means off, the max value of the slider - U32 indirect_max_non_impostors = (0 == max_non_impostors) ? LLVOAvatar::IMPOSTORS_OFF : max_non_impostors; + U32 indirect_max_non_impostors = (0 == max_non_impostors) ? LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER : max_non_impostors; gSavedSettings.setU32("IndirectMaxNonImpostors", indirect_max_non_impostors); } @@ -1482,7 +1382,6 @@ void LLFloaterPreferenceGraphicsAdvanced::disableUnavailableSettings() LLTextBox* reflections_text = getChild<LLTextBox>("ReflectionsText"); LLCheckBoxCtrl* ctrl_avatar_vp = getChild<LLCheckBoxCtrl>("AvatarVertexProgram"); LLCheckBoxCtrl* ctrl_avatar_cloth = getChild<LLCheckBoxCtrl>("AvatarCloth"); - LLCheckBoxCtrl* ctrl_shader_enable = getChild<LLCheckBoxCtrl>("BasicShaders"); LLCheckBoxCtrl* ctrl_wind_light = getChild<LLCheckBoxCtrl>("WindLightUseAtmosShaders"); LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders"); LLComboBox* ctrl_shadows = getChild<LLComboBox>("ShadowDetail"); @@ -1492,42 +1391,6 @@ void LLFloaterPreferenceGraphicsAdvanced::disableUnavailableSettings() LLSliderCtrl* sky = getChild<LLSliderCtrl>("SkyMeshDetail"); LLTextBox* sky_text = getChild<LLTextBox>("SkyMeshDetailText"); - // if vertex shaders off, disable all shader related products - if (!LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable")) - { - ctrl_shader_enable->setEnabled(FALSE); - ctrl_shader_enable->setValue(FALSE); - - ctrl_wind_light->setEnabled(FALSE); - ctrl_wind_light->setValue(FALSE); - - sky->setEnabled(FALSE); - sky_text->setEnabled(FALSE); - - ctrl_reflections->setEnabled(FALSE); - ctrl_reflections->setValue(0); - reflections_text->setEnabled(FALSE); - - ctrl_avatar_vp->setEnabled(FALSE); - ctrl_avatar_vp->setValue(FALSE); - - ctrl_avatar_cloth->setEnabled(FALSE); - ctrl_avatar_cloth->setValue(FALSE); - - ctrl_shadows->setEnabled(FALSE); - ctrl_shadows->setValue(0); - shadows_text->setEnabled(FALSE); - - ctrl_ssao->setEnabled(FALSE); - ctrl_ssao->setValue(FALSE); - - ctrl_dof->setEnabled(FALSE); - ctrl_dof->setValue(FALSE); - - ctrl_deferred->setEnabled(FALSE); - ctrl_deferred->setValue(FALSE); - } - // disabled windlight if (!LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders")) { @@ -1637,6 +1500,7 @@ void LLFloaterPreference::refresh() { advanced->refresh(); } + updateClickActionViews(); } void LLFloaterPreferenceGraphicsAdvanced::refresh() @@ -1678,37 +1542,6 @@ void LLFloaterPreference::onChangeQuality(const LLSD& data) refresh(); } -void LLFloaterPreference::onClickSetKey() -{ - LLVoiceSetKeyDialog* dialog = LLFloaterReg::showTypedInstance<LLVoiceSetKeyDialog>("voice_set_key", LLSD(), TRUE); - if (dialog) - { - dialog->setParent(this); - } -} - -void LLFloaterPreference::setKey(KEY key) -{ - getChild<LLUICtrl>("modifier_combo")->setValue(LLKeyboard::stringFromKey(key)); - // update the control right away since we no longer wait for apply - getChild<LLUICtrl>("modifier_combo")->onCommit(); -} - -void LLFloaterPreference::onClickSetMiddleMouse() -{ - LLUICtrl* p2t_line_editor = getChild<LLUICtrl>("modifier_combo"); - - // update the control right away since we no longer wait for apply - p2t_line_editor->setControlValue(MIDDLE_MOUSE_CV); - - //push2talk button "middle mouse" control value is in English, need to localize it for presentation - LLPanel* advanced_preferences = dynamic_cast<LLPanel*>(p2t_line_editor->getParent()); - if (advanced_preferences) - { - p2t_line_editor->setValue(advanced_preferences->getString("middle_mouse")); - } -} - void LLFloaterPreference::onClickSetSounds() { // Disable Enable gesture sounds checkbox if the master sound is disabled @@ -1716,18 +1549,6 @@ void LLFloaterPreference::onClickSetSounds() getChild<LLCheckBoxCtrl>("gesture_audio_play_btn")->setEnabled(!gSavedSettings.getBOOL("MuteSounds")); } -/* -void LLFloaterPreference::onClickSkipDialogs() -{ - LLNotificationsUtil::add("SkipShowNextTimeDialogs", LLSD(), LLSD(), boost::bind(&callback_skip_dialogs, _1, _2, this)); -} - -void LLFloaterPreference::onClickResetDialogs() -{ - LLNotificationsUtil::add("ResetShowNextTimeDialogs", LLSD(), LLSD(), boost::bind(&callback_reset_dialogs, _1, _2, this)); -} - */ - void LLFloaterPreference::onClickEnablePopup() { LLScrollListCtrl& disabled_popups = getChildRef<LLScrollListCtrl>("disabled_popups"); @@ -1739,7 +1560,7 @@ void LLFloaterPreference::onClickEnablePopup() LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate(*(std::string*)((*itor)->getUserdata())); //gSavedSettings.setWarning(templatep->mName, TRUE); std::string notification_name = templatep->mName; - LLUI::sSettingGroups["ignores"]->setBOOL(notification_name, TRUE); + LLUI::getInstance()->mSettingGroups["ignores"]->setBOOL(notification_name, TRUE); } buildPopupLists(); @@ -1766,7 +1587,7 @@ void LLFloaterPreference::resetAllIgnored() iter != LLNotifications::instance().templatesEnd(); ++iter) { - if (iter->second->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) + if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) { iter->second->mForm->setIgnored(false); } @@ -1779,7 +1600,7 @@ void LLFloaterPreference::setAllIgnored() iter != LLNotifications::instance().templatesEnd(); ++iter) { - if (iter->second->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) + if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) { iter->second->mForm->setIgnored(true); } @@ -1911,6 +1732,8 @@ void LLFloaterPreference::setPersonalInfo(const std::string& visibility, bool im getChildView("log_path_button")->setEnabled(TRUE); getChildView("chat_font_size")->setEnabled(TRUE); getChildView("conversation_log_combo")->setEnabled(TRUE); + getChild<LLUICtrl>("voice_call_friends_only_check")->setEnabled(TRUE); + getChild<LLUICtrl>("voice_call_friends_only_check")->setValue(gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly")); } @@ -1955,7 +1778,7 @@ void LLFloaterPreferenceGraphicsAdvanced::updateMaxNonImpostors() LLSliderCtrl* ctrl = getChild<LLSliderCtrl>("IndirectMaxNonImpostors",true); U32 value = ctrl->getValue().asInteger(); - if (0 == value || LLVOAvatar::IMPOSTORS_OFF <= value) + if (0 == value || LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER <= value) { value=0; } @@ -2019,6 +1842,14 @@ void LLFloaterPreference::updateMaxComplexity() LLAvatarComplexityControls::updateMax( getChild<LLSliderCtrl>("IndirectMaxComplexity"), getChild<LLTextBox>("IndirectMaxComplexityText")); + + LLFloaterPreferenceGraphicsAdvanced* floater_graphics_advanced = LLFloaterReg::findTypedInstance<LLFloaterPreferenceGraphicsAdvanced>("prefs_graphics_advanced"); + if (floater_graphics_advanced) + { + LLAvatarComplexityControls::updateMax( + floater_graphics_advanced->getChild<LLSliderCtrl>("IndirectMaxComplexity"), + floater_graphics_advanced->getChild<LLTextBox>("IndirectMaxComplexityText")); + } } bool LLFloaterPreference::loadFromFilename(const std::string& filename, std::map<std::string, std::string> &label_map) @@ -2066,6 +1897,14 @@ void LLFloaterPreferenceGraphicsAdvanced::updateMaxComplexity() LLAvatarComplexityControls::updateMax( getChild<LLSliderCtrl>("IndirectMaxComplexity"), getChild<LLTextBox>("IndirectMaxComplexityText")); + + LLFloaterPreference* floater_preferences = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (floater_preferences) + { + LLAvatarComplexityControls::updateMax( + floater_preferences->getChild<LLSliderCtrl>("IndirectMaxComplexity"), + floater_preferences->getChild<LLTextBox>("IndirectMaxComplexityText")); + } } void LLFloaterPreference::onChangeMaturity() @@ -2191,7 +2030,7 @@ void LLFloaterPreference::onClickAdvanced() void LLFloaterPreference::onClickActionChange() { - mClickActionDirty = true; + updateClickActionControls(); } void LLFloaterPreference::onClickPermsDefault() @@ -2199,6 +2038,11 @@ void LLFloaterPreference::onClickPermsDefault() LLFloaterReg::showInstance("perms_default"); } +void LLFloaterPreference::onClickRememberedUsernames() +{ + LLFloaterReg::showInstance("forget_username"); +} + void LLFloaterPreference::onDeleteTranscripts() { LLSD args; @@ -2226,21 +2070,81 @@ void LLFloaterPreference::onLogChatHistorySaved() } } -void LLFloaterPreference::updateClickActionSettings() +void LLFloaterPreference::updateClickActionControls() { - const int single_clk_action = getChild<LLComboBox>("single_click_action_combo")->getValue().asInteger(); - const int double_clk_action = getChild<LLComboBox>("double_click_action_combo")->getValue().asInteger(); - - gSavedSettings.setBOOL("ClickToWalk", single_clk_action == 1); - gSavedSettings.setBOOL("DoubleClickAutoPilot", double_clk_action == 1); - gSavedSettings.setBOOL("DoubleClickTeleport", double_clk_action == 2); + const int single_clk_action = getChild<LLComboBox>("single_click_action_combo")->getValue().asInteger(); + const int double_clk_action = getChild<LLComboBox>("double_click_action_combo")->getValue().asInteger(); + + // Todo: This is a very ugly way to get access to keybindings. + // Reconsider possible options. + // Potential option: make constructor of LLKeyConflictHandler private + // but add a getter that will return shared pointer for specific + // mode, pointer should only exist so long as there are external users. + // In such case we won't need to do this 'dynamic_cast' nightmare. + // updateTable() can also be avoided + LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core"); + for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); + iter != tabcontainer->getChildList()->end(); ++iter) + { + LLView* view = *iter; + LLPanelPreferenceControls* panel = dynamic_cast<LLPanelPreferenceControls*>(view); + if (panel) + { + panel->setKeyBind("walk_to", + EMouseClickType::CLICK_LEFT, + KEY_NONE, + MASK_NONE, + single_clk_action == 1); + + panel->setKeyBind("walk_to", + EMouseClickType::CLICK_DOUBLELEFT, + KEY_NONE, + MASK_NONE, + double_clk_action == 1); + + panel->setKeyBind("teleport_to", + EMouseClickType::CLICK_DOUBLELEFT, + KEY_NONE, + MASK_NONE, + double_clk_action == 2); + + panel->updateAndApply(); + } + } } -void LLFloaterPreference::updateClickActionControls() +void LLFloaterPreference::updateClickActionViews() { - const bool click_to_walk = gSavedSettings.getBOOL("ClickToWalk"); - const bool dbl_click_to_walk = gSavedSettings.getBOOL("DoubleClickAutoPilot"); - const bool dbl_click_to_teleport = gSavedSettings.getBOOL("DoubleClickTeleport"); + bool click_to_walk = false; + bool dbl_click_to_walk = false; + bool dbl_click_to_teleport = false; + + // Todo: This is a very ugly way to get access to keybindings. + // Reconsider possible options. + LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core"); + for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); + iter != tabcontainer->getChildList()->end(); ++iter) + { + LLView* view = *iter; + LLPanelPreferenceControls* panel = dynamic_cast<LLPanelPreferenceControls*>(view); + if (panel) + { + click_to_walk = panel->canKeyBindHandle("walk_to", + EMouseClickType::CLICK_LEFT, + KEY_NONE, + MASK_NONE); + + dbl_click_to_walk = panel->canKeyBindHandle("walk_to", + EMouseClickType::CLICK_DOUBLELEFT, + KEY_NONE, + MASK_NONE); + + dbl_click_to_teleport = panel->canKeyBindHandle("teleport_to", + EMouseClickType::CLICK_DOUBLELEFT, + KEY_NONE, + MASK_NONE); + } + } getChild<LLComboBox>("single_click_action_combo")->setValue((int)click_to_walk); getChild<LLComboBox>("double_click_action_combo")->setValue(dbl_click_to_teleport ? 2 : (int)dbl_click_to_walk); @@ -2427,16 +2331,6 @@ BOOL LLPanelPreference::postBuild() getChild<LLTextBox>("mute_chb_label")->setClickedCallback(boost::bind(&toggleMuteWhenMinimized)); } - //////////////////////PanelAdvanced /////////////////// - if (hasChild("modifier_combo", TRUE)) - { - //localizing if push2talk button is set to middle mouse - if (MIDDLE_MOUSE_CV == getChild<LLUICtrl>("modifier_combo")->getValue().asString()) - { - getChild<LLUICtrl>("modifier_combo")->setValue(getString("middle_mouse")); - } - } - //////////////////////PanelSetup /////////////////// if (hasChild("max_bandwidth"), TRUE) { @@ -2525,9 +2419,13 @@ void LLPanelPreference::showMultipleViewersWarning(LLUICtrl* checkbox, const LLS void LLPanelPreference::showFriendsOnlyWarning(LLUICtrl* checkbox, const LLSD& value) { - if (checkbox && checkbox->getValue()) + if (checkbox) { - LLNotificationsUtil::add("FriendsAndGroupsOnly"); + gSavedPerAccountSettings.setBOOL("VoiceCallsFriendsOnly", checkbox->getValue().asBoolean()); + if (checkbox->getValue()) + { + LLNotificationsUtil::add("FriendsAndGroupsOnly"); + } } } @@ -2602,26 +2500,23 @@ void LLPanelPreference::updateMediaAutoPlayCheckbox(LLUICtrl* ctrl) bool music_enabled = getChild<LLCheckBoxCtrl>("enable_music")->get(); bool media_enabled = getChild<LLCheckBoxCtrl>("enable_media")->get(); - getChild<LLCheckBoxCtrl>("media_auto_play_btn")->setEnabled(music_enabled || media_enabled); + getChild<LLCheckBoxCtrl>("media_auto_play_combo")->setEnabled(music_enabled || media_enabled); } } void LLPanelPreference::deletePreset(const LLSD& user_data) { - std::string subdirectory = user_data.asString(); - LLFloaterReg::showInstance("delete_pref_preset", subdirectory); + LLFloaterReg::showInstance("delete_pref_preset", user_data.asString()); } void LLPanelPreference::savePreset(const LLSD& user_data) { - std::string subdirectory = user_data.asString(); - LLFloaterReg::showInstance("save_pref_preset", subdirectory); + LLFloaterReg::showInstance("save_pref_preset", user_data.asString()); } void LLPanelPreference::loadPreset(const LLSD& user_data) { - std::string subdirectory = user_data.asString(); - LLFloaterReg::showInstance("load_pref_preset", subdirectory); + LLFloaterReg::showInstance("load_pref_preset", user_data.asString()); } void LLPanelPreference::setHardwareDefaults() @@ -2633,7 +2528,6 @@ class LLPanelPreferencePrivacy : public LLPanelPreference public: LLPanelPreferencePrivacy() { - mAccountIndependentSettings.push_back("VoiceCallsFriendsOnly"); mAccountIndependentSettings.push_back("AutoDisengageMic"); } @@ -2679,7 +2573,7 @@ BOOL LLPanelPreferenceGraphics::postBuild() LLPresetsManager* presetsMgr = LLPresetsManager::getInstance(); presetsMgr->setPresetListChangeCallback(boost::bind(&LLPanelPreferenceGraphics::onPresetsListChange, this)); - presetsMgr->createMissingDefault(); // a no-op after the first time, but that's ok + presetsMgr->createMissingDefault(PRESETS_GRAPHIC); // a no-op after the first time, but that's ok return LLPanelPreference::postBuild(); } @@ -2700,11 +2594,6 @@ void LLPanelPreferenceGraphics::onPresetsListChange() { instance->saveSettings(); //make cancel work correctly after changing the preset } - else - { - std::string dummy; - instance->saveGraphicsPreset(dummy); - } } void LLPanelPreferenceGraphics::setPresetText() @@ -2722,7 +2611,7 @@ void LLPanelPreferenceGraphics::setPresetText() } } - if (hasDirtyChilds() && !preset_graphic_active.empty()) + if (hasDirtyChilds() && !preset_graphic_active.empty()) { gSavedSettings.setString("PresetGraphicActive", ""); preset_graphic_active.clear(); @@ -2842,10 +2731,589 @@ void LLPanelPreferenceGraphics::setHardwareDefaults() resetDirtyChilds(); } +//------------------------LLPanelPreferenceControls-------------------------------- +static LLPanelInjector<LLPanelPreferenceControls> t_pref_contrls("panel_preference_controls"); + +LLPanelPreferenceControls::LLPanelPreferenceControls() + :LLPanelPreference(), + mEditingColumn(-1), + mEditingMode(0) +{ + // MODE_COUNT - 1 because there are currently no settings assigned to 'saved settings'. + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) + { + mConflictHandler[i].setLoadMode((LLKeyConflictHandler::ESourceMode)i); + } +} + +LLPanelPreferenceControls::~LLPanelPreferenceControls() +{ +} + +BOOL LLPanelPreferenceControls::postBuild() +{ + // populate list of controls + pControlsTable = getChild<LLScrollListCtrl>("controls_list"); + pKeyModeBox = getChild<LLComboBox>("key_mode"); + + pControlsTable->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onListCommit, this)); + pKeyModeBox->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onModeCommit, this)); + getChild<LLButton>("restore_defaults")->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onRestoreDefaultsBtn, this)); + + return TRUE; +} + +void LLPanelPreferenceControls::regenerateControls() +{ + mEditingMode = pKeyModeBox->getValue().asInteger(); + mConflictHandler[mEditingMode].loadFromSettings((LLKeyConflictHandler::ESourceMode)mEditingMode); + populateControlTable(); +} + +bool LLPanelPreferenceControls::addControlTableColumns(const std::string &filename) +{ + LLXMLNodePtr xmlNode; + LLScrollListCtrl::Contents contents; + if (!LLUICtrlFactory::getLayeredXMLNode(filename, xmlNode)) + { + LL_WARNS() << "Failed to load " << filename << LL_ENDL; + return false; + } + LLXUIParser parser; + parser.readXUI(xmlNode, contents, filename); + + if (!contents.validateBlock()) + { + return false; + } + + for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator col_it = contents.columns.begin(); + col_it != contents.columns.end(); + ++col_it) + { + pControlsTable->addColumn(*col_it); + } + + return true; +} + +bool LLPanelPreferenceControls::addControlTableRows(const std::string &filename) +{ + LLXMLNodePtr xmlNode; + LLScrollListCtrl::Contents contents; + if (!LLUICtrlFactory::getLayeredXMLNode(filename, xmlNode)) + { + LL_WARNS() << "Failed to load " << filename << LL_ENDL; + return false; + } + LLXUIParser parser; + parser.readXUI(xmlNode, contents, filename); + + if (!contents.validateBlock()) + { + return false; + } + + LLScrollListCell::Params cell_params; + // init basic cell params + cell_params.font = LLFontGL::getFontSansSerif(); + cell_params.font_halign = LLFontGL::LEFT; + cell_params.column = ""; + cell_params.value = ""; + + + for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator row_it = contents.rows.begin(); + row_it != contents.rows.end(); + ++row_it) + { + std::string control = row_it->value.getValue().asString(); + if (!control.empty() && control != "menu_separator") + { + bool show = true; + bool enabled = mConflictHandler[mEditingMode].canAssignControl(control); + if (!enabled) + { + // If empty: this is a placeholder to make sure user won't assign + // value by accident, don't show it + // If not empty: predefined control combination user should see + // to know that combination is reserved + show = !mConflictHandler[mEditingMode].isControlEmpty(control); + // example: teleport_to and walk_to in first person view, and + // sitting related functions, see generatePlaceholders() + } + + if (show) + { + // At the moment viewer is hardcoded to assume that columns are named as lst_ctrl%d + LLScrollListItem::Params item_params(*row_it); + item_params.enabled.setValue(enabled); + + S32 num_columns = pControlsTable->getNumColumns(); + for (S32 col = 1; col < num_columns; col++) + { + cell_params.column = llformat("lst_ctrl%d", col); + cell_params.value = mConflictHandler[mEditingMode].getControlString(control, col - 1); + item_params.columns.add(cell_params); + } + pControlsTable->addRow(item_params, EAddPosition::ADD_BOTTOM); + } + } + else + { + // Separator example: + // <rows + // enabled = "false"> + // <columns + // type = "icon" + // color = "0 0 0 0.7" + // halign = "center" + // value = "menu_separator" + // column = "lst_action" / > + //</rows> + pControlsTable->addRow(*row_it, EAddPosition::ADD_BOTTOM); + } + } + return true; +} + +void LLPanelPreferenceControls::addControlTableSeparator() +{ + LLScrollListItem::Params separator_params; + separator_params.enabled(false); + LLScrollListCell::Params column_params; + column_params.type = "icon"; + column_params.value = "menu_separator"; + column_params.column = "lst_action"; + column_params.color = LLColor4(0.f, 0.f, 0.f, 0.7f); + column_params.font_halign = LLFontGL::HCENTER; + separator_params.columns.add(column_params); + pControlsTable->addRow(separator_params, EAddPosition::ADD_BOTTOM); +} + +void LLPanelPreferenceControls::populateControlTable() +{ + pControlsTable->clearRows(); + pControlsTable->clearColumns(); + + // Add columns + std::string filename; + switch ((LLKeyConflictHandler::ESourceMode)mEditingMode) + { + case LLKeyConflictHandler::MODE_THIRD_PERSON: + case LLKeyConflictHandler::MODE_FIRST_PERSON: + case LLKeyConflictHandler::MODE_EDIT_AVATAR: + case LLKeyConflictHandler::MODE_SITTING: + filename = "control_table_contents_columns_basic.xml"; + break; + default: + // Either unknown mode or MODE_SAVED_SETTINGS + // It doesn't have UI or actual settings yet + LL_INFOS() << "Unimplemented mode" << LL_ENDL; + return; + } + addControlTableColumns(filename); + + // Add rows. + // Each file represents individual visual group (movement/camera/media...) + if (mEditingMode == LLKeyConflictHandler::MODE_FIRST_PERSON) + { + // Don't display whole camera and editing groups + addControlTableRows("control_table_contents_movement.xml"); + addControlTableSeparator(); + addControlTableRows("control_table_contents_media.xml"); + } + // MODE_THIRD_PERSON; MODE_EDIT_AVATAR; MODE_SITTING + else if (mEditingMode < LLKeyConflictHandler::MODE_SAVED_SETTINGS) + { + // In case of 'sitting' mode, movements still apply due to vehicles + // but walk_to is not supported and will be hidden by addControlTableRows + addControlTableRows("control_table_contents_movement.xml"); + addControlTableSeparator(); + + addControlTableRows("control_table_contents_camera.xml"); + addControlTableSeparator(); + + addControlTableRows("control_table_contents_editing.xml"); + addControlTableSeparator(); + + addControlTableRows("control_table_contents_media.xml"); + } + else + { + LL_INFOS() << "Unimplemented mode" << LL_ENDL; + return; + } +} + +void LLPanelPreferenceControls::updateTable() +{ + mEditingControl.clear(); + std::vector<LLScrollListItem*> list = pControlsTable->getAllData(); + for (S32 i = 0; i < list.size(); ++i) + { + std::string control = list[i]->getValue(); + if (!control.empty()) + { + LLScrollListCell* cell = NULL; + + S32 num_columns = pControlsTable->getNumColumns(); + for (S32 col = 1; col < num_columns; col++) + { + cell = list[i]->getColumn(col); + cell->setValue(mConflictHandler[mEditingMode].getControlString(control, col - 1)); + } + } + } + pControlsTable->deselectAllItems(); +} + +void LLPanelPreferenceControls::apply() +{ + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) + { + if (mConflictHandler[i].hasUnsavedChanges()) + { + mConflictHandler[i].saveToSettings(); + } + } +} + +void LLPanelPreferenceControls::cancel() +{ + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) + { + if (mConflictHandler[i].hasUnsavedChanges()) + { + mConflictHandler[i].clear(); + } + } + pControlsTable->clearRows(); + pControlsTable->clearColumns(); +} + +void LLPanelPreferenceControls::saveSettings() +{ + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) + { + if (mConflictHandler[i].hasUnsavedChanges()) + { + mConflictHandler[i].saveToSettings(); + mConflictHandler[i].clear(); + } + } + + S32 mode = pKeyModeBox->getValue().asInteger(); + if (mConflictHandler[mode].empty() || pControlsTable->isEmpty()) + { + regenerateControls(); + } +} + +void LLPanelPreferenceControls::resetDirtyChilds() +{ + regenerateControls(); +} + +void LLPanelPreferenceControls::onListCommit() +{ + LLScrollListItem* item = pControlsTable->getFirstSelected(); + if (item == NULL) + { + return; + } + + std::string control = item->getValue(); + + if (control.empty()) + { + pControlsTable->deselectAllItems(); + return; + } + + if (!mConflictHandler[mEditingMode].canAssignControl(control)) + { + pControlsTable->deselectAllItems(); + return; + } + + S32 cell_ind = item->getSelectedCell(); + if (cell_ind <= 0) + { + pControlsTable->deselectAllItems(); + return; + } + + // List does not tell us what cell was clicked, so we have to figure it out manually, but + // fresh mouse coordinates are not yet accessible during onCommit() and there are other issues, + // so we cheat: remember item user clicked at, trigger 'key dialog' on hover that comes next, + // use coordinates from hover to calculate cell + + LLScrollListCell* cell = item->getColumn(cell_ind); + if (cell) + { + LLSetKeyBindDialog* dialog = LLFloaterReg::getTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD()); + if (dialog) + { + mEditingControl = control; + mEditingColumn = cell_ind; + dialog->setParent(this, pControlsTable, DEFAULT_KEY_FILTER); + + LLFloater* root_floater = gFloaterView->getParentFloater(this); + if (root_floater) + root_floater->addDependentFloater(dialog); + dialog->openFloater(); + dialog->setFocus(TRUE); + } + } + else + { + pControlsTable->deselectAllItems(); + } +} + +void LLPanelPreferenceControls::onModeCommit() +{ + mEditingMode = pKeyModeBox->getValue().asInteger(); + if (mConflictHandler[mEditingMode].empty()) + { + // opening for first time + mConflictHandler[mEditingMode].loadFromSettings((LLKeyConflictHandler::ESourceMode)mEditingMode); + } + populateControlTable(); +} + +void LLPanelPreferenceControls::onRestoreDefaultsBtn() +{ + LLNotificationsUtil::add("PreferenceControlsDefaults", LLSD(), LLSD(), boost::bind(&LLPanelPreferenceControls::onRestoreDefaultsResponse, this, _1, _2)); +} + +void LLPanelPreferenceControls::onRestoreDefaultsResponse(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch(option) + { + case 0: // All + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) + { + mConflictHandler[i].resetToDefaults(); + // Apply changes to viewer as 'temporary' + mConflictHandler[i].saveToSettings(true); + + // notify comboboxes in move&view about potential change + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->updateClickActionViews(); + } + } + + updateTable(); + break; + case 1: // Current + mConflictHandler[mEditingMode].resetToDefaults(); + // Apply changes to viewer as 'temporary' + mConflictHandler[mEditingMode].saveToSettings(true); + + if (mEditingMode == LLKeyConflictHandler::MODE_THIRD_PERSON) + { + // notify comboboxes in move&view about potential change + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->updateClickActionViews(); + } + } + + updateTable(); + break; + case 2: // Cancel + default: + //exit; + break; + } +} + +// Bypass to let Move & view read values without need to create own key binding handler +// Assumes third person view +// Might be better idea to just move whole mConflictHandler into LLFloaterPreference +bool LLPanelPreferenceControls::canKeyBindHandle(const std::string &control, EMouseClickType click, KEY key, MASK mask) +{ + S32 mode = LLKeyConflictHandler::MODE_THIRD_PERSON; + if (mConflictHandler[mode].empty()) + { + // opening for first time + mConflictHandler[mode].loadFromSettings(LLKeyConflictHandler::MODE_THIRD_PERSON); + } + + return mConflictHandler[mode].canHandleControl(control, click, key, mask); +} + +// Bypass to let Move & view modify values without need to create own key binding handler +// Assumes third person view +// Might be better idea to just move whole mConflictHandler into LLFloaterPreference +void LLPanelPreferenceControls::setKeyBind(const std::string &control, EMouseClickType click, KEY key, MASK mask, bool set) +{ + S32 mode = LLKeyConflictHandler::MODE_THIRD_PERSON; + if (mConflictHandler[mode].empty()) + { + // opening for first time + mConflictHandler[mode].loadFromSettings(LLKeyConflictHandler::MODE_THIRD_PERSON); + } + + if (!mConflictHandler[mode].canAssignControl(mEditingControl)) + { + return; + } + + bool already_recorded = mConflictHandler[mode].canHandleControl(control, click, key, mask); + if (set) + { + if (already_recorded) + { + // nothing to do + return; + } + + // find free spot to add data, if no free spot, assign to first + S32 index = 0; + for (S32 i = 0; i < 3; i++) + { + if (mConflictHandler[mode].getControl(control, i).isEmpty()) + { + index = i; + break; + } + } + mConflictHandler[mode].registerControl(control, index, click, key, mask, true); + } + else if (!set) + { + if (!already_recorded) + { + // nothing to do + return; + } + + // find specific control and reset it + for (S32 i = 0; i < 3; i++) + { + LLKeyData data = mConflictHandler[mode].getControl(control, i); + if (data.mMouse == click && data.mKey == key && data.mMask == mask) + { + mConflictHandler[mode].clearControl(control, i); + } + } + } +} + +void LLPanelPreferenceControls::updateAndApply() +{ + S32 mode = LLKeyConflictHandler::MODE_THIRD_PERSON; + mConflictHandler[mode].saveToSettings(true); + updateTable(); +} + +// from LLSetKeybindDialog's interface +bool LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes) +{ + if (!mConflictHandler[mEditingMode].canAssignControl(mEditingControl)) + { + return true; + } + + if ( mEditingColumn > 0) + { + if (all_modes) + { + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) + { + if (mConflictHandler[i].empty()) + { + mConflictHandler[i].loadFromSettings((LLKeyConflictHandler::ESourceMode)i); + } + mConflictHandler[i].registerControl(mEditingControl, mEditingColumn - 1, click, key, mask, true); + // Apply changes to viewer as 'temporary' + mConflictHandler[i].saveToSettings(true); + } + } + else + { + mConflictHandler[mEditingMode].registerControl(mEditingControl, mEditingColumn - 1, click, key, mask, true); + // Apply changes to viewer as 'temporary' + mConflictHandler[mEditingMode].saveToSettings(true); + } + } + + updateTable(); + + if ((mEditingMode == LLKeyConflictHandler::MODE_THIRD_PERSON || all_modes) + && (mEditingControl == "walk_to" + || mEditingControl == "teleport_to" + || click == CLICK_LEFT + || click == CLICK_DOUBLELEFT)) + { + // notify comboboxes in move&view about potential change + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->updateClickActionViews(); + } + } + + return true; +} + +void LLPanelPreferenceControls::onDefaultKeyBind(bool all_modes) +{ + if (!mConflictHandler[mEditingMode].canAssignControl(mEditingControl)) + { + return; + } + + if (mEditingColumn > 0) + { + if (all_modes) + { + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) + { + if (mConflictHandler[i].empty()) + { + mConflictHandler[i].loadFromSettings((LLKeyConflictHandler::ESourceMode)i); + } + mConflictHandler[i].resetToDefault(mEditingControl, mEditingColumn - 1); + // Apply changes to viewer as 'temporary' + mConflictHandler[i].saveToSettings(true); + } + } + else + { + mConflictHandler[mEditingMode].resetToDefault(mEditingControl, mEditingColumn - 1); + // Apply changes to viewer as 'temporary' + mConflictHandler[mEditingMode].saveToSettings(true); + } + } + updateTable(); + + if (mEditingMode == LLKeyConflictHandler::MODE_THIRD_PERSON || all_modes) + { + // notify comboboxes in move&view about potential change + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->updateClickActionViews(); + } + } +} + +void LLPanelPreferenceControls::onCancelKeyBind() +{ + pControlsTable->deselectAllItems(); +} + LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key) : LLFloater(key) { - mCommitCallbackRegistrar.add("Pref.VertexShaderEnable", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onVertexShaderEnable, this)); + mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onRenderOptionEnable, this)); mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxNonImpostors", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxNonImpostors,this)); mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxComplexity,this)); } @@ -2895,6 +3363,7 @@ void LLFloaterPreferenceGraphicsAdvanced::onClickCloseBtn(bool app_quitting) { instance->cancel(); } + updateMaxComplexity(); } LLFloaterPreferenceProxy::~LLFloaterPreferenceProxy() diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 1b8229ada6..1268935712 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -37,13 +37,17 @@ #include "llavatarpropertiesprocessor.h" #include "llconversationlog.h" #include "llsearcheditor.h" +#include "llsetkeybinddialog.h" +#include "llkeyconflict.h" class LLConversationLogObserver; class LLPanelPreference; class LLPanelLCD; class LLPanelDebug; class LLMessageSystem; +class LLComboBox; class LLScrollListCtrl; +class LLScrollListCell; class LLSliderCtrl; class LLSD; class LLTextBox; @@ -102,6 +106,8 @@ public: void selectPrivacyPanel(); void selectChatPanel(); void getControlNames(std::vector<std::string>& names); + // updates click/double-click action controls depending on values from settings.xml + void updateClickActionViews(); protected: void onBtnOK(const LLSD& userdata); @@ -122,16 +128,14 @@ protected: // callback for defaults void setHardwareDefaults(); void setRecommended(); - // callback for when client turns on shaders - void onVertexShaderEnable(); + // callback for when client modifies a render option + void onRenderOptionEnable(); // callback for when client turns on impostors void onAvatarImpostorsEnable(); // callback for commit in the "Single click on land" and "Double click on land" comboboxes. void onClickActionChange(); - // updates click/double-click action settings depending on controls values - void updateClickActionSettings(); - // updates click/double-click action controls depending on values from settings.xml + // updates click/double-click action keybindngs depending on view values void updateClickActionControls(); public: @@ -146,9 +150,6 @@ public: void onClickResetCache(); void onClickSkin(LLUICtrl* ctrl,const LLSD& userdata); void onSelectSkin(); - void onClickSetKey(); - void setKey(KEY key); - void onClickSetMiddleMouse(); void onClickSetSounds(); void onClickEnablePopup(); void onClickDisablePopup(); @@ -167,7 +168,6 @@ public: void refreshUI(); - void onCommitParcelMediaAutoPlayEnable(); void onCommitMediaEnabled(); void onCommitMusicEnabled(); void applyResolution(); @@ -180,6 +180,7 @@ public: void onClickProxySettings(); void onClickTranslationSettings(); void onClickPermsDefault(); + void onClickRememberedUsernames(); void onClickAutoReplace(); void onClickSpellChecker(); void onClickRenderExceptions(); @@ -190,6 +191,7 @@ public: void buildPopupLists(); static void refreshSkin(void* data); void selectPanel(const LLSD& name); + void saveCameraPreset(std::string& preset); void saveGraphicsPreset(std::string& preset); private: @@ -202,7 +204,6 @@ private: static std::string sSkin; notifications_map mNotificationOptions; - bool mClickActionDirty; ///< Set to true when the click/double-click options get changed by user. bool mGotPersonalInfo; bool mOriginalIMViaEmail; bool mLanguageChanged; @@ -213,6 +214,7 @@ private: std::string mDirectoryVisibility; LLAvatarData mAvatarProperties; + std::string mSavedCameraPreset; std::string mSavedGraphicsPreset; LOG_CLASS(LLFloaterPreference); @@ -287,11 +289,64 @@ protected: bool hasDirtyChilds(); private: - void onPresetsListChange(); LOG_CLASS(LLPanelPreferenceGraphics); }; +class LLPanelPreferenceControls : public LLPanelPreference, public LLKeyBindResponderInterface +{ + LOG_CLASS(LLPanelPreferenceControls); +public: + LLPanelPreferenceControls(); + virtual ~LLPanelPreferenceControls(); + + BOOL postBuild(); + + void apply(); + void cancel(); + void saveSettings(); + void resetDirtyChilds(); + + void onListCommit(); + void onModeCommit(); + void onRestoreDefaultsBtn(); + void onRestoreDefaultsResponse(const LLSD& notification, const LLSD& response); + + // Bypass to let Move & view read values without need to create own key binding handler + // Todo: consider a better way to share access to keybindings + bool canKeyBindHandle(const std::string &control, EMouseClickType click, KEY key, MASK mask); + // Bypasses to let Move & view modify values without need to create own key binding handler + void setKeyBind(const std::string &control, EMouseClickType click, KEY key, MASK mask, bool set /*set or reset*/ ); + void updateAndApply(); + + // from interface + /*virtual*/ bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes); + /*virtual*/ void onDefaultKeyBind(bool all_modes); + /*virtual*/ void onCancelKeyBind(); + +private: + // reloads settings, discards current changes, updates table + void regenerateControls(); + + // These fuctions do not clean previous content + bool addControlTableColumns(const std::string &filename); + bool addControlTableRows(const std::string &filename); + void addControlTableSeparator(); + + // Cleans content and then adds content from xml files according to current mEditingMode + void populateControlTable(); + + // Updates keybindings from storage to table + void updateTable(); + + LLScrollListCtrl* pControlsTable; + LLComboBox *pKeyModeBox; + LLKeyConflictHandler mConflictHandler[LLKeyConflictHandler::MODE_COUNT]; + std::string mEditingControl; + S32 mEditingColumn; + S32 mEditingMode; +}; + class LLFloaterPreferenceGraphicsAdvanced : public LLFloater { public: @@ -312,8 +367,9 @@ class LLFloaterPreferenceGraphicsAdvanced : public LLFloater static void setIndirectMaxNonImpostors(); static void setIndirectMaxArc(); void refresh(); - // callback for when client turns on shaders - void onVertexShaderEnable(); + // callback for when client modifies a render option + void onRenderOptionEnable(); + void onAdvancedAtmosphericsEnable(); LOG_CLASS(LLFloaterPreferenceGraphicsAdvanced); }; diff --git a/indra/newview/llfloaterpreferenceviewadvanced.cpp b/indra/newview/llfloaterpreferenceviewadvanced.cpp new file mode 100644 index 0000000000..f8db738923 --- /dev/null +++ b/indra/newview/llfloaterpreferenceviewadvanced.cpp @@ -0,0 +1,82 @@ +/** + * @file llfloaterpreferenceviewadvanced.cpp + * @brief floater for adjusting camera position + * + * $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 "llviewerprecompiledheaders.h" +#include "llagentcamera.h" +#include "llfloaterpreferenceviewadvanced.h" +#include "llfloater.h" +#include "llfloaterreg.h" +#include "lluictrlfactory.h" +#include "llspinctrl.h" +#include "llviewercontrol.h" + + +LLFloaterPreferenceViewAdvanced::LLFloaterPreferenceViewAdvanced(const LLSD& key) +: LLFloater(key) +{ + mCommitCallbackRegistrar.add("CommitSettings", boost::bind(&LLFloaterPreferenceViewAdvanced::onCommitSettings, this)); +} + +LLFloaterPreferenceViewAdvanced::~LLFloaterPreferenceViewAdvanced() +{} + +void LLFloaterPreferenceViewAdvanced::updateCameraControl(const LLVector3& vector) +{ + getChild<LLSpinCtrl>("camera_x")->setValue(vector[VX]); + getChild<LLSpinCtrl>("camera_y")->setValue(vector[VY]); + getChild<LLSpinCtrl>("camera_z")->setValue(vector[VZ]); +} + +void LLFloaterPreferenceViewAdvanced::updateFocusControl(const LLVector3d& vector3d) +{ + getChild<LLSpinCtrl>("focus_x")->setValue(vector3d[VX]); + getChild<LLSpinCtrl>("focus_y")->setValue(vector3d[VY]); + getChild<LLSpinCtrl>("focus_z")->setValue(vector3d[VZ]); +} + + void LLFloaterPreferenceViewAdvanced::draw() +{ + updateCameraControl(gAgentCamera.getCameraOffsetInitial()); + updateFocusControl(gAgentCamera.getFocusOffsetInitial()); + + LLFloater::draw(); +} + +void LLFloaterPreferenceViewAdvanced::onCommitSettings() +{ + LLVector3 vector; + LLVector3d vector3d; + + vector.mV[VX] = (F32)getChild<LLUICtrl>("camera_x")->getValue().asReal(); + vector.mV[VY] = (F32)getChild<LLUICtrl>("camera_y")->getValue().asReal(); + vector.mV[VZ] = (F32)getChild<LLUICtrl>("camera_z")->getValue().asReal(); + gSavedSettings.setVector3("CameraOffsetRearView", vector); + + vector3d.mdV[VX] = (F32)getChild<LLUICtrl>("focus_x")->getValue().asReal(); + vector3d.mdV[VY] = (F32)getChild<LLUICtrl>("focus_y")->getValue().asReal(); + vector3d.mdV[VZ] = (F32)getChild<LLUICtrl>("focus_z")->getValue().asReal(); + gSavedSettings.setVector3d("FocusOffsetRearView", vector3d); +} diff --git a/indra/newview/llfloaterpreferenceviewadvanced.h b/indra/newview/llfloaterpreferenceviewadvanced.h new file mode 100644 index 0000000000..4619fdaab1 --- /dev/null +++ b/indra/newview/llfloaterpreferenceviewadvanced.h @@ -0,0 +1,51 @@ +/** + * @file llfloaterpreferenceviewadvanced.h + * @brief floater for adjusting camera position + * + * $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$ + */ + +#ifndef LLFLOATERPREFERENCEVIEWADVANCED_H +#define LLFLOATERPREFERENCEVIEWADVANCED_H + +#include "llcontrol.h" +#include "llfloater.h" + +class LLFloaterPreferenceViewAdvanced +: public LLFloater +{ + friend class LLFloaterReg; + +public: + LLFloaterPreferenceViewAdvanced(const LLSD& key); + virtual void draw(); + + void onCommitSettings(); + void updateCameraControl(const LLVector3& vector); + void updateFocusControl(const LLVector3d& vector3d); + +private: + virtual ~LLFloaterPreferenceViewAdvanced(); +}; + +#endif //LLFLOATERPREFERENCEVIEWADVANCED_H + diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp index fbb7432f71..64ad40f419 100644 --- a/indra/newview/llfloaterproperties.cpp +++ b/indra/newview/llfloaterproperties.cpp @@ -85,7 +85,7 @@ public: } virtual void changed(U32 mask); private: - LLFloaterProperties* mFloater; + LLFloaterProperties* mFloater; // Not a handle because LLFloaterProperties is managing LLPropertiesObserver }; void LLPropertiesObserver::changed(U32 mask) diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index ec934a4732..ec1909d02a 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -53,8 +53,6 @@ #include "llcheckboxctrl.h" #include "llclipboard.h" #include "llcombobox.h" -#include "lldaycyclemanager.h" -#include "llenvmanager.h" #include "llestateinfomodel.h" #include "llfilepicker.h" #include "llfloatergodtools.h" // for send_sim_wide_deletes() @@ -88,7 +86,6 @@ #include "llviewertexteditor.h" #include "llviewerwindow.h" #include "llvlcomposition.h" -#include "llwaterparammanager.h" #include "lltrans.h" #include "llagentui.h" #include "llmeshrepository.h" @@ -100,6 +97,7 @@ #include "llpanelexperiences.h" #include "llcorehttputil.h" #include "llavatarnamecache.h" +#include "llenvironment.h" const S32 TERRAIN_TEXTURE_COUNT = 4; const S32 CORNER_COUNT = 4; @@ -182,6 +180,40 @@ void unpack_request_params( } */ +class LLPanelRegionEnvironment : public LLPanelEnvironmentInfo +{ +public: + LLPanelRegionEnvironment(); + virtual ~LLPanelRegionEnvironment(); + + virtual void refresh() override; + + virtual bool isRegion() const override { return true; } + virtual LLParcel * getParcel() override { return nullptr; } + virtual bool canEdit() override { return LLEnvironment::instance().canAgentUpdateRegionEnvironment(); } + virtual bool isLargeEnough() override { return true; } // regions are always large enough. + + bool refreshFromRegion(LLViewerRegion* region); + + virtual BOOL postBuild() override; + virtual void onOpen(const LLSD& key) override {}; + + virtual S32 getParcelId() override { return INVALID_PARCEL_ID; } + +protected: + static const U32 DIRTY_FLAG_OVERRIDE; + + virtual void refreshFromSource() override; + + bool confirmUpdateEstateEnvironment(const LLSD& notification, const LLSD& response); + + void onChkAllowOverride(bool value); + +private: + bool mAllowOverrideRestore; + connection_t mCommitConnect; +}; + bool estate_dispatch_initialized = false; @@ -196,7 +228,9 @@ LLUUID LLFloaterRegionInfo::sRequestInvoice; LLFloaterRegionInfo::LLFloaterRegionInfo(const LLSD& seed) - : LLFloater(seed) + : LLFloater(seed), + mEnvironmentPanel(NULL), + mRegionChangedCallback() {} BOOL LLFloaterRegionInfo::postBuild() @@ -232,10 +266,10 @@ BOOL LLFloaterRegionInfo::postBuild() panel->buildFromFile("panel_region_terrain.xml"); mTab->addTabPanel(panel); - panel = new LLPanelEnvironmentInfo; - mInfoPanels.push_back(panel); - panel->buildFromFile("panel_region_environment.xml"); - mTab->addTabPanel(panel); + mEnvironmentPanel = new LLPanelRegionEnvironment; + mEnvironmentPanel->buildFromFile("panel_region_environment.xml"); +// mEnvironmentPanel->configureForRegion(); + mTab->addTabPanel(mEnvironmentPanel); panel = new LLPanelRegionDebugInfo; mInfoPanels.push_back(panel); @@ -260,13 +294,18 @@ BOOL LLFloaterRegionInfo::postBuild() &processEstateOwnerRequest); // Request region info when agent region changes. - gAgent.addRegionChangedCallback(boost::bind(&LLFloaterRegionInfo::requestRegionInfo, this)); + mRegionChangedCallback = gAgent.addRegionChangedCallback(boost::bind(&LLFloaterRegionInfo::onRegionChanged, this)); return TRUE; } LLFloaterRegionInfo::~LLFloaterRegionInfo() -{} +{ + if (mRegionChangedCallback.connected()) + { + mRegionChangedCallback.disconnect(); + } +} void LLFloaterRegionInfo::onOpen(const LLSD& key) { @@ -293,16 +332,26 @@ void LLFloaterRegionInfo::onClose(bool app_quitting) } } +void LLFloaterRegionInfo::onRegionChanged() +{ + if (getVisible()) //otherwise onOpen will do request + { + requestRegionInfo(); + } +} + // static void LLFloaterRegionInfo::requestRegionInfo() { - LLTabContainer* tab = getChild<LLTabContainer>("region_panels"); - - tab->getChild<LLPanel>("General")->setCtrlsEnabled(FALSE); - tab->getChild<LLPanel>("Debug")->setCtrlsEnabled(FALSE); - tab->getChild<LLPanel>("Terrain")->setCtrlsEnabled(FALSE); - tab->getChild<LLPanel>("Estate")->setCtrlsEnabled(FALSE); - tab->getChild<LLPanel>("Access")->setCtrlsEnabled(FALSE); + LLTabContainer* tab = findChild<LLTabContainer>("region_panels"); + if (tab) + { + tab->getChild<LLPanel>("General")->setCtrlsEnabled(FALSE); + tab->getChild<LLPanel>("Debug")->setCtrlsEnabled(FALSE); + tab->getChild<LLPanel>("Terrain")->setCtrlsEnabled(FALSE); + tab->getChild<LLPanel>("Estate")->setCtrlsEnabled(FALSE); + tab->getChild<LLPanel>("Access")->setCtrlsEnabled(FALSE); + } // Must allow anyone to request the RegionInfo data // so non-owners/non-gods can see the values. @@ -362,13 +411,13 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) { return; } - +#if 0 // We need to re-request environment setting here, // otherwise after we apply (send) updated region settings we won't get them back, // so our environment won't be updated. // This is also the way to know about externally changed region environment. LLEnvManagerNew::instance().requestRegionSettings(); - +#endif LLTabContainer* tab = floater->getChild<LLTabContainer>("region_panels"); LLViewerRegion* region = gAgent.getRegion(); @@ -475,7 +524,12 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) panel->setCtrlsEnabled(allow_modify); - floater->refreshFromRegion( gAgent.getRegion() ); + if (floater->getVisible()) + { + // Note: region info also causes LLRegionInfoModel::instance().update(msg); -> requestRegion(); -> changed message + // we need to know env version here and in update(msg) to know when to request and when not to, when to filter 'changed' + floater->refreshFromRegion(gAgent.getRegion()); + } // else will rerequest on onOpen either way } // static @@ -519,6 +573,16 @@ LLPanelRegionGeneralInfo* LLFloaterRegionInfo::getPanelGeneral() } // static +LLPanelRegionEnvironment* LLFloaterRegionInfo::getPanelEnvironment() +{ + LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance<LLFloaterRegionInfo>("region_info"); + if (!floater) return NULL; + LLTabContainer* tab = floater->getChild<LLTabContainer>("region_panels"); + LLPanelRegionEnvironment* panel = (LLPanelRegionEnvironment*)tab->getChild<LLPanel>("panel_env_info"); + return panel; +} + +// static LLPanelRegionTerrainInfo* LLFloaterRegionInfo::getPanelRegionTerrain() { LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance<LLFloaterRegionInfo>("region_info"); @@ -573,12 +637,9 @@ 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)); + mEnvironmentPanel->refreshFromRegion(region); } // public @@ -589,6 +650,7 @@ void LLFloaterRegionInfo::refresh() { (*iter)->refresh(); } + mEnvironmentPanel->refresh(); } void LLFloaterRegionInfo::enableTopButtons() @@ -2416,605 +2478,6 @@ bool LLDispatchSetEstateExperience::operator()( return true; } - - -LLPanelEnvironmentInfo::LLPanelEnvironmentInfo() -: mEnableEditing(false), - mRegionSettingsRadioGroup(NULL), - mDayCycleSettingsRadioGroup(NULL), - mWaterPresetCombo(NULL), - mSkyPresetCombo(NULL), - mDayCyclePresetCombo(NULL) -{ -} - -// virtual -BOOL LLPanelEnvironmentInfo::postBuild() -{ - mRegionSettingsRadioGroup = getChild<LLRadioGroup>("region_settings_radio_group"); - mRegionSettingsRadioGroup->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onSwitchRegionSettings, this)); - - mDayCycleSettingsRadioGroup = getChild<LLRadioGroup>("sky_dayc_settings_radio_group"); - mDayCycleSettingsRadioGroup->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onSwitchDayCycle, this)); - - mWaterPresetCombo = getChild<LLComboBox>("water_settings_preset_combo"); - mWaterPresetCombo->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onSelectWaterPreset, this)); - - mSkyPresetCombo = getChild<LLComboBox>("sky_settings_preset_combo"); - mSkyPresetCombo->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onSelectSkyPreset, this)); - - mDayCyclePresetCombo = getChild<LLComboBox>("dayc_settings_preset_combo"); - mDayCyclePresetCombo->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onSelectDayCycle, this)); - - childSetCommitCallback("apply_btn", boost::bind(&LLPanelEnvironmentInfo::onBtnApply, this), NULL); - getChild<LLButton>("apply_btn")->setRightMouseDownCallback(boost::bind(&LLEnvManagerNew::dumpUserPrefs, LLEnvManagerNew::getInstance())); - childSetCommitCallback("cancel_btn", boost::bind(&LLPanelEnvironmentInfo::onBtnCancel, this), NULL); - getChild<LLButton>("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; -} - -// virtual -void LLPanelEnvironmentInfo::onOpen(const LLSD& key) -{ - LL_DEBUGS("Windlight") << "Panel opened, refreshing" << LL_ENDL; - refresh(); -} - -// virtual -void LLPanelEnvironmentInfo::onVisibilityChange(BOOL new_visibility) -{ - // If hiding (user switched to another tab or closed the floater), - // display user's preferred environment. - if (!new_visibility) - { - LLEnvManagerNew::instance().usePrefs(); - } -} - -// virtual -bool LLPanelEnvironmentInfo::refreshFromRegion(LLViewerRegion* region) -{ - 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); -} - -void LLPanelEnvironmentInfo::refresh() -{ - if(gDisconnected) - { - return; - } - - 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); - - setControlsEnabled(mEnableEditing); - - setDirty(false); -} - -void LLPanelEnvironmentInfo::setControlsEnabled(bool enabled) -{ - mRegionSettingsRadioGroup->setEnabled(enabled); - mDayCycleSettingsRadioGroup->setEnabled(enabled); - - mWaterPresetCombo->setEnabled(enabled); - mSkyPresetCombo->setEnabled(enabled); - mDayCyclePresetCombo->setEnabled(enabled); - - getChildView("apply_btn")->setEnabled(enabled); - getChildView("cancel_btn")->setEnabled(enabled); - - if (enabled) - { - // Enable/disable some controls based on currently selected radio buttons. - bool use_defaults = mRegionSettingsRadioGroup->getSelectedIndex() == 0; - getChild<LLView>("user_environment_settings")->setEnabled(!use_defaults); - - bool is_fixed_sky = mDayCycleSettingsRadioGroup->getSelectedIndex() == 0; - mSkyPresetCombo->setEnabled(is_fixed_sky); - mDayCyclePresetCombo->setEnabled(!is_fixed_sky); - } -} - -void LLPanelEnvironmentInfo::setApplyProgress(bool started) -{ - LLLoadingIndicator* indicator = getChild<LLLoadingIndicator>("progress_indicator"); - - indicator->setVisible(started); - - if (started) - { - indicator->start(); - } - else - { - indicator->stop(); - } -} - -void LLPanelEnvironmentInfo::setDirty(bool dirty) -{ - getChildView("apply_btn")->setEnabled(dirty); - getChildView("cancel_btn")->setEnabled(dirty); -} - -void LLPanelEnvironmentInfo::sendRegionSunUpdate() -{ - 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("WindlightSync") << "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("WindlightSync") << "Sun hour: " << region_info.mSunHour << LL_ENDL; - - region_info.sendRegionTerrain(LLFloaterRegionInfo::getLastInvoice()); -} - -void LLPanelEnvironmentInfo::fixEstateSun() -{ - // 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()) - { - LL_INFOS() << "Switching estate to global sun" << LL_ENDL; - estate_info.setUseFixedSun(false); - estate_info.sendEstateInfo(); - } -} - -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) - { - const std::string& region_name = gAgent.getRegion()->getName(); - mWaterPresetCombo->add(region_name, LLWLParamKey(region_name, LLEnvKey::SCOPE_REGION).toLLSD()); - mWaterPresetCombo->addSeparator(); - } - - std::list<std::string> user_presets, system_presets; - LLWaterParamManager::instance().getPresetNames(user_presets, system_presets); - - // Add local user presets first. - for (std::list<std::string>::const_iterator it = user_presets.begin(); it != user_presets.end(); ++it) - { - mWaterPresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toLLSD()); - } - - if (user_presets.size() > 0) - { - mWaterPresetCombo->addSeparator(); - } - - // Add local system presets. - for (std::list<std::string>::const_iterator it = system_presets.begin(); it != system_presets.end(); ++it) - { - mWaterPresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toLLSD()); - } - - // There's no way to select current preset because its name is not stored on server. -} - -void LLPanelEnvironmentInfo::populateSkyPresetsList() -{ - mSkyPresetCombo->removeall(); - - 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); - - // 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) - { - std::string preset_name = *it; - std::string item_title = preset_name + " (" + region_name + ")"; - mSkyPresetCombo->add(item_title, LLWLParamKey(preset_name, LLEnvKey::SCOPE_REGION).toStringVal()); - } - - if (!region_presets.empty()) - { - mSkyPresetCombo->addSeparator(); - } - - // Add user presets. - for (LLWLParamManager::preset_name_list_t::const_iterator it = user_presets.begin(); it != user_presets.end(); ++it) - { - mSkyPresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toStringVal()); - } - - if (!user_presets.empty()) - { - mSkyPresetCombo->addSeparator(); - } - - // Add system presets. - for (LLWLParamManager::preset_name_list_t::const_iterator it = sys_presets.begin(); it != sys_presets.end(); ++it) - { - mSkyPresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toStringVal()); - } - - // 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()); - } -} - -void LLPanelEnvironmentInfo::populateDayCyclesList() -{ - 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(); - } - - // 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) - { - mDayCyclePresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toStringVal()); - } - - if (user_days.size() > 0) - { - mDayCyclePresetCombo->addSeparator(); - } - - // 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()); - } - - // Current day cycle is already selected. -} - -bool LLPanelEnvironmentInfo::getSelectedWaterParams(LLSD& water_params) -{ - LLWLParamKey water_key(mWaterPresetCombo->getSelectedValue()); - - if (water_key.scope == LLEnvKey::SCOPE_REGION) - { - water_params = LLEnvManagerNew::instance().getRegionSettings().getWaterParams(); - } - else - { - 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(); - } - - return true; -} - -bool LLPanelEnvironmentInfo::getSelectedSkyParams(LLSD& sky_params, std::string& preset_name) -{ - std::string preset_key(mSkyPresetCombo->getValue().asString()); - LLWLParamKey preset(preset_key); - - // 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; -} - -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 (!LLDayCycleManager::instance().getPreset(dc.name, day_cycle)) - { - LL_WARNS() << "Error getting day cycle " << dc.name << LL_ENDL; - return false; - } - - // Create sky map from the day cycle. - { - LLWLDayCycle tmp_day; - tmp_day.loadDayCycle(day_cycle, dc.scope); - tmp_day.getSkyMap(sky_map); - } - } - - scope = dc.scope; - - return true; -} -void LLPanelEnvironmentInfo::onSwitchRegionSettings() -{ - bool use_defaults = mRegionSettingsRadioGroup->getSelectedIndex() == 0; - getChild<LLView>("user_environment_settings")->setEnabled(!use_defaults); - - if (use_defaults) - { - LLEnvManagerNew::instance().useDefaults(); - } - else - { - onSelectWaterPreset(); - onSwitchDayCycle(); - } - - setDirty(true); -} - -void LLPanelEnvironmentInfo::onSwitchDayCycle() -{ - bool is_fixed_sky = mDayCycleSettingsRadioGroup->getSelectedIndex() == 0; - - mSkyPresetCombo->setEnabled(is_fixed_sky); - mDayCyclePresetCombo->setEnabled(!is_fixed_sky); - - if (is_fixed_sky) - { - onSelectSkyPreset(); - } - else - { - onSelectDayCycle(); - } - - setDirty(true); -} - -void LLPanelEnvironmentInfo::onSelectWaterPreset() -{ - LLSD water_params; - - if (getSelectedWaterParams(water_params)) - { - LLEnvManagerNew::instance().useWaterParams(water_params); - } - - setDirty(true); -} - -void LLPanelEnvironmentInfo::onSelectSkyPreset() -{ - LLSD params; - std::string dummy; - - if (getSelectedSkyParams(params, dummy)) - { - LLEnvManagerNew::instance().useSkyParams(params); - } - - setDirty(true); -} - -void LLPanelEnvironmentInfo::onSelectDayCycle() -{ - LLSD day_cycle; - LLSD sky_map; // unused - short scope; - - if (getSelectedDayCycleParams(day_cycle, sky_map, scope)) - { - LLEnvManagerNew::instance().useDayCycleParams(day_cycle, (LLEnvKey::EScope) scope); - } - - setDirty(true); -} - -void LLPanelEnvironmentInfo::onBtnApply() -{ - 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) - { - // 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)) - { - 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<LLWLParamKey, LLWLParamSet> 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; - - short scope; // unused - if (!getSelectedDayCycleParams(day_cycle, sky_map, scope)) - { - return; - } - - // 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) - { - LL_DEBUGS("Windlight") << "Fixing negative time" << LL_ENDL; - day_cycle[0][0] = 0.0f; - } - } - - // Get water params. - if (!getSelectedWaterParams(water_params)) - { - // *TODO: show a notification? - return; - } - } - - // 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); -} - -void LLPanelEnvironmentInfo::onBtnCancel() -{ - // Reload last saved region settings. - refresh(); - - // 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 LLPanelEnvironmentInfo::onRegionSettingschange() -{ - LL_DEBUGS("Windlight") << "Region settings changed, refreshing" << LL_ENDL; - refresh(); - - // 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(); - } -} - BOOL LLPanelRegionExperiences::postBuild() { mAllowed = setupList("panel_allowed", ESTATE_EXPERIENCE_ALLOWED_ADD, ESTATE_EXPERIENCE_ALLOWED_REMOVE); @@ -4239,3 +3702,152 @@ bool LLPanelEstateAccess::refreshFromRegion(LLViewerRegion* region) return LLPanelRegionInfo::refreshFromRegion(region); } +//========================================================================= +const U32 LLPanelRegionEnvironment::DIRTY_FLAG_OVERRIDE(0x01 << 4); + +LLPanelRegionEnvironment::LLPanelRegionEnvironment(): + LLPanelEnvironmentInfo(), + mAllowOverrideRestore(false) +{ +} + +LLPanelRegionEnvironment::~LLPanelRegionEnvironment() +{ + if (mCommitConnect.connected()) + mCommitConnect.disconnect(); +} + +BOOL LLPanelRegionEnvironment::postBuild() +{ + LLEstateInfoModel& estate_info = LLEstateInfoModel::instance(); + + if (!LLPanelEnvironmentInfo::postBuild()) + return FALSE; + + getChild<LLUICtrl>(BTN_USEDEFAULT)->setLabelArg("[USEDEFAULT]", getString(STR_LABEL_USEDEFAULT)); + getChild<LLUICtrl>(CHK_ALLOWOVERRIDE)->setVisible(TRUE); + getChild<LLUICtrl>(PNL_ENVIRONMENT_ALTITUDES)->setVisible(TRUE); + + getChild<LLUICtrl>(CHK_ALLOWOVERRIDE)->setCommitCallback([this](LLUICtrl *, const LLSD &value){ onChkAllowOverride(value.asBoolean()); }); + + mCommitConnect = estate_info.setCommitCallback(boost::bind(&LLPanelRegionEnvironment::refreshFromEstate, this)); + return TRUE; +} + + +void LLPanelRegionEnvironment::refresh() +{ + commitDayLenOffsetChanges(false); // commit unsaved changes if any + + if (!mCurrentEnvironment) + { + if (mCurEnvVersion <= INVALID_PARCEL_ENVIRONMENT_VERSION) + { + refreshFromSource(); // will immediately set mCurEnvVersion + } // else - already requesting + return; + } + + LLPanelEnvironmentInfo::refresh(); + + getChild<LLUICtrl>(CHK_ALLOWOVERRIDE)->setValue(mAllowOverride); +} + +bool LLPanelRegionEnvironment::refreshFromRegion(LLViewerRegion* region) +{ + if (!region) + { + setNoSelection(true); + setControlsEnabled(false); + mCurEnvVersion = INVALID_PARCEL_ENVIRONMENT_VERSION; + getChild<LLUICtrl>("region_text")->setValue(LLSD("")); + } + else + { + getChild<LLUICtrl>("region_text")->setValue(LLSD(region->getName())); + } + setNoSelection(false); + + if (gAgent.getRegion()->getRegionID() != region->getRegionID()) + { + setCrossRegion(true); + mCurEnvVersion = INVALID_PARCEL_ENVIRONMENT_VERSION; + } + setCrossRegion(false); + + refreshFromSource(); + return true; +} + +void LLPanelRegionEnvironment::refreshFromSource() +{ + LL_DEBUGS("ENVIRONMENT") << "Requesting environment for region, known version " << mCurEnvVersion << LL_ENDL; + LLHandle<LLPanel> that_h = getHandle(); + + if (mCurEnvVersion < UNSET_PARCEL_ENVIRONMENT_VERSION) + { + // to mark as requesting + mCurEnvVersion = UNSET_PARCEL_ENVIRONMENT_VERSION; + } + + LLEnvironment::instance().requestRegion( + [that_h](S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envifo) { _onEnvironmentReceived(that_h, parcel_id, envifo); }); + + setControlsEnabled(false); +} + +bool LLPanelRegionEnvironment::confirmUpdateEstateEnvironment(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.setAllowEnvironmentOverride(mAllowOverride); + // send the update to sim + estate_info.sendEstateInfo(); + clearDirtyFlag(DIRTY_FLAG_OVERRIDE); + } + break; + + case 1: + mAllowOverride = mAllowOverrideRestore; + getChild<LLUICtrl>(CHK_ALLOWOVERRIDE)->setValue(mAllowOverride); + break; + default: + break; + } + return false; +} + +void LLPanelRegionEnvironment::onChkAllowOverride(bool value) +{ + setDirtyFlag(DIRTY_FLAG_OVERRIDE); + mAllowOverrideRestore = mAllowOverride; + mAllowOverride = value; + + + std::string notification("EstateParcelEnvironmentOverride"); + if (LLPanelEstateInfo::isLindenEstate()) + notification = "ChangeLindenEstate"; + + LLSD args; + args["ESTATENAME"] = LLEstateInfoModel::instance().getName(); + LLNotification::Params params(notification); + params.substitutions(args); + params.functor.function([this](const LLSD& notification, const LLSD& response) { confirmUpdateEstateEnvironment(notification, response); }); + + if (!value || LLPanelEstateInfo::isLindenEstate()) + { // warn if turning off or a Linden Estate + LLNotifications::instance().add(params); + } + else + { + LLNotifications::instance().forceResponse(params, 0); + } + +} diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index 5d0f5fc6fc..75d0c3ea5c 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -35,8 +35,8 @@ #include "llhost.h" #include "llpanel.h" #include "llextendedstatus.h" +#include "llpanelenvironment.h" -#include "llenvmanager.h" // for LLEnvironmentSettings #include "lleventcoro.h" class LLAvatarName; @@ -66,13 +66,9 @@ class LLPanelExperienceListEditor; class LLPanelExperiences; class LLPanelRegionExperiences; class LLPanelEstateAccess; +class LLPanelRegionEnvironment; class LLEventTimer; -class LLEnvironmentSettings; -class LLWLParamManager; -class LLWaterParamManager; -class LLWLParamSet; -class LLWaterParamSet; class LLFloaterRegionInfo : public LLFloater { @@ -100,10 +96,12 @@ public: static LLPanelRegionTerrainInfo* getPanelRegionTerrain(); static LLPanelRegionExperiences* getPanelExperiences(); static LLPanelRegionGeneralInfo* getPanelGeneral(); + static LLPanelRegionEnvironment* getPanelEnvironment(); // from LLPanel virtual void refresh(); + void onRegionChanged(); void requestRegionInfo(); void requestMeshRezInfo(); void enableTopButtons(); @@ -124,12 +122,13 @@ protected: LLTabContainer* mTab; typedef std::vector<LLPanelRegionInfo*> info_panels_t; info_panels_t mInfoPanels; - //static S32 sRequestSerial; // serial # of last EstateOwnerRequest + LLPanelRegionEnvironment *mEnvironmentPanel; + //static S32 sRequestSerial; // serial # of last EstateOwnerRequest static LLUUID sRequestInvoice; private: - LLAgent::god_level_change_slot_t mGodLevelChangeSlot; - + LLAgent::god_level_change_slot_t mGodLevelChangeSlot; + boost::signals2::connection mRegionChangedCallback; }; @@ -398,69 +397,10 @@ protected: ///////////////////////////////////////////////////////////////////////////// -class LLPanelEnvironmentInfo : public LLPanelRegionInfo -{ - LOG_CLASS(LLPanelEnvironmentInfo); - -public: - LLPanelEnvironmentInfo(); - - // LLPanel - /*virtual*/ BOOL postBuild(); - /*virtual*/ void onOpen(const LLSD& key); - - // LLView - /*virtual*/ void onVisibilityChange(BOOL new_visibility); - - // LLPanelRegionInfo - /*virtual*/ bool refreshFromRegion(LLViewerRegion* region); - -private: - void refresh(); - void setControlsEnabled(bool enabled); - void setApplyProgress(bool started); - void setDirty(bool dirty); - - void sendRegionSunUpdate(); - void fixEstateSun(); - - void populateWaterPresetsList(); - void populateSkyPresetsList(); - void populateDayCyclesList(); - - bool getSelectedWaterParams(LLSD& water_params); - bool getSelectedSkyParams(LLSD& sky_params, std::string& preset_name); - bool getSelectedDayCycleParams(LLSD& day_cycle, LLSD& sky_map, short& scope); - - void onSwitchRegionSettings(); - void onSwitchDayCycle(); - - void onSelectWaterPreset(); - void onSelectSkyPreset(); - void onSelectDayCycle(); - - void onBtnApply(); - void onBtnCancel(); - - void onRegionSettingschange(); - void onRegionSettingsApplied(bool ok); - - /// New environment settings that are being applied to the region. - LLEnvironmentSettings mNewRegionSettings; - - bool mEnableEditing; - - LLRadioGroup* mRegionSettingsRadioGroup; - LLRadioGroup* mDayCycleSettingsRadioGroup; - - LLComboBox* mWaterPresetCombo; - LLComboBox* mSkyPresetCombo; - LLComboBox* mDayCyclePresetCombo; -}; class LLPanelRegionExperiences : public LLPanelRegionInfo { - LOG_CLASS(LLPanelEnvironmentInfo); + LOG_CLASS(LLPanelRegionExperiences); public: LLPanelRegionExperiences(){} @@ -493,7 +433,7 @@ private: class LLPanelEstateAccess : public LLPanelRegionInfo { - LOG_CLASS(LLPanelEnvironmentInfo); + LOG_CLASS(LLPanelEstateAccess); public: LLPanelEstateAccess(); diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 960fd9620d..a30c73768d 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -102,7 +102,6 @@ public: virtual LLSD prepareUpload(); virtual LLSD generatePostBody(); - virtual S32 getEconomyUploadCost(); virtual LLUUID finishUpload(LLSD &result); virtual bool showInventoryPanel() const { return false; } @@ -129,11 +128,6 @@ LLSD LLARScreenShotUploader::generatePostBody() return mReport; } -S32 LLARScreenShotUploader::getEconomyUploadCost() -{ // Abuse report screen shots do not cost anything to upload. - return 0; -} - LLUUID LLARScreenShotUploader::finishUpload(LLSD &result) { /* *TODO$: Report success or failure. Carried over from previous todo on responder*/ @@ -752,9 +746,6 @@ LLSD LLFloaterReporter::gatherReport() const char* platform = "Mac"; #elif LL_LINUX const char* platform = "Lnx"; -#elif LL_SOLARIS - const char* platform = "Sol"; - const char* short_platform = "O:S"; #else const char* platform = "???"; #endif @@ -771,7 +762,7 @@ LLSD LLFloaterReporter::gatherReport() std::ostringstream details; - details << "V" << LLVersionInfo::getVersion() << std::endl << std::endl; // client version moved to body of email for abuse reports + details << "V" << LLVersionInfo::instance().getVersion() << std::endl << std::endl; // client version moved to body of email for abuse reports std::string object_name = getChild<LLUICtrl>("object_name")->getValue().asString(); if (!object_name.empty() && !mOwnerName.empty()) @@ -789,7 +780,7 @@ LLSD LLFloaterReporter::gatherReport() std::string version_string; version_string = llformat( "%s %s %s %s %s", - LLVersionInfo::getShortVersion().c_str(), + LLVersionInfo::instance().getShortVersion().c_str(), platform, gSysCPU.getFamily().c_str(), gGLManager.mGLRenderer.c_str(), @@ -936,7 +927,7 @@ void LLFloaterReporter::takeNewSnapshot() // Take a screenshot, but don't draw this floater. setVisible(FALSE); - if( !gViewerWindow->rawSnapshot(mImageRaw, IMAGE_WIDTH, IMAGE_HEIGHT, TRUE, FALSE, TRUE, FALSE)) + if (!gViewerWindow->rawSnapshot(mImageRaw,IMAGE_WIDTH, IMAGE_HEIGHT, TRUE, FALSE, TRUE /*UI*/, TRUE, FALSE)) { LL_WARNS() << "Unable to take screenshot" << LL_ENDL; setVisible(TRUE); diff --git a/indra/newview/llfloatersavecamerapreset.cpp b/indra/newview/llfloatersavecamerapreset.cpp new file mode 100644 index 0000000000..11809f9c82 --- /dev/null +++ b/indra/newview/llfloatersavecamerapreset.cpp @@ -0,0 +1,172 @@ +/** + * @file llfloatersavecamerapreset.cpp + * @brief Floater to save a camera preset + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2020, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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 "llfloatersavecamerapreset.h" + +#include "llagent.h" +#include "llagentcamera.h" +#include "llbutton.h" +#include "llcombobox.h" +#include "llfloaterpreference.h" +#include "llfloaterreg.h" +#include "lllineeditor.h" +#include "llnotificationsutil.h" +#include "llpresetsmanager.h" +#include "llradiogroup.h" +#include "lltrans.h" +#include "llvoavatarself.h" + +LLFloaterSaveCameraPreset::LLFloaterSaveCameraPreset(const LLSD &key) + : LLModalDialog(key) +{ +} + +// virtual +BOOL LLFloaterSaveCameraPreset::postBuild() +{ + mPresetCombo = getChild<LLComboBox>("preset_combo"); + + mNameEditor = getChild<LLLineEditor>("preset_txt_editor"); + mNameEditor->setKeystrokeCallback(boost::bind(&LLFloaterSaveCameraPreset::onPresetNameEdited, this), NULL); + + mSaveButton = getChild<LLButton>("save"); + mSaveButton->setCommitCallback(boost::bind(&LLFloaterSaveCameraPreset::onBtnSave, this)); + + mSaveRadioGroup = getChild<LLRadioGroup>("radio_save_preset"); + mSaveRadioGroup->setCommitCallback(boost::bind(&LLFloaterSaveCameraPreset::onSwitchSaveReplace, this)); + + getChild<LLButton>("cancel")->setCommitCallback(boost::bind(&LLFloaterSaveCameraPreset::onBtnCancel, this)); + + LLPresetsManager::instance().setPresetListChangeCallback(boost::bind(&LLFloaterSaveCameraPreset::onPresetsListChange, this)); + + return TRUE; +} + +void LLFloaterSaveCameraPreset::onPresetNameEdited() +{ + if (mSaveRadioGroup->getSelectedIndex() == 0) + { + // Disable saving a preset having empty name. + std::string name = mNameEditor->getValue(); + mSaveButton->setEnabled(!name.empty()); + } +} + +void LLFloaterSaveCameraPreset::onOpen(const LLSD& key) +{ + LLModalDialog::onOpen(key); + S32 index = 0; + if (key.has("index")) + { + index = key["index"].asInteger(); + } + + LLPresetsManager::getInstance()->setPresetNamesInComboBox(PRESETS_CAMERA, mPresetCombo, DEFAULT_BOTTOM); + + mSaveRadioGroup->setSelectedIndex(index); + onPresetNameEdited(); + onSwitchSaveReplace(); +} + +void LLFloaterSaveCameraPreset::onBtnSave() +{ + bool is_saving_new = mSaveRadioGroup->getSelectedIndex() == 0; + std::string name = is_saving_new ? mNameEditor->getText() : mPresetCombo->getSimple(); + + if ((name == LLTrans::getString(PRESETS_DEFAULT)) || (name == PRESETS_DEFAULT)) + { + LLNotificationsUtil::add("DefaultPresetNotSaved"); + } + else + { + if (isAgentAvatarValid() && gAgentAvatarp->getParent()) + { + gSavedSettings.setLLSD("AvatarSitRotation", gAgent.getFrameAgent().getQuaternion().getValue()); + } + if (gAgentCamera.isJoystickCameraUsed()) + { + gSavedSettings.setVector3("CameraOffsetRearView", gAgentCamera.getCurrentCameraOffset()); + gSavedSettings.setVector3d("FocusOffsetRearView", gAgentCamera.getCurrentFocusOffset()); + gAgentCamera.resetCameraZoomFraction(); + gAgentCamera.setFocusOnAvatar(TRUE, TRUE, FALSE); + } + else + { + LLVector3 camera_offset = gSavedSettings.getVector3("CameraOffsetRearView") * gAgentCamera.getCurrentCameraZoomFraction(); + gSavedSettings.setVector3("CameraOffsetRearView", camera_offset); + gAgentCamera.resetCameraZoomFraction(); + } + if (is_saving_new) + { + std::list<std::string> preset_names; + LLPresetsManager::getInstance()->loadPresetNamesFromDir(PRESETS_CAMERA, preset_names, DEFAULT_HIDE); + if (std::find(preset_names.begin(), preset_names.end(), name) != preset_names.end()) + { + LLSD args; + args["NAME"] = name; + LLNotificationsUtil::add("PresetAlreadyExists", args); + return; + } + } + if (!LLPresetsManager::getInstance()->savePreset(PRESETS_CAMERA, name)) + { + LLSD args; + args["NAME"] = name; + LLNotificationsUtil::add("PresetNotSaved", args); + } + } + + closeFloater(); +} + +void LLFloaterSaveCameraPreset::onPresetsListChange() +{ + LLPresetsManager::getInstance()->setPresetNamesInComboBox(PRESETS_CAMERA, mPresetCombo, DEFAULT_BOTTOM); +} + +void LLFloaterSaveCameraPreset::onBtnCancel() +{ + closeFloater(); +} + +void LLFloaterSaveCameraPreset::onSwitchSaveReplace() +{ + bool is_saving_new = mSaveRadioGroup->getSelectedIndex() == 0; + std::string label = is_saving_new ? getString("btn_label_save") : getString("btn_label_replace"); + mSaveButton->setLabel(label); + mNameEditor->setEnabled(is_saving_new); + mPresetCombo->setEnabled(!is_saving_new); + if (is_saving_new) + { + onPresetNameEdited(); + } + else + { + mSaveButton->setEnabled(true); + } +} diff --git a/indra/newview/llfloaterdeleteenvpreset.h b/indra/newview/llfloatersavecamerapreset.h index 1211505273..282f213438 100644 --- a/indra/newview/llfloaterdeleteenvpreset.h +++ b/indra/newview/llfloatersavecamerapreset.h @@ -1,10 +1,11 @@ /** - * @file llfloaterdeleteenvpreset.h - * @brief Floater to delete a water / sky / day cycle preset. + * @file llfloatersavecamerapreset.h + * @brief Floater to save a camera preset + * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2011, Linden Research, Inc. + * Copyright (C) 2020, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,39 +25,36 @@ * $/LicenseInfo$ */ -#ifndef LL_LLFLOATERDELETEENVPRESET_H -#define LL_LLFLOATERDELETEENVPRESET_H +#ifndef LL_LLFLOATERSAVECAMERAPRESET_H +#define LL_LLFLOATERSAVECAMERAPRESET_H -#include "llfloater.h" +#include "llmodaldialog.h" class LLComboBox; +class LLRadioGroup; +class LLLineEditor; -class LLFloaterDeleteEnvPreset : public LLFloater +class LLFloaterSaveCameraPreset : public LLModalDialog { - LOG_CLASS(LLFloaterDeleteEnvPreset); public: - LLFloaterDeleteEnvPreset(const LLSD &key); + LLFloaterSaveCameraPreset(const LLSD &key); /*virtual*/ BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); - void onBtnDelete(); + void onBtnSave(); void onBtnCancel(); + void onSwitchSaveReplace(); private: - void populatePresetsList(); - void populateWaterPresetsList(); - void populateSkyPresetsList(); - void populateDayCyclesList(); - - void postPopulate(); - - void onDeleteDayCycleConfirmation(); - void onDeleteSkyPresetConfirmation(); - void onDeleteWaterPresetConfirmation(); + LLRadioGroup* mSaveRadioGroup; + LLLineEditor* mNameEditor; + LLComboBox* mPresetCombo; + LLButton* mSaveButton; - LLComboBox* mPresetCombo; + void onPresetsListChange(); + void onPresetNameEdited(); }; -#endif // LL_LLFLOATERDELETEENVPRESET_H +#endif // LL_LLFLOATERSAVECAMERAPRESET_H diff --git a/indra/newview/llfloatersaveprefpreset.cpp b/indra/newview/llfloatersaveprefpreset.cpp index 684778c93a..dd47d02bfa 100644 --- a/indra/newview/llfloatersaveprefpreset.cpp +++ b/indra/newview/llfloatersaveprefpreset.cpp @@ -1,6 +1,6 @@ /** * @file llfloatersaveprefpreset.cpp - * @brief Floater to save a graphics / camera preset + * @brief Floater to save a graphics preset * * $LicenseInfo:firstyear=2014&license=viewerlgpl$ * Second Life Viewer Source Code @@ -37,24 +37,27 @@ #include "lltrans.h" LLFloaterSavePrefPreset::LLFloaterSavePrefPreset(const LLSD &key) -: LLFloater(key) + : LLFloater(key) { } // virtual BOOL LLFloaterSavePrefPreset::postBuild() -{ LLFloaterPreference* preferences = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences"); +{ + LLFloaterPreference* preferences = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences"); if (preferences) { preferences->addDependentFloater(this); } + getChild<LLComboBox>("preset_combo")->setTextEntryCallback(boost::bind(&LLFloaterSavePrefPreset::onPresetNameEdited, this)); getChild<LLComboBox>("preset_combo")->setCommitCallback(boost::bind(&LLFloaterSavePrefPreset::onPresetNameEdited, this)); getChild<LLButton>("save")->setCommitCallback(boost::bind(&LLFloaterSavePrefPreset::onBtnSave, this)); + getChild<LLButton>("cancel")->setCommitCallback(boost::bind(&LLFloaterSavePrefPreset::onBtnCancel, this)); LLPresetsManager::instance().setPresetListChangeCallback(boost::bind(&LLFloaterSavePrefPreset::onPresetsListChange, this)); - + mSaveButton = getChild<LLButton>("save"); mPresetCombo = getChild<LLComboBox>("preset_combo"); @@ -73,10 +76,6 @@ void LLFloaterSavePrefPreset::onOpen(const LLSD& key) { mSubdirectory = key.asString(); - std::string floater_title = getString(std::string("title_") + mSubdirectory); - - setTitle(floater_title); - EDefaultOptions option = DEFAULT_HIDE; LLPresetsManager::getInstance()->setPresetNamesInComboBox(mSubdirectory, mPresetCombo, option); @@ -87,7 +86,10 @@ void LLFloaterSavePrefPreset::onBtnSave() { std::string name = mPresetCombo->getSimple(); - if ((name == LLTrans::getString(PRESETS_DEFAULT)) || (name == PRESETS_DEFAULT)) + std::string upper_name(name); + LLStringUtil::toUpper(upper_name); + + if ((name == LLTrans::getString(PRESETS_DEFAULT)) || (upper_name == PRESETS_DEFAULT_UPPER)) { LLNotificationsUtil::add("DefaultPresetNotSaved"); } diff --git a/indra/newview/llfloatersaveprefpreset.h b/indra/newview/llfloatersaveprefpreset.h index 09a87b8c62..ae58180e7f 100644 --- a/indra/newview/llfloatersaveprefpreset.h +++ b/indra/newview/llfloatersaveprefpreset.h @@ -1,6 +1,6 @@ /** * @file llfloatersaveprefpreset.h - * @brief Floater to save a graphics / camera preset + * @brief Floater to save a graphics preset * * $LicenseInfo:firstyear=2014&license=viewerlgpl$ @@ -45,6 +45,7 @@ public: void onBtnCancel(); private: + LLComboBox* mPresetCombo; LLButton* mSaveButton; diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index d1246dae4c..779542cfcc 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -48,7 +48,7 @@ public: LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_THROTTLE) { } bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web) { - if (!LLUI::sSettingGroups["config"]->getBOOL("EnableSearch")) + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableSearch")) { LLNotificationsUtil::add("NoSearch", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); return true; diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index fb202b4c40..186994c857 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -111,6 +111,7 @@ void LLFloaterSettingsDebug::onCommitSettings() LLVector3 vector; LLVector3d vectord; + LLQuaternion quat; LLRect rect; LLColor4 col4; LLColor3 col3; @@ -146,6 +147,13 @@ void LLFloaterSettingsDebug::onCommitSettings() vectord.mdV[VZ] = getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); controlp->set(vectord.getValue()); break; + case TYPE_QUAT: + quat.mQ[VX] = getChild<LLUICtrl>("val_spinner_1")->getValue().asReal(); + quat.mQ[VY] = getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); + quat.mQ[VZ] = getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); + quat.mQ[VS] = getChild<LLUICtrl>("val_spinner_4")->getValue().asReal();; + controlp->set(quat.getValue()); + break; case TYPE_RECT: rect.mLeft = getChild<LLUICtrl>("val_spinner_1")->getValue().asInteger(); rect.mRight = getChild<LLUICtrl>("val_spinner_2")->getValue().asInteger(); @@ -351,6 +359,40 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) } break; } + case TYPE_QUAT: + { + LLQuaternion q; + q.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")); + spinner4->setVisible(TRUE); + spinner4->setLabel(std::string("S")); + if (!spinner1->hasFocus()) + { + spinner1->setPrecision(4); + spinner1->setValue(q.mQ[VX]); + } + if (!spinner2->hasFocus()) + { + spinner2->setPrecision(4); + spinner2->setValue(q.mQ[VY]); + } + if (!spinner3->hasFocus()) + { + spinner3->setPrecision(4); + spinner3->setValue(q.mQ[VZ]); + } + if (!spinner4->hasFocus()) + { + spinner4->setPrecision(4); + spinner4->setValue(q.mQ[VS]); + } + break; + } case TYPE_RECT: { LLRect r; diff --git a/indra/newview/llfloatersidepanelcontainer.cpp b/indra/newview/llfloatersidepanelcontainer.cpp index 64ddeff1b0..dd7ce40e97 100644 --- a/indra/newview/llfloatersidepanelcontainer.cpp +++ b/indra/newview/llfloatersidepanelcontainer.cpp @@ -60,7 +60,7 @@ void LLFloaterSidePanelContainer::onOpen(const LLSD& key) void LLFloaterSidePanelContainer::closeFloater(bool app_quitting) { LLPanelOutfitEdit* panel_outfit_edit = - dynamic_cast<LLPanelOutfitEdit*>(LLFloaterSidePanelContainer::getPanel("appearance", "panel_outfit_edit")); + dynamic_cast<LLPanelOutfitEdit*>(LLFloaterSidePanelContainer::findPanel("appearance", "panel_outfit_edit")); if (panel_outfit_edit) { LLFloater *parent = gFloaterView->getParentFloater(panel_outfit_edit); @@ -145,3 +145,15 @@ LLPanel* LLFloaterSidePanelContainer::getPanel(const std::string& floater_name, return NULL; } + +LLPanel* LLFloaterSidePanelContainer::findPanel(const std::string& floater_name, const std::string& panel_name) +{ + LLFloaterSidePanelContainer* floaterp = LLFloaterReg::findTypedInstance<LLFloaterSidePanelContainer>(floater_name); + + if (floaterp) + { + return floaterp->findChild<LLPanel>(panel_name, true); + } + + return NULL; +} diff --git a/indra/newview/llfloatersidepanelcontainer.h b/indra/newview/llfloatersidepanelcontainer.h index 635514e26c..20baf28184 100644 --- a/indra/newview/llfloatersidepanelcontainer.h +++ b/indra/newview/llfloatersidepanelcontainer.h @@ -62,6 +62,8 @@ public: static void showPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key); static LLPanel* getPanel(const std::string& floater_name, const std::string& panel_name = sMainPanelName); + + static LLPanel* findPanel(const std::string& floater_name, const std::string& panel_name = sMainPanelName); /** * Gets the panel of given type T (doesn't show it or do anything else with it). diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 2798e375c7..ef7a9fd536 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -29,8 +29,6 @@ #include "llfloatersnapshot.h" #include "llfloaterreg.h" -#include "llfloaterflickr.h" -#include "llfloatertwitter.h" #include "llimagefiltersmanager.h" #include "llcheckboxctrl.h" #include "llcombobox.h" @@ -1240,10 +1238,7 @@ BOOL LLFloaterSnapshot::isWaitingState() BOOL LLFloaterSnapshotBase::ImplBase::updatePreviewList(bool initialized) { - LLFloaterFlickr* floater_flickr = LLFloaterReg::findTypedInstance<LLFloaterFlickr>("flickr"); - LLFloaterTwitter* floater_twitter = LLFloaterReg::findTypedInstance<LLFloaterTwitter>("twitter"); - - if (!initialized && !floater_flickr && !floater_twitter) + if (!initialized) return FALSE; BOOL changed = FALSE; diff --git a/indra/newview/llfloatersnapshot.h b/indra/newview/llfloatersnapshot.h index bcba14d63d..8221b0a637 100644 --- a/indra/newview/llfloatersnapshot.h +++ b/indra/newview/llfloatersnapshot.h @@ -34,6 +34,7 @@ class LLSpinCtrl; class LLSnapshotLivePreview; +class LLToolset; class LLFloaterSnapshotBase : public LLFloater { diff --git a/indra/newview/llfloaterspellchecksettings.cpp b/indra/newview/llfloaterspellchecksettings.cpp index b87044ef5a..de5d59f484 100644 --- a/indra/newview/llfloaterspellchecksettings.cpp +++ b/indra/newview/llfloaterspellchecksettings.cpp @@ -56,7 +56,7 @@ void LLFloaterSpellCheckerSettings::draw() bool enable_remove = !sel_items.empty(); for (std::vector<LLScrollListItem*>::const_iterator sel_it = sel_items.begin(); sel_it != sel_items.end(); ++sel_it) { - enable_remove &= LLSpellChecker::canRemoveDictionary((*sel_it)->getValue().asString()); + enable_remove &= LLSpellChecker::getInstance()->canRemoveDictionary((*sel_it)->getValue().asString()); } getChild<LLUICtrl>("spellcheck_remove_btn")->setEnabled(enable_remove); } @@ -121,7 +121,7 @@ void LLFloaterSpellCheckerSettings::onClose(bool app_quitting) for (std::vector<LLScrollListItem*>::const_iterator item_it = list_items.begin(); item_it != list_items.end(); ++item_it) { const std::string language = (*item_it)->getValue().asString(); - if (LLSpellChecker::hasDictionary(language, true)) + if (LLSpellChecker::getInstance()->hasDictionary(language, true)) { list_dict.push_back(language); } @@ -164,7 +164,7 @@ void LLFloaterSpellCheckerSettings::refreshDictionaries(bool from_settings) } dict_combo->clearRows(); - const LLSD& dict_map = LLSpellChecker::getDictionaryMap(); + const LLSD& dict_map = LLSpellChecker::getInstance()->getDictionaryMap(); if (dict_map.size()) { for (LLSD::array_const_iterator dict_it = dict_map.beginArray(); dict_it != dict_map.endArray(); ++dict_it) @@ -216,7 +216,7 @@ void LLFloaterSpellCheckerSettings::refreshDictionaries(bool from_settings) for (LLSpellChecker::dict_list_t::const_iterator it = active_list.begin(); it != active_list.end(); ++it) { const std::string language = *it; - const LLSD dict = LLSpellChecker::getDictionaryData(language); + const LLSD dict = LLSpellChecker::getInstance()->getDictionaryData(language); row["value"] = language; row["columns"][0]["value"] = (!dict["user_installed"].asBoolean()) ? language : language + " " + LLTrans::getString("UserDictionary"); active_ctrl->addElement(row); @@ -380,7 +380,7 @@ void LLFloaterSpellCheckerImport::onBtnOK() custom_file_out.close(); } - LLSpellChecker::refreshDictionaryMap(); + LLSpellChecker::getInstance()->refreshDictionaryMap(); } closeFloater(false); diff --git a/indra/newview/llfloatertwitter.cpp b/indra/newview/llfloatertwitter.cpp deleted file mode 100644 index 2b33bc6935..0000000000 --- a/indra/newview/llfloatertwitter.cpp +++ /dev/null @@ -1,810 +0,0 @@ -/** -* @file llfloatertwitter.cpp -* @brief Implementation of llfloatertwitter -* @author cho@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 "llfloatertwitter.h" - -#include "llagent.h" -#include "llagentui.h" -#include "llcheckboxctrl.h" -#include "llcombobox.h" -#include "lltwitterconnect.h" -#include "llfloaterbigpreview.h" -#include "llfloaterreg.h" -#include "lliconctrl.h" -#include "llimagefiltersmanager.h" -#include "llresmgr.h" // LLLocale -#include "llsdserialize.h" -#include "llloadingindicator.h" -#include "llslurl.h" -#include "lltrans.h" -#include "llsnapshotlivepreview.h" -#include "llviewerregion.h" -#include "llviewercontrol.h" -#include "llviewermedia.h" -#include "lltabcontainer.h" -#include "lltexteditor.h" - -static LLPanelInjector<LLTwitterPhotoPanel> t_panel_photo("lltwitterphotopanel"); -static LLPanelInjector<LLTwitterAccountPanel> t_panel_account("lltwitteraccountpanel"); - -const std::string DEFAULT_PHOTO_LOCATION_URL = "http://maps.secondlife.com/"; -const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=twitter&utm_medium=photo&utm_campaign=slshare"; -const std::string DEFAULT_STATUS_TEXT = " #SecondLife"; - -/////////////////////////// -//LLTwitterPhotoPanel/////// -/////////////////////////// - -LLTwitterPhotoPanel::LLTwitterPhotoPanel() : -mResolutionComboBox(NULL), -mRefreshBtn(NULL), -mBtnPreview(NULL), -mWorkingLabel(NULL), -mThumbnailPlaceholder(NULL), -mStatusCounterLabel(NULL), -mStatusTextBox(NULL), -mLocationCheckbox(NULL), -mPhotoCheckbox(NULL), -mBigPreviewFloater(NULL), -mPostButton(NULL) -{ - mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", boost::bind(&LLTwitterPhotoPanel::onSend, this)); - mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", boost::bind(&LLTwitterPhotoPanel::onClickNewSnapshot, this)); - mCommitCallbackRegistrar.add("SocialSharing.BigPreview", boost::bind(&LLTwitterPhotoPanel::onClickBigPreview, this)); -} - -LLTwitterPhotoPanel::~LLTwitterPhotoPanel() -{ - if(mPreviewHandle.get()) - { - mPreviewHandle.get()->die(); - } -} - -BOOL LLTwitterPhotoPanel::postBuild() -{ - setVisibleCallback(boost::bind(&LLTwitterPhotoPanel::onVisibilityChange, this, _2)); - - mResolutionComboBox = getChild<LLUICtrl>("resolution_combobox"); - mResolutionComboBox->setValue("[i800,i600]"); // hardcoded defaults ftw! - mResolutionComboBox->setCommitCallback(boost::bind(&LLTwitterPhotoPanel::updateResolution, this, TRUE)); - mFilterComboBox = getChild<LLUICtrl>("filters_combobox"); - mFilterComboBox->setCommitCallback(boost::bind(&LLTwitterPhotoPanel::updateResolution, this, TRUE)); - mRefreshBtn = getChild<LLUICtrl>("new_snapshot_btn"); - mBtnPreview = getChild<LLButton>("big_preview_btn"); - mWorkingLabel = getChild<LLUICtrl>("working_lbl"); - mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder"); - mStatusCounterLabel = getChild<LLUICtrl>("status_counter_label"); - mStatusTextBox = getChild<LLUICtrl>("photo_status"); - mStatusTextBox->setValue(DEFAULT_STATUS_TEXT); - mLocationCheckbox = getChild<LLUICtrl>("add_location_cb"); - mLocationCheckbox->setCommitCallback(boost::bind(&LLTwitterPhotoPanel::onAddLocationToggled, this)); - mPhotoCheckbox = getChild<LLUICtrl>("add_photo_cb"); - mPhotoCheckbox->setCommitCallback(boost::bind(&LLTwitterPhotoPanel::onAddPhotoToggled, this)); - mPostButton = getChild<LLUICtrl>("post_photo_btn"); - mCancelButton = getChild<LLUICtrl>("cancel_photo_btn"); - mBigPreviewFloater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview")); - - // Update filter list - std::vector<std::string> filter_list = LLImageFiltersManager::getInstance()->getFiltersList(); - LLComboBox* filterbox = static_cast<LLComboBox *>(mFilterComboBox); - for (U32 i = 0; i < filter_list.size(); i++) - { - filterbox->add(filter_list[i]); - } - - return LLPanel::postBuild(); -} - -// virtual -S32 LLTwitterPhotoPanel::notify(const LLSD& info) -{ - if (info.has("snapshot-updating")) - { - // Disable the Post button and whatever else while the snapshot is not updated - // updateControls(); - return 1; - } - - if (info.has("snapshot-updated")) - { - // Enable the send/post/save buttons. - updateControls(); - - // The refresh button is initially hidden. We show it after the first update, - // i.e. after snapshot is taken - LLUICtrl * refresh_button = getRefreshBtn(); - if (!refresh_button->getVisible()) - { - refresh_button->setVisible(true); - } - return 1; - } - - return 0; -} - -void LLTwitterPhotoPanel::draw() -{ - LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get()); - - // Enable interaction only if no transaction with the service is on-going (prevent duplicated posts) - bool no_ongoing_connection = !(LLTwitterConnect::instance().isTransactionOngoing()); - bool photo_checked = mPhotoCheckbox->getValue().asBoolean(); - mCancelButton->setEnabled(no_ongoing_connection); - mStatusTextBox->setEnabled(no_ongoing_connection); - mResolutionComboBox->setEnabled(no_ongoing_connection && photo_checked); - mFilterComboBox->setEnabled(no_ongoing_connection && photo_checked); - mRefreshBtn->setEnabled(no_ongoing_connection && photo_checked); - mBtnPreview->setEnabled(no_ongoing_connection); - mLocationCheckbox->setEnabled(no_ongoing_connection); - mPhotoCheckbox->setEnabled(no_ongoing_connection); - - bool add_location = mLocationCheckbox->getValue().asBoolean(); - bool add_photo = mPhotoCheckbox->getValue().asBoolean(); - updateStatusTextLength(false); - - // Reassign the preview floater if we have the focus and the preview exists - if (hasFocus() && isPreviewVisible()) - { - attachPreview(); - } - - // Toggle the button state as appropriate - bool preview_active = (isPreviewVisible() && mBigPreviewFloater->isFloaterOwner(getParentByType<LLFloater>())); - mBtnPreview->setToggleState(preview_active); - - // Display the preview if one is available - if (previewp && previewp->getThumbnailImage()) - { - const LLRect& thumbnail_rect = mThumbnailPlaceholder->getRect(); - const S32 thumbnail_w = previewp->getThumbnailWidth(); - const S32 thumbnail_h = previewp->getThumbnailHeight(); - - // calc preview offset within the preview rect - const S32 local_offset_x = (thumbnail_rect.getWidth() - thumbnail_w) / 2 ; - const S32 local_offset_y = (thumbnail_rect.getHeight() - thumbnail_h) / 2 ; - S32 offset_x = thumbnail_rect.mLeft + local_offset_x; - S32 offset_y = thumbnail_rect.mBottom + local_offset_y; - - gGL.matrixMode(LLRender::MM_MODELVIEW); - // Apply floater transparency to the texture unless the floater is focused. - F32 alpha = (add_photo ? (getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency()) : 0.5f); - LLColor4 color = LLColor4::white; - gl_draw_scaled_image(offset_x, offset_y, - thumbnail_w, thumbnail_h, - previewp->getThumbnailImage(), color % alpha); - } - - // Update the visibility of the working (computing preview) label - mWorkingLabel->setVisible(!(previewp && previewp->getSnapshotUpToDate())); - - // Enable Post if we have a preview to send and no on going connection being processed - mPostButton->setEnabled(no_ongoing_connection && (previewp && previewp->getSnapshotUpToDate()) && (add_photo || add_location || !mStatusTextBox->getValue().asString().empty())); - - // Draw the rest of the panel on top of it - LLPanel::draw(); -} - -LLSnapshotLivePreview* LLTwitterPhotoPanel::getPreviewView() -{ - LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)mPreviewHandle.get(); - return previewp; -} - -void LLTwitterPhotoPanel::onVisibilityChange(BOOL visible) -{ - if (visible) - { - if (mPreviewHandle.get()) - { - LLSnapshotLivePreview* preview = getPreviewView(); - if(preview) - { - LL_DEBUGS() << "opened, updating snapshot" << LL_ENDL; - preview->updateSnapshot(TRUE); - } - } - else - { - LLRect full_screen_rect = getRootView()->getRect(); - LLSnapshotLivePreview::Params p; - p.rect(full_screen_rect); - LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p); - mPreviewHandle = previewp->getHandle(); - - previewp->setContainer(this); - previewp->setSnapshotType(LLSnapshotModel::SNAPSHOT_WEB); - previewp->setSnapshotFormat(LLSnapshotModel::SNAPSHOT_FORMAT_JPEG); - previewp->setThumbnailSubsampled(TRUE); // We want the preview to reflect the *saved* image - previewp->setAllowRenderUI(FALSE); // We do not want the rendered UI in our snapshots - previewp->setAllowFullScreenPreview(FALSE); // No full screen preview in SL Share mode - previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect()); - - updateControls(); - } - } -} - -void LLTwitterPhotoPanel::onAddLocationToggled() -{ - bool add_location = mLocationCheckbox->getValue().asBoolean(); - updateStatusTextLength(!add_location); -} - -void LLTwitterPhotoPanel::onAddPhotoToggled() -{ - bool add_photo = mPhotoCheckbox->getValue().asBoolean(); - updateStatusTextLength(!add_photo); -} - -void LLTwitterPhotoPanel::onClickNewSnapshot() -{ - LLSnapshotLivePreview* previewp = getPreviewView(); - if (previewp) - { - previewp->updateSnapshot(TRUE); - } -} - -void LLTwitterPhotoPanel::onClickBigPreview() -{ - // Toggle the preview - if (isPreviewVisible()) - { - LLFloaterReg::hideInstance("big_preview"); - } - else - { - attachPreview(); - LLFloaterReg::showInstance("big_preview"); - } -} - -bool LLTwitterPhotoPanel::isPreviewVisible() -{ - return (mBigPreviewFloater && mBigPreviewFloater->getVisible()); -} - -void LLTwitterPhotoPanel::attachPreview() -{ - if (mBigPreviewFloater) - { - LLSnapshotLivePreview* previewp = getPreviewView(); - mBigPreviewFloater->setPreview(previewp); - mBigPreviewFloater->setFloaterOwner(getParentByType<LLFloater>()); - } -} - -void LLTwitterPhotoPanel::onSend() -{ - LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterPhotoPanel"); // just in case it is already listening - LLEventPumps::instance().obtain("TwitterConnectState").listen("LLTwitterPhotoPanel", boost::bind(&LLTwitterPhotoPanel::onTwitterConnectStateChange, this, _1)); - - // Connect to Twitter if necessary and then post - if (LLTwitterConnect::instance().isConnected()) - { - sendPhoto(); - } - else - { - LLTwitterConnect::instance().checkConnectionToTwitter(true); - } -} - -bool LLTwitterPhotoPanel::onTwitterConnectStateChange(const LLSD& data) -{ - switch (data.get("enum").asInteger()) - { - case LLTwitterConnect::TWITTER_CONNECTED: - sendPhoto(); - break; - - case LLTwitterConnect::TWITTER_POSTED: - LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterPhotoPanel"); - clearAndClose(); - break; - } - - return false; -} - -void LLTwitterPhotoPanel::sendPhoto() -{ - // Get the status text - std::string status = mStatusTextBox->getValue().asString(); - - // Add the location if required - bool add_location = mLocationCheckbox->getValue().asBoolean(); - if (add_location) - { - // Get the SLURL for the location - LLSLURL slurl; - LLAgentUI::buildSLURL(slurl); - std::string slurl_string = slurl.getSLURLString(); - - // Use a valid http:// URL if the scheme is secondlife:// - LLURI slurl_uri(slurl_string); - if (slurl_uri.scheme() == LLSLURL::SLURL_SECONDLIFE_SCHEME) - { - slurl_string = DEFAULT_PHOTO_LOCATION_URL; - } - - // Add query parameters so Google Analytics can track incoming clicks! - slurl_string += DEFAULT_PHOTO_QUERY_PARAMETERS; - - // Add it to the status (pretty crude, but we don't have a better option with photos) - if (status.empty()) - status = slurl_string; - else - status = status + " " + slurl_string; - } - - // Add the photo if required - bool add_photo = mPhotoCheckbox->getValue().asBoolean(); - if (add_photo) - { - // Get the image - LLSnapshotLivePreview* previewp = getPreviewView(); - - // Post to Twitter - LLTwitterConnect::instance().uploadPhoto(previewp->getFormattedImage(), status); - } - else - { - // Just post the status to Twitter - LLTwitterConnect::instance().updateStatus(status); - } - - updateControls(); -} - -void LLTwitterPhotoPanel::clearAndClose() -{ - mStatusTextBox->setValue(DEFAULT_STATUS_TEXT); - - LLFloater* floater = getParentByType<LLFloater>(); - if (floater) - { - floater->closeFloater(); - if (mBigPreviewFloater) - { - mBigPreviewFloater->closeOnFloaterOwnerClosing(floater); - } - } -} - -void LLTwitterPhotoPanel::updateStatusTextLength(BOOL restore_old_status_text) -{ - bool add_location = mLocationCheckbox->getValue().asBoolean(); - - // Restrict the status text length to Twitter's character limit - LLTextEditor* status_text_box = dynamic_cast<LLTextEditor*>(mStatusTextBox); - if (status_text_box) - { - int max_status_length = 280 - (add_location ? 40 : 0); - status_text_box->setMaxTextLength(max_status_length); - if (restore_old_status_text) - { - if (mOldStatusText.length() > status_text_box->getText().length() && status_text_box->getText() == mOldStatusText.substr(0, status_text_box->getText().length())) - { - status_text_box->setText(mOldStatusText); - } - if (mOldStatusText.length() <= max_status_length) - { - mOldStatusText = ""; - } - } - if (status_text_box->getText().length() > max_status_length) - { - if (mOldStatusText.length() < status_text_box->getText().length() || status_text_box->getText() != mOldStatusText.substr(0, status_text_box->getText().length())) - { - mOldStatusText = status_text_box->getText(); - } - status_text_box->setText(mOldStatusText.substr(0, max_status_length)); - } - - // Update the status character counter - int characters_remaining = max_status_length - status_text_box->getText().length(); - mStatusCounterLabel->setValue(characters_remaining); - } - -} - -void LLTwitterPhotoPanel::updateControls() -{ - LLSnapshotLivePreview* previewp = getPreviewView(); - BOOL got_snap = previewp && previewp->getSnapshotUpToDate(); - - // *TODO: Separate maximum size for Web images from postcards - LL_DEBUGS() << "Is snapshot up-to-date? " << got_snap << LL_ENDL; - - updateResolution(FALSE); -} - -void LLTwitterPhotoPanel::updateResolution(BOOL do_update) -{ - LLComboBox* combobox = static_cast<LLComboBox *>(mResolutionComboBox); - LLComboBox* filterbox = static_cast<LLComboBox *>(mFilterComboBox); - - std::string sdstring = combobox->getSelectedValue(); - LLSD sdres; - std::stringstream sstream(sdstring); - LLSDSerialize::fromNotation(sdres, sstream, sdstring.size()); - - S32 width = sdres[0]; - S32 height = sdres[1]; - - // Note : index 0 of the filter drop down is assumed to be "No filter" in whichever locale - std::string filter_name = (filterbox->getCurrentIndex() ? filterbox->getSimple() : ""); - - LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get()); - if (previewp && combobox->getCurrentIndex() >= 0) - { - S32 original_width = 0 , original_height = 0 ; - previewp->getSize(original_width, original_height) ; - - if (width == 0 || height == 0) - { - // take resolution from current window size - LL_DEBUGS() << "Setting preview res from window: " << gViewerWindow->getWindowWidthRaw() << "x" << gViewerWindow->getWindowHeightRaw() << LL_ENDL; - previewp->setSize(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw()); - } - else - { - // use the resolution from the selected pre-canned drop-down choice - LL_DEBUGS() << "Setting preview res selected from combo: " << width << "x" << height << LL_ENDL; - previewp->setSize(width, height); - } - - checkAspectRatio(width); - - previewp->getSize(width, height); - - if (original_width != width || original_height != height) - { - previewp->setSize(width, height); - if (do_update) - { - previewp->updateSnapshot(TRUE); - updateControls(); - } - } - // Get the old filter, compare to the current one "filter_name" and set if changed - std::string original_filter = previewp->getFilter(); - if (original_filter != filter_name) - { - previewp->setFilter(filter_name); - if (do_update) - { - previewp->updateSnapshot(FALSE, TRUE); - updateControls(); - } - } - } -} - -void LLTwitterPhotoPanel::checkAspectRatio(S32 index) -{ - LLSnapshotLivePreview *previewp = getPreviewView() ; - - BOOL keep_aspect = FALSE; - - if (0 == index) // current window size - { - keep_aspect = TRUE; - } - else // predefined resolution - { - keep_aspect = FALSE; - } - - if (previewp) - { - previewp->mKeepAspectRatio = keep_aspect; - } -} - -LLUICtrl* LLTwitterPhotoPanel::getRefreshBtn() -{ - return mRefreshBtn; -} - -/////////////////////////// -//LLTwitterAccountPanel////// -/////////////////////////// - -LLTwitterAccountPanel::LLTwitterAccountPanel() : -mAccountCaptionLabel(NULL), -mAccountNameLabel(NULL), -mPanelButtons(NULL), -mConnectButton(NULL), -mDisconnectButton(NULL) -{ - mCommitCallbackRegistrar.add("SocialSharing.Connect", boost::bind(&LLTwitterAccountPanel::onConnect, this)); - mCommitCallbackRegistrar.add("SocialSharing.Disconnect", boost::bind(&LLTwitterAccountPanel::onDisconnect, this)); - - setVisibleCallback(boost::bind(&LLTwitterAccountPanel::onVisibilityChange, this, _2)); -} - -BOOL LLTwitterAccountPanel::postBuild() -{ - mAccountCaptionLabel = getChild<LLTextBox>("account_caption_label"); - mAccountNameLabel = getChild<LLTextBox>("account_name_label"); - mPanelButtons = getChild<LLUICtrl>("panel_buttons"); - mConnectButton = getChild<LLUICtrl>("connect_btn"); - mDisconnectButton = getChild<LLUICtrl>("disconnect_btn"); - - return LLPanel::postBuild(); -} - -void LLTwitterAccountPanel::draw() -{ - LLTwitterConnect::EConnectionState connection_state = LLTwitterConnect::instance().getConnectionState(); - - //Disable the 'disconnect' button and the 'use another account' button when disconnecting in progress - bool disconnecting = connection_state == LLTwitterConnect::TWITTER_DISCONNECTING; - mDisconnectButton->setEnabled(!disconnecting); - - //Disable the 'connect' button when a connection is in progress - bool connecting = connection_state == LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS; - mConnectButton->setEnabled(!connecting); - - LLPanel::draw(); -} - -void LLTwitterAccountPanel::onVisibilityChange(BOOL visible) -{ - if(visible) - { - LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterAccountPanel"); - LLEventPumps::instance().obtain("TwitterConnectState").listen("LLTwitterAccountPanel", boost::bind(&LLTwitterAccountPanel::onTwitterConnectStateChange, this, _1)); - - LLEventPumps::instance().obtain("TwitterConnectInfo").stopListening("LLTwitterAccountPanel"); - LLEventPumps::instance().obtain("TwitterConnectInfo").listen("LLTwitterAccountPanel", boost::bind(&LLTwitterAccountPanel::onTwitterConnectInfoChange, this)); - - //Connected - if(LLTwitterConnect::instance().isConnected()) - { - showConnectedLayout(); - } - //Check if connected (show disconnected layout in meantime) - else - { - showDisconnectedLayout(); - } - if ((LLTwitterConnect::instance().getConnectionState() == LLTwitterConnect::TWITTER_NOT_CONNECTED) || - (LLTwitterConnect::instance().getConnectionState() == LLTwitterConnect::TWITTER_CONNECTION_FAILED)) - { - LLTwitterConnect::instance().checkConnectionToTwitter(); - } - } - else - { - LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterAccountPanel"); - LLEventPumps::instance().obtain("TwitterConnectInfo").stopListening("LLTwitterAccountPanel"); - } -} - -bool LLTwitterAccountPanel::onTwitterConnectStateChange(const LLSD& data) -{ - if(LLTwitterConnect::instance().isConnected()) - { - //In process of disconnecting so leave the layout as is - if(data.get("enum").asInteger() != LLTwitterConnect::TWITTER_DISCONNECTING) - { - showConnectedLayout(); - } - } - else - { - showDisconnectedLayout(); - } - - return false; -} - -bool LLTwitterAccountPanel::onTwitterConnectInfoChange() -{ - LLSD info = LLTwitterConnect::instance().getInfo(); - std::string clickable_name; - - //Strings of format [http://www.somewebsite.com Click Me] become clickable text - if(info.has("link") && info.has("name")) - { - clickable_name = "[" + info["link"].asString() + " " + info["name"].asString() + "]"; - } - - mAccountNameLabel->setText(clickable_name); - - return false; -} - -void LLTwitterAccountPanel::showConnectButton() -{ - if(!mConnectButton->getVisible()) - { - mConnectButton->setVisible(TRUE); - mDisconnectButton->setVisible(FALSE); - } -} - -void LLTwitterAccountPanel::hideConnectButton() -{ - if(mConnectButton->getVisible()) - { - mConnectButton->setVisible(FALSE); - mDisconnectButton->setVisible(TRUE); - } -} - -void LLTwitterAccountPanel::showDisconnectedLayout() -{ - mAccountCaptionLabel->setText(getString("twitter_disconnected")); - mAccountNameLabel->setText(std::string("")); - showConnectButton(); -} - -void LLTwitterAccountPanel::showConnectedLayout() -{ - LLTwitterConnect::instance().loadTwitterInfo(); - - mAccountCaptionLabel->setText(getString("twitter_connected")); - hideConnectButton(); -} - -void LLTwitterAccountPanel::onConnect() -{ - LLTwitterConnect::instance().checkConnectionToTwitter(true); -} - -void LLTwitterAccountPanel::onDisconnect() -{ - LLTwitterConnect::instance().disconnectFromTwitter(); -} - -//////////////////////// -//LLFloaterTwitter/////// -//////////////////////// - -LLFloaterTwitter::LLFloaterTwitter(const LLSD& key) : LLFloater(key), - mTwitterPhotoPanel(NULL), - mStatusErrorText(NULL), - mStatusLoadingText(NULL), - mStatusLoadingIndicator(NULL) -{ - mCommitCallbackRegistrar.add("SocialSharing.Cancel", boost::bind(&LLFloaterTwitter::onCancel, this)); -} - -void LLFloaterTwitter::onClose(bool app_quitting) -{ - LLFloaterBigPreview* big_preview_floater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview")); - if (big_preview_floater) - { - big_preview_floater->closeOnFloaterOwnerClosing(this); - } - LLFloater::onClose(app_quitting); -} - -void LLFloaterTwitter::onCancel() -{ - LLFloaterBigPreview* big_preview_floater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview")); - if (big_preview_floater) - { - big_preview_floater->closeOnFloaterOwnerClosing(this); - } - closeFloater(); -} - -BOOL LLFloaterTwitter::postBuild() -{ - // Keep tab of the Photo Panel - mTwitterPhotoPanel = static_cast<LLTwitterPhotoPanel*>(getChild<LLUICtrl>("panel_twitter_photo")); - // Connection status widgets - mStatusErrorText = getChild<LLTextBox>("connection_error_text"); - mStatusLoadingText = getChild<LLTextBox>("connection_loading_text"); - mStatusLoadingIndicator = getChild<LLUICtrl>("connection_loading_indicator"); - return LLFloater::postBuild(); -} - -void LLFloaterTwitter::showPhotoPanel() -{ - LLTabContainer* parent = dynamic_cast<LLTabContainer*>(mTwitterPhotoPanel->getParent()); - if (!parent) - { - LL_WARNS() << "Cannot find panel container" << LL_ENDL; - return; - } - - parent->selectTabPanel(mTwitterPhotoPanel); -} - -void LLFloaterTwitter::draw() -{ - if (mStatusErrorText && mStatusLoadingText && mStatusLoadingIndicator) - { - mStatusErrorText->setVisible(false); - mStatusLoadingText->setVisible(false); - mStatusLoadingIndicator->setVisible(false); - LLTwitterConnect::EConnectionState connection_state = LLTwitterConnect::instance().getConnectionState(); - std::string status_text; - - switch (connection_state) - { - case LLTwitterConnect::TWITTER_NOT_CONNECTED: - // No status displayed when first opening the panel and no connection done - case LLTwitterConnect::TWITTER_CONNECTED: - // When successfully connected, no message is displayed - case LLTwitterConnect::TWITTER_POSTED: - // No success message to show since we actually close the floater after successful posting completion - break; - case LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS: - // Connection loading indicator - mStatusLoadingText->setVisible(true); - status_text = LLTrans::getString("SocialTwitterConnecting"); - mStatusLoadingText->setValue(status_text); - mStatusLoadingIndicator->setVisible(true); - break; - case LLTwitterConnect::TWITTER_POSTING: - // Posting indicator - mStatusLoadingText->setVisible(true); - status_text = LLTrans::getString("SocialTwitterPosting"); - mStatusLoadingText->setValue(status_text); - mStatusLoadingIndicator->setVisible(true); - break; - case LLTwitterConnect::TWITTER_CONNECTION_FAILED: - // Error connecting to the service - mStatusErrorText->setVisible(true); - status_text = LLTrans::getString("SocialTwitterErrorConnecting"); - mStatusErrorText->setValue(status_text); - break; - case LLTwitterConnect::TWITTER_POST_FAILED: - // Error posting to the service - mStatusErrorText->setVisible(true); - status_text = LLTrans::getString("SocialTwitterErrorPosting"); - mStatusErrorText->setValue(status_text); - break; - case LLTwitterConnect::TWITTER_DISCONNECTING: - // Disconnecting loading indicator - mStatusLoadingText->setVisible(true); - status_text = LLTrans::getString("SocialTwitterDisconnecting"); - mStatusLoadingText->setValue(status_text); - mStatusLoadingIndicator->setVisible(true); - break; - case LLTwitterConnect::TWITTER_DISCONNECT_FAILED: - // Error disconnecting from the service - mStatusErrorText->setVisible(true); - status_text = LLTrans::getString("SocialTwitterErrorDisconnecting"); - mStatusErrorText->setValue(status_text); - break; - } - } - LLFloater::draw(); -} - diff --git a/indra/newview/llfloatertwitter.h b/indra/newview/llfloatertwitter.h deleted file mode 100644 index d586799d18..0000000000 --- a/indra/newview/llfloatertwitter.h +++ /dev/null @@ -1,138 +0,0 @@ -/** -* @file llfloatertwitter.h -* @brief Header file for llfloatertwitter -* @author cho@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_LLFLOATERTWITTER_H -#define LL_LLFLOATERTWITTER_H - -#include "llfloater.h" -#include "lltextbox.h" -#include "llviewertexture.h" - -class LLIconCtrl; -class LLCheckBoxCtrl; -class LLSnapshotLivePreview; -class LLFloaterBigPreview; - -class LLTwitterPhotoPanel : public LLPanel -{ -public: - LLTwitterPhotoPanel(); - ~LLTwitterPhotoPanel(); - - BOOL postBuild(); - void draw(); - - LLSnapshotLivePreview* getPreviewView(); - void onVisibilityChange(BOOL new_visibility); - void onAddLocationToggled(); - void onAddPhotoToggled(); - void onClickBigPreview(); - void onClickNewSnapshot(); - void onSend(); - S32 notify(const LLSD& info); - bool onTwitterConnectStateChange(const LLSD& data); - - void sendPhoto(); - void clearAndClose(); - - void updateStatusTextLength(BOOL restore_old_status_text); - void updateControls(); - void updateResolution(BOOL do_update); - void checkAspectRatio(S32 index); - LLUICtrl* getRefreshBtn(); - -private: - bool isPreviewVisible(); - void attachPreview(); - - LLHandle<LLView> mPreviewHandle; - - LLUICtrl * mResolutionComboBox; - LLUICtrl * mFilterComboBox; - LLUICtrl * mRefreshBtn; - LLUICtrl * mWorkingLabel; - LLUICtrl * mThumbnailPlaceholder; - LLUICtrl * mStatusCounterLabel; - LLUICtrl * mStatusTextBox; - LLUICtrl * mLocationCheckbox; - LLUICtrl * mPhotoCheckbox; - LLUICtrl * mPostButton; - LLUICtrl * mCancelButton; - LLButton * mBtnPreview; - - LLFloaterBigPreview * mBigPreviewFloater; - - std::string mOldStatusText; -}; - -class LLTwitterAccountPanel : public LLPanel -{ -public: - LLTwitterAccountPanel(); - BOOL postBuild(); - void draw(); - -private: - void onVisibilityChange(BOOL new_visibility); - bool onTwitterConnectStateChange(const LLSD& data); - bool onTwitterConnectInfoChange(); - void onConnect(); - void onUseAnotherAccount(); - void onDisconnect(); - - void showConnectButton(); - void hideConnectButton(); - void showDisconnectedLayout(); - void showConnectedLayout(); - - LLTextBox * mAccountCaptionLabel; - LLTextBox * mAccountNameLabel; - LLUICtrl * mPanelButtons; - LLUICtrl * mConnectButton; - LLUICtrl * mDisconnectButton; -}; - - -class LLFloaterTwitter : public LLFloater -{ -public: - LLFloaterTwitter(const LLSD& key); - BOOL postBuild(); - void draw(); - void onClose(bool app_quitting); - void onCancel(); - - void showPhotoPanel(); - -private: - LLTwitterPhotoPanel* mTwitterPhotoPanel; - LLTextBox* mStatusErrorText; - LLTextBox* mStatusLoadingText; - LLUICtrl* mStatusLoadingIndicator; -}; - -#endif // LL_LLFLOATERTWITTER_H - diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 211371571d..9d16faf0b5 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -291,8 +291,8 @@ bool LLPreviewedFloater::sShowRectangles = false; // Changes are made here LLLocalizationResetForcer::LLLocalizationResetForcer(LLFloaterUIPreview* floater, S32 ID) { - mSavedLocalization = LLUI::sSettingGroups["config"]->getString("Language"); // save current localization setting - LLUI::sSettingGroups["config"]->setString("Language", floater->getLocStr(ID));// hack language to be the one we want to preview floaters in + mSavedLocalization = LLUI::getInstance()->mSettingGroups["config"]->getString("Language"); // save current localization setting + LLUI::getInstance()->mSettingGroups["config"]->setString("Language", floater->getLocStr(ID));// hack language to be the one we want to preview floaters in // forcibly reset XUI paths with this new language gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), floater->getLocStr(ID)); } @@ -301,7 +301,7 @@ LLLocalizationResetForcer::LLLocalizationResetForcer(LLFloaterUIPreview* floater // Changes are reversed here LLLocalizationResetForcer::~LLLocalizationResetForcer() { - LLUI::sSettingGroups["config"]->setString("Language", mSavedLocalization); // reset language to what it was before we changed it + LLUI::getInstance()->mSettingGroups["config"]->setString("Language", mSavedLocalization); // reset language to what it was before we changed it // forcibly reset XUI paths with this new language gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), mSavedLocalization); } diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index f2efef0c33..63bce3d2eb 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -122,8 +122,7 @@ void LLFloaterURLEntry::headerFetchComplete(S32 status, const std::string& mime_ } } - // Decrement the cursor - getWindow()->decBusyCount(); + getChildView("loading_label")->setVisible( false); closeFloater(); } @@ -302,3 +301,9 @@ bool LLFloaterURLEntry::callback_clear_url_list(const LLSD& notification, const } return false; } + +void LLFloaterURLEntry::onClose( bool app_quitting ) +{ + // Decrement the cursor + getWindow()->decBusyCount(); +} diff --git a/indra/newview/llfloaterurlentry.h b/indra/newview/llfloaterurlentry.h index 20f4604907..04a8eca069 100644 --- a/indra/newview/llfloaterurlentry.h +++ b/indra/newview/llfloaterurlentry.h @@ -42,6 +42,7 @@ public: // that panel via the handle. static LLHandle<LLFloater> show(LLHandle<LLPanel> panel_land_media_handle, const std::string media_url); /*virtual*/ BOOL postBuild(); + /*virtual*/ void onClose( bool app_quitting ); void headerFetchComplete(S32 status, const std::string& mime_type); bool addURLToCombobox(const std::string& media_url); diff --git a/indra/newview/llfloatervoicevolume.cpp b/indra/newview/llfloatervoicevolume.cpp index 38446e46df..59e1f49f81 100644 --- a/indra/newview/llfloatervoicevolume.cpp +++ b/indra/newview/llfloatervoicevolume.cpp @@ -127,7 +127,7 @@ void LLFloaterVoiceVolume::onOpen(const LLSD& data) // Extract appropriate avatar id mAvatarID = data["avatar_id"]; - LLUI::positionViewNearMouse(this); + LLUI::getInstance()->positionViewNearMouse(this); getChild<LLUICtrl>("avatar_name")->setValue(""); updateVolumeControls(); diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp index 13953d6be5..23fd6d9c8e 100644 --- a/indra/newview/llfloaterwebcontent.cpp +++ b/indra/newview/llfloaterwebcontent.cpp @@ -30,8 +30,6 @@ #include "lliconctrl.h" #include "llfloaterreg.h" #include "llhttpconstants.h" -#include "llflickrconnect.h" -#include "lltwitterconnect.h" #include "lllayoutstack.h" #include "llpluginclassmedia.h" #include "llprogressbar.h" @@ -234,7 +232,7 @@ void LLFloaterWebContent::preCreate(LLFloaterWebContent::Params& p) void LLFloaterWebContent::open_media(const Params& p) { - LLViewerMedia::proxyWindowOpened(p.target(), p.id()); + LLViewerMedia::getInstance()->proxyWindowOpened(p.target(), p.id()); mWebBrowser->setHomePageUrl(p.url); mWebBrowser->setTarget(p.target); mWebBrowser->navigateTo(p.url); @@ -288,27 +286,7 @@ void LLFloaterWebContent::onOpen(const LLSD& key) //virtual void LLFloaterWebContent::onClose(bool app_quitting) { - // If we close the web browsing window showing the Flickr login, we need to signal to this object that the connection will not happen - // MAINT-3440 note change here to use findInstance and not getInstance - latter creates an instance if it's not there which is bad. - LLFloater* flickr_web = LLFloaterReg::findInstance("flickr_web"); - if (flickr_web == this) - { - if (!LLFlickrConnect::instance().isConnected()) - { - LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED); - } - } - // Same with Twitter - // MAINT-3440 note change here to use findInstance and not getInstance - latter creates an instance if it's not there which is bad. - LLFloater* twitter_web = LLFloaterReg::findInstance("twitter_web"); - if (twitter_web == this) - { - if (!LLTwitterConnect::instance().isConnected()) - { - LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED); - } - } - LLViewerMedia::proxyWindowClosed(mUUID); + LLViewerMedia::getInstance()->proxyWindowClosed(mUUID); destroy(); } diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 1e9c9ce5e0..27197f0b06 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -122,7 +122,7 @@ public: bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) { - if (!LLUI::sSettingGroups["config"]->getBOOL("EnableWorldMap")) + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableWorldMap")) { LLNotificationsUtil::add("NoWorldMap", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); return true; @@ -160,7 +160,7 @@ public: bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) { - if (!LLUI::sSettingGroups["config"]->getBOOL("EnableWorldMap")) + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableWorldMap")) { LLNotificationsUtil::add("NoWorldMap", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); return true; diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h index fce945df6c..97e99297cf 100644 --- a/indra/newview/llfloaterworldmap.h +++ b/indra/newview/llfloaterworldmap.h @@ -33,7 +33,6 @@ #define LL_LLFLOATERWORLDMAP_H #include "llfloater.h" -#include "llhudtext.h" #include "llmapimagetype.h" #include "lltracker.h" #include "llslurl.h" diff --git a/indra/newview/llflyoutcombobtn.cpp b/indra/newview/llflyoutcombobtn.cpp new file mode 100644 index 0000000000..e4f1d9fcaa --- /dev/null +++ b/indra/newview/llflyoutcombobtn.cpp @@ -0,0 +1,162 @@ +/** + * @file llflyoutcombobtn.cpp + * @brief Represents outfit save/save as combo button. + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llflyoutcombobtn.h" +#include "llviewermenu.h" + +LLFlyoutComboBtnCtrl::LLFlyoutComboBtnCtrl(LLPanel* parent, + const std::string &action_button, + const std::string &flyout_button, + const std::string &menu_file, + bool apply_immediately) : + mParent(parent), + mActionButton(action_button), + mFlyoutButton(flyout_button), + mApplyImmediately(apply_immediately) +{ + // register action mapping before creating menu + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar save_registar; + save_registar.add("FlyoutCombo.Button.Action", [this](LLUICtrl *ctrl, const LLSD &data) { onFlyoutItemSelected(ctrl, data); }); + LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enabled_rgistar; + enabled_rgistar.add("FlyoutCombo.Button.Check", [this](LLUICtrl *ctrl, const LLSD &data) { return onFlyoutItemCheck(ctrl, data); }); + + mParent->childSetAction(flyout_button, [this](LLUICtrl *ctrl, const LLSD &data) { onFlyoutButton(ctrl, data); }); + mParent->childSetAction(action_button, [this](LLUICtrl *ctrl, const LLSD &data) { onFlyoutAction(ctrl, data); }); + + mFlyoutMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu> (menu_file, gMenuHolder, + LLViewerMenuHolderGL::child_registry_t::instance()); + + // select the first item in the list. + setSelectedItem(0); +} + +void LLFlyoutComboBtnCtrl::setAction(LLUICtrl::commit_callback_t cb) +{ + mActionSignal.connect(cb); +} + + +U32 LLFlyoutComboBtnCtrl::getItemCount() +{ + return mFlyoutMenu->getItemCount(); +} + +void LLFlyoutComboBtnCtrl::setSelectedItem(S32 itemno) +{ + LLMenuItemGL *pitem = mFlyoutMenu->getItem(itemno); + setSelectedItem(pitem); +} + +void LLFlyoutComboBtnCtrl::setSelectedItem(const std::string &item) +{ + LLMenuItemGL *pitem = mFlyoutMenu->getChild<LLMenuItemGL>(item, false); + setSelectedItem(pitem); +} + +void LLFlyoutComboBtnCtrl::setSelectedItem(LLMenuItemGL *pitem) +{ + if (!pitem) + { + LL_WARNS("INTERFACE") << "NULL item selected" << LL_ENDL; + return; + } + + mSelectedName = pitem->getName(); + + LLButton *action_button = mParent->getChild<LLButton>(mActionButton); + action_button->setEnabled(pitem->getEnabled()); + action_button->setLabel(pitem->getLabel()); +} + +void LLFlyoutComboBtnCtrl::setMenuItemEnabled(const std::string& item, bool enabled) +{ + mFlyoutMenu->setItemEnabled(item, enabled); + if (item == mSelectedName) + { + mParent->getChildView(mActionButton)->setEnabled(enabled); + } +} + +void LLFlyoutComboBtnCtrl::setShownBtnEnabled(bool enabled) +{ + mParent->getChildView(mActionButton)->setEnabled(enabled); +} + +void LLFlyoutComboBtnCtrl::setMenuItemVisible(const std::string &item, bool visible) +{ + mFlyoutMenu->setItemVisible(item, visible); +} + + +void LLFlyoutComboBtnCtrl::setMenuItemLabel(const std::string &item, const std::string &label) +{ + mFlyoutMenu->setItemLabel(item, label); +} + +void LLFlyoutComboBtnCtrl::onFlyoutButton(LLUICtrl *ctrl, const LLSD &data) +{ + S32 x, y; + LLUI::getInstance()->getMousePositionLocal(mParent, &x, &y); + + mFlyoutMenu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(mParent, mFlyoutMenu, x, y); +} + +void LLFlyoutComboBtnCtrl::onFlyoutItemSelected(LLUICtrl *ctrl, const LLSD &data) +{ + LLMenuItemGL *pmenuitem = static_cast<LLMenuItemGL*>(ctrl); + setSelectedItem(pmenuitem); + + if (mApplyImmediately) + { + onFlyoutAction(pmenuitem, data); + } +} + +bool LLFlyoutComboBtnCtrl::onFlyoutItemCheck(LLUICtrl *ctrl, const LLSD &data) +{ + if (mApplyImmediately) + { + return false; + } + else + { + LLMenuItemGL *pmenuitem = static_cast<LLMenuItemGL*>(ctrl); + + return pmenuitem->getName() == mSelectedName; + } +} + +void LLFlyoutComboBtnCtrl::onFlyoutAction(LLUICtrl *ctrl, const LLSD &data) +{ + LLMenuItemGL *pmenuitem = mFlyoutMenu->getChild<LLMenuItemGL>(mSelectedName); + + if (!mActionSignal.empty()) + mActionSignal(pmenuitem, data); +} + diff --git a/indra/newview/llflyoutcombobtn.h b/indra/newview/llflyoutcombobtn.h new file mode 100644 index 0000000000..e41cd0cecb --- /dev/null +++ b/indra/newview/llflyoutcombobtn.h @@ -0,0 +1,76 @@ +/** + * @file llsaveoutfitcombobtn.h + * @brief Represents outfit save/save as combo button. + * + * $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_LLFLYOUTCOMBOBTN_H +#define LL_LLFLYOUTCOMBOBTN_H + +/*TODO: Make this button generic */ + +class LLButton; + +#include "lltoggleablemenu.h" + +class LLFlyoutComboBtnCtrl +{ + LOG_CLASS(LLFlyoutComboBtnCtrl); +public: + LLFlyoutComboBtnCtrl(LLPanel* parent, + const std::string &action_button, + const std::string &flyout_button, + const std::string &menu_file, + bool apply_immediately = true); + + void setMenuItemEnabled(const std::string &item, bool enabled); + void setShownBtnEnabled(bool enabled); + void setMenuItemVisible(const std::string &item, bool visible); + void setMenuItemLabel(const std::string &item, const std::string &label); + + U32 getItemCount(); + void setSelectedItem(S32 itemno); + void setSelectedItem(const std::string &item); + + void setAction(LLUICtrl::commit_callback_t cb); + +protected: + void onFlyoutButton(LLUICtrl *, const LLSD &); + void onFlyoutItemSelected(LLUICtrl *, const LLSD &); + bool onFlyoutItemCheck(LLUICtrl *, const LLSD &); + void onFlyoutAction(LLUICtrl *, const LLSD &); + + void setSelectedItem(LLMenuItemGL *pitem); + +private: + LLPanel * mParent; + LLToggleableMenu * mFlyoutMenu; + std::string mActionButton; + std::string mFlyoutButton; + + std::string mSelectedName; + bool mApplyImmediately; + + LLUICtrl::commit_signal_t mActionSignal; +}; +#endif // LL_LLFLYOUTCOMBOBTN_H diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h index dea54cbe57..51b98339c4 100644 --- a/indra/newview/llfolderviewmodelinventory.h +++ b/indra/newview/llfolderviewmodelinventory.h @@ -45,12 +45,14 @@ public: virtual LLFolderType::EType getPreferredType() const = 0; virtual void showProperties(void) = 0; virtual BOOL isItemInTrash( void) const { return FALSE; } // TODO: make into pure virtual. + virtual BOOL isAgentInventory() const { return FALSE; } virtual BOOL isUpToDate() 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; - virtual EInventorySortGroup getSortGroup() const = 0; + virtual LLWearableType::EType getWearableType() const = 0; + virtual LLSettingsType::type_e getSettingsType() const = 0; + virtual EInventorySortGroup getSortGroup() const = 0; virtual LLInventoryObject* getInventoryObject() const = 0; virtual void requestSort(); virtual void setPassedFilter(bool filtered, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0); diff --git a/indra/newview/llfollowcam.cpp b/indra/newview/llfollowcam.cpp index 612afc0d18..c2ea3b07c1 100644 --- a/indra/newview/llfollowcam.cpp +++ b/indra/newview/llfollowcam.cpp @@ -30,12 +30,6 @@ #include "llagent.h" //------------------------------------------------------- -// class statics -//------------------------------------------------------- -std::map<LLUUID, LLFollowCamParams*> LLFollowCamMgr::sParamMap; -std::vector<LLFollowCamParams*> LLFollowCamMgr::sParamStack; - -//------------------------------------------------------- // constants //------------------------------------------------------- const F32 FOLLOW_CAM_ZOOM_FACTOR = 0.1f; @@ -668,18 +662,20 @@ LLFollowCam::~LLFollowCam() //------------------------------------------------------- // LLFollowCamMgr //------------------------------------------------------- -//static -void LLFollowCamMgr::cleanupClass() +LLFollowCamMgr::LLFollowCamMgr() { - for (param_map_t::iterator iter = sParamMap.begin(); iter != sParamMap.end(); ++iter) - { - LLFollowCamParams* params = iter->second; - delete params; - } - sParamMap.clear(); } -//static +LLFollowCamMgr::~LLFollowCamMgr() +{ + for (param_map_t::iterator iter = mParamMap.begin(); iter != mParamMap.end(); ++iter) + { + LLFollowCamParams* params = iter->second; + delete params; + } + mParamMap.clear(); +} + void LLFollowCamMgr::setPositionLag( const LLUUID& source, F32 lag) { LLFollowCamParams* paramsp = getParamsForID(source); @@ -689,7 +685,6 @@ void LLFollowCamMgr::setPositionLag( const LLUUID& source, F32 lag) } } -//static void LLFollowCamMgr::setFocusLag( const LLUUID& source, F32 lag) { LLFollowCamParams* paramsp = getParamsForID(source); @@ -699,7 +694,6 @@ void LLFollowCamMgr::setFocusLag( const LLUUID& source, F32 lag) } } -//static void LLFollowCamMgr::setFocusThreshold( const LLUUID& source, F32 threshold) { LLFollowCamParams* paramsp = getParamsForID(source); @@ -710,7 +704,6 @@ void LLFollowCamMgr::setFocusThreshold( const LLUUID& source, F32 threshold) } -//static void LLFollowCamMgr::setPositionThreshold( const LLUUID& source, F32 threshold) { LLFollowCamParams* paramsp = getParamsForID(source); @@ -720,7 +713,6 @@ void LLFollowCamMgr::setPositionThreshold( const LLUUID& source, F32 threshold) } } -//static void LLFollowCamMgr::setDistance( const LLUUID& source, F32 distance) { LLFollowCamParams* paramsp = getParamsForID(source); @@ -730,7 +722,6 @@ void LLFollowCamMgr::setDistance( const LLUUID& source, F32 distance) } } -//static void LLFollowCamMgr::setPitch( const LLUUID& source, F32 pitch) { LLFollowCamParams* paramsp = getParamsForID(source); @@ -740,7 +731,6 @@ void LLFollowCamMgr::setPitch( const LLUUID& source, F32 pitch) } } -//static void LLFollowCamMgr::setFocusOffset( const LLUUID& source, const LLVector3& offset) { LLFollowCamParams* paramsp = getParamsForID(source); @@ -750,7 +740,6 @@ void LLFollowCamMgr::setFocusOffset( const LLUUID& source, const LLVector3& offs } } -//static void LLFollowCamMgr::setBehindnessAngle( const LLUUID& source, F32 angle) { LLFollowCamParams* paramsp = getParamsForID(source); @@ -760,7 +749,6 @@ void LLFollowCamMgr::setBehindnessAngle( const LLUUID& source, F32 angle) } } -//static void LLFollowCamMgr::setBehindnessLag( const LLUUID& source, F32 force) { LLFollowCamParams* paramsp = getParamsForID(source); @@ -770,7 +758,6 @@ void LLFollowCamMgr::setBehindnessLag( const LLUUID& source, F32 force) } } -//static void LLFollowCamMgr::setPosition( const LLUUID& source, const LLVector3 position) { LLFollowCamParams* paramsp = getParamsForID(source); @@ -780,7 +767,6 @@ void LLFollowCamMgr::setPosition( const LLUUID& source, const LLVector3 position } } -//static void LLFollowCamMgr::setFocus( const LLUUID& source, const LLVector3 focus) { LLFollowCamParams* paramsp = getParamsForID(source); @@ -790,7 +776,6 @@ void LLFollowCamMgr::setFocus( const LLUUID& source, const LLVector3 focus) } } -//static void LLFollowCamMgr::setPositionLocked( const LLUUID& source, bool locked) { LLFollowCamParams* paramsp = getParamsForID(source); @@ -800,7 +785,6 @@ void LLFollowCamMgr::setPositionLocked( const LLUUID& source, bool locked) } } -//static void LLFollowCamMgr::setFocusLocked( const LLUUID& source, bool locked ) { LLFollowCamParams* paramsp = getParamsForID(source); @@ -810,16 +794,15 @@ void LLFollowCamMgr::setFocusLocked( const LLUUID& source, bool locked ) } } -//static LLFollowCamParams* LLFollowCamMgr::getParamsForID(const LLUUID& source) { LLFollowCamParams* params = NULL; - param_map_t::iterator found_it = sParamMap.find(source); - if (found_it == sParamMap.end()) // didn't find it? + param_map_t::iterator found_it = mParamMap.find(source); + if (found_it == mParamMap.end()) // didn't find it? { params = new LLFollowCamParams(); - sParamMap[source] = params; + mParamMap[source] = params; } else { @@ -829,56 +812,51 @@ LLFollowCamParams* LLFollowCamMgr::getParamsForID(const LLUUID& source) return params; } -//static LLFollowCamParams* LLFollowCamMgr::getActiveFollowCamParams() { - if (sParamStack.empty()) + if (mParamStack.empty()) { return NULL; } - return sParamStack.back(); + return mParamStack.back(); } -//static void LLFollowCamMgr::setCameraActive( const LLUUID& source, bool active ) { LLFollowCamParams* params = getParamsForID(source); - param_stack_t::iterator found_it = std::find(sParamStack.begin(), sParamStack.end(), params); - if (found_it != sParamStack.end()) + param_stack_t::iterator found_it = std::find(mParamStack.begin(), mParamStack.end(), params); + if (found_it != mParamStack.end()) { - sParamStack.erase(found_it); + mParamStack.erase(found_it); } // put on top of stack if(active) { - sParamStack.push_back(params); + mParamStack.push_back(params); } } -//static void LLFollowCamMgr::removeFollowCamParams(const LLUUID& source) { setCameraActive(source, FALSE); LLFollowCamParams* params = getParamsForID(source); - sParamMap.erase(source); + mParamMap.erase(source); delete params; } -//static bool LLFollowCamMgr::isScriptedCameraSource(const LLUUID& source) { - param_map_t::iterator found_it = sParamMap.find(source); - return (found_it != sParamMap.end()); + param_map_t::iterator found_it = mParamMap.find(source); + return (found_it != mParamMap.end()); } -//static void LLFollowCamMgr::dump() { S32 param_count = 0; LL_INFOS() << "Scripted camera active stack" << LL_ENDL; - for (param_stack_t::iterator param_it = sParamStack.begin(); - param_it != sParamStack.end(); + for (param_stack_t::iterator param_it = mParamStack.begin(); + param_it != mParamStack.end(); ++param_it) { LL_INFOS() << param_count++ << diff --git a/indra/newview/llfollowcam.h b/indra/newview/llfollowcam.h index f4b7b2723a..7995848160 100644 --- a/indra/newview/llfollowcam.h +++ b/indra/newview/llfollowcam.h @@ -193,40 +193,40 @@ protected: };// end of FollowCam class -class LLFollowCamMgr +class LLFollowCamMgr : public LLSingleton<LLFollowCamMgr> { -public: - static void cleanupClass ( ); - - static void setPositionLag ( const LLUUID& source, F32 lag); - static void setFocusLag ( const LLUUID& source, F32 lag); - static void setFocusThreshold ( const LLUUID& source, F32 threshold); - static void setPositionThreshold ( const LLUUID& source, F32 threshold); - static void setDistance ( const LLUUID& source, F32 distance); - static void setPitch ( const LLUUID& source, F32 pitch); - static void setFocusOffset ( const LLUUID& source, const LLVector3& offset); - static void setBehindnessAngle ( const LLUUID& source, F32 angle); - static void setBehindnessLag ( const LLUUID& source, F32 lag); - static void setPosition ( const LLUUID& source, const LLVector3 position); - static void setFocus ( const LLUUID& source, const LLVector3 focus); - static void setPositionLocked ( const LLUUID& source, bool locked); - static void setFocusLocked ( const LLUUID& source, bool locked ); - - static void setCameraActive ( const LLUUID& source, bool active ); - - static LLFollowCamParams* getActiveFollowCamParams(); - static LLFollowCamParams* getParamsForID(const LLUUID& source); - static void removeFollowCamParams(const LLUUID& source); - static bool isScriptedCameraSource(const LLUUID& source); - static void dump(); + LLSINGLETON(LLFollowCamMgr); + ~LLFollowCamMgr(); +public: + void setPositionLag ( const LLUUID& source, F32 lag); + void setFocusLag ( const LLUUID& source, F32 lag); + void setFocusThreshold ( const LLUUID& source, F32 threshold); + void setPositionThreshold ( const LLUUID& source, F32 threshold); + void setDistance ( const LLUUID& source, F32 distance); + void setPitch ( const LLUUID& source, F32 pitch); + void setFocusOffset ( const LLUUID& source, const LLVector3& offset); + void setBehindnessAngle ( const LLUUID& source, F32 angle); + void setBehindnessLag ( const LLUUID& source, F32 lag); + void setPosition ( const LLUUID& source, const LLVector3 position); + void setFocus ( const LLUUID& source, const LLVector3 focus); + void setPositionLocked ( const LLUUID& source, bool locked); + void setFocusLocked ( const LLUUID& source, bool locked ); + + void setCameraActive ( const LLUUID& source, bool active ); + + LLFollowCamParams* getActiveFollowCamParams(); + LLFollowCamParams* getParamsForID(const LLUUID& source); + void removeFollowCamParams(const LLUUID& source); + bool isScriptedCameraSource(const LLUUID& source); + void dump(); protected: typedef std::map<LLUUID, LLFollowCamParams*> param_map_t; - static param_map_t sParamMap; + param_map_t mParamMap; typedef std::vector<LLFollowCamParams*> param_stack_t; - static param_stack_t sParamStack; + param_stack_t mParamStack; }; #endif //LL_FOLLOWCAM_H diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp index 62cbea6401..0be748ace9 100644 --- a/indra/newview/llfriendcard.cpp +++ b/indra/newview/llfriendcard.cpp @@ -504,7 +504,7 @@ void LLFriendCardsManager::syncFriendsFolder() gAgentID.asString(), LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, - NOT_WEARABLE, + NO_INV_SUBTYPE, PERM_MOVE | PERM_TRANSFER, NULL); } diff --git a/indra/newview/llgiveinventory.cpp b/indra/newview/llgiveinventory.cpp index 3ab8fed2c6..127055459d 100644 --- a/indra/newview/llgiveinventory.cpp +++ b/indra/newview/llgiveinventory.cpp @@ -129,23 +129,14 @@ bool LLGiveInventory::isInventoryGiveAcceptable(const LLInventoryItem* item) switch(item->getType()) { case LLAssetType::AT_OBJECT: - 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(gAgentID)) copyable = true; - - if (!copyable && get_is_item_worn(item->getUUID())) + if (get_is_item_worn(item->getUUID())) { - // worn no-copy items can't be transfered, - // but it is valid to transfer a copy of a worn item acceptable = false; } + break; } break; default: diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index fea01786f3..698c15bd2d 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -44,6 +44,7 @@ #include "llviewercamera.h" #include "llvoavatarself.h" +#include "llsky.h" #include "llagent.h" #include "lltoolmgr.h" #include "llselectmgr.h" @@ -771,6 +772,16 @@ void draw_line_cube(F32 width, const LLVector3& center) gGL.vertex3f(center.mV[VX] + width ,center.mV[VY] - width,center.mV[VZ] - width); } +void draw_cross_lines(const LLVector3& center, F32 dx, F32 dy, F32 dz) +{ + gGL.vertex3f(center.mV[VX] - dx, center.mV[VY], center.mV[VZ]); + gGL.vertex3f(center.mV[VX] + dx, center.mV[VY], center.mV[VZ]); + gGL.vertex3f(center.mV[VX], center.mV[VY] - dy, center.mV[VZ]); + gGL.vertex3f(center.mV[VX], center.mV[VY] + dy, center.mV[VZ]); + gGL.vertex3f(center.mV[VX], center.mV[VY], center.mV[VZ] - dz); + gGL.vertex3f(center.mV[VX], center.mV[VY], center.mV[VZ] + dz); +} + void LLViewerObjectList::renderObjectBeacons() { if (mDebugBeacons.empty()) @@ -808,13 +819,7 @@ void LLViewerObjectList::renderObjectBeacons() gGL.begin(LLRender::LINES); gGL.color4fv(color.mV); - gGL.vertex3f(thisline.mV[VX],thisline.mV[VY],thisline.mV[VZ] - 50.f); - gGL.vertex3f(thisline.mV[VX],thisline.mV[VY],thisline.mV[VZ] + 50.f); - gGL.vertex3f(thisline.mV[VX] - 2.f,thisline.mV[VY],thisline.mV[VZ]); - gGL.vertex3f(thisline.mV[VX] + 2.f,thisline.mV[VY],thisline.mV[VZ]); - gGL.vertex3f(thisline.mV[VX],thisline.mV[VY] - 2.f,thisline.mV[VZ]); - gGL.vertex3f(thisline.mV[VX],thisline.mV[VY] + 2.f,thisline.mV[VZ]); - + draw_cross_lines(thisline, 2.0f, 2.0f, 50.f); draw_line_cube(0.10f, thisline); gGL.end(); @@ -843,13 +848,7 @@ void LLViewerObjectList::renderObjectBeacons() const LLVector3 &thisline = debug_beacon.mPositionAgent; gGL.begin(LLRender::LINES); gGL.color4fv(debug_beacon.mColor.mV); - gGL.vertex3f(thisline.mV[VX],thisline.mV[VY],thisline.mV[VZ] - 0.5f); - gGL.vertex3f(thisline.mV[VX],thisline.mV[VY],thisline.mV[VZ] + 0.5f); - gGL.vertex3f(thisline.mV[VX] - 0.5f,thisline.mV[VY],thisline.mV[VZ]); - gGL.vertex3f(thisline.mV[VX] + 0.5f,thisline.mV[VY],thisline.mV[VZ]); - gGL.vertex3f(thisline.mV[VX],thisline.mV[VY] - 0.5f,thisline.mV[VZ]); - gGL.vertex3f(thisline.mV[VX],thisline.mV[VY] + 0.5f,thisline.mV[VZ]); - + draw_cross_lines(thisline, 0.5f, 0.5f, 0.5f); draw_line_cube(0.10f, thisline); gGL.end(); @@ -880,6 +879,34 @@ void LLViewerObjectList::renderObjectBeacons() } } +void LLSky::renderSunMoonBeacons(const LLVector3& pos_agent, const LLVector3& direction, LLColor4 color) +{ + LLGLSUIDefault gls_ui; + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.bind(); + } + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + LLVector3 pos_end; + for (S32 i = 0; i < 3; ++i) + { + pos_end.mV[i] = pos_agent.mV[i] + (50 * direction.mV[i]); + } + glLineWidth(LLPipeline::DebugBeaconLineWidth); + gGL.begin(LLRender::LINES); + color.mV[3] *= 0.5f; + gGL.color4fv(color.mV); + draw_cross_lines(pos_agent, 0.5f, 0.5f, 0.5f); + draw_cross_lines(pos_end, 2.f, 2.f, 2.f); + gGL.vertex3fv(pos_agent.mV); + gGL.vertex3fv(pos_end.mV); + gGL.end(); + + gGL.flush(); + glLineWidth(1.f); + +} //----------------------------------------------------------------------------- // gpu_benchmark() helper classes @@ -1005,7 +1032,7 @@ F32 gpu_benchmark() //number of samples to take const S32 samples = 64; - + //time limit, allocation operations shouldn't take longer then 30 seconds, same for actual benchmark. const F32 time_limit = 30; @@ -1133,7 +1160,7 @@ F32 gpu_benchmark() F32 gbps = results[results.size()/2]; LL_INFOS("Benchmark") << "Memory bandwidth is " << llformat("%.3f", gbps) << "GB/sec according to CPU timers, " << (F32)results.size() << " tests took " << time_passed << " seconds" << LL_ENDL; - + #if LL_DARWIN if (gbps > 512.f) { diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index 913efd6434..12d82d101f 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -39,6 +39,7 @@ #include "llfloaterimcontainer.h" #include "llimview.h" // for gIMMgr #include "llnotificationsutil.h" +#include "llstartup.h" #include "llstatusbar.h" // can_afford_transaction() #include "groupchatlistener.h" @@ -55,7 +56,12 @@ public: bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web) { - if (!LLUI::sSettingGroups["config"]->getBOOL("EnableGroupInfo")) + if (LLStartUp::getStartupState() < STATE_STARTED) + { + return true; + } + + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableGroupInfo")) { LLNotificationsUtil::add("NoGroupInfo", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); return true; @@ -400,10 +406,10 @@ void LLGroupActions::createGroup() { LLSD params; params["group_id"] = LLUUID::null; - params["open_tab_name"] = "panel_group_info_sidetray"; + params["open_tab_name"] = "panel_group_creation_sidetray"; params["action"] = "create"; - LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params); + LLFloaterSidePanelContainer::showPanel("people", "panel_group_creation_sidetray", params); } //static diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index 088d052533..32f88b49ac 100644 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -44,9 +44,8 @@ #include "roles_constants.h" #include "lltransactiontypes.h" #include "llstatusbar.h" -#include "lleconomy.h" #include "llviewerwindow.h" -#include "llpanelgroup.h" +#include "llpanelgroupcreate.h" #include "llgroupactions.h" #include "llnotificationsutil.h" #include "lluictrlfactory.h" @@ -945,10 +944,14 @@ static void formatDateString(std::string &date_string) } } +static LLTrace::BlockTimerStatHandle FTM_PROCESS_GROUP_MEMBERS_REPLY("Process Group Members"); + // static void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data) { - LL_DEBUGS() << "LLGroupMgr::processGroupMembersReply" << LL_ENDL; + LL_RECORD_BLOCK_TIME(FTM_PROCESS_GROUP_MEMBERS_REPLY); + + LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupMembersReply" << LL_ENDL; LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); if (gAgent.getID() != agent_id) @@ -1051,10 +1054,14 @@ void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data) LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA); } +static LLTrace::BlockTimerStatHandle FTM_PROCESS_GROUP_PROPERTIES_REPLY("Process Group Properties"); + //static void LLGroupMgr::processGroupPropertiesReply(LLMessageSystem* msg, void** data) { - LL_DEBUGS() << "LLGroupMgr::processGroupPropertiesReply" << LL_ENDL; + LL_RECORD_BLOCK_TIME(FTM_PROCESS_GROUP_PROPERTIES_REPLY); + + LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupPropertiesReply" << LL_ENDL; if (!msg) { LL_ERRS() << "Can't access the messaging system" << LL_ENDL; @@ -1120,13 +1127,25 @@ void LLGroupMgr::processGroupPropertiesReply(LLMessageSystem* msg, void** data) group_datap->mGroupPropertiesDataComplete = true; group_datap->mChanged = TRUE; + properties_request_map_t::iterator request = LLGroupMgr::getInstance()->mPropRequests.find(group_id); + if (request != LLGroupMgr::getInstance()->mPropRequests.end()) + { + LLGroupMgr::getInstance()->mPropRequests.erase(request); + } + else + { + LL_DEBUGS("GrpMgr") << "GroupPropertyResponse received with no pending request. Response was slow." << LL_ENDL; + } LLGroupMgr::getInstance()->notifyObservers(GC_PROPERTIES); } +static LLTrace::BlockTimerStatHandle FTM_PROCESS_GROUP_ROLE_DATA_REPLY("Process Group Role Data"); // static void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data) { - LL_DEBUGS() << "LLGroupMgr::processGroupRoleDataReply" << LL_ENDL; + LL_RECORD_BLOCK_TIME(FTM_PROCESS_GROUP_ROLE_DATA_REPLY); + + LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupRoleDataReply" << LL_ENDL; LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); if (gAgent.getID() != agent_id) @@ -1187,7 +1206,7 @@ void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data) - LL_DEBUGS() << "Adding role data: " << name << " {" << role_id << "}" << LL_ENDL; + LL_DEBUGS("GrpMgr") << "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; } @@ -1208,10 +1227,13 @@ void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data) LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_DATA); } +static LLTrace::BlockTimerStatHandle FTM_PROCESS_GROUP_ROLE_MEMBERS_REPLY("Process Group Role Members"); // static void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data) { - LL_DEBUGS() << "LLGroupMgr::processGroupRoleMembersReply" << LL_ENDL; + LL_RECORD_BLOCK_TIME(FTM_PROCESS_GROUP_ROLE_MEMBERS_REPLY); + + LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupRoleMembersReply" << LL_ENDL; LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); if (gAgent.getID() != agent_id) @@ -1272,7 +1294,7 @@ void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data) if (rd && md) { - LL_DEBUGS() << "Adding role-member pair: " << role_id << ", " << member_id << LL_ENDL; + LL_DEBUGS("GrpMgr") << "Adding role-member pair: " << role_id << ", " << member_id << LL_ENDL; rd->addMember(member_id); md->addRole(role_id,rd); } @@ -1324,7 +1346,7 @@ void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data) // static void LLGroupMgr::processGroupTitlesReply(LLMessageSystem* msg, void** data) { - LL_DEBUGS() << "LLGroupMgr::processGroupTitlesReply" << LL_ENDL; + LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupTitlesReply" << LL_ENDL; LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); if (gAgent.getID() != agent_id) @@ -1357,7 +1379,7 @@ void LLGroupMgr::processGroupTitlesReply(LLMessageSystem* msg, void** data) if (!title.mTitle.empty()) { - LL_DEBUGS() << "LLGroupMgr adding title: " << title.mTitle << ", " << title.mRoleID << ", " << (title.mSelected ? 'Y' : 'N') << LL_ENDL; + LL_DEBUGS("GrpMgr") << "LLGroupMgr adding title: " << title.mTitle << ", " << title.mRoleID << ", " << (title.mSelected ? 'Y' : 'N') << LL_ENDL; group_datap->mTitles.push_back(title); } } @@ -1369,7 +1391,7 @@ void LLGroupMgr::processGroupTitlesReply(LLMessageSystem* msg, void** data) // static void LLGroupMgr::processEjectGroupMemberReply(LLMessageSystem* msg, void ** data) { - LL_DEBUGS() << "processEjectGroupMemberReply" << LL_ENDL; + LL_DEBUGS("GrpMgr") << "processEjectGroupMemberReply" << LL_ENDL; LLUUID group_id; msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id); BOOL success; @@ -1385,7 +1407,7 @@ void LLGroupMgr::processEjectGroupMemberReply(LLMessageSystem* msg, void ** data // static void LLGroupMgr::processJoinGroupReply(LLMessageSystem* msg, void ** data) { - LL_DEBUGS() << "processJoinGroupReply" << LL_ENDL; + LL_DEBUGS("GrpMgr") << "processJoinGroupReply" << LL_ENDL; LLUUID group_id; BOOL success; msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id); @@ -1405,7 +1427,7 @@ void LLGroupMgr::processJoinGroupReply(LLMessageSystem* msg, void ** data) // static void LLGroupMgr::processLeaveGroupReply(LLMessageSystem* msg, void ** data) { - LL_DEBUGS() << "processLeaveGroupReply" << LL_ENDL; + LL_DEBUGS("GrpMgr") << "processLeaveGroupReply" << LL_ENDL; LLUUID group_id; BOOL success; msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id); @@ -1452,7 +1474,7 @@ void LLGroupMgr::processCreateGroupReply(LLMessageSystem* msg, void ** data) gAgent.mGroups.push_back(gd); - LLPanelGroup::refreshCreatedGroup(group_id); + LLPanelGroupCreate::refreshCreatedGroup(group_id); //FIXME //LLFloaterGroupInfo::closeCreateGroup(); //LLFloaterGroupInfo::showFromUUID(group_id,"roles_tab"); @@ -1489,6 +1511,28 @@ LLGroupMgrGroupData* LLGroupMgr::createGroupData(const LLUUID& id) return group_datap; } +bool LLGroupMgr::hasPendingPropertyRequest(const LLUUID & id) +{ + properties_request_map_t::iterator existing_req = LLGroupMgr::getInstance()->mPropRequests.find(id); + if (existing_req != LLGroupMgr::getInstance()->mPropRequests.end()) + { + if (gFrameTime - existing_req->second < MIN_GROUP_PROPERTY_REQUEST_FREQ) + { + return true; + } + else + { + LLGroupMgr::getInstance()->mPropRequests.erase(existing_req); + } + } + return false; +} + +void LLGroupMgr::addPendingPropertyRequest(const LLUUID& id) +{ + LLGroupMgr::getInstance()->mPropRequests[id] = gFrameTime; +} + void LLGroupMgr::notifyObservers(LLGroupChange gc) { for (group_map_t::iterator gi = mGroups.begin(); gi != mGroups.end(); ++gi) @@ -1567,10 +1611,17 @@ void LLGroupMgr::addGroup(LLGroupMgrGroupData* group_datap) void LLGroupMgr::sendGroupPropertiesRequest(const LLUUID& group_id) { - LL_DEBUGS() << "LLGroupMgr::sendGroupPropertiesRequest" << LL_ENDL; + LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupPropertiesRequest" << LL_ENDL; // This will happen when we get the reply //LLGroupMgrGroupData* group_datap = createGroupData(group_id); + if (LLGroupMgr::getInstance()->hasPendingPropertyRequest(group_id)) + { + LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupPropertiesRequest suppressed repeat for " << group_id << LL_ENDL; + return; + } + LLGroupMgr::getInstance()->addPendingPropertyRequest(group_id); + LLMessageSystem* msg = gMessageSystem; msg->newMessage("GroupProfileRequest"); msg->nextBlock("AgentData"); @@ -1583,7 +1634,7 @@ void LLGroupMgr::sendGroupPropertiesRequest(const LLUUID& group_id) void LLGroupMgr::sendGroupMembersRequest(const LLUUID& group_id) { - LL_DEBUGS() << "LLGroupMgr::sendGroupMembersRequest" << LL_ENDL; + LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupMembersRequest" << LL_ENDL; LLGroupMgrGroupData* group_datap = createGroupData(group_id); if (group_datap->mMemberRequestID.isNull()) { @@ -1605,7 +1656,7 @@ void LLGroupMgr::sendGroupMembersRequest(const LLUUID& group_id) void LLGroupMgr::sendGroupRoleDataRequest(const LLUUID& group_id) { - LL_DEBUGS() << "LLGroupMgr::sendGroupRoleDataRequest" << LL_ENDL; + LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupRoleDataRequest" << LL_ENDL; LLGroupMgrGroupData* group_datap = createGroupData(group_id); if (group_datap->mRoleDataRequestID.isNull()) { @@ -1626,7 +1677,7 @@ void LLGroupMgr::sendGroupRoleDataRequest(const LLUUID& group_id) void LLGroupMgr::sendGroupRoleMembersRequest(const LLUUID& group_id) { - LL_DEBUGS() << "LLGroupMgr::sendGroupRoleMembersRequest" << LL_ENDL; + LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupRoleMembersRequest" << LL_ENDL; LLGroupMgrGroupData* group_datap = createGroupData(group_id); if (group_datap->mRoleMembersRequestID.isNull()) @@ -1636,7 +1687,7 @@ void LLGroupMgr::sendGroupRoleMembersRequest(const LLUUID& group_id) || !group_datap->isRoleDataComplete()) { // *TODO: KLW FIXME: Should we start a member or role data request? - LL_INFOS() << " Pending: " << (group_datap->mPendingRoleMemberRequest ? "Y" : "N") + LL_INFOS("GrpMgr") << " Pending: " << (group_datap->mPendingRoleMemberRequest ? "Y" : "N") << " MemberDataComplete: " << (group_datap->mMemberDataComplete ? "Y" : "N") << " RoleDataComplete: " << (group_datap->mRoleDataComplete ? "Y" : "N") << LL_ENDL; group_datap->mPendingRoleMemberRequest = TRUE; @@ -1660,7 +1711,7 @@ void LLGroupMgr::sendGroupRoleMembersRequest(const LLUUID& group_id) void LLGroupMgr::sendGroupTitlesRequest(const LLUUID& group_id) { - LL_DEBUGS() << "LLGroupMgr::sendGroupTitlesRequest" << LL_ENDL; + LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupTitlesRequest" << LL_ENDL; LLGroupMgrGroupData* group_datap = createGroupData(group_id); group_datap->mTitles.clear(); @@ -1679,7 +1730,7 @@ void LLGroupMgr::sendGroupTitlesRequest(const LLUUID& group_id) void LLGroupMgr::sendGroupTitleUpdate(const LLUUID& group_id, const LLUUID& title_role_id) { - LL_DEBUGS() << "LLGroupMgr::sendGroupTitleUpdate" << LL_ENDL; + LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupTitleUpdate" << LL_ENDL; LLMessageSystem* msg = gMessageSystem; msg->newMessage("GroupTitleUpdate"); @@ -1738,7 +1789,7 @@ void LLGroupMgr::sendCreateGroupRequest(const std::string& name, void LLGroupMgr::sendUpdateGroupInfo(const LLUUID& group_id) { - LL_DEBUGS() << "LLGroupMgr::sendUpdateGroupInfo" << LL_ENDL; + LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendUpdateGroupInfo" << LL_ENDL; LLGroupMgrGroupData* group_datap = createGroupData(group_id); LLMessageSystem* msg = gMessageSystem; @@ -1767,7 +1818,7 @@ void LLGroupMgr::sendUpdateGroupInfo(const LLUUID& group_id) void LLGroupMgr::sendGroupRoleMemberChanges(const LLUUID& group_id) { - LL_DEBUGS() << "LLGroupMgr::sendGroupRoleMemberChanges" << LL_ENDL; + LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupRoleMemberChanges" << LL_ENDL; LLGroupMgrGroupData* group_datap = createGroupData(group_id); if (group_datap->mRoleMemberChanges.empty()) return; @@ -2314,7 +2365,7 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) void LLGroupMgr::sendGroupRoleChanges(const LLUUID& group_id) { - LL_DEBUGS() << "LLGroupMgr::sendGroupRoleChanges" << LL_ENDL; + LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupRoleChanges" << LL_ENDL; LLGroupMgrGroupData* group_datap = getGroupData(group_id); if (group_datap && group_datap->pendingRoleChanges()) @@ -2329,7 +2380,7 @@ void LLGroupMgr::sendGroupRoleChanges(const LLUUID& group_id) void LLGroupMgr::cancelGroupRoleChanges(const LLUUID& group_id) { - LL_DEBUGS() << "LLGroupMgr::cancelGroupRoleChanges" << LL_ENDL; + LL_DEBUGS("GrpMgr") << "LLGroupMgr::cancelGroupRoleChanges" << LL_ENDL; LLGroupMgrGroupData* group_datap = getGroupData(group_id); if (group_datap) group_datap->cancelRoleChanges(); @@ -2363,7 +2414,7 @@ bool LLGroupMgr::parseRoleActions(const std::string& xml_filename) std::string action_set_name; if (action_set->getAttributeString("name", action_set_name)) { - LL_DEBUGS() << "Loading action set " << action_set_name << LL_ENDL; + LL_DEBUGS("GrpMgr") << "Loading action set " << action_set_name << LL_ENDL; role_action_data->mName = action_set_name; } else @@ -2404,7 +2455,7 @@ bool LLGroupMgr::parseRoleActions(const std::string& xml_filename) std::string action_name; if (action->getAttributeString("name", action_name)) { - LL_DEBUGS() << "Loading action " << action_name << LL_ENDL; + LL_DEBUGS("GrpMgr") << "Loading action " << action_name << LL_ENDL; role_action->mName = action_name; } else diff --git a/indra/newview/llgroupmgr.h b/indra/newview/llgroupmgr.h index cf9735e38a..0d25e8fb22 100644 --- a/indra/newview/llgroupmgr.h +++ b/indra/newview/llgroupmgr.h @@ -448,6 +448,8 @@ private: void notifyObserver(const LLUUID& group_id, LLGroupChange gc); void addGroup(LLGroupMgrGroupData* group_datap); LLGroupMgrGroupData* createGroupData(const LLUUID &id); + bool hasPendingPropertyRequest(const LLUUID& id); + void addPendingPropertyRequest(const LLUUID& id); typedef std::multimap<LLUUID,LLGroupMgrObserver*> observer_multimap_t; observer_multimap_t mObservers; @@ -455,6 +457,10 @@ private: typedef std::map<LLUUID, LLGroupMgrGroupData*> group_map_t; group_map_t mGroups; + const U64MicrosecondsImplicit MIN_GROUP_PROPERTY_REQUEST_FREQ = 100000;//100ms between requests should be enough to avoid spamming. + typedef std::map<LLUUID, U64MicrosecondsImplicit> properties_request_map_t; + properties_request_map_t mPropRequests; + typedef std::set<LLParticularGroupObserver*> observer_set_t; typedef std::map<LLUUID,observer_set_t> observer_map_t; observer_map_t mParticularObservers; diff --git a/indra/newview/llhints.cpp b/indra/newview/llhints.cpp index 197408b40e..7271376a3c 100644 --- a/indra/newview/llhints.cpp +++ b/indra/newview/llhints.cpp @@ -240,7 +240,7 @@ void LLHintPopup::draw() } else { - LLView* targetp = LLHints::getHintTarget(mTarget).get(); + LLView* targetp = LLHints::getInstance()->getHintTarget(mTarget).get(); if (!targetp) { // target widget is no longer valid, go away @@ -349,10 +349,20 @@ void LLHintPopup::draw() } -LLRegistry<std::string, LLHandle<LLView> > LLHints::sTargetRegistry; -std::map<LLNotificationPtr, class LLHintPopup*> LLHints::sHints; +/// LLHints + +LLHints::LLHints() +{ + LLControlVariablePtr control = gSavedSettings.getControl("EnableUIHints"); + mControlConnection = control->getSignal()->connect(boost::bind(&LLHints::showHints, this, _2)); + gViewerWindow->getHintHolder()->setVisible(control->getValue().asBoolean()); +} + +LLHints::~LLHints() +{ + mControlConnection.disconnect(); +} -//static void LLHints::show(LLNotificationPtr hint) { LLHintPopup::Params p(LLUICtrlFactory::getDefaultParams<LLHintPopup>()); @@ -365,7 +375,7 @@ void LLHints::show(LLNotificationPtr hint) { LLHintPopup* popup = new LLHintPopup(p); - sHints[hint] = popup; + mHints[hint] = popup; LLView* hint_holder = gViewerWindow->getHintHolder(); if (hint_holder) @@ -376,27 +386,24 @@ void LLHints::show(LLNotificationPtr hint) } } -//static void LLHints::hide(LLNotificationPtr hint) { - hint_map_t::iterator found_it = sHints.find(hint); - if (found_it != sHints.end()) + hint_map_t::iterator found_it = mHints.find(hint); + if (found_it != mHints.end()) { found_it->second->hide(); - sHints.erase(found_it); + mHints.erase(found_it); } } -//static void LLHints::registerHintTarget(const std::string& name, LLHandle<LLView> target) { - sTargetRegistry.defaultRegistrar().replace(name, target); + mTargetRegistry.defaultRegistrar().replace(name, target); } -//static LLHandle<LLView> LLHints::getHintTarget(const std::string& name) { - LLHandle<LLView>* handlep = sTargetRegistry.getValue(name); + LLHandle<LLView>* handlep = mTargetRegistry.getValue(name); if (handlep) { return *handlep; @@ -407,18 +414,6 @@ LLHandle<LLView> LLHints::getHintTarget(const std::string& name) } } -//static -void LLHints::initClass() -{ - sRegister.reference(); - - LLControlVariablePtr control = gSavedSettings.getControl("EnableUIHints"); - control->getSignal()->connect(boost::bind(&showHints, _2)); - gViewerWindow->getHintHolder()->setVisible(control->getValue().asBoolean()); - -} - -//staic void LLHints::showHints(const LLSD& show) { bool visible = show.asBoolean(); diff --git a/indra/newview/llhints.h b/indra/newview/llhints.h index dd6195a9ce..1f730734d0 100644 --- a/indra/newview/llhints.h +++ b/indra/newview/llhints.h @@ -32,19 +32,22 @@ #include "llinitdestroyclass.h" -class LLHints : public LLInitClass<LLHints> +class LLHints : public LLSingleton<LLHints> { + LLSINGLETON(LLHints); + ~LLHints(); public: - static void show(LLNotificationPtr hint); - static void hide(LLNotificationPtr hint); - static void registerHintTarget(const std::string& name, LLHandle<LLView> target); - static LLHandle<LLView> getHintTarget(const std::string& name); - static void initClass(); + void show(LLNotificationPtr hint); + void hide(LLNotificationPtr hint); + void registerHintTarget(const std::string& name, LLHandle<LLView> target); + LLHandle<LLView> getHintTarget(const std::string& name); private: - static LLRegistry<std::string, LLHandle<LLView> > sTargetRegistry; + LLRegistry<std::string, LLHandle<LLView> > mTargetRegistry; typedef std::map<LLNotificationPtr, class LLHintPopup*> hint_map_t; - static hint_map_t sHints; - static void showHints(const LLSD& show); + hint_map_t mHints; + void showHints(const LLSD& show); + + boost::signals2::connection mControlConnection; }; diff --git a/indra/newview/llhudeffectbeam.cpp b/indra/newview/llhudeffectbeam.cpp index 54e683e048..d1d83e6e03 100644 --- a/indra/newview/llhudeffectbeam.cpp +++ b/indra/newview/llhudeffectbeam.cpp @@ -90,7 +90,7 @@ void LLHUDEffectBeam::packData(LLMessageSystem *mesgsys) memset(packed_data, 0, 41); if (mSourceObject) { - htonmemcpy(packed_data, mSourceObject->mID.mData, MVT_LLUUID, 16); + htolememcpy(packed_data, mSourceObject->mID.mData, MVT_LLUUID, 16); } if (mTargetObject) @@ -104,11 +104,11 @@ void LLHUDEffectBeam::packData(LLMessageSystem *mesgsys) if (mTargetObject) { - htonmemcpy(&(packed_data[17]), mTargetObject->mID.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[17]), mTargetObject->mID.mData, MVT_LLUUID, 16); } else { - htonmemcpy(&(packed_data[17]), mTargetPos.mdV, MVT_LLVector3d, 24); + htolememcpy(&(packed_data[17]), mTargetPos.mdV, MVT_LLVector3d, 24); } mesgsys->addBinaryDataFast(_PREHASH_TypeData, packed_data, 41); } @@ -131,7 +131,7 @@ void LLHUDEffectBeam::unpackData(LLMessageSystem *mesgsys, S32 blocknum) } mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, 41, blocknum); - htonmemcpy(source_id.mData, packed_data, MVT_LLUUID, 16); + htolememcpy(source_id.mData, packed_data, MVT_LLUUID, 16); LLViewerObject *objp = gObjectList.findObject(source_id); if (objp) @@ -143,7 +143,7 @@ void LLHUDEffectBeam::unpackData(LLMessageSystem *mesgsys, S32 blocknum) if (use_target_object) { - htonmemcpy(target_id.mData, &packed_data[17], MVT_LLUUID, 16); + htolememcpy(target_id.mData, &packed_data[17], MVT_LLUUID, 16); LLViewerObject *objp = gObjectList.findObject(target_id); if (objp) @@ -153,7 +153,7 @@ void LLHUDEffectBeam::unpackData(LLMessageSystem *mesgsys, S32 blocknum) } else { - htonmemcpy(new_target.mdV, &(packed_data[17]), MVT_LLVector3d, 24); + htolememcpy(new_target.mdV, &(packed_data[17]), MVT_LLVector3d, 24); setTargetPos(new_target); } diff --git a/indra/newview/llhudeffectlookat.cpp b/indra/newview/llhudeffectlookat.cpp index f46152dcec..6898dce7b1 100644 --- a/indra/newview/llhudeffectlookat.cpp +++ b/indra/newview/llhudeffectlookat.cpp @@ -269,29 +269,29 @@ void LLHUDEffectLookAt::packData(LLMessageSystem *mesgsys) if (mSourceObject) { - htonmemcpy(&(packed_data[SOURCE_AVATAR]), mSourceObject->mID.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[SOURCE_AVATAR]), mSourceObject->mID.mData, MVT_LLUUID, 16); } else { - htonmemcpy(&(packed_data[SOURCE_AVATAR]), LLUUID::null.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[SOURCE_AVATAR]), LLUUID::null.mData, MVT_LLUUID, 16); } // pack both target object and position // position interpreted as offset if target object is non-null if (mTargetObject) { - htonmemcpy(&(packed_data[TARGET_OBJECT]), mTargetObject->mID.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[TARGET_OBJECT]), mTargetObject->mID.mData, MVT_LLUUID, 16); } else { - htonmemcpy(&(packed_data[TARGET_OBJECT]), LLUUID::null.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[TARGET_OBJECT]), LLUUID::null.mData, MVT_LLUUID, 16); } - htonmemcpy(&(packed_data[TARGET_POS]), mTargetOffsetGlobal.mdV, MVT_LLVector3d, 24); + htolememcpy(&(packed_data[TARGET_POS]), mTargetOffsetGlobal.mdV, MVT_LLVector3d, 24); U8 lookAtTypePacked = (U8)mTargetType; - htonmemcpy(&(packed_data[LOOKAT_TYPE]), &lookAtTypePacked, MVT_U8, 1); + htolememcpy(&(packed_data[LOOKAT_TYPE]), &lookAtTypePacked, MVT_U8, 1); mesgsys->addBinaryDataFast(_PREHASH_TypeData, packed_data, PKT_SIZE); @@ -325,7 +325,7 @@ void LLHUDEffectLookAt::unpackData(LLMessageSystem *mesgsys, S32 blocknum) } mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, PKT_SIZE, blocknum); - htonmemcpy(source_id.mData, &(packed_data[SOURCE_AVATAR]), MVT_LLUUID, 16); + htolememcpy(source_id.mData, &(packed_data[SOURCE_AVATAR]), MVT_LLUUID, 16); LLViewerObject *objp = gObjectList.findObject(source_id); if (objp && objp->isAvatar()) @@ -338,11 +338,11 @@ void LLHUDEffectLookAt::unpackData(LLMessageSystem *mesgsys, S32 blocknum) return; } - htonmemcpy(target_id.mData, &(packed_data[TARGET_OBJECT]), MVT_LLUUID, 16); + htolememcpy(target_id.mData, &(packed_data[TARGET_OBJECT]), MVT_LLUUID, 16); objp = gObjectList.findObject(target_id); - htonmemcpy(new_target.mdV, &(packed_data[TARGET_POS]), MVT_LLVector3d, 24); + htolememcpy(new_target.mdV, &(packed_data[TARGET_POS]), MVT_LLVector3d, 24); if (objp) { @@ -358,7 +358,7 @@ void LLHUDEffectLookAt::unpackData(LLMessageSystem *mesgsys, S32 blocknum) } U8 lookAtTypeUnpacked = 0; - htonmemcpy(&lookAtTypeUnpacked, &(packed_data[LOOKAT_TYPE]), MVT_U8, 1); + htolememcpy(&lookAtTypeUnpacked, &(packed_data[LOOKAT_TYPE]), MVT_U8, 1); mTargetType = (ELookAtType)lookAtTypeUnpacked; if (mTargetType == LOOKAT_TARGET_NONE) diff --git a/indra/newview/llhudeffectpointat.cpp b/indra/newview/llhudeffectpointat.cpp index cc772c8f5c..ecf6d42d69 100644 --- a/indra/newview/llhudeffectpointat.cpp +++ b/indra/newview/llhudeffectpointat.cpp @@ -107,28 +107,28 @@ void LLHUDEffectPointAt::packData(LLMessageSystem *mesgsys) if (mSourceObject) { - htonmemcpy(&(packed_data[SOURCE_AVATAR]), mSourceObject->mID.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[SOURCE_AVATAR]), mSourceObject->mID.mData, MVT_LLUUID, 16); } else { - htonmemcpy(&(packed_data[SOURCE_AVATAR]), LLUUID::null.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[SOURCE_AVATAR]), LLUUID::null.mData, MVT_LLUUID, 16); } // pack both target object and position // position interpreted as offset if target object is non-null if (mTargetObject) { - htonmemcpy(&(packed_data[TARGET_OBJECT]), mTargetObject->mID.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[TARGET_OBJECT]), mTargetObject->mID.mData, MVT_LLUUID, 16); } else { - htonmemcpy(&(packed_data[TARGET_OBJECT]), LLUUID::null.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[TARGET_OBJECT]), LLUUID::null.mData, MVT_LLUUID, 16); } - htonmemcpy(&(packed_data[TARGET_POS]), mTargetOffsetGlobal.mdV, MVT_LLVector3d, 24); + htolememcpy(&(packed_data[TARGET_POS]), mTargetOffsetGlobal.mdV, MVT_LLVector3d, 24); U8 pointAtTypePacked = (U8)mTargetType; - htonmemcpy(&(packed_data[POINTAT_TYPE]), &pointAtTypePacked, MVT_U8, 1); + htolememcpy(&(packed_data[POINTAT_TYPE]), &pointAtTypePacked, MVT_U8, 1); mesgsys->addBinaryDataFast(_PREHASH_TypeData, packed_data, PKT_SIZE); @@ -164,10 +164,10 @@ void LLHUDEffectPointAt::unpackData(LLMessageSystem *mesgsys, S32 blocknum) } mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, PKT_SIZE, blocknum); - htonmemcpy(source_id.mData, &(packed_data[SOURCE_AVATAR]), MVT_LLUUID, 16); - htonmemcpy(target_id.mData, &(packed_data[TARGET_OBJECT]), MVT_LLUUID, 16); - htonmemcpy(new_target.mdV, &(packed_data[TARGET_POS]), MVT_LLVector3d, 24); - htonmemcpy(&pointAtTypeUnpacked, &(packed_data[POINTAT_TYPE]), MVT_U8, 1); + htolememcpy(source_id.mData, &(packed_data[SOURCE_AVATAR]), MVT_LLUUID, 16); + htolememcpy(target_id.mData, &(packed_data[TARGET_OBJECT]), MVT_LLUUID, 16); + htolememcpy(new_target.mdV, &(packed_data[TARGET_POS]), MVT_LLVector3d, 24); + htolememcpy(&pointAtTypeUnpacked, &(packed_data[POINTAT_TYPE]), MVT_U8, 1); LLViewerObject *objp = gObjectList.findObject(source_id); if (objp && objp->isAvatar()) diff --git a/indra/newview/llhudeffecttrail.cpp b/indra/newview/llhudeffecttrail.cpp index fc6efdb840..2ba8aa422b 100644 --- a/indra/newview/llhudeffecttrail.cpp +++ b/indra/newview/llhudeffecttrail.cpp @@ -87,15 +87,15 @@ void LLHUDEffectSpiral::packData(LLMessageSystem *mesgsys) if (mSourceObject) { - htonmemcpy(packed_data, mSourceObject->mID.mData, MVT_LLUUID, 16); + htolememcpy(packed_data, mSourceObject->mID.mData, MVT_LLUUID, 16); } if (mTargetObject) { - htonmemcpy(packed_data + 16, mTargetObject->mID.mData, MVT_LLUUID, 16); + htolememcpy(packed_data + 16, mTargetObject->mID.mData, MVT_LLUUID, 16); } if (!mPositionGlobal.isExactlyZero()) { - htonmemcpy(packed_data + 32, mPositionGlobal.mdV, MVT_LLVector3d, 24); + htolememcpy(packed_data + 32, mPositionGlobal.mdV, MVT_LLVector3d, 24); } mesgsys->addBinaryDataFast(_PREHASH_TypeData, packed_data, 56); } @@ -116,9 +116,9 @@ void LLHUDEffectSpiral::unpackData(LLMessageSystem *mesgsys, S32 blocknum) mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, EFFECT_SIZE, blocknum, EFFECT_SIZE); - htonmemcpy(object_id.mData, packed_data, MVT_LLUUID, 16); - htonmemcpy(target_object_id.mData, packed_data + 16, MVT_LLUUID, 16); - htonmemcpy(mPositionGlobal.mdV, packed_data + 32, MVT_LLVector3d, 24); + htolememcpy(object_id.mData, packed_data, MVT_LLUUID, 16); + htolememcpy(target_object_id.mData, packed_data + 16, MVT_LLUUID, 16); + htolememcpy(mPositionGlobal.mdV, packed_data + 32, MVT_LLVector3d, 24); LLViewerObject *objp = NULL; diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp index 81d862a827..9d49c30a49 100644 --- a/indra/newview/llhudnametag.cpp +++ b/indra/newview/llhudnametag.cpp @@ -105,6 +105,9 @@ LLHUDNameTag::LLHUDNameTag(const U8 type) { LLPointer<LLHUDNameTag> ptr(this); sTextObjects.insert(ptr); + + mRoundedRectImgp = LLUI::getUIImage("Rounded_Rect"); + mRoundedRectTopImgp = LLUI::getUIImage("Rounded_Rect_Top"); } LLHUDNameTag::~LLHUDNameTag() @@ -274,9 +277,6 @@ void LLHUDNameTag::renderText(BOOL for_select) mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f)); - // *TODO: cache this image - LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Rect"); - // *TODO: make this a per-text setting LLColor4 bg_color = LLUIColorTable::instance().getColor("NameTagBackground"); bg_color.setAlpha(gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor); @@ -306,17 +306,16 @@ void LLHUDNameTag::renderText(BOOL for_select) LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); LLRect screen_rect; screen_rect.setCenterAndSize(0, static_cast<S32>(lltrunc(-mHeight / 2 + mOffsetY)), static_cast<S32>(lltrunc(mWidth)), static_cast<S32>(lltrunc(mHeight))); - imagep->draw3D(render_position, x_pixel_vec, y_pixel_vec, screen_rect, bg_color); + mRoundedRectImgp->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] = gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor; - rect_top_image->draw3D(render_position, x_pixel_vec, y_pixel_vec, label_top_rect, label_top_color); + mRoundedRectTopImgp->draw3D(render_position, x_pixel_vec, y_pixel_vec, label_top_rect, label_top_color); } F32 y_offset = (F32)mOffsetY; @@ -415,7 +414,8 @@ void LLHUDNameTag::clearString() void LLHUDNameTag::addLine(const std::string &text_utf8, const LLColor4& color, const LLFontGL::StyleFlags style, - const LLFontGL* font) + const LLFontGL* font, + const bool use_ellipses) { LLWString wline = utf8str_to_wstring(text_utf8); if (!wline.empty()) @@ -432,18 +432,52 @@ void LLHUDNameTag::addLine(const std::string &text_utf8, tokenizer tokens(wline, sep); tokenizer::iterator iter = tokens.begin(); - while (iter != tokens.end()) - { - U32 line_length = 0; - do - { - F32 max_pixels = HUD_TEXT_MAX_WIDTH; - S32 segment_length = font->maxDrawableChars(iter->substr(line_length).c_str(), max_pixels, wline.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE); - LLHUDTextSegment segment(iter->substr(line_length, segment_length), style, color, font); - mTextSegments.push_back(segment); - line_length += segment_length; - } - while (line_length != iter->size()); + const F32 max_pixels = HUD_TEXT_MAX_WIDTH; + while (iter != tokens.end()) + { + U32 line_length = 0; + if (use_ellipses) + { + // "QualityAssuranceAssuresQuality1" will end up like "QualityAssuranceAssuresQual..." + // "QualityAssuranceAssuresQuality QualityAssuranceAssuresQuality" will end up like "QualityAssuranceAssuresQual..." + // "QualityAssurance AssuresQuality1" will end up as "QualityAssurance AssuresQua..." because we are enforcing single line + do + { + S32 segment_length = font->maxDrawableChars(iter->substr(line_length).c_str(), max_pixels, wline.length(), LLFontGL::ANYWHERE); + if (segment_length + line_length < wline.length()) // since we only draw one string, line_length should be 0 + { + // token does does not fit into signle line, need to draw "...". + // Use four dots for ellipsis width to generate padding + const LLWString dots_pad(utf8str_to_wstring(std::string("...."))); + S32 elipses_width = font->getWidthF32(dots_pad.c_str()); + // truncated string length + segment_length = font->maxDrawableChars(iter->substr(line_length).c_str(), max_pixels - elipses_width, wline.length(), LLFontGL::ANYWHERE); + const LLWString dots(utf8str_to_wstring(std::string("..."))); + LLHUDTextSegment segment(iter->substr(line_length, segment_length) + dots, style, color, font); + mTextSegments.push_back(segment); + break; // consider it to be complete + } + else + { + // token fits fully into string + LLHUDTextSegment segment(iter->substr(line_length, segment_length), style, color, font); + mTextSegments.push_back(segment); + line_length += segment_length; + } + } while (line_length != iter->size()); + } + else + { + // "QualityAssuranceAssuresQuality 1" will be split into two lines "QualityAssuranceAssuresQualit" and "y 1" + // "QualityAssurance AssuresQuality 1" will be split into two lines "QualityAssurance" and "AssuresQuality" + do + { + S32 segment_length = font->maxDrawableChars(iter->substr(line_length).c_str(), max_pixels, wline.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE); + LLHUDTextSegment segment(iter->substr(line_length, segment_length), style, color, font); + mTextSegments.push_back(segment); + line_length += segment_length; + } while (line_length != iter->size()); + } ++iter; } } diff --git a/indra/newview/llhudnametag.h b/indra/newview/llhudnametag.h index 38a4f18415..7577dd5de6 100644 --- a/indra/newview/llhudnametag.h +++ b/indra/newview/llhudnametag.h @@ -40,8 +40,8 @@ #include <set> #include <vector> -class LLDrawable; class LLHUDNameTag; +class LLUIImage; struct llhudnametag_further_away { @@ -92,7 +92,7 @@ public: void clearString(); // Add text a line at a time, allowing custom formatting - void addLine(const std::string &text_utf8, const LLColor4& color, const LLFontGL::StyleFlags style = LLFontGL::NORMAL, const LLFontGL* font = NULL); + void addLine(const std::string &text_utf8, const LLColor4& color, const LLFontGL::StyleFlags style = LLFontGL::NORMAL, const LLFontGL* font = NULL, const bool use_ellipses = false); // For bubble chat, set the part above the chat text void setLabel(const std::string& label_utf8); @@ -171,6 +171,8 @@ private: EVertAlignment mVertAlignment; S32 mLOD; BOOL mHidden; + LLPointer<LLUIImage> mRoundedRectImgp; + LLPointer<LLUIImage> mRoundedRectTopImgp; static BOOL sDisplayText ; static std::set<LLPointer<LLHUDNameTag> > sTextObjects; diff --git a/indra/newview/llhudobject.h b/indra/newview/llhudobject.h index 2f7a98c86c..ce128519ea 100644 --- a/indra/newview/llhudobject.h +++ b/indra/newview/llhudobject.h @@ -102,7 +102,7 @@ protected: static void sortObjects(); LLHUDObject(const U8 type); - ~LLHUDObject(); + virtual ~LLHUDObject(); virtual void render() = 0; virtual void renderForTimer() {}; diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index ef3b234f50..7c957ac712 100644 --- a/indra/newview/llhudtext.cpp +++ b/indra/newview/llhudtext.cpp @@ -138,9 +138,6 @@ void LLHUDText::renderText() mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f)); - // *TODO: cache this image - LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Square"); - // *TODO: make this a per-text setting LLColor4 bg_color = LLUIColorTable::instance().getColor("ObjectBubbleColor"); bg_color.setAlpha(gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor); @@ -565,7 +562,10 @@ S32 LLHUDText::getMaxLines() void LLHUDText::markDead() { - sTextObjects.erase(LLPointer<LLHUDText>(this)); + // make sure we have at least one pointer + // till the end of the function + LLPointer<LLHUDText> ptr(this); + sTextObjects.erase(ptr); LLHUDObject::markDead(); } @@ -589,8 +589,6 @@ void LLHUDText::renderAllHUD() LLVertexBuffer::unbind(); - LLVertexBuffer::unbind(); - LLGLState::checkStates(); LLGLState::checkTextureChannels(); LLGLState::checkClientArrays(); diff --git a/indra/newview/llimagefiltersmanager.cpp b/indra/newview/llimagefiltersmanager.cpp index ee6b39efac..3b8adc1610 100644 --- a/indra/newview/llimagefiltersmanager.cpp +++ b/indra/newview/llimagefiltersmanager.cpp @@ -1,6 +1,6 @@ /** * @file llimagefiltersmanager.cpp - * @brief Load image filters list and retrieve their path. Mostly used for Flickr UI at the moment. + * @brief Load image filters list and retrieve their path. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code @@ -48,7 +48,7 @@ LLImageFiltersManager::~LLImageFiltersManager() { } -// virtual static +// virtual void LLImageFiltersManager::initSingleton() { loadAllFilters(); diff --git a/indra/newview/llimagefiltersmanager.h b/indra/newview/llimagefiltersmanager.h index f1ed3cf1c3..d06212d85a 100644 --- a/indra/newview/llimagefiltersmanager.h +++ b/indra/newview/llimagefiltersmanager.h @@ -1,6 +1,6 @@ /** * @file llimagefiltersmanager.h - * @brief Load image filters list and retrieve their path. Mostly used for Flickr UI at the moment. + * @brief Load image filters list and retrieve their path. * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index d59c301210..1e43e4ea3a 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -29,6 +29,7 @@ #include "llimprocessing.h" #include "llagent.h" +#include "llappviewer.h" #include "llavatarnamecache.h" #include "llfirstuse.h" #include "llfloaterreg.h" @@ -61,6 +62,8 @@ #pragma warning (disable:4702) #endif +extern void on_new_message(const LLSD& msg); + // 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) @@ -447,7 +450,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, || (dialog == IM_FROM_TASK && LLMuteList::getInstance()->isMuted(session_id)); 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("VoiceCallsFriendsOnly"); + BOOL accept_im_from_only_friend = gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly"); BOOL is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && LLMuteList::getInstance()->isLinden(name); @@ -695,7 +698,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, // 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); - agent_id = LLAvatarNameCache::findIdByName(legacy_name); + agent_id = LLAvatarNameCache::getInstance()->findIdByName(legacy_name); if (agent_id.isNull()) { @@ -715,7 +718,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, { info = new LLOfferInfo(); - info->mIM = IM_GROUP_NOTICE; + info->mIM = dialog; info->mFromID = from_id; info->mFromGroup = from_group; info->mTransactionID = session_id; @@ -854,41 +857,41 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, } else // IM_TASK_INVENTORY_OFFERED { - if (offline == IM_OFFLINE && session_id.isNull() && aux_id.notNull() && binary_bucket_size > sizeof(S8)* 5) + if (sizeof(S8) == binary_bucket_size) { - // cap received offline message - std::string str_bucket = ll_safe_string((char*)binary_bucket, binary_bucket_size); - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep("|", "", boost::keep_empty_tokens); - tokenizer tokens(str_bucket, sep); - tokenizer::iterator iter = tokens.begin(); - - info->mType = (LLAssetType::EType)(atoi((*(iter++)).c_str())); - // Note There is more elements in 'tokens' ... - - info->mObjectID = LLUUID::null; - info->mFromObject = TRUE; + info->mType = (LLAssetType::EType) binary_bucket[0]; } else { - 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; + /*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<char *>(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<LLAssetType::EType>(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->mTransactionID = session_id; 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; @@ -896,12 +899,18 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, 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); + 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); + } } // 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) @@ -1021,6 +1030,14 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, } LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); + if (message != "") + { + LLSD msg_notify; + msg_notify["session_id"] = LLUUID(); + msg_notify["from_id"] = chat.mFromID; + msg_notify["source_type"] = chat.mSourceType; + on_new_message(msg_notify); + } } @@ -1147,7 +1164,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, { return; } - else if (gSavedSettings.getBOOL("VoiceCallsFriendsOnly") && (LLAvatarTracker::instance().getBuddyInfo(from_id) == NULL)) + else if (gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly") && (LLAvatarTracker::instance().getBuddyInfo(from_id) == NULL)) { return; } @@ -1387,10 +1404,8 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, payload["sender"] = sender.getIPandPort(); bool add_notification = true; - for (LLToastNotifyPanel::instance_iter ti(LLToastNotifyPanel::beginInstances()) - , tend(LLToastNotifyPanel::endInstances()); ti != tend; ++ti) + for (auto& panel : LLToastNotifyPanel::instance_snapshot()) { - LLToastNotifyPanel& panel = *ti; const std::string& notification_name = panel.getNotificationName(); if (notification_name == "OfferFriendship" && panel.isControlPanelEnabled()) { @@ -1468,6 +1483,7 @@ void LLIMProcessing::requestOfflineMessages() static BOOL requested = FALSE; if (!requested && gMessageSystem + && !gDisconnected && LLMuteList::getInstance()->isLoaded() && isAgentAvatarValid() && gAgent.getRegion() @@ -1551,11 +1567,15 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) return; } + if (!gAgent.getRegion()) + { + LL_WARNS("Messaging") << "Region null while attempting to load messages." << LL_ENDL; + return; + } + LL_INFOS("Messaging") << "Processing offline messages." << LL_ENDL; - std::vector<U8> data; - S32 binary_bucket_size = 0; - LLHost sender = gAgent.getRegion()->getHost(); + LLHost sender = gAgent.getRegionHost(); LLSD::array_iterator i = messages.beginArray(); LLSD::array_iterator iEnd = messages.endArray(); @@ -1563,12 +1583,30 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) { const LLSD &message_data(*i); - LLVector3 position(message_data["local_x"].asReal(), message_data["local_y"].asReal(), message_data["local_z"].asReal()); - data = message_data["binary_bucket"].asBinary(); - binary_bucket_size = data.size(); // message_data["count"] always 0 - U32 parent_estate_id = message_data.has("parent_estate_id") ? message_data["parent_estate_id"].asInteger() : 1; // 1 - IMMainland + /* 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<U8> bin_bucket; + if (message_data.has("binary_bucket")) + { + bin_bucket = message_data["binary_bucket"].asBinary(); + } + else + { + bin_bucket.push_back(0); + } - // Todo: once dirtsim-369 releases, remove one of the int/str options + // Todo: once drtsim-451 releases, remove the string option BOOL from_group; if (message_data["from_group"].isInteger()) { @@ -1579,22 +1617,25 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) from_group = message_data["from_group"].asString() == "Y"; } - LLIMProcessing::processNewMessage(message_data["from_agent_id"].asUUID(), + + LLIMProcessing::processNewMessage( + message_data["from_agent_id"].asUUID(), from_group, message_data["to_agent_id"].asUUID(), - IM_OFFLINE, - (EInstantMessage)message_data["dialog"].asInteger(), - LLUUID::null, // session id, since there is none we can only use frienship/group invite caps - message_data["timestamp"].asInteger(), + message_data.has("offline") ? static_cast<U8>(message_data["offline"].asInteger()) : IM_OFFLINE, + static_cast<EInstantMessage>(message_data["dialog"].asInteger()), + message_data["transaction-id"].asUUID(), + static_cast<U32>(message_data["timestamp"].asInteger()), message_data["from_agent_name"].asString(), message_data["message"].asString(), - parent_estate_id, + static_cast<U32>((message_data.has("parent_estate_id")) ? message_data["parent_estate_id"].asInteger() : 1), // 1 - IMMainland message_data["region_id"].asUUID(), position, - &data[0], - binary_bucket_size, + bin_bucket.data(), + bin_bucket.size(), sender, - message_data["asset_id"].asUUID()); // not necessarily an asset + message_data["asset_id"].asUUID()); + } } diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 0f5d514660..1059324a16 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -83,11 +83,6 @@ void startConfrenceCoro(std::string url, LLUUID tempSessionId, LLUUID creatorId, void chatterBoxInvitationCoro(std::string url, LLUUID sessionId, LLIMMgr::EInvitationType invitationType); void start_deprecated_conference_chat(const LLUUID& temp_session_id, const LLUUID& creator_id, const LLUUID& other_participant_id, const LLSD& agents_to_invite); -std::string LLCallDialogManager::sPreviousSessionlName = ""; -LLIMModel::LLIMSession::SType LLCallDialogManager::sPreviousSessionType = LLIMModel::LLIMSession::P2P_SESSION; -std::string LLCallDialogManager::sCurrentSessionlName = ""; -LLIMModel::LLIMSession* LLCallDialogManager::sSession = NULL; -LLVoiceChannel::EState LLCallDialogManager::sOldState = LLVoiceChannel::STATE_READY; const LLUUID LLOutgoingCallDialog::OCD_KEY = LLUUID("7CF78E11-0CFE-498D-ADB9-1417BF03DDB4"); // // Globals @@ -520,6 +515,7 @@ LLIMModel::LLIMModel() { addNewMsgCallback(boost::bind(&LLFloaterIMSession::newIMCallback, _1)); addNewMsgCallback(boost::bind(&on_new_message, _1)); + LLCallDialogManager::instance(); } LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg) @@ -811,7 +807,7 @@ void LLIMModel::LLIMSession::addMessagesFromHistory(const std::list<LLSD>& histo { // convert it to a legacy name if we have a complete name std::string legacy_name = gCacheName->buildLegacyName(from); - from_id = LLAvatarNameCache::findIdByName(legacy_name); + from_id = LLAvatarNameCache::getInstance()->findIdByName(legacy_name); } std::string timestamp = msg[LL_IM_TIME]; @@ -848,7 +844,7 @@ void LLIMModel::LLIMSession::loadHistory() std::list<LLSD> chat_history; //involves parsing of a chat history - LLLogChat::loadChatHistory(mHistoryFileName, chat_history); + LLLogChat::loadChatHistory(mHistoryFileName, chat_history, LLSD(), isGroupChat()); addMessagesFromHistory(chat_history); } } @@ -912,6 +908,11 @@ bool LLIMModel::LLIMSession::isP2P() return IM_NOTHING_SPECIAL == mType; } +bool LLIMModel::LLIMSession::isGroupChat() +{ + return IM_SESSION_GROUP_START == mType || (IM_SESSION_INVITE == mType && gAgent.isInGroup(mSessionID)); +} + bool LLIMModel::LLIMSession::isOtherParticipantAvaline() { return !mOtherParticipantIsAvatar; @@ -968,6 +969,13 @@ void LLIMModel::LLIMSession::buildHistoryFileName() // Incoming P2P sessions include a name that we can use to build a history file name mHistoryFileName = LLCacheName::buildUsername(mName); } + + // user's account name can change, but filenames and session names are account name based + LLConversationLog::getInstance()->verifyFilename(mSessionID, mHistoryFileName, av_name.getCompleteName()); + } + else if (isGroupChat()) + { + mHistoryFileName = mName + GROUP_CHAT_SUFFIX; } } @@ -1786,7 +1794,12 @@ LLIMMgr::onConfirmForceCloseError( // Class LLCallDialogManager //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LLCallDialogManager::LLCallDialogManager() +LLCallDialogManager::LLCallDialogManager(): +mPreviousSessionlName(""), +mPreviousSessionType(LLIMModel::LLIMSession::P2P_SESSION), +mCurrentSessionlName(""), +mSession(NULL), +mOldState(LLVoiceChannel::STATE_READY) { } @@ -1794,39 +1807,45 @@ LLCallDialogManager::~LLCallDialogManager() { } -void LLCallDialogManager::initClass() +void LLCallDialogManager::initSingleton() { LLVoiceChannel::setCurrentVoiceChannelChangedCallback(LLCallDialogManager::onVoiceChannelChanged); } +// static void LLCallDialogManager::onVoiceChannelChanged(const LLUUID &session_id) { + LLCallDialogManager::getInstance()->onVoiceChannelChangedInt(session_id); +} + +void LLCallDialogManager::onVoiceChannelChangedInt(const LLUUID &session_id) +{ LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); if(!session) { - sPreviousSessionlName = sCurrentSessionlName; - sCurrentSessionlName = ""; // Empty string results in "Nearby Voice Chat" after substitution + mPreviousSessionlName = mCurrentSessionlName; + mCurrentSessionlName = ""; // Empty string results in "Nearby Voice Chat" after substitution return; } - if (sSession) + if (mSession) { // store previous session type to process Avaline calls in dialogs - sPreviousSessionType = sSession->mSessionType; + mPreviousSessionType = mSession->mSessionType; } - sSession = session; + mSession = session; static boost::signals2::connection prev_channel_state_changed_connection; // disconnect previously connected callback to avoid have invalid sSession in onVoiceChannelStateChanged() prev_channel_state_changed_connection.disconnect(); prev_channel_state_changed_connection = - sSession->mVoiceChannel->setStateChangedCallback(boost::bind(LLCallDialogManager::onVoiceChannelStateChanged, _1, _2, _3, _4)); + mSession->mVoiceChannel->setStateChangedCallback(boost::bind(LLCallDialogManager::onVoiceChannelStateChanged, _1, _2, _3, _4)); - if(sCurrentSessionlName != session->mName) + if(mCurrentSessionlName != session->mName) { - sPreviousSessionlName = sCurrentSessionlName; - sCurrentSessionlName = session->mName; + mPreviousSessionlName = mCurrentSessionlName; + mCurrentSessionlName = session->mName; } if (LLVoiceChannel::getCurrentVoiceChannel()->getState() == LLVoiceChannel::STATE_CALL_STARTED && @@ -1835,14 +1854,14 @@ void LLCallDialogManager::onVoiceChannelChanged(const LLUUID &session_id) //*TODO get rid of duplicated code LLSD mCallDialogPayload; - mCallDialogPayload["session_id"] = sSession->mSessionID; - mCallDialogPayload["session_name"] = sSession->mName; - mCallDialogPayload["other_user_id"] = sSession->mOtherParticipantID; - mCallDialogPayload["old_channel_name"] = sPreviousSessionlName; - mCallDialogPayload["old_session_type"] = sPreviousSessionType; + mCallDialogPayload["session_id"] = mSession->mSessionID; + mCallDialogPayload["session_name"] = mSession->mName; + mCallDialogPayload["other_user_id"] = mSession->mOtherParticipantID; + mCallDialogPayload["old_channel_name"] = mPreviousSessionlName; + mCallDialogPayload["old_session_type"] = mPreviousSessionType; mCallDialogPayload["state"] = LLVoiceChannel::STATE_CALL_STARTED; - mCallDialogPayload["disconnected_channel_name"] = sSession->mName; - mCallDialogPayload["session_type"] = sSession->mSessionType; + mCallDialogPayload["disconnected_channel_name"] = mSession->mName; + mCallDialogPayload["session_type"] = mSession->mSessionType; LLOutgoingCallDialog* ocd = LLFloaterReg::getTypedInstance<LLOutgoingCallDialog>("outgoing_call", LLOutgoingCallDialog::OCD_KEY); if(ocd) @@ -1853,26 +1872,32 @@ void LLCallDialogManager::onVoiceChannelChanged(const LLUUID &session_id) } +// static void LLCallDialogManager::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent) { + LLCallDialogManager::getInstance()->onVoiceChannelStateChangedInt(old_state, new_state, direction, ended_by_agent); +} + +void LLCallDialogManager::onVoiceChannelStateChangedInt(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent) +{ LLSD mCallDialogPayload; LLOutgoingCallDialog* ocd = NULL; - if(sOldState == new_state) + if(mOldState == new_state) { return; } - sOldState = new_state; + mOldState = new_state; - mCallDialogPayload["session_id"] = sSession->mSessionID; - mCallDialogPayload["session_name"] = sSession->mName; - mCallDialogPayload["other_user_id"] = sSession->mOtherParticipantID; - mCallDialogPayload["old_channel_name"] = sPreviousSessionlName; - mCallDialogPayload["old_session_type"] = sPreviousSessionType; + mCallDialogPayload["session_id"] = mSession->mSessionID; + mCallDialogPayload["session_name"] = mSession->mName; + mCallDialogPayload["other_user_id"] = mSession->mOtherParticipantID; + mCallDialogPayload["old_channel_name"] = mPreviousSessionlName; + mCallDialogPayload["old_session_type"] = mPreviousSessionType; mCallDialogPayload["state"] = new_state; - mCallDialogPayload["disconnected_channel_name"] = sSession->mName; - mCallDialogPayload["session_type"] = sSession->mSessionType; + mCallDialogPayload["disconnected_channel_name"] = mSession->mName; + mCallDialogPayload["session_type"] = mSession->mSessionType; mCallDialogPayload["ended_by_agent"] = ended_by_agent; switch(new_state) @@ -1887,7 +1912,7 @@ void LLCallDialogManager::onVoiceChannelStateChanged(const LLVoiceChannel::EStat case LLVoiceChannel::STATE_HUNG_UP: // this state is coming before session is changed, so, put it into payload map - mCallDialogPayload["old_session_type"] = sSession->mSessionType; + mCallDialogPayload["old_session_type"] = mSession->mSessionType; break; case LLVoiceChannel::STATE_CONNECTED : @@ -1925,7 +1950,7 @@ LLCallDialog::LLCallDialog(const LLSD& payload) LLCallDialog::~LLCallDialog() { - LLUI::removePopup(this); + LLUI::getInstance()->removePopup(this); } BOOL LLCallDialog::postBuild() @@ -2002,7 +2027,7 @@ void LLCallDialog::onOpen(const LLSD& key) LLDockableFloater::onOpen(key); // it should be over the all floaters. EXT-5116 - LLUI::addPopup(this); + LLUI::getInstance()->addPopup(this); } void LLCallDialog::setIcon(const LLSD& session_id, const LLSD& participant_id) @@ -2232,6 +2257,19 @@ BOOL LLOutgoingCallDialog::postBuild() // Class LLIncomingCallDialog //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +const std::array<std::string, 4> voice_call_types = +{ + "VoiceInviteP2P", + "VoiceInviteGroup", + "VoiceInviteAdHoc", + "InviteAdHoc" +}; + +bool is_voice_call_type(const std::string &value) +{ + return std::find(voice_call_types.begin(), voice_call_types.end(), value) != voice_call_types.end(); +} + LLIncomingCallDialog::LLIncomingCallDialog(const LLSD& payload) : LLCallDialog(payload), mAvatarNameCacheConnection() @@ -2261,9 +2299,28 @@ BOOL LLIncomingCallDialog::postBuild() { LLCallDialog::postBuild(); + if (!mPayload.isMap() || mPayload.size() == 0) + { + LL_INFOS("IMVIEW") << "IncomingCall: invalid argument" << LL_ENDL; + return TRUE; + } + LLUUID session_id = mPayload["session_id"].asUUID(); LLSD caller_id = mPayload["caller_id"]; std::string caller_name = mPayload["caller_name"].asString(); + + if (session_id.isNull() && caller_id.asUUID().isNull()) + { + LL_INFOS("IMVIEW") << "IncomingCall: invalid ids" << LL_ENDL; + return TRUE; + } + + std::string notify_box_type = mPayload["notify_box_type"].asString(); + if (!is_voice_call_type(notify_box_type)) + { + LL_INFOS("IMVIEW") << "IncomingCall: notify_box_type was not provided" << LL_ENDL; + return TRUE; + } // init notification's lifetime std::istringstream ss( getString("lifetime") ); @@ -2280,15 +2337,14 @@ BOOL LLIncomingCallDialog::postBuild() if (gAgent.getGroupData(session_id, data)) { args["[GROUP]"] = data.mName; - call_type = getString(mPayload["notify_box_type"], args); + call_type = getString(notify_box_type, args); } } else { - call_type = getString(mPayload["notify_box_type"]); + call_type = getString(notify_box_type); } - - + // check to see if this is an Avaline call bool is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id); if (caller_name == "anonymous") @@ -2318,7 +2374,6 @@ BOOL LLIncomingCallDialog::postBuild() childSetAction("Start IM", onStartIM, this); setDefaultBtn("Accept"); - std::string notify_box_type = mPayload["notify_box_type"].asString(); if(notify_box_type != "VoiceInviteGroup" && notify_box_type != "VoiceInviteAdHoc") { // starting notification's timer for P2P and AVALINE invitations @@ -2469,10 +2524,10 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload correct_session_name.append(ADHOC_NAME_SUFFIX); } } - LL_INFOS() << "Corrected session name is " << correct_session_name << LL_ENDL; + LL_INFOS("IMVIEW") << "Corrected session name is " << correct_session_name << LL_ENDL; break; default: - LL_WARNS() << "Received an empty session name from a server and failed to generate a new proper session name" << LL_ENDL; + LL_WARNS("IMVIEW") << "Received an empty session name from a server and failed to generate a new proper session name" << LL_ENDL; break; } } @@ -2662,7 +2717,7 @@ void LLIMMgr::addMessage( } bool skip_message = false; bool from_linden = LLMuteList::getInstance()->isLinden(from); - if (gSavedSettings.getBOOL("VoiceCallsFriendsOnly") && !from_linden) + if (gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly") && !from_linden) { // Evaluate if we need to skip this message when that setting is true (default is false) skip_message = (LLAvatarTracker::instance().getBuddyInfo(other_participant_id) == NULL); // Skip non friends... @@ -2672,6 +2727,14 @@ void LLIMMgr::addMessage( bool new_session = !hasSession(new_session_id); if (new_session) { + // Group chat session was initiated by muted resident, do not start this session viewerside + // do not send leave msg either, so we are able to get group messages from other participants + if ((IM_SESSION_INVITE == dialog) && gAgent.isInGroup(new_session_id) && + LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !from_linden) + { + return; + } + LLAvatarName av_name; if (LLAvatarNameCache::get(other_participant_id, &av_name) && !name_is_setted) { @@ -2715,13 +2778,13 @@ void LLIMMgr::addMessage( LL_WARNS() << "Leaving IM session from initiating muted resident " << from << LL_ENDL; if (!gIMMgr->leaveSession(new_session_id)) { - LL_INFOS() << "Session " << new_session_id << " does not exist." << LL_ENDL; + LL_INFOS("IMVIEW") << "Session " << new_session_id << " does not exist." << LL_ENDL; } return; } //Play sound for new conversations - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation") == TRUE)) + if (!skip_message & !gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation") == TRUE)) { make_ui_sound("UISndNewIncomingIMSession"); } @@ -2926,7 +2989,7 @@ LLUUID LLIMMgr::addSession( //we don't need to show notes about online/offline, mute/unmute users' statuses for existing sessions if (!new_session) return session_id; - LL_INFOS() << "LLIMMgr::addSession, new session added, name = " << name << ", session id = " << session_id << LL_ENDL; + LL_INFOS("IMVIEW") << "LLIMMgr::addSession, new session added, name = " << name << ", session id = " << session_id << LL_ENDL; //Per Plan's suggestion commented "explicit offline status warning" out to make Dessie happier (see EXT-3609) //*TODO After February 2010 remove this commented out line if no one will be missing that warning @@ -2963,7 +3026,7 @@ void LLIMMgr::removeSession(const LLUUID& session_id) LLIMModel::getInstance()->clearSession(session_id); - LL_INFOS() << "LLIMMgr::removeSession, session removed, session id = " << session_id << LL_ENDL; + LL_INFOS("IMVIEW") << "LLIMMgr::removeSession, session removed, session id = " << session_id << LL_ENDL; notifyObserverSessionRemoved(session_id); } @@ -3029,13 +3092,13 @@ void LLIMMgr::inviteToSession( if (LLMuteList::getInstance()->isMuted(caller_id, LLMute::flagVoiceChat) && voice_invite && "VoiceInviteQuestionDefault" == question_type) { - LL_INFOS() << "Rejecting voice call from initiating muted resident " << caller_name << LL_ENDL; + LL_INFOS("IMVIEW") << "Rejecting voice call from initiating muted resident " << caller_name << LL_ENDL; LLIncomingCallDialog::processCallResponse(1, payload); return; } else if (LLMuteList::getInstance()->isMuted(caller_id, LLMute::flagAll & ~LLMute::flagVoiceChat) && !voice_invite) { - LL_INFOS() << "Rejecting session invite from initiating muted resident " << caller_name << LL_ENDL; + LL_INFOS("IMVIEW") << "Rejecting session invite from initiating muted resident " << caller_name << LL_ENDL; return; } } @@ -3051,7 +3114,7 @@ void LLIMMgr::inviteToSession( if (voice_invite) { bool isRejectGroupCall = (gSavedSettings.getBOOL("VoiceCallsRejectGroup") && (notify_box_type == "VoiceInviteGroup")); - bool isRejectNonFriendCall = (gSavedSettings.getBOOL("VoiceCallsFriendsOnly") && (LLAvatarTracker::instance().getBuddyInfo(caller_id) == NULL)); + bool isRejectNonFriendCall = (gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly") && (LLAvatarTracker::instance().getBuddyInfo(caller_id) == NULL)); if (isRejectGroupCall || isRejectNonFriendCall || gAgent.isDoNotDisturb()) { if (gAgent.isDoNotDisturb() && !isRejectGroupCall && !isRejectNonFriendCall) diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 81d3ffa1a6..79c831ebb6 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -91,6 +91,7 @@ public: bool isOutgoingAdHoc() const; bool isAdHoc(); bool isP2P(); + bool isGroupChat(); bool isOtherParticipantAvaline(); bool isP2PSessionType() const { return mSessionType == P2P_SESSION;} @@ -499,22 +500,26 @@ private: LLSD mPendingAgentListUpdates; }; -class LLCallDialogManager : public LLInitClass<LLCallDialogManager> +class LLCallDialogManager : public LLSingleton<LLCallDialogManager> { -public: - LLCallDialogManager(); + LLSINGLETON(LLCallDialogManager); ~LLCallDialogManager(); - - static void initClass(); +public: + // static for convinience static void onVoiceChannelChanged(const LLUUID &session_id); static void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent); +private: + void initSingleton(); + void onVoiceChannelChangedInt(const LLUUID &session_id); + void onVoiceChannelStateChangedInt(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent); + protected: - static std::string sPreviousSessionlName; - static LLIMModel::LLIMSession::SType sPreviousSessionType; - static std::string sCurrentSessionlName; - static LLIMModel::LLIMSession* sSession; - static LLVoiceChannel::EState sOldState; + std::string mPreviousSessionlName; + LLIMModel::LLIMSession::SType mPreviousSessionType; + std::string mCurrentSessionlName; + LLIMModel::LLIMSession* mSession; + LLVoiceChannel::EState mOldState; }; class LLCallDialog : public LLDockableFloater diff --git a/indra/newview/llinspect.cpp b/indra/newview/llinspect.cpp index e6cb068613..479e8f9abf 100644 --- a/indra/newview/llinspect.cpp +++ b/indra/newview/llinspect.cpp @@ -28,7 +28,7 @@ #include "lltooltip.h" #include "llcontrol.h" // LLCachedControl -#include "llui.h" // LLUI::sSettingsGroups +#include "llui.h" // LLUI::getInstance()->mSettingsGroups #include "llviewermenu.h" LLInspect::LLInspect(const LLSD& key) @@ -45,8 +45,8 @@ LLInspect::~LLInspect() // virtual void LLInspect::draw() { - static LLCachedControl<F32> FADE_TIME(*LLUI::sSettingGroups["config"], "InspectorFadeTime", 1.f); - static LLCachedControl<F32> STAY_TIME(*LLUI::sSettingGroups["config"], "InspectorShowTime", 1.f); + static LLCachedControl<F32> FADE_TIME(*LLUI::getInstance()->mSettingGroups["config"], "InspectorFadeTime", 1.f); + static LLCachedControl<F32> STAY_TIME(*LLUI::getInstance()->mSettingGroups["config"], "InspectorShowTime", 1.f); if (mOpenTimer.getStarted()) { LLFloater::draw(); @@ -113,7 +113,7 @@ BOOL LLInspect::handleToolTip(S32 x, S32 y, MASK mask) params.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); params.message = child_handler->getToolTip(); //set up delay if there is no visible tooltip at this moment - params.delay_time = LLToolTipMgr::instance().toolTipVisible() ? 0.f : LLUI::sSettingGroups["config"]->getF32( "ToolTipDelay" ); + params.delay_time = LLToolTipMgr::instance().toolTipVisible() ? 0.f : LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipDelay" ); LLToolTipMgr::instance().show(params); handled = TRUE; } @@ -137,7 +137,7 @@ bool LLInspect::childHasVisiblePopupMenu() LLRect floater_rc = calcScreenRect(); LLRect menu_screen_rc = child_menu->calcScreenRect(); S32 mx, my; - LLUI::getMousePositionScreen(&mx, &my); + LLUI::getInstance()->getMousePositionScreen(&mx, &my); // This works wrong if we spawn a menu near Inspector and menu overlaps Inspector. if(floater_rc.overlaps(menu_screen_rc) && menu_screen_rc.pointInRect(mx, my)) diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index 88e7ad1b71..10814ac076 100644 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -207,11 +207,11 @@ void LLInspectAvatar::onOpen(const LLSD& data) // See LLToolTipMgr::createToolTip if (data.has("pos")) { - LLUI::positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger()); + LLUI::getInstance()->positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger()); } else { - LLUI::positionViewNearMouse(this); + LLUI::getInstance()->positionViewNearMouse(this); } // Generate link to avatar profile. diff --git a/indra/newview/llinspectgroup.cpp b/indra/newview/llinspectgroup.cpp index 8332443162..fa8a53c546 100644 --- a/indra/newview/llinspectgroup.cpp +++ b/indra/newview/llinspectgroup.cpp @@ -129,11 +129,11 @@ void LLInspectGroup::onOpen(const LLSD& data) // See LLToolTipMgr::createToolTip if (data.has("pos")) { - LLUI::positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger()); + LLUI::getInstance()->positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger()); } else { - LLUI::positionViewNearMouse(this); + LLUI::getInstance()->positionViewNearMouse(this); } // can't call from constructor as widgets are not built yet diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp index 46019557f8..f78a5cc64e 100644 --- a/indra/newview/llinspectobject.cpp +++ b/indra/newview/llinspectobject.cpp @@ -202,11 +202,11 @@ void LLInspectObject::onOpen(const LLSD& data) // See LLToolTipMgr::createToolTip if (data.has("pos")) { - LLUI::positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger()); + LLUI::getInstance()->positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger()); } else { - LLUI::positionViewNearMouse(this); + LLUI::getInstance()->positionViewNearMouse(this); } // Promote hovered object to a complete selection, which will also force @@ -241,7 +241,7 @@ void LLInspectObject::onOpen(const LLSD& data) if(!mMediaEntry) return; - mMediaImpl = LLViewerMedia::getMediaImplFromTextureID(mMediaEntry->getMediaID()); + mMediaImpl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mMediaEntry->getMediaID()); } } @@ -300,7 +300,7 @@ void LLInspectObject::update() if(!mMediaEntry) return; - mMediaImpl = LLViewerMedia::getMediaImplFromTextureID(mMediaEntry->getMediaID()); + mMediaImpl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mMediaEntry->getMediaID()); updateMediaCurrentURL(); updateSecureBrowsing(); diff --git a/indra/newview/llinspectremoteobject.cpp b/indra/newview/llinspectremoteobject.cpp index b64df2bd47..272c8acbd5 100644 --- a/indra/newview/llinspectremoteobject.cpp +++ b/indra/newview/llinspectremoteobject.cpp @@ -116,11 +116,11 @@ void LLInspectRemoteObject::onOpen(const LLSD& data) // See LLToolTipMgr::createToolTip if (data.has("pos")) { - LLUI::positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger()); + LLUI::getInstance()->positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger()); } else { - LLUI::positionViewNearMouse(this); + LLUI::getInstance()->positionViewNearMouse(this); } } diff --git a/indra/newview/llinspecttoast.cpp b/indra/newview/llinspecttoast.cpp index 47560341e7..d0034eff13 100644 --- a/indra/newview/llinspecttoast.cpp +++ b/indra/newview/llinspecttoast.cpp @@ -110,7 +110,7 @@ void LLInspectToast::onOpen(const LLSD& notification_id) panel_rect = panel->getRect(); reshape(panel_rect.getWidth(), panel_rect.getHeight()); - LLUI::positionViewNearMouse(this); + LLUI::getInstance()->positionViewNearMouse(this); } // virtual diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 349ba6183b..fc8179f3b4 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -81,6 +81,10 @@ #include "llwearableitemslist.h" #include "lllandmarkactions.h" #include "llpanellandmarks.h" +#include "llviewerparcelmgr.h" +#include "llparcel.h" + +#include "llenvironment.h" #include <boost/shared_ptr.hpp> @@ -1408,6 +1412,14 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, //LL_WARNS() << LLAssetType::lookup(asset_type) << " asset type is unhandled for uuid " << uuid << LL_ENDL; break; + case LLAssetType::AT_SETTINGS: + if (inv_type != LLInventoryType::IT_SETTINGS) + { + LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; + } + new_listener = new LLSettingsBridge(inventory, root, uuid, LLSettingsType::fromInventoryFlags(flags)); + break; + default: LL_INFOS_ONCE() << "Unhandled asset type (llassetstorage.h): " << (S32)asset_type << " (" << LLAssetType::lookup(asset_type) << ")" << LL_ENDL; @@ -1797,7 +1809,7 @@ void LLItemBridge::restoreToWorld() msg->nextBlockFast(_PREHASH_InventoryData); itemp->packMessage(msg); - msg->sendReliable(gAgent.getRegion()->getHost()); + msg->sendReliable(gAgent.getRegionHost()); //remove local inventory copy, sim will deal with permissions and removing the item //from the actual inventory if its a no-copy etc @@ -1823,28 +1835,11 @@ void LLItemBridge::restoreToWorld() void LLItemBridge::gotoItem() { - LLInventoryObject *obj = getInventoryObject(); - if (obj && obj->getIsLinkType()) - { - const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX); - if (gInventory.isObjectDescendentOf(obj->getLinkedUUID(), inbox_id)) - { - LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); - if (sidepanel_inventory && sidepanel_inventory->getInboxPanel()) - { - sidepanel_inventory->getInboxPanel()->setSelection(obj->getLinkedUUID(), TAKE_FOCUS_NO); - } - } - else - { - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); - if (active_panel) - { - active_panel->setSelection(obj->getLinkedUUID(), TAKE_FOCUS_NO); - } - } - - } + LLInventoryObject *obj = getInventoryObject(); + if (obj && obj->getIsLinkType()) + { + show_item_original(obj->getUUID()); + } } LLUIImagePtr LLItemBridge::getIcon() const @@ -2270,7 +2265,7 @@ public: // Can be destroyed (or moved to trash) BOOL LLFolderBridge::isItemRemovable() const { - if (!get_is_category_removable(getInventoryModel(), mUUID) || isMarketplaceListingsFolder()) + if (!get_is_category_removable(getInventoryModel(), mUUID)) { return FALSE; } @@ -2287,6 +2282,11 @@ BOOL LLFolderBridge::isItemRemovable() const } } + if (isMarketplaceListingsFolder() && (!LLMarketplaceData::instance().isSLMDataFetched() || LLMarketplaceData::instance().getActivationState(mUUID))) + { + return FALSE; + } + return TRUE; } @@ -3970,6 +3970,12 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); const LLUUID &favorites = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE); const LLUUID &marketplace_listings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID &outfits_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); + + if (outfits_id == mUUID) + { + items.push_back(std::string("New Outfit")); + } if (lost_and_found_id == mUUID) { @@ -3988,6 +3994,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items 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 Settings")); 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")); @@ -4067,7 +4074,8 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items // Not sure what the right thing is to do here. if (!isCOFFolder() && cat && (cat->getPreferredType() != LLFolderType::FT_OUTFIT)) { - if (!isInboxFolder()) // don't allow creation in inbox + if (!isInboxFolder() // don't allow creation in inbox + && outfits_id != mUUID) { // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694. if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat)) @@ -4081,7 +4089,14 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items items.push_back(std::string("New Gesture")); items.push_back(std::string("New Clothes")); items.push_back(std::string("New Body Parts")); + items.push_back(std::string("New Settings")); items.push_back(std::string("upload_def")); + + if (!LLEnvironment::instance().isInventoryEnabled()) + { + disabled_items.push_back("New Settings"); + } + } } getClipboardEntries(false, items, disabled_items, flags); @@ -4347,6 +4362,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, case DAD_ANIMATION: case DAD_GESTURE: case DAD_MESH: + case DAD_SETTINGS: accept = dragItemIntoFolder(inv_item, drop, tooltip_msg); break; case DAD_LINK: @@ -4662,7 +4678,7 @@ bool move_task_inventory_callback(const LLSD& notification, const LLSD& response { LLInventoryObject::object_list_t inventory_objects; object->getInventoryContents(inventory_objects); - int contents_count = inventory_objects.size()-1; //subtract one for containing folder + int contents_count = inventory_objects.size(); LLInventoryCopyAndWearObserver* inventoryObserver = new LLInventoryCopyAndWearObserver(cat_and_wear->mCatID, contents_count, cat_and_wear->mFolderResponded, cat_and_wear->mReplace); @@ -5226,6 +5242,11 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); accept = FALSE; } + else if ((inv_item->getActualType() == LLAssetType::AT_SETTINGS) && !LLEnvironment::instance().isInventoryEnabled()) + { + tooltip_msg = LLTrans::getString("NoEnvironmentSettings"); + accept = FALSE; + } else { // Don't allow placing an original item from a notecard to Current Outfit or an outfit folder @@ -5942,6 +5963,7 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, case DAD_ANIMATION: case DAD_GESTURE: case DAD_MESH: + case DAD_SETTINGS: { LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data; const LLPermissions& perm = inv_item->getPermissions(); @@ -6353,6 +6375,14 @@ void LLObjectBridge::performAction(LLInventoryModel* model, std::string action) { LLAppearanceMgr::instance().wearItemOnAvatar(mUUID, true, false); // Don't replace if adding. } + else if ("touch" == action) + { + handle_attachment_touch(mUUID); + } + else if ("edit" == action) + { + handle_attachment_edit(mUUID); + } else if (isRemoveAction(action)) { LLAppearanceMgr::instance().removeItemFromAvatar(mUUID); @@ -6503,6 +6533,19 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) if( get_is_item_worn( mUUID ) ) { items.push_back(std::string("Wearable And Object Separator")); + + items.push_back(std::string("Attachment Touch")); + if ( ((flags & FIRST_SELECTED_ITEM) == 0) || !enable_attachment_touch(mUUID) ) + { + disabled_items.push_back(std::string("Attachment Touch")); + } + + items.push_back(std::string("Wearable Edit")); + if ( ((flags & FIRST_SELECTED_ITEM) == 0) || !get_is_item_editable(mUUID) ) + { + disabled_items.push_back(std::string("Wearable Edit")); + } + items.push_back(std::string("Detach From Yourself")); } else if (!isItemInTrash() && !isLinkedObjectInTrash() && !isLinkedObjectMissing() && !isCOFFolder()) @@ -6963,6 +7006,153 @@ void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) hide_context_entries(menu, items, disabled_items); } +// +=================================================+ +// | LLSettingsBridge | +// +=================================================+ + +LLSettingsBridge::LLSettingsBridge(LLInventoryPanel* inventory, + LLFolderView* root, + const LLUUID& uuid, + LLSettingsType::type_e settings_type): + LLItemBridge(inventory, root, uuid), + mSettingsType(settings_type) +{ +} + +LLUIImagePtr LLSettingsBridge::getIcon() const +{ + return LLInventoryIcon::getIcon(LLAssetType::AT_SETTINGS, LLInventoryType::IT_SETTINGS, mSettingsType, FALSE); +} + +void LLSettingsBridge::performAction(LLInventoryModel* model, std::string action) +{ + if ("apply_settings_local" == action) + { + // Single item only + LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem()); + if (!item) + return; + LLUUID asset_id = item->getAssetUUID(); + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, asset_id, LLEnvironment::TRANSITION_INSTANT); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); + } + else if ("apply_settings_parcel" == action) + { + // Single item only + LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem()); + if (!item) + return; + LLUUID asset_id = item->getAssetUUID(); + std::string name = item->getName(); + + U32 flags(0); + + if (!item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID())) + flags |= LLSettingsBase::FLAG_NOMOD; + if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID())) + flags |= LLSettingsBase::FLAG_NOTRANS; + + LLParcel *parcel = LLViewerParcelMgr::instance().getAgentOrSelectedParcel(); + if (!parcel) + { + LL_WARNS("INVENTORY") << "could not identify parcel." << LL_ENDL; + return; + } + S32 parcel_id = parcel->getLocalID(); + + LL_DEBUGS("ENVIRONMENT") << "Applying asset ID " << asset_id << " to parcel " << parcel_id << LL_ENDL; + LLEnvironment::instance().updateParcel(parcel_id, asset_id, name, LLEnvironment::NO_TRACK, -1, -1, flags); + LLEnvironment::instance().setSharedEnvironment(); + } + else + LLItemBridge::performAction(model, action); +} + +void LLSettingsBridge::openItem() +{ + LLViewerInventoryItem* item = getItem(); + if (item) + { + if (item->getPermissions().getOwner() != gAgent.getID()) + LLNotificationsUtil::add("NoEditFromLibrary"); + else + LLInvFVBridgeAction::doAction(item->getType(), mUUID, getInventoryModel()); + } +} + +void LLSettingsBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + LL_DEBUGS() << "LLSettingsBridge::buildContextMenu()" << LL_ENDL; + menuentry_vec_t items; + menuentry_vec_t disabled_items; + + 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 if (isItemInTrash()) + { + addTrashContextMenuOptions(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")); + + getClipboardEntries(true, items, disabled_items, flags); + + items.push_back("Settings Separator"); + items.push_back("Settings Apply Local"); + + items.push_back("Settings Apply Parcel"); + if (!canUpdateParcel()) + disabled_items.push_back("Settings Apply Parcel"); + + items.push_back("Settings Apply Region"); + if (!canUpdateRegion()) + disabled_items.push_back("Settings Apply Region"); + } + addLinkReplaceMenuOption(items, disabled_items); + hide_context_entries(menu, items, disabled_items); +} + +BOOL LLSettingsBridge::renameItem(const std::string& new_name) +{ + /*TODO: change internal settings name? */ + return LLItemBridge::renameItem(new_name); +} + +BOOL LLSettingsBridge::isItemRenameable() const +{ + LLViewerInventoryItem* item = getItem(); + if (item) + { + return (item->getPermissions().allowModifyBy(gAgent.getID())); + } + return FALSE; +} + +bool LLSettingsBridge::canUpdateParcel() const +{ + return LLEnvironment::instance().canAgentUpdateParcelEnvironment(); +} + +bool LLSettingsBridge::canUpdateRegion() const +{ + return LLEnvironment::instance().canAgentUpdateRegionEnvironment(); +} + // +=================================================+ // | LLLinkBridge | @@ -7018,21 +7208,17 @@ void LLLinkFolderBridge::performAction(LLInventoryModel* model, std::string acti } void LLLinkFolderBridge::gotoItem() { - const LLUUID &cat_uuid = getFolderID(); - if (!cat_uuid.isNull()) - { - LLFolderViewItem *base_folder = mInventoryPanel.get()->getItemByID(cat_uuid); - if (base_folder) - { - if (LLInventoryModel* model = getInventoryModel()) - { - model->fetchDescendentsOf(cat_uuid); - } - base_folder->setOpen(TRUE); - mRoot->setSelection(base_folder,TRUE); - mRoot->scrollToShowSelection(); - } - } + LLItemBridge::gotoItem(); + + const LLUUID &cat_uuid = getFolderID(); + if (!cat_uuid.isNull()) + { + LLFolderViewItem *base_folder = LLInventoryPanel::getActiveInventoryPanel()->getItemByID(cat_uuid); + if (base_folder) + { + base_folder->setOpen(TRUE); + } + } } const LLUUID &LLLinkFolderBridge::getFolderID() const { @@ -7322,6 +7508,40 @@ void LLWearableBridgeAction::wearOnAvatar() } } +class LLSettingsBridgeAction + : public LLInvFVBridgeAction +{ + friend class LLInvFVBridgeAction; +public: + virtual void doIt() + { + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLSettingsType::type_e type = item->getSettingsType(); + switch (type) + { + case LLSettingsType::ST_SKY: + LLFloaterReg::showInstance("env_fixed_environmentent_sky", LLSDMap("inventory_id", item->getUUID()), TAKE_FOCUS_YES); + break; + case LLSettingsType::ST_WATER: + LLFloaterReg::showInstance("env_fixed_environmentent_water", LLSDMap("inventory_id", item->getUUID()), TAKE_FOCUS_YES); + break; + case LLSettingsType::ST_DAYCYCLE: + LLFloaterReg::showInstance("env_edit_extdaycycle", LLSDMap("inventory_id", item->getUUID())("edit_context", "inventory"), TAKE_FOCUS_YES); + break; + default: + break; + } + } + LLInvFVBridgeAction::doIt(); + } + virtual ~LLSettingsBridgeAction(){} +protected: + LLSettingsBridgeAction(const LLUUID& id, LLInventoryModel* model) : LLInvFVBridgeAction(id, model) {} +}; + + LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_type, const LLUUID& uuid, LLInventoryModel* model) @@ -7360,6 +7580,9 @@ LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_ case LLAssetType::AT_BODYPART: action = new LLWearableBridgeAction(uuid,model); break; + case LLAssetType::AT_SETTINGS: + action = new LLSettingsBridgeAction(uuid, model); + break; default: break; } @@ -7434,11 +7657,11 @@ void LLFolderViewGroupedItemBridge::groupFilterContextMenu(folder_view_item_dequ disable_context_entries_if_present(menu, disabled_items); } -bool LLFolderViewGroupedItemBridge::canWearSelected(uuid_vec_t item_ids) +bool LLFolderViewGroupedItemBridge::canWearSelected(const uuid_vec_t& item_ids) const { for (uuid_vec_t::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it) { - LLViewerInventoryItem* item = gInventory.getItem(*it); + const LLViewerInventoryItem* item = gInventory.getItem(*it); if (!item || (item->getType() >= LLAssetType::AT_COUNT) || (item->getType() <= LLAssetType::AT_NONE)) { return false; diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 0823cf8b52..9af8664388 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -38,6 +38,7 @@ #include "lltooldraganddrop.h" #include "lllandmarklist.h" #include "llfolderviewitem.h" +#include "llsettingsbase.h" class LLInventoryFilter; class LLInventoryPanel; @@ -108,6 +109,7 @@ public: virtual void closeItem() {} virtual void showProperties(); virtual BOOL isItemRenameable() const { return TRUE; } + virtual BOOL isMultiPreviewAllowed() { return TRUE; } //virtual BOOL renameItem(const std::string& new_name) {} virtual BOOL isItemRemovable() const; virtual BOOL isItemMovable() const; @@ -136,6 +138,7 @@ public: std::string& tooltip_msg) { return FALSE; } virtual LLInventoryType::EType getInventoryType() const { return mInvType; } virtual LLWearableType::EType getWearableType() const { return LLWearableType::WT_NONE; } + virtual LLSettingsType::type_e getSettingsType() const { return LLSettingsType::ST_NONE; } EInventorySortGroup getSortGroup() const { return SG_ITEM; } virtual LLInventoryObject* getInventoryObject() const; @@ -605,6 +608,31 @@ protected: static std::string sPrefix; }; + +class LLSettingsBridge : public LLItemBridge +{ +public: + LLSettingsBridge(LLInventoryPanel* inventory, + LLFolderView* root, + const LLUUID& uuid, + LLSettingsType::type_e settings_type); + virtual LLUIImagePtr getIcon() const; + virtual void performAction(LLInventoryModel* model, std::string action); + virtual void openItem(); + virtual BOOL isMultiPreviewAllowed() { return FALSE; } + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + virtual BOOL renameItem(const std::string& new_name); + virtual BOOL isItemRenameable() const; + virtual LLSettingsType::type_e getSettingsType() const { return mSettingsType; } + +protected: + bool canUpdateRegion() const; + bool canUpdateParcel() const; + + LLSettingsType::type_e mSettingsType; + +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInvFVBridgeAction // @@ -732,7 +760,7 @@ class LLFolderViewGroupedItemBridge: public LLFolderViewGroupedItemModel public: LLFolderViewGroupedItemBridge(); virtual void groupFilterContextMenu(folder_view_item_deque& selected_items, LLMenuGL& menu); - bool canWearSelected(uuid_vec_t item_ids); + bool canWearSelected(const uuid_vec_t& item_ids) const; }; #endif // LL_LLINVENTORYBRIDGE_H diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 16385928b4..411311bbea 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -42,7 +42,7 @@ #include "llviewerfoldertype.h" #include "llradiogroup.h" #include "llstartup.h" - +#include <boost/regex.hpp> // linden library includes #include "llclipboard.h" #include "lltrans.h" @@ -53,6 +53,7 @@ LLInventoryFilter::FilterOps::FilterOps(const Params& p) : mFilterObjectTypes(p.object_types), mFilterCategoryTypes(p.category_types), mFilterWearableTypes(p.wearable_types), + mFilterSettingsTypes(p.settings_types), mMinDate(p.date_range.min_date), mMaxDate(p.date_range.max_date), mHoursAgo(p.hours_ago), @@ -62,7 +63,8 @@ LLInventoryFilter::FilterOps::FilterOps(const Params& p) mPermissions(p.permissions), mFilterTypes(p.types), mFilterUUID(p.uuid), - mFilterLinks(p.links) + mFilterLinks(p.links), + mSearchVisibility(p.search_visibility) { } @@ -73,6 +75,7 @@ LLInventoryFilter::LLInventoryFilter(const Params& p) : mName(p.name), mFilterModified(FILTER_NONE), mEmptyLookupMessage("InventoryNoMatchingItems"), + mDefaultEmptyLookupMessage(""), mFilterOps(p.filter_ops), mBackupFilterOps(mFilterOps), mFilterSubString(p.substring), @@ -116,11 +119,44 @@ bool LLInventoryFilter::check(const LLFolderViewModelItem* item) break; } - bool passed = (mFilterSubString.size() ? desc.find(mFilterSubString) != std::string::npos : true); + + bool passed = true; + if (!mExactToken.empty() && (mSearchType == SEARCHTYPE_NAME)) + { + passed = false; + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep(" "); + tokenizer tokens(desc, sep); + + for (auto token_iter : tokens) + { + if (token_iter == mExactToken) + { + passed = true; + break; + } + } + } + else if ((mFilterTokens.size() > 0) && (mSearchType == SEARCHTYPE_NAME)) + { + for (auto token_iter : mFilterTokens) + { + if (desc.find(token_iter) == std::string::npos) + { + return false; + } + } + } + else + { + passed = (mFilterSubString.size() ? desc.find(mFilterSubString) != std::string::npos : true); + } + passed = passed && checkAgainstFilterType(listener); passed = passed && checkAgainstPermissions(listener); passed = passed && checkAgainstFilterLinks(listener); passed = passed && checkAgainstCreator(listener); + passed = passed && checkAgainstSearchVisibility(listener); return passed; } @@ -159,10 +195,15 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const // 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); + { + LLViewerInventoryCategory* cat = gInventory.getCategory(folder_id); + if (!cat || (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)) + { + // At the moment background fetch only cares about VERSION_UNKNOWN, + // so do not check isCategoryComplete that compares descendant count + LLInventoryModelBackgroundFetch::instance().start(folder_id); + } } // Marketplace folder filtering @@ -254,21 +295,34 @@ bool LLInventoryFilter::checkAgainstFilterType(const LLFolderViewModelItemInvent // 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 (object && object->getIsLinkType()) - { - return FALSE; - } - } - else if ((1LL << object_type & mFilterOps.mFilterObjectTypes) == U64(0)) - { - return FALSE; - } + switch (object_type) + { + case LLInventoryType::IT_NONE: + // If it has no type, pass it, unless it's a link. + if (object && object->getIsLinkType()) + { + return FALSE; + } + break; + case LLInventoryType::IT_UNKNOWN: + { + // Unknows are only shown when we show every type. + // Unknows are 255 and won't fit in 64 bits. + if (mFilterOps.mFilterObjectTypes != 0xffffffffffffffffULL) + { + return FALSE; + } + break; + } + default: + if ((1LL << object_type & mFilterOps.mFilterObjectTypes) == U64(0)) + { + return FALSE; + } + break; + } } - + if(filterTypes & FILTERTYPE_WORN) { if (!get_is_item_worn(object_id)) @@ -325,7 +379,21 @@ bool LLInventoryFilter::checkAgainstFilterType(const LLFolderViewModelItemInvent if (filterTypes & FILTERTYPE_WEARABLE) { LLWearableType::EType type = listener->getWearableType(); - if ((0x1LL << type & mFilterOps.mFilterWearableTypes) == 0) + if ((object_type == LLInventoryType::IT_WEARABLE) && + (((0x1LL << type) & mFilterOps.mFilterWearableTypes) == 0)) + { + return FALSE; + } + } + + //////////////////////////////////////////////////////////////////////////////// + // FILTERTYPE_SETTINGS + // Pass if this item is a setting of the appropriate type + if (filterTypes & FILTERTYPE_SETTINGS) + { + LLSettingsType::type_e type = listener->getSettingsType(); + if ((object_type == LLInventoryType::IT_SETTINGS) && + (((0x1LL << type) & mFilterOps.mFilterSettingsTypes) == 0)) { return FALSE; } @@ -379,18 +447,32 @@ bool LLInventoryFilter::checkAgainstFilterType(const LLInventoryItem* item) cons // 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; - } + switch (object_type) + { + case LLInventoryType::IT_NONE: + // If it has no type, pass it, unless it's a link. + if (item && item->getIsLinkType()) + { + return FALSE; + } + break; + case LLInventoryType::IT_UNKNOWN: + { + // Unknows are only shown when we show every type. + // Unknows are 255 and won't fit in 64 bits. + if (mFilterOps.mFilterObjectTypes != 0xffffffffffffffffULL) + { + return FALSE; + } + break; + } + default: + if ((1LL << object_type & mFilterOps.mFilterObjectTypes) == U64(0)) + { + return FALSE; + } + break; + } } //////////////////////////////////////////////////////////////////////////////// @@ -503,6 +585,27 @@ bool LLInventoryFilter::checkAgainstCreator(const LLFolderViewModelItemInventory } } +bool LLInventoryFilter::checkAgainstSearchVisibility(const LLFolderViewModelItemInventory* listener) const +{ + if (!listener || !hasFilterString()) return TRUE; + + const LLUUID object_id = listener->getUUID(); + const LLInventoryObject *object = gInventory.getObject(object_id); + if (!object) return TRUE; + + const BOOL is_link = object->getIsLinkType(); + if (is_link && ((mFilterOps.mSearchVisibility & VISIBILITY_LINKS) == 0)) + return FALSE; + + if (listener->isItemInTrash() && ((mFilterOps.mSearchVisibility & VISIBILITY_TRASH) == 0)) + return FALSE; + + if (!listener->isAgentInventory() && ((mFilterOps.mSearchVisibility & VISIBILITY_LIBRARY) == 0)) + return FALSE; + + return TRUE; +} + const std::string& LLInventoryFilter::getFilterSubString(BOOL trim) const { return mFilterSubString; @@ -626,6 +729,12 @@ void LLInventoryFilter::setFilterWearableTypes(U64 types) mFilterOps.mFilterTypes |= FILTERTYPE_WEARABLE; } +void LLInventoryFilter::setFilterSettingsTypes(U64 types) +{ + updateFilterTypes(types, mFilterOps.mFilterSettingsTypes); + mFilterOps.mFilterTypes |= FILTERTYPE_SETTINGS; +} + void LLInventoryFilter::setFilterEmptySystemFolders() { mFilterOps.mFilterTypes |= FILTERTYPE_EMPTYFOLDERS; @@ -665,6 +774,61 @@ void LLInventoryFilter::setFilterMarketplaceListingFolders(bool select_only_list } } + +void LLInventoryFilter::toggleSearchVisibilityLinks() +{ + bool hide_links = mFilterOps.mSearchVisibility & VISIBILITY_LINKS; + if (hide_links) + { + mFilterOps.mSearchVisibility &= ~VISIBILITY_LINKS; + } + else + { + mFilterOps.mSearchVisibility |= VISIBILITY_LINKS; + } + + if (hasFilterString()) + { + setModified(hide_links ? FILTER_MORE_RESTRICTIVE : FILTER_LESS_RESTRICTIVE); + } +} + +void LLInventoryFilter::toggleSearchVisibilityTrash() +{ + bool hide_trash = mFilterOps.mSearchVisibility & VISIBILITY_TRASH; + if (hide_trash) + { + mFilterOps.mSearchVisibility &= ~VISIBILITY_TRASH; + } + else + { + mFilterOps.mSearchVisibility |= VISIBILITY_TRASH; + } + + if (hasFilterString()) + { + setModified(hide_trash ? FILTER_MORE_RESTRICTIVE : FILTER_LESS_RESTRICTIVE); + } +} + +void LLInventoryFilter::toggleSearchVisibilityLibrary() +{ + bool hide_library = mFilterOps.mSearchVisibility & VISIBILITY_LIBRARY; + if (hide_library) + { + mFilterOps.mSearchVisibility &= ~VISIBILITY_LIBRARY; + } + else + { + mFilterOps.mSearchVisibility |= VISIBILITY_LIBRARY; + } + + if (hasFilterString()) + { + setModified(hide_library ? FILTER_MORE_RESTRICTIVE : FILTER_LESS_RESTRICTIVE); + } +} + void LLInventoryFilter::setFilterNoMarketplaceFolder() { mFilterOps.mFilterTypes |= FILTERTYPE_NO_MARKETPLACE_ITEMS; @@ -693,6 +857,38 @@ void LLInventoryFilter::setFilterSubString(const std::string& string) if (mFilterSubString != filter_sub_string_new) { + + mFilterTokens.clear(); + if (filter_sub_string_new.find_first_of("+") != std::string::npos) + { + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep("+"); + tokenizer tokens(filter_sub_string_new, sep); + + for (auto token_iter : tokens) + { + mFilterTokens.push_back(token_iter); + } + } + + std::string old_token = mExactToken; + mExactToken.clear(); + bool exact_token_changed = false; + if (mFilterTokens.empty() && filter_sub_string_new.size() > 2) + { + boost::regex mPattern = boost::regex("\"\\s*([^<]*)?\\s*\"", + boost::regex::perl | boost::regex::icase); + boost::match_results<std::string::const_iterator> matches; + mExactToken = (boost::regex_match(filter_sub_string_new, matches, mPattern) && matches[1].matched) + ? matches[1] + : LLStringUtil::null; + if ((old_token.empty() && !mExactToken.empty()) + || (!old_token.empty() && mExactToken.empty())) + { + exact_token_changed = true; + } + } + // hitting BACKSPACE, for example const BOOL less_restrictive = mFilterSubString.size() >= filter_sub_string_new.size() && !mFilterSubString.substr(0, filter_sub_string_new.size()).compare(filter_sub_string_new); @@ -702,7 +898,11 @@ void LLInventoryFilter::setFilterSubString(const std::string& string) && !filter_sub_string_new.substr(0, mFilterSubString.size()).compare(mFilterSubString); mFilterSubString = filter_sub_string_new; - if (less_restrictive) + if (exact_token_changed) + { + setModified(FILTER_RESTART); + } + else if (less_restrictive) { setModified(FILTER_LESS_RESTRICTIVE); } @@ -740,6 +940,44 @@ void LLInventoryFilter::setFilterSubString(const std::string& string) } } +void LLInventoryFilter::setSearchVisibilityTypes(U32 types) +{ + if (mFilterOps.mSearchVisibility != types) + { + // keep current items only if no perm bits getting turned off + BOOL fewer_bits_set = (mFilterOps.mSearchVisibility & ~types); + BOOL more_bits_set = (~mFilterOps.mSearchVisibility & types); + mFilterOps.mSearchVisibility = types; + + if (more_bits_set && fewer_bits_set) + { + setModified(FILTER_RESTART); + } + else if (more_bits_set) + { + // target must have all requested permission bits, so more bits == more restrictive + setModified(FILTER_MORE_RESTRICTIVE); + } + else if (fewer_bits_set) + { + setModified(FILTER_LESS_RESTRICTIVE); + } + } +} + +void LLInventoryFilter::setSearchVisibilityTypes(const Params& params) +{ + if (!params.validateBlock()) + { + return; + } + + if (params.filter_ops.search_visibility.isProvided()) + { + setSearchVisibilityTypes(params.filter_ops.search_visibility); + } +} + void LLInventoryFilter::setFilterPermissions(PermissionMask perms) { if (mFilterOps.mPermissions != perms) @@ -1141,6 +1379,18 @@ const std::string& LLInventoryFilter::getFilterText() filtered_by_all_types = FALSE; } + if (isFilterObjectTypesWith(LLInventoryType::IT_SETTINGS)) + { + filtered_types += LLTrans::getString("Settings"); + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + not_filtered_types += LLTrans::getString("Settings"); + filtered_by_all_types = FALSE; + } + if (!LLInventoryModelBackgroundFetch::instance().folderFetchActive() && filtered_by_type && !filtered_by_all_types) @@ -1196,6 +1446,7 @@ void LLInventoryFilter::toParams(Params& params) const params.filter_ops.show_folder_state = getShowFolderState(); params.filter_ops.creator_type = getFilterCreatorType(); params.filter_ops.permissions = getFilterPermissions(); + params.filter_ops.search_visibility = getSearchVisibilityTypes(); params.substring = getFilterSubString(); params.since_logoff = isSinceLogoff(); } @@ -1219,6 +1470,7 @@ void LLInventoryFilter::fromParams(const Params& params) setShowFolderState(params.filter_ops.show_folder_state); setFilterCreator(params.filter_ops.creator_type); setFilterPermissions(params.filter_ops.permissions); + setSearchVisibilityTypes(params.filter_ops.search_visibility); setFilterSubString(params.substring); setDateRangeLastLogoff(params.since_logoff); } @@ -1243,6 +1495,16 @@ U64 LLInventoryFilter::getFilterWearableTypes() const return mFilterOps.mFilterWearableTypes; } +U64 LLInventoryFilter::getFilterSettingsTypes() const +{ + return mFilterOps.mFilterSettingsTypes; +} + +U64 LLInventoryFilter::getSearchVisibilityTypes() const +{ + return mFilterOps.mSearchVisibility; +} + bool LLInventoryFilter::hasFilterString() const { return mFilterSubString.size() > 0; @@ -1315,12 +1577,24 @@ void LLInventoryFilter::setEmptyLookupMessage(const std::string& message) mEmptyLookupMessage = message; } +void LLInventoryFilter::setDefaultEmptyLookupMessage(const std::string& message) +{ + mDefaultEmptyLookupMessage = message; +} + std::string LLInventoryFilter::getEmptyLookupMessage() const { - LLStringUtil::format_map_t args; - args["[SEARCH_TERM]"] = LLURI::escape(getFilterSubStringOrig()); + if (isDefault() && !mDefaultEmptyLookupMessage.empty()) + { + return LLTrans::getString(mDefaultEmptyLookupMessage); + } + else + { + LLStringUtil::format_map_t args; + args["[SEARCH_TERM]"] = LLURI::escape(getFilterSubStringOrig()); - return LLTrans::getString(mEmptyLookupMessage, args); + return LLTrans::getString(mEmptyLookupMessage, args); + } } diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h index 4a1fec8454..384de3e889 100644 --- a/indra/newview/llinventoryfilter.h +++ b/indra/newview/llinventoryfilter.h @@ -59,6 +59,7 @@ public: 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, // pass if item is worn + FILTERTYPE_SETTINGS = 0x1 << 12, // pass if the item is a settings object }; enum EFilterDateDirection @@ -80,7 +81,7 @@ public: 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_FOLDERS_BY_WEIGHT = 0x1 << 3, // Force folder sort by weight, usually, amount of some elements in their descendents + SO_FOLDERS_BY_WEIGHT = 0x1 << 3, // Force folder sort by weight, usually, amount of some elements in their descendants }; enum ESearchType @@ -98,6 +99,14 @@ public: FILTERCREATOR_OTHERS }; + enum ESearchVisibility + { + VISIBILITY_NONE = 0, + VISIBILITY_TRASH = 0x1 << 0, + VISIBILITY_LIBRARY = 0x1 << 1, + VISIBILITY_LINKS = 0x1 << 2 + }; + struct FilterOps { struct DateRange : public LLInitParam::Block<DateRange> @@ -115,10 +124,13 @@ public: struct Params : public LLInitParam::Block<Params> { - Optional<U32> types; + Optional<U32> types, + search_visibility; Optional<U64> object_types, wearable_types, + settings_types, category_types; + Optional<EFilterLink> links; Optional<LLUUID> uuid; Optional<DateRange> date_range; @@ -132,8 +144,10 @@ public: : types("filter_types", FILTERTYPE_OBJECT), object_types("object_types", 0xffffFFFFffffFFFFULL), wearable_types("wearable_types", 0xffffFFFFffffFFFFULL), + settings_types("settings_types", 0xffffFFFFffffFFFFULL), category_types("category_types", 0xffffFFFFffffFFFFULL), links("links", FILTERLINK_INCLUDE_LINKS), + search_visibility("search_visibility", 0xFFFFFFFF), uuid("uuid"), date_range("date_range"), hours_ago("hours_ago", 0), @@ -146,9 +160,11 @@ public: FilterOps(const Params& = Params()); - U32 mFilterTypes; + U32 mFilterTypes, + mSearchVisibility; U64 mFilterObjectTypes, // For _OBJECT mFilterWearableTypes, + mFilterSettingsTypes, // for _SETTINGS mFilterLinks, mFilterCategoryTypes; // For _CATEGORY LLUUID mFilterUUID; // for UUID @@ -158,8 +174,8 @@ public: U32 mHoursAgo; U32 mDateSearchDirection; - EFolderShow mShowFolderState; - PermissionMask mPermissions; + EFolderShow mShowFolderState; + PermissionMask mPermissions; EFilterCreatorType mFilterCreatorType; }; @@ -189,11 +205,15 @@ public: U64 getFilterObjectTypes() const; U64 getFilterCategoryTypes() const; U64 getFilterWearableTypes() const; + U64 getFilterSettingsTypes() const; + U64 getSearchVisibilityTypes() 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 setFilterSettingsTypes(U64 types); void setFilterEmptySystemFolders(); void setFilterWorn(); void setFilterMarketplaceActiveFolders(); @@ -206,6 +226,12 @@ public: ESearchType getSearchType() { return mSearchType; } void setFilterCreator(EFilterCreatorType type); + void toggleSearchVisibilityLinks(); + void toggleSearchVisibilityTrash(); + void toggleSearchVisibilityLibrary(); + void setSearchVisibilityTypes(U32 types); + void setSearchVisibilityTypes(const Params& params); + void setFilterSubString(const std::string& string); const std::string& getFilterSubString(BOOL trim = FALSE) const; const std::string& getFilterSubStringOrig() const { return mFilterSubStringOrig; } @@ -245,11 +271,12 @@ public: // +-------------------------------------------------------------------+ // + Presentation // +-------------------------------------------------------------------+ - void setShowFolderState( EFolderShow state); - EFolderShow getShowFolderState() const; + void setShowFolderState( EFolderShow state); + EFolderShow getShowFolderState() const; EFilterCreatorType getFilterCreatorType() const; void setEmptyLookupMessage(const std::string& message); + void setDefaultEmptyLookupMessage(const std::string& message); std::string getEmptyLookupMessage() const; // +-------------------------------------------------------------------+ @@ -302,6 +329,7 @@ private: bool checkAgainstPermissions(const LLInventoryItem* item) const; bool checkAgainstFilterLinks(const class LLFolderViewModelItemInventory* listener) const; bool checkAgainstCreator(const class LLFolderViewModelItemInventory* listener) const; + bool checkAgainstSearchVisibility(const class LLFolderViewModelItemInventory* listener) const; bool checkAgainstClipboard(const LLUUID& object_id) const; FilterOps mFilterOps; @@ -325,8 +353,12 @@ private: std::string mFilterText; std::string mEmptyLookupMessage; + std::string mDefaultEmptyLookupMessage; ESearchType mSearchType; + + std::vector<std::string> mFilterTokens; + std::string mExactToken; }; #endif diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 030c967019..f2e06d19f3 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -78,6 +78,7 @@ #include "lltooldraganddrop.h" #include "lltrans.h" #include "lluictrlfactory.h" +#include "llviewermenu.h" #include "llviewermessage.h" #include "llviewerfoldertype.h" #include "llviewerobjectlist.h" @@ -655,6 +656,50 @@ BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id) return TRUE; } +bool get_is_item_editable(const LLUUID& inv_item_id) +{ + if (const LLInventoryItem* inv_item = gInventory.getLinkedItem(inv_item_id)) + { + switch (inv_item->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + return gAgentWearables.isWearableModifiable(inv_item_id); + case LLAssetType::AT_OBJECT: + return true; + default: + return false;; + } + } + return gAgentAvatarp->getWornAttachment(inv_item_id) != nullptr; +} + +void handle_item_edit(const LLUUID& inv_item_id) +{ + if (get_is_item_editable(inv_item_id)) + { + if (const LLInventoryItem* inv_item = gInventory.getLinkedItem(inv_item_id)) + { + switch (inv_item->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + LLAgentWearables::editWearable(inv_item_id); + break; + case LLAssetType::AT_OBJECT: + handle_attachment_edit(inv_item_id); + break; + default: + break; + } + } + else + { + handle_attachment_edit(inv_item_id); + } + } +} + BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id) { // NOTE: This function doesn't check the folder's children. @@ -729,40 +774,45 @@ void show_item_profile(const LLUUID& item_uuid) void show_item_original(const LLUUID& item_uuid) { - LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory"); - if (!floater_inventory) - { - LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL; - return; - } - - //sidetray inventory panel - LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); - - bool do_reset_inventory_filter = !floater_inventory->isInVisibleChain(); + LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory"); + if (!floater_inventory) + { + LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL; + return; + } + LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); + if (sidepanel_inventory) + { + LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel(); + if (main_inventory) + { + main_inventory->resetFilters(); + } + reset_inventory_filter(); - LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(); - if (!active_panel) - { - //this may happen when there is no floatera and other panel is active in inventory tab + if (!LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>("inventory")->isInVisibleChain()) + { + LLFloaterReg::toggleInstanceOrBringToFront("inventory"); + } - if (sidepanel_inventory) - { - sidepanel_inventory->showInventoryPanel(); - } - } - - active_panel = LLInventoryPanel::getActiveInventoryPanel(); - if (!active_panel) - { - return; - } - active_panel->setSelection(gInventory.getLinkedItemID(item_uuid), TAKE_FOCUS_YES); - - if(do_reset_inventory_filter) - { - reset_inventory_filter(); - } + const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX); + if (gInventory.isObjectDescendentOf(gInventory.getLinkedItemID(item_uuid), inbox_id)) + { + if (sidepanel_inventory->getInboxPanel()) + { + sidepanel_inventory->openInbox(); + sidepanel_inventory->getInboxPanel()->setSelection(gInventory.getLinkedItemID(item_uuid), TAKE_FOCUS_YES); + } + } + else + { + sidepanel_inventory->selectAllItemsPanel(); + if (sidepanel_inventory->getActivePanel()) + { + sidepanel_inventory->getActivePanel()->setSelection(gInventory.getLinkedItemID(item_uuid), TAKE_FOCUS_YES); + } + } + } } @@ -1797,6 +1847,26 @@ bool validate_marketplacelistings(LLInventoryCategory* cat, validation_callback_ return result && !has_bad_items; } +void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id) +{ + LLInventoryItem* inv_item = gInventory.getItem(item_id); + if (inv_item) + { + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(inv_item->getParentUUID(), -1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); + update.push_back(new_folder); + gInventory.accountForUpdate(update); + + LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(inv_item); + new_item->setParent(new_parent_id); + new_item->updateParentOnServer(FALSE); + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + } +} + ///---------------------------------------------------------------------------- /// LLInventoryCollectFunctor implementations ///---------------------------------------------------------------------------- @@ -2395,10 +2465,32 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root if (("task_open" == action || "open" == action) && selected_items.size() > 1) { - multi_previewp = new LLMultiPreview(); - gFloaterView->addChild(multi_previewp); + bool open_multi_preview = true; - LLFloater::setFloaterHost(multi_previewp); + if ("open" == action) + { + for (std::set<LLFolderViewItem*>::iterator set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter) + { + LLFolderViewItem* folder_item = *set_iter; + if (folder_item) + { + LLInvFVBridge* bridge = dynamic_cast<LLInvFVBridge*>(folder_item->getViewModelItem()); + if (!bridge || !bridge->isMultiPreviewAllowed()) + { + open_multi_preview = false; + break; + } + } + } + } + + if (open_multi_preview) + { + multi_previewp = new LLMultiPreview(); + gFloaterView->addChild(multi_previewp); + + LLFloater::setFloaterHost(multi_previewp); + } } else if (("task_properties" == action || "properties" == action) && selected_items.size() > 1) diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index fd106bc2d8..37c3c47336 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -53,6 +53,10 @@ BOOL get_can_item_be_worn(const LLUUID& id); BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id); +// Performs the appropiate edit action (if one exists) for this item +bool get_is_item_editable(const LLUUID& inv_item_id); +void handle_item_edit(const LLUUID& inv_item_id); + BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id); BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id); @@ -88,6 +92,8 @@ 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); +void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id); + /** Miscellaneous global functions ** ** *******************************************************************************/ diff --git a/indra/newview/llinventoryicon.cpp b/indra/newview/llinventoryicon.cpp index ee6e3dd384..81c001b8bd 100644 --- a/indra/newview/llinventoryicon.cpp +++ b/indra/newview/llinventoryicon.cpp @@ -34,6 +34,7 @@ #include "llui.h" #include "lluiimage.h" #include "llwearabletype.h" +#include "llinventorysettings.h" struct IconEntry : public LLDictionaryEntry { @@ -93,6 +94,11 @@ LLIconDictionary::LLIconDictionary() addEntry(LLInventoryType::ICONNAME_LINKFOLDER, new IconEntry("Inv_LinkFolder")); addEntry(LLInventoryType::ICONNAME_MESH, new IconEntry("Inv_Mesh")); + addEntry(LLInventoryType::ICONNAME_SETTINGS_SKY, new IconEntry("Inv_SettingsSky")); + addEntry(LLInventoryType::ICONNAME_SETTINGS_WATER, new IconEntry("Inv_SettingsWater")); + addEntry(LLInventoryType::ICONNAME_SETTINGS_DAY, new IconEntry("Inv_SettingsDay")); + addEntry(LLInventoryType::ICONNAME_SETTINGS, new IconEntry("Inv_Settings")); + addEntry(LLInventoryType::ICONNAME_INVALID, new IconEntry("Inv_Invalid")); addEntry(LLInventoryType::ICONNAME_UNKNOWN, new IconEntry("Inv_Unknown")); @@ -168,6 +174,9 @@ const std::string& LLInventoryIcon::getIconName(LLAssetType::EType asset_type, break; case LLAssetType::AT_MESH: idx = LLInventoryType::ICONNAME_MESH; + case LLAssetType::AT_SETTINGS: + idx = assignSettingsIcon(misc_flag); + break; case LLAssetType::AT_UNKNOWN: idx = LLInventoryType::ICONNAME_UNKNOWN; default: @@ -189,3 +198,9 @@ LLInventoryType::EIconName LLInventoryIcon::assignWearableIcon(U32 misc_flag) const LLWearableType::EType wearable_type = LLWearableType::inventoryFlagsToWearableType(misc_flag); return LLWearableType::getIconName(wearable_type); } + +LLInventoryType::EIconName LLInventoryIcon::assignSettingsIcon(U32 misc_flag) +{ + LLSettingsType::type_e settings_type = LLSettingsType::fromInventoryFlags(misc_flag); + return LLSettingsType::getIconName(settings_type); +} diff --git a/indra/newview/llinventoryicon.h b/indra/newview/llinventoryicon.h index bc09e32087..b8637c4e33 100644 --- a/indra/newview/llinventoryicon.h +++ b/indra/newview/llinventoryicon.h @@ -48,6 +48,7 @@ public: 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 c49d61df31..28db6a5808 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -56,6 +56,7 @@ #include "llcallbacklist.h" #include "llvoavatarself.h" #include "llgesturemgr.h" +#include "llsdserialize.h" #include "llsdutil.h" #include "bufferarray.h" #include "bufferstream.h" @@ -76,8 +77,8 @@ BOOL LLInventoryModel::sFirstTimeInViewer2 = TRUE; ///---------------------------------------------------------------------------- //BOOL decompress_file(const char* src_filename, const char* dst_filename); -static const char PRODUCTION_CACHE_FORMAT_STRING[] = "%s.inv"; -static const char GRID_CACHE_FORMAT_STRING[] = "%s.%s.inv"; +static const char PRODUCTION_CACHE_FORMAT_STRING[] = "%s.inv.llsd"; +static const char GRID_CACHE_FORMAT_STRING[] = "%s.%s.inv.llsd"; static const char * const LOG_INV("Inventory"); struct InventoryIDPtrLess @@ -678,17 +679,59 @@ void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inv LLUUID categoryId = result["folder_id"].asUUID(); - // Add the category to the internal representation - LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(categoryId, - result["parent_id"].asUUID(), (LLFolderType::EType)result["type"].asInteger(), - result["name"].asString(), gAgent.getID()); + LLViewerInventoryCategory* folderp = gInventory.getCategory(categoryId); + if (!folderp) + { + // Add the category to the internal representation + LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(categoryId, + result["parent_id"].asUUID(), (LLFolderType::EType)result["type"].asInteger(), + result["name"].asString(), gAgent.getID()); - cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1 - cat->setDescendentCount(0); - LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1); - - accountForUpdate(update); - updateCategory(cat); + LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1); + accountForUpdate(update); + + cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1 + cat->setDescendentCount(0); + updateCategory(cat); + } + else + { + // bulk processing was faster than coroutine (coro request->processBulkUpdateInventory->coro response) + // category already exists, but needs an update + if (folderp->getVersion() != LLViewerInventoryCategory::VERSION_INITIAL + || folderp->getDescendentCount() != LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) + { + LL_WARNS() << "Inventory desync on folder creation. Newly created folder already has descendants or got a version.\n" + << "Name: " << folderp->getName() + << " Id: " << folderp->getUUID() + << " Version: " << folderp->getVersion() + << " Descendants: " << folderp->getDescendentCount() + << LL_ENDL; + } + // Recreate category with correct values + // Creating it anew just simplifies figuring out needed change-masks + // and making all needed updates, see updateCategory + LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(categoryId, + result["parent_id"].asUUID(), (LLFolderType::EType)result["type"].asInteger(), + result["name"].asString(), gAgent.getID()); + + if (folderp->getParentUUID() != cat->getParentUUID()) + { + LL_WARNS() << "Inventory desync on folder creation. Newly created folder has wrong parent.\n" + << "Name: " << folderp->getName() + << " Id: " << folderp->getUUID() + << " Expected parent: " << cat->getParentUUID() + << " Actual parent: " << folderp->getParentUUID() + << LL_ENDL; + LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1); + accountForUpdate(update); + } + // else: Do not update parent, parent is already aware of the change. See processBulkUpdateInventory + + cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1 + cat->setDescendentCount(0); + updateCategory(cat); + } if (callback) { @@ -888,6 +931,11 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) return mask; } + if (item->getType() == LLAssetType::AT_MESH) + { + return mask; + } + LLPointer<LLViewerInventoryItem> old_item = getItem(item->getUUID()); LLPointer<LLViewerInventoryItem> new_item; if(old_item) @@ -898,16 +946,29 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) LLUUID new_parent_id = item->getParentUUID(); bool update_parent_on_server = false; - if (new_parent_id.isNull()) + if (new_parent_id.isNull() && !LLApp::isExiting()) { - // 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.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; + } + else + { + // Probably not the best way to handle this, we might encounter real case of 'lost&found' at some point + LL_WARNS(LOG_INV) << "Update attempts to reparent item " << item->getUUID() + << " to null folder. Old parent not null. Moving to old parent. Old item name: " << old_item->getName() + << ". New name: " << item->getName() + << "." << LL_ENDL; + new_parent_id = old_parent_id; + update_parent_on_server = true; + } } if(old_parent_id != new_parent_id) @@ -1810,7 +1871,7 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) return; } - if (LLAssetType::lookup(item->getType()) == LLAssetType::badLookup()) + if (LLAssetType::lookup(item->getType()) == LLAssetType::BADLOOKUP) { if (item->getType() >= LLAssetType::AT_COUNT) { @@ -2599,6 +2660,7 @@ void LLInventoryModel::createCommonSystemCategories() gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true); gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD,true); gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS,true); + gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS, true); } struct LLUUIDAndName @@ -2642,29 +2704,37 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, { if(filename.empty()) { - LL_ERRS(LOG_INV) << "Filename is Null!" << LL_ENDL; + LL_ERRS(LOG_INV) << "filename is Null!" << LL_ENDL; return false; } - LL_INFOS(LOG_INV) << "LLInventoryModel::loadFromFile(" << filename << ")" << LL_ENDL; - LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ - if(!file) + LL_INFOS(LOG_INV) << "loading inventory from: (" << filename << ")" << LL_ENDL; + + llifstream file(filename.c_str()); + + if (!file.is_open()) { LL_INFOS(LOG_INV) << "unable to load inventory from: " << filename << LL_ENDL; return false; } - // *NOTE: This buffer size is hard coded into scanf() below. - char buffer[MAX_STRING]; /*Flawfinder: ignore*/ - char keyword[MAX_STRING]; /*Flawfinder: ignore*/ - char value[MAX_STRING]; /*Flawfinder: ignore*/ - is_cache_obsolete = true; // Obsolete until proven current - while(!feof(file) && fgets(buffer, MAX_STRING, file)) + + is_cache_obsolete = true; // Obsolete until proven current + + std::string line; + LLPointer<LLSDParser> parser = new LLSDNotationParser(); + while (std::getline(file, line)) { - sscanf(buffer, " %126s %126s", keyword, value); /* Flawfinder: ignore */ - if(0 == strcmp("inv_cache_version", keyword)) + LLSD s_item; + std::istringstream iss(line); + if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) + { + LL_WARNS(LOG_INV)<< "Parsing inventory cache failed" << LL_ENDL; + break; + } + + if (s_item.has("inv_cache_version")) { - S32 version; - int succ = sscanf(value,"%d",&version); - if ((1 == succ) && (version == sCurrentInvCacheVersion)) + S32 version = s_item["inv_cache_version"].asInteger(); + if (version == sCurrentInvCacheVersion) { // Cache is up to date is_cache_obsolete = false; @@ -2672,43 +2742,33 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, } else { - // Cache is out of date + LL_WARNS(LOG_INV)<< "Inventory cache is out of date" << LL_ENDL; break; } } - else if(0 == strcmp("inv_category", keyword)) + else if (s_item.has("cat_id")) { if (is_cache_obsolete) break; - + LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null); - if(inv_cat->importFileLocal(file)) + if(inv_cat->importLLSD(s_item)) { categories.push_back(inv_cat); } - else - { - 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 - } } - else if(0 == strcmp("inv_item", keyword)) + else if (s_item.has("item_id")) { if (is_cache_obsolete) break; LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem; - if( inv_item->importFileLocal(file) ) + if( inv_item->fromLLSD(s_item) ) { - // *FIX: Need a better solution, this prevents the - // application from freezing, but breaks inventory - // caching. if(inv_item->getUUID().isNull()) { - //delete inv_item; // automatic when inv_cat is reassigned or destroyed LL_WARNS(LOG_INV) << "Ignoring inventory with null item id: " - << inv_item->getName() << LL_ENDL; - + << inv_item->getName() << LL_ENDL; } else { @@ -2721,62 +2781,63 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, items.push_back(inv_item); } } - } - else - { - 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 - { - LL_WARNS(LOG_INV) << "Unknown token in inventory file '" << keyword << "'" - << LL_ENDL; + } } } - fclose(file); - if (is_cache_obsolete) - return false; - return true; + + file.close(); + + return !is_cache_obsolete; } // static bool LLInventoryModel::saveToFile(const std::string& filename, - const cat_array_t& categories, - const item_array_t& items) + const cat_array_t& categories, + const item_array_t& items) { - if(filename.empty()) + if (filename.empty()) { LL_ERRS(LOG_INV) << "Filename is Null!" << LL_ENDL; return false; } - LL_INFOS(LOG_INV) << "LLInventoryModel::saveToFile(" << filename << ")" << LL_ENDL; - LLFILE* file = LLFile::fopen(filename, "wb"); /*Flawfinder: ignore*/ - if(!file) + + LL_INFOS(LOG_INV) << "saving inventory to: (" << filename << ")" << LL_ENDL; + + llofstream fileXML(filename.c_str()); + if (!fileXML.is_open()) { LL_WARNS(LOG_INV) << "unable to save inventory to: " << filename << LL_ENDL; return false; } - fprintf(file, "\tinv_cache_version\t%d\n",sCurrentInvCacheVersion); + LLSD cache_ver; + cache_ver["inv_cache_version"] = sCurrentInvCacheVersion; + + fileXML << LLSDOStreamer<LLSDNotationFormatter>(cache_ver) << std::endl; + S32 count = categories.size(); + S32 cat_count = 0; S32 i; for(i = 0; i < count; ++i) { LLViewerInventoryCategory* cat = categories[i]; if(cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { - cat->exportFileLocal(file); + fileXML << LLSDOStreamer<LLSDNotationFormatter>(cat->exportLLSD()) << std::endl; + cat_count++; } } - count = items.size(); - for(i = 0; i < count; ++i) + S32 it_count = items.size(); + for(i = 0; i < it_count; ++i) { - items[i]->exportFile(file); + fileXML << LLSDOStreamer<LLSDNotationFormatter>(items[i]->asLLSD()) << std::endl; } - fclose(file); + fileXML.close(); + + LL_INFOS(LOG_INV) << "Inventory saved: " << cat_count << " categories, " << it_count << " items." << LL_ENDL; + return true; } diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index d4993a1091..3608f9e23f 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -46,12 +46,19 @@ #include "llnotificationsutil.h" #include "llpreview.h" #include "llsidepanelinventory.h" +#include "llstartup.h" #include "lltrans.h" +#include "llviewerassettype.h" #include "llviewerattachmenu.h" #include "llviewerfoldertype.h" #include "llvoavatarself.h" +class LLInventoryRecentItemsPanel; +class LLAssetFilteredInventoryPanel; + static LLDefaultChildRegistry::Register<LLInventoryPanel> r("inventory_panel"); +static LLDefaultChildRegistry::Register<LLInventoryRecentItemsPanel> t_recent_inventory_panel("recent_inventory_panel"); +static LLDefaultChildRegistry::Register<LLAssetFilteredInventoryPanel> t_asset_filtered_inv_panel("asset_filtered_inv_panel"); const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder"); const std::string LLInventoryPanel::RECENTITEMS_SORT_ORDER = std::string("RecentItemsSortOrder"); @@ -139,15 +146,20 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) : mCompletionObserver(NULL), mScroller(NULL), mSortOrderSetting(p.sort_order_setting), - mInventory(p.inventory), + mInventory(p.inventory), //inventory("", &gInventory) mAcceptsDragAndDrop(p.accepts_drag_and_drop), mAllowMultiSelect(p.allow_multi_select), + mAllowDrag(p.allow_drag), mShowItemLinkOverlays(p.show_item_link_overlays), mShowEmptyMessage(p.show_empty_message), - mViewsInitialized(false), + mSuppressFolderMenu(p.suppress_folder_menu), + mSuppressOpenItemAction(false), + mBuildViewsOnInit(p.preinitialize_views), + mViewsInitialized(VIEWS_UNINITIALIZED), mInvFVBridgeBuilder(NULL), mInventoryViewModel(p.name), - mGroupedItemBridge(new LLFolderViewGroupedItemBridge) + mGroupedItemBridge(new LLFolderViewGroupedItemBridge), + mFocusSelection(false) { mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER; @@ -190,7 +202,9 @@ LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id ) p.grouped_item_model = mGroupedItemBridge; p.use_label_suffix = mParams.use_label_suffix; p.allow_multiselect = mAllowMultiSelect; + p.allow_drag = mAllowDrag; p.show_empty_message = mShowEmptyMessage; + p.suppress_folder_menu = mSuppressFolderMenu; p.show_item_link_overlays = mShowItemLinkOverlays; p.root = NULL; p.allow_drop = mParams.allow_drop_on_root; @@ -269,14 +283,22 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params) mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this)); mInventory->addObserver(mCompletionObserver); - // Build view of inventory if we need default full hierarchy and inventory ready, - // otherwise wait for idle callback. - if (mInventory->isInventoryUsable() && !mViewsInitialized) - { - initializeViews(); - } - - gIdleCallbacks.addFunction(onIdle, (void*)this); + if (mBuildViewsOnInit) + { + // Build view of inventory if we need default full hierarchy and inventory is ready, otherwise do in onIdle. + // Initializing views takes a while so always do it onIdle if viewer already loaded. + if (mInventory->isInventoryUsable() + && mViewsInitialized == VIEWS_UNINITIALIZED + && LLStartUp::getStartupState() <= STATE_WEARABLES_WAIT) + { + initializeViews(); + } + else if (mViewsInitialized != VIEWS_INITIALIZING) + { + mViewsInitialized = VIEWS_INITIALIZING; + gIdleCallbacks.addFunction(onIdle, (void*)this); + } + } if (mSortOrderSetting != INHERIT_SORT_ORDER) { @@ -291,7 +313,6 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params) if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible")) { getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX)); - getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_OUTBOX)); } // hide marketplace listing box, unless we are a marketplace panel if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible") && !mParams.use_marketplace_folders) @@ -323,6 +344,17 @@ LLInventoryPanel::~LLInventoryPanel() clearFolderRoot(); } +/*virtual*/ +void LLInventoryPanel::onVisibilityChange(BOOL new_visibility) +{ + if (new_visibility && mViewsInitialized == VIEWS_UNINITIALIZED) + { + mViewsInitialized = VIEWS_INITIALIZING; + gIdleCallbacks.addFunction(onIdle, (void*)this); + } + LLPanel::onVisibilityChange(new_visibility); +} + void LLInventoryPanel::draw() { // Select the desired item (in case it wasn't loaded when the selection was requested) @@ -377,6 +409,11 @@ void LLInventoryPanel::setFilterWearableTypes(U64 types) getFilter().setFilterWearableTypes(types); } +void LLInventoryPanel::setFilterSettingsTypes(U64 filter) +{ + getFilter().setFilterSettingsTypes(filter); +} + void LLInventoryPanel::setFilterSubString(const std::string& string) { getFilter().setFilterSubString(string); @@ -387,7 +424,6 @@ const std::string LLInventoryPanel::getFilterSubString() return getFilter().getFilterSubString(); } - void LLInventoryPanel::setSortOrder(U32 order) { LLInventorySort sorter(order); @@ -445,195 +481,218 @@ LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState() return getFilter().getShowFolderState(); } -// Called when something changed in the global model (new item, item coming through the wire, rename, move, etc...) (CHUI-849) -static LLTrace::BlockTimerStatHandle FTM_REFRESH("Inventory Refresh"); -void LLInventoryPanel::modelChanged(U32 mask) +void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInventoryObject* model_item) { - LL_RECORD_BLOCK_TIME(FTM_REFRESH); + LLFolderViewItem* view_item = getItemByID(item_id); + LLFolderViewModelItemInventory* viewmodel_item = + static_cast<LLFolderViewModelItemInventory*>(view_item ? view_item->getViewModelItem() : NULL); - if (!mViewsInitialized) return; - - const LLInventoryModel* model = getModel(); - if (!model) return; + // 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 = NULL; - const LLInventoryModel::changed_items_t& changed_items = model->getChangedIDs(); - if (changed_items.empty()) return; + // 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<LLFolderViewFolder*>(view_item); + } - for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin(); - items_iter != changed_items.end(); - ++items_iter) + ////////////////////////////// + // LABEL Operation + // Empty out the display name for relabel. + if (mask & LLInventoryObserver::LABEL) { - const LLUUID& item_id = (*items_iter); - const LLInventoryObject* model_item = model->getObject(item_id); - LLFolderViewItem* view_item = getItemByID(item_id); - LLFolderViewModelItemInventory* viewmodel_item = - static_cast<LLFolderViewModelItemInventory*>(view_item ? view_item->getViewModelItem() : NULL); + if (view_item) + { + // Request refresh on this item (also flags for filtering) + LLInvFVBridge* bridge = (LLInvFVBridge*)view_item->getViewModelItem(); + if(bridge) + { + // Clear the display name first, so it gets properly re-built during refresh() + bridge->clearDisplayName(); - // 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 = NULL; + view_item->refresh(); + } + LLFolderViewFolder* parent = view_item->getParentFolder(); + if(parent) + { + parent->getViewModelItem()->dirtyDescendantsFilter(); + } + } + } - // Check requires as this item might have already been deleted - // as a child of its deleted parent. - if (model_item && view_item) + ////////////////////////////// + // REBUILD Operation + // Destroy and regenerate the UI. + if (mask & LLInventoryObserver::REBUILD) + { + if (model_item && view_item && viewmodel_item) { - view_folder = dynamic_cast<LLFolderViewFolder*>(view_item); + const LLUUID& idp = viewmodel_item->getUUID(); + view_item->destroyView(); + removeItemID(idp); } - ////////////////////////////// - // LABEL Operation - // Empty out the display name for relabel. - if (mask & LLInventoryObserver::LABEL) - { - if (view_item) - { - // Request refresh on this item (also flags for filtering) - LLInvFVBridge* bridge = (LLInvFVBridge*)view_item->getViewModelItem(); - if(bridge) - { // Clear the display name first, so it gets properly re-built during refresh() - bridge->clearDisplayName(); + LLInventoryObject const* objectp = mInventory->getObject(item_id); + if (objectp) + { + // providing NULL directly avoids unnessesary getItemByID calls + view_item = buildNewViews(item_id, objectp, NULL); + } + else + { + view_item = NULL; + } - view_item->refresh(); - } - LLFolderViewFolder* parent = view_item->getParentFolder(); - if(parent) - { - parent->getViewModelItem()->dirtyDescendantsFilter(); - } - } + viewmodel_item = + static_cast<LLFolderViewModelItemInventory*>(view_item ? view_item->getViewModelItem() : NULL); + view_folder = dynamic_cast<LLFolderViewFolder *>(view_item); + } + + ////////////////////////////// + // INTERNAL Operation + // This could be anything. For now, just refresh the item. + if (mask & LLInventoryObserver::INTERNAL) + { + if (view_item) + { + view_item->refresh(); } + } - ////////////////////////////// - // REBUILD Operation - // Destroy and regenerate the UI. - if (mask & LLInventoryObserver::REBUILD) + ////////////////////////////// + // SORT Operation + // Sort the folder. + if (mask & LLInventoryObserver::SORT) + { + if (view_folder) { - if (model_item && view_item && viewmodel_item) - { - const LLUUID& idp = viewmodel_item->getUUID(); - view_item->destroyView(); - removeItemID(idp); - } - view_item = buildNewViews(item_id); - viewmodel_item = - static_cast<LLFolderViewModelItemInventory*>(view_item ? view_item->getViewModelItem() : NULL); - view_folder = dynamic_cast<LLFolderViewFolder *>(view_item); + view_folder->getViewModelItem()->requestSort(); } + } + // We don't typically care which of these masks the item is actually flagged with, since the masks + // may not be accurate (e.g. in the main inventory panel, I move an item from My Inventory into + // Landmarks; this is a STRUCTURE change for that panel but is an ADD change for the Landmarks + // panel). What's relevant is that the item and UI are probably out of sync and thus need to be + // resynchronized. + if (mask & (LLInventoryObserver::STRUCTURE | + LLInventoryObserver::ADD | + LLInventoryObserver::REMOVE)) + { ////////////////////////////// - // INTERNAL Operation - // This could be anything. For now, just refresh the item. - if (mask & LLInventoryObserver::INTERNAL) + // ADD Operation + // Item exists in memory but a UI element hasn't been created for it. + if (model_item && !view_item) { - if (view_item) + // Add the UI element for this item. + LLInventoryObject const* objectp = mInventory->getObject(item_id); + if (objectp) + { + // providing NULL directly avoids unnessesary getItemByID calls + buildNewViews(item_id, objectp, NULL); + } + + // Select any newly created object that has the auto rename at top of folder root set. + if(mFolderRoot.get()->getRoot()->needsAutoRename()) { - view_item->refresh(); + setSelection(item_id, FALSE); } + updateFolderLabel(model_item->getParentUUID()); } ////////////////////////////// - // SORT Operation - // Sort the folder. - if (mask & LLInventoryObserver::SORT) + // STRUCTURE Operation + // This item already exists in both memory and UI. It was probably reparented. + else if (model_item && view_item) { - if (view_folder) + LLFolderViewFolder* old_parent = view_item->getParentFolder(); + // Don't process the item if it is the root + if (old_parent) { - view_folder->getViewModelItem()->requestSort(); - } - } - - // We don't typically care which of these masks the item is actually flagged with, since the masks - // may not be accurate (e.g. in the main inventory panel, I move an item from My Inventory into - // Landmarks; this is a STRUCTURE change for that panel but is an ADD change for the Landmarks - // panel). What's relevant is that the item and UI are probably out of sync and thus need to be - // resynchronized. - if (mask & (LLInventoryObserver::STRUCTURE | - LLInventoryObserver::ADD | - LLInventoryObserver::REMOVE)) - { - ////////////////////////////// - // ADD Operation - // Item exists in memory but a UI element hasn't been created for it. - if (model_item && !view_item) - { - // Add the UI element for this item. - buildNewViews(item_id); - // Select any newly created object that has the auto rename at top of folder root set. - if(mFolderRoot.get()->getRoot()->needsAutoRename()) - { - setSelection(item_id, FALSE); - } - updateFolderLabel(model_item->getParentUUID()); - } - - ////////////////////////////// - // STRUCTURE Operation - // 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 (old_parent) + LLFolderViewModelItemInventory* viewmodel_folder = static_cast<LLFolderViewModelItemInventory*>(old_parent->getViewModelItem()); + LLFolderViewFolder* new_parent = (LLFolderViewFolder*)getItemByID(model_item->getParentUUID()); + // Item has been moved. + if (old_parent != new_parent) { - LLFolderViewModelItemInventory* viewmodel_folder = static_cast<LLFolderViewModelItemInventory*>(old_parent->getViewModelItem()); - LLFolderViewFolder* new_parent = (LLFolderViewFolder*)getItemByID(model_item->getParentUUID()); - // Item has been moved. - if (old_parent != new_parent) + if (new_parent != NULL) { - 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->addToFolder(new_parent); + addItemID(viewmodel_item->getUUID(), view_item); + if (mInventory) { - // Item is to be moved and we found its new parent in the panel's directory, so move the item's UI. - view_item->addToFolder(new_parent); - addItemID(viewmodel_item->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()) { - 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); - } + 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(viewmodel_item->getUUID()); + 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(viewmodel_item->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->getViewModelItem()->dirtyDescendantsFilter(); + // 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(); } - } - } - - ////////////////////////////// - // REMOVE Operation - // This item has been removed from memory, but its associated UI element still exists. - else if (!model_item && view_item && viewmodel_item) - { - // Remove the item's UI. - LLFolderViewFolder* parent = view_item->getParentFolder(); - removeItemID(viewmodel_item->getUUID()); - view_item->destroyView(); - if(parent) - { - parent->getViewModelItem()->dirtyDescendantsFilter(); - LLFolderViewModelItemInventory* viewmodel_folder = static_cast<LLFolderViewModelItemInventory*>(parent->getViewModelItem()); if(viewmodel_folder) { updateFolderLabel(viewmodel_folder->getUUID()); } + old_parent->getViewModelItem()->dirtyDescendantsFilter(); } } } + + ////////////////////////////// + // REMOVE Operation + // This item has been removed from memory, but its associated UI element still exists. + else if (!model_item && view_item && viewmodel_item) + { + // Remove the item's UI. + LLFolderViewFolder* parent = view_item->getParentFolder(); + removeItemID(viewmodel_item->getUUID()); + view_item->destroyView(); + if(parent) + { + parent->getViewModelItem()->dirtyDescendantsFilter(); + LLFolderViewModelItemInventory* viewmodel_folder = static_cast<LLFolderViewModelItemInventory*>(parent->getViewModelItem()); + if(viewmodel_folder) + { + updateFolderLabel(viewmodel_folder->getUUID()); + } + } + } + } +} + +// Called when something changed in the global model (new item, item coming through the wire, rename, move, etc...) (CHUI-849) +static LLTrace::BlockTimerStatHandle FTM_REFRESH("Inventory Refresh"); +void LLInventoryPanel::modelChanged(U32 mask) +{ + LL_RECORD_BLOCK_TIME(FTM_REFRESH); + + if (mViewsInitialized != VIEWS_INITIALIZED) return; + + const LLInventoryModel* model = getModel(); + if (!model) return; + + const LLInventoryModel::changed_items_t& changed_items = model->getChangedIDs(); + if (changed_items.empty()) return; + + for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin(); + items_iter != changed_items.end(); + ++items_iter) + { + const LLUUID& item_id = (*items_iter); + const LLInventoryObject* model_item = model->getObject(item_id); + itemChanged(item_id, mask, model_item); } } @@ -685,11 +744,11 @@ void LLInventoryPanel::onIdle(void *userdata) LLInventoryPanel *self = (LLInventoryPanel*)userdata; // Inventory just initialized, do complete build - if (!self->mViewsInitialized) + if (self->mViewsInitialized != VIEWS_INITIALIZED) { self->initializeViews(); } - if (self->mViewsInitialized) + if (self->mViewsInitialized == VIEWS_INITIALIZED) { gIdleCallbacks.deleteFunction(onIdle, (void*)self); } @@ -772,7 +831,7 @@ void LLInventoryPanel::initializeViews() gIdleCallbacks.addFunction(idle, this); - mViewsInitialized = true; + mViewsInitialized = VIEWS_INITIALIZED; openStartFolderOrMyInventory(); @@ -831,18 +890,53 @@ LLFolderViewItem * LLInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id) { - LLInventoryObject const* objectp = gInventory.getObject(id); - - if (!objectp) + LLInventoryObject const* objectp = mInventory->getObject(id); + return buildNewViews(id, objectp); +} + +LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, LLInventoryObject const* objectp) +{ + if (!objectp) + { + return NULL; + } + if (!typedViewsFilter(id, objectp)) { + // if certain types are not allowed permanently, no reason to create views return NULL; } - LLFolderViewItem* folder_view_item = getItemByID(id); + const LLUUID &parent_id = objectp->getParentUUID(); + LLFolderViewItem* folder_view_item = getItemByID(id); + LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)getItemByID(parent_id); + + return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder); +} + +LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, LLInventoryObject const* objectp, LLFolderViewItem *folder_view_item) +{ + if (!objectp) + { + return NULL; + } + if (!typedViewsFilter(id, objectp)) + { + // if certain types are not allowed permanently, no reason to create views + return NULL; + } const LLUUID &parent_id = objectp->getParentUUID(); - LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)getItemByID(parent_id); - + LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)getItemByID(parent_id); + + return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder); +} + +LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, + const LLUUID& parent_id, + LLInventoryObject const* objectp, + LLFolderViewItem *folder_view_item, + LLFolderViewFolder *parent_folder) +{ // 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; @@ -863,7 +957,7 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id) { if (objectp->getType() <= LLAssetType::AT_NONE) { - LL_WARNS() << "LLInventoryPanel::buildNewViews called with invalid objectp->mType : " + LL_WARNS() << "LLInventoryPanel::buildViewsTree called with invalid objectp->mType : " << ((S32)objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID() << LL_ENDL; return NULL; @@ -872,7 +966,7 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id) if (objectp->getType() >= LLAssetType::AT_COUNT) { // Example: Happens when we add assets of new, not yet supported type to library - LL_DEBUGS() << "LLInventoryPanel::buildNewViews called with unknown objectp->mType : " + LL_DEBUGS() << "LLInventoryPanel::buildViewsTree called with unknown objectp->mType : " << ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID() << LL_ENDL; @@ -949,26 +1043,52 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id) LLViewerInventoryCategory::cat_array_t* categories; LLViewerInventoryItem::item_array_t* items; mInventory->lockDirectDescendentArrays(id, categories, items); - + + LLFolderViewFolder *parentp = dynamic_cast<LLFolderViewFolder*>(folder_view_item); + if(categories) - { + { + bool has_folders = parentp->getFoldersCount() > 0; for (LLViewerInventoryCategory::cat_array_t::const_iterator cat_iter = categories->begin(); cat_iter != categories->end(); ++cat_iter) { const LLViewerInventoryCategory* cat = (*cat_iter); - buildNewViews(cat->getUUID()); + if (typedViewsFilter(cat->getUUID(), cat)) + { + if (has_folders) + { + // This can be optimized: we don't need to call getItemByID() + // each time, especially since content is growing, we can just + // iter over copy of mItemMap in some way + LLFolderViewItem* view_itemp = getItemByID(cat->getUUID()); + buildViewsTree(cat->getUUID(), id, cat, view_itemp, parentp); + } + else + { + buildViewsTree(cat->getUUID(), id, cat, NULL, parentp); + } + } } } if(items) - { + { for (LLViewerInventoryItem::item_array_t::const_iterator item_iter = items->begin(); item_iter != items->end(); ++item_iter) { const LLViewerInventoryItem* item = (*item_iter); - buildNewViews(item->getUUID()); + if (typedViewsFilter(item->getUUID(), item)) + { + + // This can be optimized: we don't need to call getItemByID() + // each time, especially since content is growing, we can just + // iter over copy of mItemMap in some way + LLFolderViewItem* view_itemp = getItemByID(item->getUUID()); + buildViewsTree(item->getUUID(), id, item, view_itemp, parentp); + } + } } mInventory->unlockDirectDescendentArrays(id); @@ -1121,6 +1241,12 @@ void LLInventoryPanel::setSelectCallback(const boost::function<void (const std:: void LLInventoryPanel::clearSelection() { mSelectThisID.setNull(); + mFocusSelection = false; +} + +LLInventoryPanel::selected_items_t LLInventoryPanel::getSelectedItems() const +{ + return mFolderRoot.get()->getSelectionList(); } void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& items, BOOL user_action) @@ -1590,15 +1716,17 @@ LLFolderViewFolder* LLInventoryPanel::getFolderByID(const LLUUID& id) void LLInventoryPanel::setSelectionByID( const LLUUID& obj_id, BOOL take_keyboard_focus ) { LLFolderViewItem* itemp = getItemByID(obj_id); - if(itemp && itemp->getViewModelItem()) + if(itemp && itemp->getViewModelItem() && itemp->passedFilter()) { itemp->arrangeAndSet(TRUE, take_keyboard_focus); mSelectThisID.setNull(); + mFocusSelection = false; return; } else { // save the desired item to be selected later (if/when ready) + mFocusSelection = take_keyboard_focus; mSelectThisID = obj_id; } } @@ -1607,7 +1735,7 @@ void LLInventoryPanel::updateSelection() { if (mSelectThisID.notNull()) { - setSelectionByID(mSelectThisID, false); + setSelectionByID(mSelectThisID, mFocusSelection); } } @@ -1632,21 +1760,18 @@ BOOL LLInventoryPanel::handleKeyHere( KEY key, MASK mask ) // Open selected items if enter key hit on the inventory panel if (mask == MASK_NONE) { - -// @TODO$: Rider: This code is dead with Outbox, however should something similar be -// done for VMM? -// -// //Don't allow attaching or opening items from Merchant Outbox -// LLFolderViewItem* folder_item = mFolderRoot.get()->getCurSelectedItem(); -// if(folder_item) -// { -// LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem(); -// if(bridge && bridge->is() && (bridge->getInventoryType() != LLInventoryType::IT_CATEGORY)) -// { -// return handled; -// } -// } - + if (mSuppressOpenItemAction) + { + LLFolderViewItem* folder_item = mFolderRoot.get()->getCurSelectedItem(); + if(folder_item) + { + LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem(); + if(bridge && (bridge->getInventoryType() != LLInventoryType::IT_CATEGORY)) + { + return handled; + } + } + } LLInventoryAction::doToSelected(mInventory, mFolderRoot.get(), "open"); handled = TRUE; } @@ -1699,9 +1824,6 @@ bool LLInventoryPanel::isSelectionRemovable() /************************************************************************/ /* Recent Inventory Panel related class */ /************************************************************************/ -class LLInventoryRecentItemsPanel; -static LLDefaultChildRegistry::Register<LLInventoryRecentItemsPanel> t_recent_inventory_panel("recent_inventory_panel"); - static const LLRecentInventoryBridgeBuilder RECENT_ITEMS_BUILDER; class LLInventoryRecentItemsPanel : public LLInventoryPanel { @@ -1730,6 +1852,76 @@ LLInventoryRecentItemsPanel::LLInventoryRecentItemsPanel( const Params& params) mInvFVBridgeBuilder = &RECENT_ITEMS_BUILDER; } +/************************************************************************/ +/* Asset Pre-Filtered Inventory Panel related class */ +/************************************************************************/ + +void LLAssetFilteredInventoryPanel::initFromParams(const Params& p) +{ + mAssetType = LLAssetType::lookup(p.filter_asset_type.getValue()); + LLInventoryPanel::initFromParams(p); + U64 filter_cats = getFilter().getFilterCategoryTypes(); + filter_cats &= ~(1ULL << LLFolderType::FT_MARKETPLACE_LISTINGS); + getFilter().setFilterCategoryTypes(filter_cats); + getFilter().setFilterNoMarketplaceFolder(); +} + +BOOL LLAssetFilteredInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + BOOL result = FALSE; + + if (mAcceptsDragAndDrop) + { + EDragAndDropType allow_type = LLViewerAssetType::lookupDragAndDropType(mAssetType); + // Don't allow DAD_CATEGORY here since it can contain other items besides required assets + // We should see everything we drop! + if (allow_type == cargo_type) + { + result = LLInventoryPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } + } + + return result; +} + +/*virtual*/ +bool LLAssetFilteredInventoryPanel::typedViewsFilter(const LLUUID& id, LLInventoryObject const* objectp) +{ + if (!objectp) + { + return false; + } + + if (objectp->getType() != mAssetType && objectp->getType() != LLAssetType::AT_CATEGORY) + { + return false; + } + + return true; +} + +void LLAssetFilteredInventoryPanel::itemChanged(const LLUUID& id, U32 mask, const LLInventoryObject* model_item) +{ + if (!model_item && !getItemByID(id)) + { + // remove operation, but item is not in panel already + return; + } + + if (model_item + && model_item->getType() != mAssetType + && model_item->getType() != LLAssetType::AT_CATEGORY) + { + return; + } + + LLInventoryPanel::itemChanged(id, mask, model_item); +} + namespace LLInitParam { void TypeValues<LLFolderType::EType>::declareValues() @@ -1759,6 +1951,7 @@ namespace LLInitParam declare(LLFolderType::lookup(LLFolderType::FT_INBOX) , LLFolderType::FT_INBOX); declare(LLFolderType::lookup(LLFolderType::FT_OUTBOX) , LLFolderType::FT_OUTBOX); declare(LLFolderType::lookup(LLFolderType::FT_BASIC_ROOT) , LLFolderType::FT_BASIC_ROOT); + declare(LLFolderType::lookup(LLFolderType::FT_SETTINGS) , LLFolderType::FT_SETTINGS); declare(LLFolderType::lookup(LLFolderType::FT_MARKETPLACE_LISTINGS) , LLFolderType::FT_MARKETPLACE_LISTINGS); declare(LLFolderType::lookup(LLFolderType::FT_MARKETPLACE_STOCK), LLFolderType::FT_MARKETPLACE_STOCK); declare(LLFolderType::lookup(LLFolderType::FT_MARKETPLACE_VERSION), LLFolderType::FT_MARKETPLACE_VERSION); diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 12001f5a2b..a019fc2231 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -92,11 +92,13 @@ public: Optional<std::string> sort_order_setting; Optional<LLInventoryModel*> inventory; Optional<bool> allow_multi_select; + Optional<bool> allow_drag; Optional<bool> show_item_link_overlays; Optional<Filter> filter; Optional<StartFolder> start_folder; Optional<bool> use_label_suffix; Optional<bool> show_empty_message; + Optional<bool> suppress_folder_menu; Optional<bool> show_root_folder; Optional<bool> allow_drop_on_root; Optional<bool> use_marketplace_folders; @@ -106,11 +108,17 @@ public: Optional<LLFolderViewFolder::Params> folder; Optional<LLFolderViewItem::Params> item; + // All item and folder views will be initialized on init if true (default) + // Will initialize on visibility change otherwise. + Optional<bool> preinitialize_views; + Params() : sort_order_setting("sort_order_setting"), inventory("", &gInventory), allow_multi_select("allow_multi_select", true), + allow_drag("allow_drag", true), show_item_link_overlays("show_item_link_overlays", false), + suppress_folder_menu("suppress_folder_menu", false), filter("filter"), start_folder("start_folder"), use_label_suffix("use_label_suffix", true), @@ -122,7 +130,8 @@ public: accepts_drag_and_drop("accepts_drag_and_drop"), folder_view("folder_view"), folder("folder"), - item("item") + item("item"), + preinitialize_views("preinitialize_views", true) {} }; @@ -144,14 +153,17 @@ public: virtual ~LLInventoryPanel(); public: + typedef std::set<LLFolderViewItem*> selected_items_t; + LLInventoryModel* getModel() { return mInventory; } LLFolderViewModelInventory& getRootViewModel() { return mInventoryViewModel; } // LLView methods + /*virtual*/ void onVisibilityChange(BOOL new_visibility); 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, + /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, @@ -168,6 +180,8 @@ public: void setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus); void setSelectCallback(const boost::function<void (const std::deque<LLFolderViewItem*>& items, BOOL user_action)>& cb); void clearSelection(); + selected_items_t getSelectedItems() const; + bool isSelectionRemovable(); LLInventoryFilter& getFilter(); const LLInventoryFilter& getFilter() const; @@ -176,8 +190,9 @@ public: U32 getFilterObjectTypes() const; void setFilterPermMask(PermissionMask filter_perm_mask); U32 getFilterPermMask() const; - void setFilterWearableTypes(U64 filter); - void setFilterSubString(const std::string& string); + void setFilterWearableTypes(U64 filter); + void setFilterSettingsTypes(U64 filter); + void setFilterSubString(const std::string& string); const std::string getFilterSubString(); void setSinceLogoff(BOOL sl); void setHoursAgo(U32 hours); @@ -236,6 +251,8 @@ public: void setSelectionByID(const LLUUID& obj_id, BOOL take_keyboard_focus); void updateSelection(); + void setSuppressOpenItemAction(bool supress_open_item) { mSuppressOpenItemAction = supress_open_item; } + LLFolderViewModelInventory* getFolderViewModel() { return &mInventoryViewModel; } const LLFolderViewModelInventory* getFolderViewModel() const { return &mInventoryViewModel; } @@ -252,10 +269,14 @@ protected: LLInventoryModel* mInventory; LLInventoryObserver* mInventoryObserver; LLInvPanelComplObserver* mCompletionObserver; + bool mFocusSelection; bool mAcceptsDragAndDrop; bool mAllowMultiSelect; + bool mAllowDrag; bool mShowItemLinkOverlays; // Shows link graphic over inventory item icons bool mShowEmptyMessage; + bool mSuppressFolderMenu; + bool mSuppressOpenItemAction; LLHandle<LLFolderView> mFolderRoot; LLScrollContainer* mScroller; @@ -299,7 +320,7 @@ public: void addHideFolderType(LLFolderType::EType folder_type); public: - BOOL getIsViewsInitialized() const { return mViewsInitialized; } + bool getViewsInitialized() const { return mViewsInitialized == VIEWS_INITIALIZED; } protected: // Builds the UI. Call this once the inventory is usable. void initializeViews(); @@ -311,15 +332,77 @@ protected: static LLUIColor sLibraryColor; static LLUIColor sLinkColor; - LLFolderViewItem* buildNewViews(const LLUUID& id); + LLFolderViewItem* buildNewViews(const LLUUID& id); + LLFolderViewItem* buildNewViews(const LLUUID& id, + LLInventoryObject const* objectp); + LLFolderViewItem* buildNewViews(const LLUUID& id, + LLInventoryObject const* objectp, + LLFolderViewItem *target_view); + // if certain types are not allowed, no reason to create views + virtual bool typedViewsFilter(const LLUUID& id, LLInventoryObject const* objectp) { return true; } + + virtual void itemChanged(const LLUUID& item_id, U32 mask, const LLInventoryObject* model_item); BOOL getIsHiddenFolderType(LLFolderType::EType folder_type) const; virtual LLFolderView * createFolderRoot(LLUUID root_id ); virtual LLFolderViewFolder* createFolderViewFolder(LLInvFVBridge * bridge, bool allow_drop); virtual LLFolderViewItem* createFolderViewItem(LLInvFVBridge * bridge); private: - bool mBuildDefaultHierarchy; // default inventory hierarchy should be created in postBuild() - bool mViewsInitialized; // Views have been generated + // buildViewsTree does not include some checks and is meant + // for recursive use, use buildNewViews() for first call + LLFolderViewItem* buildViewsTree(const LLUUID& id, + const LLUUID& parent_id, + LLInventoryObject const* objectp, + LLFolderViewItem *target_view, + LLFolderViewFolder *parent_folder_view); + + typedef enum e_views_initialization_state + { + VIEWS_UNINITIALIZED = 0, + VIEWS_INITIALIZING, + VIEWS_INITIALIZED, + } EViewsInitializationState; + + bool mBuildViewsOnInit; + EViewsInitializationState mViewsInitialized; // Whether views have been generated +}; + +/************************************************************************/ +/* Asset Pre-Filtered Inventory Panel related class */ +/* Exchanges filter's flexibility for speed of generation and */ +/* improved performance */ +/************************************************************************/ + +class LLAssetFilteredInventoryPanel : public LLInventoryPanel +{ +public: + struct Params + : public LLInitParam::Block<Params, LLInventoryPanel::Params> + { + Mandatory<std::string> filter_asset_type; + + Params() : filter_asset_type("filter_asset_type") {} + }; + + void initFromParams(const Params& p); +protected: + LLAssetFilteredInventoryPanel(const Params& p) : LLInventoryPanel(p) {} + friend class LLUICtrlFactory; +public: + ~LLAssetFilteredInventoryPanel() {} + + /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) override; + +protected: + /*virtual*/ bool typedViewsFilter(const LLUUID& id, LLInventoryObject const* objectp) override; + /*virtual*/ void itemChanged(const LLUUID& item_id, U32 mask, const LLInventoryObject* model_item) override; + +private: + LLAssetType::EType mAssetType; }; #endif // LL_LLINVENTORYPANEL_H diff --git a/indra/newview/lljoystickbutton.cpp b/indra/newview/lljoystickbutton.cpp index 59e14e6cc0..79fafade2d 100644 --- a/indra/newview/lljoystickbutton.cpp +++ b/indra/newview/lljoystickbutton.cpp @@ -37,6 +37,7 @@ #include "llui.h" #include "llagent.h" #include "llagentcamera.h" +#include "llviewercamera.h" #include "llviewertexture.h" #include "llviewertexturelist.h" #include "llviewerwindow.h" @@ -48,12 +49,14 @@ static LLDefaultChildRegistry::Register<LLJoystickAgentSlide> r1("joystick_slide static LLDefaultChildRegistry::Register<LLJoystickAgentTurn> r2("joystick_turn"); static LLDefaultChildRegistry::Register<LLJoystickCameraRotate> r3("joystick_rotate"); static LLDefaultChildRegistry::Register<LLJoystickCameraTrack> r5("joystick_track"); - +static LLDefaultChildRegistry::Register<LLJoystickQuaternion> r6("joystick_quat"); const F32 NUDGE_TIME = 0.25f; // in seconds const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed +const S32 CENTER_DOT_RADIUS = 7; + // // Public Methods // @@ -138,9 +141,25 @@ bool LLJoystick::pointInCircle(S32 x, S32 y) const //center is x and y coordinates of center of joystick circle, and also its radius int center = this->getLocalRect().getHeight()/2; bool in_circle = (x - center) * (x - center) + (y - center) * (y - center) <= center * center; + return in_circle; } +bool LLJoystick::pointInCenterDot(S32 x, S32 y, S32 radius) const +{ + if (this->getLocalRect().getHeight() != this->getLocalRect().getWidth()) + { + LL_WARNS() << "Joystick shape is not square" << LL_ENDL; + return true; + } + + S32 center = this->getLocalRect().getHeight() / 2; + + bool in_center_circle = (x - center) * (x - center) + (y - center) * (y - center) <= radius * radius; + + return in_center_circle; +} + BOOL LLJoystick::handleMouseDown(S32 x, S32 y, MASK mask) { //LL_INFOS() << "joystick mouse down " << x << ", " << y << LL_ENDL; @@ -403,8 +422,11 @@ LLJoystickCameraRotate::LLJoystickCameraRotate(const LLJoystickCameraRotate::Par mInLeft( FALSE ), mInTop( FALSE ), mInRight( FALSE ), - mInBottom( FALSE ) -{ } + mInBottom( FALSE ), + mInCenter( FALSE ) +{ + mCenterImageName = "Cam_Rotate_Center"; +} void LLJoystickCameraRotate::updateSlop() @@ -434,7 +456,16 @@ BOOL LLJoystickCameraRotate::handleMouseDown(S32 x, S32 y, MASK mask) S32 dx = x - horiz_center; S32 dy = y - vert_center; - if (dy > dx && dy > -dx) + if (pointInCenterDot(x, y, CENTER_DOT_RADIUS)) + { + mInitialOffset.mX = 0; + mInitialOffset.mY = 0; + mInitialQuadrant = JQ_ORIGIN; + mInCenter = TRUE; + + resetJoystickCamera(); + } + else if (dy > dx && dy > -dx) { // top mInitialOffset.mX = 0; @@ -469,9 +500,20 @@ BOOL LLJoystickCameraRotate::handleMouseDown(S32 x, S32 y, MASK mask) BOOL LLJoystickCameraRotate::handleMouseUp(S32 x, S32 y, MASK mask) { gAgent.setMovementLocked(FALSE); + mInCenter = FALSE; return LLJoystick::handleMouseUp(x, y, mask); } +BOOL LLJoystickCameraRotate::handleHover(S32 x, S32 y, MASK mask) +{ + if (!pointInCenterDot(x, y, CENTER_DOT_RADIUS)) + { + mInCenter = FALSE; + } + + return LLJoystick::handleHover(x, y, mask); +} + void LLJoystickCameraRotate::onHeldDown() { updateSlop(); @@ -504,6 +546,11 @@ void LLJoystickCameraRotate::onHeldDown() } } +void LLJoystickCameraRotate::resetJoystickCamera() +{ + gAgentCamera.resetCameraOrbit(); +} + F32 LLJoystickCameraRotate::getOrbitRate() { F32 time = getElapsedHeldDownTime(); @@ -536,24 +583,31 @@ void LLJoystickCameraRotate::draw() getImageUnselected()->draw( 0, 0 ); LLPointer<LLUIImage> image = getImageSelected(); - if( mInTop ) + if (mInCenter) { - drawRotatedImage( getImageSelected(), 0 ); + drawRotatedImage(LLUI::getUIImage(mCenterImageName), 0); } - - if( mInRight ) + else { - drawRotatedImage( getImageSelected(), 1 ); - } + if (mInTop) + { + drawRotatedImage(getImageSelected(), 0); + } - if( mInBottom ) - { - drawRotatedImage( getImageSelected(), 2 ); - } + if (mInRight) + { + drawRotatedImage(getImageSelected(), 1); + } - if( mInLeft ) - { - drawRotatedImage( getImageSelected(), 3 ); + if (mInBottom) + { + drawRotatedImage(getImageSelected(), 2); + } + + if (mInLeft) + { + drawRotatedImage(getImageSelected(), 3); + } } } @@ -613,7 +667,9 @@ LLJoystickCameraTrack::Params::Params() LLJoystickCameraTrack::LLJoystickCameraTrack(const LLJoystickCameraTrack::Params& p) : LLJoystickCameraRotate(p) -{} +{ + mCenterImageName = "Cam_Tracking_Center"; +} void LLJoystickCameraTrack::onHeldDown() @@ -646,3 +702,243 @@ void LLJoystickCameraTrack::onHeldDown() gAgentCamera.setPanDownKey(getOrbitRate()); } } + +void LLJoystickCameraTrack::resetJoystickCamera() +{ + gAgentCamera.resetCameraPan(); +} + +//------------------------------------------------------------------------------- +// LLJoystickQuaternion +//------------------------------------------------------------------------------- + +LLJoystickQuaternion::Params::Params() +{ +} + +LLJoystickQuaternion::LLJoystickQuaternion(const LLJoystickQuaternion::Params &p): + LLJoystick(p), + mInLeft(false), + mInTop(false), + mInRight(false), + mInBottom(false), + mVectorZero(0.0f, 0.0f, 1.0f), + mRotation(), + mUpDnAxis(1.0f, 0.0f, 0.0f), + mLfRtAxis(0.0f, 0.0f, 1.0f), + mXAxisIndex(2), // left & right across the control + mYAxisIndex(0), // up & down across the control + mZAxisIndex(1) // tested for above and below +{ + for (int i = 0; i < 3; ++i) + { + mLfRtAxis.mV[i] = (mXAxisIndex == i) ? 1.0 : 0.0; + mUpDnAxis.mV[i] = (mYAxisIndex == i) ? 1.0 : 0.0; + } +} + +void LLJoystickQuaternion::setToggleState(BOOL left, BOOL top, BOOL right, BOOL bottom) +{ + mInLeft = left; + mInTop = top; + mInRight = right; + mInBottom = bottom; +} + +BOOL LLJoystickQuaternion::handleMouseDown(S32 x, S32 y, MASK mask) +{ + updateSlop(); + + // Set initial offset based on initial click location + S32 horiz_center = getRect().getWidth() / 2; + S32 vert_center = getRect().getHeight() / 2; + + S32 dx = x - horiz_center; + S32 dy = y - vert_center; + + if (dy > dx && dy > -dx) + { + // top + mInitialOffset.mX = 0; + mInitialOffset.mY = (mVertSlopNear + mVertSlopFar) / 2; + mInitialQuadrant = JQ_UP; + } + else if (dy > dx && dy <= -dx) + { + // left + mInitialOffset.mX = -(mHorizSlopNear + mHorizSlopFar) / 2; + mInitialOffset.mY = 0; + mInitialQuadrant = JQ_LEFT; + } + else if (dy <= dx && dy <= -dx) + { + // bottom + mInitialOffset.mX = 0; + mInitialOffset.mY = -(mVertSlopNear + mVertSlopFar) / 2; + mInitialQuadrant = JQ_DOWN; + } + else + { + // right + mInitialOffset.mX = (mHorizSlopNear + mHorizSlopFar) / 2; + mInitialOffset.mY = 0; + mInitialQuadrant = JQ_RIGHT; + } + + return LLJoystick::handleMouseDown(x, y, mask); +} + +BOOL LLJoystickQuaternion::handleMouseUp(S32 x, S32 y, MASK mask) +{ + return LLJoystick::handleMouseUp(x, y, mask); +} + +void LLJoystickQuaternion::onHeldDown() +{ + LLVector3 axis; + updateSlop(); + + S32 dx = mLastMouse.mX - mFirstMouse.mX + mInitialOffset.mX; + S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY; + + // left-right rotation + if (dx > mHorizSlopNear) + { + axis += mUpDnAxis; + } + else if (dx < -mHorizSlopNear) + { + axis -= mUpDnAxis; + } + + // over/under rotation + if (dy > mVertSlopNear) + { + axis += mLfRtAxis; + } + else if (dy < -mVertSlopNear) + { + axis -= mLfRtAxis; + } + + if (axis.isNull()) + return; + + axis.normalize(); + + LLQuaternion delta; + delta.setAngleAxis(0.0523599f, axis); // about 3deg + + mRotation *= delta; + setValue(mRotation.getValue()); + onCommit(); +} + +void LLJoystickQuaternion::draw() +{ + LLGLSUIDefault gls_ui; + + getImageUnselected()->draw(0, 0); + LLPointer<LLUIImage> image = getImageSelected(); + + if (mInTop) + { + drawRotatedImage(getImageSelected(), 0); + } + + if (mInRight) + { + drawRotatedImage(getImageSelected(), 1); + } + + if (mInBottom) + { + drawRotatedImage(getImageSelected(), 2); + } + + if (mInLeft) + { + drawRotatedImage(getImageSelected(), 3); + } + + LLVector3 draw_point = mVectorZero * mRotation; + S32 halfwidth = getRect().getWidth() / 2; + S32 halfheight = getRect().getHeight() / 2; + draw_point.mV[mXAxisIndex] = (draw_point.mV[mXAxisIndex] + 1.0) * halfwidth; + draw_point.mV[mYAxisIndex] = (draw_point.mV[mYAxisIndex] + 1.0) * halfheight; + + gl_circle_2d(draw_point.mV[mXAxisIndex], draw_point.mV[mYAxisIndex], 4, 8, + draw_point.mV[mZAxisIndex] >= 0.f); + +} + +F32 LLJoystickQuaternion::getOrbitRate() +{ + return 1; +} + +void LLJoystickQuaternion::updateSlop() +{ + // small fixed slop region + mVertSlopNear = 16; + mVertSlopFar = 32; + + mHorizSlopNear = 16; + mHorizSlopFar = 32; +} + +void LLJoystickQuaternion::drawRotatedImage(LLPointer<LLUIImage> image, S32 rotations) +{ + S32 width = image->getWidth(); + S32 height = image->getHeight(); + LLTexture* texture = image->getImage(); + + /* + * Scale texture coordinate system + * to handle the different between image size and size of texture. + */ + F32 uv[][2] = + { + { (F32)width / texture->getWidth(), (F32)height / texture->getHeight() }, + { 0.f, (F32)height / texture->getHeight() }, + { 0.f, 0.f }, + { (F32)width / texture->getWidth(), 0.f } + }; + + gGL.getTexUnit(0)->bind(texture); + + gGL.color4fv(UI_VERTEX_COLOR.mV); + + gGL.begin(LLRender::QUADS); + { + gGL.texCoord2fv(uv[(rotations + 0) % 4]); + gGL.vertex2i(width, height); + + 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.end(); +} + +void LLJoystickQuaternion::setRotation(const LLQuaternion &value) +{ + if (value != mRotation) + { + mRotation = value; + mRotation.normalize(); + LLJoystick::setValue(mRotation.getValue()); + } +} + +LLQuaternion LLJoystickQuaternion::getRotation() const +{ + return mRotation; +} + + diff --git a/indra/newview/lljoystickbutton.h b/indra/newview/lljoystickbutton.h index 4e6c774cad..b7fdf63e58 100644 --- a/indra/newview/lljoystickbutton.h +++ b/indra/newview/lljoystickbutton.h @@ -30,6 +30,7 @@ #include "llbutton.h" #include "llcoord.h" #include "llviewertexture.h" +#include "llquaternion.h" typedef enum e_joystick_quadrant { @@ -79,7 +80,8 @@ public: * Image containing circle is square and this square has adherent points with joystick * circle. Make sure to change method according to shape other than square. */ - bool pointInCircle(S32 x, S32 y) const; + bool pointInCircle(S32 x, S32 y) const; + bool pointInCenterDot(S32 x, S32 y, S32 radius) const; static std::string nameFromQuadrant(const EJoystickQuadrant quadrant); static EJoystickQuadrant quadrantFromName(const std::string& name); @@ -147,7 +149,9 @@ public: 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 onHeldDown(); + virtual void resetJoystickCamera(); virtual void draw(); protected: @@ -160,6 +164,9 @@ protected: BOOL mInTop; BOOL mInRight; BOOL mInBottom; + BOOL mInCenter; + + std::string mCenterImageName; }; @@ -176,6 +183,50 @@ public: LLJoystickCameraTrack(const LLJoystickCameraTrack::Params&); virtual void onHeldDown(); + virtual void resetJoystickCamera(); +}; + +// +class LLJoystickQuaternion : + public LLJoystick +{ +public: + struct Params : + public LLInitParam::Block<Params, LLJoystick::Params> + { + Params(); + }; + + LLJoystickQuaternion(const LLJoystickQuaternion::Params &); + + virtual void setToggleState(BOOL left, BOOL top, BOOL right, BOOL bottom); + + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual void onHeldDown(); + virtual void draw(); + + void setRotation(const LLQuaternion &value); + LLQuaternion getRotation() const; + +protected: + F32 getOrbitRate(); + virtual void updateSlop(); + void drawRotatedImage(LLPointer<LLUIImage> image, S32 rotations); + + BOOL mInLeft; + BOOL mInTop; + BOOL mInRight; + BOOL mInBottom; + + S32 mXAxisIndex; + S32 mYAxisIndex; + S32 mZAxisIndex; + + LLVector3 mVectorZero; + LLQuaternion mRotation; + LLVector3 mUpDnAxis; + LLVector3 mLfRtAxis; }; #endif // LL_LLJOYSTICKBUTTON_H diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp new file mode 100644 index 0000000000..b6107eeedf --- /dev/null +++ b/indra/newview/llkeyconflict.cpp @@ -0,0 +1,1015 @@ +/** + * @file llkeyconflict.cpp + * @brief + * + * $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$ + */ + +/* + * App-wide preferences. Note that these are not per-user, + * because we need to load many preferences before we have + * a login name. + */ + +#include "llviewerprecompiledheaders.h" + +#include "llkeyconflict.h" + +#include "llinitparam.h" +#include "llkeyboard.h" +#include "lltrans.h" +#include "llviewercontrol.h" +#include "llviewerinput.h" +#include "llviewermenu.h" +#include "llxuiparser.h" + +static const std::string saved_settings_key_controls[] = { "placeholder" }; // add settings from gSavedSettings here + +static const std::string filename_default = "key_bindings.xml"; +static const std::string filename_temporary = "key_bindings_tmp.xml"; // used to apply uncommited changes on the go. + +// LLKeyboard::stringFromMask is meant for UI and is OS dependent, +// so this class uses it's own version +std::string string_from_mask(MASK mask) +{ + std::string res; + if ((mask & MASK_CONTROL) != 0) + { + res = "CTL"; + } + if ((mask & MASK_ALT) != 0) + { + if (!res.empty()) res += "_"; + res += "ALT"; + } + if ((mask & MASK_SHIFT) != 0) + { + if (!res.empty()) res += "_"; + res += "SHIFT"; + } + + if (mask == MASK_NONE) + { + res = "NONE"; + } + return res; +} + +std::string string_from_mouse(EMouseClickType click, bool translate) +{ + std::string res; + switch (click) + { + case CLICK_LEFT: + res = "LMB"; + break; + case CLICK_MIDDLE: + res = "MMB"; + break; + case CLICK_RIGHT: + res = "RMB"; + break; + case CLICK_BUTTON4: + res = "MB4"; + break; + case CLICK_BUTTON5: + res = "MB5"; + break; + case CLICK_DOUBLELEFT: + res = "Double LMB"; + break; + default: + break; + } + + if (translate && !res.empty()) + { + res = LLTrans::getString(res); + } + return res; +} + +// LLKeyConflictHandler + +S32 LLKeyConflictHandler::sTemporaryFileUseCount = 0; + +LLKeyConflictHandler::LLKeyConflictHandler() +: mHasUnsavedChanges(false), + mUsesTemporaryFile(false), + mLoadMode(MODE_COUNT) +{ +} + +LLKeyConflictHandler::LLKeyConflictHandler(ESourceMode mode) +: mHasUnsavedChanges(false), + mUsesTemporaryFile(false), + mLoadMode(mode) +{ + loadFromSettings(mode); +} + +LLKeyConflictHandler::~LLKeyConflictHandler() +{ + clearUnsavedChanges(); + // Note: does not reset bindings if temporary file was used +} + +bool LLKeyConflictHandler::canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask) +{ + return mControlsMap[control_name].canHandle(mouse_ind, key, mask); +} + +bool LLKeyConflictHandler::canHandleKey(const std::string &control_name, KEY key, MASK mask) +{ + return canHandleControl(control_name, CLICK_NONE, key, mask); +} + +bool LLKeyConflictHandler::canHandleMouse(const std::string &control_name, EMouseClickType mouse_ind, MASK mask) +{ + return canHandleControl(control_name, mouse_ind, KEY_NONE, mask); +} + +bool LLKeyConflictHandler::canHandleMouse(const std::string &control_name, S32 mouse_ind, MASK mask) +{ + return canHandleControl(control_name, (EMouseClickType)mouse_ind, KEY_NONE, mask); +} + +bool LLKeyConflictHandler::canAssignControl(const std::string &control_name) +{ + control_map_t::iterator iter = mControlsMap.find(control_name); + if (iter != mControlsMap.end()) + { + return iter->second.mAssignable; + } + // If we don't know this control, means it wasn't assigned by user yet and thus is editable + return true; +} + +// static +bool LLKeyConflictHandler::isReservedByMenu(const KEY &key, const MASK &mask) +{ + if (key == KEY_NONE) + { + return false; + } + return (gMenuBarView && gMenuBarView->hasAccelerator(key, mask)) + || (gLoginMenuBarView && gLoginMenuBarView->hasAccelerator(key, mask)); +} + +// static +bool LLKeyConflictHandler::isReservedByMenu(const LLKeyData &data) +{ + if (data.mMouse != CLICK_NONE || data.mKey == KEY_NONE) + { + return false; + } + return (gMenuBarView && gMenuBarView->hasAccelerator(data.mKey, data.mMask)) + || (gLoginMenuBarView && gLoginMenuBarView->hasAccelerator(data.mKey, data.mMask)); +} + +bool LLKeyConflictHandler::registerControl(const std::string &control_name, U32 index, EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask) +{ + if (control_name.empty()) + { + return false; + } + LLKeyConflict &type_data = mControlsMap[control_name]; + if (!type_data.mAssignable) + { + // Example: user tried to assign camera spin to all modes, but first person mode doesn't support it + return false; + } + LLKeyData data(mouse, key, mask, ignore_mask); + if (type_data.mKeyBind.getKeyData(index) == data) + { + return true; + } + if (isReservedByMenu(data)) + { + return false; + } + if (removeConflicts(data, type_data.mConflictMask)) + { + type_data.mKeyBind.replaceKeyData(data, index); + mHasUnsavedChanges = true; + return true; + } + // control already in use/blocked + return false; +} + +bool LLKeyConflictHandler::clearControl(const std::string &control_name, U32 data_index) +{ + if (control_name.empty()) + { + return false; + } + LLKeyConflict &type_data = mControlsMap[control_name]; + if (!type_data.mAssignable) + { + // Example: user tried to assign camera spin to all modes, but first person mode doesn't support it + return false; + } + type_data.mKeyBind.resetKeyData(data_index); + mHasUnsavedChanges = true; + return true; +} + +LLKeyData LLKeyConflictHandler::getControl(const std::string &control_name, U32 index) +{ + if (control_name.empty()) + { + return LLKeyData(); + } + return mControlsMap[control_name].getKeyData(index); +} + +bool LLKeyConflictHandler::isControlEmpty(const std::string &control_name) +{ + if (control_name.empty()) + { + return true; + } + return mControlsMap[control_name].mKeyBind.isEmpty(); +} + +// static +std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata) +{ + std::string result; + + if (keydata.mMask != MASK_NONE && keydata.mKey != KEY_NONE) + { + result = LLKeyboard::stringFromAccelerator(keydata.mMask, keydata.mKey); + } + else if (keydata.mKey != KEY_NONE) + { + result = LLKeyboard::stringFromKey(keydata.mKey); + } + else if (keydata.mMask != MASK_NONE) + { + result = LLKeyboard::stringFromAccelerator(keydata.mMask); + } + + result += string_from_mouse(keydata.mMouse, true); + + return result; +} + +std::string LLKeyConflictHandler::getControlString(const std::string &control_name, U32 index) +{ + if (control_name.empty()) + { + return ""; + } + return getStringFromKeyData(mControlsMap[control_name].getKeyData(index)); +} + +void LLKeyConflictHandler::loadFromControlSettings(const std::string &name) +{ + LLControlVariablePtr var = gSavedSettings.getControl(name); + if (var) + { + LLKeyBind bind(var->getValue()); + LLKeyConflict key(bind, true, 0); + mControlsMap[name] = key; + } +} + +void LLKeyConflictHandler::loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination) +{ + for (LLInitParam::ParamIterator<LLViewerInput::KeyBinding>::const_iterator it = keymode.bindings.begin(), + end_it = keymode.bindings.end(); + it != end_it; + ++it) + { + KEY key; + MASK mask; + EMouseClickType mouse = CLICK_NONE; + if (it->mouse.isProvided()) + { + LLViewerInput::mouseFromString(it->mouse.getValue(), &mouse); + } + if (it->key.getValue().empty()) + { + key = KEY_NONE; + } + else + { + LLKeyboard::keyFromString(it->key, &key); + } + LLKeyboard::maskFromString(it->mask, &mask); + // Note: it->command is also the name of UI element, howhever xml we are loading from + // might not know all the commands, so UI will have to know what to fill by its own + // Assumes U32_MAX conflict mask, and is assignable by default, + // but assignability might have been overriden by generatePlaceholders. + LLKeyConflict &type_data = (*destination)[it->command]; + type_data.mKeyBind.addKeyData(mouse, key, mask, true); + } +} + +bool LLKeyConflictHandler::loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination) +{ + if (filename.empty()) + { + return false; + } + + bool res = false; + + LLViewerInput::Keys keys; + LLSimpleXUIParser parser; + + if (parser.readXUI(filename, keys) + && keys.validateBlock()) + { + switch (load_mode) + { + case MODE_FIRST_PERSON: + if (keys.first_person.isProvided()) + { + loadFromSettings(keys.first_person, destination); + res = true; + } + break; + case MODE_THIRD_PERSON: + if (keys.third_person.isProvided()) + { + loadFromSettings(keys.third_person, destination); + res = true; + } + break; + case MODE_EDIT_AVATAR: + if (keys.edit_avatar.isProvided()) + { + loadFromSettings(keys.edit_avatar, destination); + res = true; + } + break; + case MODE_SITTING: + if (keys.sitting.isProvided()) + { + loadFromSettings(keys.sitting, destination); + res = true; + } + break; + default: + LL_ERRS() << "Not implememted mode " << load_mode << LL_ENDL; + break; + } + } + return res; +} + +void LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode) +{ + mControlsMap.clear(); + mDefaultsMap.clear(); + + // E.X. In case we need placeholder keys for conflict resolution. + generatePlaceholders(load_mode); + + if (load_mode == MODE_SAVED_SETTINGS) + { + // load settings clss knows about, but it also possible to load settings by name separately + const S32 size = std::extent<decltype(saved_settings_key_controls)>::value; + for (U32 i = 0; i < size; i++) + { + loadFromControlSettings(saved_settings_key_controls[i]); + } + } + else + { + // load defaults + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, filename_default); + if (!loadFromSettings(load_mode, filename, &mDefaultsMap)) + { + LL_WARNS() << "Failed to load default settings, aborting" << LL_ENDL; + return; + } + + // load user's + filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default); + if (!gDirUtilp->fileExists(filename) || !loadFromSettings(load_mode, filename, &mControlsMap)) + { + // mind placeholders + mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end()); + } + } + mLoadMode = load_mode; +} + +void LLKeyConflictHandler::saveToSettings(bool temporary) +{ + if (mControlsMap.empty()) + { + return; + } + + if (mLoadMode == MODE_SAVED_SETTINGS) + { + // Does not support 'temporary', preferences handle that themself + // so in case of saved settings we just do not clear mHasUnsavedChanges + control_map_t::iterator iter = mControlsMap.begin(); + control_map_t::iterator end = mControlsMap.end(); + + for (; iter != end; ++iter) + { + if (iter->first.empty()) + { + continue; + } + + LLKeyConflict &key = iter->second; + key.mKeyBind.trimEmpty(); + if (!key.mAssignable) + { + continue; + } + + if (gSavedSettings.controlExists(iter->first)) + { + gSavedSettings.setLLSD(iter->first, key.mKeyBind.asLLSD()); + } + else if (!key.mKeyBind.empty()) + { + // Note: this is currently not in use, might be better for load mechanics to ask for and retain control group + // otherwise settings loaded from other control groups will end in gSavedSettings + LL_INFOS() << "Creating new keybinding " << iter->first << LL_ENDL; + gSavedSettings.declareLLSD(iter->first, key.mKeyBind.asLLSD(), "comment", LLControlVariable::PERSIST_ALWAYS); + } + } + } + else + { + // Determine what file to load and load full copy of that file + std::string filename; + + if (temporary) + { + filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_temporary); + if (!gDirUtilp->fileExists(filename)) + { + filename.clear(); + } + } + + if (filename.empty()) + { + filename = gDirUtilp->findFile(filename_default, + gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""), + gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + } + + LLViewerInput::Keys keys; + LLSimpleXUIParser parser; + + if (parser.readXUI(filename, keys) + && keys.validateBlock()) + { + // replace category we edited + + // mode is a HACK to correctly reset bindings without reparsing whole file and avoid doing + // own param container (which will face issues with inasseesible members of LLInitParam) + LLViewerInput::KeyMode mode; + LLViewerInput::KeyBinding binding; + + control_map_t::iterator iter = mControlsMap.begin(); + control_map_t::iterator end = mControlsMap.end(); + for (; iter != end; ++iter) + { + // By default xml have (had) up to 6 elements per function + // eventually it will be cleaned up and UI will only shows 3 per function, + // so make sure to cleanup. + // Also this helps in keeping file small. + iter->second.mKeyBind.trimEmpty(); + U32 size = iter->second.mKeyBind.getDataCount(); + for (U32 i = 0; i < size; ++i) + { + if (iter->first.empty()) + { + continue; + } + + LLKeyConflict &key = iter->second; + key.mKeyBind.trimEmpty(); + if (key.mKeyBind.empty() || !key.mAssignable) + { + continue; + } + + LLKeyData data = key.mKeyBind.getKeyData(i); + // Still write empty LLKeyData to make sure we will maintain UI position + if (data.mKey == KEY_NONE) + { + // Might be better idea to be consistent and use NONE. LLViewerInput can work with both cases + binding.key = ""; + } + else + { + binding.key = LLKeyboard::stringFromKey(data.mKey, false /*Do not localize*/); + } + binding.mask = string_from_mask(data.mMask); + if (data.mMouse == CLICK_NONE) + { + binding.mouse.setProvided(false); + } + else + { + // set() because 'optional', for compatibility purposes + // just copy old keys.xml and rename to key_bindings.xml, it should work + binding.mouse.set(string_from_mouse(data.mMouse, false), true); + } + binding.command = iter->first; + mode.bindings.add(binding); + } + } + + switch (mLoadMode) + { + case MODE_FIRST_PERSON: + if (keys.first_person.isProvided()) + { + keys.first_person.bindings.set(mode.bindings, true); + } + break; + case MODE_THIRD_PERSON: + if (keys.third_person.isProvided()) + { + keys.third_person.bindings.set(mode.bindings, true); + } + break; + case MODE_EDIT_AVATAR: + if (keys.edit_avatar.isProvided()) + { + keys.edit_avatar.bindings.set(mode.bindings, true); + } + break; + case MODE_SITTING: + if (keys.sitting.isProvided()) + { + keys.sitting.bindings.set(mode.bindings, true); + } + break; + default: + LL_ERRS() << "Not implememted mode " << mLoadMode << LL_ENDL; + break; + } + + if (temporary) + { + // write to temporary xml and use it for gViewerInput + filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_temporary); + if (!mUsesTemporaryFile) + { + mUsesTemporaryFile = true; + sTemporaryFileUseCount++; + } + } + else + { + // write back to user's xml and use it for gViewerInput + filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default); + // Don't reset mUsesTemporaryFile, it will be reset at cleanup stage + } + + LLXMLNodePtr output_node = new LLXMLNode("keys", false); + LLXUIParser parser; + parser.writeXUI(output_node, keys); + + // Write the resulting XML to file + if (!output_node->isNull()) + { + LLFILE *fp = LLFile::fopen(filename, "w"); + if (fp != NULL) + { + LLXMLNode::writeHeaderToFile(fp); + output_node->writeToFile(fp); + fclose(fp); + } + } + // Now force a rebind for keyboard + if (gDirUtilp->fileExists(filename)) + { + // Ideally instead of rebinding immediately we should shedule + // the rebind since single file can have multiple handlers, + // one per mode, saving simultaneously. + // Or whatever uses LLKeyConflictHandler should control the process. + gViewerInput.loadBindingsXML(filename); + } + } + } + +#if 1 + // Legacy support + // Remove #if-#endif section half a year after DRTVWR-501 releases. + // Update legacy settings in settings.xml + // We only care for third person view since legacy settings can't store + // more than one mode. + // We are saving this even if we are in temporary mode - preferences + // will restore values on cancel + if (mLoadMode == MODE_THIRD_PERSON && mHasUnsavedChanges) + { + bool value = canHandleMouse("walk_to", CLICK_DOUBLELEFT, MASK_NONE); + gSavedSettings.setBOOL("DoubleClickAutoPilot", value); + + value = canHandleMouse("walk_to", CLICK_LEFT, MASK_NONE); + gSavedSettings.setBOOL("ClickToWalk", value); + + // new method can save both toggle and push-to-talk values simultaneously, + // but legacy one can save only one. It also doesn't support mask. + LLKeyData data = getControl("toggle_voice", 0); + bool can_toggle = !data.isEmpty(); + if (!can_toggle) + { + data = getControl("voice_follow_key", 0); + } + + gSavedSettings.setBOOL("PushToTalkToggle", can_toggle); + if (data.isEmpty()) + { + // legacy viewer has a bug that might crash it if NONE value is assigned. + // just reset to default + gSavedSettings.getControl("PushToTalkButton")->resetToDefault(false); + } + else + { + if (data.mKey != KEY_NONE) + { + gSavedSettings.setString("PushToTalkButton", LLKeyboard::stringFromKey(data.mKey)); + } + else + { + std::string ctrl_value; + switch (data.mMouse) + { + case CLICK_MIDDLE: + ctrl_value = "MiddleMouse"; + break; + case CLICK_BUTTON4: + ctrl_value = "MouseButton4"; + break; + case CLICK_BUTTON5: + ctrl_value = "MouseButton5"; + break; + default: + ctrl_value = "MiddleMouse"; + break; + } + gSavedSettings.setString("PushToTalkButton", ctrl_value); + } + } + } +#endif + + if (mLoadMode == MODE_THIRD_PERSON && mHasUnsavedChanges) + { + // Map floater should react to doubleclick if doubleclick for teleport is set + // Todo: Seems conterintuitive for map floater to share inworld controls + // after these changes release, discuss with UI UX engineer if this should just + // be set to 1 by default (before release this also doubles as legacy support) + bool value = canHandleMouse("teleport_to", CLICK_DOUBLELEFT, MASK_NONE); + gSavedSettings.setBOOL("DoubleClickTeleport", value); + } + + if (!temporary) + { + // will remove any temporary file if there were any + clearUnsavedChanges(); + } +} + +LLKeyData LLKeyConflictHandler::getDefaultControl(const std::string &control_name, U32 index) +{ + if (control_name.empty()) + { + return LLKeyData(); + } + if (mLoadMode == MODE_SAVED_SETTINGS) + { + LLControlVariablePtr var = gSavedSettings.getControl(control_name); + if (var) + { + return LLKeyBind(var->getDefault()).getKeyData(index); + } + return LLKeyData(); + } + else + { + control_map_t::iterator iter = mDefaultsMap.find(control_name); + if (iter != mDefaultsMap.end()) + { + return iter->second.mKeyBind.getKeyData(index); + } + return LLKeyData(); + } +} + +void LLKeyConflictHandler::resetToDefault(const std::string &control_name, U32 index) +{ + if (control_name.empty()) + { + return; + } + LLKeyData data = getDefaultControl(control_name, index); + + if (data != mControlsMap[control_name].getKeyData(index)) + { + // reset controls that might have been switched to our current control + removeConflicts(data, mControlsMap[control_name].mConflictMask); + mControlsMap[control_name].setKeyData(data, index); + } +} + +void LLKeyConflictHandler::resetToDefaultAndResolve(const std::string &control_name, bool ignore_conflicts) +{ + if (control_name.empty()) + { + return; + } + if (mLoadMode == MODE_SAVED_SETTINGS) + { + LLControlVariablePtr var = gSavedSettings.getControl(control_name); + if (var) + { + LLKeyBind bind(var->getDefault()); + if (!ignore_conflicts) + { + for (S32 i = 0; i < bind.getDataCount(); ++i) + { + removeConflicts(bind.getKeyData(i), mControlsMap[control_name].mConflictMask); + } + } + mControlsMap[control_name].mKeyBind = bind; + } + else + { + mControlsMap[control_name].mKeyBind.clear(); + } + } + else + { + control_map_t::iterator iter = mDefaultsMap.find(control_name); + if (iter != mDefaultsMap.end()) + { + if (!ignore_conflicts) + { + for (S32 i = 0; i < iter->second.mKeyBind.getDataCount(); ++i) + { + removeConflicts(iter->second.mKeyBind.getKeyData(i), mControlsMap[control_name].mConflictMask); + } + } + mControlsMap[control_name].mKeyBind = iter->second.mKeyBind; + } + else + { + mControlsMap[control_name].mKeyBind.clear(); + } + } +} + +void LLKeyConflictHandler::resetToDefault(const std::string &control_name) +{ + // reset specific binding without ignoring conflicts + resetToDefaultAndResolve(control_name, false); +} + +void LLKeyConflictHandler::resetToDefaults(ESourceMode mode) +{ + if (mode == MODE_SAVED_SETTINGS) + { + control_map_t::iterator iter = mControlsMap.begin(); + control_map_t::iterator end = mControlsMap.end(); + + for (; iter != end; ++iter) + { + resetToDefaultAndResolve(iter->first, true); + } + } + else + { + mControlsMap.clear(); + generatePlaceholders(mode); + mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end()); + } + + mHasUnsavedChanges = true; +} + +void LLKeyConflictHandler::resetToDefaults() +{ + if (!empty()) + { + resetToDefaults(mLoadMode); + } + else + { + // not optimal since: + // 1. We are not sure that mLoadMode was set + // 2. We are not sure if there are any changes in comparison to default + // 3. We are loading 'current' only to replace it + // but it is reliable and works Todo: consider optimizing. + loadFromSettings(mLoadMode); + resetToDefaults(mLoadMode); + } +} + +void LLKeyConflictHandler::clear() +{ + if (clearUnsavedChanges()) + { + // temporary file was removed, this means we were using it and need to reload keyboard's bindings + resetKeyboardBindings(); + } + mControlsMap.clear(); + mDefaultsMap.clear(); +} + +// static +void LLKeyConflictHandler::resetKeyboardBindings() +{ + // Try to load User's bindings first + std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default); + if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file)) + { + // Failed to load custom bindings, try default ones + key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, filename_default); + if (!gViewerInput.loadBindingsXML(key_bindings_file)) + { + LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL; + } + } +} + +void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode) +{ + // These controls are meant to cause conflicts when user tries to assign same control somewhere else + // also this can be used to pre-record controls that should not conflict or to assign conflict groups/masks + + if (load_mode == MODE_FIRST_PERSON) + { + // First person view doesn't support camera controls + // Note: might be better idea to just load these from control_table_contents_camera.xml + // or to pass from floaterpreferences when it loads said file + registerTemporaryControl("look_up"); + registerTemporaryControl("look_down"); + registerTemporaryControl("move_forward"); + registerTemporaryControl("move_backward"); + registerTemporaryControl("move_forward_fast"); + registerTemporaryControl("move_backward_fast"); + registerTemporaryControl("spin_over"); + registerTemporaryControl("spin_under"); + registerTemporaryControl("pan_up"); + registerTemporaryControl("pan_down"); + registerTemporaryControl("pan_left"); + registerTemporaryControl("pan_right"); + registerTemporaryControl("pan_in"); + registerTemporaryControl("pan_out"); + registerTemporaryControl("spin_around_ccw"); + registerTemporaryControl("spin_around_cw"); + + // control_table_contents_editing.xml + registerTemporaryControl("edit_avatar_spin_ccw"); + registerTemporaryControl("edit_avatar_spin_cw"); + registerTemporaryControl("edit_avatar_spin_over"); + registerTemporaryControl("edit_avatar_spin_under"); + registerTemporaryControl("edit_avatar_move_forward"); + registerTemporaryControl("edit_avatar_move_backward"); + + // no autopilot or teleport + registerTemporaryControl("walk_to"); + registerTemporaryControl("teleport_to"); + } + + if (load_mode == MODE_EDIT_AVATAR) + { + // no autopilot or teleport + registerTemporaryControl("walk_to"); + registerTemporaryControl("teleport_to"); + } + + if (load_mode == MODE_SITTING) + { + // no autopilot + registerTemporaryControl("walk_to"); + } + else + { + // sitting related functions should only be avaliable in sitting mode + registerTemporaryControl("move_forward_sitting"); + registerTemporaryControl("move_backward_sitting"); + registerTemporaryControl("spin_over_sitting"); + registerTemporaryControl("spin_under_sitting"); + registerTemporaryControl("spin_around_ccw_sitting"); + registerTemporaryControl("spin_around_cw_sitting"); + } +} + +bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, const U32 &conlict_mask) +{ + if (conlict_mask == CONFLICT_NOTHING) + { + // Can't conflict + return true; + } + std::map<std::string, S32> conflict_list; + control_map_t::iterator cntrl_iter = mControlsMap.begin(); + control_map_t::iterator cntrl_end = mControlsMap.end(); + for (; cntrl_iter != cntrl_end; ++cntrl_iter) + { + S32 index = cntrl_iter->second.mKeyBind.findKeyData(data); + if (index >= 0 + && cntrl_iter->second.mConflictMask != CONFLICT_NOTHING + && (cntrl_iter->second.mConflictMask & conlict_mask) != 0) + { + if (cntrl_iter->second.mAssignable) + { + // Potentially we can have multiple conflict flags conflicting + // including unassignable keys. + // So record the conflict and find all others before doing any changes. + // Assume that there is only one conflict per bind + conflict_list[cntrl_iter->first] = index; + } + else + { + return false; + } + } + } + + std::map<std::string, S32>::iterator cnflct_iter = conflict_list.begin(); + std::map<std::string, S32>::iterator cnflct_end = conflict_list.end(); + for (; cnflct_iter != cnflct_end; ++cnflct_iter) + { + mControlsMap[cnflct_iter->first].mKeyBind.resetKeyData(cnflct_iter->second); + } + return true; +} + +void LLKeyConflictHandler::registerTemporaryControl(const std::string &control_name, EMouseClickType mouse, KEY key, MASK mask, U32 conflict_mask) +{ + LLKeyConflict *type_data = &mControlsMap[control_name]; + type_data->mAssignable = false; + type_data->mConflictMask = conflict_mask; + type_data->mKeyBind.addKeyData(mouse, key, mask, false); +} + +void LLKeyConflictHandler::registerTemporaryControl(const std::string &control_name, U32 conflict_mask) +{ + LLKeyConflict *type_data = &mControlsMap[control_name]; + type_data->mAssignable = false; + type_data->mConflictMask = conflict_mask; +} + +bool LLKeyConflictHandler::clearUnsavedChanges() +{ + bool result = false; + mHasUnsavedChanges = false; + + if (mUsesTemporaryFile) + { + mUsesTemporaryFile = false; + sTemporaryFileUseCount--; + if (!sTemporaryFileUseCount) + { + result = clearTemporaryFile(); + } + // else: might be usefull to overwrite content of temp file with defaults + // but at the moment there is no such need + } + return result; +} + +//static +bool LLKeyConflictHandler::clearTemporaryFile() +{ + // At the moment single file needs five handlers (one per mode), so doing this + // will remove file for all hadlers + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_temporary); + if (gDirUtilp->fileExists(filename)) + { + LLFile::remove(filename); + return true; + } + return false; +} + diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h new file mode 100644 index 0000000000..2926ca3aeb --- /dev/null +++ b/indra/newview/llkeyconflict.h @@ -0,0 +1,175 @@ +/** + * @file llkeyconflict.h + * @brief + * + * $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_LLKEYCONFLICT_H +#define LL_LLKEYCONFLICT_H + +#include "llkeybind.h" +#include "llviewerinput.h" + + +class LLKeyConflict +{ +public: + LLKeyConflict() : mAssignable(true), mConflictMask(U32_MAX) {} //temporary assignable, don't forget to change once all keys are recorded + LLKeyConflict(bool assignable, U32 conflict_mask) + : mAssignable(assignable), mConflictMask(conflict_mask) {} + LLKeyConflict(const LLKeyBind &bind, bool assignable, U32 conflict_mask) + : mAssignable(assignable), mConflictMask(conflict_mask), mKeyBind(bind) {} + + LLKeyData getPrimaryKeyData() { return mKeyBind.getKeyData(0); } + LLKeyData getKeyData(U32 index) { return mKeyBind.getKeyData(index); } + void setPrimaryKeyData(const LLKeyData& data) { mKeyBind.replaceKeyData(data, 0); } + void setKeyData(const LLKeyData& data, U32 index) { mKeyBind.replaceKeyData(data, index); } + bool canHandle(EMouseClickType mouse, KEY key, MASK mask) { return mKeyBind.canHandle(mouse, key, mask); } + + LLKeyBind mKeyBind; + bool mAssignable; // whether user can change key or key simply acts as placeholder + U32 mConflictMask; +}; + +class LLKeyConflictHandler +{ +public: + + enum ESourceMode // partially repeats e_keyboard_mode + { + MODE_FIRST_PERSON, + MODE_THIRD_PERSON, + MODE_EDIT_AVATAR, + MODE_SITTING, + MODE_SAVED_SETTINGS, // for settings from saved settings + MODE_COUNT + }; + + const U32 CONFLICT_NOTHING = 0; + // at the moment this just means that key will conflict with everything that is identical + const U32 CONFLICT_ANY = U32_MAX; + + // Note: missed selection and edition commands (would be really nice to go through selection via MB4/5 or wheel) + + LLKeyConflictHandler(); + LLKeyConflictHandler(ESourceMode mode); + ~LLKeyConflictHandler(); + + bool canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask); + bool canHandleKey(const std::string &control_name, KEY key, MASK mask); + bool canHandleMouse(const std::string &control_name, EMouseClickType mouse_ind, MASK mask); + bool canHandleMouse(const std::string &control_name, S32 mouse_ind, MASK mask); //Just for convinience + bool canAssignControl(const std::string &control_name); + static bool isReservedByMenu(const KEY &key, const MASK &mask); + static bool isReservedByMenu(const LLKeyData &data); + + // @control_name - see REGISTER_KEYBOARD_ACTION in llviewerinput for avaliable options, + // usually this is just name of the function + // @data_index - single control (function) can have multiple key combinations trigering + // it, this index indicates combination function will change/add; Note that preferences + // floater can only display up to 3 options, but data_index can be bigger than that + // @mouse_ind - mouse action (middle click, MB5 etc) + // @key - keyboard key action + // @mask - shift/ctrl/alt flags + // @ignore_mask - Either to expect exact match (ctrl+K will not trigger if ctrl+shift+K + // is active) or ignore not expected masks as long as expected mask is present + // (ctrl+K will be triggered if ctrl+shift+K is active) + bool registerControl(const std::string &control_name, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask, bool ignore_mask); //todo: return conflicts? + bool clearControl(const std::string &control_name, U32 data_index); + + LLKeyData getControl(const std::string &control_name, U32 data_index); + bool isControlEmpty(const std::string &control_name); + + // localized string + static std::string getStringFromKeyData(const LLKeyData& keydata); + std::string getControlString(const std::string &control_name, U32 data_index); + + // Load single control, overrides existing one if names match + void loadFromControlSettings(const std::string &name); + // Drops any changes loads controls with ones from 'saved settings' or from xml + void loadFromSettings(ESourceMode load_mode); + + // Saves settings to 'saved settings' or to xml + // If 'temporary' is set, function will save settings to temporary + // file and reload input bindings from temporary file. + // 'temporary' does not support gSavedSettings, those are handled + // by preferences, so 'temporary' is such case will simply not + // reset mHasUnsavedChanges + // + // 'temporary' exists to support ability of live-editing settings in + // preferences: temporary for testing changes 'live' without saving them, + // then hitting ok/cancel and save/discard values permanently. + void saveToSettings(bool apply_temporary = false); + + LLKeyData getDefaultControl(const std::string &control_name, U32 data_index); + // Resets keybinding to default variant from 'saved settings' or xml + void resetToDefault(const std::string &control_name, U32 index); + void resetToDefault(const std::string &control_name); + // resets current mode to defaults + void resetToDefaults(); + + bool empty() { return mControlsMap.empty(); } + void clear(); + + // reloads bindings from last valid user's xml or from default xml + // to keyboard's handler + static void resetKeyboardBindings(); + + bool hasUnsavedChanges() { return mHasUnsavedChanges; } + void setLoadMode(ESourceMode mode) { mLoadMode = mode; } + ESourceMode getLoadMode() { return mLoadMode; } + +private: + void resetToDefaultAndResolve(const std::string &control_name, bool ignore_conflicts); + void resetToDefaults(ESourceMode mode); + + // at the moment these kind of control is not savable, but takes part in conflict resolution + void registerTemporaryControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask); + void registerTemporaryControl(const std::string &control_name, U32 conflict_mask = 0); + + typedef std::map<std::string, LLKeyConflict> control_map_t; + void loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination); + bool loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination); + void generatePlaceholders(ESourceMode load_mode); //E.x. non-assignable values + // returns false in case user is trying to reuse control that can't be reassigned + bool removeConflicts(const LLKeyData &data, const U32 &conlict_mask); + + // removes flags and removes temporary file, returns 'true' if file was removed + bool clearUnsavedChanges(); + // return true if there was a file to remove + static bool clearTemporaryFile(); + + control_map_t mControlsMap; + control_map_t mDefaultsMap; + bool mHasUnsavedChanges; + ESourceMode mLoadMode; + + // To implement 'apply immediately'+revert on cancel, class applies changes to temporary file + // but this only works for settings from keybndings files (key_bindings.xml) + // saved setting rely onto external mechanism of preferences floater + bool mUsesTemporaryFile; + static S32 sTemporaryFileUseCount; +}; + + +#endif // LL_LLKEYCONFLICT_H diff --git a/indra/newview/lllandmarkactions.cpp b/indra/newview/lllandmarkactions.cpp index 9c00243f44..a17dc674ac 100644 --- a/indra/newview/lllandmarkactions.cpp +++ b/indra/newview/lllandmarkactions.cpp @@ -228,23 +228,6 @@ 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, @@ -261,18 +244,13 @@ void LLLandmarkActions::createLandmarkHere( 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, + NO_INV_SUBTYPE, PERM_ALL, NULL); } diff --git a/indra/newview/lllandmarkactions.h b/indra/newview/lllandmarkactions.h index 870d92811e..ae7b072fcb 100644 --- a/indra/newview/lllandmarkactions.h +++ b/indra/newview/lllandmarkactions.h @@ -72,12 +72,6 @@ public: */ static LLViewerInventoryItem* findLandmarkForAgentPos(); - - /** - * @brief Checks whether agent has rights to create landmark for current parcel. - */ - static bool canCreateLandmarkHere(); - /** * @brief Creates landmark for current parcel. */ diff --git a/indra/newview/lllandmarklist.cpp b/indra/newview/lllandmarklist.cpp index c58540914e..9106d4e986 100644 --- a/indra/newview/lllandmarklist.cpp +++ b/indra/newview/lllandmarklist.cpp @@ -39,6 +39,11 @@ // Globals LLLandmarkList gLandmarkList; +// number is mostly arbitrary, but it should be below DEFAULT_QUEUE_SIZE pool size, +// which is 4096, to not overfill the pool if user has more than 4K of landmarks +// and it should leave some space for other potential simultaneous asset request +const S32 MAX_SIMULTANEOUS_REQUESTS = 512; + //////////////////////////////////////////////////////////////////////////// // LLLandmarkList @@ -69,6 +74,21 @@ LLLandmark* LLLandmarkList::getAsset(const LLUUID& asset_uuid, loaded_callback_t { return NULL; } + + if (cb) + { + // Multiple different sources can request same landmark, + // mLoadedCallbackMap is a multimap that allows multiple pairs with same key + // Todo: this might need to be improved to not hold identical callbacks multiple times + loaded_callback_map_t::value_type vt(asset_uuid, cb); + mLoadedCallbackMap.insert(vt); + } + + if ( mWaitList.find(asset_uuid) != mWaitList.end() ) + { + // Landmark is sheduled for download, but not requested yet + return NULL; + } landmark_requested_list_t::iterator iter = mRequestedList.find(asset_uuid); if (iter != mRequestedList.end()) @@ -79,18 +99,25 @@ LLLandmark* LLLandmarkList::getAsset(const LLUUID& asset_uuid, loaded_callback_t return NULL; } } - - if (cb) - { - loaded_callback_map_t::value_type vt(asset_uuid, cb); - mLoadedCallbackMap.insert(vt); - } + if (mRequestedList.size() > MAX_SIMULTANEOUS_REQUESTS) + { + // Workarounds for corutines pending list size limit: + // Postpone download till queue is emptier. + // Coroutines have own built in 'pending' list, but unfortunately + // it is too small compared to potential amount of landmarks + // or assets. + mWaitList.insert(asset_uuid); + return NULL; + } + + mRequestedList[asset_uuid] = gFrameTimeSeconds; + + // Note that getAssetData can callback immediately and cleans mRequestedList gAssetStorage->getAssetData(asset_uuid, LLAssetType::AT_LANDMARK, LLLandmarkList::processGetAssetReply, NULL); - mRequestedList[asset_uuid] = gFrameTimeSeconds; } return NULL; } @@ -109,36 +136,49 @@ void LLLandmarkList::processGetAssetReply( LLVFile file(vfs, uuid, type); S32 file_length = file.getSize(); - std::vector<char> buffer(file_length + 1); - file.read( (U8*)&buffer[0], file_length); - buffer[ file_length ] = 0; + if (file_length > 0) + { + std::vector<char> buffer(file_length + 1); + file.read((U8*)&buffer[0], file_length); + buffer[file_length] = 0; - LLLandmark* landmark = LLLandmark::constructFromString(&buffer[0]); - if (landmark) - { - gLandmarkList.mList[ uuid ] = landmark; - gLandmarkList.mRequestedList.erase(uuid); - - LLVector3d pos; - if(!landmark->getGlobalPos(pos)) - { - LLUUID region_id; - if(landmark->getRegionID(region_id)) - { - LLLandmark::requestRegionHandle( - gMessageSystem, - gAgent.getRegionHost(), - region_id, - boost::bind(&LLLandmarkList::onRegionHandle, &gLandmarkList, uuid)); - } - - // the callback will be called when we get the region handle. - } - else - { - gLandmarkList.makeCallbacks(uuid); - } - } + LLLandmark* landmark = LLLandmark::constructFromString(&buffer[0], buffer.size()); + if (landmark) + { + gLandmarkList.mList[uuid] = landmark; + gLandmarkList.mRequestedList.erase(uuid); + + LLVector3d pos; + if (!landmark->getGlobalPos(pos)) + { + LLUUID region_id; + if (landmark->getRegionID(region_id)) + { + LLLandmark::requestRegionHandle( + gMessageSystem, + gAgent.getRegionHost(), + region_id, + boost::bind(&LLLandmarkList::onRegionHandle, &gLandmarkList, uuid)); + } + + // the callback will be called when we get the region handle. + } + else + { + gLandmarkList.makeCallbacks(uuid); + } + } + else + { + // failed to parse, shouldn't happen + gLandmarkList.eraseCallbacks(uuid); + } + } + else + { + // got a good status, but no file, shouldn't happen + gLandmarkList.eraseCallbacks(uuid); + } } else { @@ -155,8 +195,36 @@ void LLLandmarkList::processGetAssetReply( } gLandmarkList.mBadList.insert(uuid); + gLandmarkList.mRequestedList.erase(uuid); //mBadList effectively blocks any load, so no point keeping id in requests + gLandmarkList.eraseCallbacks(uuid); } + // getAssetData can fire callback immediately, causing + // a recursion which is suboptimal for very large wait list. + // 'scheduling' indicates that we are inside request and + // shouldn't be launching more requests. + static bool scheduling = false; + if (!scheduling && !gLandmarkList.mWaitList.empty()) + { + scheduling = true; + while (!gLandmarkList.mWaitList.empty() && gLandmarkList.mRequestedList.size() < MAX_SIMULTANEOUS_REQUESTS) + { + // start new download from wait list + landmark_uuid_list_t::iterator iter = gLandmarkList.mWaitList.begin(); + LLUUID asset_uuid = *iter; + gLandmarkList.mWaitList.erase(iter); + + // add to mRequestedList before calling getAssetData() + gLandmarkList.mRequestedList[asset_uuid] = gFrameTimeSeconds; + + // Note that getAssetData can callback immediately and cleans mRequestedList + gAssetStorage->getAssetData(asset_uuid, + LLAssetType::AT_LANDMARK, + LLLandmarkList::processGetAssetReply, + NULL); + } + scheduling = false; + } } BOOL LLLandmarkList::isAssetInLoadedCallbackMap(const LLUUID& asset_uuid) @@ -172,32 +240,39 @@ BOOL LLLandmarkList::assetExists(const LLUUID& asset_uuid) void LLLandmarkList::onRegionHandle(const LLUUID& landmark_id) { LLLandmark* landmark = getAsset(landmark_id); - - if (!landmark) - { - LL_WARNS() << "Got region handle but the landmark not found." << LL_ENDL; - return; - } + if (!landmark) + { + LL_WARNS() << "Got region handle but the landmark " << landmark_id << " not found." << LL_ENDL; + eraseCallbacks(landmark_id); + return; + } // Calculate landmark global position. // This should succeed since the region handle is available. LLVector3d pos; if (!landmark->getGlobalPos(pos)) { - LL_WARNS() << "Got region handle but the landmark global position is still unknown." << LL_ENDL; - return; + LL_WARNS() << "Got region handle but the landmark " << landmark_id << " global position is still unknown." << LL_ENDL; + eraseCallbacks(landmark_id); + return; } + // Call this even if no landmark exists to clean mLoadedCallbackMap makeCallbacks(landmark_id); } +void LLLandmarkList::eraseCallbacks(const LLUUID& landmark_id) +{ + mLoadedCallbackMap.erase(landmark_id); +} + void LLLandmarkList::makeCallbacks(const LLUUID& landmark_id) { LLLandmark* landmark = getAsset(landmark_id); if (!landmark) { - LL_WARNS() << "Landmark to make callbacks for not found." << LL_ENDL; + LL_WARNS() << "Landmark " << landmark_id << " 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..4f3b11660d 100644 --- a/indra/newview/lllandmarklist.h +++ b/indra/newview/lllandmarklist.h @@ -65,14 +65,16 @@ public: protected: void onRegionHandle(const LLUUID& landmark_id); + void eraseCallbacks(const LLUUID& landmark_id); void makeCallbacks(const LLUUID& landmark_id); typedef std::map<LLUUID, LLLandmark*> landmark_list_t; landmark_list_t mList; - typedef std::set<LLUUID> landmark_bad_list_t; - landmark_bad_list_t mBadList; - + typedef std::set<LLUUID> landmark_uuid_list_t; + landmark_uuid_list_t mBadList; + landmark_uuid_list_t mWaitList; + typedef std::map<LLUUID,F32> landmark_requested_list_t; landmark_requested_list_t mRequestedList; diff --git a/indra/newview/lllegacyatmospherics.cpp b/indra/newview/lllegacyatmospherics.cpp new file mode 100644 index 0000000000..a2acb3efe2 --- /dev/null +++ b/indra/newview/lllegacyatmospherics.cpp @@ -0,0 +1,853 @@ +/** + * @file lllegacyatmospherics.cpp + * @brief LLAtmospherics 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 "lllegacyatmospherics.h" + +#include "llfeaturemanager.h" +#include "llviewercontrol.h" +#include "llframetimer.h" + +#include "llagent.h" +#include "llagentcamera.h" +#include "lldrawable.h" +#include "llface.h" +#include "llglheaders.h" +#include "llsky.h" +#include "llviewercamera.h" +#include "llviewertexturelist.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" +#include "llworld.h" +#include "pipeline.h" +#include "v3colorutil.h" + +#include "llsettingssky.h" +#include "llenvironment.h" +#include "lldrawpoolwater.h" + +class LLFastLn +{ +public: + LLFastLn() + { + mTable[0] = 0; + for( S32 i = 1; i < 257; i++ ) + { + mTable[i] = log((F32)i); + } + } + + F32 ln( F32 x ) + { + const F32 OO_255 = 0.003921568627450980392156862745098f; + const F32 LN_255 = 5.5412635451584261462455391880218f; + + if( x < OO_255 ) + { + return log(x); + } + else + if( x < 1 ) + { + x *= 255.f; + S32 index = llfloor(x); + F32 t = x - index; + F32 low = mTable[index]; + F32 high = mTable[index + 1]; + return low + t * (high - low) - LN_255; + } + else + if( x <= 255 ) + { + S32 index = llfloor(x); + F32 t = x - index; + F32 low = mTable[index]; + F32 high = mTable[index + 1]; + return low + t * (high - low); + } + else + { + return log( x ); + } + } + + F32 pow( F32 x, F32 y ) + { + return (F32)LL_FAST_EXP(y * ln(x)); + } + + +private: + F32 mTable[257]; // index 0 is unused +}; + +static LLFastLn gFastLn; + + +// Functions used a lot. + +inline F32 LLHaze::calcPhase(const F32 cos_theta) const +{ + const F32 g2 = mG * mG; + const F32 den = 1 + g2 - 2 * mG * cos_theta; + return (1 - g2) * gFastLn.pow(den, -1.5); +} + +inline void color_pow(LLColor3 &col, const F32 e) +{ + col.mV[0] = gFastLn.pow(col.mV[0], e); + col.mV[1] = gFastLn.pow(col.mV[1], e); + col.mV[2] = gFastLn.pow(col.mV[2], e); +} + +inline LLColor3 color_norm(const LLColor3 &col) +{ + const F32 m = color_max(col); + if (m > 1.f) + { + return 1.f/m * col; + } + else return col; +} + +inline void color_gamma_correct(LLColor3 &col) +{ + const F32 gamma_inv = 1.f/1.2f; + if (col.mV[0] != 0.f) + { + col.mV[0] = gFastLn.pow(col.mV[0], gamma_inv); + } + if (col.mV[1] != 0.f) + { + col.mV[1] = gFastLn.pow(col.mV[1], gamma_inv); + } + if (col.mV[2] != 0.f) + { + col.mV[2] = gFastLn.pow(col.mV[2], gamma_inv); + } +} + +static LLColor3 calc_air_sca_sea_level() +{ + static LLColor3 WAVE_LEN(675, 520, 445); + static LLColor3 refr_ind = refr_ind_calc(WAVE_LEN); + static LLColor3 n21 = refr_ind * refr_ind - LLColor3(1, 1, 1); + static LLColor3 n4 = n21 * n21; + static LLColor3 wl2 = WAVE_LEN * WAVE_LEN * 1e-6f; + static LLColor3 wl4 = wl2 * wl2; + static LLColor3 mult_const = fsigma * 2.0f/ 3.0f * 1e24f * (F_PI * F_PI) * n4; + static F32 dens_div_N = F32( ATM_SEA_LEVEL_NDENS / Ndens2); + return dens_div_N * mult_const.divide(wl4); +} + +// static constants. +LLColor3 const LLHaze::sAirScaSeaLevel = calc_air_sca_sea_level(); +F32 const LLHaze::sAirScaIntense = color_intens(LLHaze::sAirScaSeaLevel); +F32 const LLHaze::sAirScaAvg = LLHaze::sAirScaIntense / 3.f; + +/*************************************** + Atmospherics +***************************************/ + +LLAtmospherics::LLAtmospherics() +: mCloudDensity(0.2f), + mWind(0.f), + mWorldScale(1.f) +{ + /// WL PARAMS + mInitialized = FALSE; + mAmbientScale = gSavedSettings.getF32("SkyAmbientScale"); + mNightColorShift = gSavedSettings.getColor3("SkyNightColorShift"); + mFogColor.mV[VRED] = mFogColor.mV[VGREEN] = mFogColor.mV[VBLUE] = 0.5f; + mFogColor.mV[VALPHA] = 0.0f; + mFogRatio = 1.2f; + mHazeConcentration = 0.f; + mInterpVal = 0.f; +} + + +LLAtmospherics::~LLAtmospherics() +{ +} + +void LLAtmospherics::init() +{ + const F32 haze_int = color_intens(mHaze.calcSigSca(0)); + mHazeConcentration = haze_int / (color_intens(mHaze.calcAirSca(0)) + haze_int); + mInitialized = true; +} + +LLColor4 LLAtmospherics::calcSkyColorInDir(AtmosphericsVars& vars, const LLVector3 &dir, bool isShiny) +{ + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + return calcSkyColorInDir(psky, vars, dir, isShiny); +} + +// This cubemap is used as "environmentMap" in indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl +LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3 &dir, bool isShiny) +{ + F32 sky_saturation = 0.25f; + F32 land_saturation = 0.1f; + + if (isShiny && dir.mV[VZ] < -0.02f) + { + LLColor4 col; + LLColor3 desat_fog = LLColor3(mFogColor); + F32 brightness = desat_fog.brightness();// NOTE: Linear brightness! + // So that shiny somewhat shows up at night. + if (brightness < 0.15f) + { + brightness = 0.15f; + desat_fog = smear(0.15f); + } + F32 greyscale_sat = brightness * (1.0f - land_saturation); + desat_fog = desat_fog * land_saturation + smear(greyscale_sat); + if (!gPipeline.canUseWindLightShaders()) + { + col = LLColor4(desat_fog, 0.f); + } + else + { + col = LLColor4(desat_fog * 0.5f, 0.f); + } + float x = 1.0f-fabsf(-0.1f-dir.mV[VZ]); + x *= x; + col.mV[0] *= x*x; + col.mV[1] *= powf(x, 2.5f); + col.mV[2] *= x*x*x; + return col; + } + + // undo OGL_TO_CFR_ROTATION and negate vertical direction. + LLVector3 Pn = LLVector3(-dir[1] , -dir[2], -dir[0]); + + //calculates hazeColor + calcSkyColorWLVert(psky, Pn, vars); + + if (isShiny) + { + F32 brightness = vars.hazeColor.brightness(); + F32 greyscale_sat = brightness * (1.0f - sky_saturation); + LLColor3 sky_color = vars.hazeColor * sky_saturation + smear(greyscale_sat); + //sky_color *= (0.5f + 0.5f * brightness); // SL-12574 EEP sky is being attenuated too much + return LLColor4(sky_color, 0.0f); + } + + bool low_end = !gPipeline.canUseWindLightShaders(); + LLColor3 sky_color = low_end ? vars.hazeColor * 2.0f : psky->gammaCorrect(vars.hazeColor * 2.0f); + + return LLColor4(sky_color, 0.0f); +} + +// NOTE: Keep these in sync! +// indra\newview\app_settings\shaders\class1\deferred\skyV.glsl +// indra\newview\app_settings\shaders\class1\deferred\cloudsV.glsl +// indra\newview\lllegacyatmospherics.cpp +void LLAtmospherics::calcSkyColorWLVert(const LLSettingsSky::ptr_t &psky, LLVector3 & Pn, AtmosphericsVars& vars) +{ + LLColor3 blue_density = vars.blue_density; + LLColor3 blue_horizon = vars.blue_horizon; + F32 haze_horizon = vars.haze_horizon; + F32 haze_density = vars.haze_density; + F32 density_multiplier = vars.density_multiplier; + F32 max_y = vars.max_y; + LLVector4 sun_norm = vars.sun_norm; + + // project the direction ray onto the sky dome. + F32 phi = acos(Pn[1]); + F32 sinA = sin(F_PI - phi); + if (fabsf(sinA) < 0.01f) + { //avoid division by zero + sinA = 0.01f; + } + + F32 Plen = vars.dome_radius * sin(F_PI + phi + asin(vars.dome_offset * sinA)) / sinA; + + Pn *= Plen; + + // Set altitude + if (Pn[1] > 0.f) + { + Pn *= (max_y / Pn[1]); + } + else + { + Pn *= (-32000.f / Pn[1]); + } + + Plen = Pn.length(); + Pn /= Plen; + + // Initialize temp variables + LLColor3 sunlight = vars.sunlight; + LLColor3 ambient = vars.ambient; + + LLColor3 glow = vars.glow; + F32 cloud_shadow = vars.cloud_shadow; + + // Sunlight attenuation effect (hue and brightness) due to atmosphere + // this is used later for sunlight modulation at various altitudes + LLColor3 light_atten = vars.light_atten; + LLColor3 light_transmittance = psky->getLightTransmittance(Plen); + (void)light_transmittance; // silence Clang warn-error + + // Calculate relative weights + LLColor3 temp2(0.f, 0.f, 0.f); + LLColor3 temp1 = vars.total_density; + + LLColor3 blue_weight = componentDiv(blue_density, temp1); + LLColor3 blue_factor = blue_horizon * blue_weight; + LLColor3 haze_weight = componentDiv(smear(haze_density), temp1); + LLColor3 haze_factor = haze_horizon * haze_weight; + + + // Compute sunlight from P & lightnorm (for long rays like sky) + temp2.mV[1] = llmax(F_APPROXIMATELY_ZERO, llmax(0.f, Pn[1]) * 1.0f + sun_norm.mV[1] ); + + temp2.mV[1] = 1.f / temp2.mV[1]; + componentMultBy(sunlight, componentExp((light_atten * -1.f) * temp2.mV[1])); + componentMultBy(sunlight, light_transmittance); + + // Distance + temp2.mV[2] = Plen * density_multiplier; + + // Transparency (-> temp1) + temp1 = componentExp((temp1 * -1.f) * temp2.mV[2]); + + // Compute haze glow + temp2.mV[0] = Pn * LLVector3(sun_norm); + + temp2.mV[0] = 1.f - temp2.mV[0]; + // temp2.x is 0 at the sun and increases away from sun + temp2.mV[0] = llmax(temp2.mV[0], .001f); + // Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) + + // Higher glow.x gives dimmer glow (because next step is 1 / "angle") + temp2.mV[0] *= glow.mV[0]; + + temp2.mV[0] = pow(temp2.mV[0], glow.mV[2]); + // glow.z should be negative, so we're doing a sort of (1 / "angle") function + + // Add "minimum anti-solar illumination" + temp2.mV[0] += .25f; + + + // Haze color above cloud + vars.hazeColor = (blue_factor * (sunlight + ambient) + componentMult(haze_factor, sunlight * temp2.mV[0] + ambient)); + + // Increase ambient when there are more clouds + LLColor3 tmpAmbient = ambient + (LLColor3::white - ambient) * cloud_shadow * 0.5f; + + // Dim sunlight by cloud shadow percentage + sunlight *= (1.f - cloud_shadow); + + // Haze color below cloud + vars.hazeColorBelowCloud = (blue_factor * (sunlight + tmpAmbient) + componentMult(haze_factor, sunlight * temp2.mV[0] + tmpAmbient)); + + // Final atmosphere additive + componentMultBy(vars.hazeColor, LLColor3::white - temp1); + +/* + // SL-12574 + + // Attenuate cloud color by atmosphere + temp1 = componentSqrt(temp1); //less atmos opacity (more transparency) below clouds + + // At horizon, blend high altitude sky color towards the darker color below the clouds + vars.hazeColor += componentMult(vars.hazeColorBelowCloud - vars.hazeColor, LLColor3::white - componentSqrt(temp1)); +*/ +} + +void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in) +{ + LLVector3 tosun = tosun_in; + + if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG)) + { + if (!LLGLSLShader::sNoFixedFunction) + { + glFogf(GL_FOG_DENSITY, 0); + glFogfv(GL_FOG_COLOR, (F32 *) &LLColor4::white.mV); + glFogf(GL_FOG_END, 1000000.f); + } + return; + } + + const BOOL hide_clip_plane = TRUE; + LLColor4 target_fog(0.f, 0.2f, 0.5f, 0.f); + + const F32 water_height = gAgent.getRegion() ? gAgent.getRegion()->getWaterHeight() : 0.f; + // LLWorld::getInstance()->getWaterHeight(); + F32 camera_height = gAgentCamera.getCameraPositionAgent().mV[2]; + + F32 near_clip_height = LLViewerCamera::getInstance()->getAtAxis().mV[VZ] * LLViewerCamera::getInstance()->getNear(); + camera_height += near_clip_height; + + F32 fog_distance = 0.f; + LLColor3 res_color[3]; + + LLColor3 sky_fog_color = LLColor3::white; + LLColor3 render_fog_color = LLColor3::white; + + const F32 tosun_z = tosun.mV[VZ]; + tosun.mV[VZ] = 0.f; + tosun.normalize(); + LLVector3 perp_tosun; + perp_tosun.mV[VX] = -tosun.mV[VY]; + perp_tosun.mV[VY] = tosun.mV[VX]; + LLVector3 tosun_45 = tosun + perp_tosun; + tosun_45.normalize(); + + F32 delta = 0.06f; + tosun.mV[VZ] = delta; + perp_tosun.mV[VZ] = delta; + tosun_45.mV[VZ] = delta; + tosun.normalize(); + perp_tosun.normalize(); + tosun_45.normalize(); + + // Sky colors, just slightly above the horizon in the direction of the sun, perpendicular to the sun, and at a 45 degree angle to the sun. + AtmosphericsVars vars; + + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + + // invariants across whole sky tex process... + vars.blue_density = psky->getBlueDensity(); + vars.blue_horizon = psky->getBlueHorizon(); + vars.haze_density = psky->getHazeDensity(); + vars.haze_horizon = psky->getHazeHorizon(); + vars.density_multiplier = psky->getDensityMultiplier(); + vars.distance_multiplier = psky->getDistanceMultiplier(); + vars.max_y = psky->getMaxY(); + vars.sun_norm = LLEnvironment::instance().getSunDirectionCFR(); + vars.sunlight = psky->getSunlightColor(); + vars.ambient = psky->getAmbientColor(); + vars.glow = psky->getGlow(); + vars.cloud_shadow = psky->getCloudShadow(); + vars.dome_radius = psky->getDomeRadius(); + vars.dome_offset = psky->getDomeOffset(); + vars.light_atten = psky->getLightAttenuation(vars.max_y); + vars.light_transmittance = psky->getLightTransmittance(vars.max_y); + vars.total_density = psky->getTotalDensity(); + vars.gamma = psky->getGamma(); + + res_color[0] = calcSkyColorInDir(vars, tosun); + res_color[1] = calcSkyColorInDir(vars, perp_tosun); + res_color[2] = calcSkyColorInDir(vars, tosun_45); + + sky_fog_color = color_norm(res_color[0] + res_color[1] + res_color[2]); + + F32 full_off = -0.25f; + F32 full_on = 0.00f; + F32 on = (tosun_z - full_off) / (full_on - full_off); + on = llclamp(on, 0.01f, 1.f); + sky_fog_color *= 0.5f * on; + + + // We need to clamp these to non-zero, in order for the gamma correction to work. 0^y = ??? + S32 i; + for (i = 0; i < 3; i++) + { + sky_fog_color.mV[i] = llmax(0.0001f, sky_fog_color.mV[i]); + } + + color_gamma_correct(sky_fog_color); + + render_fog_color = sky_fog_color; + + F32 fog_density = 0.f; + fog_distance = mFogRatio * distance; + + if (camera_height > water_height) + { + LLColor4 fog(render_fog_color); + if (!LLGLSLShader::sNoFixedFunction) + { + glFogfv(GL_FOG_COLOR, fog.mV); + } + mGLFogCol = fog; + + if (hide_clip_plane) + { + // For now, set the density to extend to the cull distance. + const F32 f_log = 2.14596602628934723963618357029f; // sqrt(fabs(log(0.01f))) + fog_density = f_log/fog_distance; + if (!LLGLSLShader::sNoFixedFunction) + { + glFogi(GL_FOG_MODE, GL_EXP2); + } + } + else + { + const F32 f_log = 4.6051701859880913680359829093687f; // fabs(log(0.01f)) + fog_density = (f_log)/fog_distance; + if (!LLGLSLShader::sNoFixedFunction) + { + glFogi(GL_FOG_MODE, GL_EXP); + } + } + } + else + { + LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater(); + F32 depth = water_height - camera_height; + + // get the water param manager variables + float water_fog_density = pwater->getModifiedWaterFogDensity(depth <= 0.0f); + + LLColor4 water_fog_color(pwater->getWaterFogColor()); + + // adjust the color based on depth. We're doing linear approximations + float depth_scale = gSavedSettings.getF32("WaterGLFogDepthScale"); + float depth_modifier = 1.0f - llmin(llmax(depth / depth_scale, 0.01f), + gSavedSettings.getF32("WaterGLFogDepthFloor")); + + LLColor4 fogCol = water_fog_color * depth_modifier; + fogCol.setAlpha(1); + + // set the gl fog color + mGLFogCol = fogCol; + + // set the density based on what the shaders use + fog_density = water_fog_density * gSavedSettings.getF32("WaterGLFogDensityScale"); + + if (!LLGLSLShader::sNoFixedFunction) + { + glFogfv(GL_FOG_COLOR, (F32 *) &fogCol.mV); + glFogi(GL_FOG_MODE, GL_EXP2); + } + } + + mFogColor = sky_fog_color; + mFogColor.setAlpha(1); + + LLDrawPoolWater::sWaterFogEnd = fog_distance*2.2f; + + if (!LLGLSLShader::sNoFixedFunction) + { + LLGLSFog gls_fog; + glFogf(GL_FOG_END, fog_distance*2.2f); + glFogf(GL_FOG_DENSITY, fog_density); + glHint(GL_FOG_HINT, GL_NICEST); + } + stop_glerror(); +} + +// Functions used a lot. +F32 color_norm_pow(LLColor3& col, F32 e, BOOL postmultiply) +{ + F32 mv = color_max(col); + if (0 == mv) + { + return 0; + } + + col *= 1.f / mv; + color_pow(col, e); + if (postmultiply) + { + col *= mv; + } + return mv; +} + +// Returns angle (RADIANs) between the horizontal projection of "v" and the x_axis. +// Range of output is 0.0f to 2pi //359.99999...f +// Returns 0.0f when "v" = +/- z_axis. +F32 azimuth(const LLVector3 &v) +{ + F32 azimuth = 0.0f; + if (v.mV[VX] == 0.0f) + { + if (v.mV[VY] > 0.0f) + { + azimuth = F_PI * 0.5f; + } + else if (v.mV[VY] < 0.0f) + { + azimuth = F_PI * 1.5f;// 270.f; + } + } + else + { + azimuth = (F32) atan(v.mV[VY] / v.mV[VX]); + if (v.mV[VX] < 0.0f) + { + azimuth += F_PI; + } + else if (v.mV[VY] < 0.0f) + { + azimuth += F_PI * 2; + } + } + return azimuth; +} + +bool operator==(const AtmosphericsVars& a, const AtmosphericsVars& b) +{ + if (a.hazeColor != b.hazeColor) + { + return false; + } + + if (a.hazeColorBelowCloud != b.hazeColorBelowCloud) + { + return false; + } + + if (a.cloudColorSun != b.cloudColorSun) + { + return false; + } + + if (a.cloudColorAmbient != b.cloudColorAmbient) + { + return false; + } + + if (a.cloudDensity != b.cloudDensity) + { + return false; + } + + if (a.density_multiplier != b.density_multiplier) + { + return false; + } + + if (a.haze_horizon != b.haze_horizon) + { + return false; + } + + if (a.haze_density != b.haze_density) + { + return false; + } + + if (a.blue_horizon != b.blue_horizon) + { + return false; + } + + if (a.blue_density != b.blue_density) + { + return false; + } + + if (a.dome_offset != b.dome_offset) + { + return false; + } + + if (a.dome_radius != b.dome_radius) + { + return false; + } + + if (a.cloud_shadow != b.cloud_shadow) + { + return false; + } + + if (a.glow != b.glow) + { + return false; + } + + if (a.ambient != b.ambient) + { + return false; + } + + if (a.sunlight != b.sunlight) + { + return false; + } + + if (a.sun_norm != b.sun_norm) + { + return false; + } + + if (a.gamma != b.gamma) + { + return false; + } + + if (a.max_y != b.max_y) + { + return false; + } + + if (a.distance_multiplier != b.distance_multiplier) + { + return false; + } + + // light_atten, light_transmittance, total_density + // are ignored as they always change when the values above do + // they're just shared calc across the sky map generation to save cycles + + return true; +} + +bool approximatelyEqual(const F32 &a, const F32 &b, const F32 &fraction_treshold) +{ + F32 diff = fabs(a - b); + if (diff < F_APPROXIMATELY_ZERO || diff < llmax(fabs(a), fabs(b)) * fraction_treshold) + { + return true; + } + return false; +} + +bool approximatelyEqual(const LLColor3 &a, const LLColor3 &b, const F32 &fraction_treshold) +{ + return approximatelyEqual(a.mV[0], b.mV[0], fraction_treshold) + && approximatelyEqual(a.mV[1], b.mV[1], fraction_treshold) + && approximatelyEqual(a.mV[2], b.mV[2], fraction_treshold); +} + +bool approximatelyEqual(const LLVector4 &a, const LLVector4 &b, const F32 &fraction_treshold) +{ + return approximatelyEqual(a.mV[0], b.mV[0], fraction_treshold) + && approximatelyEqual(a.mV[1], b.mV[1], fraction_treshold) + && approximatelyEqual(a.mV[2], b.mV[2], fraction_treshold) + && approximatelyEqual(a.mV[3], b.mV[3], fraction_treshold); +} + +bool approximatelyEqual(const AtmosphericsVars& a, const AtmosphericsVars& b, const F32 fraction_treshold) +{ + if (!approximatelyEqual(a.hazeColor, b.hazeColor, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.hazeColorBelowCloud, b.hazeColorBelowCloud, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.cloudColorSun, b.cloudColorSun, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.cloudColorAmbient, b.cloudColorAmbient, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.cloudDensity, b.cloudDensity, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.density_multiplier, b.density_multiplier, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.haze_horizon, b.haze_horizon, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.haze_density, b.haze_density, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.blue_horizon, b.blue_horizon, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.blue_density, b.blue_density, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.dome_offset, b.dome_offset, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.dome_radius, b.dome_radius, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.cloud_shadow, b.cloud_shadow, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.glow, b.glow, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.ambient, b.ambient, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.sunlight, b.sunlight, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.sun_norm, b.sun_norm, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.gamma, b.gamma, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.max_y, b.max_y, fraction_treshold)) + { + return false; + } + + if (!approximatelyEqual(a.distance_multiplier, b.distance_multiplier, fraction_treshold)) + { + return false; + } + + // light_atten, light_transmittance, total_density + // are ignored as they always change when the values above do + // they're just shared calc across the sky map generation to save cycles + + return true; +} + diff --git a/indra/newview/lllegacyatmospherics.h b/indra/newview/lllegacyatmospherics.h new file mode 100644 index 0000000000..03c8efb91a --- /dev/null +++ b/indra/newview/lllegacyatmospherics.h @@ -0,0 +1,284 @@ +/** + * @file lllegacyatmospherics.h + * @brief LLVOSky 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_LLLEGACYATMOSPHERICS_H +#define LL_LLLEGACYATMOSPHERICS_H + +#include "stdtypes.h" +#include "v3color.h" +#include "v4coloru.h" +#include "llviewertexture.h" +#include "llviewerobject.h" +#include "llframetimer.h" +#include "v3colorutil.h" +#include "llsettingssky.h" + +////////////////////////////////// +// +// Lots of constants +// +// Will clean these up at some point... +// + +const F32 HORIZON_DIST = 1024.0f; +const F32 ATM_EXP_FALLOFF = 0.000126f; +const F32 ATM_SEA_LEVEL_NDENS = 2.55e25f; +const F32 ATM_HEIGHT = 100000.f; + +// 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; + +class LLFace; +class LLHaze; + +LL_FORCE_INLINE LLColor3 refr_ind_calc(const LLColor3 &wave_length) +{ + LLColor3 refr_ind; + for (S32 i = 0; i < 3; ++i) + { + const F32 wl2 = wave_length.mV[i] * wave_length.mV[i] * 1e-6f; + refr_ind.mV[i] = 6.43e3f + ( 2.95e6f / ( 146.0f - 1.f/wl2 ) ) + ( 2.55e4f / ( 41.0f - 1.f/wl2 ) ); + refr_ind.mV[i] *= 1.0e-8f; + refr_ind.mV[i] += 1.f; + } + return refr_ind; +} + + +class LLHaze +{ +public: + LLHaze() : mG(0), mFalloff(1), mAbsCoef(0.f) {mSigSca.setToBlack();} + LLHaze(const F32 g, const LLColor3& sca, const F32 fo = 2.f) : + mG(g), mSigSca(0.25f/F_PI * sca), mFalloff(fo), mAbsCoef(0.f) + { + mAbsCoef = color_intens(mSigSca) / sAirScaIntense; + } + + LLHaze(const F32 g, const F32 sca, const F32 fo = 2.f) : mG(g), + mSigSca(0.25f/F_PI * LLColor3(sca, sca, sca)), mFalloff(fo) + { + mAbsCoef = 0.01f * sca / sAirScaAvg; + } + +/* Proportion of light that is scattered into 'path' from 'in' over distance dt. */ +/* assumes that vectors 'path' and 'in' are normalized. Scattering coef / 2pi */ + + LL_FORCE_INLINE LLColor3 calcAirSca(const F32 h) + { + return calcFalloff(h) * sAirScaSeaLevel; + } + + LL_FORCE_INLINE void calcAirSca(const F32 h, LLColor3 &result) + { + result = sAirScaSeaLevel; + result *= calcFalloff(h); + } + + F32 getG() const { return mG; } + + void setG(const F32 g) + { + mG = g; + } + + const LLColor3& getSigSca() const // sea level + { + return mSigSca; + } + + void setSigSca(const LLColor3& s) + { + mSigSca = s; + mAbsCoef = 0.01f * color_intens(mSigSca) / sAirScaIntense; + } + + void setSigSca(const F32 s0, const F32 s1, const F32 s2) + { + mSigSca = sAirScaAvg * LLColor3 (s0, s1, s2); + mAbsCoef = 0.01f * (s0 + s1 + s2) / 3; + } + + F32 getFalloff() const + { + return mFalloff; + } + + void setFalloff(const F32 fo) + { + mFalloff = fo; + } + + F32 getAbsCoef() const + { + return mAbsCoef; + } + + inline static F32 calcFalloff(const F32 h) + { + return (h <= 0) ? 1.0f : (F32)LL_FAST_EXP(-ATM_EXP_FALLOFF * h); + } + + inline LLColor3 calcSigSca(const F32 h) const + { + return calcFalloff(h * mFalloff) * mSigSca; + } + + inline void calcSigSca(const F32 h, LLColor3 &result) const + { + result = mSigSca; + result *= calcFalloff(h * mFalloff); + } + + LLColor3 calcSigExt(const F32 h) const + { + return calcFalloff(h * mFalloff) * (1 + mAbsCoef) * mSigSca; + } + + F32 calcPhase(const F32 cos_theta) const; + +private: + static LLColor3 const sAirScaSeaLevel; + static F32 const sAirScaIntense; + static F32 const sAirScaAvg; + +protected: + F32 mG; + LLColor3 mSigSca; + F32 mFalloff; // 1 - slow, >1 - faster + F32 mAbsCoef; +}; + + +class LLCubeMap; + +class AtmosphericsVars +{ +public: + AtmosphericsVars() + : hazeColor(0,0,0) + , hazeColorBelowCloud(0,0,0) + , cloudColorSun(0,0,0) + , cloudColorAmbient(0,0,0) + , cloudDensity(0.0f) + , blue_density() + , blue_horizon() + , haze_density(0.0f) + , haze_horizon(0.0f) + , density_multiplier(0.0f) + , max_y(0.0f) + , gamma(1.0f) + , sun_norm(0.0f, 1.0f, 0.0f, 1.0f) + , sunlight() + , ambient() + , glow() + , cloud_shadow(1.0f) + , dome_radius(1.0f) + , dome_offset(1.0f) + , light_atten() + , light_transmittance() + { + } + + friend bool operator==(const AtmosphericsVars& a, const AtmosphericsVars& b); + // returns true if values are within treshold of each other. + friend bool approximatelyEqual(const AtmosphericsVars& a, const AtmosphericsVars& b, const F32 fraction_treshold); + + LLColor3 hazeColor; + LLColor3 hazeColorBelowCloud; + LLColor3 cloudColorSun; + LLColor3 cloudColorAmbient; + F32 cloudDensity; + LLColor3 blue_density; + LLColor3 blue_horizon; + F32 haze_density; + F32 haze_horizon; + F32 density_multiplier; + F32 distance_multiplier; + F32 max_y; + F32 gamma; + LLVector4 sun_norm; + LLColor3 sunlight; + LLColor3 ambient; + LLColor3 glow; + F32 cloud_shadow; + F32 dome_radius; + F32 dome_offset; + LLColor3 light_atten; + LLColor3 light_transmittance; + LLColor3 total_density; +}; + +class LLAtmospherics +{ +public: + LLAtmospherics(); + ~LLAtmospherics(); + + void init(); + void updateFog(const F32 distance, const LLVector3& tosun); + + const LLHaze& getHaze() const { return mHaze; } + LLHaze& getHaze() { return mHaze; } + F32 getHazeConcentration() const { return mHazeConcentration; } + void setHaze(const LLHaze& h) { mHaze = h; } + void setFogRatio(const F32 fog_ratio) { mFogRatio = fog_ratio; } + + F32 getFogRatio() const { return mFogRatio; } + LLColor4 getFogColor() const { return mFogColor; } + LLColor4 getGLFogColor() const { return mGLFogCol; } + + void setCloudDensity(F32 cloud_density) { mCloudDensity = cloud_density; } + void setWind ( const LLVector3& wind ) { mWind = wind.length(); } + + LLColor4 calcSkyColorInDir(AtmosphericsVars& vars, const LLVector3& dir, bool isShiny = false); + LLColor4 calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3& dir, bool isShiny = false); + +protected: + + void calcSkyColorWLVert(const LLSettingsSky::ptr_t &psky, LLVector3 & Pn, AtmosphericsVars& vars); + LLColor3 getHazeColor(LLSettingsSky::ptr_t psky, AtmosphericsVars& vars, F32 costheta, F32 cloud_shadow); + + LLHaze mHaze; + F32 mHazeConcentration; + F32 mCloudDensity; + F32 mWind; + BOOL mInitialized; + LLVector3 mLastLightingDirection; + LLColor3 mLastTotalAmbient; + F32 mAmbientScale; + LLColor3 mNightColorShift; + F32 mInterpVal; + LLColor4 mFogColor; + LLColor4 mGLFogCol; + F32 mFogRatio; + F32 mWorldScale; +}; + +#endif diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 0243e2183e..5a17332fde 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -69,9 +69,6 @@ /*=======================================*/ /* Formal declarations, constants, etc. */ /*=======================================*/ -std::list<LLLocalBitmap*> LLLocalBitmapMgr::sBitmapList; -LLLocalBitmapTimer LLLocalBitmapMgr::sTimer; -bool LLLocalBitmapMgr::sNeedsRebake; static const F32 LL_LOCAL_TIMER_HEARTBEAT = 3.0; static const BOOL LL_LOCAL_USE_MIPMAPS = true; @@ -131,7 +128,7 @@ LLLocalBitmap::~LLLocalBitmap() if(LL_LOCAL_REPLACE_ON_DEL && mValid && gAgentAvatarp) // fix for STORM-1837 { replaceIDs(mWorldID, IMG_DEFAULT); - LLLocalBitmapMgr::doRebake(); + LLLocalBitmapMgr::getInstance()->doRebake(); } // delete self from gimagelist @@ -571,7 +568,7 @@ void LLLocalBitmap::updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableTyp gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index); gAgentAvatarp->wearableUpdated(type); /* telling the manager to rebake once update cycle is fully done */ - LLLocalBitmapMgr::setNeedsRebake(); + LLLocalBitmapMgr::getInstance()->setNeedsRebake(); } } @@ -905,7 +902,7 @@ bool LLLocalBitmapTimer::isRunning() BOOL LLLocalBitmapTimer::tick() { - LLLocalBitmapMgr::doUpdates(); + LLLocalBitmapMgr::getInstance()->doUpdates(); return FALSE; } @@ -914,17 +911,12 @@ BOOL LLLocalBitmapTimer::tick() /*=======================================*/ LLLocalBitmapMgr::LLLocalBitmapMgr() { - // The class is all made of static members, should i even bother instantiating? } LLLocalBitmapMgr::~LLLocalBitmapMgr() { -} - -void LLLocalBitmapMgr::cleanupClass() -{ - std::for_each(sBitmapList.begin(), sBitmapList.end(), DeletePointer()); - sBitmapList.clear(); + std::for_each(mBitmapList.begin(), mBitmapList.end(), DeletePointer()); + mBitmapList.clear(); } bool LLLocalBitmapMgr::addUnit() @@ -934,7 +926,7 @@ bool LLLocalBitmapMgr::addUnit() LLFilePicker& picker = LLFilePicker::instance(); if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE)) { - sTimer.stopTimer(); + mTimer.stopTimer(); std::string filename = picker.getFirstFile(); while(!filename.empty()) @@ -949,7 +941,7 @@ bool LLLocalBitmapMgr::addUnit() if (unit->getValid()) { - sBitmapList.push_back(unit); + mBitmapList.push_back(unit); add_successful = true; } else @@ -968,7 +960,7 @@ bool LLLocalBitmapMgr::addUnit() filename = picker.getNextFile(); } - sTimer.startTimer(); + mTimer.startTimer(); } return add_successful; @@ -1007,10 +999,10 @@ bool LLLocalBitmapMgr::checkTextureDimensions(std::string filename) void LLLocalBitmapMgr::delUnit(LLUUID tracking_id) { - if (!sBitmapList.empty()) + if (!mBitmapList.empty()) { std::vector<LLLocalBitmap*> to_delete; - for (local_list_iter iter = sBitmapList.begin(); iter != sBitmapList.end(); iter++) + for (local_list_iter iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) { /* finding which ones we want deleted and making a separate list */ LLLocalBitmap* unit = *iter; if (unit->getTrackingID() == tracking_id) @@ -1023,7 +1015,7 @@ void LLLocalBitmapMgr::delUnit(LLUUID tracking_id) del_iter != to_delete.end(); del_iter++) { /* iterating over a temporary list, hence preserving the iterator validity while deleting. */ LLLocalBitmap* unit = *del_iter; - sBitmapList.remove(unit); + mBitmapList.remove(unit); delete unit; unit = NULL; } @@ -1034,7 +1026,7 @@ LLUUID LLLocalBitmapMgr::getWorldID(LLUUID tracking_id) { LLUUID world_id = LLUUID::null; - for (local_list_iter iter = sBitmapList.begin(); iter != sBitmapList.end(); iter++) + for (local_list_iter iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) { LLLocalBitmap* unit = *iter; if (unit->getTrackingID() == tracking_id) @@ -1046,11 +1038,24 @@ LLUUID LLLocalBitmapMgr::getWorldID(LLUUID tracking_id) return world_id; } +bool LLLocalBitmapMgr::isLocal(const LLUUID world_id) +{ + for (local_list_iter iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) + { + LLLocalBitmap* unit = *iter; + if (unit->getWorldID() == world_id) + { + return true; + } + } + return false; +} + std::string LLLocalBitmapMgr::getFilename(LLUUID tracking_id) { std::string filename = ""; - for (local_list_iter iter = sBitmapList.begin(); iter != sBitmapList.end(); iter++) + for (local_list_iter iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) { LLLocalBitmap* unit = *iter; if (unit->getTrackingID() == tracking_id) @@ -1068,10 +1073,10 @@ void LLLocalBitmapMgr::feedScrollList(LLScrollListCtrl* ctrl) { ctrl->clearRows(); - if (!sBitmapList.empty()) + if (!mBitmapList.empty()) { - for (local_list_iter iter = sBitmapList.begin(); - iter != sBitmapList.end(); iter++) + for (local_list_iter iter = mBitmapList.begin(); + iter != mBitmapList.end(); iter++) { LLSD element; element["columns"][0]["column"] = "unit_name"; @@ -1092,29 +1097,29 @@ void LLLocalBitmapMgr::feedScrollList(LLScrollListCtrl* ctrl) void LLLocalBitmapMgr::doUpdates() { // preventing theoretical overlap in cases with huge number of loaded images. - sTimer.stopTimer(); - sNeedsRebake = false; + mTimer.stopTimer(); + mNeedsRebake = false; - for (local_list_iter iter = sBitmapList.begin(); iter != sBitmapList.end(); iter++) + for (local_list_iter iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) { (*iter)->updateSelf(); } doRebake(); - sTimer.startTimer(); + mTimer.startTimer(); } void LLLocalBitmapMgr::setNeedsRebake() { - sNeedsRebake = true; + mNeedsRebake = true; } void LLLocalBitmapMgr::doRebake() { /* separated that from doUpdates to insure a rebake can be called separately during deletion */ - if (sNeedsRebake) + if (mNeedsRebake) { gAgentAvatarp->forceBakeAllTextures(LL_LOCAL_SLAM_FOR_DEBUG); - sNeedsRebake = false; + mNeedsRebake = false; } } diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h index ee4161fb45..d5ee7efdc6 100644 --- a/indra/newview/lllocalbitmaps.h +++ b/indra/newview/lllocalbitmaps.h @@ -110,31 +110,29 @@ class LLLocalBitmapTimer : public LLEventTimer }; -class LLLocalBitmapMgr +class LLLocalBitmapMgr : public LLSingleton<LLLocalBitmapMgr> { - public: - LLLocalBitmapMgr(); - ~LLLocalBitmapMgr(); - - public: - static void cleanupClass(); - static bool addUnit(); - static void delUnit(LLUUID tracking_id); - static bool checkTextureDimensions(std::string filename); - - static LLUUID getWorldID(LLUUID tracking_id); - static std::string getFilename(LLUUID tracking_id); - - static void feedScrollList(LLScrollListCtrl* ctrl); - static void doUpdates(); - static void setNeedsRebake(); - static void doRebake(); - - private: - static std::list<LLLocalBitmap*> sBitmapList; - static LLLocalBitmapTimer sTimer; - static bool sNeedsRebake; - typedef std::list<LLLocalBitmap*>::iterator local_list_iter; + LLSINGLETON(LLLocalBitmapMgr); + ~LLLocalBitmapMgr(); +public: + bool addUnit(); + void delUnit(LLUUID tracking_id); + bool checkTextureDimensions(std::string filename); + + LLUUID getWorldID(LLUUID tracking_id); + bool isLocal(LLUUID world_id); + std::string getFilename(LLUUID tracking_id); + + void feedScrollList(LLScrollListCtrl* ctrl); + void doUpdates(); + void setNeedsRebake(); + void doRebake(); + +private: + std::list<LLLocalBitmap*> mBitmapList; + LLLocalBitmapTimer mTimer; + bool mNeedsRebake; + typedef std::list<LLLocalBitmap*>::iterator local_list_iter; }; #endif diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 11bc1425f9..d6f3068610 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -44,7 +44,7 @@ // newview includes #include "llagent.h" -#include "llenvmanager.h" +#include "llfloaterreg.h" #include "llfloatersidepanelcontainer.h" #include "llinventoryobserver.h" #include "lllandmarkactions.h" @@ -297,7 +297,6 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) LLButton::Params maturity_button = p.maturity_button; mMaturityButton = LLUICtrlFactory::create<LLButton>(maturity_button); addChild(mMaturityButton); - mMaturityButton->setClickedCallback(boost::bind(&LLLocationInputCtrl::onMaturityButtonClicked, this)); LLButton::Params for_sale_button = p.for_sale_button; for_sale_button.tool_tip = LLTrans::getString("LocationCtrlForSaleTooltip"); @@ -655,7 +654,7 @@ void LLLocationInputCtrl::onAddLandmarkButtonClicked() } else { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); + LLFloaterReg::showInstance("add_landmark"); } } @@ -664,11 +663,6 @@ void LLLocationInputCtrl::onAgentParcelChange() refresh(); } -void LLLocationInputCtrl::onMaturityButtonClicked() -{ - LLUI::sHelpImpl->showTopic(mMaturityHelpTopic); -} - void LLLocationInputCtrl::onRegionBoundaryCrossed() { createNavMeshStatusListenerForCurrentRegion(); @@ -1100,9 +1094,7 @@ void LLLocationInputCtrl::changeLocationPresentation() //change location presentation only if user does not select/paste anything and //human-readable region name is being displayed - std::string text = mTextEntry->getText(); - LLStringUtil::trim(text); - if(!mTextEntry->hasSelection() && text == mHumanReadableLocation) + if(!mTextEntry->hasSelection() && mTextEntry->getText() == mHumanReadableLocation) { //needs unescaped one LLSLURL slurl; @@ -1135,7 +1127,7 @@ void LLLocationInputCtrl::onLocationContextMenuItemClicked(const LLSD& userdata) if(!landmark) { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); + LLFloaterReg::showInstance("add_landmark"); } else { diff --git a/indra/newview/lllocationinputctrl.h b/indra/newview/lllocationinputctrl.h index da71bab6c1..79dbe17982 100644 --- a/indra/newview/lllocationinputctrl.h +++ b/indra/newview/lllocationinputctrl.h @@ -160,7 +160,6 @@ private: void onForSaleButtonClicked(); void onAddLandmarkButtonClicked(); void onAgentParcelChange(); - void onMaturityButtonClicked(); void onRegionBoundaryCrossed(); void onNavMeshStatusChange(const LLPathfindingNavMeshStatus &pNavMeshStatus); // callbacks diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 1bdeddbcfe..eebc2486a2 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -67,6 +67,8 @@ const std::string LL_IM_FROM("from"); const std::string LL_IM_FROM_ID("from_id"); const std::string LL_TRANSCRIPT_FILE_EXTENSION("txt"); +const std::string GROUP_CHAT_SUFFIX(" (group)"); + const static char IM_SYMBOL_SEPARATOR(':'); const static std::string IM_SEPARATOR(std::string() + IM_SYMBOL_SEPARATOR + " "); const static std::string NEW_LINE("\n"); @@ -131,6 +133,16 @@ void append_to_last_message(std::list<LLSD>& messages, const std::string& line) messages.back()[LL_IM_TEXT] = im_text; } +std::string remove_utf8_bom(const char* buf) +{ + std::string res(buf); + if (res[0] == (char)0xEF && res[1] == (char)0xBB && res[2] == (char)0xBF) + { + res.erase(0, 3); + } + return res; +} + class LLLogChatTimeScanner: public LLSingleton<LLLogChatTimeScanner> { LLSINGLETON(LLLogChatTimeScanner); @@ -209,11 +221,24 @@ LLLogChatTimeScanner::LLLogChatTimeScanner() mTimeStream.imbue(std::locale(mTimeStream.getloc(), new time_input_facet(DATE_FORMAT))); } -LLLogChat::save_history_signal_t * LLLogChat::sSaveHistorySignal = NULL; +LLLogChat::LLLogChat() +: mSaveHistorySignal(NULL) // only needed in preferences +{ + mHistoryThreadsMutex = new LLMutex(); +} -std::map<LLUUID,LLLoadHistoryThread *> LLLogChat::sLoadHistoryThreads; -std::map<LLUUID,LLDeleteHistoryThread *> LLLogChat::sDeleteHistoryThreads; -LLMutex* LLLogChat::sHistoryThreadsMutex = NULL; +LLLogChat::~LLLogChat() +{ + delete mHistoryThreadsMutex; + mHistoryThreadsMutex = NULL; + + if (mSaveHistorySignal) + { + mSaveHistorySignal->disconnect_all_slots(); + delete mSaveHistorySignal; + mSaveHistorySignal = NULL; + } +} //static @@ -256,6 +281,28 @@ std::string LLLogChat::makeLogFileName(std::string filename) return filename; } +//static +void LLLogChat::renameLogFile(const std::string& old_filename, const std::string& new_filename) +{ + std::string new_name = cleanFileName(new_filename); + std::string old_name = cleanFileName(old_filename); + new_name = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS, new_name); + old_name = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS, old_name); + + if (new_name.empty() || old_name.empty()) + { + return; + } + + new_name += '.' + LL_TRANSCRIPT_FILE_EXTENSION; + old_name += '.' + LL_TRANSCRIPT_FILE_EXTENSION; + + if (!LLFile::isfile(new_name) && LLFile::isfile(old_name)) + { + LLFile::rename(old_name, new_name); + } +} + std::string LLLogChat::cleanFileName(std::string filename) { std::string invalidChars = "\"\'\\/?*:.<>|[]{}~"; // Cannot match glob or illegal filename chars @@ -338,14 +385,11 @@ void LLLogChat::saveHistory(const std::string& filename, file.close(); - if (NULL != sSaveHistorySignal) - { - (*sSaveHistorySignal)(); - } + LLLogChat::getInstance()->triggerHistorySignal(); } // static -void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params) +void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params, bool is_group) { if (file_name.empty()) { @@ -358,10 +402,25 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& m LLFILE* fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r");/*Flawfinder: ignore*/ if (!fptr) { - fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ + if (is_group) + { + std::string old_name(file_name); + old_name.erase(old_name.size() - GROUP_CHAT_SUFFIX.size()); + fptr = LLFile::fopen(LLLogChat::makeLogFileName(old_name), "r"); + if (fptr) + { + fclose(fptr); + LLFile::copy(LLLogChat::makeLogFileName(old_name), LLLogChat::makeLogFileName(file_name)); + } + fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r"); + } if (!fptr) { - return; //No previous conversation with this name. + fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ + if (!fptr) + { + return; //No previous conversation with this name. + } } } @@ -390,7 +449,7 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& m continue; } - std::string line(buffer); + std::string line(remove_utf8_bom(buffer)); //updated 1.23 plain text log format requires a space added before subsequent lines in a multilined message if (' ' == line[0]) @@ -416,13 +475,12 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& m fclose(fptr); } -// static bool LLLogChat::historyThreadsFinished(LLUUID session_id) { LLMutexLock lock(historyThreadsMutex()); bool finished = true; - std::map<LLUUID,LLLoadHistoryThread *>::iterator it = sLoadHistoryThreads.find(session_id); - if (it != sLoadHistoryThreads.end()) + std::map<LLUUID,LLLoadHistoryThread *>::iterator it = mLoadHistoryThreads.find(session_id); + if (it != mLoadHistoryThreads.end()) { finished = it->second->isFinished(); } @@ -430,95 +488,93 @@ bool LLLogChat::historyThreadsFinished(LLUUID session_id) { return false; } - std::map<LLUUID,LLDeleteHistoryThread *>::iterator dit = sDeleteHistoryThreads.find(session_id); - if (dit != sDeleteHistoryThreads.end()) + std::map<LLUUID,LLDeleteHistoryThread *>::iterator dit = mDeleteHistoryThreads.find(session_id); + if (dit != mDeleteHistoryThreads.end()) { finished = finished && dit->second->isFinished(); } return finished; } -// static LLLoadHistoryThread* LLLogChat::getLoadHistoryThread(LLUUID session_id) { LLMutexLock lock(historyThreadsMutex()); - std::map<LLUUID,LLLoadHistoryThread *>::iterator it = sLoadHistoryThreads.find(session_id); - if (it != sLoadHistoryThreads.end()) + std::map<LLUUID,LLLoadHistoryThread *>::iterator it = mLoadHistoryThreads.find(session_id); + if (it != mLoadHistoryThreads.end()) { return it->second; } return NULL; } -// static LLDeleteHistoryThread* LLLogChat::getDeleteHistoryThread(LLUUID session_id) { LLMutexLock lock(historyThreadsMutex()); - std::map<LLUUID,LLDeleteHistoryThread *>::iterator it = sDeleteHistoryThreads.find(session_id); - if (it != sDeleteHistoryThreads.end()) + std::map<LLUUID,LLDeleteHistoryThread *>::iterator it = mDeleteHistoryThreads.find(session_id); + if (it != mDeleteHistoryThreads.end()) { return it->second; } return NULL; } -// static bool LLLogChat::addLoadHistoryThread(LLUUID& session_id, LLLoadHistoryThread* lthread) { LLMutexLock lock(historyThreadsMutex()); - std::map<LLUUID,LLLoadHistoryThread *>::const_iterator it = sLoadHistoryThreads.find(session_id); - if (it != sLoadHistoryThreads.end()) + std::map<LLUUID,LLLoadHistoryThread *>::const_iterator it = mLoadHistoryThreads.find(session_id); + if (it != mLoadHistoryThreads.end()) { return false; } - sLoadHistoryThreads[session_id] = lthread; + mLoadHistoryThreads[session_id] = lthread; return true; } -// static bool LLLogChat::addDeleteHistoryThread(LLUUID& session_id, LLDeleteHistoryThread* dthread) { LLMutexLock lock(historyThreadsMutex()); - std::map<LLUUID,LLDeleteHistoryThread *>::const_iterator it = sDeleteHistoryThreads.find(session_id); - if (it != sDeleteHistoryThreads.end()) + std::map<LLUUID,LLDeleteHistoryThread *>::const_iterator it = mDeleteHistoryThreads.find(session_id); + if (it != mDeleteHistoryThreads.end()) { return false; } - sDeleteHistoryThreads[session_id] = dthread; + mDeleteHistoryThreads[session_id] = dthread; return true; } -// static void LLLogChat::cleanupHistoryThreads() { LLMutexLock lock(historyThreadsMutex()); std::vector<LLUUID> uuids; - std::map<LLUUID,LLLoadHistoryThread *>::iterator lit = sLoadHistoryThreads.begin(); - for (; lit != sLoadHistoryThreads.end(); lit++) + std::map<LLUUID,LLLoadHistoryThread *>::iterator lit = mLoadHistoryThreads.begin(); + for (; lit != mLoadHistoryThreads.end(); lit++) { - if (lit->second->isFinished() && sDeleteHistoryThreads[lit->first]->isFinished()) + if (lit->second->isFinished() && mDeleteHistoryThreads[lit->first]->isFinished()) { delete lit->second; - delete sDeleteHistoryThreads[lit->first]; + delete mDeleteHistoryThreads[lit->first]; uuids.push_back(lit->first); } } std::vector<LLUUID>::iterator uuid_it = uuids.begin(); for ( ;uuid_it != uuids.end(); uuid_it++) { - sLoadHistoryThreads.erase(*uuid_it); - sDeleteHistoryThreads.erase(*uuid_it); + mLoadHistoryThreads.erase(*uuid_it); + mDeleteHistoryThreads.erase(*uuid_it); } } -//static LLMutex* LLLogChat::historyThreadsMutex() { - if (sHistoryThreadsMutex == NULL) - { - sHistoryThreadsMutex = new LLMutex(); - } - return sHistoryThreadsMutex; + return mHistoryThreadsMutex; +} + +void LLLogChat::triggerHistorySignal() +{ + if (NULL != mSaveHistorySignal) + { + (*mSaveHistorySignal)(); + } } // static @@ -596,15 +652,14 @@ void LLLogChat::getListOfTranscriptBackupFiles(std::vector<std::string>& list_of findTranscriptFiles(pattern, list_of_transcriptions); } -//static boost::signals2::connection LLLogChat::setSaveHistorySignal(const save_history_signal_t::slot_type& cb) { - if (NULL == sSaveHistorySignal) + if (NULL == mSaveHistorySignal) { - sSaveHistorySignal = new save_history_signal_t(); + mSaveHistorySignal = new save_history_signal_t(); } - return sSaveHistorySignal->connect(cb); + return mSaveHistorySignal->connect(cb); } //static @@ -738,8 +793,8 @@ bool LLLogChat::isTranscriptExist(const LLUUID& avatar_id, bool is_group) { std::string file_name; gCacheName->getGroupName(avatar_id, file_name); - file_name = makeLogFileName(file_name); - return isTranscriptFileFound(makeLogFileName(file_name)); + file_name = makeLogFileName(file_name + GROUP_CHAT_SUFFIX); + return isTranscriptFileFound(file_name); } return false; } @@ -782,7 +837,7 @@ bool LLLogChat::isTranscriptFileFound(std::string fullname) { //matching a timestamp boost::match_results<std::string::const_iterator> matches; - if (boost::regex_match(std::string(buffer), matches, TIMESTAMP)) + if (boost::regex_match(remove_utf8_bom(buffer), matches, TIMESTAMP)) { result = true; } @@ -1047,12 +1102,28 @@ void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::list<LL if (!fptr) { - fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ + bool is_group = load_params.has("is_group") ? load_params["is_group"].asBoolean() : false; + if (is_group) + { + std::string old_name(file_name); + old_name.erase(old_name.size() - GROUP_CHAT_SUFFIX.size()); + fptr = LLFile::fopen(LLLogChat::makeLogFileName(old_name), "r"); + if (fptr) + { + fclose(fptr); + LLFile::copy(LLLogChat::makeLogFileName(old_name), LLLogChat::makeLogFileName(file_name)); + } + fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r"); + } if (!fptr) { - mNewLoad = false; - (*mLoadEndSignal)(messages, file_name); - return; //No previous conversation with this name. + fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ + if (!fptr) + { + mNewLoad = false; + (*mLoadEndSignal)(messages, file_name); + return; //No previous conversation with this name. + } } } @@ -1087,7 +1158,7 @@ void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::list<LL firstline = FALSE; continue; } - std::string line(buffer); + std::string line(remove_utf8_bom(buffer)); //updated 1.23 plaint text log format requires a space added before subsequent lines in a multilined message if (' ' == line[0]) diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h index fcbd38a044..c4b61ee716 100644 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -79,8 +79,10 @@ public: static void deleteHistory(); }; -class LLLogChat +class LLLogChat : public LLSingleton<LLLogChat> { + LLSINGLETON(LLLogChat); + ~LLLogChat(); public: // status values for callback function enum ELogLineType { @@ -92,6 +94,7 @@ public: static std::string timestamp(bool withdate = false); static std::string makeLogFileName(std::string(filename)); + static void renameLogFile(const std::string& old_filename, const std::string& new_filename); /** *Add functions to get old and non date stamped file names when needed */ @@ -104,10 +107,10 @@ public: static void getListOfTranscriptFiles(std::vector<std::string>& list); static void getListOfTranscriptBackupFiles(std::vector<std::string>& list_of_transcriptions); - static void loadChatHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params = LLSD()); + static void loadChatHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params = LLSD(), bool is_group = false); typedef boost::signals2::signal<void ()> save_history_signal_t; - static boost::signals2::connection setSaveHistorySignal(const save_history_signal_t::slot_type& cb); + boost::signals2::connection setSaveHistorySignal(const save_history_signal_t::slot_type& cb); static bool moveTranscripts(const std::string currentDirectory, const std::string newDirectory, @@ -123,21 +126,23 @@ public: static bool isAdHocTranscriptExist(std::string file_name); static bool isTranscriptFileFound(std::string fullname); - static bool historyThreadsFinished(LLUUID session_id); - static LLLoadHistoryThread* getLoadHistoryThread(LLUUID session_id); - static LLDeleteHistoryThread* getDeleteHistoryThread(LLUUID session_id); - static bool addLoadHistoryThread(LLUUID& session_id, LLLoadHistoryThread* lthread); - static bool addDeleteHistoryThread(LLUUID& session_id, LLDeleteHistoryThread* dthread); - static void cleanupHistoryThreads(); + bool historyThreadsFinished(LLUUID session_id); + LLLoadHistoryThread* getLoadHistoryThread(LLUUID session_id); + LLDeleteHistoryThread* getDeleteHistoryThread(LLUUID session_id); + bool addLoadHistoryThread(LLUUID& session_id, LLLoadHistoryThread* lthread); + bool addDeleteHistoryThread(LLUUID& session_id, LLDeleteHistoryThread* dthread); + void cleanupHistoryThreads(); private: static std::string cleanFileName(std::string filename); - static save_history_signal_t * sSaveHistorySignal; - static std::map<LLUUID,LLLoadHistoryThread *> sLoadHistoryThreads; - static std::map<LLUUID,LLDeleteHistoryThread *> sDeleteHistoryThreads; - static LLMutex* sHistoryThreadsMutex; - static LLMutex* historyThreadsMutex(); + LLMutex* historyThreadsMutex(); + void triggerHistorySignal(); + + save_history_signal_t * mSaveHistorySignal; + std::map<LLUUID,LLLoadHistoryThread *> mLoadHistoryThreads; + std::map<LLUUID,LLDeleteHistoryThread *> mDeleteHistoryThreads; + LLMutex* mHistoryThreadsMutex; }; /** @@ -192,6 +197,7 @@ protected: virtual ~LLChatLogParser() {}; }; +extern const std::string GROUP_CHAT_SUFFIX; // LLSD map lookup constants extern const std::string LL_IM_TIME; //("time"); diff --git a/indra/newview/llloginhandler.cpp b/indra/newview/llloginhandler.cpp index eca34c0d4d..22cedf450e 100644 --- a/indra/newview/llloginhandler.cpp +++ b/indra/newview/llloginhandler.cpp @@ -139,8 +139,11 @@ LLPointer<LLCredential> LLLoginHandler::initializeLoginInfo() // so try to load it from the UserLoginInfo result = loadSavedUserLoginInfo(); if (result.isNull()) - { - result = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + { + // Since legacy viewer store login info one per grid, newer viewers have to + // reuse same information to remember last user and for compatibility, + // but otherwise login info is stored in separate map in gSecAPIHandler + result = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); } return result; diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 8a69acb8dc..e81d2cc082 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -58,11 +58,12 @@ #include "llevents.h" #include "llappviewer.h" #include "llsdserialize.h" +#include "lltrans.h" #include <boost/scoped_ptr.hpp> #include <sstream> -const S32 LOGIN_MAX_RETRIES = 3; +const S32 LOGIN_MAX_RETRIES = 0; // Viewer should not autmatically retry login const F32 LOGIN_SRV_TIMEOUT_MIN = 10; const F32 LOGIN_SRV_TIMEOUT_MAX = 120; const F32 LOGIN_DNS_TIMEOUT_FACTOR = 0.9; // make DNS wait shorter then retry time @@ -215,8 +216,8 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia request_params["last_exec_event"] = mLastExecEvent; request_params["last_exec_duration"] = mLastExecDuration; request_params["mac"] = (char*)hashed_unique_id_string; - request_params["version"] = LLVersionInfo::getVersion(); - request_params["channel"] = LLVersionInfo::getChannel(); + request_params["version"] = LLVersionInfo::instance().getVersion(); + request_params["channel"] = LLVersionInfo::instance().getChannel(); request_params["platform"] = mPlatform; request_params["address_size"] = ADDRESS_SIZE; request_params["platform_version"] = mPlatformVersion; @@ -332,7 +333,7 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event) { data["certificate"] = response["certificate"]; } - + if (gViewerWindow) gViewerWindow->setShowProgress(FALSE); @@ -349,13 +350,36 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event) // login.cgi is insisting on a required update. We were called with an // event that bundles both the login.cgi 'response' and the // synchronization event from the 'updater'. - std::string required_version = response["message_args"]["VERSION"]; - LL_WARNS("LLLogin") << "Login failed because an update to version " << required_version << " is required." << LL_ENDL; + std::string login_version = response["message_args"]["VERSION"]; + std::string vvm_version = updater["VERSION"]; + std::string relnotes = updater["URL"]; + LL_WARNS("LLLogin") << "Login failed because an update to version " << login_version << " is required." << LL_ENDL; + // vvm_version might be empty because we might not have gotten + // SLVersionChecker's LoginSync handshake. But if it IS populated, it + // should (!) be the same as the version we got from login.cgi. + if ((! vvm_version.empty()) && vvm_version != login_version) + { + LL_WARNS("LLLogin") << "VVM update version " << vvm_version + << " differs from login version " << login_version + << "; presenting VVM version to match release notes URL" + << LL_ENDL; + login_version = vvm_version; + } + if (relnotes.empty() || relnotes.find("://") == std::string::npos) + { + relnotes = LLTrans::getString("RELEASE_NOTES_BASE_URL"); + if (!LLStringUtil::endsWith(relnotes, "/")) + relnotes += "/"; + relnotes += LLURI::escape(login_version) + ".html"; + } if (gViewerWindow) gViewerWindow->setShowProgress(FALSE); - LLSD args(LLSDMap("VERSION", required_version)); + LLSD args; + args["VERSION"] = login_version; + args["URL"] = relnotes; + if (updater.isUndefined()) { // If the updater failed to shake hands, better advise the user to @@ -427,6 +451,7 @@ void LLLoginInstance::handleLoginSuccess(const LLSD& event) LL_INFOS("LLLogin") << "LLLoginInstance::handleLoginSuccess" << LL_ENDL; attemptComplete(); + mRequestData.clear(); } void LLLoginInstance::handleDisconnect(const LLSD& event) diff --git a/indra/newview/llmachineid.cpp b/indra/newview/llmachineid.cpp index 51127928d1..57a6ecb604 100644 --- a/indra/newview/llmachineid.cpp +++ b/indra/newview/llmachineid.cpp @@ -237,7 +237,7 @@ S32 LLMachineID::init() { if (j >= serial_size || vtProp.bstrVal[j] == 0) break; - + static_unique_id[i] = (unsigned int)(static_unique_id[i] + serialNumber[j]); j++; } diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp index f158aae3d2..c3e39429a2 100644 --- a/indra/newview/llmaniprotate.cpp +++ b/indra/newview/llmaniprotate.cpp @@ -447,6 +447,7 @@ BOOL LLManipRotate::handleMouseDownOnPart( S32 x, S32 y, MASK mask ) } mMouseCur = mMouseDown; + mAgentSelfAtAxis = gAgent.getAtAxis(); // no point checking if avatar was selected, just save the value // Route future Mouse messages here preemptively. (Release on mouse up.) setMouseCapture( TRUE ); @@ -610,6 +611,26 @@ void LLManipRotate::drag( S32 x, S32 y ) else { object->setRotation(new_rot, damped); + LLVOAvatar* avatar = object->asAvatar(); + if (avatar && avatar->isSelf() + && LLSelectMgr::getInstance()->mAllowSelectAvatar + && !object->getParent()) + { + // Normal avatars use object's orienttion, but self uses + // separate LLCoordFrame + // See LVOAvatar::updateOrientation() + if (gAgentCamera.getFocusOnAvatar()) + { + //Don't rotate camera with avatar + gAgentCamera.setFocusOnAvatar(false, false, false); + } + + LLVector3 at_axis = mAgentSelfAtAxis; + at_axis *= mRotation; + at_axis.mV[VZ] = 0.f; + at_axis.normalize(); + gAgent.resetAxes(at_axis); + } rebuild(object); } @@ -717,7 +738,7 @@ void LLManipRotate::drag( S32 x, S32 y ) LLViewerObject *root_object = (cur == NULL) ? NULL : cur->getRootEdit(); if( cur->permModify() && cur->permMove() && !cur->isPermanentEnforced() && ((root_object == NULL) || !root_object->isPermanentEnforced()) && - !cur->isAvatar()) + (!cur->isAvatar() || LLSelectMgr::getInstance()->mAllowSelectAvatar)) { selectNode->mLastRotation = cur->getRotation(); selectNode->mLastPositionLocal = cur->getPosition(); diff --git a/indra/newview/llmaniprotate.h b/indra/newview/llmaniprotate.h index e8f1c24c58..dc36ef796a 100644 --- a/indra/newview/llmaniprotate.h +++ b/indra/newview/llmaniprotate.h @@ -95,6 +95,7 @@ private: LLVector3 mMouseDown; LLVector3 mMouseCur; + LLVector3 mAgentSelfAtAxis; // Own agent uses separate rotation method F32 mRadiusMeters; LLVector3 mCenterToCam; diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index 92a09357c8..9248c160c6 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -386,7 +386,7 @@ BOOL LLManipTranslate::handleMouseDownOnPart( S32 x, S32 y, MASK mask ) } else if (gSavedSettings.getBOOL("SnapToMouseCursor")) { - LLUI::setMousePositionScreen(mouse_pos.mX, mouse_pos.mY); + LLUI::getInstance()->setMousePositionScreen(mouse_pos.mX, mouse_pos.mY); x = mouse_pos.mX; y = mouse_pos.mY; } diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index a0e19f2d19..aa0c7fb73b 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -219,7 +219,7 @@ namespace LLMarketplaceImport httpHeaders->append(HTTP_OUT_HEADER_CONNECTION, "Keep-Alive"); httpHeaders->append(HTTP_OUT_HEADER_COOKIE, sMarketplaceCookie); httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_XML); - httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, LLViewerMedia::getCurrentUserAgent()); + httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, LLViewerMedia::getInstance()->getCurrentUserAgent()); LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD(), httpOpts, httpHeaders); @@ -283,11 +283,11 @@ namespace LLMarketplaceImport httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*"); httpHeaders->append(HTTP_OUT_HEADER_COOKIE, sMarketplaceCookie); httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); - httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, LLViewerMedia::getCurrentUserAgent()); + httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, LLViewerMedia::getInstance()->getCurrentUserAgent()); } else { - httpHeaders = LLViewerMedia::getHttpHeaders(); + httpHeaders = LLViewerMedia::getInstance()->getHttpHeaders(); } LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts, httpHeaders); @@ -1294,6 +1294,11 @@ void LLMarketplaceData::setSLMDataFetched(U32 status) } } +bool LLMarketplaceData::isSLMDataFetched() +{ + return mMarketPlaceDataFetched == MarketplaceFetchCodes::MARKET_FETCH_DONE; +} + // Creation / Deletion / Update // Methods publicly called bool LLMarketplaceData::createListing(const LLUUID& folder_id) diff --git a/indra/newview/llmarketplacefunctions.h b/indra/newview/llmarketplacefunctions.h index ec312baca3..fee9225f77 100644 --- a/indra/newview/llmarketplacefunctions.h +++ b/indra/newview/llmarketplacefunctions.h @@ -204,7 +204,9 @@ public: void setDataFetchedSignal(const status_updated_signal_t::slot_type& cb); void setSLMDataFetched(U32 status); U32 getSLMDataFetched() { return mMarketPlaceDataFetched; } - + + bool isSLMDataFetched(); + // 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); diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 7f6955d08c..0affe8efb4 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -202,12 +202,29 @@ 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; } //////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + if (LLPanel::handleScrollHWheel(x, y, clicks)) return TRUE; + if (mMediaSource && mMediaSource->hasMedia()) + { + convertInputCoords(x, y); + mMediaSource->scrollWheel(x, y, clicks, 0, gKeyboard->currentMask(TRUE)); + } + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// // virtual BOOL LLMediaCtrl::handleToolTip(S32 x, S32 y, MASK mask) { @@ -691,7 +708,7 @@ bool LLMediaCtrl::ensureMediaSourceExists() if(mMediaSource.isNull()) { // If we don't already have a media source, try to create one. - mMediaSource = LLViewerMedia::newMediaImpl(mMediaTextureID, mTextureWidth, mTextureHeight); + mMediaSource = LLViewerMedia::getInstance()->newMediaImpl(mMediaTextureID, mTextureWidth, mTextureHeight); if ( mMediaSource ) { mMediaSource->setUsedInUI(true); @@ -1098,7 +1115,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) auth_request_params.substitutions = args; auth_request_params.payload = LLSD().with("media_id", mMediaTextureID); - auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2); + auth_request_params.functor.function = boost::bind(&LLViewerMedia::authSubmitCallback, _1, _2); LLNotifications::instance().add(auth_request_params); }; break; @@ -1144,7 +1161,7 @@ void LLMediaCtrl::onPopup(const LLSD& notification, const LLSD& response) else { // Make sure the opening instance knows its window open request was denied, so it can clean things up. - LLViewerMedia::proxyWindowClosed(notification["payload"]["uuid"]); + LLViewerMedia::getInstance()->proxyWindowClosed(notification["payload"]["uuid"]); } } diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 11400c8274..bd24c47a4f 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -31,6 +31,7 @@ #include "lluictrl.h" #include "llframetimer.h" +#include "llnotificationptr.h" class LLViewBorder; class LLUICtrlFactory; @@ -92,6 +93,7 @@ public: 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 handleScrollHWheel( S32 x, S32 y, S32 clicks ); virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); // navigation @@ -144,7 +146,7 @@ public: void setTextureSize(S32 width, S32 height); - void showNotification(boost::shared_ptr<class LLNotification> notify); + void showNotification(LLNotificationPtr notify); void hideNotification(); void setTrustedContent(bool trusted); diff --git a/indra/newview/llmenuoptionpathfindingrebakenavmesh.cpp b/indra/newview/llmenuoptionpathfindingrebakenavmesh.cpp index 63d97f6ac2..0663dd41ee 100644 --- a/indra/newview/llmenuoptionpathfindingrebakenavmesh.cpp +++ b/indra/newview/llmenuoptionpathfindingrebakenavmesh.cpp @@ -34,7 +34,6 @@ #include <boost/signals2.hpp> #include "llagent.h" -#include "llenvmanager.h" #include "llnotificationsutil.h" #include "llpathfindingmanager.h" #include "llpathfindingnavmesh.h" diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 31e3d408d7..2c1c1191da 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -41,7 +41,6 @@ #include "lldeadmantimer.h" #include "llfloatermodelpreview.h" #include "llfloaterperms.h" -#include "lleconomy.h" #include "llimagej2c.h" #include "llhost.h" #include "llmath.h" @@ -100,7 +99,7 @@ // locking actions. In particular, the following operations // on LLMeshRepository are very averse to any stalls: // * loadMesh -// * getMeshHeader (For structural details, see: +// * search in mMeshHeader (For structural details, see: // http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format) // * notifyLoadedMeshes // * getSkinInfo @@ -877,12 +876,12 @@ LLMeshRepoThread::~LLMeshRepoThread() void LLMeshRepoThread::run() { LLCDResult res = LLConvexDecomposition::initThread(); - if (res != LLCD_OK) + if (res != LLCD_OK && LLConvexDecomposition::isFunctional()) { LL_WARNS(LOG_MESH) << "Convex decomposition unable to be loaded. Expect severe problems." << LL_ENDL; } - while (!LLApp::isQuitting()) + while (!LLApp::isExiting()) { // *TODO: Revise sleep/wake strategy and try to move away // from polling operations in this thread. We can sleep @@ -899,7 +898,7 @@ void LLMeshRepoThread::run() mSignal->wait(); - if (LLApp::isQuitting()) + if (LLApp::isExiting()) { break; } @@ -1143,7 +1142,7 @@ void LLMeshRepoThread::run() } res = LLConvexDecomposition::quitThread(); - if (res != LLCD_OK) + if (res != LLCD_OK && LLConvexDecomposition::isFunctional()) { LL_WARNS(LOG_MESH) << "Convex decomposition unable to be quit." << LL_ENDL; } @@ -1169,7 +1168,7 @@ void LLMeshRepoThread::loadMeshPhysicsShape(const LLUUID& mesh_id) void LLMeshRepoThread::lockAndLoadMeshLOD(const LLVolumeParams& mesh_params, S32 lod) { - if (!LLAppViewer::isQuitting()) + if (!LLAppViewer::isExiting()) { loadMeshLOD(mesh_params, lod); } @@ -1554,7 +1553,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) if (!zero) { //attempt to parse - if (physicsShapeReceived(mesh_id, buffer, size)) + if (physicsShapeReceived(mesh_id, buffer, size) == MESH_OK) { delete[] buffer; return true; @@ -1648,7 +1647,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, bool c LLMeshRepository::sCacheBytesRead += bytes; ++LLMeshRepository::sCacheReads; file.read(buffer, bytes); - if (headerReceived(mesh_params, buffer, bytes)) + if (headerReceived(mesh_params, buffer, bytes) == MESH_OK) { // Found mesh in VFS cache return true; @@ -1795,7 +1794,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, return retval; } -bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size) +EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size) { const LLUUID mesh_id = mesh_params.getSculptID(); LLSD header; @@ -1803,30 +1802,39 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat U32 header_size = 0; if (data_size > 0) { - std::string res_str((char*) data, data_size); + std::istringstream stream; + try + { + std::string res_str((char*)data, data_size); - std::string deprecated_header("<? LLSD/Binary ?>"); + std::string deprecated_header("<? LLSD/Binary ?>"); - if (res_str.substr(0, deprecated_header.size()) == deprecated_header) - { - res_str = res_str.substr(deprecated_header.size()+1, data_size); - header_size = deprecated_header.size()+1; - } - data_size = res_str.size(); + if (res_str.substr(0, deprecated_header.size()) == deprecated_header) + { + res_str = res_str.substr(deprecated_header.size() + 1, data_size); + header_size = deprecated_header.size() + 1; + } + data_size = res_str.size(); - std::istringstream stream(res_str); + stream.str(res_str); + } + catch (std::bad_alloc&) + { + // out of memory, we won't be able to process this mesh + return MESH_OUT_OF_MEMORY; + } if (!LLSDSerialize::fromBinary(header, stream, data_size)) { LL_WARNS(LOG_MESH) << "Mesh header parse error. Not a valid mesh asset! ID: " << mesh_id << LL_ENDL; - return false; + return MESH_PARSE_FAILURE; } if (!header.isMap()) { LL_WARNS(LOG_MESH) << "Mesh header is invalid for ID: " << mesh_id << LL_ENDL; - return false; + return MESH_INVALID; } if (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION) @@ -1872,7 +1880,7 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat } } - return true; + return MESH_OK; } EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size) @@ -1889,7 +1897,7 @@ EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_p std::string mesh_string((char*)data, data_size); stream.str(mesh_string); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { // out of memory, we won't be able to process this mesh return MESH_OUT_OF_MEMORY; @@ -1903,6 +1911,12 @@ EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_p { LLMutexLock lock(mMutex); mLoadedQ.push(mesh); + // LLPointer is not thread safe, since we added this pointer into + // threaded list, make sure counter gets decreased inside mutex lock + // and won't affect mLoadedQ processing + volume = NULL; + // might be good idea to turn mesh into pointer to avoid making a copy + mesh.mVolume = NULL; } return MESH_OK; } @@ -1917,18 +1931,25 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat if (data_size > 0) { - std::string res_str((char*) data, data_size); - - std::istringstream stream(res_str); + try + { + std::string res_str((char*)data, data_size); + std::istringstream stream(res_str); - U32 uzip_result = LLUZipHelper::unzip_llsd(skin, stream, data_size); - if (uzip_result != LLUZipHelper::ZR_OK) - { - LL_WARNS(LOG_MESH) << "Mesh skin info parse error. Not a valid mesh asset! ID: " << mesh_id - << " uzip result" << uzip_result - << LL_ENDL; - return false; - } + U32 uzip_result = LLUZipHelper::unzip_llsd(skin, stream, data_size); + if (uzip_result != LLUZipHelper::ZR_OK) + { + LL_WARNS(LOG_MESH) << "Mesh skin info parse error. Not a valid mesh asset! ID: " << mesh_id + << " uzip result" << uzip_result + << LL_ENDL; + return false; + } + } + catch (std::bad_alloc&) + { + LL_WARNS(LOG_MESH) << "Out of memory for mesh ID " << mesh_id << " of size: " << data_size << LL_ENDL; + return false; + } } { @@ -1950,19 +1971,26 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3 LLSD decomp; if (data_size > 0) - { - std::string res_str((char*) data, data_size); - - std::istringstream stream(res_str); + { + try + { + std::string res_str((char*)data, data_size); + std::istringstream stream(res_str); - U32 uzip_result = LLUZipHelper::unzip_llsd(decomp, stream, data_size); - if (uzip_result != LLUZipHelper::ZR_OK) - { - LL_WARNS(LOG_MESH) << "Mesh decomposition parse error. Not a valid mesh asset! ID: " << mesh_id - << " uzip result: " << uzip_result - << LL_ENDL; - return false; - } + U32 uzip_result = LLUZipHelper::unzip_llsd(decomp, stream, data_size); + if (uzip_result != LLUZipHelper::ZR_OK) + { + LL_WARNS(LOG_MESH) << "Mesh decomposition parse error. Not a valid mesh asset! ID: " << mesh_id + << " uzip result: " << uzip_result + << LL_ENDL; + return false; + } + } + catch (std::bad_alloc&) + { + LL_WARNS(LOG_MESH) << "Out of memory for mesh ID " << mesh_id << " of size: " << data_size << LL_ENDL; + return false; + } } { @@ -1977,7 +2005,7 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3 return true; } -bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size) +EMeshProcessingResult LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size) { LLSD physics_shape; @@ -1994,8 +2022,19 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); volume_params.setSculptID(mesh_id, LL_SCULPT_TYPE_MESH); LLPointer<LLVolume> volume = new LLVolume(volume_params,0); - std::string mesh_string((char*) data, data_size); - std::istringstream stream(mesh_string); + + std::istringstream stream; + try + { + std::string mesh_string((char*)data, data_size); + stream.str(mesh_string); + } + catch (std::bad_alloc&) + { + // out of memory, we won't be able to process this mesh + delete d; + return MESH_OUT_OF_MEMORY; + } if (volume->unpackVolumeFaces(stream, data_size)) { @@ -2034,7 +2073,7 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 LLMutexLock lock(mMutex); mDecompositionQ.push_back(d); } - return true; + return MESH_OK; } LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures, @@ -2615,7 +2654,7 @@ void LLMeshUploadThread::doWholeModelUpload() LL_DEBUGS(LOG_MESH) << "POST request issued." << LL_ENDL; mHttpRequest->update(0); - while (! LLApp::isQuitting() && ! finished() && ! isDiscarded()) + while (! LLApp::isExiting() && ! finished() && ! isDiscarded()) { ms_sleep(sleep_time); sleep_time = llmin(250U, sleep_time + sleep_time); @@ -2664,7 +2703,7 @@ void LLMeshUploadThread::requestWholeModelFee() U32 sleep_time(10); mHttpRequest->update(0); - while (! LLApp::isQuitting() && ! finished() && ! isDiscarded()) + while (! LLApp::isExiting() && ! finished() && ! isDiscarded()) { ms_sleep(sleep_time); sleep_time = llmin(250U, sleep_time + sleep_time); @@ -2772,7 +2811,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp if (observer) { - observer->setModelPhysicsFeeErrorStatus(status.toULong(), reason); + observer->setModelPhysicsFeeErrorStatus(status.toULong(), reason, body["error"]); } } else @@ -2805,7 +2844,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp if (observer) { - observer->setModelPhysicsFeeErrorStatus(status.toULong(), reason); + observer->setModelPhysicsFeeErrorStatus(status.toULong(), reason, body["error"]); } } } @@ -2830,12 +2869,12 @@ void LLMeshRepoThread::notifyLoadedMeshes() mMutex->unlock(); break; } - LoadedMesh mesh = mLoadedQ.front(); + LoadedMesh mesh = mLoadedQ.front(); // make sure nothing else owns volume pointer by this point mLoadedQ.pop(); mMutex->unlock(); update_metrics = true; - if (mesh.mVolume && mesh.mVolume->getNumVolumeFaces() > 0) + if (mesh.mVolume->getNumVolumeFaces() > 0) { gMeshRepo.notifyMeshLoaded(mesh.mMeshParams, mesh.mVolume); } @@ -3110,7 +3149,7 @@ common_exit: LLMeshHeaderHandler::~LLMeshHeaderHandler() { - if (!LLApp::isQuitting()) + if (!LLApp::isExiting()) { if (! mProcessed) { @@ -3143,15 +3182,21 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b U8 * data, S32 data_size) { LLUUID mesh_id = mMeshParams.getSculptID(); - bool success = (! MESH_HEADER_PROCESS_FAILED) - && ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong - && gMeshRepo.mThread->headerReceived(mMeshParams, data, data_size); + bool success = (!MESH_HEADER_PROCESS_FAILED) + && ((data != NULL) == (data_size > 0)); // if we have data but no size or have size but no data, something is wrong; llassert(success); + EMeshProcessingResult res = MESH_UNKNOWN; + if (success) + { + res = gMeshRepo.mThread->headerReceived(mMeshParams, data, data_size); + success = (res == MESH_OK); + } if (! success) { // *TODO: Get real reason for parse failure here. Might we want to retry? LL_WARNS(LOG_MESH) << "Unable to parse mesh header. ID: " << mesh_id - << ", Unknown reason. Not retrying." + << ", Size: " << data_size + << ", Reason: " << res << " Not retrying." << LL_ENDL; // Can't get the header so none of the LODs will be available @@ -3174,7 +3219,6 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b header_bytes = (S32)gMeshRepo.mThread->mMeshHeaderSize[mesh_id]; header = iter->second; } - gMeshRepo.mThread->mHeaderMutex->unlock(); if (header_bytes > 0 && !header.has("404") @@ -3195,7 +3239,10 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b lod_bytes = llmax(lod_bytes, header["skin"]["offset"].asInteger() + header["skin"]["size"].asInteger()); lod_bytes = llmax(lod_bytes, header["physics_convex"]["offset"].asInteger() + header["physics_convex"]["size"].asInteger()); - S32 header_bytes = (S32) gMeshRepo.mThread->mMeshHeaderSize[mesh_id]; + // Do not unlock mutex untill we are done with LLSD. + // LLSD is smart and can work like smart pointer, is not thread safe. + gMeshRepo.mThread->mHeaderMutex->unlock(); + S32 bytes = lod_bytes + header_bytes; @@ -3231,6 +3278,8 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b { LL_WARNS(LOG_MESH) << "Trying to cache nonexistent mesh, mesh id: " << mesh_id << LL_ENDL; + gMeshRepo.mThread->mHeaderMutex->unlock(); + // headerReceived() parsed header, but header's data is invalid so none of the LODs will be available LLMutexLock lock(gMeshRepo.mThread->mMutex); for (int i(0); i < 4; ++i) @@ -3243,7 +3292,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b LLMeshLODHandler::~LLMeshLODHandler() { - if (! LLApp::isQuitting()) + if (! LLApp::isExiting()) { if (! mProcessed) { @@ -3431,7 +3480,7 @@ void LLMeshPhysicsShapeHandler::processData(LLCore::BufferArray * /* body */, S3 { if ((!MESH_PHYS_SHAPE_PROCESS_FAILED) && ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong - && gMeshRepo.mThread->physicsShapeReceived(mMeshID, data, data_size)) + && gMeshRepo.mThread->physicsShapeReceived(mMeshID, data, data_size) == MESH_OK) { // good fetch from sim, write to VFS for caching LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE); @@ -3471,6 +3520,11 @@ void LLMeshRepository::init() LLConvexDecomposition::getInstance()->initSystem(); + if (!LLConvexDecomposition::isFunctional()) + { + LL_INFOS(LOG_MESH) << "Using STUB for LLConvexDecomposition" << LL_ENDL; + } + mDecompThread = new LLPhysicsDecomp(); mDecompThread->start(); @@ -3499,7 +3553,7 @@ void LLMeshRepository::shutdown() mUploads[i]->discard() ; //discard the uploading requests. } - mThread->mSignal->signal(); + mThread->mSignal->broadcast(); while (!mThread->isStopped()) { @@ -4095,42 +4149,42 @@ void LLMeshRepository::buildHull(const LLVolumeParams& params, S32 detail) bool LLMeshRepository::hasPhysicsShape(const LLUUID& mesh_id) { - LLSD mesh = mThread->getMeshHeader(mesh_id); - if (mesh.has("physics_mesh") && mesh["physics_mesh"].has("size") && (mesh["physics_mesh"]["size"].asInteger() > 0)) - { - return true; - } - - LLModel::Decomposition* decomp = getDecomposition(mesh_id); - if (decomp && !decomp->mHull.empty()) - { - return true; - } + if (mesh_id.isNull()) + { + return false; + } - return false; -} + if (mThread->hasPhysicsShapeInHeader(mesh_id)) + { + return true; + } -LLSD& LLMeshRepository::getMeshHeader(const LLUUID& mesh_id) -{ - LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH); + LLModel::Decomposition* decomp = getDecomposition(mesh_id); + if (decomp && !decomp->mHull.empty()) + { + return true; + } - return mThread->getMeshHeader(mesh_id); + return false; } -LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id) +bool LLMeshRepoThread::hasPhysicsShapeInHeader(const LLUUID& mesh_id) { - static LLSD dummy_ret; - if (mesh_id.notNull()) - { - LLMutexLock lock(mHeaderMutex); - mesh_header_map::iterator iter = mMeshHeader.find(mesh_id); - if (iter != mMeshHeader.end() && mMeshHeaderSize[mesh_id] > 0) - { - return iter->second; - } - } + LLMutexLock lock(mHeaderMutex); + if (mMeshHeaderSize[mesh_id] > 0) + { + mesh_header_map::iterator iter = mMeshHeader.find(mesh_id); + if (iter != mMeshHeader.end()) + { + LLSD &mesh = iter->second; + if (mesh.has("physics_mesh") && mesh["physics_mesh"].has("size") && (mesh["physics_mesh"]["size"].asInteger() > 0)) + { + return true; + } + } + } - return dummy_ret; + return false; } @@ -4628,7 +4682,8 @@ void LLPhysicsDecomp::shutdown() if (mSignal) { mQuitting = true; - mSignal->signal(); + // There is only one wait(), but just in case 'broadcast' + mSignal->broadcast(); while (!isStopped()) { diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index bba0c9f2cb..81e49cb1d8 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -57,6 +57,8 @@ typedef enum e_mesh_processing_result_enum MESH_NO_DATA = 1, MESH_OUT_OF_MEMORY, MESH_HTTP_REQUEST_FAILED, + MESH_PARSE_FAILURE, + MESH_INVALID, MESH_UNKNOWN } EMeshProcessingResult; @@ -336,12 +338,12 @@ public: bool fetchMeshHeader(const LLVolumeParams& mesh_params, bool can_retry = true); bool fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, bool can_retry = true); - bool headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size); + EMeshProcessingResult headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size); EMeshProcessingResult lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size); bool skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size); bool decompositionReceived(const LLUUID& mesh_id, U8* data, S32 data_size); - bool physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size); - LLSD& getMeshHeader(const LLUUID& mesh_id); + EMeshProcessingResult physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size); + bool hasPhysicsShapeInHeader(const LLUUID& mesh_id); void notifyLoadedMeshes(); S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod); @@ -593,9 +595,6 @@ public: bool meshUploadEnabled(); bool meshRezEnabled(); - - - LLSD& getMeshHeader(const LLUUID& mesh_id); void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position, diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp new file mode 100644 index 0000000000..a9e80ab5da --- /dev/null +++ b/indra/newview/llmodelpreview.cpp @@ -0,0 +1,3570 @@ +/** + * @file llmodelpreview.cpp + * @brief LLModelPreview class implementation + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2020, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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 "llmodelpreview.h" + +#include "llmodelloader.h" +#include "lldaeloader.h" +#include "llfloatermodelpreview.h" + +#include "llagent.h" +#include "llanimationstates.h" +#include "llcallbacklist.h" +#include "lldatapacker.h" +#include "lldrawable.h" +#include "llface.h" +#include "lliconctrl.h" +#include "llmatrix4a.h" +#include "llmeshrepository.h" +#include "llrender.h" +#include "llsdutil_math.h" +#include "llskinningutil.h" +#include "llstring.h" +#include "llsdserialize.h" +#include "lltoolmgr.h" +#include "llui.h" +#include "llvector4a.h" +#include "llviewercamera.h" +#include "llviewercontrol.h" +#include "llviewerobjectlist.h" +#include "llviewernetwork.h" +#include "llviewershadermgr.h" +#include "llviewertexteditor.h" +#include "llviewertexturelist.h" +#include "llvoavatar.h" +#include "pipeline.h" + +// ui controls (from floater) +#include "llbutton.h" +#include "llcombobox.h" +#include "llspinctrl.h" +#include "lltabcontainer.h" +#include "lltextbox.h" + +#include "glod/glod.h" +#include <boost/algorithm/string.hpp> + +bool LLModelPreview::sIgnoreLoadedCallback = false; + +// Extra configurability, to be exposed later in xml (LLModelPreview probably +// should become UI control at some point or get split into preview control) +static const LLColor4 PREVIEW_CANVAS_COL(0.169f, 0.169f, 0.169f, 1.f); +static const LLColor4 PREVIEW_EDGE_COL(0.4f, 0.4f, 0.4f, 1.0); +static const LLColor4 PREVIEW_BASE_COL(1.f, 1.f, 1.f, 1.f); +static const LLColor3 PREVIEW_BRIGHTNESS(0.9f, 0.9f, 0.9f); +static const F32 PREVIEW_EDGE_WIDTH(1.f); +static const LLColor4 PREVIEW_PSYH_EDGE_COL(0.f, 0.25f, 0.5f, 0.25f); +static const LLColor4 PREVIEW_PSYH_FILL_COL(0.f, 0.5f, 1.0f, 0.5f); +static const F32 PREVIEW_PSYH_EDGE_WIDTH(1.f); +static const LLColor4 PREVIEW_DEG_EDGE_COL(1.f, 0.f, 0.f, 1.f); +static const LLColor4 PREVIEW_DEG_FILL_COL(1.f, 0.f, 0.f, 0.5f); +static const F32 PREVIEW_DEG_EDGE_WIDTH(3.f); +static const F32 PREVIEW_DEG_POINT_SIZE(8.f); +static const F32 PREVIEW_ZOOM_LIMIT(10.f); + +const F32 SKIN_WEIGHT_CAMERA_DISTANCE = 16.f; + +BOOL stop_gloderror() +{ + GLuint error = glodGetError(); + + if (error != GLOD_NO_ERROR) + { + LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL; + return TRUE; + } + + return FALSE; +} + +LLViewerFetchedTexture* bindMaterialDiffuseTexture(const LLImportMaterial& material) +{ + LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_PREVIEW); + + if (texture) + { + if (texture->getDiscardLevel() > -1) + { + gGL.getTexUnit(0)->bind(texture, true); + return texture; + } + } + + return NULL; +} + +std::string stripSuffix(std::string name) +{ + if ((name.find("_LOD") != -1) || (name.find("_PHYS") != -1)) + { + return name.substr(0, name.rfind('_')); + } + return name; +} + +std::string getLodSuffix(S32 lod) +{ + std::string suffix; + switch (lod) + { + case LLModel::LOD_IMPOSTOR: suffix = "_LOD0"; break; + case LLModel::LOD_LOW: suffix = "_LOD1"; break; + case LLModel::LOD_MEDIUM: suffix = "_LOD2"; break; + case LLModel::LOD_PHYSICS: suffix = "_PHYS"; break; + case LLModel::LOD_HIGH: break; + } + return suffix; +} + +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++; + } +} + +//----------------------------------------------------------------------------- +// LLModelPreview +//----------------------------------------------------------------------------- + +LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) + : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex() + , mLodsQuery() + , mLodsWithParsingError() + , mPelvisZOffset(0.0f) + , mLegacyRigFlags(U32_MAX) + , mRigValidJointUpload(false) + , mPhysicsSearchLOD(LLModel::LOD_PHYSICS) + , mResetJoints(false) + , mModelNoErrors(true) + , mLastJointUpdate(false) + , mFirstSkinUpdate(true) + , mHasDegenerate(false) + , mImporterDebug(LLCachedControl<bool>(gSavedSettings, "ImporterDebug", 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; + mLookUpLodFiles = 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(); + + createPreviewAvatar(); +} + +LLModelPreview::~LLModelPreview() +{ + // 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) + { + mModelLoader->shutdown(); + } + + if (mPreviewAvatar) + { + mPreviewAvatar->markDead(); + mPreviewAvatar = NULL; + } +} + +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<LLModel*> 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()) + { + // 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); + } + + 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(), + mFMP->childGetValue("lock_scale_if_joint_position").asBoolean(), + TRUE, + FALSE, + instance.mModel->mSubmodelID); + + 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 x_transformed = LLVector3(1, 0, 0) * transformation - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + LLVector3 scale = LLVector3(x_length, y_length, z_length); + + F32 radius = scale.length()*0.5f*debug_scale; + + LLMeshCostData costs; + if (gMeshRepo.getCostData(ret, costs)) + { + streaming_cost += costs.getRadiusBasedStreamingCost(radius); + } + } + } + + F32 scale = mFMP ? mFMP->childGetValue("import_scale").asReal()*2.f : 2.f; + + mDetailsSignal(mPreviewScale[0] * scale, mPreviewScale[1] * scale, mPreviewScale[2] * scale, streaming_cost, physics_cost); + + updateStatusMessages(); + + return (U32)streaming_cost; +} + +void LLModelPreview::rebuildUploadData() +{ + assert_main_thread(); + + mUploadData.clear(); + mTextureSet.clear(); + + //fill uploaddata instance vectors from scene data + + std::string requested_name = mFMP->getChild<LLUICtrl>("description_form")->getValue().asString(); + + LLSpinCtrl* scale_spinner = mFMP->getChild<LLSpinCtrl>("import_scale"); + + F32 scale = scale_spinner->getValue().asReal(); + + LLMatrix4 scale_mat; + scale_mat.initScale(LLVector3(scale, scale, scale)); + + F32 max_scale = 0.f; + + BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching"); + U32 load_state = 0; + + for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) + { //for each transform in scene + LLMatrix4 mat = iter->first; + + // compute position + LLVector3 position = LLVector3(0, 0, 0) * mat; + + // compute scale + LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + + max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); + + mat *= scale_mat; + + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end();) + { //for each instance with said transform applied + LLModelInstance instance = *model_iter++; + + LLModel* base_model = instance.mModel; + + if (base_model && !requested_name.empty()) + { + base_model->mRequestedLabel = requested_name; + } + + for (int i = LLModel::NUM_LODS - 1; i >= LLModel::LOD_IMPOSTOR; i--) + { + LLModel* lod_model = NULL; + if (!legacyMatching) + { + // 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 = getLodSuffix(extensionLOD); + + if (name_to_match.find(toAdd) == -1) + { + name_to_match += toAdd; + } + + FindModel(mScene[i], name_to_match, lod_model, transform); + + if (!lod_model && i != LLModel::LOD_PHYSICS) + { + if (mImporterDebug) + { + std::ostringstream out; + out << "Search of" << name_to_match; + out << " in LOD" << i; + out << " list failed. Searching for alternative among LOD lists."; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + } + + 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 = getLodSuffix(searchLOD); + + if (name_to_match.find(toAdd) == -1) + { + 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 (mImporterDebug) + { + std::ostringstream out; + out << "Attempting to use model index " << idx; + out << " for LOD" << i; + out << " of " << instance.mLabel; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + } + break; + } + } + + // If the model list for the current LOD includes that index... + // + if (mModel[i].size() > idx) + { + // Assign that index from the model list for our LOD as the LOD model for this instance + // + lod_model = mModel[i][idx]; + if (mImporterDebug) + { + std::ostringstream out; + out << "Indexed match of model index " << idx << " at LOD " << i << " to model named " << lod_model->mLabel; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + } + } + else if (mImporterDebug) + { + std::ostringstream out; + out << "List of models does not include index " << idx; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + } + } + + if (lod_model) + { + if (mImporterDebug) + { + std::ostringstream out; + if (i == LLModel::LOD_PHYSICS) + { + out << "Assigning collision for " << instance.mLabel << " to match " << lod_model->mLabel; + } + else + { + out << "Assigning LOD" << i << " for " << instance.mLabel << " to found match " << lod_model->mLabel; + } + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + } + 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 (mImporterDebug) + { + std::ostringstream out; + out << "List of models does not include " << instance.mLabel; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + } + } + } + + LLModel* high_lod_model = instance.mLOD[LLModel::LOD_HIGH]; + if (!high_lod_model) + { + LLFloaterModelPreview::addStringToLog("Model " + instance.mLabel + " has no High Lod (LOD3).", true); + load_state = 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)) + { + LLFloaterModelPreview::addStringToLog("Model " + instance.mLabel + " has mismatching materials between lods." , true); + load_state = 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.01)) + { + // Bind shape matrix is not in standard X-forward orientation. + // Might be good idea to only show this once. It can be spammy. + std::ostringstream out; + out << "non-identity bind shape rot. mat is "; + out << high_lod_model->mSkinInfo.mBindShapeMatrix; + out << " bind_rot "; + out << bind_rot; + LL_WARNS() << out.str() << LL_ENDL; + + LLFloaterModelPreview::addStringToLog(out, getLoadState() != LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION); + load_state = 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 (mImporterDebug) + { + std::ostringstream out; + out << "Model " << mModel[lod][model_ind]->mLabel << " was not used - mismatching lod models."; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, true); + } + load_state = LLModelLoader::ERROR_MATERIALS; + mFMP->childDisable("calculate_btn"); + } + } + } + + // Update state for notifications + if (load_state > 0) + { + // encountered issues + setLoadState(load_state); + } + else if (getLoadState() == LLModelLoader::ERROR_MATERIALS + || getLoadState() == LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION) + { + // This is only valid for these two error types because they are + // only used inside rebuildUploadData() and updateStatusMessages() + // updateStatusMessages() is called after rebuildUploadData() + setLoadState(LLModelLoader::DONE); + } + + F32 max_import_scale = (DEFAULT_MAX_PRIM_SCALE - 0.1f) / max_scale; + + F32 max_axis = llmax(mPreviewScale.mV[0], mPreviewScale.mV[1]); + max_axis = llmax(max_axis, mPreviewScale.mV[2]); + 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); + + scale_spinner->setMaxValue(max_import_scale); + + if (max_import_scale < scale) + { + scale_spinner->setValue(max_import_scale); + } + +} + +void LLModelPreview::saveUploadData(bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position) +{ + if (!mLODFile[LLModel::LOD_HIGH].empty()) + { + std::string filename = mLODFile[LLModel::LOD_HIGH]; + std::string slm_filename; + + if (LLModelLoader::getSLMFilename(filename, slm_filename)) + { + saveUploadData(slm_filename, save_skinweights, save_joint_positions, lock_scale_if_joint_position); + } + } +} + +void LLModelPreview::saveUploadData(const std::string& filename, + bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position) +{ + + std::set<LLPointer<LLModel> > meshes; + std::map<LLModel*, std::string> mesh_binary; + + LLModel::hull empty_hull; + + LLSD data; + + data["version"] = SLM_SUPPORTED_VERSION; + if (!mBaseModel.empty()) + { + data["name"] = mBaseModel[0]->getName(); + } + + S32 mesh_id = 0; + + //build list of unique models and initialize local id + for (U32 i = 0; i < mUploadData.size(); ++i) + { + LLModelInstance& instance = mUploadData[i]; + + if (meshes.find(instance.mModel) == meshes.end()) + { + instance.mModel->mLocalID = mesh_id++; + meshes.insert(instance.mModel); + + std::stringstream str; + LLModel::Decomposition& decomp = + instance.mLOD[LLModel::LOD_PHYSICS].notNull() ? + instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics : + instance.mModel->mPhysics; + + LLModel::writeModel(str, + instance.mLOD[LLModel::LOD_PHYSICS], + instance.mLOD[LLModel::LOD_HIGH], + instance.mLOD[LLModel::LOD_MEDIUM], + instance.mLOD[LLModel::LOD_LOW], + instance.mLOD[LLModel::LOD_IMPOSTOR], + decomp, + save_skinweights, + save_joint_positions, + lock_scale_if_joint_position, + FALSE, TRUE, instance.mModel->mSubmodelID); + + data["mesh"][instance.mModel->mLocalID] = str.str(); + } + + data["instance"][i] = instance.asLLSD(); + } + + llofstream out(filename.c_str(), std::ios_base::out | std::ios_base::binary); + LLSDSerialize::toBinary(data, out); + out.flush(); + out.close(); +} + +void LLModelPreview::clearModel(S32 lod) +{ + if (lod < 0 || lod > LLModel::LOD_PHYSICS) + { + return; + } + + mVertexBuffer[lod].clear(); + mModel[lod].clear(); + 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<std::string> cv_names, attach_names; + av->getSortedJointNames(1, cv_names); + av->getSortedJointNames(2, attach_names); + for (std::vector<std::string>::iterator it = cv_names.begin(); it != cv_names.end(); ++it) + { + joint_map[*it] = *it; + } + for (std::vector<std::string>::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(); + + LLMutexLock lock(this); + + if (lod < LLModel::LOD_IMPOSTOR || lod > LLModel::NUM_LODS - 1) + { + std::ostringstream out; + out << "Invalid level of detail: "; + out << lod; + LL_WARNS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, true); + assert(lod >= LLModel::LOD_IMPOSTOR && lod < LLModel::NUM_LODS); + return; + } + + // This triggers if you bring up the file picker and then hit CANCEL. + // Just use the previous model (if any) and ignore that you brought up + // the file picker. + + if (filename.empty()) + { + if (mBaseModel.empty()) + { + // this is the initial file picking. Close the whole floater + // if we don't have a base model to show for high LOD. + mFMP->closeFloater(false); + } + mLoading = false; + return; + } + + if (mModelLoader) + { + LL_WARNS() << "Incompleted model load operation pending." << LL_ENDL; + return; + } + + mLODFile[lod] = filename; + + if (lod == LLModel::LOD_HIGH) + { + clearGLODGroup(); + } + + std::map<std::string, std::string> 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 + { + // For MAINT-6647, we have set force_disable_slm to true, + // which means this code path will never be taken. Trying to + // re-use SLM files has never worked properly; in particular, + // it tends to force the UI into strange checkbox options + // which cannot be altered. + + //only try to load from slm if viewer is configured to do so and this is the + //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")); + + setPreviewLOD(lod); + + if (getLoadState() >= LLModelLoader::ERROR_PARSING) + { + mFMP->childDisable("ok_btn"); + mFMP->childDisable("calculate_btn"); + } + + if (lod == mPreviewLOD) + { + mFMP->childSetValue("lod_file_" + lod_name[lod], mLODFile[lod]); + } + else if (lod == LLModel::LOD_PHYSICS) + { + mFMP->childSetValue("physics_file", mLODFile[lod]); + } + + mFMP->openFloater(); +} + +void LLModelPreview::setPhysicsFromLOD(S32 lod) +{ + assert_main_thread(); + + if (lod >= 0 && lod <= 3) + { + mPhysicsSearchLOD = lod; + mModel[LLModel::LOD_PHYSICS] = mModel[lod]; + mScene[LLModel::LOD_PHYSICS] = mScene[lod]; + mLODFile[LLModel::LOD_PHYSICS].clear(); + mFMP->childSetValue("physics_file", mLODFile[LLModel::LOD_PHYSICS]); + mVertexBuffer[LLModel::LOD_PHYSICS].clear(); + rebuildUploadData(); + refresh(); + updateStatusMessages(); + } +} + +void LLModelPreview::clearIncompatible(S32 lod) +{ + //Don't discard models if specified model is the physic rep + if (lod == LLModel::LOD_PHYSICS) + { + 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 + if (i != lod) + { + if (countRootModels(mModel[i]) != lod_size) + { + mModel[i].clear(); + mScene[i].clear(); + mVertexBuffer[i].clear(); + + if (i == LLModel::LOD_HIGH) + { + mBaseModel = mModel[lod]; + clearGLODGroup(); + mBaseScene = mScene[lod]; + mVertexBuffer[5].clear(); + } + } + } + } +} + +void LLModelPreview::clearGLODGroup() +{ + if (mGroup) + { + for (std::map<LLPointer<LLModel>, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) + { + glodDeleteObject(iter->second); + stop_gloderror(); + } + mObject.clear(); + + glodDeleteGroup(mGroup); + stop_gloderror(); + mGroup = 0; + } +} + +void LLModelPreview::loadModelCallback(S32 loaded_lod) +{ + assert_main_thread(); + + LLMutexLock lock(this); + if (!mModelLoader) + { + mLoading = false; + return; + } + if (getLoadState() >= LLModelLoader::ERROR_PARSING) + { + mLoading = false; + 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"); + } + + // Copy determinations about rig so UI will reflect them + // + setRigValidForJointPositionUpload(mModelLoader->isRigValidForJointPositionUpload()); + setLegacyRigFlags(mModelLoader->getLegacyRigFlags()); + + mModelLoader->loadTextures(); + + if (loaded_lod == -1) + { //populate all LoDs from model loader scene + mBaseModel.clear(); + mBaseScene.clear(); + + bool skin_weights = false; + bool joint_overrides = false; + bool lock_scale_if_joint_position = false; + + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { //for each LoD + + //clear scene and model info + mScene[lod].clear(); + mModel[lod].clear(); + mVertexBuffer[lod].clear(); + + if (mModelLoader->mScene.begin()->second[0].mLOD[lod].notNull()) + { //if this LoD exists in the loaded scene + + //copy scene to current LoD + mScene[lod] = mModelLoader->mScene; + + //touch up copied scene to look like current LoD + for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) + { + LLModelLoader::model_instance_list& list = iter->second; + + for (LLModelLoader::model_instance_list::iterator list_iter = list.begin(); list_iter != list.end(); ++list_iter) + { + //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; + + if (mModel[lod].size() <= idx) + { //stretch model list to fit model at given index + mModel[lod].resize(idx + 1); + } + + mModel[lod][idx] = list_iter->mModel; + if (!list_iter->mModel->mSkinWeights.empty()) + { + skin_weights = true; + + if (!list_iter->mModel->mSkinInfo.mAlternateBindMatrix.empty()) + { + joint_overrides = true; + } + if (list_iter->mModel->mSkinInfo.mLockScaleIfJointPosition) + { + lock_scale_if_joint_position = true; + } + } + } + } + } + } + + if (mFMP) + { + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*)mFMP; + + if (skin_weights) + { //enable uploading/previewing of skin weights if present in .slm file + fmp->enableViewOption("show_skin_weight"); + mViewOption["show_skin_weight"] = true; + fmp->childSetValue("upload_skin", true); + } + + if (joint_overrides) + { + fmp->enableViewOption("show_joint_overrides"); + mViewOption["show_joint_overrides"] = true; + fmp->enableViewOption("show_joint_positions"); + mViewOption["show_joint_positions"] = true; + fmp->childSetValue("upload_joints", true); + } + else + { + fmp->clearAvatarTab(); + } + + if (lock_scale_if_joint_position) + { + fmp->enableViewOption("lock_scale_if_joint_position"); + mViewOption["lock_scale_if_joint_position"] = true; + fmp->childSetValue("lock_scale_if_joint_position", true); + } + } + + //copy high lod to base scene for LoD generation + mBaseScene = mScene[LLModel::LOD_HIGH]; + mBaseModel = mModel[LLModel::LOD_HIGH]; + + mDirty = true; + resetPreviewTarget(); + } + else + { //only replace given LoD + mModel[loaded_lod] = mModelLoader->mModelList; + mScene[loaded_lod] = mModelLoader->mScene; + mVertexBuffer[loaded_lod].clear(); + + setPreviewLOD(loaded_lod); + + 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 + mGenLOD = true; + } + + mBaseModel = mModel[loaded_lod]; + clearGLODGroup(); + + mBaseScene = mScene[loaded_lod]; + mVertexBuffer[5].clear(); + } + else + { + 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 (mImporterDebug) + { + std::ostringstream out; + out << "High LOD has submodels"; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + } + 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 (mImporterDebug) + { + std::ostringstream out; + out << "Loaded LOD " << loaded_lod << ": correct names" << (name_based ? "" : "NOT ") << "found; submodels " << (has_submodels ? "" : "NOT ") << "found"; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + } + + 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) + { + name += getLodSuffix(loaded_lod); + + if (mImporterDebug) + { + std::ostringstream out; + out << "Loded model name " << mModel[loaded_lod][idx]->mLabel; + out << " for LOD " << loaded_lod; + out << " doesn't match the base model. Renaming to " << name; + LL_WARNS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + } + + mModel[loaded_lod][idx]->mLabel = name; + } + } + } + } + } + } + + clearIncompatible(loaded_lod); + + mDirty = true; + + if (loaded_lod == LLModel::LOD_HIGH) + { + resetPreviewTarget(); + } + } + + mLoading = false; + if (mFMP) + { + if (!mBaseModel.empty()) + { + const std::string& model_name = mBaseModel[0]->getName(); + LLLineEditor* description_form = mFMP->getChild<LLLineEditor>("description_form"); + if (description_form->getText().empty()) + { + description_form->setText(model_name); + } + // Add info to log that loading is complete (purpose: separator between loading and other logs) + LLSD args; + args["MODEL_NAME"] = model_name; // Teoretically shouldn't be empty, but might be better idea to add filename here + LLFloaterModelPreview::addStringToLog("ModelLoaded", args, false, loaded_lod); + } + } + refresh(); + + mModelLoadedSignal(); + + mModelLoader = NULL; +} + +void LLModelPreview::resetPreviewTarget() +{ + if (mModelLoader) + { + mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; + mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; + } + + setPreviewTarget(mPreviewScale.magVec()*10.f); +} + +void LLModelPreview::generateNormals() +{ + assert_main_thread(); + + S32 which_lod = mPreviewLOD; + + if (which_lod > 4 || which_lod < 0 || + mModel[which_lod].empty()) + { + return; + } + + F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal(); + + mRequestedCreaseAngle[which_lod] = angle_cutoff; + + angle_cutoff *= DEG_TO_RAD; + + if (which_lod == 3 && !mBaseModel.empty()) + { + 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) + { + (*it)->generateNormals(angle_cutoff); + } + + mVertexBuffer[5].clear(); + } + + 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(); +} + +void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit) +{ + // Allow LoD from -1 to LLModel::LOD_PHYSICS + if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1) + { + std::ostringstream out; + out << "Invalid level of detail: " << which_lod; + LL_WARNS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + assert(which_lod >= -1 && which_lod < LLModel::NUM_LODS); + return; + } + + if (mBaseModel.empty()) + { + return; + } + + LLVertexBuffer::unbind(); + + bool no_ff = LLGLSLShader::sNoFixedFunction; + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + LLGLSLShader::sNoFixedFunction = false; + + if (shader) + { + shader->unbind(); + } + + stop_gloderror(); + static U32 cur_name = 1; + + S32 limit = -1; + + U32 triangle_count = 0; + + 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) + { + for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance) + { + 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; + + U32 lod_mode = 0; + + F32 lod_error_threshold = 0; + + // The LoD should be in range from Lowest to High + if (which_lod > -1 && which_lod < NUM_LOD) + { + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[which_lod]); + if (iface) + { + lod_mode = iface->getFirstSelectedIndex(); + } + + lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[which_lod]).asReal(); + } + + if (which_lod != -1) + { + mRequestedLoDMode[which_lod] = lod_mode; + } + + if (lod_mode == 0) + { + lod_mode = GLOD_TRIANGLE_BUDGET; + + // The LoD should be in range from Lowest to High + 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 + { + lod_mode = GLOD_ERROR_THRESHOLD; + } + + bool object_dirty = false; + + if (mGroup == 0) + { + object_dirty = true; + mGroup = cur_name++; + glodNewGroup(mGroup); + } + + if (object_dirty) + { + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { //build GLOD objects for each model in base model list + LLModel* mdl = *iter; + + if (mObject[mdl] != 0) + { + glodDeleteObject(mObject[mdl]); + } + + mObject[mdl] = cur_name++; + + glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE); + stop_gloderror(); + + if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) + { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation + mVertexBuffer[5].clear(); + } + + if (mVertexBuffer[5].empty()) + { + genBuffers(5, false); + } + + U32 tri_count = 0; + for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) + { + LLVertexBuffer* buff = mVertexBuffer[5][mdl][i]; + buff->setBuffer(type_mask & buff->getTypeMask()); + + U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); + if (num_indices > 2) + { + glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, (U8*)mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); + } + tri_count += num_indices / 3; + stop_gloderror(); + } + + glodBuildObject(mObject[mdl]); + stop_gloderror(); + } + } + + + S32 start = LLModel::LOD_HIGH; + S32 end = 0; + + if (which_lod != -1) + { + start = end = which_lod; + } + + mMaxTriangleLimit = base_triangle_count; + + for (S32 lod = start; lod >= end; --lod) + { + if (which_lod == -1) + { + if (lod < start) + { + triangle_count /= decimation; + } + } + else + { + if (enforce_tri_limit) + { + triangle_count = limit; + } + else + { + for (S32 j = LLModel::LOD_HIGH; j>which_lod; --j) + { + triangle_count /= decimation; + } + } + } + + mModel[lod].clear(); + mModel[lod].resize(mBaseModel.size()); + mVertexBuffer[lod].clear(); + + U32 actual_tris = 0; + U32 actual_verts = 0; + U32 submeshes = 0; + + mRequestedTriangleCount[lod] = (S32)((F32)triangle_count / triangle_ratio); + mRequestedErrorThreshold[lod] = lod_error_threshold; + + glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); + stop_gloderror(); + + glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); + stop_gloderror(); + + glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); + stop_gloderror(); + + if (lod_mode != GLOD_TRIANGLE_BUDGET) + { + glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, 0); + } + else + { + //SH-632: always add 1 to desired amount to avoid decimating below desired amount + glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count + 1); + } + + stop_gloderror(); + glodAdaptGroup(mGroup); + stop_gloderror(); + + for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) + { + LLModel* base = mBaseModel[mdl_idx]; + + GLint patch_count = 0; + glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); + stop_gloderror(); + + LLVolumeParams volume_params; + 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 + getLodSuffix(lod); + + 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(); + + GLint* names = new GLint[patch_count]; + glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); + stop_gloderror(); + + mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); + + LLModel* target_model = mModel[lod][mdl_idx]; + + for (GLint i = 0; i < patch_count; ++i) + { + type_mask = mVertexBuffer[5][base][i]->getTypeMask(); + + LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0); + + if (sizes[i * 2 + 1] > 0 && sizes[i * 2] > 0) + { + if (!buff->allocateBuffer(sizes[i * 2 + 1], sizes[i * 2], true)) + { + // Todo: find a way to stop preview in this case instead of crashing + LL_ERRS() << "Failed buffer allocation during preview LOD generation." + << " Vertices: " << sizes[i * 2 + 1] + << " Indices: " << sizes[i * 2] << LL_ENDL; + } + buff->setBuffer(type_mask); + glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, (U8*)buff->getIndicesPointer()); + stop_gloderror(); + } + else + { + // This face was eliminated or we failed to allocate buffer, + // attempt to create a dummy triangle (one vertex, 3 indices, all 0) + buff->allocateBuffer(1, 3, true); + memset((U8*)buff->getMappedData(), 0, buff->getSize()); + memset((U8*)buff->getIndicesPointer(), 0, buff->getIndicesSize()); + } + + buff->validateRange(0, buff->getNumVerts() - 1, buff->getNumIndices(), 0); + + LLStrider<LLVector3> pos; + LLStrider<LLVector3> norm; + LLStrider<LLVector2> tc; + LLStrider<U16> index; + + buff->getVertexStrider(pos); + if (type_mask & LLVertexBuffer::MAP_NORMAL) + { + buff->getNormalStrider(norm); + } + if (type_mask & LLVertexBuffer::MAP_TEXCOORD0) + { + buff->getTexCoord0Strider(tc); + } + + buff->getIndexStrider(index); + + target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); + actual_tris += buff->getNumIndices() / 3; + actual_verts += buff->getNumVerts(); + ++submeshes; + + if (!validate_face(target_model->getVolumeFace(names[i]))) + { + LL_ERRS() << "Invalid face generated during LOD generation." << LL_ENDL; + } + } + + //blind copy skin weights and just take closest skin weight to point on + //decimated mesh for now (auto-generating LODs with skin weights is still a bit + //of an open problem). + target_model->mPosition = base->mPosition; + target_model->mSkinWeights = base->mSkinWeights; + target_model->mSkinInfo = base->mSkinInfo; + //copy material list + target_model->mMaterialList = base->mMaterialList; + + if (!validate_model(target_model)) + { + LL_ERRS() << "Invalid model generated when creating LODs" << LL_ENDL; + } + + delete[] sizes; + delete[] names; + } + + //rebuild scene based on mBaseScene + mScene[lod].clear(); + mScene[lod] = mBaseScene; + + for (U32 i = 0; i < mBaseModel.size(); ++i) + { + LLModel* mdl = mBaseModel[i]; + LLModel* target = mModel[lod][i]; + if (target) + { + for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) + { + for (U32 j = 0; j < iter->second.size(); ++j) + { + if (iter->second[j].mModel == mdl) + { + iter->second[j].mModel = target; + } + } + } + } + } + } + + mResourceCost = calcResourceCost(); + + LLVertexBuffer::unbind(); + LLGLSLShader::sNoFixedFunction = no_ff; + if (shader) + { + shader->bind(); + } +} + +void LLModelPreview::updateStatusMessages() +{ + // bit mask values for physics errors. used to prevent overwrite of single line status + // TODO: use this to provied multiline status + enum PhysicsError + { + NONE = 0, + NOHAVOK = 1, + DEGENERATE = 2, + TOOMANYHULLS = 4, + TOOMANYVERTSINHULL = 8 + }; + + assert_main_thread(); + + U32 has_physics_error{ PhysicsError::NONE }; // physics error bitmap + //triangle/vertex/submesh count for each mesh asset for each lod + std::vector<S32> tris[LLModel::NUM_LODS]; + std::vector<S32> verts[LLModel::NUM_LODS]; + std::vector<S32> submeshes[LLModel::NUM_LODS]; + + //total triangle/vertex/submesh count for each lod + S32 total_tris[LLModel::NUM_LODS]; + S32 total_verts[LLModel::NUM_LODS]; + S32 total_submeshes[LLModel::NUM_LODS]; + + 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) + { + 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"); + } + else + { + //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; + } + + std::string instance_name = instance.mLabel; + + if (mImporterDebug) + { + // 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. + // + std::ostringstream out; + out << "Instance " << lod_model->mLabel << " LOD " << i << " Verts: " << cur_verts; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + + out.str(""); + out << "Instance " << lod_model->mLabel << " LOD " << i << " Tris: " << cur_tris; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + + out.str(""); + out << "Instance " << lod_model->mLabel << " LOD " << i << " Faces: " << cur_submeshes; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + + out.str(""); + LLModel::material_list::iterator mat_iter = lod_model->mMaterialList.begin(); + while (mat_iter != lod_model->mMaterialList.end()) + { + out << "Instance " << lod_model->mLabel << " LOD " << i << " Material " << *(mat_iter); + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + out.str(""); + 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) + { + mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; + } + + mHasDegenerate = false; + {//check for degenerate triangles in physics mesh + U32 lod = LLModel::LOD_PHYSICS; + const LLVector4a scale(0.5f); + for (U32 i = 0; i < mModel[lod].size() && !mHasDegenerate; ++i) + { //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 && !mHasDegenerate; ++j) + { //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) && !mHasDegenerate;) + { + U16 index_a = face.mIndices[k + 0]; + U16 index_b = face.mIndices[k + 1]; + U16 index_c = face.mIndices[k + 2]; + + if (index_c == 0 && index_b == 0 && index_a == 0) // test in reverse as 3rd index is less likely to be 0 in a normal case + { + LL_DEBUGS("MeshValidation") << "Empty placeholder triangle (3 identical index 0 verts) ignored" << LL_ENDL; + } + else + { + 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)) + { + mHasDegenerate = true; + } + } + k += 3; + } + } + } + } + } + + // flag degenerates here rather than deferring to a MAV error later + mFMP->childSetVisible("physics_status_message_text", mHasDegenerate); //display or clear + auto degenerateIcon = mFMP->getChild<LLIconCtrl>("physics_status_message_icon"); + degenerateIcon->setVisible(mHasDegenerate); + if (mHasDegenerate) + { + has_physics_error |= PhysicsError::DEGENERATE; + mFMP->childSetValue("physics_status_message_text", mFMP->getString("phys_status_degenerate_triangles")); + LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Error"); + degenerateIcon->setImage(img); + } + + 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]; + + mModelNoErrors = true; + + 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; + + std::string message = "mesh_status_good"; + + if (total_tris[lod] > 0) + { + mFMP->childSetValue(lod_triangles_name[lod], llformat("%d", total_tris[lod])); + mFMP->childSetValue(lod_vertices_name[lod], llformat("%d", total_verts[lod])); + } + else + { + if (lod == lod_high) + { + upload_status[lod] = 2; + message = "mesh_status_missing_lod"; + } + else + { + for (S32 i = lod - 1; i >= 0; --i) + { + if (total_tris[i] > 0) + { + upload_status[lod] = 2; + message = "mesh_status_missing_lod"; + } + } + } + + mFMP->childSetValue(lod_triangles_name[lod], mesh_status_na); + mFMP->childSetValue(lod_vertices_name[lod], mesh_status_na); + } + + if (lod != lod_high) + { + if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) + { //number of submeshes is different + 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"; + upload_status[lod] = 2; + } + else if (!verts[lod].empty()) + { + S32 sum_verts_higher_lod = 0; + S32 sum_verts_this_lod = 0; + for (U32 i = 0; i < verts[lod].size(); ++i) + { + sum_verts_higher_lod += ((i < verts[lod + 1].size()) ? verts[lod + 1][i] : 0); + sum_verts_this_lod += verts[lod][i]; + } + + if ((sum_verts_higher_lod > 0) && + (sum_verts_this_lod > sum_verts_higher_lod)) + { + //too many vertices in this lod + message = "mesh_status_too_many_vertices"; + upload_status[lod] = 1; + } + } + } + + LLIconCtrl* icon = mFMP->getChild<LLIconCtrl>(lod_icon_name[lod]); + LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]); + icon->setVisible(true); + icon->setImage(img); + + if (upload_status[lod] >= 2) + { + mModelNoErrors = false; + } + + if (lod == mPreviewLOD) + { + mFMP->childSetValue("lod_status_message_text", mFMP->getString(message)); + icon = mFMP->getChild<LLIconCtrl>("lod_status_message_icon"); + icon->setImage(img); + } + + updateLodControls(lod); + } + + + //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]; + + if (mdl) + { + for (U32 j = 0; j < mdl->mPhysics.mHull.size(); ++j) + { + if (mdl->mPhysics.mHull[j].size() > 256) + { + physExceededVertexLimit = TRUE; + LL_INFOS() << "Physical model " << mdl->mLabel << " exceeds vertex per hull limitations." << LL_ENDL; + break; + } + } + } + } + + if (physExceededVertexLimit) + { + has_physics_error |= PhysicsError::TOOMANYVERTSINHULL; + } + + if (!(has_physics_error & PhysicsError::DEGENERATE)){ // only update this field (incluides clearing it) if it is not already in use. + mFMP->childSetVisible("physics_status_message_text", physExceededVertexLimit); + LLIconCtrl* physStatusIcon = mFMP->getChild<LLIconCtrl>("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); + } + } + + if (getLoadState() >= LLModelLoader::ERROR_PARSING) + { + mModelNoErrors = false; + LL_INFOS() << "Loader returned errors, model can't be uploaded" << LL_ENDL; + } + + bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean(); + bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean(); + + if (uploadingSkin) + { + if (uploadingJointPositions && !isRigValidForJointPositionUpload()) + { + mModelNoErrors = false; + LL_INFOS() << "Invalid rig, there might be issues with uploading Joint positions" << LL_ENDL; + } + } + + if (mModelNoErrors && mModelLoader) + { + if (!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean()) + { + // Some textures are still loading, prevent upload until they are done + mModelNoErrors = false; + } + } + + if (!mModelNoErrors || mHasDegenerate) + { + mFMP->childDisable("ok_btn"); + mFMP->childDisable("calculate_btn"); + } + else + { + mFMP->childEnable("ok_btn"); + mFMP->childEnable("calculate_btn"); + } + + if (mModelNoErrors && mLodsWithParsingError.empty()) + { + mFMP->childEnable("calculate_btn"); + } + else + { + mFMP->childDisable("calculate_btn"); + } + + //add up physics triangles etc + S32 phys_tris = 0; + S32 phys_hulls = 0; + S32 phys_points = 0; + + //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) + { + LLModel* model = instance->mModel; + if (model) + { + 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; + } + } + } + } + } + + if (phys_tris > 0) + { + mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris)); + } + else + { + mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na); + } + + if (phys_hulls > 0) + { + mFMP->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls)); + mFMP->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points)); + } + else + { + mFMP->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na); + mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); + } + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (fmp) + { + if (phys_tris > 0 || phys_hulls > 0) + { + if (!fmp->isViewOptionEnabled("show_physics")) + { + fmp->enableViewOption("show_physics"); + mViewOption["show_physics"] = true; + fmp->childSetValue("show_physics", true); + } + } + else + { + fmp->disableViewOption("show_physics"); + mViewOption["show_physics"] = false; + fmp->childSetValue("show_physics", false); + + } + + //bool use_hull = fmp->childGetValue("physics_use_hull").asBoolean(); + + //fmp->childSetEnabled("physics_optimize", !use_hull); + + bool enable = (phys_tris > 0 || phys_hulls > 0) && fmp->mCurRequest.empty(); + //enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean(); + + //enable/disable "analysis" UI + LLPanel* panel = fmp->getChild<LLPanel>("physics analysis"); + LLView* child = panel->getFirstChild(); + while (child) + { + child->setEnabled(enable); + child = panel->findNextSibling(child); + } + + enable = phys_hulls > 0 && fmp->mCurRequest.empty(); + //enable/disable "simplification" UI + panel = fmp->getChild<LLPanel>("physics simplification"); + child = panel->getFirstChild(); + while (child) + { + child->setEnabled(enable); + child = panel->findNextSibling(child); + } + + if (fmp->mCurRequest.empty()) + { + fmp->childSetVisible("Simplify", true); + fmp->childSetVisible("simplify_cancel", false); + fmp->childSetVisible("Decompose", true); + fmp->childSetVisible("decompose_cancel", false); + + if (phys_hulls > 0) + { + fmp->childEnable("Simplify"); + } + + if (phys_tris || phys_hulls > 0) + { + fmp->childEnable("Decompose"); + } + } + else + { + fmp->childEnable("simplify_cancel"); + fmp->childEnable("decompose_cancel"); + } + } + + + LLCtrlSelectionInterface* iface = fmp->childGetSelectionInterface("physics_lod_combo"); + S32 which_mode = 0; + S32 file_mode = 1; + if (iface) + { + which_mode = iface->getFirstSelectedIndex(); + file_mode = iface->getItemCount() - 1; + } + + if (which_mode == file_mode) + { + mFMP->childEnable("physics_file"); + mFMP->childEnable("physics_browse"); + } + else + { + mFMP->childDisable("physics_file"); + mFMP->childDisable("physics_browse"); + } + + LLSpinCtrl* crease = mFMP->getChild<LLSpinCtrl>("crease_angle"); + + if (mRequestedCreaseAngle[mPreviewLOD] == -1.f) + { + mFMP->childSetColor("crease_label", LLColor4::grey); + crease->forceSetValue(75.f); + } + else + { + mFMP->childSetColor("crease_label", LLColor4::white); + crease->forceSetValue(mRequestedCreaseAngle[mPreviewLOD]); + } + + mModelUpdatedSignal(true); + +} + +void LLModelPreview::updateLodControls(S32 lod) +{ + if (lod < LLModel::LOD_IMPOSTOR || lod > LLModel::LOD_HIGH) + { + std::ostringstream out; + out << "Invalid level of detail: " << lod; + LL_WARNS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + assert(lod >= LLModel::LOD_IMPOSTOR && lod <= LLModel::LOD_HIGH); + return; + } + + const char* lod_controls[] = + { + "lod_mode_", + "lod_triangle_limit_", + "lod_error_threshold_" + }; + const U32 num_lod_controls = sizeof(lod_controls) / sizeof(char*); + + const char* file_controls[] = + { + "lod_browse_", + "lod_file_", + }; + const U32 num_file_controls = sizeof(file_controls) / sizeof(char*); + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (!fmp) return; + + LLComboBox* lod_combo = mFMP->findChild<LLComboBox>("lod_source_" + lod_name[lod]); + if (!lod_combo) return; + + S32 lod_mode = lod_combo->getCurrentIndex(); + if (lod_mode == LOD_FROM_FILE) // LoD from file + { + fmp->mLODMode[lod] = 0; + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childSetVisible(file_controls[i] + lod_name[lod], true); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childSetVisible(lod_controls[i] + lod_name[lod], false); + } + } + else if (lod_mode == USE_LOD_ABOVE) // use LoD above + { + fmp->mLODMode[lod] = 2; + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childSetVisible(file_controls[i] + lod_name[lod], false); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childSetVisible(lod_controls[i] + lod_name[lod], false); + } + + if (lod < LLModel::LOD_HIGH) + { + mModel[lod] = mModel[lod + 1]; + mScene[lod] = mScene[lod + 1]; + mVertexBuffer[lod].clear(); + + // Also update lower LoD + if (lod > LLModel::LOD_IMPOSTOR) + { + updateLodControls(lod - 1); + } + } + } + else // auto generate, the default case for all LoDs except High + { + fmp->mLODMode[lod] = 1; + + //don't actually regenerate lod when refreshing UI + mLODFrozen = true; + + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->getChildView(file_controls[i] + lod_name[lod])->setVisible(false); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->getChildView(lod_controls[i] + lod_name[lod])->setVisible(true); + } + + + LLSpinCtrl* threshold = mFMP->getChild<LLSpinCtrl>("lod_error_threshold_" + lod_name[lod]); + LLSpinCtrl* limit = mFMP->getChild<LLSpinCtrl>("lod_triangle_limit_" + lod_name[lod]); + + limit->setMaxValue(mMaxTriangleLimit); + limit->forceSetValue(mRequestedTriangleCount[lod]); + + threshold->forceSetValue(mRequestedErrorThreshold[lod]); + + mFMP->getChild<LLComboBox>("lod_mode_" + lod_name[lod])->selectNthItem(mRequestedLoDMode[lod]); + + if (mRequestedLoDMode[lod] == 0) + { + limit->setVisible(true); + threshold->setVisible(false); + + limit->setMaxValue(mMaxTriangleLimit); + limit->setIncrement(mMaxTriangleLimit / 32); + } + else + { + limit->setVisible(false); + threshold->setVisible(true); + } + + mLODFrozen = false; + } +} + +void LLModelPreview::setPreviewTarget(F32 distance) +{ + mCameraDistance = distance; + mCameraZoom = 1.f; + mCameraPitch = 0.f; + mCameraYaw = 0.f; + mCameraOffset.clearVec(); +} + +void LLModelPreview::clearBuffers() +{ + for (U32 i = 0; i < 6; i++) + { + mVertexBuffer[i].clear(); + } +} + +void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) +{ + U32 tri_count = 0; + U32 vertex_count = 0; + U32 mesh_count = 0; + + + LLModelLoader::model_list* model = NULL; + + if (lod < 0 || lod > 4) + { + model = &mBaseModel; + lod = 5; + } + else + { + model = &(mModel[lod]); + } + + if (!mVertexBuffer[lod].empty()) + { + mVertexBuffer[lod].clear(); + } + + mVertexBuffer[lod].clear(); + + LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); + + for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) + { + LLModel* mdl = *iter; + if (!mdl) + { + continue; + } + + LLModel* base_mdl = *base_iter; + base_iter++; + + S32 num_faces = mdl->getNumVolumeFaces(); + for (S32 i = 0; i < num_faces; ++i) + { + const LLVolumeFace &vf = mdl->getVolumeFace(i); + U32 num_vertices = vf.mNumVertices; + U32 num_indices = vf.mNumIndices; + + if (!num_vertices || !num_indices) + { + continue; + } + + LLVertexBuffer* vb = NULL; + + bool skinned = include_skin_weights && !mdl->mSkinWeights.empty(); + + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + if (skinned) + { + mask |= LLVertexBuffer::MAP_WEIGHT4; + } + + vb = new LLVertexBuffer(mask, 0); + + if (!vb->allocateBuffer(num_vertices, num_indices, TRUE)) + { + // We are likely to crash due this failure, if this happens, find a way to gracefully stop preview + std::ostringstream out; + out << "Failed to allocate Vertex Buffer for model preview "; + out << num_vertices << " vertices and "; + out << num_indices << " indices"; + LL_WARNS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, true); + } + + LLStrider<LLVector3> vertex_strider; + LLStrider<LLVector3> normal_strider; + LLStrider<LLVector2> tc_strider; + LLStrider<U16> index_strider; + LLStrider<LLVector4> weights_strider; + + vb->getVertexStrider(vertex_strider); + vb->getIndexStrider(index_strider); + + if (skinned) + { + vb->getWeight4Strider(weights_strider); + } + + LLVector4a::memcpyNonAliased16((F32*)vertex_strider.get(), (F32*)vf.mPositions, num_vertices * 4 * sizeof(F32)); + + if (vf.mTexCoords) + { + vb->getTexCoord0Strider(tc_strider); + S32 tex_size = (num_vertices * 2 * sizeof(F32) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)tc_strider.get(), (F32*)vf.mTexCoords, tex_size); + } + + if (vf.mNormals) + { + vb->getNormalStrider(normal_strider); + LLVector4a::memcpyNonAliased16((F32*)normal_strider.get(), (F32*)vf.mNormals, num_vertices * 4 * sizeof(F32)); + } + + if (skinned) + { + for (U32 i = 0; i < num_vertices; i++) + { + //find closest weight to vf.mVertices[i].mPosition + LLVector3 pos(vf.mPositions[i].getF32ptr()); + + const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); + llassert(weight_list.size()>0 && weight_list.size() <= 4); // LLModel::loadModel() should guarantee this + + LLVector4 w(0, 0, 0, 0); + + for (U32 i = 0; i < weight_list.size(); ++i) + { + 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; + } + } + + // build indices + for (U32 i = 0; i < num_indices; i++) + { + *(index_strider++) = vf.mIndices[i]; + } + + mVertexBuffer[lod][mdl].push_back(vb); + + vertex_count += num_vertices; + tri_count += num_indices / 3; + ++mesh_count; + + } + } +} + +void LLModelPreview::update() +{ + 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(); + } +} + +//----------------------------------------------------------------------------- +// createPreviewAvatar +//----------------------------------------------------------------------------- +void LLModelPreview::createPreviewAvatar(void) +{ + mPreviewAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR); + if (mPreviewAvatar) + { + mPreviewAvatar->createDrawable(&gPipeline); + mPreviewAvatar->mSpecialRenderMode = 1; + mPreviewAvatar->startMotion(ANIM_AGENT_STAND); + mPreviewAvatar->hideSkirt(); + } + else + { + LL_INFOS() << "Failed to create preview avatar for upload model window" << LL_ENDL; + } +} + +//static +U32 LLModelPreview::countRootModels(LLModelLoader::model_list models) +{ + U32 root_models = 0; + model_list::iterator model_iter = models.begin(); + while (model_iter != models.end()) + { + LLModel* mdl = *model_iter; + if (mdl && mdl->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) + { + // Load loader's warnings into floater's log tab + const LLSD out = pPreview->mModelLoader->logOut(); + LLSD::array_const_iterator iter_out = out.beginArray(); + LLSD::array_const_iterator end_out = out.endArray(); + for (; iter_out != end_out; ++iter_out) + { + if (iter_out->has("Message")) + { + LLFloaterModelPreview::addStringToLog(iter_out->get("Message"), *iter_out, true, pPreview->mModelLoader->mLod); + } + } + pPreview->mModelLoader->clearLog(); + pPreview->loadModelCallback(lod); // removes mModelLoader in some cases + if (pPreview->mLookUpLodFiles && (lod != LLModel::LOD_HIGH)) + { + pPreview->lookupLODModelFiles(lod); + } + } + +} + +void LLModelPreview::lookupLODModelFiles(S32 lod) +{ + if (lod == LLModel::LOD_PHYSICS) + { + mLookUpLodFiles = false; + return; + } + S32 next_lod = (lod - 1 >= LLModel::LOD_IMPOSTOR) ? lod - 1 : LLModel::LOD_PHYSICS; + + std::string lod_filename = mLODFile[LLModel::LOD_HIGH]; + std::string ext = ".dae"; + std::string::size_type i = lod_filename.rfind(ext); + if (i != std::string::npos) + { + lod_filename.replace(i, lod_filename.size() - ext.size(), getLodSuffix(next_lod) + ext); + } + if (gDirUtilp->fileExists(lod_filename)) + { + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (fmp) + { + fmp->setCtrlLoadFromFile(next_lod); + } + loadModel(lod_filename, next_lod); + } + else + { + lookupLODModelFiles(next_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://" + LLURI::unescape(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) +{ + U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0); + + buff->allocateBuffer(1, 3, true); + memset((U8*)buff->getMappedData(), 0, buff->getSize()); + memset((U8*)buff->getIndicesPointer(), 0, buff->getIndicesSize()); + + buff->validateRange(0, buff->getNumVerts() - 1, buff->getNumIndices(), 0); + + LLStrider<LLVector3> pos; + LLStrider<LLVector3> norm; + LLStrider<LLVector2> tc; + LLStrider<U16> index; + + buff->getVertexStrider(pos); + + if (type_mask & LLVertexBuffer::MAP_NORMAL) + { + buff->getNormalStrider(norm); + } + if (type_mask & LLVertexBuffer::MAP_TEXCOORD0) + { + buff->getTexCoord0Strider(tc); + } + + buff->getIndexStrider(index); + + //resize face array + int faceCnt = pTarget->getNumVolumeFaces(); + pTarget->setNumVolumeFaces(faceCnt + 1); + pTarget->setVolumeFaceData(faceCnt + 1, pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); + +} + +//----------------------------------------------------------------------------- +// render() +//----------------------------------------------------------------------------- +// Todo: we shouldn't be setting all those UI elements on render. +// Note: Render happens each frame with skinned avatars +BOOL LLModelPreview::render() +{ + assert_main_thread(); + + LLMutexLock lock(this); + mNeedsUpdate = FALSE; + + bool use_shaders = LLGLSLShader::sNoFixedFunction; + + bool edges = mViewOption["show_edges"]; + bool joint_overrides = mViewOption["show_joint_overrides"]; + bool joint_positions = mViewOption["show_joint_positions"]; + bool skin_weight = mViewOption["show_skin_weight"]; + bool textures = mViewOption["show_textures"]; + bool physics = mViewOption["show_physics"]; + + S32 width = getWidth(); + S32 height = getHeight(); + + LLGLSUIDefault def; // GL_BLEND, GL_ALPHA_TEST, GL_CULL_FACE, depth test + LLGLDisable no_blend(GL_BLEND); + LLGLEnable cull(GL_CULL_FACE); + LLGLDepthTest depth(GL_FALSE); // SL-12781 disable z-buffer to render background color + LLGLDisable fog(GL_FOG); + + { + if (use_shaders) + { + gUIProgram.bind(); + } + //clear background to grey + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.ortho(0.0f, width, 0.0f, height, -1.0f, 1.0f); + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadIdentity(); + + gGL.color4fv(PREVIEW_CANVAS_COL.mV); + gl_rect_2d_simple(width, height); + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + if (use_shaders) + { + gUIProgram.unbind(); + } + } + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + + bool has_skin_weights = false; + bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); + bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); + + if (upload_joints != mLastJointUpdate) + { + mLastJointUpdate = upload_joints; + if (fmp) + { + fmp->clearAvatarTab(); + } + } + + 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) + { + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + model->mPelvisOffset = mPelvisZOffset; + if (!model->mSkinWeights.empty()) + { + has_skin_weights = true; + } + } + } + + if (has_skin_weights && lodsReady()) + { //model has skin weights, enable view options for skin weights and joint positions + U32 flags = getLegacyRigFlags(); + if (fmp) + { + if (flags == LEGACY_RIG_OK) + { + if (mFirstSkinUpdate) + { + // auto enable weight upload if weights are present + // (note: all these UI updates need to be somewhere that is not render) + mViewOption["show_skin_weight"] = true; + skin_weight = true; + fmp->childSetValue("upload_skin", true); + mFirstSkinUpdate = false; + } + + fmp->enableViewOption("show_skin_weight"); + fmp->setViewOptionEnabled("show_joint_overrides", skin_weight); + fmp->setViewOptionEnabled("show_joint_positions", skin_weight); + mFMP->childEnable("upload_skin"); + mFMP->childSetValue("show_skin_weight", skin_weight); + + } + else if ((flags & LEGACY_RIG_FLAG_TOO_MANY_JOINTS) > 0) + { + mFMP->childSetVisible("skin_too_many_joints", true); + } + else if ((flags & LEGACY_RIG_FLAG_UNKNOWN_JOINT) > 0) + { + mFMP->childSetVisible("skin_unknown_joint", true); + } + } + } + else + { + mFMP->childDisable("upload_skin"); + if (fmp) + { + mViewOption["show_skin_weight"] = false; + fmp->disableViewOption("show_skin_weight"); + fmp->disableViewOption("show_joint_overrides"); + fmp->disableViewOption("show_joint_positions"); + + skin_weight = false; + mFMP->childSetValue("show_skin_weight", false); + fmp->setViewOptionEnabled("show_skin_weight", skin_weight); + } + } + + if (upload_skin && !has_skin_weights) + { //can't upload skin weights if model has no skin weights + mFMP->childSetValue("upload_skin", false); + upload_skin = false; + } + + if (!upload_skin && upload_joints) + { //can't upload joints if not uploading skin weights + mFMP->childSetValue("upload_joints", false); + upload_joints = false; + } + + if (fmp) + { + if (upload_skin) + { + // will populate list of joints + fmp->updateAvatarTab(upload_joints); + } + else + { + fmp->clearAvatarTab(); + } + } + + if (upload_skin && upload_joints) + { + mFMP->childEnable("lock_scale_if_joint_position"); + } + else + { + mFMP->childDisable("lock_scale_if_joint_position"); + mFMP->childSetValue("lock_scale_if_joint_position", false); + } + + //Only enable joint offsets if it passed the earlier critiquing + if (isRigValidForJointPositionUpload()) + { + mFMP->childSetEnabled("upload_joints", upload_skin); + } + + F32 explode = mFMP->childGetValue("physics_explode").asReal(); + + LLGLDepthTest gls_depth(GL_TRUE); // SL-12781 re-enable z-buffer for 3D model preview + + LLRect preview_rect; + + preview_rect = mFMP->getChildView("preview_panel")->getRect(); + + F32 aspect = (F32)preview_rect.getWidth() / preview_rect.getHeight(); + + LLViewerCamera::getInstance()->setAspect(aspect); + + LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); + + LLVector3 offset = mCameraOffset; + LLVector3 target_pos = mPreviewTarget + offset; + + F32 z_near = 0.001f; + F32 z_far = mCameraDistance*10.0f + mPreviewScale.magVec() + mCameraOffset.magVec(); + + if (skin_weight) + { + target_pos = getPreviewAvatar()->getPositionAgent() + offset; + z_near = 0.01f; + z_far = 1024.f; + + //render avatar previews every frame + refresh(); + } + + if (use_shaders) + { + gObjectPreviewProgram.bind(); + } + + gGL.loadIdentity(); + gPipeline.enableLightsPreview(); + + LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * + LLQuaternion(mCameraYaw, LLVector3::z_axis); + + LLQuaternion av_rot = camera_rot; + F32 camera_distance = skin_weight ? SKIN_WEIGHT_CAMERA_DISTANCE : mCameraDistance; + LLViewerCamera::getInstance()->setOriginAndLookAt( + target_pos + ((LLVector3(camera_distance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + + + z_near = llclamp(z_far * 0.001f, 0.001f, 0.1f); + + LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); + + stop_glerror(); + + gGL.pushMatrix(); + gGL.color4fv(PREVIEW_EDGE_COL.mV); + + const U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + LLGLEnable normalize(GL_NORMALIZE); + + if (!mBaseModel.empty() && mVertexBuffer[5].empty()) + { + genBuffers(-1, skin_weight); + //genBuffers(3); + //genLODs(); + } + + if (!mModel[mPreviewLOD].empty()) + { + mFMP->childEnable("reset_btn"); + + bool regen = mVertexBuffer[mPreviewLOD].empty(); + if (!regen) + { + const std::vector<LLPointer<LLVertexBuffer> >& vb_vec = mVertexBuffer[mPreviewLOD].begin()->second; + if (!vb_vec.empty()) + { + const LLVertexBuffer* buff = vb_vec[0]; + regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight; + } + else + { + LL_INFOS() << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL; + regen = TRUE; + } + } + + if (regen) + { + genBuffers(mPreviewLOD, skin_weight); + } + + if (!skin_weight) + { + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + + LLModel* model = instance.mLOD[mPreviewLOD]; + + if (!model) + { + continue; + } + + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; + + gGL.multMatrix((GLfloat*)mat.mMatrix); + + + U32 num_models = mVertexBuffer[mPreviewLOD][model].size(); + for (U32 i = 0; i < num_models; ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + buffer->setBuffer(type_mask & buffer->getTypeMask()); + + if (textures) + { + int 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); + + // Find the tex for this material, bind it, and add it to our set + // + LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material); + if (tex) + { + mTextureSet.insert(tex); + } + } + } + else + { + gGL.diffuseColor4fv(PREVIEW_BASE_COL.mV); + } + + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.diffuseColor4fv(PREVIEW_EDGE_COL.mV); + if (edges) + { + glLineWidth(PREVIEW_EDGE_WIDTH); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + gGL.popMatrix(); + } + + if (physics) + { + glClear(GL_DEPTH_BUFFER_BIT); + + for (U32 pass = 0; pass < 2; pass++) + { + if (pass == 0) + { //depth only pass + gGL.setColorMask(false, false); + } + else + { + gGL.setColorMask(true, true); + } + + //enable alpha blending on second pass but not first pass + LLGLState blend(GL_BLEND, pass); + + gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA); + + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + + LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; + + if (!model) + { + continue; + } + + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; + + gGL.multMatrix((GLfloat*)mat.mMatrix); + + + bool render_mesh = true; + LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; + if (decomp) + { + LLMutexLock(decomp->mMutex); + + LLModel::Decomposition& physics = model->mPhysics; + + if (!physics.mHull.empty()) + { + render_mesh = false; + + if (physics.mMesh.empty()) + { //build vertex buffer for physics mesh + gMeshRepo.buildPhysicsMesh(physics); + } + + if (!physics.mMesh.empty()) + { //render hull instead of mesh + for (U32 i = 0; i < physics.mMesh.size(); ++i) + { + if (explode > 0.f) + { + gGL.pushMatrix(); + + LLVector3 offset = model->mHullCenter[i] - model->mCenterOfHullCenters; + offset *= explode; + + gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); + } + + static std::vector<LLColor4U> hull_colors; + + if (i + 1 >= hull_colors.size()) + { + hull_colors.push_back(LLColor4U(rand() % 128 + 127, rand() % 128 + 127, rand() % 128 + 127, 128)); + } + + gGL.diffuseColor4ubv(hull_colors[i].mV); + LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals); + + if (explode > 0.f) + { + gGL.popMatrix(); + } + } + } + } + } + + if (render_mesh) + { + if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) + { + genBuffers(LLModel::LOD_PHYSICS, false); + } + + U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); + if (pass > 0){ + for (U32 i = 0; i < num_models; ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.diffuseColor4fv(PREVIEW_PSYH_FILL_COL.mV); + + buffer->setBuffer(type_mask & buffer->getTypeMask()); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0); + + gGL.diffuseColor4fv(PREVIEW_PSYH_EDGE_COL.mV); + glLineWidth(PREVIEW_PSYH_EDGE_WIDTH); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + } + gGL.popMatrix(); + } + + // only do this if mDegenerate was set in the preceding mesh checks [Check this if the ordering ever breaks] + if (mHasDegenerate) + { + glLineWidth(PREVIEW_DEG_EDGE_WIDTH); + glPointSize(PREVIEW_DEG_POINT_SIZE); + gPipeline.enableLightsFullbright(); + //show degenerate triangles + LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); + LLGLDisable cull(GL_CULL_FACE); + gGL.diffuseColor4f(1.f, 0.f, 0.f, 1.f); + const LLVector4a scale(0.5f); + + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + + LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; + + if (!model) + { + continue; + } + + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; + + gGL.multMatrix((GLfloat*)mat.mMatrix); + + + LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; + if (decomp) + { + LLMutexLock(decomp->mMutex); + + LLModel::Decomposition& physics = model->mPhysics; + + if (physics.mHull.empty()) + { + if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) + { + genBuffers(LLModel::LOD_PHYSICS, false); + } + + U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); + for (U32 v = 0; v < num_models; ++v) + { + LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][v]; + + buffer->setBuffer(type_mask & buffer->getTypeMask()); + + LLStrider<LLVector3> pos_strider; + buffer->getVertexStrider(pos_strider, 0); + LLVector4a* pos = (LLVector4a*)pos_strider.get(); + + LLStrider<U16> idx; + buffer->getIndexStrider(idx, 0); + + for (U32 i = 0; i < buffer->getNumIndices(); i += 3) + { + LLVector4a v1; v1.setMul(pos[*idx++], scale); + LLVector4a v2; v2.setMul(pos[*idx++], scale); + LLVector4a v3; v3.setMul(pos[*idx++], scale); + + if (ll_is_degenerate(v1, v2, v3)) + { + buffer->draw(LLRender::LINE_LOOP, 3, i); + buffer->draw(LLRender::POINTS, 3, i); + } + } + } + } + } + + gGL.popMatrix(); + } + glLineWidth(1.f); + glPointSize(1.f); + gPipeline.enableLightsPreview(); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + } + } + } + else + { + target_pos = getPreviewAvatar()->getPositionAgent(); + getPreviewAvatar()->clearAttachmentOverrides(); // removes pelvis fixup + LLUUID fake_mesh_id; + fake_mesh_id.generate(); + getPreviewAvatar()->addPelvisFixup(mPelvisZOffset, fake_mesh_id); + bool pelvis_recalc = false; + + LLViewerCamera::getInstance()->setOriginAndLookAt( + target_pos + ((LLVector3(camera_distance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + + 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) + { + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + + if (!model->mSkinWeights.empty()) + { + const LLMeshSkinInfo *skin = &model->mSkinInfo; + LLSkinningUtil::initJointNums(&model->mSkinInfo, getPreviewAvatar());// inits skin->mJointNums if nessesary + U32 joint_count = LLSkinningUtil::getMeshJointCount(skin); + U32 bind_count = skin->mAlternateBindMatrix.size(); + + if (joint_overrides + && bind_count > 0 + && joint_count == bind_count) + { + // 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(); + for (U32 j = 0; j < joint_count; ++j) + { + LLJoint *joint = getPreviewAvatar()->getJoint(skin->mJointNums[j]); + if (joint) + { + const LLVector3& jointPos = skin->mAlternateBindMatrix[j].getTranslation(); + if (joint->aboveJointPosThreshold(jointPos)) + { + bool override_changed; + joint->addAttachmentPosOverride(jointPos, fake_mesh_id, "model", override_changed); + + if (override_changed) + { + //If joint is a pelvis then handle old/new pelvis to foot values + if (joint->getName() == "mPelvis")// or skin->mJointNames[j] + { + pelvis_recalc = true; + } + } + if (skin->mLockScaleIfJointPosition) + { + // Note that unlike positions, there's no threshold check here, + // just a lock at the default value. + joint->addAttachmentScaleOverride(joint->getDefaultScale(), fake_mesh_id, "model"); + } + } + } + } + } + + for (U32 i = 0, e = mVertexBuffer[mPreviewLOD][model].size(); i < e; ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + const LLVolumeFace& face = model->getVolumeFace(i); + + LLStrider<LLVector3> position; + buffer->getVertexStrider(position); + + LLStrider<LLVector4> weight; + buffer->getWeight4Strider(weight); + + //quick 'n dirty software vertex skinning + + //build matrix palette + + LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; + LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, joint_count, + skin, getPreviewAvatar()); + + LLMatrix4a bind_shape_matrix; + bind_shape_matrix.loadu(skin->mBindShapeMatrix); + U32 max_joints = LLSkinningUtil::getMaxJointCount(); + for (U32 j = 0; j < buffer->getNumVerts(); ++j) + { + LLMatrix4a final_mat; + F32 *wptr = weight[j].mV; + LLSkinningUtil::getPerVertexSkinMatrix(wptr, mat, true, final_mat, max_joints); + + //VECTORIZE THIS + LLVector4a& v = face.mPositions[j]; + + LLVector4a t; + LLVector4a dst; + bind_shape_matrix.affineTransform(v, t); + final_mat.affineTransform(t, dst); + + position[j][0] = dst[0]; + position[j][1] = dst[1]; + position[j][2] = dst[2]; + } + + llassert(model->mMaterialList.size() > i); + const std::string& binding = instance.mModel->mMaterialList[i]; + const LLImportMaterial& material = instance.mMaterial[binding]; + + buffer->setBuffer(type_mask & buffer->getTypeMask()); + gGL.diffuseColor4fv(material.mDiffuseColor.mV); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + // Find the tex for this material, bind it, and add it to our set + // + LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material); + if (tex) + { + mTextureSet.insert(tex); + } + + buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); + + if (edges) + { + gGL.diffuseColor4fv(PREVIEW_EDGE_COL.mV); + glLineWidth(PREVIEW_EDGE_WIDTH); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + } + } + } + + if (joint_positions) + { + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + if (shader) + { + gDebugProgram.bind(); + } + getPreviewAvatar()->renderCollisionVolumes(); + if (fmp->mTabContainer->getCurrentPanelIndex() == fmp->mAvatarTabIndex) + { + getPreviewAvatar()->renderBones(fmp->mSelectedJointName); + } + else + { + getPreviewAvatar()->renderBones(); + } + if (shader) + { + shader->bind(); + } + } + + if (pelvis_recalc) + { + // size/scale recalculation + getPreviewAvatar()->postPelvisSetRecalc(); + } + } + } + + if (use_shaders) + { + gObjectPreviewProgram.unbind(); + } + + gGL.popMatrix(); + + return TRUE; +} + +//----------------------------------------------------------------------------- +// refresh() +//----------------------------------------------------------------------------- +void LLModelPreview::refresh() +{ + mNeedsUpdate = TRUE; +} + +//----------------------------------------------------------------------------- +// rotate() +//----------------------------------------------------------------------------- +void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) +{ + mCameraYaw = mCameraYaw + yaw_radians; + + mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); +} + +//----------------------------------------------------------------------------- +// zoom() +//----------------------------------------------------------------------------- +void LLModelPreview::zoom(F32 zoom_amt) +{ + F32 new_zoom = mCameraZoom + zoom_amt; + // TODO: stop clamping in render + mCameraZoom = llclamp(new_zoom, 1.f, PREVIEW_ZOOM_LIMIT); +} + +void LLModelPreview::pan(F32 right, F32 up) +{ + bool skin_weight = mViewOption["show_skin_weight"]; + F32 camera_distance = skin_weight ? SKIN_WEIGHT_CAMERA_DISTANCE : mCameraDistance; + mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * camera_distance / mCameraZoom, -1.f, 1.f); + mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * camera_distance / mCameraZoom, -1.f, 1.f); +} + +void LLModelPreview::setPreviewLOD(S32 lod) +{ + lod = llclamp(lod, 0, (S32)LLModel::LOD_HIGH); + + if (lod != mPreviewLOD) + { + mPreviewLOD = lod; + + LLComboBox* combo_box = mFMP->getChild<LLComboBox>("preview_lod_combo"); + combo_box->setCurrentByIndex((NUM_LOD - 1) - mPreviewLOD); // combo box list of lods is in reverse order + mFMP->childSetValue("lod_file_" + lod_name[mPreviewLOD], mLODFile[mPreviewLOD]); + + LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); + LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); + + for (S32 i = 0; i <= LLModel::LOD_HIGH; ++i) + { + const LLColor4& color = (i == lod) ? highlight_color : normal_color; + + mFMP->childSetColor(lod_status_name[i], color); + mFMP->childSetColor(lod_label_name[i], color); + mFMP->childSetColor(lod_triangles_name[i], color); + mFMP->childSetColor(lod_vertices_name[i], color); + } + + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*)mFMP; + if (fmp) + { + // make preview repopulate tab + fmp->clearAvatarTab(); + } + } + refresh(); + updateStatusMessages(); +} + +//static +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(); + + if (final && preview->mModelLoader) + { + if (preview->mModelLoader->mNumOfFetchingTextures > 0) + { + preview->mModelLoader->mNumOfFetchingTextures--; + } + } +} + +// 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 && fmp->mModelPreview) + { + LLModelPreview* preview = fmp->mModelPreview; + if (preview->mLodsQuery.size() > 0) + { + S32 lod = preview->mLodsQuery.back(); + preview->mLodsQuery.pop_back(); + preview->genLODs(lod); + + if (preview->mLookUpLodFiles && (lod == LLModel::LOD_HIGH)) + { + preview->lookupLODModelFiles(LLModel::LOD_HIGH); + } + + // return false to continue cycle + return false; + } + } + // nothing to process + return true; +} + +void LLModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) +{ + if (!mLODFrozen) + { + genLODs(lod, 3, enforce_tri_limit); + refresh(); + } +} + diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h new file mode 100644 index 0000000000..3664a27a72 --- /dev/null +++ b/indra/newview/llmodelpreview.h @@ -0,0 +1,313 @@ +/** + * @file llmodelpreview.h + * @brief LLModelPreview class definition, class + * responsible for model preview inside LLFloaterModelPreview + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2020, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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_LLMODELPREVIEW_H +#define LL_LLMODELPREVIEW_H + +#include "lldynamictexture.h" +#include "llfloatermodelpreview.h" +#include "llmeshrepository.h" +#include "llmodelloader.h" //NUM_LOD +#include "llmodel.h" + +class LLJoint; +class LLVOAvatar; +class LLTextBox; +class LLVertexBuffer; +class DAE; +class daeElement; +class domProfile_COMMON; +class domInstance_geometry; +class domNode; +class domTranslate; +class domController; +class domSkin; +class domMesh; + +// const strings needed by classes that use model preivew +static const std::string lod_name[NUM_LOD + 1] = +{ + "lowest", + "low", + "medium", + "high", + "I went off the end of the lod_name array. Me so smart." +}; + +static const 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." +}; + +static const 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." +}; + +static const 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." +}; + +static const 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." +}; + +static const std::string lod_status_image[NUM_LOD + 1] = +{ + "ModelImport_Status_Good", + "ModelImport_Status_Warning", + "ModelImport_Status_Error", + "I went off the end of the lod_status_image array. Me so smart." +}; + +static const 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." +}; + +class LLModelPreview : public LLViewerDynamicTexture, public LLMutex +{ + LOG_CLASS(LLModelPreview); + + typedef boost::signals2::signal<void(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost)> details_signal_t; + typedef boost::signals2::signal<void(void)> model_loaded_signal_t; + typedef boost::signals2::signal<void(bool)> model_updated_signal_t; + +public: + + typedef enum + { + LOD_FROM_FILE = 0, + GENERATE, + USE_LOD_ABOVE, + } eLoDMode; + +public: + // Todo: model preview shouldn't need floater dependency, it + // should just expose data to floater, not control flaoter like it does + LLModelPreview(S32 width, S32 height, LLFloater* fmp); + virtual ~LLModelPreview(); + + void resetPreviewTarget(); + void setPreviewTarget(F32 distance); + void setTexture(U32 name) { mTextureName = name; } + + void setPhysicsFromLOD(S32 lod); + BOOL render(); + void update(); + void genBuffers(S32 lod, bool skinned); + void clearBuffers(); + void refresh(); + void rotate(F32 yaw_radians, F32 pitch_radians); + void zoom(F32 zoom_amt); + void pan(F32 right, F32 up); + 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 generateNormals(); + void restoreNormals(); + U32 calcResourceCost(); + void rebuildUploadData(); + void saveUploadData(bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position); + void saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position); + void clearIncompatible(S32 lod); + void updateStatusMessages(); + void updateLodControls(S32 lod); + void clearGLODGroup(); + void onLODParamCommit(S32 lod, bool enforce_tri_limit); + void addEmptyFace(LLModel* pTarget); + + const bool getModelPivot(void) const { return mHasPivot; } + void setHasPivot(bool val) { mHasPivot = val; } + void setModelPivot(const LLVector3& pivot) { mModelPivot = pivot; } + + //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; } + + //Accessors for the legacy rigs + const bool isLegacyRigValid(void) const { return mLegacyRigFlags == 0; } + U32 getLegacyRigFlags() const { return mLegacyRigFlags; } + void setLegacyRigFlags(U32 rigFlags) { mLegacyRigFlags = rigFlags; } + + 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; } + + static bool sIgnoreLoadedCallback; + std::vector<S32> mLodsQuery; + std::vector<S32> mLodsWithParsingError; + bool mHasDegenerate; + +protected: + + static void loadedCallback(LLModelLoader::scene& scene, LLModelLoader::model_list& model_list, S32 lod, void* opaque); + static void stateChangedCallback(U32 state, void* opaque); + + static LLJoint* lookupJointByName(const std::string&, void* opaque); + static U32 loadTextures(LLImportMaterial& material, void* opaque); + + void lookupLODModelFiles(S32 lod); + +private: + //Utility function for controller vertex compare + bool verifyCount(int expected, int result); + //Creates the dummy avatar for the preview window + void createPreviewAvatar(void); + //Accessor for the dummy avatar + LLVOAvatar* getPreviewAvatar(void) { return mPreviewAvatar; } + // Count amount of original models, excluding sub-models + static U32 countRootModels(LLModelLoader::model_list models); + +protected: + friend class LLModelLoader; + friend class LLFloaterModelPreview; + friend class LLFloaterModelPreview::DecompRequest; + friend class LLPhysicsDecomp; + + LLFloater* mFMP; + + BOOL mNeedsUpdate; + bool mDirty; + bool mGenLOD; + U32 mTextureName; + F32 mCameraDistance; + F32 mCameraYaw; + F32 mCameraPitch; + F32 mCameraZoom; + LLVector3 mCameraOffset; + LLVector3 mPreviewTarget; + LLVector3 mPreviewScale; + S32 mPreviewLOD; + S32 mPhysicsSearchLOD; + U32 mResourceCost; + std::string mLODFile[LLModel::NUM_LODS]; + bool mLoading; + U32 mLoadState; + bool mResetJoints; + bool mModelNoErrors; + bool mLookUpLodFiles; + + std::map<std::string, bool> mViewOption; + + //GLOD object parameters (must rebuild object if these change) + bool mLODFrozen; + F32 mBuildShareTolerance; + U32 mBuildQueueMode; + U32 mBuildOperator; + U32 mBuildBorderMode; + U32 mRequestedLoDMode[LLModel::NUM_LODS]; + S32 mRequestedTriangleCount[LLModel::NUM_LODS]; + F32 mRequestedErrorThreshold[LLModel::NUM_LODS]; + U32 mRequestedBuildOperator[LLModel::NUM_LODS]; + U32 mRequestedQueueMode[LLModel::NUM_LODS]; + U32 mRequestedBorderMode[LLModel::NUM_LODS]; + F32 mRequestedShareTolerance[LLModel::NUM_LODS]; + F32 mRequestedCreaseAngle[LLModel::NUM_LODS]; + + LLModelLoader* mModelLoader; + + LLModelLoader::scene mScene[LLModel::NUM_LODS]; + LLModelLoader::scene mBaseScene; + + LLModelLoader::model_list mModel[LLModel::NUM_LODS]; + LLModelLoader::model_list mBaseModel; + + typedef std::vector<LLVolumeFace> v_LLVolumeFace_t; + typedef std::vector<v_LLVolumeFace_t> vv_LLVolumeFace_t; + + vv_LLVolumeFace_t mModelFacesCopy[LLModel::NUM_LODS]; + vv_LLVolumeFace_t mBaseModelFacesCopy; + + U32 mGroup; + std::map<LLPointer<LLModel>, U32> mObject; + U32 mMaxTriangleLimit; + + LLMeshUploadThread::instance_list mUploadData; + std::set<LLViewerFetchedTexture * > mTextureSet; + + //map of vertex buffers to models (one vertex buffer in vector per face in model + std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[LLModel::NUM_LODS + 1]; + + details_signal_t mDetailsSignal; + model_loaded_signal_t mModelLoadedSignal; + model_updated_signal_t mModelUpdatedSignal; + + LLVector3 mModelPivot; + bool mHasPivot; + + float mPelvisZOffset; + + bool mRigValidJointUpload; + U32 mLegacyRigFlags; + + bool mLastJointUpdate; + bool mFirstSkinUpdate; + + JointNameSet mJointsFromNode; + JointTransformMap mJointTransformMap; + + LLPointer<LLVOAvatar> mPreviewAvatar; + LLCachedControl<bool> mImporterDebug; +}; + +#endif // LL_LLMODELPREVIEW_H diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp index 19f238d99a..54409a6994 100644 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -568,12 +568,14 @@ BOOL LLPanelStandStopFlying::postBuild() mStandButton->setCommitCallback(boost::bind(&LLPanelStandStopFlying::onStandButtonClick, this)); mStandButton->setCommitCallback(boost::bind(&LLFloaterMove::enableInstance)); mStandButton->setVisible(FALSE); - LLHints::registerHintTarget("stand_btn", mStandButton->getHandle()); + LLHints::getInstance()->registerHintTarget("stand_btn", mStandButton->getHandle()); mStopFlyingButton = getChild<LLButton>("stop_fly_btn"); //mStopFlyingButton->setCommitCallback(boost::bind(&LLFloaterMove::setFlyingMode, FALSE)); mStopFlyingButton->setCommitCallback(boost::bind(&LLPanelStandStopFlying::onStopFlyingButtonClick, this)); mStopFlyingButton->setVisible(FALSE); + + gViewerWindow->setOnWorldViewRectUpdated(boost::bind(&LLPanelStandStopFlying::updatePosition, this)); return TRUE; } @@ -670,7 +672,7 @@ LLPanelStandStopFlying* LLPanelStandStopFlying::getStandStopFlyingPanel() panel->buildFromFile("panel_stand_stop_flying.xml"); panel->setVisible(FALSE); - //LLUI::getRootView()->addChild(panel); + //LLUI::getInstance()->getRootView()->addChild(panel); LL_INFOS() << "Build LLPanelStandStopFlying panel" << LL_ENDL; diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index 64df449c26..4a8ef53a8b 100644 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -169,6 +169,14 @@ LLMuteList::LLMuteList() : gMessageSystem.callWhenReady(boost::bind(&LLMessageSystem::setHandlerFuncFast, _1, _PREHASH_UseCachedMuteList, processUseCachedMuteList, static_cast<void**>(NULL))); + + // make sure mute list's instance gets initialized before we start any name requests + LLAvatarNameCache::getInstance()->setAccountNameChangedCallback([this](const LLUUID& id, const LLAvatarName& av_name) + { + // it would be better to just pass LLAvatarName instead of doing unnesssesary copies + // but this way is just more convinient + onAccountNameChanged(id, av_name.getUserName()); + }); } //----------------------------------------------------------------------------- @@ -179,6 +187,11 @@ LLMuteList::~LLMuteList() } +void LLMuteList::cleanupSingleton() +{ + LLAvatarNameCache::getInstance()->setAccountNameChangedCallback(NULL); +} + BOOL LLMuteList::isLinden(const std::string& name) const { std::string username = boost::replace_all_copy(name, ".", " "); @@ -232,8 +245,8 @@ BOOL LLMuteList::add(const LLMute& mute, U32 flags) LL_WARNS() << "Trying to self; ignored" << LL_ENDL; return FALSE; } - - S32 mute_list_limit = gSavedSettings.getS32("MuteListLimit"); + + static LLCachedControl<S32> mute_list_limit(gSavedSettings, "MuteListLimit", 1000); if (getMutes().size() >= mute_list_limit) { LL_WARNS() << "Mute limit is reached; ignored" << LL_ENDL; @@ -358,6 +371,10 @@ void LLMuteList::updateAdd(const LLMute& mute) msg->addU32("MuteFlags", mute.mFlags); gAgent.sendReliableMessage(); + if (!mIsLoaded) + { + LL_WARNS() << "Added elements to non-initialized block list" << LL_ENDL; + } mIsLoaded = TRUE; // why is this here? -MG } @@ -391,6 +408,8 @@ BOOL LLMuteList::remove(const LLMute& mute, U32 flags) else { // The caller didn't pass any flags -- just remove the mute entry entirely. + // set flags to notify observers with (flag being present means that something is allowed) + localmute.mFlags = LLMute::flagAll; } // Always remove the entry from the set -- it will be re-added with new flags if necessary. @@ -411,8 +430,8 @@ BOOL LLMuteList::remove(const LLMute& mute, U32 flags) } // Must be after erase. + notifyObservers(); notifyObserversDetailed(localmute); - setLoaded(); // why is this here? -MG } else { @@ -425,8 +444,8 @@ BOOL LLMuteList::remove(const LLMute& mute, U32 flags) updateRemove(mute); mLegacyMutes.erase(legacy_it); // Must be after erase. + notifyObservers(); notifyObserversDetailed(mute); - setLoaded(); // why is this here? -MG } } @@ -584,6 +603,19 @@ BOOL LLMuteList::loadFromFile(const std::string& filename) } fclose(fp); setLoaded(); + + // server does not maintain up-to date account names (not display names!) + // in this list, so it falls to viewer. + pending_names_t::iterator iter = mPendingAgentNameUpdates.begin(); + pending_names_t::iterator end = mPendingAgentNameUpdates.end(); + while (iter != end) + { + // this will send updates to server, make sure mIsLoaded is set + onAccountNameChanged(iter->first, iter->second); + iter++; + } + mPendingAgentNameUpdates.clear(); + return TRUE; } @@ -694,7 +726,20 @@ void LLMuteList::requestFromServer(const LLUUID& agent_id) msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_MuteData); msg->addU32Fast(_PREHASH_MuteCRC, crc.getCRC()); - gAgent.sendReliableMessage(); + + if (gDisconnected) + { + LL_WARNS() << "Trying to request mute list when disconnected!" << LL_ENDL; + return; + } + if (!gAgent.getRegion()) + { + LL_WARNS() << "No region for agent yet, skipping mute list request!" << LL_ENDL; + return; + } + // Double amount of retries due to this request happening during busy stage + // Ideally this should be turned into a capability + gMessageSystem->sendReliable(gAgent.getRegionHost(), LL_DEFAULT_RELIABLE_RETRIES * 2, TRUE, LL_PING_BASED_TIMEOUT_DUMMY, NULL, NULL); } //----------------------------------------------------------------------------- @@ -767,6 +812,48 @@ void LLMuteList::onFileMuteList(void** user_data, S32 error_code, LLExtStat ext_ delete local_filename_and_path; } +void LLMuteList::onAccountNameChanged(const LLUUID& id, const std::string& username) +{ + if (mIsLoaded) + { + LLMute mute(id, username, LLMute::AGENT); + mute_set_t::iterator mute_it = mMutes.find(mute); + if (mute_it != mMutes.end() + && mute_it->mName != mute.mName + && mute_it->mType == LLMute::AGENT) // just in case, it is std::set, not map + { + // existing mute, but name changed, copy data + mute.mFlags = mute_it->mFlags; + + // erase old variant + mMutes.erase(mute_it); + + // (re)add the mute entry. + { + std::pair<mute_set_t::iterator, bool> result = mMutes.insert(mute); + if (result.second) + { + LL_INFOS() << "Muting " << mute.mName << " id " << mute.mID << " flags " << mute.mFlags << LL_ENDL; + updateAdd(mute); + // Do not notify observers here, observers do not know or need to handle name changes + // Example: block list considers notifyObserversDetailed as a selection update; + // Various chat/voice statuses care only about id and flags + // Since apropriate update time for account names is considered to be in 'hours' it is + // fine not to update UI (will be fine after restart or couple other changes) + + } + } + } + } + else + { + // Delay update until we load file + // Ex: Buddies list can arrive too early since we prerequest + // names from Buddies list before we load blocklist + mPendingAgentNameUpdates[id] = username; + } +} + void LLMuteList::addObserver(LLMuteListObserver* observer) { mObservers.insert(observer); diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h index f2fcf3dbb3..0d426fbd48 100644 --- a/indra/newview/llmutelist.h +++ b/indra/newview/llmutelist.h @@ -73,6 +73,7 @@ class LLMuteList : public LLSingleton<LLMuteList> { LLSINGLETON(LLMuteList); ~LLMuteList(); + /*virtual*/ void cleanupSingleton(); public: // reasons for auto-unmuting a resident enum EAutoReason @@ -131,6 +132,7 @@ private: static void processUseCachedMuteList(LLMessageSystem* msg, void**); static void onFileMuteList(void** user_data, S32 code, LLExtStat ext_status); + void onAccountNameChanged(const LLUUID& id, const std::string& username); private: struct compare_by_name @@ -155,7 +157,9 @@ private: }; typedef std::set<LLMute, compare_by_id> mute_set_t; mute_set_t mMutes; - + typedef std::map<LLUUID, std::string> pending_names_t; + pending_names_t mPendingAgentNameUpdates; + typedef std::set<std::string> string_set_t; string_set_t mLegacyMutes; diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index d7c5364fba..3209d23e43 100644 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -154,7 +154,7 @@ void LLNameListCtrl::mouseOverHighlightNthItem( S32 target_index ) bool is_mouse_over_name_cell = false; S32 mouse_x, mouse_y; - LLUI::getMousePositionLocal(this, &mouse_x, &mouse_y); + LLUI::getInstance()->getMousePositionLocal(this, &mouse_x, &mouse_y); S32 column_index = getColumnIndexFromOffset(mouse_x); LLScrollListItem* hit_item = hitItem(mouse_x, mouse_y); diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index cfe2e6bf6a..19dbbeb60e 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -58,6 +58,7 @@ #include "llweb.h" #include "llhints.h" +#include "llfloatersidepanelcontainer.h" #include "llinventorymodel.h" #include "lllandmarkactions.h" @@ -290,6 +291,7 @@ BOOL LLNavigationBar::postBuild() mBtnBack = getChild<LLPullButton>("back_btn"); mBtnForward = getChild<LLPullButton>("forward_btn"); mBtnHome = getChild<LLButton>("home_btn"); + mBtnLandmarks = getChild<LLButton>("landmarks_btn"); mCmbLocation= getChild<LLLocationInputCtrl>("location_combo"); @@ -305,6 +307,8 @@ BOOL LLNavigationBar::postBuild() mBtnHome->setClickedCallback(boost::bind(&LLNavigationBar::onHomeButtonClicked, this)); + mBtnLandmarks->setClickedCallback(boost::bind(&LLNavigationBar::onLandmarksButtonClicked, this)); + mCmbLocation->setCommitCallback(boost::bind(&LLNavigationBar::onLocationSelection, this)); mTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> @@ -320,7 +324,7 @@ BOOL LLNavigationBar::postBuild() LLTeleportHistory::getInstance()->setHistoryChangedCallback( boost::bind(&LLNavigationBar::onTeleportHistoryChanged, this)); - LLHints::registerHintTarget("nav_bar", getHandle()); + LLHints::getInstance()->registerHintTarget("nav_bar", getHandle()); mNavigationPanel = getChild<LLLayoutPanel>("navigation_layout_panel"); mFavoritePanel = getChild<LLLayoutPanel>("favorites_layout_panel"); @@ -401,6 +405,12 @@ void LLNavigationBar::onHomeButtonClicked() gAgent.teleportHome(); } +void LLNavigationBar::onLandmarksButtonClicked() +{ + LLFloaterReg::toggleInstanceOrBringToFront("places"); + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "open_landmark_tab")); +} + void LLNavigationBar::onTeleportHistoryMenuItemClicked(const LLSD& userdata) { int idx = userdata.asInteger(); diff --git a/indra/newview/llnavigationbar.h b/indra/newview/llnavigationbar.h index a44c6dd699..646911a62c 100755 --- a/indra/newview/llnavigationbar.h +++ b/indra/newview/llnavigationbar.h @@ -119,6 +119,7 @@ private: void onNavigationButtonHeldUp(LLButton* nav_button); void onForwardButtonClicked(); void onHomeButtonClicked(); + void onLandmarksButtonClicked(); void onLocationSelection(); void onLocationPrearrange(const LLSD& data); void onTeleportFinished(const LLVector3d& global_agent_pos); @@ -144,6 +145,7 @@ private: LLPullButton* mBtnBack; LLPullButton* mBtnForward; LLButton* mBtnHome; + LLButton* mBtnLandmarks; LLLocationInputCtrl* mCmbLocation; LLRect mDefaultNbRect; LLRect mDefaultFpRect; diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 248c361ca4..112da55682 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -329,7 +329,7 @@ void LLNetMap::draw() S32 local_mouse_x; S32 local_mouse_y; //localMouse(&local_mouse_x, &local_mouse_y); - LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); + LLUI::getInstance()->getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); mClosestAgentToCursor.setNull(); F32 closest_dist_squared = F32_MAX; // value will be overridden in the loop F32 min_pick_dist_squared = (mDotRadius * MIN_PICK_SCALE) * (mDotRadius * MIN_PICK_SCALE); @@ -354,7 +354,7 @@ void LLNetMap::draw() LLColor4 color = show_as_friend ? map_avatar_friend_color : map_avatar_color; - unknown_relative_z = positions[i].mdV[VZ] == COARSEUPDATE_MAX_Z && + unknown_relative_z = positions[i].mdV[VZ] >= COARSEUPDATE_MAX_Z && camera_position.mV[VZ] >= COARSEUPDATE_MAX_Z; LLWorldMapView::drawAvatar( @@ -835,7 +835,7 @@ BOOL LLNetMap::handleMouseUp( S32 x, S32 y, MASK mask ) LLRect clip_rect = getRect(); clip_rect.stretch(-8); clip_rect.clipPointToRect(mMouseDown.mX, mMouseDown.mY, local_x, local_y); - LLUI::setMousePositionLocal(this, local_x, local_y); + LLUI::getInstance()->setMousePositionLocal(this, local_x, local_y); // finish the pan mPanning = false; diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h index 52c5234137..ef4aced2c7 100644 --- a/indra/newview/llnotificationhandler.h +++ b/indra/newview/llnotificationhandler.h @@ -297,6 +297,7 @@ public: * Writes notification message to IM p2p session. */ static void logToIMP2P(const LLNotificationPtr& notification, bool to_file_only = false); + static void logToIMP2P(const LLUUID& from_id, const std::string& message, bool to_file_only = false); /** * Writes group notice notification message to IM group session. diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp index 6a58196760..39a0b9b50e 100644 --- a/indra/newview/llnotificationhandlerutil.cpp +++ b/indra/newview/llnotificationhandlerutil.cpp @@ -123,15 +123,13 @@ void log_name_callback(const LLAvatarName& av_name, const std::string& from_name } // static -void LLHandlerUtil::logToIMP2P(const LLNotificationPtr& notification, bool to_file_only) +void LLHandlerUtil::logToIMP2P(const LLUUID& from_id, const std::string& message, bool to_file_only) { if (!gCacheName) { return; } - LLUUID from_id = notification->getPayload()["from_id"]; - if (from_id.isNull()) { // Normal behavior for system generated messages, don't spam. @@ -141,15 +139,22 @@ void LLHandlerUtil::logToIMP2P(const LLNotificationPtr& notification, bool to_fi if(to_file_only) { - LLAvatarNameCache::get(from_id, boost::bind(&log_name_callback, _2, "", notification->getMessage(), LLUUID())); + LLAvatarNameCache::get(from_id, boost::bind(&log_name_callback, _2, "", message, LLUUID())); } else { - LLAvatarNameCache::get(from_id, boost::bind(&log_name_callback, _2, INTERACTIVE_SYSTEM_FROM, notification->getMessage(), from_id)); + LLAvatarNameCache::get(from_id, boost::bind(&log_name_callback, _2, INTERACTIVE_SYSTEM_FROM, message, from_id)); } } // static +void LLHandlerUtil::logToIMP2P(const LLNotificationPtr& notification, bool to_file_only) +{ + LLUUID from_id = notification->getPayload()["from_id"]; + logToIMP2P(from_id, notification->getMessage(), to_file_only); +} + +// static void LLHandlerUtil::logGroupNoticeToIMGroup( const LLNotificationPtr& notification) { @@ -177,7 +182,7 @@ void LLHandlerUtil::logGroupNoticeToIMGroup( { // Legacy support and fallback method // if we can't retrieve sender id from group notice system message, try to lookup it from cache - sender_id = LLAvatarNameCache::findIdByName(sender_name); + sender_id = LLAvatarNameCache::getInstance()->findIdByName(sender_name); } logToIM(IM_SESSION_GROUP_START, group_name, sender_name, payload["message"], diff --git a/indra/newview/llnotificationhinthandler.cpp b/indra/newview/llnotificationhinthandler.cpp index f40369a2e0..f1226c53ff 100644 --- a/indra/newview/llnotificationhinthandler.cpp +++ b/indra/newview/llnotificationhinthandler.cpp @@ -40,17 +40,17 @@ LLHintHandler::LLHintHandler() void LLHintHandler::onAdd(LLNotificationPtr p) { - LLHints::show(p); + LLHints::getInstance()->show(p); } void LLHintHandler::onLoad(LLNotificationPtr p) { - LLHints::show(p); + LLHints::getInstance()->show(p); } void LLHintHandler::onDelete(LLNotificationPtr p) { - LLHints::hide(p); + LLHints::getInstance()->hide(p); } bool LLHintHandler::processNotification(const LLNotificationPtr& p) diff --git a/indra/newview/llnotificationlistitem.cpp b/indra/newview/llnotificationlistitem.cpp index b405d3dca2..6a79a0c68c 100644 --- a/indra/newview/llnotificationlistitem.cpp +++ b/indra/newview/llnotificationlistitem.cpp @@ -262,6 +262,7 @@ std::set<std::string> LLTransactionNotificationListItem::getTypes() std::set<std::string> types; types.insert("PaymentReceived"); types.insert("PaymentSent"); + types.insert("UploadPayment"); return types; } diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp index 14d25d8158..a9678b1e93 100644 --- a/indra/newview/llnotificationofferhandler.cpp +++ b/indra/newview/llnotificationofferhandler.cpp @@ -37,6 +37,8 @@ #include "llimview.h" #include "llnotificationsutil.h" +#include <boost/regex.hpp> + using namespace LLNotificationsUI; //-------------------------------------------------------------------------- @@ -143,7 +145,19 @@ bool LLOfferHandler::processNotification(const LLNotificationPtr& notification) { // log only to file if notif panel can be embedded to IM and IM is opened bool file_only = add_notif_to_im && LLHandlerUtil::isIMFloaterOpened(notification); - LLHandlerUtil::logToIMP2P(notification, file_only); + if ((notification->getName() == "TeleportOffered" + || notification->getName() == "TeleportOffered_MaturityExceeded" + || notification->getName() == "TeleportOffered_MaturityBlocked")) + { + boost::regex r("<icon\\s*>\\s*([^<]*)?\\s*</icon\\s*>( - )?", + boost::regex::perl|boost::regex::icase); + std::string stripped_msg = boost::regex_replace(notification->getMessage(), r, ""); + LLHandlerUtil::logToIMP2P(notification->getPayload()["from_id"], stripped_msg,file_only); + } + else + { + LLHandlerUtil::logToIMP2P(notification, file_only); + } } } diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index b2b6de94b3..c1b622ffff 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -36,7 +36,7 @@ #include "llaccordionctrltab.h" #include "llappearancemgr.h" -#include "lleconomy.h" +#include "llagentbenefits.h" #include "llerror.h" #include "llfilepicker.h" #include "llfloaterperms.h" @@ -67,6 +67,7 @@ LLOutfitGallery::LLOutfitGallery(const LLOutfitGallery::Params& p) mOutfitsObserver(NULL), mScrollPanel(NULL), mGalleryPanel(NULL), + mLastRowPanel(NULL), mGalleryCreated(false), mRowCount(0), mItemsAddedCount(0), @@ -166,9 +167,7 @@ bool compareGalleryItem(LLOutfitGalleryItem* item1, LLOutfitGalleryItem* item2) std::string name1 = item1->getItemName(); std::string name2 = item2->getItemName(); - LLStringUtil::toUpper(name1); - LLStringUtil::toUpper(name2); - return name1 < name2; + return (LLStringUtil::compareDict(name1, name2) < 0); } else { @@ -241,7 +240,15 @@ void LLOutfitGallery::removeLastRow() mGalleryPanel->removeChild(mLastRowPanel); mUnusedRowPanels.push_back(mLastRowPanel); mRowPanels.pop_back(); - mLastRowPanel = mRowPanels.back(); + if (mRowPanels.size() > 0) + { + // Just removed last row + mLastRowPanel = mRowPanels.back(); + } + else + { + mLastRowPanel = NULL; + } } LLPanel* LLOutfitGallery::addToRow(LLPanel* row_stack, LLOutfitGalleryItem* item, int pos, int hgap) @@ -910,6 +917,7 @@ bool LLOutfitGalleryContextMenu::onEnable(LLSD::String param) bool LLOutfitGalleryContextMenu::onVisible(LLSD::String param) { + mMenuHandle.get()->getChild<LLUICtrl>("upload_photo")->setLabelArg("[UPLOAD_COST]", std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost())); if ("remove_photo" == param) { LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList); @@ -1046,6 +1054,7 @@ void LLOutfitGallery::updateSnapshotFolderObserver() void LLOutfitGallery::refreshOutfit(const LLUUID& category_id) { LLViewerInventoryCategory* category = gInventory.getCategory(category_id); + if (category) { bool photo_loaded = false; LLInventoryModel::cat_array_t sub_cat_array; @@ -1109,7 +1118,7 @@ void LLOutfitGallery::refreshOutfit(const LLUUID& category_id) } } - if (mGalleryCreated && !LLApp::isQuitting()) + if (mGalleryCreated && !LLApp::isExiting()) { reArrangeRows(); } @@ -1205,7 +1214,7 @@ void LLOutfitGallery::uploadOutfitImage(const std::vector<std::string>& filename return; } - S32 expected_upload_cost = LLGlobalEconomy::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 = LLAgentBenefitsMgr::current().getTextureUploadCost(); void *nruserdata = NULL; nruserdata = (void *)&outfit_id; @@ -1215,7 +1224,6 @@ void LLOutfitGallery::uploadOutfitImage(const std::vector<std::string>& filename checkRemovePhoto(outfit_id); std::string upload_pending_name = outfit_id.asString(); std::string upload_pending_desc = ""; - LLAssetStorage::LLStoreAssetCallback callback = NULL; LLUUID photo_id = upload_new_resource(filename, // file upload_pending_name, upload_pending_desc, @@ -1223,7 +1231,7 @@ void LLOutfitGallery::uploadOutfitImage(const std::vector<std::string>& filename LLFloaterPerms::getNextOwnerPerms("Uploads"), LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"), - upload_pending_name, callback, expected_upload_cost, nruserdata, false); + upload_pending_name, LLAssetStorage::LLStoreAssetCallback(), expected_upload_cost, nruserdata, false); mOutfitLinkPending = outfit_id; } delete unit; @@ -1364,6 +1372,7 @@ void LLOutfitGallery::onSelectPhoto(LLUUID selected_outfit_id) texture_floaterp->setOnFloaterCommitCallback(boost::bind(&LLOutfitGallery::onTexturePickerCommit, this, _1, _2)); texture_floaterp->setOnUpdateImageStatsCallback(boost::bind(&LLOutfitGallery::onTexturePickerUpdateImageStats, this, _1)); texture_floaterp->setLocalTextureEnabled(FALSE); + texture_floaterp->setCanApply(false, true); } floaterp->openFloater(); diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index f2a284a561..423e57978a 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -35,6 +35,7 @@ #include "llaccordionctrltab.h" #include "llagentwearables.h" #include "llappearancemgr.h" +#include "llagentbenefits.h" #include "llfloatersidepanelcontainer.h" #include "llinventoryfunctions.h" #include "llinventorymodel.h" @@ -58,10 +59,7 @@ bool LLOutfitTabNameComparator::compare(const LLAccordionCtrlTab* tab1, const LL std::string name1 = tab1->getTitle(); std::string name2 = tab2->getTitle(); - LLStringUtil::toUpper(name1); - LLStringUtil::toUpper(name2); - - return name1 < name2; + return (LLStringUtil::compareDict(name1, name2) < 0); } struct outfit_accordion_tab_params : public LLInitParam::Block<outfit_accordion_tab_params, LLAccordionCtrlTab::Params> @@ -1235,6 +1233,7 @@ bool LLOutfitListGearMenuBase::onEnable(LLSD::String param) bool LLOutfitListGearMenuBase::onVisible(LLSD::String param) { + getMenu()->getChild<LLUICtrl>("upload_photo")->setLabelArg("[UPLOAD_COST]", std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost())); const LLUUID& selected_outfit_id = getSelectedOutfitID(); if (selected_outfit_id.isNull()) // no selection or invalid outfit selected { diff --git a/indra/newview/lloutputmonitorctrl.cpp b/indra/newview/lloutputmonitorctrl.cpp index 7f6c065bb9..7129641c20 100644 --- a/indra/newview/lloutputmonitorctrl.cpp +++ b/indra/newview/lloutputmonitorctrl.cpp @@ -245,11 +245,11 @@ void LLOutputMonitorCtrl::draw() // virtual BOOL LLOutputMonitorCtrl::handleMouseUp(S32 x, S32 y, MASK mask) { - if (mSpeakerId != gAgentID && !mShowParticipantsSpeaking) + if (mSpeakerId != gAgentID) { LLFloaterReg::showInstance("floater_voice_volume", LLSD().with("avatar_id", mSpeakerId)); } - else if(mShowParticipantsSpeaking) + else if (mShowParticipantsSpeaking) { LLFloaterReg::showInstance("chat_voice", LLSD()); } @@ -312,10 +312,14 @@ void LLOutputMonitorCtrl::setSpeakerId(const LLUUID& speaker_id, const LLUUID& s } } -void LLOutputMonitorCtrl::onChange() +void LLOutputMonitorCtrl::onChangeDetailed(const LLMute& mute) { - // check only blocking on voice. EXT-3542 - mIsMuted = LLMuteList::getInstance()->isMuted(mSpeakerId, LLMute::flagVoiceChat); + if (mute.mID == mSpeakerId) + { + // Check only blocking on voice. + // Logic goes in reverse, if flag is set, action is allowed + mIsMuted = !(LLMute::flagVoiceChat & mute.mFlags); + } } // virtual diff --git a/indra/newview/lloutputmonitorctrl.h b/indra/newview/lloutputmonitorctrl.h index 98966d39ee..e80745e1df 100644 --- a/indra/newview/lloutputmonitorctrl.h +++ b/indra/newview/lloutputmonitorctrl.h @@ -105,7 +105,8 @@ public: void setSpeakerId(const LLUUID& speaker_id, const LLUUID& session_id = LLUUID::null, bool show_other_participants_speaking = false); //called by mute list - virtual void onChange(); + virtual void onChange() {}; + virtual void onChangeDetailed(const LLMute& mute); /** * Implementation of LLSpeakingIndicator interface. diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 5d1b582d1f..37ed4bc74c 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -44,6 +44,7 @@ #include "llavatariconctrl.h" #include "llfloaterreg.h" #include "llnotificationsutil.h" +#include "llviewermenu.h" // is_agent_mappable #include "llvoiceclient.h" #include "lltextbox.h" #include "lltrans.h" diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 6d0c30fbf3..c0342eef4e 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -764,6 +764,7 @@ void LLPanelClassifiedEdit::processProperties(void* data, EAvatarProcessorType t setClassifiedName(c_info->name); setDescription(c_info->description); setSnapshotId(c_info->snapshot_id); + setParcelId(c_info->parcel_id); setPosGlobal(c_info->pos_global); setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global)); diff --git a/indra/newview/llpanelcontents.cpp b/indra/newview/llpanelcontents.cpp index 451f41cd3b..3bae0cebfb 100644 --- a/indra/newview/llpanelcontents.cpp +++ b/indra/newview/llpanelcontents.cpp @@ -30,7 +30,6 @@ #include "llpanelcontents.h" // linden library includes -#include "lleconomy.h" #include "llerror.h" #include "llfloaterreg.h" #include "llfontgl.h" diff --git a/indra/newview/llpaneleditsky.cpp b/indra/newview/llpaneleditsky.cpp new file mode 100644 index 0000000000..a169712bd8 --- /dev/null +++ b/indra/newview/llpaneleditsky.cpp @@ -0,0 +1,976 @@ +/** +* @file llpaneleditsky.cpp +* @brief Floaters to create and edit fixed settings for sky and water. +* +* $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 "llpaneleditsky.h" + +#include "llslider.h" +#include "llsliderctrl.h" +#include "lltexturectrl.h" +#include "llcolorswatch.h" +#include "llvirtualtrackball.h" +#include "llsettingssky.h" +#include "llenvironment.h" +#include "llatmosphere.h" + +namespace +{ + // Atmosphere Tab + const std::string FIELD_SKY_AMBIENT_LIGHT("ambient_light"); + const std::string FIELD_SKY_BLUE_HORIZON("blue_horizon"); + const std::string FIELD_SKY_BLUE_DENSITY("blue_density"); + const std::string FIELD_SKY_HAZE_HORIZON("haze_horizon"); + const std::string FIELD_SKY_HAZE_DENSITY("haze_density"); + const std::string FIELD_SKY_SCENE_GAMMA("scene_gamma"); + const std::string FIELD_SKY_DENSITY_MULTIP("density_multip"); + const std::string FIELD_SKY_DISTANCE_MULTIP("distance_multip"); + const std::string FIELD_SKY_MAX_ALT("max_alt"); + + const std::string FIELD_SKY_CLOUD_COLOR("cloud_color"); + const std::string FIELD_SKY_CLOUD_COVERAGE("cloud_coverage"); + const std::string FIELD_SKY_CLOUD_SCALE("cloud_scale"); + const std::string FIELD_SKY_CLOUD_VARIANCE("cloud_variance"); + + const std::string FIELD_SKY_CLOUD_SCROLL_XY("cloud_scroll_xy"); + const std::string FIELD_SKY_CLOUD_MAP("cloud_map"); + const std::string FIELD_SKY_CLOUD_DENSITY_X("cloud_density_x"); + const std::string FIELD_SKY_CLOUD_DENSITY_Y("cloud_density_y"); + const std::string FIELD_SKY_CLOUD_DENSITY_D("cloud_density_d"); + const std::string FIELD_SKY_CLOUD_DETAIL_X("cloud_detail_x"); + const std::string FIELD_SKY_CLOUD_DETAIL_Y("cloud_detail_y"); + const std::string FIELD_SKY_CLOUD_DETAIL_D("cloud_detail_d"); + + const std::string FIELD_SKY_SUN_MOON_COLOR("sun_moon_color"); + const std::string FIELD_SKY_GLOW_FOCUS("glow_focus"); + const std::string FIELD_SKY_GLOW_SIZE("glow_size"); + const std::string FIELD_SKY_STAR_BRIGHTNESS("star_brightness"); + const std::string FIELD_SKY_SUN_ROTATION("sun_rotation"); + const std::string FIELD_SKY_SUN_AZIMUTH("sun_azimuth"); + const std::string FIELD_SKY_SUN_ELEVATION("sun_elevation"); + const std::string FIELD_SKY_SUN_IMAGE("sun_image"); + const std::string FIELD_SKY_SUN_SCALE("sun_scale"); + const std::string FIELD_SKY_SUN_BEACON("sunbeacon"); + const std::string FIELD_SKY_MOON_BEACON("moonbeacon"); + const std::string FIELD_SKY_MOON_ROTATION("moon_rotation"); + const std::string FIELD_SKY_MOON_AZIMUTH("moon_azimuth"); + const std::string FIELD_SKY_MOON_ELEVATION("moon_elevation"); + const std::string FIELD_SKY_MOON_IMAGE("moon_image"); + const std::string FIELD_SKY_MOON_SCALE("moon_scale"); + const std::string FIELD_SKY_MOON_BRIGHTNESS("moon_brightness"); + + const std::string PANEL_SKY_SUN_LAYOUT("sun_layout"); + const std::string PANEL_SKY_MOON_LAYOUT("moon_layout"); + + const std::string FIELD_SKY_DENSITY_RAYLEIGH_EXPONENTIAL("rayleigh_exponential"); + const std::string FIELD_SKY_DENSITY_RAYLEIGH_EXPONENTIAL_SCALE("rayleigh_exponential_scale"); + const std::string FIELD_SKY_DENSITY_RAYLEIGH_LINEAR("rayleigh_linear"); + const std::string FIELD_SKY_DENSITY_RAYLEIGH_CONSTANT("rayleigh_constant"); + const std::string FIELD_SKY_DENSITY_RAYLEIGH_MAX_ALTITUDE("rayleigh_max_altitude"); + + const std::string FIELD_SKY_DENSITY_MIE_EXPONENTIAL("mie_exponential"); + const std::string FIELD_SKY_DENSITY_MIE_EXPONENTIAL_SCALE("mie_exponential_scale"); + const std::string FIELD_SKY_DENSITY_MIE_LINEAR("mie_linear"); + const std::string FIELD_SKY_DENSITY_MIE_CONSTANT("mie_constant"); + const std::string FIELD_SKY_DENSITY_MIE_ANISO("mie_aniso_factor"); + const std::string FIELD_SKY_DENSITY_MIE_MAX_ALTITUDE("mie_max_altitude"); + + const std::string FIELD_SKY_DENSITY_ABSORPTION_EXPONENTIAL("absorption_exponential"); + const std::string FIELD_SKY_DENSITY_ABSORPTION_EXPONENTIAL_SCALE("absorption_exponential_scale"); + const std::string FIELD_SKY_DENSITY_ABSORPTION_LINEAR("absorption_linear"); + const std::string FIELD_SKY_DENSITY_ABSORPTION_CONSTANT("absorption_constant"); + const std::string FIELD_SKY_DENSITY_ABSORPTION_MAX_ALTITUDE("absorption_max_altitude"); + + const std::string FIELD_SKY_DENSITY_MOISTURE_LEVEL("moisture_level"); + const std::string FIELD_SKY_DENSITY_DROPLET_RADIUS("droplet_radius"); + const std::string FIELD_SKY_DENSITY_ICE_LEVEL("ice_level"); + + const F32 SLIDER_SCALE_SUN_AMBIENT(3.0f); + const F32 SLIDER_SCALE_BLUE_HORIZON_DENSITY(2.0f); + const F32 SLIDER_SCALE_GLOW_R(20.0f); + const F32 SLIDER_SCALE_GLOW_B(-5.0f); + const F32 SLIDER_SCALE_DENSITY_MULTIPLIER(0.001f); +} + +static LLPanelInjector<LLPanelSettingsSkyAtmosTab> t_settings_atmos("panel_settings_atmos"); +static LLPanelInjector<LLPanelSettingsSkyCloudTab> t_settings_cloud("panel_settings_cloud"); +static LLPanelInjector<LLPanelSettingsSkySunMoonTab> t_settings_sunmoon("panel_settings_sunmoon"); +static LLPanelInjector<LLPanelSettingsSkyDensityTab> t_settings_density("panel_settings_density"); + +//========================================================================== +LLPanelSettingsSky::LLPanelSettingsSky() : + LLSettingsEditPanel(), + mSkySettings() +{ + +} + + +//========================================================================== +LLPanelSettingsSkyAtmosTab::LLPanelSettingsSkyAtmosTab() : + LLPanelSettingsSky() +{ +} + + +BOOL LLPanelSettingsSkyAtmosTab::postBuild() +{ + getChild<LLUICtrl>(FIELD_SKY_AMBIENT_LIGHT)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onAmbientLightChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_BLUE_HORIZON)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onBlueHorizonChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_BLUE_DENSITY)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onBlueDensityChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_HAZE_HORIZON)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onHazeHorizonChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_HAZE_DENSITY)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onHazeDensityChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_SCENE_GAMMA)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onSceneGammaChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MULTIP)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onDensityMultipChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DISTANCE_MULTIP)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onDistanceMultipChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_MAX_ALT)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMaxAltChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MOISTURE_LEVEL)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMoistureLevelChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_DROPLET_RADIUS)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onDropletRadiusChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ICE_LEVEL)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onIceLevelChanged(); }); + refresh(); + + return TRUE; +} + +//virtual +void LLPanelSettingsSkyAtmosTab::setEnabled(BOOL enabled) +{ + LLPanelSettingsSky::setEnabled(enabled); + + // Make sure we have initialized children (initialized) + if (getFirstChild()) + { + getChild<LLUICtrl>(FIELD_SKY_HAZE_HORIZON)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_HAZE_DENSITY)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_SCENE_GAMMA)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MULTIP)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DISTANCE_MULTIP)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_MAX_ALT)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MOISTURE_LEVEL)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_DROPLET_RADIUS)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ICE_LEVEL)->setEnabled(enabled); + } +} + +void LLPanelSettingsSkyAtmosTab::refresh() +{ + if (!mSkySettings) + { + setAllChildrenEnabled(FALSE); + setEnabled(FALSE); + return; + } + + setEnabled(getCanChangeSettings()); + setAllChildrenEnabled(getCanChangeSettings()); + + getChild<LLColorSwatchCtrl>(FIELD_SKY_AMBIENT_LIGHT)->set(mSkySettings->getAmbientColor() / SLIDER_SCALE_SUN_AMBIENT); + getChild<LLColorSwatchCtrl>(FIELD_SKY_BLUE_HORIZON)->set(mSkySettings->getBlueHorizon() / SLIDER_SCALE_BLUE_HORIZON_DENSITY); + getChild<LLColorSwatchCtrl>(FIELD_SKY_BLUE_DENSITY)->set(mSkySettings->getBlueDensity() / SLIDER_SCALE_BLUE_HORIZON_DENSITY); + + getChild<LLUICtrl>(FIELD_SKY_HAZE_HORIZON)->setValue(mSkySettings->getHazeHorizon()); + getChild<LLUICtrl>(FIELD_SKY_HAZE_DENSITY)->setValue(mSkySettings->getHazeDensity()); + getChild<LLUICtrl>(FIELD_SKY_SCENE_GAMMA)->setValue(mSkySettings->getGamma()); + F32 density_mult = mSkySettings->getDensityMultiplier(); + density_mult /= SLIDER_SCALE_DENSITY_MULTIPLIER; + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MULTIP)->setValue(density_mult); + getChild<LLUICtrl>(FIELD_SKY_DISTANCE_MULTIP)->setValue(mSkySettings->getDistanceMultiplier()); + getChild<LLUICtrl>(FIELD_SKY_MAX_ALT)->setValue(mSkySettings->getMaxY()); + + F32 moisture_level = mSkySettings->getSkyMoistureLevel(); + F32 droplet_radius = mSkySettings->getSkyDropletRadius(); + F32 ice_level = mSkySettings->getSkyIceLevel(); + + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MOISTURE_LEVEL)->setValue(moisture_level); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_DROPLET_RADIUS)->setValue(droplet_radius); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ICE_LEVEL)->setValue(ice_level); +} + +//------------------------------------------------------------------------- +void LLPanelSettingsSkyAtmosTab::onAmbientLightChanged() +{ + if (!mSkySettings) return; + mSkySettings->setAmbientColor(LLColor3(getChild<LLColorSwatchCtrl>(FIELD_SKY_AMBIENT_LIGHT)->get() * SLIDER_SCALE_SUN_AMBIENT)); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkyAtmosTab::onBlueHorizonChanged() +{ + if (!mSkySettings) return; + mSkySettings->setBlueHorizon(LLColor3(getChild<LLColorSwatchCtrl>(FIELD_SKY_BLUE_HORIZON)->get() * SLIDER_SCALE_BLUE_HORIZON_DENSITY)); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkyAtmosTab::onBlueDensityChanged() +{ + if (!mSkySettings) return; + mSkySettings->setBlueDensity(LLColor3(getChild<LLColorSwatchCtrl>(FIELD_SKY_BLUE_DENSITY)->get() * SLIDER_SCALE_BLUE_HORIZON_DENSITY)); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkyAtmosTab::onHazeHorizonChanged() +{ + if (!mSkySettings) return; + mSkySettings->setHazeHorizon(getChild<LLUICtrl>(FIELD_SKY_HAZE_HORIZON)->getValue().asReal()); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkyAtmosTab::onHazeDensityChanged() +{ + if (!mSkySettings) return; + mSkySettings->setHazeDensity(getChild<LLUICtrl>(FIELD_SKY_HAZE_DENSITY)->getValue().asReal()); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkyAtmosTab::onSceneGammaChanged() +{ + if (!mSkySettings) return; + mSkySettings->setGamma(getChild<LLUICtrl>(FIELD_SKY_SCENE_GAMMA)->getValue().asReal()); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkyAtmosTab::onDensityMultipChanged() +{ + if (!mSkySettings) return; + F32 density_mult = getChild<LLUICtrl>(FIELD_SKY_DENSITY_MULTIP)->getValue().asReal(); + density_mult *= SLIDER_SCALE_DENSITY_MULTIPLIER; + mSkySettings->setDensityMultiplier(density_mult); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkyAtmosTab::onDistanceMultipChanged() +{ + if (!mSkySettings) return; + mSkySettings->setDistanceMultiplier(getChild<LLUICtrl>(FIELD_SKY_DISTANCE_MULTIP)->getValue().asReal()); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkyAtmosTab::onMaxAltChanged() +{ + if (!mSkySettings) return; + mSkySettings->setMaxY(getChild<LLUICtrl>(FIELD_SKY_MAX_ALT)->getValue().asReal()); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkyAtmosTab::onMoistureLevelChanged() +{ + if (!mSkySettings) return; + F32 moisture_level = getChild<LLUICtrl>(FIELD_SKY_DENSITY_MOISTURE_LEVEL)->getValue().asReal(); + mSkySettings->setSkyMoistureLevel(moisture_level); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkyAtmosTab::onDropletRadiusChanged() +{ + if (!mSkySettings) return; + F32 droplet_radius = getChild<LLUICtrl>(FIELD_SKY_DENSITY_DROPLET_RADIUS)->getValue().asReal(); + mSkySettings->setSkyDropletRadius(droplet_radius); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkyAtmosTab::onIceLevelChanged() +{ + if (!mSkySettings) return; + F32 ice_level = getChild<LLUICtrl>(FIELD_SKY_DENSITY_ICE_LEVEL)->getValue().asReal(); + mSkySettings->setSkyIceLevel(ice_level); + mSkySettings->update(); + setIsDirty(); +} + +//========================================================================== +LLPanelSettingsSkyCloudTab::LLPanelSettingsSkyCloudTab() : + LLPanelSettingsSky() +{ +} + +BOOL LLPanelSettingsSkyCloudTab::postBuild() +{ + getChild<LLUICtrl>(FIELD_SKY_CLOUD_COLOR)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onCloudColorChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_COVERAGE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onCloudCoverageChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_SCALE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onCloudScaleChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_VARIANCE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onCloudVarianceChanged(); }); + + getChild<LLUICtrl>(FIELD_SKY_CLOUD_SCROLL_XY)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onCloudScrollChanged(); }); + getChild<LLTextureCtrl>(FIELD_SKY_CLOUD_MAP)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onCloudMapChanged(); }); + getChild<LLTextureCtrl>(FIELD_SKY_CLOUD_MAP)->setDefaultImageAssetID(LLSettingsSky::GetDefaultCloudNoiseTextureId()); + getChild<LLTextureCtrl>(FIELD_SKY_CLOUD_MAP)->setAllowNoTexture(TRUE); + + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DENSITY_X)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onCloudDensityChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DENSITY_Y)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onCloudDensityChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DENSITY_D)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onCloudDensityChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DETAIL_X)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onCloudDetailChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DETAIL_Y)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onCloudDetailChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DETAIL_D)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onCloudDetailChanged(); }); + + refresh(); + + return TRUE; +} + +//virtual +void LLPanelSettingsSkyCloudTab::setEnabled(BOOL enabled) +{ + LLPanelSettingsSky::setEnabled(enabled); + + // Make sure we have children (initialized) + if (getFirstChild()) + { + getChild<LLUICtrl>(FIELD_SKY_CLOUD_COVERAGE)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_SCALE)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_VARIANCE)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DENSITY_X)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DENSITY_Y)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DENSITY_D)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DETAIL_X)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DETAIL_Y)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DETAIL_D)->setEnabled(enabled); + } +} + +void LLPanelSettingsSkyCloudTab::refresh() +{ + if (!mSkySettings) + { + setAllChildrenEnabled(FALSE); + setEnabled(FALSE); + return; + } + + setEnabled(getCanChangeSettings()); + setAllChildrenEnabled(getCanChangeSettings()); + + getChild<LLColorSwatchCtrl>(FIELD_SKY_CLOUD_COLOR)->set(mSkySettings->getCloudColor()); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_COVERAGE)->setValue(mSkySettings->getCloudShadow()); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_SCALE)->setValue(mSkySettings->getCloudScale()); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_VARIANCE)->setValue(mSkySettings->getCloudVariance()); + + LLVector2 cloudScroll(mSkySettings->getCloudScrollRate()); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_SCROLL_XY)->setValue(cloudScroll.getValue()); + + getChild<LLTextureCtrl>(FIELD_SKY_CLOUD_MAP)->setValue(mSkySettings->getCloudNoiseTextureId()); + + LLVector3 cloudDensity(mSkySettings->getCloudPosDensity1().getValue()); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DENSITY_X)->setValue(cloudDensity[0]); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DENSITY_Y)->setValue(cloudDensity[1]); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DENSITY_D)->setValue(cloudDensity[2]); + + LLVector3 cloudDetail(mSkySettings->getCloudPosDensity2().getValue()); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DETAIL_X)->setValue(cloudDetail[0]); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DETAIL_Y)->setValue(cloudDetail[1]); + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DETAIL_D)->setValue(cloudDetail[2]); +} + +//------------------------------------------------------------------------- +void LLPanelSettingsSkyCloudTab::onCloudColorChanged() +{ + if (!mSkySettings) return; + mSkySettings->setCloudColor(LLColor3(getChild<LLColorSwatchCtrl>(FIELD_SKY_CLOUD_COLOR)->get())); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkyCloudTab::onCloudCoverageChanged() +{ + if (!mSkySettings) return; + mSkySettings->setCloudShadow(getChild<LLUICtrl>(FIELD_SKY_CLOUD_COVERAGE)->getValue().asReal()); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkyCloudTab::onCloudScaleChanged() +{ + if (!mSkySettings) return; + mSkySettings->setCloudScale(getChild<LLUICtrl>(FIELD_SKY_CLOUD_SCALE)->getValue().asReal()); + setIsDirty(); +} + +void LLPanelSettingsSkyCloudTab::onCloudVarianceChanged() +{ + if (!mSkySettings) return; + mSkySettings->setCloudVariance(getChild<LLUICtrl>(FIELD_SKY_CLOUD_VARIANCE)->getValue().asReal()); + setIsDirty(); +} + +void LLPanelSettingsSkyCloudTab::onCloudScrollChanged() +{ + if (!mSkySettings) return; + LLVector2 scroll(getChild<LLUICtrl>(FIELD_SKY_CLOUD_SCROLL_XY)->getValue()); + mSkySettings->setCloudScrollRate(scroll); + setIsDirty(); +} + +void LLPanelSettingsSkyCloudTab::onCloudMapChanged() +{ + if (!mSkySettings) return; + LLTextureCtrl* ctrl = getChild<LLTextureCtrl>(FIELD_SKY_CLOUD_MAP); + mSkySettings->setCloudNoiseTextureId(ctrl->getValue().asUUID()); + setIsDirty(); +} + +void LLPanelSettingsSkyCloudTab::onCloudDensityChanged() +{ + if (!mSkySettings) return; + LLColor3 density(getChild<LLUICtrl>(FIELD_SKY_CLOUD_DENSITY_X)->getValue().asReal(), + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DENSITY_Y)->getValue().asReal(), + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DENSITY_D)->getValue().asReal()); + + mSkySettings->setCloudPosDensity1(density); + setIsDirty(); +} + +void LLPanelSettingsSkyCloudTab::onCloudDetailChanged() +{ + if (!mSkySettings) return; + LLColor3 detail(getChild<LLUICtrl>(FIELD_SKY_CLOUD_DETAIL_X)->getValue().asReal(), + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DETAIL_Y)->getValue().asReal(), + getChild<LLUICtrl>(FIELD_SKY_CLOUD_DETAIL_D)->getValue().asReal()); + + mSkySettings->setCloudPosDensity2(detail); + setIsDirty(); +} + +//========================================================================== +LLPanelSettingsSkySunMoonTab::LLPanelSettingsSkySunMoonTab() : + LLPanelSettingsSky() +{ +} + + +BOOL LLPanelSettingsSkySunMoonTab::postBuild() +{ + getChild<LLUICtrl>(FIELD_SKY_SUN_MOON_COLOR)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onSunMoonColorChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_GLOW_FOCUS)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onGlowChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_GLOW_SIZE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onGlowChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_STAR_BRIGHTNESS)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onStarBrightnessChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_SUN_ROTATION)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onSunRotationChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_SUN_AZIMUTH)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onSunAzimElevChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_SUN_ELEVATION)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onSunAzimElevChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_SUN_IMAGE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onSunImageChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_SUN_SCALE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onSunScaleChanged(); }); + getChild<LLTextureCtrl>(FIELD_SKY_SUN_IMAGE)->setBlankImageAssetID(LLSettingsSky::GetBlankSunTextureId()); + getChild<LLTextureCtrl>(FIELD_SKY_SUN_IMAGE)->setDefaultImageAssetID(LLSettingsSky::GetBlankSunTextureId()); + getChild<LLTextureCtrl>(FIELD_SKY_SUN_IMAGE)->setAllowNoTexture(TRUE); + getChild<LLUICtrl>(FIELD_SKY_MOON_ROTATION)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMoonRotationChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_MOON_AZIMUTH)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMoonAzimElevChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_MOON_ELEVATION)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMoonAzimElevChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_MOON_IMAGE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMoonImageChanged(); }); + getChild<LLTextureCtrl>(FIELD_SKY_MOON_IMAGE)->setDefaultImageAssetID(LLSettingsSky::GetDefaultMoonTextureId()); + getChild<LLTextureCtrl>(FIELD_SKY_MOON_IMAGE)->setBlankImageAssetID(LLSettingsSky::GetDefaultMoonTextureId()); + getChild<LLTextureCtrl>(FIELD_SKY_MOON_IMAGE)->setAllowNoTexture(TRUE); + getChild<LLUICtrl>(FIELD_SKY_MOON_SCALE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMoonScaleChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_MOON_BRIGHTNESS)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMoonBrightnessChanged(); }); + + refresh(); + + return TRUE; +} + +//virtual +void LLPanelSettingsSkySunMoonTab::setEnabled(BOOL enabled) +{ + LLPanelSettingsSky::setEnabled(enabled); + + // Make sure we have children + if (getFirstChild()) + { + getChild<LLUICtrl>(FIELD_SKY_GLOW_FOCUS)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_GLOW_SIZE)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_STAR_BRIGHTNESS)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_SUN_SCALE)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_MOON_SCALE)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_MOON_BRIGHTNESS)->setEnabled(enabled); + getChildView(PANEL_SKY_SUN_LAYOUT)->setAllChildrenEnabled(TRUE); + getChildView(PANEL_SKY_MOON_LAYOUT)->setAllChildrenEnabled(TRUE); + } +} + +void LLPanelSettingsSkySunMoonTab::refresh() +{ + if (!mSkySettings || !getCanChangeSettings()) + { + getChildView(PANEL_SKY_SUN_LAYOUT)->setAllChildrenEnabled(FALSE); + getChildView(PANEL_SKY_MOON_LAYOUT)->setAllChildrenEnabled(FALSE); + getChildView(FIELD_SKY_SUN_BEACON)->setEnabled(TRUE); + getChildView(FIELD_SKY_MOON_BEACON)->setEnabled(TRUE); + + if (!mSkySettings) + return; + } + else + { + setEnabled(TRUE); + setAllChildrenEnabled(TRUE); + } + + getChild<LLColorSwatchCtrl>(FIELD_SKY_SUN_MOON_COLOR)->set(mSkySettings->getSunlightColor() / SLIDER_SCALE_SUN_AMBIENT); + + LLColor3 glow(mSkySettings->getGlow()); + + // takes 40 - 0.2 range -> 0 - 1.99 UI range + getChild<LLUICtrl>(FIELD_SKY_GLOW_SIZE)->setValue(2.0 - (glow.mV[0] / SLIDER_SCALE_GLOW_R)); + getChild<LLUICtrl>(FIELD_SKY_GLOW_FOCUS)->setValue(glow.mV[2] / SLIDER_SCALE_GLOW_B); + + getChild<LLUICtrl>(FIELD_SKY_STAR_BRIGHTNESS)->setValue(mSkySettings->getStarBrightness()); + getChild<LLTextureCtrl>(FIELD_SKY_SUN_IMAGE)->setValue(mSkySettings->getSunTextureId()); + getChild<LLUICtrl>(FIELD_SKY_SUN_SCALE)->setValue(mSkySettings->getSunScale()); + getChild<LLTextureCtrl>(FIELD_SKY_MOON_IMAGE)->setValue(mSkySettings->getMoonTextureId()); + getChild<LLUICtrl>(FIELD_SKY_MOON_SCALE)->setValue(mSkySettings->getMoonScale()); + getChild<LLUICtrl>(FIELD_SKY_MOON_BRIGHTNESS)->setValue(mSkySettings->getMoonBrightness()); + + // Sun rotation values + F32 azimuth, elevation; + LLQuaternion quat = mSkySettings->getSunRotation(); + LLVirtualTrackball::getAzimuthAndElevationDeg(quat, azimuth, elevation); + + getChild<LLVirtualTrackball>(FIELD_SKY_SUN_ROTATION)->setRotation(quat); + getChild<LLUICtrl>(FIELD_SKY_SUN_AZIMUTH)->setValue(azimuth); + getChild<LLUICtrl>(FIELD_SKY_SUN_ELEVATION)->setValue(elevation); + + // Moon rotation values + quat = mSkySettings->getMoonRotation(); + LLVirtualTrackball::getAzimuthAndElevationDeg(quat, azimuth, elevation); + + getChild<LLVirtualTrackball>(FIELD_SKY_MOON_ROTATION)->setRotation(quat); + getChild<LLUICtrl>(FIELD_SKY_MOON_AZIMUTH)->setValue(azimuth); + getChild<LLUICtrl>(FIELD_SKY_MOON_ELEVATION)->setValue(elevation); + +} + +//------------------------------------------------------------------------- +void LLPanelSettingsSkySunMoonTab::onSunMoonColorChanged() +{ + if (!mSkySettings) return; + LLColor3 color(getChild<LLColorSwatchCtrl>(FIELD_SKY_SUN_MOON_COLOR)->get()); + + color *= SLIDER_SCALE_SUN_AMBIENT; + + mSkySettings->setSunlightColor(color); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkySunMoonTab::onGlowChanged() +{ + if (!mSkySettings) return; + LLColor3 glow(getChild<LLUICtrl>(FIELD_SKY_GLOW_SIZE)->getValue().asReal(), 0.0f, getChild<LLUICtrl>(FIELD_SKY_GLOW_FOCUS)->getValue().asReal()); + + // takes 0 - 1.99 UI range -> 40 -> 0.2 range + glow.mV[0] = (2.0f - glow.mV[0]) * SLIDER_SCALE_GLOW_R; + glow.mV[2] *= SLIDER_SCALE_GLOW_B; + + mSkySettings->setGlow(glow); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkySunMoonTab::onStarBrightnessChanged() +{ + if (!mSkySettings) return; + mSkySettings->setStarBrightness(getChild<LLUICtrl>(FIELD_SKY_STAR_BRIGHTNESS)->getValue().asReal()); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkySunMoonTab::onSunRotationChanged() +{ + LLQuaternion quat = getChild<LLVirtualTrackball>(FIELD_SKY_SUN_ROTATION)->getRotation(); + + F32 azimuth, elevation; + LLVirtualTrackball::getAzimuthAndElevationDeg(quat, azimuth, elevation); + getChild<LLUICtrl>(FIELD_SKY_SUN_AZIMUTH)->setValue(azimuth); + getChild<LLUICtrl>(FIELD_SKY_SUN_ELEVATION)->setValue(elevation); + if (mSkySettings) + { + mSkySettings->setSunRotation(quat); + mSkySettings->update(); + setIsDirty(); + } +} + +void LLPanelSettingsSkySunMoonTab::onSunAzimElevChanged() +{ + F32 azimuth = getChild<LLUICtrl>(FIELD_SKY_SUN_AZIMUTH)->getValue().asReal(); + F32 elevation = getChild<LLUICtrl>(FIELD_SKY_SUN_ELEVATION)->getValue().asReal(); + LLQuaternion quat; + + azimuth *= DEG_TO_RAD; + elevation *= DEG_TO_RAD; + + if (is_approx_zero(elevation)) + { + elevation = F_APPROXIMATELY_ZERO; + } + + quat.setAngleAxis(-elevation, 0, 1, 0); + LLQuaternion az_quat; + az_quat.setAngleAxis(F_TWO_PI - azimuth, 0, 0, 1); + quat *= az_quat; + + getChild<LLVirtualTrackball>(FIELD_SKY_SUN_ROTATION)->setRotation(quat); + + if (mSkySettings) + { + mSkySettings->setSunRotation(quat); + mSkySettings->update(); + setIsDirty(); + } +} + +void LLPanelSettingsSkySunMoonTab::onSunScaleChanged() +{ + if (!mSkySettings) return; + mSkySettings->setSunScale((getChild<LLUICtrl>(FIELD_SKY_SUN_SCALE)->getValue().asReal())); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkySunMoonTab::onSunImageChanged() +{ + if (!mSkySettings) return; + mSkySettings->setSunTextureId(getChild<LLTextureCtrl>(FIELD_SKY_SUN_IMAGE)->getValue().asUUID()); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkySunMoonTab::onMoonRotationChanged() +{ + LLQuaternion quat = getChild<LLVirtualTrackball>(FIELD_SKY_MOON_ROTATION)->getRotation(); + + F32 azimuth, elevation; + LLVirtualTrackball::getAzimuthAndElevationDeg(quat, azimuth, elevation); + getChild<LLUICtrl>(FIELD_SKY_MOON_AZIMUTH)->setValue(azimuth); + getChild<LLUICtrl>(FIELD_SKY_MOON_ELEVATION)->setValue(elevation); + + if (mSkySettings) + { + mSkySettings->setMoonRotation(quat); + mSkySettings->update(); + setIsDirty(); + } +} + +void LLPanelSettingsSkySunMoonTab::onMoonAzimElevChanged() +{ + F32 azimuth = getChild<LLUICtrl>(FIELD_SKY_MOON_AZIMUTH)->getValue().asReal(); + F32 elevation = getChild<LLUICtrl>(FIELD_SKY_MOON_ELEVATION)->getValue().asReal(); + LLQuaternion quat; + + azimuth *= DEG_TO_RAD; + elevation *= DEG_TO_RAD; + + if (is_approx_zero(elevation)) + { + elevation = F_APPROXIMATELY_ZERO; + } + + quat.setAngleAxis(-elevation, 0, 1, 0); + LLQuaternion az_quat; + az_quat.setAngleAxis(F_TWO_PI- azimuth, 0, 0, 1); + quat *= az_quat; + + getChild<LLVirtualTrackball>(FIELD_SKY_MOON_ROTATION)->setRotation(quat); + + if (mSkySettings) + { + mSkySettings->setMoonRotation(quat); + mSkySettings->update(); + setIsDirty(); + } +} + +void LLPanelSettingsSkySunMoonTab::onMoonImageChanged() +{ + if (!mSkySettings) return; + mSkySettings->setMoonTextureId(getChild<LLTextureCtrl>(FIELD_SKY_MOON_IMAGE)->getValue().asUUID()); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkySunMoonTab::onMoonScaleChanged() +{ + if (!mSkySettings) return; + mSkySettings->setMoonScale((getChild<LLUICtrl>(FIELD_SKY_MOON_SCALE)->getValue().asReal())); + mSkySettings->update(); + setIsDirty(); +} + +void LLPanelSettingsSkySunMoonTab::onMoonBrightnessChanged() +{ + if (!mSkySettings) return; + mSkySettings->setMoonBrightness((getChild<LLUICtrl>(FIELD_SKY_MOON_BRIGHTNESS)->getValue().asReal())); + mSkySettings->update(); + setIsDirty(); +} + +LLPanelSettingsSkyDensityTab::LLPanelSettingsSkyDensityTab() +{ +} + +BOOL LLPanelSettingsSkyDensityTab::postBuild() +{ + getChild<LLUICtrl>(FIELD_SKY_DENSITY_RAYLEIGH_EXPONENTIAL)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onRayleighExponentialChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_RAYLEIGH_EXPONENTIAL_SCALE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onRayleighExponentialScaleChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_RAYLEIGH_LINEAR)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onRayleighLinearChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_RAYLEIGH_CONSTANT)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onRayleighConstantChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_RAYLEIGH_MAX_ALTITUDE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onRayleighMaxAltitudeChanged(); }); + + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_EXPONENTIAL)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMieExponentialChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_EXPONENTIAL_SCALE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMieExponentialScaleChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_LINEAR)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMieLinearChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_CONSTANT)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMieConstantChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_ANISO)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMieAnisoFactorChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_MAX_ALTITUDE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMieMaxAltitudeChanged(); }); + + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ABSORPTION_EXPONENTIAL)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onAbsorptionExponentialChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ABSORPTION_EXPONENTIAL_SCALE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onAbsorptionExponentialScaleChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ABSORPTION_LINEAR)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onAbsorptionLinearChanged(); }); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ABSORPTION_CONSTANT)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onAbsorptionConstantChanged(); }); + + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ABSORPTION_MAX_ALTITUDE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onAbsorptionMaxAltitudeChanged(); }); + + refresh(); + return TRUE; +} + +void LLPanelSettingsSkyDensityTab::setEnabled(BOOL enabled) +{ + LLPanelSettingsSky::setEnabled(enabled); + + // Make sure we have children + if (getFirstChild()) + { + getChild<LLUICtrl>(FIELD_SKY_DENSITY_RAYLEIGH_EXPONENTIAL)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_RAYLEIGH_EXPONENTIAL_SCALE)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_RAYLEIGH_LINEAR)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_RAYLEIGH_CONSTANT)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_RAYLEIGH_MAX_ALTITUDE)->setEnabled(enabled); + + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_EXPONENTIAL)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_EXPONENTIAL_SCALE)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_LINEAR)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_CONSTANT)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_ANISO)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_MAX_ALTITUDE)->setEnabled(enabled); + + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ABSORPTION_EXPONENTIAL)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ABSORPTION_EXPONENTIAL_SCALE)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ABSORPTION_LINEAR)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ABSORPTION_CONSTANT)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ABSORPTION_MAX_ALTITUDE)->setEnabled(enabled); + } +} + +void LLPanelSettingsSkyDensityTab::refresh() +{ + if (!mSkySettings) + { + setAllChildrenEnabled(FALSE); + setEnabled(FALSE); + return; + } + + setEnabled(getCanChangeSettings()); + setAllChildrenEnabled(getCanChangeSettings()); + + // Get first (only) profile layer of each type for editing + LLSD rayleigh_config = mSkySettings->getRayleighConfig(); + LLSD mie_config = mSkySettings->getMieConfig(); + LLSD absorption_config = mSkySettings->getAbsorptionConfig(); + + F32 rayleigh_exponential_term = rayleigh_config[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM].asReal(); + F32 rayleigh_exponential_scale = rayleigh_config[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR].asReal(); + F32 rayleigh_linear_term = rayleigh_config[LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM].asReal(); + F32 rayleigh_constant_term = rayleigh_config[LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM].asReal(); + F32 rayleigh_max_alt = rayleigh_config[LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH].asReal(); + + F32 mie_exponential_term = mie_config[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM].asReal(); + F32 mie_exponential_scale = mie_config[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR].asReal(); + F32 mie_linear_term = mie_config[LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM].asReal(); + F32 mie_constant_term = mie_config[LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM].asReal(); + F32 mie_aniso_factor = mie_config[LLSettingsSky::SETTING_MIE_ANISOTROPY_FACTOR].asReal(); + F32 mie_max_alt = mie_config[LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH].asReal(); + + F32 absorption_exponential_term = absorption_config[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM].asReal(); + F32 absorption_exponential_scale = absorption_config[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR].asReal(); + F32 absorption_linear_term = absorption_config[LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM].asReal(); + F32 absorption_constant_term = absorption_config[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM].asReal(); + F32 absorption_max_alt = absorption_config[LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH].asReal(); + + getChild<LLUICtrl>(FIELD_SKY_DENSITY_RAYLEIGH_EXPONENTIAL)->setValue(rayleigh_exponential_term); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_RAYLEIGH_EXPONENTIAL_SCALE)->setValue(rayleigh_exponential_scale); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_RAYLEIGH_LINEAR)->setValue(rayleigh_linear_term); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_RAYLEIGH_CONSTANT)->setValue(rayleigh_constant_term); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_RAYLEIGH_MAX_ALTITUDE)->setValue(rayleigh_max_alt); + + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_EXPONENTIAL)->setValue(mie_exponential_term); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_EXPONENTIAL_SCALE)->setValue(mie_exponential_scale); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_LINEAR)->setValue(mie_linear_term); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_CONSTANT)->setValue(mie_constant_term); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_ANISO)->setValue(mie_aniso_factor); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_MIE_MAX_ALTITUDE)->setValue(mie_max_alt); + + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ABSORPTION_EXPONENTIAL)->setValue(absorption_exponential_term); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ABSORPTION_EXPONENTIAL_SCALE)->setValue(absorption_exponential_scale); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ABSORPTION_LINEAR)->setValue(absorption_linear_term); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ABSORPTION_CONSTANT)->setValue(absorption_constant_term); + getChild<LLUICtrl>(FIELD_SKY_DENSITY_ABSORPTION_MAX_ALTITUDE)->setValue(absorption_max_alt); +} + +void LLPanelSettingsSkyDensityTab::updateProfile() +{ + F32 rayleigh_exponential_term = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_RAYLEIGH_EXPONENTIAL)->getValueF32(); + F32 rayleigh_exponential_scale = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_RAYLEIGH_EXPONENTIAL_SCALE)->getValueF32(); + F32 rayleigh_linear_term = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_RAYLEIGH_LINEAR)->getValueF32(); + F32 rayleigh_constant_term = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_RAYLEIGH_CONSTANT)->getValueF32(); + F32 rayleigh_max_alt = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_RAYLEIGH_MAX_ALTITUDE)->getValueF32(); + + F32 mie_exponential_term = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_MIE_EXPONENTIAL)->getValueF32(); + F32 mie_exponential_scale = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_MIE_EXPONENTIAL_SCALE)->getValueF32(); + F32 mie_linear_term = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_MIE_LINEAR)->getValueF32(); + F32 mie_constant_term = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_MIE_CONSTANT)->getValueF32(); + F32 mie_aniso_factor = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_MIE_ANISO)->getValueF32(); + F32 mie_max_alt = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_MIE_MAX_ALTITUDE)->getValueF32(); + + F32 absorption_exponential_term = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_ABSORPTION_EXPONENTIAL)->getValueF32(); + F32 absorption_exponential_scale = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_ABSORPTION_EXPONENTIAL_SCALE)->getValueF32(); + F32 absorption_linear_term = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_ABSORPTION_LINEAR)->getValueF32(); + F32 absorption_constant_term = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_ABSORPTION_CONSTANT)->getValueF32(); + F32 absorption_max_alt = getChild<LLSliderCtrl>(FIELD_SKY_DENSITY_ABSORPTION_MAX_ALTITUDE)->getValueF32(); + + LLSD rayleigh_config = LLSettingsSky::createSingleLayerDensityProfile(rayleigh_max_alt, rayleigh_exponential_term, rayleigh_exponential_scale, rayleigh_linear_term, rayleigh_constant_term); + LLSD mie_config = LLSettingsSky::createSingleLayerDensityProfile(mie_max_alt, mie_exponential_term, mie_exponential_scale, mie_linear_term, mie_constant_term, mie_aniso_factor); + LLSD absorption_layer = LLSettingsSky::createSingleLayerDensityProfile(absorption_max_alt, absorption_exponential_term, absorption_exponential_scale, absorption_linear_term, absorption_constant_term); + + static LLSD absorption_layer_ozone = LLSettingsSky::createDensityProfileLayer(0.0f, 0.0f, 0.0f, -1.0f / 15000.0f, 8.0f / 3.0f); + + LLSD absorption_config; + absorption_config.append(absorption_layer); + absorption_config.append(absorption_layer_ozone); + + mSkySettings->setRayleighConfigs(rayleigh_config); + mSkySettings->setMieConfigs(mie_config); + mSkySettings->setAbsorptionConfigs(absorption_config); + mSkySettings->update(); + setIsDirty(); + + if (gAtmosphere) + { + AtmosphericModelSettings atmospheric_settings; + LLEnvironment::getAtmosphericModelSettings(atmospheric_settings, mSkySettings); + gAtmosphere->configureAtmosphericModel(atmospheric_settings); + } +} + +void LLPanelSettingsSkyDensityTab::onRayleighExponentialChanged() +{ + updateProfile(); +} + +void LLPanelSettingsSkyDensityTab::onRayleighExponentialScaleChanged() +{ + updateProfile(); +} + +void LLPanelSettingsSkyDensityTab::onRayleighLinearChanged() +{ + updateProfile(); +} + +void LLPanelSettingsSkyDensityTab::onRayleighConstantChanged() +{ + updateProfile(); +} + +void LLPanelSettingsSkyDensityTab::onRayleighMaxAltitudeChanged() +{ + updateProfile(); +} + +void LLPanelSettingsSkyDensityTab::onMieExponentialChanged() +{ + updateProfile(); +} + +void LLPanelSettingsSkyDensityTab::onMieExponentialScaleChanged() +{ + updateProfile(); +} + +void LLPanelSettingsSkyDensityTab::onMieLinearChanged() +{ + updateProfile(); +} + +void LLPanelSettingsSkyDensityTab::onMieConstantChanged() +{ + updateProfile(); +} + +void LLPanelSettingsSkyDensityTab::onMieAnisoFactorChanged() +{ + updateProfile(); +} + +void LLPanelSettingsSkyDensityTab::onMieMaxAltitudeChanged() +{ + updateProfile(); +} + +void LLPanelSettingsSkyDensityTab::onAbsorptionExponentialChanged() +{ + updateProfile(); +} + +void LLPanelSettingsSkyDensityTab::onAbsorptionExponentialScaleChanged() +{ + updateProfile(); +} + +void LLPanelSettingsSkyDensityTab::onAbsorptionLinearChanged() +{ + updateProfile(); +} + +void LLPanelSettingsSkyDensityTab::onAbsorptionConstantChanged() +{ + updateProfile(); +} + +void LLPanelSettingsSkyDensityTab::onAbsorptionMaxAltitudeChanged() +{ + updateProfile(); +} diff --git a/indra/newview/llpaneleditsky.h b/indra/newview/llpaneleditsky.h new file mode 100644 index 0000000000..cb63d40b0c --- /dev/null +++ b/indra/newview/llpaneleditsky.h @@ -0,0 +1,173 @@ +/** +* @file llpaneleditsky.h +* @brief Panels for sky settings +* +* $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 LLPANEL_EDIT_SKY_H +#define LLPANEL_EDIT_SKY_H + +#include "llpanel.h" +#include "llsettingssky.h" +#include "llfloatereditenvironmentbase.h" + +//========================================================================= +class LLSlider; +class LLColorSwatchCtrl; +class LLTextureCtrl; + +//========================================================================= +class LLPanelSettingsSky : public LLSettingsEditPanel +{ + LOG_CLASS(LLPanelSettingsSky); + +public: + LLPanelSettingsSky(); + + virtual void setSettings(const LLSettingsBase::ptr_t &settings) override { setSky(std::static_pointer_cast<LLSettingsSky>(settings)); } + + LLSettingsSky::ptr_t getSky() const { return mSkySettings; } + void setSky(const LLSettingsSky::ptr_t &sky) { mSkySettings = sky; clearIsDirty(); refresh(); } + +protected: + LLSettingsSky::ptr_t mSkySettings; +}; + +class LLPanelSettingsSkyAtmosTab : public LLPanelSettingsSky +{ + LOG_CLASS(LLPanelSettingsSkyAtmosTab); + +public: + LLPanelSettingsSkyAtmosTab(); + + virtual BOOL postBuild() override; + virtual void setEnabled(BOOL enabled) override; + +protected: + virtual void refresh() override; + +private: + void onAmbientLightChanged(); + void onBlueHorizonChanged(); + void onBlueDensityChanged(); + void onHazeHorizonChanged(); + void onHazeDensityChanged(); + void onSceneGammaChanged(); + void onDensityMultipChanged(); + void onDistanceMultipChanged(); + void onMaxAltChanged(); + void onMoistureLevelChanged(); + void onDropletRadiusChanged(); + void onIceLevelChanged(); + +}; + +class LLPanelSettingsSkyCloudTab : public LLPanelSettingsSky +{ + LOG_CLASS(LLPanelSettingsSkyCloudTab); + +public: + LLPanelSettingsSkyCloudTab(); + + virtual BOOL postBuild() override; + void setEnabled(BOOL enabled) override; + +protected: + virtual void refresh() override; + +private: + void onCloudColorChanged(); + void onCloudCoverageChanged(); + void onCloudScaleChanged(); + void onCloudVarianceChanged(); + void onCloudScrollChanged(); + void onCloudMapChanged(); + void onCloudDensityChanged(); + void onCloudDetailChanged(); +}; + +class LLPanelSettingsSkySunMoonTab : public LLPanelSettingsSky +{ + LOG_CLASS(LLPanelSettingsSkySunMoonTab); + +public: + LLPanelSettingsSkySunMoonTab(); + + virtual BOOL postBuild() override; + virtual void setEnabled(BOOL enabled) override; + +protected: + virtual void refresh() override; + +private: + void onSunMoonColorChanged(); + void onGlowChanged(); + void onStarBrightnessChanged(); + void onSunRotationChanged(); + void onSunAzimElevChanged(); + void onSunScaleChanged(); + void onSunImageChanged(); + void onMoonRotationChanged(); + void onMoonAzimElevChanged(); + void onMoonScaleChanged(); + void onMoonBrightnessChanged(); + void onMoonImageChanged(); +}; + +// single subtab of the density settings tab +class LLPanelSettingsSkyDensityTab : public LLPanelSettingsSky +{ + LOG_CLASS(LLPanelSettingsSkyDensityTab); + +public: + LLPanelSettingsSkyDensityTab(); + + virtual BOOL postBuild() override; + virtual void setEnabled(BOOL enabled) override; + +protected: + virtual void refresh() override; + + void onRayleighExponentialChanged(); + void onRayleighExponentialScaleChanged(); + void onRayleighLinearChanged(); + void onRayleighConstantChanged(); + void onRayleighMaxAltitudeChanged(); + + void onMieExponentialChanged(); + void onMieExponentialScaleChanged(); + void onMieLinearChanged(); + void onMieConstantChanged(); + void onMieAnisoFactorChanged(); + void onMieMaxAltitudeChanged(); + + void onAbsorptionExponentialChanged(); + void onAbsorptionExponentialScaleChanged(); + void onAbsorptionLinearChanged(); + void onAbsorptionConstantChanged(); + void onAbsorptionMaxAltitudeChanged(); + + // update the settings for our profile type + void updateProfile(); +}; +#endif // LLPANEL_EDIT_SKY_H diff --git a/indra/newview/llpaneleditwater.cpp b/indra/newview/llpaneleditwater.cpp new file mode 100644 index 0000000000..a09964e17d --- /dev/null +++ b/indra/newview/llpaneleditwater.cpp @@ -0,0 +1,251 @@ +/** +* @file llpaneleditwater.cpp +* @brief Floaters to create and edit fixed settings for sky and water. +* +* $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 "llpaneleditwater.h" + +#include "llslider.h" +#include "lltexturectrl.h" +#include "llcolorswatch.h" +#include "llxyvector.h" +#include "llviewercontrol.h" + +namespace +{ + const std::string FIELD_WATER_FOG_COLOR("water_fog_color"); + const std::string FIELD_WATER_FOG_DENSITY("water_fog_density"); + const std::string FIELD_WATER_UNDERWATER_MOD("water_underwater_mod"); + const std::string FIELD_WATER_NORMAL_MAP("water_normal_map"); + + const std::string FIELD_WATER_WAVE1_XY("water_wave1_xy"); + const std::string FIELD_WATER_WAVE2_XY("water_wave2_xy"); + + const std::string FIELD_WATER_NORMAL_SCALE_X("water_normal_scale_x"); + const std::string FIELD_WATER_NORMAL_SCALE_Y("water_normal_scale_y"); + const std::string FIELD_WATER_NORMAL_SCALE_Z("water_normal_scale_z"); + + const std::string FIELD_WATER_FRESNEL_SCALE("water_fresnel_scale"); + const std::string FIELD_WATER_FRESNEL_OFFSET("water_fresnel_offset"); + + const std::string FIELD_WATER_SCALE_ABOVE("water_scale_above"); + const std::string FIELD_WATER_SCALE_BELOW("water_scale_below"); + const std::string FIELD_WATER_BLUR_MULTIP("water_blur_multip"); +} + +static LLPanelInjector<LLPanelSettingsWaterMainTab> t_settings_water("panel_settings_water"); + +//========================================================================== +LLPanelSettingsWater::LLPanelSettingsWater() : + LLSettingsEditPanel(), + mWaterSettings() +{ + +} + + +//========================================================================== +LLPanelSettingsWaterMainTab::LLPanelSettingsWaterMainTab(): + LLPanelSettingsWater(), + mClrFogColor(nullptr), + mTxtNormalMap(nullptr) +{ +} + + +BOOL LLPanelSettingsWaterMainTab::postBuild() +{ + mClrFogColor = getChild<LLColorSwatchCtrl>(FIELD_WATER_FOG_COLOR); + mTxtNormalMap = getChild<LLTextureCtrl>(FIELD_WATER_NORMAL_MAP); + + getChild<LLXYVector>(FIELD_WATER_WAVE1_XY)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onLargeWaveChanged(); }); + + mClrFogColor->setCommitCallback([this](LLUICtrl *, const LLSD &) { onFogColorChanged(); }); + getChild<LLUICtrl>(FIELD_WATER_FOG_DENSITY)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onFogDensityChanged(); }); +// getChild<LLUICtrl>(FIELD_WATER_FOG_DENSITY)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onFogDensityChanged(getChild<LLUICtrl>(FIELD_WATER_FOG_DENSITY)->getValue().asReal()); }); + getChild<LLUICtrl>(FIELD_WATER_UNDERWATER_MOD)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onFogUnderWaterChanged(); }); + + mTxtNormalMap->setDefaultImageAssetID(LLSettingsWater::GetDefaultWaterNormalAssetId()); + mTxtNormalMap->setBlankImageAssetID(LLUUID( gSavedSettings.getString( "DefaultBlankNormalTexture" ))); + mTxtNormalMap->setCommitCallback([this](LLUICtrl *, const LLSD &) { onNormalMapChanged(); }); + + getChild<LLUICtrl>(FIELD_WATER_WAVE2_XY)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onSmallWaveChanged(); }); + + getChild<LLUICtrl>(FIELD_WATER_NORMAL_SCALE_X)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onNormalScaleChanged(); }); + getChild<LLUICtrl>(FIELD_WATER_NORMAL_SCALE_Y)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onNormalScaleChanged(); }); + getChild<LLUICtrl>(FIELD_WATER_NORMAL_SCALE_Z)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onNormalScaleChanged(); }); + + getChild<LLUICtrl>(FIELD_WATER_FRESNEL_SCALE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onFresnelScaleChanged(); }); + getChild<LLUICtrl>(FIELD_WATER_FRESNEL_OFFSET)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onFresnelOffsetChanged(); }); + getChild<LLUICtrl>(FIELD_WATER_SCALE_ABOVE)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onScaleAboveChanged(); }); + getChild<LLUICtrl>(FIELD_WATER_SCALE_BELOW)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onScaleBelowChanged(); }); + getChild<LLUICtrl>(FIELD_WATER_BLUR_MULTIP)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onBlurMultipChanged(); }); + + refresh(); + + return TRUE; +} + +//virtual +void LLPanelSettingsWaterMainTab::setEnabled(BOOL enabled) +{ + LLPanelSettingsWater::setEnabled(enabled); + getChild<LLUICtrl>(FIELD_WATER_FOG_DENSITY)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_WATER_UNDERWATER_MOD)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_WATER_FRESNEL_SCALE)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_WATER_FRESNEL_OFFSET)->setEnabled(enabled); + + getChild<LLUICtrl>(FIELD_WATER_NORMAL_SCALE_X)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_WATER_NORMAL_SCALE_Y)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_WATER_NORMAL_SCALE_Z)->setEnabled(enabled); + + getChild<LLUICtrl>(FIELD_WATER_SCALE_ABOVE)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_WATER_SCALE_BELOW)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_WATER_BLUR_MULTIP)->setEnabled(enabled); +} + +//========================================================================== +void LLPanelSettingsWaterMainTab::refresh() +{ + if (!mWaterSettings) + { + setAllChildrenEnabled(FALSE); + setEnabled(FALSE); + return; + } + + setEnabled(getCanChangeSettings()); + setAllChildrenEnabled(getCanChangeSettings()); + mClrFogColor->set(mWaterSettings->getWaterFogColor()); + getChild<LLUICtrl>(FIELD_WATER_FOG_DENSITY)->setValue(mWaterSettings->getWaterFogDensity()); + getChild<LLUICtrl>(FIELD_WATER_UNDERWATER_MOD)->setValue(mWaterSettings->getFogMod()); + mTxtNormalMap->setValue(mWaterSettings->getNormalMapID()); + LLVector2 vect2 = mWaterSettings->getWave1Dir() * -1.0; // Flip so that north and east are + + getChild<LLUICtrl>(FIELD_WATER_WAVE1_XY)->setValue(vect2.getValue()); + vect2 = mWaterSettings->getWave2Dir() * -1.0; // Flip so that north and east are + + getChild<LLUICtrl>(FIELD_WATER_WAVE2_XY)->setValue(vect2.getValue()); + LLVector3 vect3 = mWaterSettings->getNormalScale(); + getChild<LLUICtrl>(FIELD_WATER_NORMAL_SCALE_X)->setValue(vect3[0]); + getChild<LLUICtrl>(FIELD_WATER_NORMAL_SCALE_Y)->setValue(vect3[1]); + getChild<LLUICtrl>(FIELD_WATER_NORMAL_SCALE_Z)->setValue(vect3[2]); + getChild<LLUICtrl>(FIELD_WATER_FRESNEL_SCALE)->setValue(mWaterSettings->getFresnelScale()); + getChild<LLUICtrl>(FIELD_WATER_FRESNEL_OFFSET)->setValue(mWaterSettings->getFresnelOffset()); + getChild<LLUICtrl>(FIELD_WATER_SCALE_ABOVE)->setValue(mWaterSettings->getScaleAbove()); + getChild<LLUICtrl>(FIELD_WATER_SCALE_BELOW)->setValue(mWaterSettings->getScaleBelow()); + getChild<LLUICtrl>(FIELD_WATER_BLUR_MULTIP)->setValue(mWaterSettings->getBlurMultiplier()); +} + +//========================================================================== + +void LLPanelSettingsWaterMainTab::onFogColorChanged() +{ + if (!mWaterSettings) return; + mWaterSettings->setWaterFogColor(LLColor3(mClrFogColor->get())); + setIsDirty(); +} + +void LLPanelSettingsWaterMainTab::onFogDensityChanged() +{ + if (!mWaterSettings) return; + mWaterSettings->setWaterFogDensity(getChild<LLUICtrl>(FIELD_WATER_FOG_DENSITY)->getValue().asReal()); + setIsDirty(); +} + +void LLPanelSettingsWaterMainTab::onFogUnderWaterChanged() +{ + if (!mWaterSettings) return; + mWaterSettings->setFogMod(getChild<LLUICtrl>(FIELD_WATER_UNDERWATER_MOD)->getValue().asReal()); + setIsDirty(); +} + +void LLPanelSettingsWaterMainTab::onNormalMapChanged() +{ + if (!mWaterSettings) return; + mWaterSettings->setNormalMapID(mTxtNormalMap->getImageAssetID()); + setIsDirty(); +} + +void LLPanelSettingsWaterMainTab::onLargeWaveChanged() +{ + if (!mWaterSettings) return; + LLVector2 vect(getChild<LLUICtrl>(FIELD_WATER_WAVE1_XY)->getValue()); + vect *= -1.0; // Flip so that north and east are - + mWaterSettings->setWave1Dir(vect); + setIsDirty(); +} + +void LLPanelSettingsWaterMainTab::onSmallWaveChanged() +{ + if (!mWaterSettings) return; + LLVector2 vect(getChild<LLUICtrl>(FIELD_WATER_WAVE2_XY)->getValue()); + vect *= -1.0; // Flip so that north and east are - + mWaterSettings->setWave2Dir(vect); + setIsDirty(); +} + + +void LLPanelSettingsWaterMainTab::onNormalScaleChanged() +{ + if (!mWaterSettings) return; + LLVector3 vect(getChild<LLUICtrl>(FIELD_WATER_NORMAL_SCALE_X)->getValue().asReal(), getChild<LLUICtrl>(FIELD_WATER_NORMAL_SCALE_Y)->getValue().asReal(), getChild<LLUICtrl>(FIELD_WATER_NORMAL_SCALE_Z)->getValue().asReal()); + mWaterSettings->setNormalScale(vect); + setIsDirty(); +} + +void LLPanelSettingsWaterMainTab::onFresnelScaleChanged() +{ + if (!mWaterSettings) return; + mWaterSettings->setFresnelScale(getChild<LLUICtrl>(FIELD_WATER_FRESNEL_SCALE)->getValue().asReal()); + setIsDirty(); +} + +void LLPanelSettingsWaterMainTab::onFresnelOffsetChanged() +{ + if (!mWaterSettings) return; + mWaterSettings->setFresnelOffset(getChild<LLUICtrl>(FIELD_WATER_FRESNEL_OFFSET)->getValue().asReal()); + setIsDirty(); +} + +void LLPanelSettingsWaterMainTab::onScaleAboveChanged() +{ + if (!mWaterSettings) return; + mWaterSettings->setScaleAbove(getChild<LLUICtrl>(FIELD_WATER_SCALE_ABOVE)->getValue().asReal()); + setIsDirty(); +} + +void LLPanelSettingsWaterMainTab::onScaleBelowChanged() +{ + if (!mWaterSettings) return; + mWaterSettings->setScaleBelow(getChild<LLUICtrl>(FIELD_WATER_SCALE_BELOW)->getValue().asReal()); + setIsDirty(); +} + +void LLPanelSettingsWaterMainTab::onBlurMultipChanged() +{ + if (!mWaterSettings) return; + mWaterSettings->setBlurMultiplier(getChild<LLUICtrl>(FIELD_WATER_BLUR_MULTIP)->getValue().asReal()); + setIsDirty(); +} diff --git a/indra/newview/llpaneleditwater.h b/indra/newview/llpaneleditwater.h new file mode 100644 index 0000000000..4b7ec903c9 --- /dev/null +++ b/indra/newview/llpaneleditwater.h @@ -0,0 +1,98 @@ +/** +* @file llpaneleditwater.h +* @brief Panels for water settings +* +* $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 LLPANEL_EDIT_WATER_H +#define LLPANEL_EDIT_WATER_H + +#include "llpanel.h" +#include "llsettingswater.h" + +#include "llfloatereditenvironmentbase.h" + +//========================================================================= +class LLSlider; +class LLColorSwatchCtrl; +class LLTextureCtrl; +class LLXYVector; + +//========================================================================= +class LLPanelSettingsWater : public LLSettingsEditPanel +{ + LOG_CLASS(LLPanelSettingsWater); + +public: + LLPanelSettingsWater(); + + virtual void setSettings(const LLSettingsBase::ptr_t &settings) override { setWater(std::static_pointer_cast<LLSettingsWater>(settings)); } + + LLSettingsWater::ptr_t getWater() const { return mWaterSettings; } + void setWater(const LLSettingsWater::ptr_t &water) { mWaterSettings = water; clearIsDirty(); refresh(); } + +protected: + LLSettingsWater::ptr_t mWaterSettings; +}; + +// *RIDER* In this case this split is unecessary since there is only a single +// tab page for water settings at this point. However more may be added in the +// future and I want to reinforce the pattern used for sky/atmosphere tabs. +class LLPanelSettingsWaterMainTab : public LLPanelSettingsWater +{ + LOG_CLASS(LLPanelSettingsWaterMainTab); + +public: + LLPanelSettingsWaterMainTab(); + + virtual BOOL postBuild() override; + virtual void setEnabled(BOOL enabled) override; + +protected: + virtual void refresh() override; + +private: + + LLColorSwatchCtrl * mClrFogColor; +// LLSlider * mSldFogDensity; +// LLSlider * mSldUnderWaterMod; + LLTextureCtrl * mTxtNormalMap; + + void onFogColorChanged(); + void onFogDensityChanged(); + void onFogUnderWaterChanged(); + void onNormalMapChanged(); + + void onLargeWaveChanged(); + void onSmallWaveChanged(); + + void onNormalScaleChanged(); + void onFresnelScaleChanged(); + void onFresnelOffsetChanged(); + void onScaleAboveChanged(); + void onScaleBelowChanged(); + void onBlurMultipChanged(); +}; + + +#endif // LLPANEL_EDIT_WATER_H diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 6573be0aaf..c601a6c210 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -778,7 +778,7 @@ BOOL LLPanelEditWearable::postBuild() LL_WARNS() << "could not get wearable dictionary entry for wearable of type: " << type << LL_ENDL; continue; } - U8 num_subparts = wearable_entry->mSubparts.size(); + U8 num_subparts = (U8)(wearable_entry->mSubparts.size()); for (U8 index = 0; index < num_subparts; ++index) { @@ -1181,7 +1181,7 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO updatePanelPickerControls(type); // clear and rebuild visual param list - U8 num_subparts = wearable_entry->mSubparts.size(); + U8 num_subparts = (U8)(wearable_entry->mSubparts.size()); for (U8 index = 0; index < num_subparts; ++index) { @@ -1372,7 +1372,7 @@ void LLPanelEditWearable::updateScrollingPanelUI() const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(type); llassert(wearable_entry); if (!wearable_entry) return; - U8 num_subparts = wearable_entry->mSubparts.size(); + U8 num_subparts = (U8)(wearable_entry->mSubparts.size()); LLScrollingPanelParam::sUpdateDelayFrames = 0; for (U8 index = 0; index < num_subparts; ++index) diff --git a/indra/newview/llpanelenvironment.cpp b/indra/newview/llpanelenvironment.cpp new file mode 100644 index 0000000000..2ad7a23278 --- /dev/null +++ b/indra/newview/llpanelenvironment.cpp @@ -0,0 +1,1178 @@ +/** + * @file llpanelenvironment.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 "llpanelprofile.h" +#include "lluictrlfactory.h" +#include "llexperiencecache.h" +#include "llagent.h" +#include "llparcel.h" + +#include "llviewerregion.h" +#include "llpanelenvironment.h" +#include "llslurl.h" +#include "lllayoutstack.h" + +#include "llfloater.h" +#include "llfloaterreg.h" +#include "llfloatereditextdaycycle.h" +#include "llmultisliderctrl.h" +#include "llnotificationsutil.h" +#include "llsettingsvo.h" + +#include "llappviewer.h" +#include "llcallbacklist.h" +#include "llviewerparcelmgr.h" + +#include "llinventorymodel.h" + +//========================================================================= +namespace +{ + const std::string FLOATER_DAY_CYCLE_EDIT("env_edit_extdaycycle"); + const std::string STRING_REGION_ENV("str_region_env"); + const std::string STRING_EMPTY_NAME("str_empty"); + + inline bool ends_with(std::string const & value, std::string const & ending) + { + if (ending.size() > value.size()) + return false; + return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); + } + +} + +//========================================================================= +const std::string LLPanelEnvironmentInfo::BTN_SELECTINV("btn_select_inventory"); +const std::string LLPanelEnvironmentInfo::BTN_EDIT("btn_edit"); +const std::string LLPanelEnvironmentInfo::BTN_USEDEFAULT("btn_usedefault"); +const std::string LLPanelEnvironmentInfo::BTN_RST_ALTITUDES("btn_rst_altitudes"); +const std::string LLPanelEnvironmentInfo::SLD_DAYLENGTH("sld_day_length"); +const std::string LLPanelEnvironmentInfo::SLD_DAYOFFSET("sld_day_offset"); +const std::string LLPanelEnvironmentInfo::SLD_ALTITUDES("sld_altitudes"); +const std::string LLPanelEnvironmentInfo::ICN_GROUND("icon_ground"); +const std::string LLPanelEnvironmentInfo::ICN_WATER("icon_water"); +const std::string LLPanelEnvironmentInfo::CHK_ALLOWOVERRIDE("chk_allow_override"); +const std::string LLPanelEnvironmentInfo::LBL_TIMEOFDAY("lbl_apparent_time"); +const std::string LLPanelEnvironmentInfo::PNL_SETTINGS("pnl_environment_config"); +const std::string LLPanelEnvironmentInfo::PNL_ENVIRONMENT_ALTITUDES("pnl_environment_altitudes"); +const std::string LLPanelEnvironmentInfo::PNL_BUTTONS("pnl_environment_buttons"); +const std::string LLPanelEnvironmentInfo::PNL_DISABLED("pnl_environment_disabled"); +const std::string LLPanelEnvironmentInfo::TXT_DISABLED("txt_environment_disabled"); +const std::string LLPanelEnvironmentInfo::PNL_REGION_MSG("pnl_environment_region_msg"); +const std::string LLPanelEnvironmentInfo::SDT_DROP_TARGET("sdt_drop_target"); + +const std::string LLPanelEnvironmentInfo::STR_LABEL_USEDEFAULT("str_label_use_default"); +const std::string LLPanelEnvironmentInfo::STR_LABEL_USEREGION("str_label_use_region"); +const std::string LLPanelEnvironmentInfo::STR_ALTITUDE_DESCRIPTION("str_altitude_desription"); +const std::string LLPanelEnvironmentInfo::STR_NO_PARCEL("str_no_parcel"); +const std::string LLPanelEnvironmentInfo::STR_CROSS_REGION("str_cross_region"); +const std::string LLPanelEnvironmentInfo::STR_LEGACY("str_legacy"); +const std::string LLPanelEnvironmentInfo::STR_DISALLOWED("str_disallowed"); +const std::string LLPanelEnvironmentInfo::STR_TOO_SMALL("str_too_small"); + +const S32 LLPanelEnvironmentInfo::MINIMUM_PARCEL_SIZE(128); + +const U32 LLPanelEnvironmentInfo::DIRTY_FLAG_DAYCYCLE(0x01 << 0); +const U32 LLPanelEnvironmentInfo::DIRTY_FLAG_DAYLENGTH(0x01 << 1); +const U32 LLPanelEnvironmentInfo::DIRTY_FLAG_DAYOFFSET(0x01 << 2); +const U32 LLPanelEnvironmentInfo::DIRTY_FLAG_ALTITUDES(0x01 << 3); + +const U32 LLPanelEnvironmentInfo::DIRTY_FLAG_MASK( + LLPanelEnvironmentInfo::DIRTY_FLAG_DAYCYCLE | + LLPanelEnvironmentInfo::DIRTY_FLAG_DAYLENGTH | + LLPanelEnvironmentInfo::DIRTY_FLAG_DAYOFFSET | + LLPanelEnvironmentInfo::DIRTY_FLAG_ALTITUDES); + +const U32 ALTITUDE_SLIDER_COUNT = 3; +const F32 ALTITUDE_DEFAULT_HEIGHT_STEP = 1000; +const U32 ALTITUDE_MARKERS_COUNT = 3; +const U32 ALTITUDE_PREFIXERS_COUNT = 5; + +const std::string slider_marker_base = "mark"; + +const std::string alt_sliders[] = { + "sld1", + "sld2", + "sld3", +}; + +const std::string alt_prefixes[] = { + "alt1", + "alt2", + "alt3", + "ground", + "water", +}; + +const std::string alt_panels[] = { + "pnl_alt1", + "pnl_alt2", + "pnl_alt3", + "pnl_ground", + "pnl_water", +}; + +static LLDefaultChildRegistry::Register<LLSettingsDropTarget> r("settings_drop_target"); + +//========================================================================= +LLPanelEnvironmentInfo::LLPanelEnvironmentInfo(): + mCurrentEnvironment(), + mDirtyFlag(0), + mEditorLastParcelId(INVALID_PARCEL_ID), + mCrossRegion(false), + mNoSelection(false), + mNoEnvironment(false), + mCurEnvVersion(INVALID_PARCEL_ENVIRONMENT_VERSION), + mSettingsFloater(), + mEditFloater(), + mAllowOverride(true) +{ +} + +LLPanelEnvironmentInfo::~LLPanelEnvironmentInfo() +{ + if (mChangeMonitor.connected()) + mChangeMonitor.disconnect(); + if (mCommitConnection.connected()) + mCommitConnection.disconnect(); + if (mUpdateConnection.connected()) + mUpdateConnection.disconnect(); +} + +BOOL LLPanelEnvironmentInfo::postBuild() +{ + + getChild<LLUICtrl>(BTN_USEDEFAULT)->setCommitCallback([this](LLUICtrl *, const LLSD &){ onBtnDefault(); }); + getChild<LLUICtrl>(BTN_SELECTINV)->setCommitCallback([this](LLUICtrl *, const LLSD &){ onBtnSelect(); }); + getChild<LLUICtrl>(BTN_EDIT)->setCommitCallback([this](LLUICtrl *, const LLSD &){ onBtnEdit(); }); + getChild<LLUICtrl>(BTN_RST_ALTITUDES)->setCommitCallback([this](LLUICtrl *, const LLSD &){ onBtnRstAltitudes(); }); + + getChild<LLUICtrl>(SLD_DAYLENGTH)->setCommitCallback([this](LLUICtrl *, const LLSD &value) { onSldDayLengthChanged(value.asReal()); }); + getChild<LLSliderCtrl>(SLD_DAYLENGTH)->setSliderMouseUpCallback([this](LLUICtrl *, const LLSD &) { onDayLenOffsetMouseUp(); }); + getChild<LLSliderCtrl>(SLD_DAYLENGTH)->setSliderEditorCommitCallback([this](LLUICtrl *, const LLSD &) { onDayLenOffsetMouseUp(); }); + getChild<LLUICtrl>(SLD_DAYOFFSET)->setCommitCallback([this](LLUICtrl *, const LLSD &value) { onSldDayOffsetChanged(value.asReal()); }); + getChild<LLSliderCtrl>(SLD_DAYOFFSET)->setSliderMouseUpCallback([this](LLUICtrl *, const LLSD &) { onDayLenOffsetMouseUp(); }); + getChild<LLSliderCtrl>(SLD_DAYOFFSET)->setSliderEditorCommitCallback([this](LLUICtrl *, const LLSD &) { onDayLenOffsetMouseUp(); }); + + getChild<LLMultiSliderCtrl>(SLD_ALTITUDES)->setCommitCallback([this](LLUICtrl *cntrl, const LLSD &value) { onAltSliderCallback(cntrl, value); }); + getChild<LLMultiSliderCtrl>(SLD_ALTITUDES)->setSliderMouseUpCallback([this](LLUICtrl *, const LLSD &) { onAltSliderMouseUp(); }); + + mChangeMonitor = LLEnvironment::instance().setEnvironmentChanged([this](LLEnvironment::EnvSelection_t env, S32 version) { onEnvironmentChanged(env, version); }); + + for (U32 idx = 0; idx < ALTITUDE_SLIDER_COUNT; idx++) + { + LLSettingsDropTarget* drop_target = findChild<LLSettingsDropTarget>("sdt_" + alt_prefixes[idx]); + if (drop_target) + { + drop_target->setPanel(this, alt_sliders[idx]); + } + // set initial values to prevent [ALTITUDE] from displaying + updateAltLabel(alt_prefixes[idx], idx + 2, idx * 1000); + } + getChild<LLSettingsDropTarget>("sdt_" + alt_prefixes[3])->setPanel(this, alt_prefixes[3]); + getChild<LLSettingsDropTarget>("sdt_" + alt_prefixes[4])->setPanel(this, alt_prefixes[4]); + + return TRUE; +} + +// virtual +void LLPanelEnvironmentInfo::onOpen(const LLSD& key) +{ + refreshFromSource(); +} + +// virtual +void LLPanelEnvironmentInfo::onVisibilityChange(BOOL new_visibility) +{ + if (new_visibility) + { + gIdleCallbacks.addFunction(onIdlePlay, this); + } + else + { + commitDayLenOffsetChanges(false); // arrow-key changes + + LLFloaterSettingsPicker *picker = getSettingsPicker(false); + if (picker) + { + picker->closeFloater(); + } + + gIdleCallbacks.deleteFunction(onIdlePlay, this); + LLFloaterEditExtDayCycle *dayeditor = getEditFloater(false); + if (mCommitConnection.connected()) + mCommitConnection.disconnect(); + + if (dayeditor) + { + if (dayeditor->isDirty()) + dayeditor->refresh(); + else + { + dayeditor->closeFloater(); + mEditFloater.markDead(); + } + } + } + +} + +void LLPanelEnvironmentInfo::refresh() +{ + if (gDisconnected) + return; + + if (!setControlsEnabled(canEdit())) + return; + + if (!mCurrentEnvironment) + { + return; + } + + F32Hours daylength(mCurrentEnvironment->mDayLength); + F32Hours dayoffset(mCurrentEnvironment->mDayOffset); + + if (dayoffset.value() > 12.0f) + dayoffset -= F32Hours(24.0); + + getChild<LLSliderCtrl>(SLD_DAYLENGTH)->setValue(daylength.value()); + getChild<LLSliderCtrl>(SLD_DAYOFFSET)->setValue(dayoffset.value()); + + udpateApparentTimeOfDay(); + + updateEditFloater(mCurrentEnvironment, canEdit()); + + LLEnvironment::altitude_list_t altitudes = mCurrentEnvironment->mAltitudes; + + if (altitudes.size() > 0) + { + LLMultiSliderCtrl *sld = getChild<LLMultiSliderCtrl>(SLD_ALTITUDES); + sld->clear(); + + for (S32 idx = 0; idx < ALTITUDE_SLIDER_COUNT; ++idx) + { + // make sure values are in range, server is supposed to validate them, + // but issues happen, try to fix values in such case + F32 altitude = llclamp(altitudes[idx + 1], sld->getMinValue(), sld->getMaxValue()); + bool res = sld->addSlider(altitude, alt_sliders[idx]); + if (!res) + { + LL_WARNS_ONCE("ENVPANEL") << "Failed to validate altitude from server for parcel id" << getParcelId() << LL_ENDL; + // Find a spot to insert altitude. + // Assuming everything alright with slider, we should find new place in 11 steps top (step 25m, no overlap 100m) + F32 alt_step = (altitude > (sld->getMaxValue() / 2)) ? -sld->getIncrement() : sld->getIncrement(); + for (U32 i = 0; i < 30; i++) + { + altitude += alt_step; + if (altitude > sld->getMaxValue()) + { + altitude = sld->getMinValue(); + } + else if (altitude < sld->getMinValue()) + { + altitude = sld->getMaxValue(); + } + res = sld->addSlider(altitude, alt_sliders[idx]); + if (res) break; + } + } + if (res) + { + // slider has some auto correction that might have kicked in + altitude = sld->getSliderValue(alt_sliders[idx]); + } + else + { + // Something is very very wrong + LL_WARNS_ONCE("ENVPANEL") << "Failed to set up altitudes for parcel id " << getParcelId() << LL_ENDL; + } + updateAltLabel(alt_prefixes[idx], idx + 2, altitude); + mAltitudes[alt_sliders[idx]] = AltitudeData(idx + 2, idx, altitude); + } + if (sld->getCurNumSliders() != ALTITUDE_SLIDER_COUNT) + { + LL_WARNS("ENVPANEL") << "Failed to add altitude sliders!" << LL_ENDL; + } + readjustAltLabels(); + sld->resetCurSlider(); + } + + updateAltLabel(alt_prefixes[3], 1, 0); // ground + updateAltLabel(alt_prefixes[4], 0, 0); // water + +} + +void LLPanelEnvironmentInfo::refreshFromEstate() +{ + LLViewerRegion *pRegion = gAgent.getRegion(); + + bool oldAO = mAllowOverride; + mAllowOverride = (isRegion() && LLEstateInfoModel::instance().getAllowEnvironmentOverride()) || pRegion->getAllowEnvironmentOverride(); + if (oldAO != mAllowOverride) + refresh(); +} + +std::string LLPanelEnvironmentInfo::getNameForTrackIndex(S32 index) +{ + std::string invname; + if (!mCurrentEnvironment || index < LLSettingsDay::TRACK_WATER || index >= LLSettingsDay::TRACK_MAX) + { + invname = getString(STRING_EMPTY_NAME); + } + else if (mCurrentEnvironment->mDayCycleName.empty()) + { + invname = mCurrentEnvironment->mNameList[index]; + + if (invname.empty()) + { + if (index <= LLSettingsDay::TRACK_GROUND_LEVEL) + invname = getString(isRegion() ? STRING_EMPTY_NAME : STRING_REGION_ENV); + } + } + else if (!mCurrentEnvironment->mDayCycle->isTrackEmpty(index)) + { + invname = mCurrentEnvironment->mDayCycleName; + } + + + if (invname.empty()) + { + invname = getNameForTrackIndex(index - 1); + if (invname[0] != '(') + invname = "(" + invname + ")"; + } + + return invname; +} + +LLFloaterSettingsPicker * LLPanelEnvironmentInfo::getSettingsPicker(bool create) +{ + LLFloaterSettingsPicker *picker = static_cast<LLFloaterSettingsPicker *>(mSettingsFloater.get()); + + // Show the dialog + if (!picker && create) + { + picker = new LLFloaterSettingsPicker(this, + LLUUID::null); + + mSettingsFloater = picker->getHandle(); + + picker->setCommitCallback([this](LLUICtrl *, const LLSD &data){ onPickerCommitted(data["ItemId"].asUUID()); }); + } + + return picker; +} + +LLFloaterEditExtDayCycle * LLPanelEnvironmentInfo::getEditFloater(bool create) +{ + static const S32 FOURHOURS(4 * 60 * 60); + LLFloaterEditExtDayCycle *editor = static_cast<LLFloaterEditExtDayCycle *>(mEditFloater.get()); + + // Show the dialog + if (!editor && create) + { + LLSD params(LLSDMap(LLFloaterEditExtDayCycle::KEY_EDIT_CONTEXT, isRegion() ? LLFloaterEditExtDayCycle::CONTEXT_REGION : LLFloaterEditExtDayCycle::CONTEXT_PARCEL) + (LLFloaterEditExtDayCycle::KEY_DAY_LENGTH, mCurrentEnvironment ? (S32)(mCurrentEnvironment->mDayLength.value()) : FOURHOURS)); + + editor = (LLFloaterEditExtDayCycle *)LLFloaterReg::getInstance(FLOATER_DAY_CYCLE_EDIT, params); + + if (!editor) + return nullptr; + mEditFloater = editor->getHandle(); + } + + if (editor && !mCommitConnection.connected()) + mCommitConnection = editor->setEditCommitSignal([this](LLSettingsDay::ptr_t pday) { onEditCommitted(pday); }); + + return editor; +} + + +void LLPanelEnvironmentInfo::updateEditFloater(const LLEnvironment::EnvironmentInfo::ptr_t &nextenv, bool enable) +{ + LLFloaterEditExtDayCycle *dayeditor(getEditFloater(false)); + + if (!dayeditor || !dayeditor->isInVisibleChain()) + return; + + if (!nextenv || !nextenv->mDayCycle || !enable) + { + if (mCommitConnection.connected()) + mCommitConnection.disconnect(); + + if (dayeditor->isDirty()) + dayeditor->refresh(); + else + dayeditor->closeFloater(); + } + else if (dayeditor->getEditingAssetId() != nextenv->mDayCycle->getAssetId() + || mEditorLastParcelId != nextenv->mParcelId + || mEditorLastRegionId != nextenv->mRegionId) + { + // Ignore dirty + // If parcel selection changed whatever we do except saving to inventory with + // old settings will be invalid. + mEditorLastParcelId = nextenv->mParcelId; + mEditorLastRegionId = nextenv->mRegionId; + + dayeditor->setEditDayCycle(nextenv->mDayCycle); + } +} + +bool LLPanelEnvironmentInfo::setControlsEnabled(bool enabled) +{ + bool is_unavailable(false); + bool is_legacy = (mCurrentEnvironment) ? mCurrentEnvironment->mIsLegacy : true; + bool is_bigenough = isLargeEnough(); + + if (mNoEnvironment || (!LLEnvironment::instance().isExtendedEnvironmentEnabled() && !isRegion())) + { + is_unavailable = true; + getChild<LLTextBox>(TXT_DISABLED)->setText(getString(STR_LEGACY)); + } + else if (mNoSelection) + { + is_unavailable = true; + getChild<LLTextBox>(TXT_DISABLED)->setText(getString(STR_NO_PARCEL)); + } + else if (mCrossRegion) + { + is_unavailable = true; + getChild<LLTextBox>(TXT_DISABLED)->setText(getString(STR_CROSS_REGION)); + } + else if (!isRegion() && !mAllowOverride) + { + is_unavailable = true; + getChild<LLTextBox>(TXT_DISABLED)->setText(getString(STR_DISALLOWED)); + } + else if (!is_bigenough) + { + is_unavailable = true; + getChild<LLTextBox>(TXT_DISABLED)->setText(getString(STR_TOO_SMALL)); + } + + if (is_unavailable) + { + getChild<LLUICtrl>(PNL_SETTINGS)->setVisible(false); + getChild<LLUICtrl>(PNL_BUTTONS)->setVisible(false); + getChild<LLUICtrl>(PNL_DISABLED)->setVisible(true); + getChild<LLUICtrl>(PNL_ENVIRONMENT_ALTITUDES)->setVisible(false); + getChild<LLUICtrl>(PNL_REGION_MSG)->setVisible(false); + updateEditFloater(mCurrentEnvironment, false); + + return false; + } + getChild<LLUICtrl>(PNL_SETTINGS)->setVisible(true); + getChild<LLUICtrl>(PNL_BUTTONS)->setVisible(true); + getChild<LLUICtrl>(PNL_DISABLED)->setVisible(false); + getChild<LLUICtrl>(PNL_REGION_MSG)->setVisible(isRegion()); + + getChild<LLUICtrl>(PNL_ENVIRONMENT_ALTITUDES)->setVisible(LLEnvironment::instance().isExtendedEnvironmentEnabled()); + getChild<LLUICtrl>(BTN_RST_ALTITUDES)->setVisible(isRegion()); + + bool can_enable = enabled && !is_legacy && mCurrentEnvironment && (mCurEnvVersion != INVALID_PARCEL_ENVIRONMENT_VERSION); + getChild<LLUICtrl>(BTN_SELECTINV)->setEnabled(can_enable); + getChild<LLUICtrl>(BTN_USEDEFAULT)->setEnabled(can_enable); + getChild<LLUICtrl>(BTN_EDIT)->setEnabled(can_enable); + getChild<LLUICtrl>(SLD_DAYLENGTH)->setEnabled(can_enable); + getChild<LLUICtrl>(SLD_DAYOFFSET)->setEnabled(can_enable); + getChild<LLUICtrl>(SLD_ALTITUDES)->setEnabled(can_enable && isRegion()); + getChild<LLUICtrl>(ICN_GROUND)->setColor((can_enable && isRegion()) ? LLColor4::white : LLColor4::grey % 0.8f); + getChild<LLUICtrl>(ICN_WATER)->setColor((can_enable && isRegion()) ? LLColor4::white : LLColor4::grey % 0.8f); + getChild<LLUICtrl>(BTN_RST_ALTITUDES)->setEnabled(can_enable && isRegion()); + getChild<LLUICtrl>(PNL_ENVIRONMENT_ALTITUDES)->setEnabled(can_enable); + getChild<LLUICtrl>(CHK_ALLOWOVERRIDE)->setEnabled(can_enable && isRegion()); + + for (U32 idx = 0; idx < ALTITUDE_MARKERS_COUNT; idx++) + { + LLUICtrl* marker = findChild<LLUICtrl>(slider_marker_base + llformat("%u", idx)); + if (marker) + { + static LLColor4 marker_color(0.75f, 0.75f, 0.75f, 1.f); + marker->setColor((can_enable && isRegion()) ? marker_color : marker_color % 0.3f); + } + } + + for (U32 idx = 0; idx < ALTITUDE_PREFIXERS_COUNT; idx++) + { + LLSettingsDropTarget* drop_target = findChild<LLSettingsDropTarget>("sdt_" + alt_prefixes[idx]); + if (drop_target) + { + drop_target->setDndEnabled(can_enable); + } + } + + return true; +} + +void LLPanelEnvironmentInfo::setDirtyFlag(U32 flag) +{ + mDirtyFlag |= flag; +} + +void LLPanelEnvironmentInfo::clearDirtyFlag(U32 flag) +{ + mDirtyFlag &= ~flag; +} + +void LLPanelEnvironmentInfo::updateAltLabel(const std::string &alt_prefix, U32 sky_index, F32 alt_value) +{ + LLMultiSliderCtrl *sld = findChild<LLMultiSliderCtrl>(SLD_ALTITUDES); + if (!sld) + { + LL_WARNS() << "Failed to find slider " << SLD_ALTITUDES << LL_ENDL; + return; + } + LLRect sld_rect = sld->getRect(); + S32 sld_range = sld_rect.getHeight(); + S32 sld_bottom = sld_rect.mBottom; + S32 sld_offset = sld_rect.getWidth(); // Roughly identical to thumb's width in slider. + S32 pos = (sld_range - sld_offset) * ((alt_value - 100) / (4000 - 100)); + + // get related views + LLTextBox* text = findChild<LLTextBox>("txt_" + alt_prefix); + LLLineEditor *field = findChild<LLLineEditor>("edt_invname_" + alt_prefix); + LLView *alt_panel = findChild<LLView>("pnl_" + alt_prefix); + + if (text && (sky_index > 1)) + { + // update text + std::ostringstream convert; + convert << alt_value; + text->setTextArg("[ALTITUDE]", convert.str()); + convert.str(""); + convert.clear(); + convert << sky_index; + text->setTextArg("[INDEX]", convert.str()); + } + + if (field) + { + field->setText(getNameForTrackIndex(sky_index)); + } + + if (alt_panel && (sky_index > 1)) + { + // move containing panel + LLRect rect = alt_panel->getRect(); + S32 height = rect.getHeight(); + rect.mBottom = sld_bottom + (sld_offset / 2 + 1) + pos - (height / 2); + rect.mTop = rect.mBottom + height; + alt_panel->setRect(rect); + } + +} + +void LLPanelEnvironmentInfo::readjustAltLabels() +{ + // Re-adjust all labels + // Very simple "adjust after the fact" method + // Note: labels can be in any order + + LLMultiSliderCtrl *sld = findChild<LLMultiSliderCtrl>(SLD_ALTITUDES); + if (!sld) return; + + LLView* view_midle = NULL; + U32 midle_ind = 0; + S32 shift_up = 0; + S32 shift_down = 0; + LLRect sld_rect = sld->getRect(); + + // Find the middle one + for (U32 i = 0; i < ALTITUDE_SLIDER_COUNT; i++) + { + LLView* cmp_view = findChild<LLView>(alt_panels[i], true); + if (!cmp_view) return; + LLRect cmp_rect = cmp_view->getRect(); + S32 pos = 0; + shift_up = 0; + shift_down = 0; + + for (U32 j = 0; j < ALTITUDE_SLIDER_COUNT; j++) + { + if (i != j) + { + LLView* intr_view = findChild<LLView>(alt_panels[j], true); + if (!intr_view) return; + LLRect intr_rect = intr_view->getRect(); + if (cmp_rect.mBottom >= intr_rect.mBottom) + { + pos++; + } + if (intr_rect.mBottom <= cmp_rect.mTop && intr_rect.mBottom >= cmp_rect.mBottom) + { + shift_up = cmp_rect.mTop - intr_rect.mBottom; + } + else if (intr_rect.mTop >= cmp_rect.mBottom && intr_rect.mBottom <= cmp_rect.mBottom) + { + shift_down = cmp_rect.mBottom - intr_rect.mTop; + } + } + } + if (pos == 1) // middle + { + view_midle = cmp_view; + midle_ind = i; + break; + } + } + + // Account for edges + LLRect midle_rect = view_midle->getRect(); + F32 factor = 0.5f; + S32 edge_zone_height = midle_rect.getHeight() * 1.5f; + + if (midle_rect.mBottom - sld_rect.mBottom < edge_zone_height) + { + factor = 1 - ((midle_rect.mBottom - sld_rect.mBottom) / (edge_zone_height * 2)); + } + else if (sld_rect.mTop - midle_rect.mTop < edge_zone_height ) + { + factor = ((sld_rect.mTop - midle_rect.mTop) / (edge_zone_height * 2)); + } + + S32 shift_middle = (S32)(((F32)shift_down * factor) + ((F32)shift_up * (1.f - factor))); + shift_down = shift_down - shift_middle; + shift_up = shift_up - shift_middle; + + // fix crossings + for (U32 i = 0; i < ALTITUDE_SLIDER_COUNT; i++) + { + if (i != midle_ind) + { + LLView* trn_view = findChild<LLView>(alt_panels[i], true); + LLRect trn_rect = trn_view->getRect(); + + if (trn_rect.mBottom <= midle_rect.mTop && trn_rect.mBottom >= midle_rect.mBottom) + { + // Approximate shift + trn_rect.translate(0, shift_up); + trn_view->setRect(trn_rect); + } + else if (trn_rect.mTop >= midle_rect.mBottom && trn_rect.mBottom <= midle_rect.mBottom) + { + // Approximate shift + trn_rect.translate(0, shift_down); + trn_view->setRect(trn_rect); + } + } + } + + if (shift_middle != 0) + { + midle_rect.translate(0, -shift_middle); //reversed relative to others + view_midle->setRect(midle_rect); + } +} + +void LLPanelEnvironmentInfo::onSldDayLengthChanged(F32 value) +{ + if (mCurrentEnvironment) + { + F32Hours daylength(value); + + mCurrentEnvironment->mDayLength = daylength; + setDirtyFlag(DIRTY_FLAG_DAYLENGTH); + + udpateApparentTimeOfDay(); + } +} + +void LLPanelEnvironmentInfo::onSldDayOffsetChanged(F32 value) +{ + if (mCurrentEnvironment) + { + F32Hours dayoffset(value); + + if (dayoffset.value() <= 0.0f) + dayoffset += F32Hours(24.0); + + mCurrentEnvironment->mDayOffset = dayoffset; + setDirtyFlag(DIRTY_FLAG_DAYOFFSET); + + udpateApparentTimeOfDay(); + } +} + +void LLPanelEnvironmentInfo::onDayLenOffsetMouseUp() +{ + commitDayLenOffsetChanges(true); +} + +void LLPanelEnvironmentInfo::commitDayLenOffsetChanges(bool need_callback) +{ + if (mCurrentEnvironment && (getDirtyFlag() & (DIRTY_FLAG_DAYLENGTH | DIRTY_FLAG_DAYOFFSET))) + { + clearDirtyFlag(DIRTY_FLAG_DAYOFFSET); + clearDirtyFlag(DIRTY_FLAG_DAYLENGTH); + + LLHandle<LLPanel> that_h = getHandle(); + + if (need_callback) + { + LLEnvironment::instance().updateParcel(getParcelId(), + LLSettingsDay::ptr_t(), + mCurrentEnvironment->mDayLength.value(), + mCurrentEnvironment->mDayOffset.value(), + LLEnvironment::altitudes_vect_t(), + [that_h](S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envifo) { _onEnvironmentReceived(that_h, parcel_id, envifo); }); + } + else + { + LLEnvironment::instance().updateParcel(getParcelId(), + LLSettingsDay::ptr_t(), + mCurrentEnvironment->mDayLength.value(), + mCurrentEnvironment->mDayOffset.value(), + LLEnvironment::altitudes_vect_t()); + } + + } +} + +void LLPanelEnvironmentInfo::onAltSliderCallback(LLUICtrl *cntrl, const LLSD &data) +{ + LLMultiSliderCtrl *sld = (LLMultiSliderCtrl *)cntrl; + std::string sld_name = sld->getCurSlider(); + + if (sld_name.empty()) return; + + F32 sld_value = sld->getCurSliderValue(); + + mAltitudes[sld_name].mAltitude = sld_value; + + // update all labels since we could have jumped multiple and we will need to readjust + // (or sort by altitude, too little elements, so I didn't bother with efficiency) + altitudes_data_t::iterator end = mAltitudes.end(); + altitudes_data_t::iterator iter = mAltitudes.begin(); + altitudes_data_t::iterator iter2; + U32 new_index; + while (iter != end) + { + iter2 = mAltitudes.begin(); + new_index = 2; + while (iter2 != end) + { + if (iter->second.mAltitude > iter2->second.mAltitude) + { + new_index++; + } + iter2++; + } + iter->second.mTrackIndex = new_index; + + updateAltLabel(alt_prefixes[iter->second.mLabelIndex], iter->second.mTrackIndex, iter->second.mAltitude); + iter++; + } + + readjustAltLabels(); + setDirtyFlag(DIRTY_FLAG_ALTITUDES); +} + +void LLPanelEnvironmentInfo::onAltSliderMouseUp() +{ + if (isRegion() && (getDirtyFlag() & DIRTY_FLAG_ALTITUDES)) + { + clearDirtyFlag(DIRTY_FLAG_ALTITUDES); + clearDirtyFlag(DIRTY_FLAG_DAYLENGTH); + clearDirtyFlag(DIRTY_FLAG_DAYOFFSET); + + LLHandle<LLPanel> that_h = getHandle(); + LLEnvironment::altitudes_vect_t alts; + + for (auto alt : mAltitudes) + { + alts.push_back(alt.second.mAltitude); + } + setControlsEnabled(false); + LLEnvironment::instance().updateParcel(getParcelId(), + LLSettingsDay::ptr_t(), + mCurrentEnvironment ? mCurrentEnvironment->mDayLength.value() : -1, + mCurrentEnvironment ? mCurrentEnvironment->mDayOffset.value() : -1, + alts); + } +} + +void LLPanelEnvironmentInfo::onBtnDefault() +{ + LLHandle<LLPanel> that_h = getHandle(); + S32 parcel_id = getParcelId(); + LLNotificationsUtil::add("SettingsConfirmReset", LLSD(), LLSD(), + [that_h, parcel_id](const LLSD¬if, const LLSD&resp) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); + if (opt == 0) + { + LLEnvironment::instance().resetParcel(parcel_id, + [that_h](S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envifo) { _onEnvironmentReceived(that_h, parcel_id, envifo); }); + } + }); +} + +void LLPanelEnvironmentInfo::onBtnEdit() +{ + static const S32 FOURHOURS(4 * 60 * 60); + + LLFloaterEditExtDayCycle *dayeditor = getEditFloater(); + + LLSD params(LLSDMap(LLFloaterEditExtDayCycle::KEY_EDIT_CONTEXT, isRegion() ? LLFloaterEditExtDayCycle::VALUE_CONTEXT_REGION : LLFloaterEditExtDayCycle::VALUE_CONTEXT_PARCEL) + (LLFloaterEditExtDayCycle::KEY_DAY_LENGTH, mCurrentEnvironment ? (S32)(mCurrentEnvironment->mDayLength.value()) : FOURHOURS) + (LLFloaterEditExtDayCycle::KEY_CANMOD, LLSD::Boolean(true))); + + dayeditor->openFloater(params); + if (mCurrentEnvironment && mCurrentEnvironment->mDayCycle) + { + dayeditor->setEditDayCycle(mCurrentEnvironment->mDayCycle); + if (!ends_with(mCurrentEnvironment->mDayCycle->getName(), "(customized)")) + { + dayeditor->setEditName(mCurrentEnvironment->mDayCycle->getName() + "(customized)"); + } + } + else + dayeditor->setEditDefaultDayCycle(); +} + +void LLPanelEnvironmentInfo::onBtnSelect() +{ + LLFloaterSettingsPicker *picker = getSettingsPicker(); + if (picker) + { + LLUUID item_id; + if (mCurrentEnvironment && mCurrentEnvironment->mDayCycle) + { + item_id = LLFloaterSettingsPicker::findItemID(mCurrentEnvironment->mDayCycle->getAssetId(), false, false); + } + picker->setSettingsFilter(LLSettingsType::ST_NONE); + picker->setSettingsItemId(item_id); + picker->openFloater(); + picker->setFocus(TRUE); + } +} + +void LLPanelEnvironmentInfo::onBtnRstAltitudes() +{ + if (isRegion()) + { + LLHandle<LLPanel> that_h = getHandle(); + LLEnvironment::altitudes_vect_t alts; + + clearDirtyFlag(DIRTY_FLAG_ALTITUDES); + clearDirtyFlag(DIRTY_FLAG_DAYLENGTH); + clearDirtyFlag(DIRTY_FLAG_DAYOFFSET); + + for (S32 idx = 1; idx <= ALTITUDE_SLIDER_COUNT; ++idx) + { + F32 new_height = idx * ALTITUDE_DEFAULT_HEIGHT_STEP; + alts.push_back(new_height); + } + + LLEnvironment::instance().updateParcel(getParcelId(), + LLSettingsDay::ptr_t(), + mCurrentEnvironment ? mCurrentEnvironment->mDayLength.value() : -1, + mCurrentEnvironment ? mCurrentEnvironment->mDayOffset.value() : -1, + alts, + [that_h](S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envifo) { _onEnvironmentReceived(that_h, parcel_id, envifo); }); + } +} + +void LLPanelEnvironmentInfo::udpateApparentTimeOfDay() +{ + static const F32 SECONDSINDAY(24.0 * 60.0 * 60.0); + + if ((!mCurrentEnvironment) || (mCurrentEnvironment->mDayLength.value() < 1.0) || (mCurrentEnvironment->mDayOffset.value() < 1.0)) + { + getChild<LLUICtrl>(LBL_TIMEOFDAY)->setVisible(false); + return; + } + getChild<LLUICtrl>(LBL_TIMEOFDAY)->setVisible(true); + + S32Seconds now(LLDate::now().secondsSinceEpoch()); + + now += mCurrentEnvironment->mDayOffset; + + F32 perc = (F32)(now.value() % mCurrentEnvironment->mDayLength.value()) / (F32)(mCurrentEnvironment->mDayLength.value()); + + S32Seconds secondofday((S32)(perc * SECONDSINDAY)); + S32Hours hourofday(secondofday); + S32Seconds secondofhour(secondofday - hourofday); + S32Minutes minutesofhour(secondofhour); + bool am_pm(hourofday.value() >= 12); + + if (hourofday.value() < 1) + hourofday = S32Hours(12); + if (hourofday.value() > 12) + hourofday -= S32Hours(12); + + std::string lblminute(((minutesofhour.value() < 10) ? "0" : "") + LLSD(minutesofhour.value()).asString()); + + + getChild<LLUICtrl>(LBL_TIMEOFDAY)->setTextArg("[HH]", LLSD(hourofday.value()).asString()); + getChild<LLUICtrl>(LBL_TIMEOFDAY)->setTextArg("[MM]", lblminute); + getChild<LLUICtrl>(LBL_TIMEOFDAY)->setTextArg("[AP]", std::string(am_pm ? "PM" : "AM")); + getChild<LLUICtrl>(LBL_TIMEOFDAY)->setTextArg("[PRC]", LLSD((S32)(100 * perc)).asString()); + +} + +void LLPanelEnvironmentInfo::onIdlePlay(void *data) +{ + ((LLPanelEnvironmentInfo *)data)->udpateApparentTimeOfDay(); +} + + +void LLPanelEnvironmentInfo::onPickerCommitted(LLUUID item_id, std::string source) +{ + if (source == alt_prefixes[4]) + { + onPickerCommitted(item_id, 0); + } + else if (source == alt_prefixes[3]) + { + onPickerCommitted(item_id, 1); + } + else + { + onPickerCommitted(item_id, mAltitudes[source].mTrackIndex); + } +} + +void LLPanelEnvironmentInfo::onPickerCommitted(LLUUID item_id, S32 track_num) +{ + LLInventoryItem *itemp = gInventory.getItem(item_id); + if (itemp) + { + LLHandle<LLPanel> that_h = getHandle(); + clearDirtyFlag(DIRTY_FLAG_DAYLENGTH); + clearDirtyFlag(DIRTY_FLAG_DAYOFFSET); + + U32 flags(0); + + if (itemp) + { + if (!itemp->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID())) + flags |= LLSettingsBase::FLAG_NOMOD; + if (!itemp->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID())) + flags |= LLSettingsBase::FLAG_NOTRANS; + } + + LLEnvironment::instance().updateParcel(getParcelId(), + itemp->getAssetUUID(), + itemp->getName(), + track_num, + mCurrentEnvironment ? mCurrentEnvironment->mDayLength.value() : -1, + mCurrentEnvironment ? mCurrentEnvironment->mDayOffset.value() : -1, + flags, + LLEnvironment::altitudes_vect_t(), + [that_h](S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envifo) { _onEnvironmentReceived(that_h, parcel_id, envifo); }); + } +} + +void LLPanelEnvironmentInfo::onEditCommitted(LLSettingsDay::ptr_t newday) +{ + LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_EDIT); + LLEnvironment::instance().updateEnvironment(); + if (!newday) + { + LL_WARNS("ENVPANEL") << "Editor committed an empty day. Do nothing." << LL_ENDL; + return; + } + if (!mCurrentEnvironment) + { + // Attempting to save mid update? + LL_WARNS("ENVPANEL") << "Failed to apply changes from editor! Dirty state: " << mDirtyFlag << " env version: " << mCurEnvVersion << LL_ENDL; + return; + } + size_t newhash(newday->getHash()); + size_t oldhash((mCurrentEnvironment->mDayCycle) ? mCurrentEnvironment->mDayCycle->getHash() : 0); + + if (newhash != oldhash) + { + LLHandle<LLPanel> that_h = getHandle(); + clearDirtyFlag(DIRTY_FLAG_DAYLENGTH); + clearDirtyFlag(DIRTY_FLAG_DAYOFFSET); + + LLEnvironment::instance().updateParcel(getParcelId(), + newday, + mCurrentEnvironment ? mCurrentEnvironment->mDayLength.value() : -1, + mCurrentEnvironment ? mCurrentEnvironment->mDayOffset.value() : -1, + LLEnvironment::altitudes_vect_t(), + [that_h](S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envifo) { _onEnvironmentReceived(that_h, parcel_id, envifo); }); + } +} + +void LLPanelEnvironmentInfo::onEnvironmentChanged(LLEnvironment::EnvSelection_t env, S32 new_version) +{ + if (new_version < INVALID_PARCEL_ENVIRONMENT_VERSION) + { + // cleanups and local changes, we are only interested in changes sent by server + return; + } + + LL_DEBUGS("ENVPANEL") << "Received environment update " << mCurEnvVersion << " " << new_version << LL_ENDL; + + // Environment comes from different sources, from environment update callbacks, + // from hovers (causes callbacks on version change) and from personal requests + // filter out duplicates and out of order packets by checking parcel environment version. + + if (isRegion()) + { + // Note: region uses same init versions as parcel + if (env == LLEnvironment::ENV_REGION + // version should be always growing, UNSET_PARCEL_ENVIRONMENT_VERSION is backup case + && (mCurEnvVersion < new_version || mCurEnvVersion <= UNSET_PARCEL_ENVIRONMENT_VERSION)) + { + if (new_version >= UNSET_PARCEL_ENVIRONMENT_VERSION) + { + // 'pending state' to prevent re-request on following onEnvironmentChanged if there will be any + mCurEnvVersion = new_version; + } + mCurrentEnvironment.reset(); + refreshFromSource(); + } + } + else if ((env == LLEnvironment::ENV_PARCEL) + && (getParcelId() == LLViewerParcelMgr::instance().getAgentParcelId())) + { + LLParcel *parcel = getParcel(); + if (parcel) + { + // first for parcel own settings, second is for case when parcel uses region settings + if (mCurEnvVersion < new_version + || (mCurEnvVersion != new_version && new_version == UNSET_PARCEL_ENVIRONMENT_VERSION)) + { + // 'pending state' to prevent re-request on following onEnvironmentChanged if there will be any + mCurEnvVersion = new_version; + mCurrentEnvironment.reset(); + + refreshFromSource(); + } + else if (mCurrentEnvironment) + { + // update controls + refresh(); + } + } + } +} + + +void LLPanelEnvironmentInfo::onPickerAssetDownloaded(LLSettingsBase::ptr_t settings) +{ + LLSettingsVODay::buildFromOtherSetting(settings, [this](LLSettingsDay::ptr_t pday) + { + if (pday) + { + mCurrentEnvironment->mDayCycle = pday; + setDirtyFlag(DIRTY_FLAG_DAYCYCLE); + } + refresh(); + }); +} + +void LLPanelEnvironmentInfo::onEnvironmentReceived(S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envifo) +{ + if (parcel_id != getParcelId()) + { + LL_WARNS("ENVPANEL") << "Have environment for parcel " << parcel_id << " expecting " << getParcelId() << ". Discarding." << LL_ENDL; + return; + } + mCurrentEnvironment = envifo; + clearDirtyFlag(DIRTY_FLAG_MASK); + if (mCurrentEnvironment->mEnvVersion > INVALID_PARCEL_ENVIRONMENT_VERSION) + { + // Server provided version, use it + mCurEnvVersion = mCurrentEnvironment->mEnvVersion; + LL_DEBUGS("ENVPANEL") << " Setting environment version: " << mCurEnvVersion << " for parcel id: " << parcel_id << LL_ENDL; + } + // Backup: Version was not provided for some reason + else + { + LL_WARNS("ENVPANEL") << " Environment version was not provided for " << parcel_id << ", old env version: " << mCurEnvVersion << LL_ENDL; + } + + refreshFromEstate(); + refresh(); + + // todo: we have envifo and parcel env version, should we just setEnvironment() and parcel's property to prevent dupplicate requests? +} + +void LLPanelEnvironmentInfo::_onEnvironmentReceived(LLHandle<LLPanel> that_h, S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envifo) +{ + LLPanelEnvironmentInfo *that = (LLPanelEnvironmentInfo *)that_h.get(); + if (!that) + return; + that->onEnvironmentReceived(parcel_id, envifo); +} + +LLSettingsDropTarget::LLSettingsDropTarget(const LLSettingsDropTarget::Params& p) + : LLView(p), mEnvironmentInfoPanel(NULL), mDndEnabled(false) +{} + +BOOL LLSettingsDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + BOOL handled = FALSE; + + if (getParent() && mDndEnabled) + { + handled = TRUE; + + switch (cargo_type) + { + case DAD_SETTINGS: + { + LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data; + if (inv_item && mEnvironmentInfoPanel) + { + LLUUID item_id = inv_item->getUUID(); + if (gInventory.getItem(item_id)) + { + *accept = ACCEPT_YES_COPY_SINGLE; + if (drop) + { + // might be better to use name of the element + mEnvironmentInfoPanel->onPickerCommitted(item_id, mTrack); + } + } + } + else + { + *accept = ACCEPT_NO; + } + break; + } + default: + *accept = ACCEPT_NO; + break; + } + } + return handled; +} diff --git a/indra/newview/llpanelenvironment.h b/indra/newview/llpanelenvironment.h new file mode 100644 index 0000000000..38e3f09e34 --- /dev/null +++ b/indra/newview/llpanelenvironment.h @@ -0,0 +1,222 @@ +/** + * @file llpanelenvironment.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_LLPANELENVIRONMENT_H +#define LL_LLPANELENVIRONMENT_H + +#include "llaccordionctrltab.h" +#include "llradiogroup.h" +#include "llcheckboxctrl.h" +#include "llsliderctrl.h" +#include "llsettingsdaycycle.h" +#include "llenvironment.h" +#include "llparcel.h" +#include "llsettingspicker.h" +#include "llfloatereditextdaycycle.h" +#include "llestateinfomodel.h" + +class LLViewerRegion; + +class LLPanelEnvironmentInfo : public LLPanel +{ + friend class LLSettingsDropTarget; +public: + LLPanelEnvironmentInfo(); + virtual ~LLPanelEnvironmentInfo(); + + virtual BOOL postBuild() override; + virtual void onOpen(const LLSD& key) override; + + virtual BOOL isDirty() const override { return getIsDirty(); } + virtual void onVisibilityChange(BOOL new_visibility) override; + + virtual void refresh() override; + + virtual bool isRegion() const = 0; + virtual LLParcel * getParcel() = 0; + virtual bool canEdit() = 0; + virtual S32 getParcelId() = 0; + +protected: + LOG_CLASS(LLPanelEnvironmentInfo); + + static const std::string BTN_SELECTINV; + static const std::string BTN_EDIT; + static const std::string BTN_USEDEFAULT; + static const std::string BTN_RST_ALTITUDES; + static const std::string SLD_DAYLENGTH; + static const std::string SLD_DAYOFFSET; + static const std::string SLD_ALTITUDES; + static const std::string ICN_GROUND; + static const std::string ICN_WATER; + static const std::string CHK_ALLOWOVERRIDE; + static const std::string BTN_APPLY; + static const std::string BTN_CANCEL; + static const std::string LBL_TIMEOFDAY; + static const std::string PNL_SETTINGS; + static const std::string PNL_ENVIRONMENT_ALTITUDES; + static const std::string PNL_BUTTONS; + static const std::string PNL_DISABLED; + static const std::string PNL_REGION_MSG; + static const std::string TXT_DISABLED; + static const std::string SDT_DROP_TARGET; + + static const std::string STR_LABEL_USEDEFAULT; + static const std::string STR_LABEL_USEREGION; + static const std::string STR_ALTITUDE_DESCRIPTION; + static const std::string STR_NO_PARCEL; + static const std::string STR_CROSS_REGION; + static const std::string STR_LEGACY; + static const std::string STR_DISALLOWED; + static const std::string STR_TOO_SMALL; + + static const S32 MINIMUM_PARCEL_SIZE; + + static const U32 DIRTY_FLAG_DAYCYCLE; + static const U32 DIRTY_FLAG_DAYLENGTH; + static const U32 DIRTY_FLAG_DAYOFFSET; + static const U32 DIRTY_FLAG_ALTITUDES; + + static const U32 DIRTY_FLAG_MASK; + + bool setControlsEnabled(bool enabled); + void setDirtyFlag(U32 flag); + void clearDirtyFlag(U32 flag); + bool getIsDirty() const { return (mDirtyFlag != 0); } + bool getIsDirtyFlag(U32 flag) const { return ((mDirtyFlag & flag) != 0); } + U32 getDirtyFlag() const { return mDirtyFlag; } + void updateAltLabel(const std::string &alt_prefix, U32 sky_index, F32 alt_value); + void readjustAltLabels(); + + void onSldDayLengthChanged(F32 value); + void onSldDayOffsetChanged(F32 value); + void onAltSliderCallback(LLUICtrl *cntrl, const LLSD &data); + void onAltSliderMouseUp(); + + void onBtnEdit(); + void onBtnSelect(); + void onBtnDefault(); + void onBtnRstAltitudes(); + + void udpateApparentTimeOfDay(); + + void onPickerCommitted(LLUUID item_id, std::string source); + void onPickerCommitted(LLUUID item_id, S32 track_num = LLEnvironment::NO_TRACK); + void onEditCommitted(LLSettingsDay::ptr_t newday); + void onDayLenOffsetMouseUp(); + void commitDayLenOffsetChanges(bool need_callback); + + void onPickerAssetDownloaded(LLSettingsBase::ptr_t settings); + void onEnvironmentReceived(S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envifo); + static void _onEnvironmentReceived(LLHandle<LLPanel> that_h, S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envifo); + + virtual bool isLargeEnough() = 0; + virtual void refreshFromSource() = 0; + + std::string getNameForTrackIndex(S32 index); + + LLFloaterSettingsPicker * getSettingsPicker(bool create = true); + LLFloaterEditExtDayCycle * getEditFloater(bool create = true); + void updateEditFloater(const LLEnvironment::EnvironmentInfo::ptr_t &nextenv, bool enable); + + void setCrossRegion(bool val) { mCrossRegion = val; } + void setNoSelection(bool val) { mNoSelection = val; } + void setNoEnvironmentSupport(bool val) { mNoEnvironment = val; } + + LLEnvironment::EnvironmentInfo::ptr_t mCurrentEnvironment; + + void onEnvironmentChanged(LLEnvironment::EnvSelection_t env, S32 version); + + class AltitudeData + { + public: + AltitudeData() : + mTrackIndex(0), mLabelIndex(0), mAltitude(0) + {} + AltitudeData(U32 track_index, U32 label_index, F32 altitude) : + mTrackIndex(track_index), mLabelIndex(label_index), mAltitude(altitude) + {} + + U32 mTrackIndex; + U32 mLabelIndex; + F32 mAltitude; + }; + typedef std::map<std::string, AltitudeData> altitudes_data_t; + altitudes_data_t mAltitudes; + S32 mCurEnvVersion; // used to filter duplicate callbacks/refreshes + +protected: + typedef boost::signals2::connection connection_t; + + void refreshFromEstate(); + bool mAllowOverride; + +private: + static void onIdlePlay(void *); + + connection_t mCommitConnection; + connection_t mChangeMonitor; + connection_t mUpdateConnection; + + LLHandle<LLFloater> mSettingsFloater; + LLHandle<LLFloater> mEditFloater; + S32 mDirtyFlag; + S32 mEditorLastParcelId; + LLUUID mEditorLastRegionId; + bool mCrossRegion; + bool mNoSelection; + bool mNoEnvironment; + +}; + +class LLSettingsDropTarget : public LLView +{ +public: + struct Params : public LLInitParam::Block<Params, LLView::Params> + { + Params() + { + changeDefault(mouse_opaque, false); + changeDefault(follows.flags, FOLLOWS_ALL); + } + }; + LLSettingsDropTarget(const Params&); + ~LLSettingsDropTarget() {}; + + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + void setPanel(LLPanelEnvironmentInfo* panel, std::string track) { mEnvironmentInfoPanel = panel; mTrack = track; }; + void setDndEnabled(bool dnd_enabled) { mDndEnabled = dnd_enabled; }; + +protected: + LLPanelEnvironmentInfo* mEnvironmentInfoPanel; + std::string mTrack; + bool mDndEnabled; +}; +#endif // LL_LLPANELENVIRONMENT_H diff --git a/indra/newview/llpanelexperiences.cpp b/indra/newview/llpanelexperiences.cpp index 37981b36a9..91d3b523fb 100644 --- a/indra/newview/llpanelexperiences.cpp +++ b/indra/newview/llpanelexperiences.cpp @@ -93,9 +93,20 @@ void LLPanelExperiences::setExperienceList( const LLSD& experiences ) item->init(public_key); mExperiencesList->addItem(item, public_key); + + const LLSD& experience_details = LLExperienceCache::instance().get(public_key); + if (experience_details.isUndefined()) + { + LLExperienceCache::instance().get(public_key, boost::bind(&LLPanelExperiences::sortExperiencesList, this)); + } } - mExperiencesList->sort(); + sortExperiencesList(); +} + +void LLPanelExperiences::sortExperiencesList() +{ + mExperiencesList->sort(); } void LLPanelExperiences::getExperienceIdsList(std::vector<LLUUID>& result) diff --git a/indra/newview/llpanelexperiences.h b/indra/newview/llpanelexperiences.h index f29fdfdecb..9d5afd1a6a 100644 --- a/indra/newview/llpanelexperiences.h +++ b/indra/newview/llpanelexperiences.h @@ -60,6 +60,8 @@ public: void setExperienceList(const LLSD& experiences); void getExperienceIdsList(std::vector<LLUUID>& result); + void sortExperiencesList(); + LLExperienceItem* getSelectedExperienceItem(); void removeExperiences( const LLSD& ids ); void removeExperience( const LLUUID& id); diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index c686aab821..23394b26f2 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -979,7 +979,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) break; } - if(LLViewerMedia::textureHasMedia(id)) + if(LLViewerMedia::getInstance()->textureHasMedia(id)) { getChildView("button align")->setEnabled(editable); } @@ -1027,21 +1027,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) getChildView("maskcutoff")->setEnabled(editable && mIsAlpha); getChildView("label maskcutoff")->setEnabled(editable && mIsAlpha); - bool allAttachments = true; - for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin(); - iter != LLSelectMgr::getInstance()->getSelection()->end();iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - if (!object->isAttachment()) - { - allAttachments = false; - break; - } - } - - texture_ctrl->setBakeTextureEnabled(allAttachments); - + texture_ctrl->setBakeTextureEnabled(TRUE); } else if (id.isNull()) { @@ -1066,21 +1052,8 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) getChildView("label alphamode")->setEnabled(editable && mIsAlpha); getChildView("maskcutoff")->setEnabled(editable && mIsAlpha); getChildView("label maskcutoff")->setEnabled(editable && mIsAlpha); - - bool allAttachments = true; - for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin(); - iter != LLSelectMgr::getInstance()->getSelection()->end();iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - if (!object->isAttachment()) - { - allAttachments = false; - break; - } - } - - texture_ctrl->setBakeTextureEnabled(allAttachments); + + texture_ctrl->setBakeTextureEnabled(TRUE); } } @@ -1109,6 +1082,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) bool enabled = (editable && isIdenticalPlanarTexgen()); childSetValue("checkbox planar align", align_planar && enabled); + childSetVisible("checkbox planar align", enabled); childSetEnabled("checkbox planar align", enabled); childSetEnabled("button align textures", enabled && LLSelectMgr::getInstance()->getSelection()->getObjectCount() > 1); @@ -2517,13 +2491,13 @@ struct LLPanelFaceSetMediaFunctor : public LLSelectedTEFunctor const LLMediaEntry* mep = tep->hasMedia() ? tep->getMediaData() : NULL; if ( mep ) { - pMediaImpl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()); + pMediaImpl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID()); } if ( pMediaImpl.isNull()) { // If we didn't find face media for this face, check whether this face is showing parcel media. - pMediaImpl = LLViewerMedia::getMediaImplFromTextureID(tep->getID()); + pMediaImpl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(tep->getID()); } if ( pMediaImpl.notNull()) @@ -2691,7 +2665,7 @@ void LLPanelFace::LLSelectedTE::getTexId(LLUUID& id, bool& identical) id = image->getID(); } - if (!id.isNull() && LLViewerMedia::textureHasMedia(id)) + if (!id.isNull() && LLViewerMedia::getInstance()->textureHasMedia(id)) { if (te) { diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index e41211ddbd..ab255d5215 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -128,10 +128,6 @@ void LLPanelGroup::onOpen(const LLSD& key) { onBackBtnClick(); } - else if(str_action == "create") - { - setGroupID(LLUUID::null); - } else if(str_action == "refresh_notices") { LLPanelGroupNotices* panel_notices = findChild<LLPanelGroupNotices>("group_notices_tab_panel"); @@ -162,12 +158,8 @@ BOOL LLPanelGroup::postBuild() button = getChild<LLButton>("btn_refresh"); button->setClickedCallback(onBtnRefresh, this); - getChild<LLButton>("btn_create")->setVisible(false); - childSetCommitCallback("back",boost::bind(&LLPanelGroup::onBackBtnClick,this),NULL); - childSetCommitCallback("btn_create",boost::bind(&LLPanelGroup::onBtnCreate,this),NULL); - LLPanelGroupTab* panel_general = findChild<LLPanelGroupTab>("group_general_tab_panel"); LLPanelGroupTab* panel_roles = findChild<LLPanelGroupTab>("group_roles_tab_panel"); LLPanelGroupTab* panel_notices = findChild<LLPanelGroupTab>("group_notices_tab_panel"); @@ -223,7 +215,6 @@ void LLPanelGroup::reposButtons() } reposButton("btn_apply"); - reposButton("btn_create"); reposButton("btn_refresh"); reposButton("btn_cancel"); reposButton("btn_chat"); @@ -246,23 +237,6 @@ void LLPanelGroup::onBackBtnClick() } } - -void LLPanelGroup::onBtnCreate() -{ - LLPanelGroupGeneral* panel_general = findChild<LLPanelGroupGeneral>("group_general_tab_panel"); - if(!panel_general) - return; - std::string apply_mesg; - if(panel_general->apply(apply_mesg))//yes yes you need to call apply to create... - return; - if ( !apply_mesg.empty() ) - { - LLSD args; - args["MESSAGE"] = apply_mesg; - LLNotificationsUtil::add("GenericAlert", args); - } -} - void LLPanelGroup::onBtnRefresh(void* user_data) { LLPanelGroup* self = static_cast<LLPanelGroup*>(user_data); @@ -378,7 +352,6 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id) LLButton* button_apply = findChild<LLButton>("btn_apply"); LLButton* button_refresh = findChild<LLButton>("btn_refresh"); - LLButton* button_create = findChild<LLButton>("btn_create"); LLButton* button_cancel = findChild<LLButton>("btn_cancel"); LLButton* button_call = findChild<LLButton>("btn_call"); @@ -391,8 +364,6 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id) if(button_refresh) button_refresh->setVisible(!is_null_group_id); - if(button_create) - button_create->setVisible(is_null_group_id); if(button_cancel) button_cancel->setVisible(!is_null_group_id); @@ -611,18 +582,6 @@ void LLPanelGroup::showNotice(const std::string& subject, panel_notices->showNotice(subject,message,has_inventory,inventory_name,inventory_offer); } - - - -//static -void LLPanelGroup::refreshCreatedGroup(const LLUUID& group_id) -{ - LLPanelGroup* panel = LLFloaterSidePanelContainer::getPanel<LLPanelGroup>("people", "panel_group_info_sidetray"); - if(!panel) - return; - panel->setGroupID(group_id); -} - //static void LLPanelGroup::showNotice(const std::string& subject, diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h index 0b40c8b5d3..be40b08a6d 100644 --- a/indra/newview/llpanelgroup.h +++ b/indra/newview/llpanelgroup.h @@ -79,8 +79,6 @@ public: virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - static void refreshCreatedGroup(const LLUUID& group_id); - static void showNotice(const std::string& subject, const std::string& message, const LLUUID& group_id, @@ -92,7 +90,6 @@ public: protected: virtual void update(LLGroupChange gc); - void onBtnCreate(); void onBackBtnClick(); void onBtnJoin(); diff --git a/indra/newview/llpanelgroupcreate.cpp b/indra/newview/llpanelgroupcreate.cpp new file mode 100644 index 0000000000..052212dc27 --- /dev/null +++ b/indra/newview/llpanelgroupcreate.cpp @@ -0,0 +1,237 @@ +/** + * @file llpanelgroupcreate.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 "llpanelgroupcreate.h" + +// UI includes +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llfloatersidepanelcontainer.h" +#include "llsidetraypanelcontainer.h" +#include "llscrolllistctrl.h" +#include "llspinctrl.h" +#include "lltextbox.h" +#include "lltexteditor.h" +#include "lltexturectrl.h" +#include "lluictrlfactory.h" + +// Viewer includes +#include "llagentbenefits.h" +#include "llfloaterreg.h" +#include "llfloater.h" +#include "llgroupmgr.h" +#include "lltrans.h" +#include "llnotificationsutil.h" +#include "lluicolortable.h" + + +const S32 MATURE_CONTENT = 1; +const S32 NON_MATURE_CONTENT = 2; +const S32 DECLINE_TO_STATE = 0; + +static LLPanelInjector<LLPanelGroupCreate> t_panel_group_creation("panel_group_creation_sidetray"); + +LLPanelGroupCreate::LLPanelGroupCreate() +: LLPanel() +{ +} + +LLPanelGroupCreate::~LLPanelGroupCreate() +{ +} + +BOOL LLPanelGroupCreate::postBuild() +{ + childSetCommitCallback("back", boost::bind(&LLPanelGroupCreate::onBackBtnClick, this), NULL); + + mComboMature = getChild<LLComboBox>("group_mature_check", TRUE); + mCtrlOpenEnrollment = getChild<LLCheckBoxCtrl>("open_enrollement", TRUE); + mCtrlEnrollmentFee = getChild<LLCheckBoxCtrl>("check_enrollment_fee", TRUE); + mEditCharter = getChild<LLTextEditor>("charter", TRUE); + mSpinEnrollmentFee = getChild<LLSpinCtrl>("spin_enrollment_fee", TRUE); + mMembershipList = getChild<LLScrollListCtrl>("membership_list", TRUE); + + mCreateButton = getChild<LLButton>("btn_create", TRUE); + mCreateButton->setCommitCallback(boost::bind(&LLPanelGroupCreate::onBtnCreate, this)); + + mGroupNameEditor = getChild<LLLineEditor>("group_name_editor", TRUE); + mGroupNameEditor->setPrevalidate(LLTextValidate::validateASCIINoLeadingSpace); + + mInsignia = getChild<LLTextureCtrl>("insignia", TRUE); + mInsignia->setAllowLocalTexture(FALSE); + mInsignia->setCanApplyImmediately(FALSE); + + return TRUE; +} + +void LLPanelGroupCreate::onOpen(const LLSD& key) +{ + mInsignia->setImageAssetID(LLUUID::null); + mInsignia->setImageAssetName(mInsignia->getDefaultImageName()); + mGroupNameEditor->clear(); + mEditCharter->clear(); + mSpinEnrollmentFee->set(0.f); + mCtrlEnrollmentFee->set(FALSE); + mCtrlOpenEnrollment->set(FALSE); + mMembershipList->clearRows(); + + // populate list + addMembershipRow("Base"); + addMembershipRow("Premium"); + addMembershipRow("Premium Plus"); + addMembershipRow("Internal");// Present only if you are already in one, needed for testing + + S32 cost = LLAgentBenefitsMgr::current().getCreateGroupCost(); + mCreateButton->setLabelArg("[COST]", llformat("%d", cost)); +} + +//static +void LLPanelGroupCreate::refreshCreatedGroup(const LLUUID& group_id) +{ + LLSD params; + params["group_id"] = group_id; + params["open_tab_name"] = "panel_group_info_sidetray"; + LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params); +} + +void LLPanelGroupCreate::addMembershipRow(const std::string &name) +{ + if (LLAgentBenefitsMgr::has(name)) + { + bool is_current = LLAgentBenefitsMgr::isCurrent(name); + + LLScrollListItem::Params item_params; + LLScrollListCell::Params cell_params; + cell_params.font = LLFontGL::getFontSansSerif(); + // Start out right justifying numeric displays + cell_params.font_halign = LLFontGL::LEFT; + if (is_current) + { + cell_params.color = LLUIColorTable::instance().getColor("DrYellow"); + } + + cell_params.column = "clmn_name"; + std::string mem_str = name + "Membership"; + if (is_current) + { + cell_params.value = LLTrans::getString(mem_str) + " " + getString("current_membership"); + } + else + { + cell_params.value = LLTrans::getString(mem_str); + } + item_params.columns.add(cell_params); + cell_params.column = "clmn_price"; + cell_params.value = llformat("L$ %d",LLAgentBenefitsMgr::get(name).getCreateGroupCost()); + item_params.columns.add(cell_params); + mMembershipList->addRow(item_params); + } +} + +void LLPanelGroupCreate::onBackBtnClick() +{ + LLSideTrayPanelContainer* parent = dynamic_cast<LLSideTrayPanelContainer*>(getParent()); + if(parent) + { + parent->openPreviousPanel(); + } +} + +bool LLPanelGroupCreate::confirmMatureApply(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + // 0 == Yes + // 1 == No + // 2 == Cancel + switch (option) + { + case 0: + mComboMature->setCurrentByIndex(MATURE_CONTENT); + createGroup(); + break; + case 1: + mComboMature->setCurrentByIndex(NON_MATURE_CONTENT); + createGroup(); + break; + default: + break; + } + + return true; +} + +void LLPanelGroupCreate::onBtnCreate() +{ + LL_INFOS() << "Validating group creation" << LL_ENDL; + + // Validate the group name length. + std::string gr_name = mGroupNameEditor->getText(); + LLStringUtil::trim(gr_name); + S32 group_name_len = gr_name.size(); + if (group_name_len < DB_GROUP_NAME_MIN_LEN + || group_name_len > DB_GROUP_NAME_STR_LEN) + { + LLSD args; + args["MIN_LEN"] = DB_GROUP_NAME_MIN_LEN; + args["MAX_LEN"] = DB_GROUP_NAME_STR_LEN; + LLNotificationsUtil::add("GroupNameLengthWarning", args); + } + else + // Check to make sure mature has been set + if (mComboMature && + mComboMature->getCurrentIndex() == DECLINE_TO_STATE) + { + LLNotificationsUtil::add("SetGroupMature", LLSD(), LLSD(), + boost::bind(&LLPanelGroupCreate::confirmMatureApply, this, _1, _2)); + } + else + { + createGroup(); + } +} + +void LLPanelGroupCreate::createGroup() +{ + LL_INFOS() << "Creating group" << LL_ENDL; + + U32 enrollment_fee = (mCtrlEnrollmentFee->get() ? + (U32)mSpinEnrollmentFee->get() : 0); + LLUUID insignia_id = mInsignia->getImageItemID().isNull() ? LLUUID::null : mInsignia->getImageAssetID(); + + std::string gr_name = mGroupNameEditor->getText(); + LLStringUtil::trim(gr_name); + LLGroupMgr::getInstance()->sendCreateGroupRequest(gr_name, + mEditCharter->getText(), + true, + insignia_id, + enrollment_fee, + mCtrlOpenEnrollment->get(), + false, + mComboMature->getCurrentIndex() == MATURE_CONTENT); +} + diff --git a/indra/newview/llpanelgroupcreate.h b/indra/newview/llpanelgroupcreate.h new file mode 100644 index 0000000000..3ae2e7f24a --- /dev/null +++ b/indra/newview/llpanelgroupcreate.h @@ -0,0 +1,73 @@ +/** + * @file llpanelgroupcreate.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_LLPANELGROUPCREATE_H +#define LL_LLPANELGROUPCREATE_H + +#include "llpanel.h" + + +// Forward declares +class LLButton; +class LLCheckBoxCtrl; +class LLComboBox; +class LLLineEditor; +class LLTextEditor; +class LLTextureCtrl; +class LLScrollListCtrl; +class LLSpinCtrl; + + +class LLPanelGroupCreate : public LLPanel +{ +public: + LLPanelGroupCreate(); + virtual ~LLPanelGroupCreate(); + + virtual BOOL postBuild(); + + void onOpen(const LLSD& key); + + static void refreshCreatedGroup(const LLUUID& group_id); + +private: + void addMembershipRow(const std::string &name); + bool confirmMatureApply(const LLSD& notification, const LLSD& response); + void onBtnCreate(); + void onBackBtnClick(); + void createGroup(); + + LLComboBox *mComboMature; + LLButton *mCreateButton; + LLCheckBoxCtrl *mCtrlOpenEnrollment; + LLCheckBoxCtrl *mCtrlEnrollmentFee; + LLTextEditor *mEditCharter; + LLTextureCtrl *mInsignia; + LLLineEditor *mGroupNameEditor; + LLScrollListCtrl *mMembershipList; + LLSpinCtrl *mSpinEnrollmentFee; +}; + +#endif // LL_LLPANELGROUPCREATE_H diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index b53cd222e7..375daf60f8 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -30,6 +30,7 @@ #include "llavatarnamecache.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llsdparam.h" #include "lluictrlfactory.h" #include "roles_constants.h" @@ -303,6 +304,11 @@ void LLPanelGroupGeneral::draw() bool LLPanelGroupGeneral::apply(std::string& mesg) { + if (mGroupID.isNull()) + { + return false; + } + if (!mGroupID.isNull() && mAllowEdit && mComboActiveTitle && mComboActiveTitle->isDirty()) { LLGroupMgr::getInstance()->sendGroupTitleUpdate(mGroupID,mComboActiveTitle->getCurrentID()); @@ -312,7 +318,7 @@ bool LLPanelGroupGeneral::apply(std::string& mesg) BOOL has_power_in_group = gAgent.hasPowerInGroup(mGroupID,GP_GROUP_CHANGE_IDENTITY); - if (has_power_in_group || mGroupID.isNull()) + if (has_power_in_group) { LL_INFOS() << "LLPanelGroupGeneral::apply" << LL_ENDL; @@ -325,25 +331,6 @@ bool LLPanelGroupGeneral::apply(std::string& mesg) return false; } - if (mGroupID.isNull()) - { - // Validate the group name length. - S32 group_name_len = mGroupNameEditor->getText().size(); - if ( group_name_len < DB_GROUP_NAME_MIN_LEN - || group_name_len > DB_GROUP_NAME_STR_LEN) - { - std::ostringstream temp_error; - temp_error << "A group name must be between " << DB_GROUP_NAME_MIN_LEN - << " and " << DB_GROUP_NAME_STR_LEN << " characters."; - mesg = temp_error.str(); - return false; - } - - LLNotificationsUtil::add("CreateGroupCost", LLSD(), LLSD(), boost::bind(&LLPanelGroupGeneral::createGroupCallback, this, _1, _2)); - - return false; - } - LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); if (!gdatap) { @@ -450,37 +437,6 @@ bool LLPanelGroupGeneral::confirmMatureApply(const LLSD& notification, const LLS return ret; } -// static -bool LLPanelGroupGeneral::createGroupCallback(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - switch(option) - { - case 0: - { - // Yay! We are making a new group! - U32 enrollment_fee = (mCtrlEnrollmentFee->get() ? - (U32) mSpinEnrollmentFee->get() : 0); - LLUUID insignia_id = mInsignia->getImageItemID().isNull() ? LLUUID::null : mInsignia->getImageAssetID(); - - LLGroupMgr::getInstance()->sendCreateGroupRequest(mGroupNameEditor->getText(), - mEditCharter->getText(), - mCtrlShowInGroupList->get(), - insignia_id, - enrollment_fee, - mCtrlOpenEnrollment->get(), - false, - mComboMature->getCurrentIndex() == MATURE_CONTENT); - - } - break; - case 1: - default: - break; - } - return false; -} - // virtual void LLPanelGroupGeneral::update(LLGroupChange gc) { diff --git a/indra/newview/llpanelgroupgeneral.h b/indra/newview/llpanelgroupgeneral.h index 11972bafa9..1d0789521c 100644 --- a/indra/newview/llpanelgroupgeneral.h +++ b/indra/newview/llpanelgroupgeneral.h @@ -51,7 +51,6 @@ public: virtual bool needsApply(std::string& mesg); virtual bool apply(std::string& mesg); virtual void cancel(); - bool createGroupCallback(const LLSD& notification, const LLSD& response); virtual void update(LLGroupChange gc); diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index ce6834b4b3..c63d04cd55 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -155,6 +155,7 @@ BOOL LLGroupDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, case DAD_GESTURE: case DAD_CALLINGCARD: case DAD_MESH: + case DAD_SETTINGS: { LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data; if(gInventory.getItem(inv_item->getUUID()) @@ -200,9 +201,12 @@ std::string build_notice_date(const U32& the_time) time(&t); } - std::string dateStr = "["+LLTrans::getString("LTimeMthNum")+"]/[" - +LLTrans::getString("LTimeDay")+"]/[" - +LLTrans::getString("LTimeYear")+"]"; + std::string dateStr = "["+ LLTrans::getString("LTimeYear") + "]/[" + + LLTrans::getString("LTimeMthNum") + "]/[" + + LLTrans::getString("LTimeDay") + "] [" + + LLTrans::getString("LTimeHour") + "]:[" + + LLTrans::getString("LTimeMin") + "]:[" + + LLTrans::getString("LTimeSec") + "]"; LLSD substitution; substitution["datetime"] = (S32) t; LLStringUtil::format (dateStr, substitution); diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 0efb234015..e3d75d5604 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -1153,7 +1153,7 @@ void LLPanelGroupMembersSubTab::onInviteMember(void *userdata) void LLPanelGroupMembersSubTab::handleInviteMember() { - LLFloaterGroupInvite::showForGroup(mGroupID); + LLFloaterGroupInvite::showForGroup(mGroupID, NULL, false); } void LLPanelGroupMembersSubTab::onEjectMembers(void *userdata) diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp index 06bb886ae8..880323ce16 100644 --- a/indra/newview/llpanellandmarkinfo.cpp +++ b/indra/newview/llpanellandmarkinfo.cpp @@ -39,6 +39,7 @@ #include "llagent.h" #include "llagentui.h" #include "lllandmarkactions.h" +#include "llparcel.h" #include "llslurl.h" #include "llviewerinventory.h" #include "llviewerparcelmgr.h" @@ -51,7 +52,6 @@ typedef std::pair<LLUUID, std::string> folder_pair_t; static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right); -static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats); static LLPanelInjector<LLPanelLandmarkInfo> t_landmark_info("panel_landmark_info"); @@ -77,7 +77,7 @@ BOOL LLPanelLandmarkInfo::postBuild() mCreator = getChild<LLTextBox>("creator"); mCreated = getChild<LLTextBox>("created"); - mLandmarkTitle = getChild<LLTextBox>("title_value"); + mLandmarkTitle = getChild<LLLineEditor>("title_value"); mLandmarkTitleEditor = getChild<LLLineEditor>("title_editor"); mNotesEditor = getChild<LLTextEditor>("notes_editor"); mFolderCombo = getChild<LLComboBox>("folder_combo"); @@ -106,6 +106,18 @@ void LLPanelLandmarkInfo::resetLocation() // virtual void LLPanelLandmarkInfo::setInfoType(EInfoType type) { + LLUUID dest_folder; + setInfoType(type, dest_folder); +} + +// Sets CREATE_LANDMARK infotype and creates landmark at desired folder +void LLPanelLandmarkInfo::setInfoAndCreateLandmark(const LLUUID& fodler_id) +{ + setInfoType(CREATE_LANDMARK, fodler_id); +} + +void LLPanelLandmarkInfo::setInfoType(EInfoType type, const LLUUID &folder_id) +{ LLPanel* landmark_info_panel = getChild<LLPanel>("landmark_info_panel"); bool is_info_type_create_landmark = type == CREATE_LANDMARK; @@ -113,6 +125,7 @@ void LLPanelLandmarkInfo::setInfoType(EInfoType type) landmark_info_panel->setVisible(type == LANDMARK); getChild<LLTextBox>("folder_label")->setVisible(is_info_type_create_landmark); + getChild<LLButton>("edit_btn")->setVisible(!is_info_type_create_landmark); mFolderCombo->setVisible(is_info_type_create_landmark); switch(type) @@ -126,13 +139,10 @@ void LLPanelLandmarkInfo::setInfoType(EInfoType type) mNotesEditor->setEnabled(TRUE); LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance(); - std::string name = parcel_mgr->getAgentParcelName(); + LLParcel* parcel = parcel_mgr->getAgentParcel(); + std::string name = parcel->getName(); LLVector3 agent_pos = gAgent.getPositionAgent(); - std::string desc; - LLAgentUI::buildLocationString(desc, LLAgentUI::LOCATION_FORMAT_FULL, agent_pos); - mNotesEditor->setText(desc); - if (name.empty()) { S32 region_x = ll_round(agent_pos.mV[VX]); @@ -147,6 +157,7 @@ void LLPanelLandmarkInfo::setInfoType(EInfoType type) } else { + std::string desc; LLAgentUI::buildLocationString(desc, LLAgentUI::LOCATION_FORMAT_NORMAL, agent_pos); region_name = desc; } @@ -159,12 +170,31 @@ void LLPanelLandmarkInfo::setInfoType(EInfoType type) mLandmarkTitleEditor->setText(name); } + LLUUID owner_id = parcel->getOwnerID(); + if (owner_id.notNull()) + { + if (parcel->getIsGroupOwned()) + { + std::string owner_name = LLSLURL("group", parcel->getGroupID(), "inspect").getSLURLString(); + mParcelOwner->setText(owner_name); + } + else + { + std::string owner_name = LLSLURL("agent", owner_id, "inspect").getSLURLString(); + mParcelOwner->setText(owner_name); + } + } + else + { + mParcelOwner->setText(getString("public")); + } + // Moved landmark creation here from LLPanelLandmarkInfo::processParcelInfo() // because we use only agent's current coordinates instead of waiting for // remote parcel request to complete. if (!LLLandmarkActions::landmarkAlreadyExists()) { - createLandmark(LLUUID()); + createLandmark(folder_id); } } break; @@ -210,6 +240,24 @@ void LLPanelLandmarkInfo::processParcelInfo(const LLParcelData& parcel_data) mMaturityRatingText->setText(LLViewerRegion::accessToString(SIM_ACCESS_PG)); } + if (parcel_data.owner_id.notNull()) + { + if (parcel_data.flags & 0x4) // depends onto DRTSIM-453 + { + std::string owner_name = LLSLURL("group", parcel_data.owner_id, "inspect").getSLURLString(); + mParcelOwner->setText(owner_name); + } + else + { + std::string owner_name = LLSLURL("agent", parcel_data.owner_id, "inspect").getSLURLString(); + mParcelOwner->setText(owner_name); + } + } + else + { + mParcelOwner->setText(getString("public")); + } + LLSD info; info["update_verbs"] = true; info["global_x"] = parcel_data.global_x; @@ -264,7 +312,8 @@ void LLPanelLandmarkInfo::displayItemInfo(const LLInventoryItem* pItem) } else { - mOwner->setText(getString("public")); + std::string public_str = getString("public"); + mOwner->setText(public_str); } ////////////////// @@ -311,6 +360,7 @@ void LLPanelLandmarkInfo::toggleLandmarkEditMode(BOOL enabled) mNotesEditor->setReadOnly(!enabled); mFolderCombo->setVisible(enabled); getChild<LLTextBox>("folder_label")->setVisible(enabled); + getChild<LLButton>("edit_btn")->setVisible(!enabled); // HACK: To change the text color in a text editor // when it was enabled/disabled we set the text once again. @@ -357,7 +407,7 @@ void LLPanelLandmarkInfo::createLandmark(const LLUUID& folder_id) // If no parcel exists use the region name instead. if (name.empty()) { - name = mRegionName->getText(); + name = mRegionTitle; } } @@ -465,7 +515,7 @@ static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right) return left.second < right.second; } -static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats) +void LLPanelLandmarkInfo::collectLandmarkFolders(LLInventoryModel::cat_array_t& cats) { LLUUID landmarks_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); @@ -478,16 +528,20 @@ static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats) items, LLInventoryModel::EXCLUDE_TRASH, is_category); +} - // Add the "My Favorites" category. - LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - LLViewerInventoryCategory* favorites_cat = gInventory.getCategory(favorites_id); - if (!favorites_cat) - { - LL_WARNS() << "Cannot find the favorites folder" << LL_ENDL; - } - else - { - cats.push_back(favorites_cat); - } +/* virtual */ void LLUpdateLandmarkParent::fire(const LLUUID& inv_item_id) +{ + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(mItem->getParentUUID(), -1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(mNewParentId, 1); + update.push_back(new_folder); + gInventory.accountForUpdate(update); + + mItem->setParent(mNewParentId); + mItem->updateParentOnServer(FALSE); + + gInventory.updateItem(mItem); + gInventory.notifyObservers(); } diff --git a/indra/newview/llpanellandmarkinfo.h b/indra/newview/llpanellandmarkinfo.h index 01a6fd6b3d..f727f286b5 100644 --- a/indra/newview/llpanellandmarkinfo.h +++ b/indra/newview/llpanellandmarkinfo.h @@ -28,6 +28,7 @@ #define LL_LLPANELLANDMARKINFO_H #include "llpanelplaceinfo.h" +#include "llinventorymodel.h" class LLComboBox; class LLLineEditor; @@ -43,8 +44,12 @@ public: /*virtual*/ void resetLocation(); + // If landmark doesn't exists, will create it at default folder /*virtual*/ void setInfoType(EInfoType type); + // Sets CREATE_LANDMARK infotype and creates landmark at desired folder + void setInfoAndCreateLandmark(const LLUUID& fodler_id); + /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); // Displays landmark owner, creator and creation date info. @@ -59,22 +64,41 @@ public: // Select current landmark folder in combobox. BOOL setLandmarkFolder(const LLUUID& id); - // Create a landmark for the current location - // in a folder specified by folder_id. - void createLandmark(const LLUUID& folder_id); - + typedef std::vector<LLPointer<LLViewerInventoryCategory> > cat_array_t; static std::string getFullFolderName(const LLViewerInventoryCategory* cat); + static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats); private: + // Create a landmark for the current location + // in a folder specified by folder_id. + // Expects title and description to be initialized + void createLandmark(const LLUUID& folder_id); + + // If landmark doesn't exists, will create it at specified folder + void setInfoType(EInfoType type, const LLUUID &folder_id); + void populateFoldersList(); LLTextBox* mOwner; LLTextBox* mCreator; LLTextBox* mCreated; - LLTextBox* mLandmarkTitle; + LLLineEditor* mLandmarkTitle; LLLineEditor* mLandmarkTitleEditor; LLTextEditor* mNotesEditor; LLComboBox* mFolderCombo; }; +class LLUpdateLandmarkParent : public LLInventoryCallback +{ +public: + LLUpdateLandmarkParent(LLPointer<LLViewerInventoryItem> item, LLUUID new_parent) : + mItem(item), + mNewParentId(new_parent) + {}; + /* virtual */ void fire(const LLUUID& inv_item_id); + +private: + LLPointer<LLViewerInventoryItem> mItem; + LLUUID mNewParentId; +}; #endif // LL_LLPANELLANDMARKINFO_H diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index cd1dc0f070..e698a61fef 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -36,12 +36,11 @@ #include "llregionhandle.h" #include "llaccordionctrl.h" -#include "llaccordionctrltab.h" #include "llagent.h" #include "llagentpicksinfo.h" #include "llagentui.h" +#include "llavataractions.h" #include "llcallbacklist.h" -#include "lldndbutton.h" #include "llfloatersidepanelcontainer.h" #include "llfloaterworldmap.h" #include "llfolderviewitem.h" @@ -60,15 +59,8 @@ // Not yet implemented; need to remove buildPanel() from constructor when we switch //static LLRegisterPanelClassWrapper<LLLandmarksPanel> t_landmarks("panel_landmarks"); -static const std::string OPTIONS_BUTTON_NAME = "options_gear_btn"; -static const std::string ADD_BUTTON_NAME = "add_btn"; -static const std::string ADD_FOLDER_BUTTON_NAME = "add_folder_btn"; -static const std::string TRASH_BUTTON_NAME = "trash_btn"; - - // helper functions static void filter_list(LLPlacesInventoryPanel* inventory_list, const std::string& string); -static bool category_has_descendents(LLPlacesInventoryPanel* inventory_list); static void collapse_all_folders(LLFolderView* root_folder); static void expand_all_folders(LLFolderView* root_folder); static bool has_expanded_folders(LLFolderView* root_folder); @@ -149,69 +141,37 @@ void LLOpenFolderByID::doFolder(LLFolderViewFolder* folder) } } -/** - * Bridge to support knowing when the inventory has changed to update Landmarks tab - * ShowFolderState filter setting to show all folders when the filter string is empty and - * empty folder message when Landmarks inventory category has no children. - * Ensures that "Landmarks" folder in the Library is open on strart up. - */ -class LLLandmarksPanelObserver : public LLInventoryObserver -{ -public: - LLLandmarksPanelObserver(LLLandmarksPanel* lp) - : mLP(lp), - mIsLibraryLandmarksOpen(false) - {} - virtual ~LLLandmarksPanelObserver() {} - /*virtual*/ void changed(U32 mask); - -private: - LLLandmarksPanel* mLP; - bool mIsLibraryLandmarksOpen; -}; - -void LLLandmarksPanelObserver::changed(U32 mask) +LLLandmarksPanel::LLLandmarksPanel() + : LLPanelPlacesTab() + , mLandmarksInventoryPanel(NULL) + , mCurrentSelectedList(NULL) + , mGearFolderMenu(NULL) + , mGearLandmarkMenu(NULL) + , mSortingMenu(NULL) + , mAddMenu(NULL) + , isLandmarksPanel(true) { - mLP->updateShowFolderState(); - - LLPlacesInventoryPanel* library = mLP->getLibraryInventoryPanel(); - if (!mIsLibraryLandmarksOpen && library) - { - // Search for "Landmarks" folder in the Library and open it once on start up. See EXT-4827. - const LLUUID &landmarks_cat = gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_LANDMARK, false); - if (landmarks_cat.notNull()) - { - LLOpenFolderByID opener(landmarks_cat); - library->getRootFolder()->applyFunctorRecursively(opener); - mIsLibraryLandmarksOpen = opener.isFolderOpen(); - } - } + buildFromFile("panel_landmarks.xml"); } -LLLandmarksPanel::LLLandmarksPanel() +LLLandmarksPanel::LLLandmarksPanel(bool is_landmark_panel) : LLPanelPlacesTab() - , mFavoritesInventoryPanel(NULL) , mLandmarksInventoryPanel(NULL) - , mMyInventoryPanel(NULL) - , mLibraryInventoryPanel(NULL) , mCurrentSelectedList(NULL) - , mListCommands(NULL) - , mGearButton(NULL) , mGearFolderMenu(NULL) , mGearLandmarkMenu(NULL) + , mSortingMenu(NULL) + , mAddMenu(NULL) + , isLandmarksPanel(is_landmark_panel) { - mInventoryObserver = new LLLandmarksPanelObserver(this); - gInventory.addObserver(mInventoryObserver); - - buildFromFile( "panel_landmarks.xml"); + if (is_landmark_panel) + { + buildFromFile("panel_landmarks.xml"); + } } LLLandmarksPanel::~LLLandmarksPanel() { - if (gInventory.containsObserver(mInventoryObserver)) - { - gInventory.removeObserver(mInventoryObserver); - } } BOOL LLLandmarksPanel::postBuild() @@ -221,11 +181,7 @@ BOOL LLLandmarksPanel::postBuild() // mast be called before any other initXXX methods to init Gear menu initListCommandsHandlers(); - - initFavoritesInventoryPanel(); initLandmarksInventoryPanel(); - initMyInventoryPanel(); - initLibraryInventoryPanel(); return TRUE; } @@ -233,30 +189,10 @@ BOOL LLLandmarksPanel::postBuild() // virtual void LLLandmarksPanel::onSearchEdit(const std::string& string) { - // give FolderView a chance to be refreshed. So, made all accordions visible - for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) - { - LLAccordionCtrlTab* tab = *iter; - tab->setVisible(TRUE); - - // expand accordion to see matched items in each one. See EXT-2014. - if (string != "") - { - tab->changeOpenClose(false); - } - - LLPlacesInventoryPanel* inventory_list = dynamic_cast<LLPlacesInventoryPanel*>(tab->getAccordionView()); - if (NULL == inventory_list) continue; - - filter_list(inventory_list, string); - } + filter_list(mCurrentSelectedList, string); if (sFilterSubString != string) sFilterSubString = string; - - // show all folders in Landmarks Accordion for empty filter - // only if Landmarks inventory folder is not empty - updateShowFolderState(); } // virtual @@ -268,11 +204,6 @@ void LLLandmarksPanel::onShowOnMap() return; } - // Disable the "Map" button because loading landmark can take some time. - // During this time the button is useless. It will be enabled on callback finish - // or upon switching to other item. - mShowOnMapBtn->setEnabled(FALSE); - doActionOnCurSelectedLandmark(boost::bind(&LLLandmarksPanel::doShowOnMap, this, _1)); } @@ -297,6 +228,12 @@ void LLLandmarksPanel::onTeleport() } } +/*virtual*/ +void LLLandmarksPanel::onRemoveSelected() +{ + onClipboardAction("delete"); +} + // virtual bool LLLandmarksPanel::isSingleItemSelected() { @@ -316,86 +253,55 @@ bool LLLandmarksPanel::isSingleItemSelected() } // virtual -void LLLandmarksPanel::updateVerbs() -{ - if (!isTabVisible()) - return; - - bool landmark_selected = isLandmarkSelected(); - mTeleportBtn->setEnabled(landmark_selected && isActionEnabled("teleport")); - mShowProfile->setEnabled(landmark_selected && isActionEnabled("more_info")); - mShowOnMapBtn->setEnabled(landmark_selected && isActionEnabled("show_on_map")); - - // TODO: mantipov: Uncomment when mShareBtn is supported - // Share button should be enabled when neither a folder nor a landmark is selected - //mShareBtn->setEnabled(NULL != current_item); - - updateListCommands(); +LLToggleableMenu* LLLandmarksPanel::getSelectionMenu() +{ + LLToggleableMenu* menu = mGearFolderMenu; + + if (mCurrentSelectedList) + { + LLFolderViewModelItemInventory* listenerp = getCurSelectedViewModelItem(); + if (!listenerp) + return menu; + + if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK) + { + menu = mGearLandmarkMenu; + } + } + return menu; } -void LLLandmarksPanel::onSelectionChange(LLPlacesInventoryPanel* inventory_list, const std::deque<LLFolderViewItem*> &items, BOOL user_action) +// virtual +LLToggleableMenu* LLLandmarksPanel::getSortingMenu() { - if (user_action && (items.size() > 0)) - { - deselectOtherThan(inventory_list); - mCurrentSelectedList = inventory_list; - } - updateVerbs(); + return mSortingMenu; } -void LLLandmarksPanel::onSelectorButtonClicked() +// virtual +LLToggleableMenu* LLLandmarksPanel::getCreateMenu() { - // TODO: mantipov: update getting of selected item - // TODO: bind to "i" button - LLFolderViewItem* cur_item = mFavoritesInventoryPanel->getRootFolder()->getCurSelectedItem(); - if (!cur_item) return; - - LLFolderViewModelItemInventory* listenerp = static_cast<LLFolderViewModelItemInventory*>(cur_item->getViewModelItem()); - if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK) - { - LLSD key; - key["type"] = "landmark"; - key["id"] = listenerp->getUUID(); - - LLFloaterSidePanelContainer::showPanel("places", key); - } + return mAddMenu; } -void LLLandmarksPanel::updateShowFolderState() +void LLLandmarksPanel::updateVerbs() { - bool show_all_folders = mLandmarksInventoryPanel->getFilterSubString().empty(); - if (show_all_folders) + if (sRemoveBtn) { - show_all_folders = category_has_descendents(mLandmarksInventoryPanel); + sRemoveBtn->setEnabled(isActionEnabled("delete") && (isFolderSelected() || isLandmarkSelected())); } - - mLandmarksInventoryPanel->setShowFolderState(show_all_folders ? - LLInventoryFilter::SHOW_ALL_FOLDERS : - LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS - ); } void LLLandmarksPanel::setItemSelected(const LLUUID& obj_id, BOOL take_keyboard_focus) { - if (selectItemInAccordionTab(mFavoritesInventoryPanel, "tab_favorites", obj_id, take_keyboard_focus)) - { - return; - } - - if (selectItemInAccordionTab(mLandmarksInventoryPanel, "tab_landmarks", obj_id, take_keyboard_focus)) - { + if (!mCurrentSelectedList) return; - } - if (selectItemInAccordionTab(mMyInventoryPanel, "tab_inventory", obj_id, take_keyboard_focus)) - { - return; - } - - if (selectItemInAccordionTab(mLibraryInventoryPanel, "tab_library", obj_id, take_keyboard_focus)) - { + LLFolderView* root = mCurrentSelectedList->getRootFolder(); + LLFolderViewItem* item = mCurrentSelectedList->getItemByID(obj_id); + if (!item) return; - } + root->setSelection(item, FALSE, take_keyboard_focus); + root->scrollToShowSelection(); } ////////////////////////////////////////////////////////////////////////// @@ -414,18 +320,6 @@ bool LLLandmarksPanel::isFolderSelected() const return current_item && (current_item->getInventoryType() == LLInventoryType::IT_CATEGORY); } -bool LLLandmarksPanel::isReceivedFolderSelected() const -{ - // Received Folder can be only in Landmarks accordion - if (mCurrentSelectedList != mLandmarksInventoryPanel) return false; - - // *TODO: it should be filled with logic when EXT-976 is done. - - LL_WARNS() << "Not implemented yet until EXT-976 is done." << LL_ENDL; - - return false; -} - void LLLandmarksPanel::doActionOnCurSelectedLandmark(LLLandmarkList::loaded_callback_t cb) { LLFolderViewModelItemInventory* cur_item = getCurSelectedViewModelItem(); @@ -455,36 +349,6 @@ LLFolderViewModelItemInventory* LLLandmarksPanel::getCurSelectedViewModelItem() } -LLFolderViewItem* LLLandmarksPanel::selectItemInAccordionTab(LLPlacesInventoryPanel* inventory_list, - const std::string& tab_name, - const LLUUID& obj_id, - BOOL take_keyboard_focus) const -{ - if (!inventory_list) - return NULL; - - LLFolderView* root = inventory_list->getRootFolder(); - - LLFolderViewItem* item = inventory_list->getItemByID(obj_id); - if (!item) - return NULL; - - LLAccordionCtrlTab* tab = getChild<LLAccordionCtrlTab>(tab_name); - if (!tab->isExpanded()) - { - tab->changeOpenClose(false); - } - - root->setSelection(item, FALSE, take_keyboard_focus); - - LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("landmarks_accordion"); - LLRect screen_rc; - localRectToScreen(item->getRect(), &screen_rc); - accordion->notifyParent(LLSD().with("scrollToShowRect", screen_rc.getValue())); - - return item; -} - void LLLandmarksPanel::updateSortOrder(LLInventoryPanel* panel, bool byDate) { if(!panel) return; @@ -500,19 +364,29 @@ void LLLandmarksPanel::updateSortOrder(LLInventoryPanel* panel, bool byDate) } } +void LLLandmarksPanel::resetSelection() +{ +} + // virtual void LLLandmarksPanel::processParcelInfo(const LLParcelData& parcel_data) { //this function will be called after user will try to create a pick for selected landmark. // We have to make request to sever to get parcel_id and snaption_id. - if(isLandmarkSelected()) + if(mCreatePickItemId.notNull()) { - LLFolderViewModelItemInventory* cur_item = getCurSelectedViewModelItem(); - if (!cur_item) return; - LLUUID id = cur_item->getUUID(); - LLInventoryItem* inv_item = mCurrentSelectedList->getModel()->getItem(id); - doActionOnCurSelectedLandmark(boost::bind( - &LLLandmarksPanel::doProcessParcelInfo, this, _1, getCurSelectedItem(), inv_item, parcel_data)); + LLInventoryItem* inv_item = gInventory.getItem(mCreatePickItemId); + + if (inv_item && inv_item->getInventoryType() == LLInventoryType::IT_LANDMARK) + { + // we are processing response for doCreatePick, landmark should be already loaded + LLLandmark* landmark = LLLandmarkActions::getLandmark(inv_item->getUUID()); + if (landmark) + { + doProcessParcelInfo(landmark, inv_item, parcel_data); + } + } + mCreatePickItemId.setNull(); } } @@ -537,16 +411,6 @@ void LLLandmarksPanel::setErrorStatus(S32 status, const std::string& reason) // PRIVATE METHODS ////////////////////////////////////////////////////////////////////////// -void LLLandmarksPanel::initFavoritesInventoryPanel() -{ - mFavoritesInventoryPanel = getChild<LLPlacesInventoryPanel>("favorites_list"); - - initLandmarksPanel(mFavoritesInventoryPanel); - mFavoritesInventoryPanel->getFilter().setEmptyLookupMessage("FavoritesNoMatchingItems"); - - initAccordion("tab_favorites", mFavoritesInventoryPanel, true); -} - void LLLandmarksPanel::initLandmarksInventoryPanel() { mLandmarksInventoryPanel = getChild<LLPlacesInventoryPanel>("landmarks_list"); @@ -558,40 +422,14 @@ void LLLandmarksPanel::initLandmarksInventoryPanel() // subscribe to have auto-rename functionality while creating New Folder mLandmarksInventoryPanel->setSelectCallback(boost::bind(&LLInventoryPanel::onSelectionChange, mLandmarksInventoryPanel, _1, _2)); - mMyLandmarksAccordionTab = initAccordion("tab_landmarks", mLandmarksInventoryPanel, true); -} - -void LLLandmarksPanel::initMyInventoryPanel() -{ - mMyInventoryPanel= getChild<LLPlacesInventoryPanel>("my_inventory_list"); - - initLandmarksPanel(mMyInventoryPanel); - - initAccordion("tab_inventory", mMyInventoryPanel, false); -} - -void LLLandmarksPanel::initLibraryInventoryPanel() -{ - mLibraryInventoryPanel = getChild<LLPlacesInventoryPanel>("library_list"); - - initLandmarksPanel(mLibraryInventoryPanel); - - // We want to fetch only "Landmarks" category from the library. - const LLUUID &landmarks_cat = gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_LANDMARK, false); - if (landmarks_cat.notNull()) - { - LLInventoryModelBackgroundFetch::instance().start(landmarks_cat); - } - - // Expanding "Library" tab for new users who have no landmarks in "My Inventory". - initAccordion("tab_library", mLibraryInventoryPanel, true); + mCurrentSelectedList = mLandmarksInventoryPanel; } void LLLandmarksPanel::initLandmarksPanel(LLPlacesInventoryPanel* inventory_list) { inventory_list->getFilter().setEmptyLookupMessage("PlacesNoMatchingItems"); inventory_list->setFilterTypes(0x1 << LLInventoryType::IT_LANDMARK); - inventory_list->setSelectCallback(boost::bind(&LLLandmarksPanel::onSelectionChange, this, inventory_list, _1, _2)); + inventory_list->setSelectCallback(boost::bind(&LLLandmarksPanel::updateVerbs, this)); inventory_list->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); bool sorting_order = gSavedSettings.getBOOL("LandmarksSortedByDate"); @@ -609,86 +447,10 @@ void LLLandmarksPanel::initLandmarksPanel(LLPlacesInventoryPanel* inventory_list inventory_list->saveFolderState(); } -LLAccordionCtrlTab* LLLandmarksPanel::initAccordion(const std::string& accordion_tab_name, LLPlacesInventoryPanel* inventory_list, bool expand_tab) -{ - LLAccordionCtrlTab* accordion_tab = getChild<LLAccordionCtrlTab>(accordion_tab_name); - - mAccordionTabs.push_back(accordion_tab); - accordion_tab->setDropDownStateChangedCallback( - boost::bind(&LLLandmarksPanel::onAccordionExpandedCollapsed, this, _2, inventory_list)); - accordion_tab->setDisplayChildren(expand_tab); - return accordion_tab; -} - -void LLLandmarksPanel::onAccordionExpandedCollapsed(const LLSD& param, LLPlacesInventoryPanel* inventory_list) -{ - bool expanded = param.asBoolean(); - - if(!expanded && (mCurrentSelectedList == inventory_list)) - { - inventory_list->getRootFolder()->clearSelection(); - - mCurrentSelectedList = NULL; - updateVerbs(); - } - - // Start background fetch, mostly for My Inventory and Library - if (expanded) - { - const LLUUID &cat_id = inventory_list->getRootFolderID(); - // Just because the category itself has been fetched, doesn't mean its child folders have. - /* - if (!gInventory.isCategoryComplete(cat_id)) - */ - { - LLInventoryModelBackgroundFetch::instance().start(cat_id); - } - - // Apply filter substring because it might have been changed - // while accordion was closed. See EXT-3714. - filter_list(inventory_list, sFilterSubString); - } -} - -void LLLandmarksPanel::deselectOtherThan(const LLPlacesInventoryPanel* inventory_list) -{ - if (inventory_list != mFavoritesInventoryPanel) - { - mFavoritesInventoryPanel->clearSelection(); - } - - if (inventory_list != mLandmarksInventoryPanel) - { - mLandmarksInventoryPanel->clearSelection(); - } - if (inventory_list != mMyInventoryPanel) - { - mMyInventoryPanel->clearSelection(); - } - if (inventory_list != mLibraryInventoryPanel) - { - mLibraryInventoryPanel->clearSelection(); - } -} // List Commands Handlers void LLLandmarksPanel::initListCommandsHandlers() { - mListCommands = getChild<LLPanel>("bottom_panel"); - - mGearButton = getChild<LLMenuButton>(OPTIONS_BUTTON_NAME); - mGearButton->setMouseDownCallback(boost::bind(&LLLandmarksPanel::onActionsButtonClick, this)); - - mListCommands->childSetAction(TRASH_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onTrashButtonClick, this)); - - LLDragAndDropButton* trash_btn = mListCommands->getChild<LLDragAndDropButton>(TRASH_BUTTON_NAME); - trash_btn->setDragAndDropHandler(boost::bind(&LLLandmarksPanel::handleDragAndDropToTrash, this - , _4 // BOOL drop - , _5 // EDragAndDropType cargo_type - , _6 // void* cargo_data - , _7 // EAcceptance* accept - )); - mCommitCallbackRegistrar.add("Places.LandmarksGear.Add.Action", boost::bind(&LLLandmarksPanel::onAddAction, this, _2)); mCommitCallbackRegistrar.add("Places.LandmarksGear.CopyPaste.Action", boost::bind(&LLLandmarksPanel::onClipboardAction, this, _2)); mCommitCallbackRegistrar.add("Places.LandmarksGear.Custom.Action", boost::bind(&LLLandmarksPanel::onCustomAction, this, _2)); @@ -697,23 +459,16 @@ void LLLandmarksPanel::initListCommandsHandlers() mEnableCallbackRegistrar.add("Places.LandmarksGear.Enable", boost::bind(&LLLandmarksPanel::isActionEnabled, this, _2)); mGearLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_places_gear_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); mGearFolderMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_places_gear_folder.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - mMenuAdd = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_place_add_button.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mSortingMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_places_gear_sorting.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mAddMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_place_add_button.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); mGearLandmarkMenu->setVisibilityChangeCallback(boost::bind(&LLLandmarksPanel::onMenuVisibilityChange, this, _1, _2)); mGearFolderMenu->setVisibilityChangeCallback(boost::bind(&LLLandmarksPanel::onMenuVisibilityChange, this, _1, _2)); - mListCommands->childSetAction(ADD_BUTTON_NAME, boost::bind(&LLLandmarksPanel::showActionMenu, this, mMenuAdd, ADD_BUTTON_NAME)); -} - - -void LLLandmarksPanel::updateListCommands() -{ - bool add_folder_enabled = isActionEnabled("category"); - bool trash_enabled = isActionEnabled("delete") && (isFolderSelected() || isLandmarkSelected()); - - // keep Options & Add Landmark buttons always enabled - mListCommands->getChildView(ADD_FOLDER_BUTTON_NAME)->setEnabled(add_folder_enabled); - mListCommands->getChildView(TRASH_BUTTON_NAME)->setEnabled(trash_enabled); + // show menus even if all items are disabled + mGearLandmarkMenu->setAlwaysShowMenu(TRUE); + mGearFolderMenu->setAlwaysShowMenu(TRUE); + mAddMenu->setAlwaysShowMenu(TRUE); } void LLLandmarksPanel::updateMenuVisibility(LLUICtrl* menu) @@ -721,43 +476,6 @@ void LLLandmarksPanel::updateMenuVisibility(LLUICtrl* menu) onMenuVisibilityChange(menu, LLSD().with("visibility", true)); } -void LLLandmarksPanel::onActionsButtonClick() -{ - LLToggleableMenu* menu = mGearFolderMenu; - - if(mCurrentSelectedList) - { - LLFolderViewModelItemInventory* listenerp = getCurSelectedViewModelItem(); - if(!listenerp) - return; - - if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK) - { - menu = mGearLandmarkMenu; - } - } - - mGearButton->setMenu(menu); -} - -void LLLandmarksPanel::showActionMenu(LLMenuGL* menu, std::string spawning_view_name) -{ - if (menu) - { - menu->buildDrawLabels(); - menu->updateParent(LLMenuGL::sMenuContainer); - menu->arrangeAndClear(); - - LLView* spawning_view = getChild<LLView>(spawning_view_name); - - S32 menu_x, menu_y; - //show menu in co-ordinates of panel - spawning_view->localPointToOtherView(0, spawning_view->getRect().getHeight(), &menu_x, &menu_y, this); - menu_y += menu->getRect().getHeight(); - LLMenuGL::showPopup(this, menu, menu_x, menu_y); - } -} - void LLLandmarksPanel::onTrashButtonClick() const { onClipboardAction("delete"); @@ -769,7 +487,8 @@ void LLLandmarksPanel::onAddAction(const LLSD& userdata) const LLFolderViewItem* item = getCurSelectedItem(); std::string command_name = userdata.asString(); - if("add_landmark" == command_name) + if("add_landmark" == command_name + || "add_landmark_root" == command_name) { LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); if(landmark) @@ -778,7 +497,20 @@ void LLLandmarksPanel::onAddAction(const LLSD& userdata) const } else { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); + LLSD args; + args["type"] = "create_landmark"; + if ("add_landmark" == command_name + && view_model->getInventoryType() == LLInventoryType::IT_CATEGORY) + { + args["dest_folder"] = view_model->getUUID(); + } + if ("add_landmark_root" == command_name + && mCurrentSelectedList == mLandmarksInventoryPanel) + { + args["dest_folder"] = mLandmarksInventoryPanel->getRootFolderID(); + } + // else will end up in favorites + LLFloaterReg::showInstance("add_landmark", args); } } else if ("category" == command_name) @@ -810,13 +542,14 @@ void LLLandmarksPanel::onAddAction(const LLSD& userdata) const //in case My Landmarks tab is completely empty (thus cannot be determined as being selected) menu_create_inventory_item(mLandmarksInventoryPanel, NULL, LLSD("category"), gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK)); - - if (mMyLandmarksAccordionTab) - { - mMyLandmarksAccordionTab->changeOpenClose(false); - } } } + else if ("category_root" == command_name) + { + //in case My Landmarks tab is completely empty (thus cannot be determined as being selected) + menu_create_inventory_item(mLandmarksInventoryPanel, NULL, LLSD("category"), + gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK)); + } } void LLLandmarksPanel::onClipboardAction(const LLSD& userdata) const @@ -850,27 +583,11 @@ void LLLandmarksPanel::onFoldingAction(const LLSD& userdata) if ("expand_all" == command_name) { - expand_all_folders(mFavoritesInventoryPanel->getRootFolder()); - expand_all_folders(mLandmarksInventoryPanel->getRootFolder()); - expand_all_folders(mMyInventoryPanel->getRootFolder()); - expand_all_folders(mLibraryInventoryPanel->getRootFolder()); - - for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) - { - (*iter)->changeOpenClose(false); - } + expand_all_folders(mCurrentSelectedList->getRootFolder()); } else if ("collapse_all" == command_name) { - collapse_all_folders(mFavoritesInventoryPanel->getRootFolder()); - collapse_all_folders(mLandmarksInventoryPanel->getRootFolder()); - collapse_all_folders(mMyInventoryPanel->getRootFolder()); - collapse_all_folders(mLibraryInventoryPanel->getRootFolder()); - - for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) - { - (*iter)->changeOpenClose(true); - } + collapse_all_folders(mCurrentSelectedList->getRootFolder()); } else if ("sort_by_date" == command_name) { @@ -878,8 +595,6 @@ void LLLandmarksPanel::onFoldingAction(const LLSD& userdata) sorting_order=!sorting_order; gSavedSettings.setBOOL("LandmarksSortedByDate",sorting_order); updateSortOrder(mLandmarksInventoryPanel, sorting_order); - updateSortOrder(mMyInventoryPanel, sorting_order); - updateSortOrder(mLibraryInventoryPanel, sorting_order); } else { @@ -911,51 +626,21 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const ? mCurrentSelectedList->getRootFolder() : NULL; + bool is_single_selection = root_folder_view && root_folder_view->getSelectedCount() == 1; + if ("collapse_all" == command_name) { - bool disable_collapse_all = !has_expanded_folders(mFavoritesInventoryPanel->getRootFolder()) - && !has_expanded_folders(mLandmarksInventoryPanel->getRootFolder()) - && !has_expanded_folders(mMyInventoryPanel->getRootFolder()) - && !has_expanded_folders(mLibraryInventoryPanel->getRootFolder()); - if (disable_collapse_all) - { - for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) - { - if ((*iter)->isExpanded()) - { - disable_collapse_all = false; - break; - } - } - } - - return !disable_collapse_all; + return has_expanded_folders(mCurrentSelectedList->getRootFolder()); } else if ("expand_all" == command_name) { - bool disable_expand_all = !has_collapsed_folders(mFavoritesInventoryPanel->getRootFolder()) - && !has_collapsed_folders(mLandmarksInventoryPanel->getRootFolder()) - && !has_collapsed_folders(mMyInventoryPanel->getRootFolder()) - && !has_collapsed_folders(mLibraryInventoryPanel->getRootFolder()); - if (disable_expand_all) - { - for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) - { - if (!(*iter)->isExpanded()) - { - disable_expand_all = false; - break; - } - } - } - - return !disable_expand_all; + return has_collapsed_folders(mCurrentSelectedList->getRootFolder()); } else if ("sort_by_date" == command_name) { - // disable "sort_by_date" for Favorites accordion because + // disable "sort_by_date" for Favorites tab because // it has its own items order. EXT-1758 - if (mCurrentSelectedList == mFavoritesInventoryPanel) + if (!isLandmarksPanel) { return false; } @@ -972,6 +657,11 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const std::set<LLFolderViewItem*> selected_uuids = root_folder_view->getSelectionList(); + if (selected_uuids.empty()) + { + return false; + } + // Allow to execute the command only if it can be applied to all selected items. for (std::set<LLFolderViewItem*>::const_iterator iter = selected_uuids.begin(); iter != selected_uuids.end(); ++iter) { @@ -992,7 +682,6 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const ) { // disable some commands for multi-selection. EXT-1757 - bool is_single_selection = root_folder_view && root_folder_view->getSelectedCount() == 1; if (!is_single_selection) { return false; @@ -1011,9 +700,9 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const // Disable "Show on Map" if landmark loading is in progress. return !gLandmarkList.isAssetInLoadedCallbackMap(asset_uuid); - } - else if ("rename" == command_name) - { + } + else if ("rename" == command_name) + { LLFolderViewItem* selected_item = getCurSelectedItem(); if (!selected_item) return false; @@ -1022,16 +711,10 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const return true; } - else if("category" == command_name) - { - // we can add folder only in Landmarks Accordion - if (mCurrentSelectedList == mLandmarksInventoryPanel) - { - // ... but except Received folder - return !isReceivedFolderSelected(); - } - //"Add a folder" is enabled by default (case when My Landmarks is empty) - else return true; + if ("category_root" == command_name || "category" == command_name) + { + // we can add folder only in Landmarks tab + return isLandmarksPanel; } else if("create_pick" == command_name) { @@ -1045,6 +728,78 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const } return false; } + else if ("add_landmark" == command_name) + { + if (!is_single_selection) + { + return false; + } + + LLFolderViewModelItemInventory* view_model = getCurSelectedViewModelItem(); + if (!view_model || view_model->getInventoryType() != LLInventoryType::IT_CATEGORY) + { + return false; + } + LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); + if (landmark) + { + //already exists + return false; + } + return true; + } + else if ("add_landmark_root" == command_name) + { + LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); + if (landmark) + { + //already exists + return false; + } + return true; + } + else if ("share" == command_name) + { + if (!mCurrentSelectedList) + { + return false; + } + if (!LLAvatarActions::canShareSelectedItems(mCurrentSelectedList)) + { + return false; + } + return true; + } + else if (command_name == "move_to_landmarks" || command_name == "move_to_favorites") + { + LLFolderViewModelItemInventory* cur_item_model = getCurSelectedViewModelItem(); + if (cur_item_model) + { + LLFolderType::EType folder_type = command_name == "move_to_landmarks" ? LLFolderType::FT_FAVORITE : LLFolderType::FT_LANDMARK; + if (!gInventory.isObjectDescendentOf(cur_item_model->getUUID(), gInventory.findCategoryUUIDForType(folder_type))) + { + return false; + } + + if (root_folder_view) + { + std::set<LLFolderViewItem*> selected_uuids = root_folder_view->getSelectionList(); + for (std::set<LLFolderViewItem*>::const_iterator iter = selected_uuids.begin(); iter != selected_uuids.end(); ++iter) + { + LLFolderViewItem* item = *iter; + if (!item) return false; + + cur_item_model = static_cast<LLFolderViewModelItemInventory*>(item->getViewModelItem()); + if (!cur_item_model || cur_item_model->getInventoryType() != LLInventoryType::IT_LANDMARK) + { + return false; + } + } + return true; + } + } + return false; + } else { LL_WARNS() << "Unprocessed command has come: " << command_name << LL_ENDL; @@ -1070,12 +825,42 @@ void LLLandmarksPanel::onCustomAction(const LLSD& userdata) } else if ("create_pick" == command_name) { - doActionOnCurSelectedLandmark(boost::bind(&LLLandmarksPanel::doCreatePick, this, _1)); + LLFolderViewModelItemInventory* cur_item = getCurSelectedViewModelItem(); + if (cur_item) + { + doActionOnCurSelectedLandmark(boost::bind(&LLLandmarksPanel::doCreatePick, this, _1, cur_item->getUUID())); + } } + else if ("share" == command_name && mCurrentSelectedList) + { + LLAvatarActions::shareWithAvatars(mCurrentSelectedList); + } else if ("restore" == command_name && mCurrentSelectedList) { mCurrentSelectedList->doToSelected(userdata); } + else if (command_name == "move_to_landmarks" || command_name == "move_to_favorites") + { + LLFolderView* root_folder_view = mCurrentSelectedList ? mCurrentSelectedList->getRootFolder() : NULL; + if (root_folder_view) + { + LLFolderType::EType folder_type = command_name == "move_to_landmarks" ? LLFolderType::FT_LANDMARK : LLFolderType::FT_FAVORITE; + std::set<LLFolderViewItem*> selected_uuids = root_folder_view->getSelectionList(); + for (std::set<LLFolderViewItem*>::const_iterator iter = selected_uuids.begin(); iter != selected_uuids.end(); ++iter) + { + LLFolderViewItem* item = *iter; + if (item) + { + LLFolderViewModelItemInventory* item_model = static_cast<LLFolderViewModelItemInventory*>(item->getViewModelItem()); + if (item_model) + { + change_item_parent(item_model->getUUID(), gInventory.findCategoryUUIDForType(folder_type)); + } + } + } + } + + } } void LLLandmarksPanel::onMenuVisibilityChange(LLUICtrl* ctrl, const LLSD& param) @@ -1142,29 +927,17 @@ bool LLLandmarksPanel::canItemBeModified(const std::string& command_name, LLFold if (!item) return false; - // nothing can be modified in Library - if (mLibraryInventoryPanel == mCurrentSelectedList) return false; - bool can_be_modified = false; // landmarks can be modified in any other accordion... if (static_cast<LLFolderViewModelItemInventory*>(item->getViewModelItem())->getInventoryType() == LLInventoryType::IT_LANDMARK) { can_be_modified = true; - - // we can modify landmarks anywhere except paste to My Inventory - if ("paste" == command_name) - { - can_be_modified = (mCurrentSelectedList != mMyInventoryPanel); - } } else { // ...folders only in the Landmarks accordion... - can_be_modified = mLandmarksInventoryPanel == mCurrentSelectedList; - - // ...except "Received" folder - can_be_modified &= !isReceivedFolderSelected(); + can_be_modified = isLandmarksPanel; } // then ask LLFolderView permissions @@ -1281,12 +1054,10 @@ void LLLandmarksPanel::doShowOnMap(LLLandmark* landmark) LLFloaterReg::showInstance("world_map", "center"); } - mShowOnMapBtn->setEnabled(TRUE); mGearLandmarkMenu->setItemEnabled("show_on_map", TRUE); } void LLLandmarksPanel::doProcessParcelInfo(LLLandmark* landmark, - LLFolderViewItem* cur_item, LLInventoryItem* inv_item, const LLParcelData& parcel_data) { @@ -1315,7 +1086,7 @@ void LLLandmarksPanel::doProcessParcelInfo(LLLandmark* landmark, LLPickData data; data.pos_global = landmark_global_pos; - data.name = cur_item->getName(); + data.name = inv_item->getName(); data.desc = inv_item->getDescription(); data.snapshot_id = parcel_data.snapshot_id; data.parcel_id = parcel_data.parcel_id; @@ -1335,11 +1106,13 @@ void LLLandmarksPanel::doProcessParcelInfo(LLLandmark* landmark, panel_pick, panel_places,params)); } -void LLLandmarksPanel::doCreatePick(LLLandmark* landmark) +void LLLandmarksPanel::doCreatePick(LLLandmark* landmark, const LLUUID &item_id) { LLViewerRegion* region = gAgent.getRegion(); if (!region) return; + mCreatePickItemId = item_id; + LLGlobalVec pos_global; LLUUID region_id; landmark->getGlobalPos(pos_global); @@ -1392,27 +1165,12 @@ static void filter_list(LLPlacesInventoryPanel* inventory_list, const std::strin inventory_list->setFilterSubString(string); } -static bool category_has_descendents(LLPlacesInventoryPanel* inventory_list) -{ - LLViewerInventoryCategory* category = gInventory.getCategory(inventory_list->getRootFolderID()); - if (category) - { - return category->getDescendentCount() > 0; - } - - return false; -} - static void collapse_all_folders(LLFolderView* root_folder) { if (!root_folder) return; root_folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); - - // The top level folder is invisible, it must be open to - // display its sub-folders. - root_folder->openTopLevelFolders(); root_folder->arrangeAll(); } @@ -1479,4 +1237,31 @@ void toggle_restore_menu(LLMenuGL *menu, BOOL visible, BOOL enabled) } } } + +LLFavoritesPanel::LLFavoritesPanel() + : LLLandmarksPanel(false) +{ + buildFromFile("panel_favorites.xml"); +} + +BOOL LLFavoritesPanel::postBuild() +{ + if (!gInventory.isInventoryUsable()) + return FALSE; + + // mast be called before any other initXXX methods to init Gear menu + LLLandmarksPanel::initListCommandsHandlers(); + + initFavoritesInventoryPanel(); + + return TRUE; +} + +void LLFavoritesPanel::initFavoritesInventoryPanel() +{ + mCurrentSelectedList = getChild<LLPlacesInventoryPanel>("favorites_list"); + + LLLandmarksPanel::initLandmarksPanel(mCurrentSelectedList); + mCurrentSelectedList->getFilter().setEmptyLookupMessage("FavoritesNoMatchingItems"); +} // EOF diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index c11cbe05ae..d7408269b5 100644 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -50,81 +50,69 @@ class LLLandmarksPanel : public LLPanelPlacesTab, LLRemoteParcelInfoObserver { public: LLLandmarksPanel(); + LLLandmarksPanel(bool is_landmark_panel); virtual ~LLLandmarksPanel(); - /*virtual*/ BOOL postBuild(); - /*virtual*/ void onSearchEdit(const std::string& string); - /*virtual*/ void onShowOnMap(); - /*virtual*/ void onShowProfile(); - /*virtual*/ void onTeleport(); - /*virtual*/ void updateVerbs(); - /*virtual*/ bool isSingleItemSelected(); + BOOL postBuild() override; + void onSearchEdit(const std::string& string) override; + void onShowOnMap() override; + void onShowProfile() override; + void onTeleport() override; + void onRemoveSelected() override; + void updateVerbs() override; + bool isSingleItemSelected() override; + + LLToggleableMenu* getSelectionMenu() override; + LLToggleableMenu* getSortingMenu() override; + LLToggleableMenu* getCreateMenu() override; + + /** + * Processes drag-n-drop of the Landmarks and folders into trash button. + */ + bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept) override; - void onSelectionChange(LLPlacesInventoryPanel* inventory_list, const std::deque<LLFolderViewItem*> &items, BOOL user_action); - void onSelectorButtonClicked(); void setCurrentSelectedList(LLPlacesInventoryPanel* inventory_list) { mCurrentSelectedList = inventory_list; } /** - * Update filter ShowFolderState setting to show empty folder message - * if Landmarks inventory folder is empty. - */ - void updateShowFolderState(); - - /** * Selects item with "obj_id" in one of accordion tabs. */ void setItemSelected(const LLUUID& obj_id, BOOL take_keyboard_focus); - LLPlacesInventoryPanel* getLibraryInventoryPanel() { return mLibraryInventoryPanel; } - void updateMenuVisibility(LLUICtrl* menu); + void doCreatePick(LLLandmark* landmark, const LLUUID &item_id ); + + void resetSelection(); + protected: /** * @return true - if current selected panel is not null and selected item is a landmark */ bool isLandmarkSelected() const; bool isFolderSelected() const; - bool isReceivedFolderSelected() const; void doActionOnCurSelectedLandmark(LLLandmarkList::loaded_callback_t cb); LLFolderViewItem* getCurSelectedItem() const; LLFolderViewModelItemInventory* getCurSelectedViewModelItem() const; - /** - * Selects item with "obj_id" in "inventory_list" and scrolls accordion - * scrollbar to show the item. - * Returns pointer to the item if it is found in "inventory_list", otherwise NULL. - */ - LLFolderViewItem* selectItemInAccordionTab(LLPlacesInventoryPanel* inventory_list, - const std::string& tab_name, - const LLUUID& obj_id, - BOOL take_keyboard_focus) const; - void updateSortOrder(LLInventoryPanel* panel, bool byDate); //LLRemoteParcelInfoObserver interface - /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); - /*virtual*/ void setParcelID(const LLUUID& parcel_id); - /*virtual*/ void setErrorStatus(S32 status, const std::string& reason); + void processParcelInfo(const LLParcelData& parcel_data) override; + void setParcelID(const LLUUID& parcel_id) override; + void setErrorStatus(S32 status, const std::string& reason) override; + + // List Commands Handlers + void initListCommandsHandlers(); + void initLandmarksPanel(LLPlacesInventoryPanel* inventory_list); + + LLPlacesInventoryPanel* mCurrentSelectedList; private: - void initFavoritesInventoryPanel(); void initLandmarksInventoryPanel(); - void initMyInventoryPanel(); - void initLibraryInventoryPanel(); - void initLandmarksPanel(LLPlacesInventoryPanel* inventory_list); - LLAccordionCtrlTab* initAccordion(const std::string& accordion_tab_name, LLPlacesInventoryPanel* inventory_list, bool expand_tab); - void onAccordionExpandedCollapsed(const LLSD& param, LLPlacesInventoryPanel* inventory_list); - void deselectOtherThan(const LLPlacesInventoryPanel* inventory_list); - // List Commands Handlers - void initListCommandsHandlers(); - void updateListCommands(); - void onActionsButtonClick(); - void showActionMenu(LLMenuGL* menu, std::string spawning_view_name); void onTrashButtonClick() const; void onAddAction(const LLSD& command_name) const; void onClipboardAction(const LLSD& command_name) const; @@ -151,38 +139,33 @@ private: void onPickPanelExit( LLPanelPickEdit* pick_panel, LLView* owner, const LLSD& params); /** - * Processes drag-n-drop of the Landmarks and folders into trash button. - */ - bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept); - - /** * Landmark actions callbacks. Fire when a landmark is loaded from the list. */ void doShowOnMap(LLLandmark* landmark); void doProcessParcelInfo(LLLandmark* landmark, - LLFolderViewItem* cur_item, LLInventoryItem* inv_item, const LLParcelData& parcel_data); - void doCreatePick(LLLandmark* landmark); private: - LLPlacesInventoryPanel* mFavoritesInventoryPanel; LLPlacesInventoryPanel* mLandmarksInventoryPanel; - LLPlacesInventoryPanel* mMyInventoryPanel; - LLPlacesInventoryPanel* mLibraryInventoryPanel; - LLMenuButton* mGearButton; LLToggleableMenu* mGearLandmarkMenu; LLToggleableMenu* mGearFolderMenu; - LLMenuGL* mMenuAdd; - LLPlacesInventoryPanel* mCurrentSelectedList; - LLInventoryObserver* mInventoryObserver; + LLToggleableMenu* mSortingMenu; + LLToggleableMenu* mAddMenu; - LLPanel* mListCommands; + bool isLandmarksPanel; - typedef std::vector<LLAccordionCtrlTab*> accordion_tabs_t; - accordion_tabs_t mAccordionTabs; + LLUUID mCreatePickItemId; // item we requested a pick for +}; - LLAccordionCtrlTab* mMyLandmarksAccordionTab; + +class LLFavoritesPanel : public LLLandmarksPanel +{ +public: + LLFavoritesPanel(); + + BOOL postBuild() override; + void initFavoritesInventoryPanel(); }; #endif //LL_LLPANELLANDMARKS_H diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index e253557797..381b80fb66 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -41,7 +41,6 @@ #include "llcommandhandler.h" // for secondlife:///app/login/ #include "llcombobox.h" #include "llviewercontrol.h" -#include "llfloaterpreference.h" #include "llfocusmgr.h" #include "lllineeditor.h" #include "llnotificationsutil.h" @@ -77,6 +76,60 @@ LLPanelLogin *LLPanelLogin::sInstance = NULL; BOOL LLPanelLogin::sCapslockDidNotification = FALSE; BOOL LLPanelLogin::sCredentialSet = FALSE; +// Helper functions + +LLPointer<LLCredential> load_user_credentials(std::string &user_key) +{ + if (gSecAPIHandler->hasCredentialMap("login_list", LLGridManager::getInstance()->getGrid())) + { + // user_key should be of "name Resident" format + return gSecAPIHandler->loadFromCredentialMap("login_list", LLGridManager::getInstance()->getGrid(), user_key); + } + else + { + // legacy (or legacy^2, since it also tries to load from settings) + return gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + } +} + +// keys are lower case to be case insensitive so they are not always +// identical to names which retain user input, like: +// "AwEsOmE Resident" -> "awesome_resident" +std::string get_user_key_from_name(const std::string &username) +{ + std::string key = username; + LLStringUtil::trim(key); + LLStringUtil::toLower(key); + if (!LLGridManager::getInstance()->isSystemGrid()) + { + size_t separator_index = username.find_first_of(" "); + if (separator_index == username.npos) + { + // CRED_IDENTIFIER_TYPE_ACCOUNT + return key; + } + } + // CRED_IDENTIFIER_TYPE_AGENT + size_t separator_index = username.find_first_of(" ._"); + std::string first = username.substr(0, separator_index); + std::string last; + if (separator_index != username.npos) + { + last = username.substr(separator_index + 1, username.npos); + LLStringUtil::trim(last); + } + else + { + // ...on Linden grids, single username users as considered to have + // last name "Resident" + // *TODO: Make login.cgi support "account_name" like above + last = "resident"; + } + + key = first + "_" + last; + return key; +} + class LLLoginLocationAutoHandler : public LLCommandHandler { public: @@ -168,6 +221,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, mCallback(callback), mCallbackData(cb_data), mListener(new LLPanelLoginListener(this)), + mFirstLoginThisInstall(gSavedSettings.getBOOL("FirstLoginThisInstall")), mUsernameLength(0), mPasswordLength(0), mLocationLength(0), @@ -186,7 +240,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, login_holder->addChild(this); } - if (gSavedSettings.getBOOL("FirstLoginThisInstall")) + if (mFirstLoginThisInstall) { buildFromFile( "panel_login_first.xml"); } @@ -200,41 +254,45 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, LLLineEditor* password_edit(getChild<LLLineEditor>("password_edit")); password_edit->setKeystrokeCallback(onPassKey, this); // STEAM-14: When user presses Enter with this field in focus, initiate login - password_edit->setCommitCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); + password_edit->setCommitCallback(boost::bind(&LLPanelLogin::onClickConnect, false)); // change z sort of clickable text to be behind buttons sendChildToBack(getChildView("forgot_password_text")); sendChildToBack(getChildView("sign_up_text")); - LLComboBox* favorites_combo = getChild<LLComboBox>("start_location_combo"); - updateLocationSelectorsVisibility(); // separate so that it can be called from preferences - favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); - favorites_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLocationSLURL, this)); - - LLComboBox* server_choice_combo = getChild<LLComboBox>("server_combo"); - server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectServer, this)); - - // Load all of the grids, sorted, and then add a bar and the current grid at the top - server_choice_combo->removeall(); - - std::string current_grid = LLGridManager::getInstance()->getGrid(); - std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(); - for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin(); - grid_choice != known_grids.end(); - grid_choice++) - { - if (!grid_choice->first.empty() && current_grid != grid_choice->first) - { - LL_DEBUGS("AppInit")<<"adding "<<grid_choice->first<<LL_ENDL; - server_choice_combo->add(grid_choice->second, grid_choice->first); - } - } - server_choice_combo->sortByName(); - LL_DEBUGS("AppInit")<<"adding current "<<current_grid<<LL_ENDL; - server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(), - current_grid, - ADD_TOP); - server_choice_combo->selectFirstItem(); + std::string current_grid = LLGridManager::getInstance()->getGrid(); + if (!mFirstLoginThisInstall) + { + LLComboBox* favorites_combo = getChild<LLComboBox>("start_location_combo"); + updateLocationSelectorsVisibility(); // separate so that it can be called from preferences + favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, false)); + favorites_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLocationSLURL, this)); + + LLComboBox* server_choice_combo = getChild<LLComboBox>("server_combo"); + server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectServer, this)); + + // Load all of the grids, sorted, and then add a bar and the current grid at the top + server_choice_combo->removeall(); + + std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(); + for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin(); + grid_choice != known_grids.end(); + grid_choice++) + { + if (!grid_choice->first.empty() && current_grid != grid_choice->first) + { + LL_DEBUGS("AppInit") << "adding " << grid_choice->first << LL_ENDL; + server_choice_combo->add(grid_choice->second, grid_choice->first); + } + } + server_choice_combo->sortByName(); + + LL_DEBUGS("AppInit") << "adding current " << current_grid << LL_ENDL; + server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(), + current_grid, + ADD_TOP); + server_choice_combo->selectFirstItem(); + } LLSLURL start_slurl(LLStartUp::getStartSLURL()); // The StartSLURL might have been set either by an explicit command-line @@ -279,10 +337,10 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, LLButton* def_btn = getChild<LLButton>("connect_btn"); setDefaultBtn(def_btn); - std::string channel = LLVersionInfo::getChannel(); + std::string channel = LLVersionInfo::instance().getChannel(); std::string version = llformat("%s (%d)", - LLVersionInfo::getShortVersion().c_str(), - LLVersionInfo::getBuild()); + LLVersionInfo::instance().getShortVersion().c_str(), + LLVersionInfo::instance().getBuild()); LLTextBox* forgot_password_text = getChild<LLTextBox>("forgot_password_text"); forgot_password_text->setClickedCallback(onClickForgotPassword, NULL); @@ -297,14 +355,30 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, loadLoginPage(); LLComboBox* username_combo(getChild<LLComboBox>("username_combo")); - username_combo->setTextChangedCallback(boost::bind(&LLPanelLogin::addFavoritesToStartLocation, this)); + username_combo->setTextChangedCallback(boost::bind(&LLPanelLogin::onUserNameTextEnty, this)); // STEAM-14: When user presses Enter with this field in focus, initiate login - username_combo->setCommitCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); + username_combo->setCommitCallback(boost::bind(&LLPanelLogin::onUserListCommit, this)); + username_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); username_combo->setKeystrokeOnEsc(TRUE); + + if (!mFirstLoginThisInstall) + { + LLCheckBoxCtrl* remember_name = getChild<LLCheckBoxCtrl>("remember_name"); + remember_name->setCommitCallback(boost::bind(&LLPanelLogin::onRememberUserCheck, this)); + } } void LLPanelLogin::addFavoritesToStartLocation() { + if (mFirstLoginThisInstall) + { + // first login panel has no favorites, just update name length and buttons + std::string user_defined_name = getChild<LLComboBox>("username_combo")->getSimple(); + mUsernameLength = user_defined_name.length(); + updateLoginButtons(); + return; + } + // Clear the combo. LLComboBox* combo = getChild<LLComboBox>("start_location_combo"); if (!combo) return; @@ -316,14 +390,14 @@ void LLPanelLogin::addFavoritesToStartLocation() // Load favorites into the combo. std::string user_defined_name = getChild<LLComboBox>("username_combo")->getSimple(); + LLStringUtil::trim(user_defined_name); LLStringUtil::toLower(user_defined_name); - std::replace(user_defined_name.begin(), user_defined_name.end(), '.', ' '); std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites_" + LLGridManager::getInstance()->getGrid() + ".xml"); std::string old_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml"); mUsernameLength = user_defined_name.length(); updateLoginButtons(); - std::string::size_type index = user_defined_name.find(' '); + std::string::size_type index = user_defined_name.find_first_of(" ._"); if (index != std::string::npos) { std::string username = user_defined_name.substr(0, index); @@ -332,6 +406,10 @@ void LLPanelLogin::addFavoritesToStartLocation() { user_defined_name = username; } + else + { + user_defined_name = username + " " + lastname; + } } LLSD fav_llsd; @@ -377,6 +455,13 @@ void LLPanelLogin::addFavoritesToStartLocation() } break; } + if (combo->getValue().asString().empty()) + { + combo->selectFirstItem(); + // Value 'home' or 'last' should have been taken from NextLoginLocation + // but NextLoginLocation was not set, so init it from combo explicitly + onLocationSLURL(); + } } LLPanelLogin::~LLPanelLogin() @@ -443,24 +528,6 @@ void LLPanelLogin::giveFocus() } // static -void LLPanelLogin::showLoginWidgets() -{ - if (sInstance) - { - // *NOTE: Mani - This may or may not be obselete code. - // It seems to be part of the defunct? reg-in-client project. - sInstance->getChildView("login_widgets")->setVisible( true); - LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html"); - - // *TODO: Append all the usual login parameters, like first_login=Y etc. - std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage(); - web_browser->navigateTo( splash_screen_url, "text/html" ); - LLUICtrl* username_combo = sInstance->getChild<LLUICtrl>("username_combo"); - username_combo->setFocus(TRUE); - } -} - -// static void LLPanelLogin::show(const LLRect &rect, void (*callback)(S32 option, void* user_data), void* callback_data) @@ -480,9 +547,64 @@ void LLPanelLogin::show(const LLRect &rect, gFocusMgr.setDefaultKeyboardFocus(sInstance); } +//static +void LLPanelLogin::reshapePanel() +{ + if (sInstance) + { + LLRect rect = sInstance->getRect(); + sInstance->reshape(rect.getWidth(), rect.getHeight()); + } +} + +//static +void LLPanelLogin::populateFields(LLPointer<LLCredential> credential, bool remember_user, bool remember_psswrd) +{ + if (!sInstance) + { + LL_WARNS() << "Attempted fillFields with no login view shown" << LL_ENDL; + return; + } + if (sInstance->mFirstLoginThisInstall) + { + LLUICtrl* remember_check = sInstance->getChild<LLUICtrl>("remember_check"); + remember_check->setValue(remember_psswrd); + // no list to populate + setFields(credential); + } + else + { + sInstance->getChild<LLUICtrl>("remember_name")->setValue(remember_user); + LLUICtrl* remember_password = sInstance->getChild<LLUICtrl>("remember_password"); + remember_password->setValue(remember_user && remember_psswrd); + remember_password->setEnabled(remember_user); + sInstance->populateUserList(credential); + } +} + +//static +void LLPanelLogin::resetFields() +{ + if (!sInstance) + { + // class not existing at this point might happen since this + // function is used to reset list in case of changes by external sources + return; + } + if (sInstance->mFirstLoginThisInstall) + { + // no list to populate + LL_WARNS() << "Shouldn't happen, user should have no ability to modify list on first install" << LL_ENDL; + } + else + { + LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + sInstance->populateUserList(cred); + } +} + // static -void LLPanelLogin::setFields(LLPointer<LLCredential> credential, - BOOL remember) +void LLPanelLogin::setFields(LLPointer<LLCredential> credential) { if (!sInstance) { @@ -492,36 +614,43 @@ void LLPanelLogin::setFields(LLPointer<LLCredential> credential, sCredentialSet = TRUE; LL_INFOS("Credentials") << "Setting login fields to " << *credential << LL_ENDL; - LLSD identifier = credential->getIdentifier(); - if((std::string)identifier["type"] == "agent") + LLSD identifier = credential.notNull() ? credential->getIdentifier() : LLSD(); + + if(identifier.has("type") && (std::string)identifier["type"] == "agent") { + // not nessesary for panel_login.xml, needed for panel_login_first.xml std::string firstname = identifier["first_name"].asString(); std::string lastname = identifier["last_name"].asString(); std::string login_id = firstname; - if (!lastname.empty() && lastname != "Resident") + if (!lastname.empty() && lastname != "Resident" && lastname != "resident") { // support traditional First Last name SLURLs login_id += " "; login_id += lastname; } - sInstance->getChild<LLComboBox>("username_combo")->setLabel(login_id); + sInstance->getChild<LLComboBox>("username_combo")->setLabel(login_id); + sInstance->mUsernameLength = login_id.length(); } - else if((std::string)identifier["type"] == "account") + else if(identifier.has("type") && (std::string)identifier["type"] == "account") { - sInstance->getChild<LLComboBox>("username_combo")->setLabel((std::string)identifier["account_name"]); + std::string login_id = identifier["account_name"].asString(); + sInstance->getChild<LLComboBox>("username_combo")->setLabel(login_id); + sInstance->mUsernameLength = login_id.length(); } else { - sInstance->getChild<LLComboBox>("username_combo")->setLabel(std::string()); + sInstance->getChild<LLComboBox>("username_combo")->setLabel(std::string()); + sInstance->mUsernameLength = 0; } + sInstance->addFavoritesToStartLocation(); // if the password exists in the credential, set the password field with // a filler to get some stars - LLSD authenticator = credential->getAuthenticator(); + LLSD authenticator = credential.notNull() ? credential->getAuthenticator() : LLSD(); LL_INFOS("Credentials") << "Setting authenticator field " << authenticator["type"].asString() << LL_ENDL; if(authenticator.isMap() && authenticator.has("secret") && - (authenticator["secret"].asString().size() > 0) && remember) + (authenticator["secret"].asString().size() > 0)) { // This is a MD5 hex digest of a password. @@ -535,38 +664,28 @@ void LLPanelLogin::setFields(LLPointer<LLCredential> credential, } else { - sInstance->getChild<LLUICtrl>("password_edit")->setValue(std::string()); + sInstance->getChild<LLUICtrl>("password_edit")->setValue(std::string()); + sInstance->mPasswordLength = 0; } - sInstance->getChild<LLUICtrl>("remember_check")->setValue(remember); } - // static void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, - BOOL& remember) + bool& remember_user, + bool& remember_psswrd) { if (!sInstance) { LL_WARNS() << "Attempted getFields with no login view shown" << LL_ENDL; return; } - - // load the credential so we can pass back the stored password or hash if the user did - // not modify the password field. - - credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); LLSD identifier = LLSD::emptyMap(); LLSD authenticator = LLSD::emptyMap(); - - if(credential.notNull()) - { - authenticator = credential->getAuthenticator(); - } - std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString(); - LLStringUtil::trim(username); + std::string username = sInstance->getChild<LLComboBox>("username_combo")->getSimple(); std::string password = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString(); + LLStringUtil::trim(username); LL_INFOS("Credentials", "Authentication") << "retrieving username:" << username << LL_ENDL; // determine if the username is a first/last form or not. @@ -581,11 +700,27 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, if (LLPanelLogin::sInstance->mPasswordModified) { - authenticator = LLSD::emptyMap(); // password is plaintext authenticator["type"] = CRED_AUTHENTICATOR_TYPE_CLEAR; authenticator["secret"] = password; } + else + { + credential = load_user_credentials(username); + if (credential.notNull()) + { + authenticator = credential->getAuthenticator(); + if (authenticator.emptyMap()) + { + // Likely caused by user trying to log in to non-system grid + // with unsupported name format, just retry + LL_WARNS() << "Authenticator failed to load for: " << username << LL_ENDL; + // password is plaintext + authenticator["type"] = CRED_AUTHENTICATOR_TYPE_CLEAR; + authenticator["secret"] = password; + } + } + } } else { @@ -597,7 +732,7 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, if (separator_index != username.npos) { last = username.substr(separator_index+1, username.npos); - LLStringUtil::trim(last); + LLStringUtil::trim(last); } else { @@ -625,10 +760,29 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, pass.hex_digest(md5pass); authenticator["secret"] = md5pass; } + else + { + std::string key = first + "_" + last; + LLStringUtil::toLower(key); + credential = load_user_credentials(key); + if (credential.notNull()) + { + authenticator = credential->getAuthenticator(); + } + } } } credential = gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(), identifier, authenticator); - remember = sInstance->getChild<LLUICtrl>("remember_check")->getValue(); + if (!sInstance->mFirstLoginThisInstall) + { + remember_psswrd = sInstance->getChild<LLUICtrl>("remember_password")->getValue(); + remember_user = sInstance->getChild<LLUICtrl>("remember_name")->getValue(); + } + else + { + remember_psswrd = sInstance->getChild<LLUICtrl>("remember_check")->getValue(); + remember_user = remember_psswrd; // on panel_login_first "remember_check" is named as 'remember me' + } } @@ -641,11 +795,8 @@ BOOL LLPanelLogin::areCredentialFieldsDirty() } else { - std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString(); - LLStringUtil::trim(username); - std::string password = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString(); LLComboBox* combo = sInstance->getChild<LLComboBox>("username_combo"); - if(combo && combo->isDirty()) + if (combo && combo->getCurrentIndex() == -1 && !combo->getValue().asString().empty()) { return true; } @@ -816,9 +967,9 @@ void LLPanelLogin::loadLoginPage() // Channel and Version params["version"] = llformat("%s (%d)", - LLVersionInfo::getShortVersion().c_str(), - LLVersionInfo::getBuild()); - params["channel"] = LLVersionInfo::getChannel(); + LLVersionInfo::instance().getShortVersion().c_str(), + LLVersionInfo::instance().getBuild()); + params["channel"] = LLVersionInfo::instance().getChannel(); // Grid params["grid"] = LLGridManager::getInstance()->getGridId(); @@ -856,12 +1007,15 @@ void LLPanelLogin::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent ev // Protected methods //--------------------------------------------------------------------------- // static -void LLPanelLogin::onClickConnect(void *) +void LLPanelLogin::onClickConnect(bool commit_fields) { if (sInstance && sInstance->mCallback) { - // JC - Make sure the fields all get committed. - sInstance->setFocus(FALSE); + if (commit_fields) + { + // JC - Make sure the fields all get committed. + sInstance->setFocus(FALSE); + } LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo"); LLSD combo_val = combo->getSelectedValue(); @@ -898,8 +1052,8 @@ void LLPanelLogin::onClickConnect(void *) { sCredentialSet = FALSE; LLPointer<LLCredential> cred; - BOOL remember; - getFields(cred, remember); + bool remember_1, remember_2; + getFields(cred, remember_1, remember_2); std::string identifier_type; cred->identifierType(identifier_type); LLSD allowed_credential_types; @@ -953,6 +1107,69 @@ void LLPanelLogin::onClickSignUp(void*) } // static +void LLPanelLogin::onUserNameTextEnty(void*) +{ + sInstance->mPasswordModified = true; + sInstance->getChild<LLUICtrl>("password_edit")->setValue(std::string()); + sInstance->mPasswordLength = 0; + sInstance->addFavoritesToStartLocation(); //will call updateLoginButtons() +} + +// static +void LLPanelLogin::onUserListCommit(void*) +{ + if (sInstance) + { + LLComboBox* username_combo(sInstance->getChild<LLComboBox>("username_combo")); + static S32 ind = -1; + if (ind != username_combo->getCurrentIndex()) + { + std::string user_key = username_combo->getSelectedValue(); + LLPointer<LLCredential> cred = gSecAPIHandler->loadFromCredentialMap("login_list", LLGridManager::getInstance()->getGrid(), user_key); + setFields(cred); + sInstance->mPasswordModified = false; + } + else + { + std::string pass = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString(); + if (pass.empty()) + { + sInstance->giveFocus(); + } + else + { + onClickConnect(); + } + } + } +} + +// static +// At the moment only happens if !mFirstLoginThisInstall +void LLPanelLogin::onRememberUserCheck(void*) +{ + if (sInstance && !sInstance->mFirstLoginThisInstall) + { + LLCheckBoxCtrl* remember_name(sInstance->getChild<LLCheckBoxCtrl>("remember_name")); + LLCheckBoxCtrl* remember_psswrd(sInstance->getChild<LLCheckBoxCtrl>("remember_password")); + LLComboBox* user_combo(sInstance->getChild<LLComboBox>("username_combo")); + + bool remember = remember_name->getValue().asBoolean(); + if (user_combo->getCurrentIndex() != -1 && !remember) + { + remember = true; + remember_name->setValue(true); + LLNotificationsUtil::add("LoginCantRemoveUsername"); + } + if (!remember) + { + remember_psswrd->setValue(false); + } + remember_psswrd->setEnabled(remember); + } +} + +// static void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data) { LLPanelLogin *self = (LLPanelLogin *)user_data; @@ -976,12 +1193,37 @@ void LLPanelLogin::updateServer() try { // if they've selected another grid, we should load the credentials - // for that grid and set them to the UI. - if(!sInstance->areCredentialFieldsDirty()) + // for that grid and set them to the UI. But if there were any modifications to + // fields, modifications should carry over. + // Not sure if it should carry over password but it worked like this before login changes + // Example: you started typing in and found that your are under wrong grid, + // you switch yet don't lose anything + if (sInstance->areCredentialFieldsDirty()) { - LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); - bool remember = sInstance->getChild<LLUICtrl>("remember_check")->getValue(); - sInstance->setFields(credential, remember); + // save modified creds + LLComboBox* user_combo = sInstance->getChild<LLComboBox>("username_combo"); + LLLineEditor* pswd_edit = sInstance->getChild<LLLineEditor>("password_edit"); + std::string username = user_combo->getSimple(); + LLStringUtil::trim(username); + std::string password = pswd_edit->getValue().asString(); + + // populate dropbox and setFields + // Note: following call is related to initializeLoginInfo() + LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + sInstance->populateUserList(credential); + + // restore creds + user_combo->setTextEntry(username); + pswd_edit->setValue(password); + sInstance->mUsernameLength = username.length(); + sInstance->mPasswordLength = password.length(); + } + else + { + // populate dropbox and setFields + // Note: following call is related to initializeLoginInfo() + LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + sInstance->populateUserList(credential); } // update the login panel links @@ -1011,14 +1253,85 @@ void LLPanelLogin::updateLoginButtons() LLButton* login_btn = getChild<LLButton>("connect_btn"); login_btn->setEnabled(mUsernameLength != 0 && mPasswordLength != 0); + + if (!mFirstLoginThisInstall) + { + LLComboBox* user_combo = getChild<LLComboBox>("username_combo"); + LLCheckBoxCtrl* remember_name = getChild<LLCheckBoxCtrl>("remember_name"); + if (user_combo->getCurrentIndex() != -1) + { + remember_name->setValue(true); + LLCheckBoxCtrl* remember_pass = getChild<LLCheckBoxCtrl>("remember_password"); + remember_pass->setEnabled(TRUE); + } // Note: might be good idea to do "else remember_name->setValue(mRememberedState)" but it might behave 'weird' to user + } +} + +void LLPanelLogin::populateUserList(LLPointer<LLCredential> credential) +{ + LLComboBox* user_combo = getChild<LLComboBox>("username_combo"); + user_combo->removeall(); + user_combo->clear(); + user_combo->setValue(std::string()); + getChild<LLUICtrl>("password_edit")->setValue(std::string()); + mUsernameLength = 0; + mPasswordLength = 0; + + if (gSecAPIHandler->hasCredentialMap("login_list", LLGridManager::getInstance()->getGrid())) + { + LLSecAPIHandler::credential_map_t credencials; + gSecAPIHandler->loadCredentialMap("login_list", LLGridManager::getInstance()->getGrid(), credencials); + + LLSecAPIHandler::credential_map_t::iterator cr_iter = credencials.begin(); + LLSecAPIHandler::credential_map_t::iterator cr_end = credencials.end(); + while (cr_iter != cr_end) + { + if (cr_iter->second.notNull()) // basic safety in case of future changes + { + // cr_iter->first == user_id , to be able to be find it in case we select it + user_combo->add(LLPanelLogin::getUserName(cr_iter->second), cr_iter->first, ADD_BOTTOM, TRUE); + } + cr_iter++; + } + + if (credential.isNull() || !user_combo->setSelectedByValue(LLSD(credential->userID()), true)) + { + // selection failed, fields will be mepty + updateLoginButtons(); + } + else + { + setFields(credential); + } + } + else + { + if (credential.notNull()) + { + const LLSD &ident = credential->getIdentifier(); + if (ident.isMap() && ident.has("type")) + { + // this llsd might hold invalid credencial (failed login), so + // do not add to the list, just set field. + setFields(credential); + } + else + { + updateLoginButtons(); + } + } + else + { + updateLoginButtons(); + } + } } + void LLPanelLogin::onSelectServer() { // The user twiddled with the grid choice ui. // apply the selection to the grid setting. - LLPointer<LLCredential> credential; - LLComboBox* server_combo = getChild<LLComboBox>("server_combo"); LLSD server_combo_val = server_combo->getSelectedValue(); LL_INFOS("AppInit") << "grid "<<server_combo_val.asString()<< LL_ENDL; @@ -1040,21 +1353,24 @@ void LLPanelLogin::onSelectServer() switch (index) { case 0: // last location + LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST)); + break; case 1: // home location - // do nothing - these are grid-agnostic locations + LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME)); 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() != LLGridManager::getInstance()->getGrid() - ) + if (location.empty() + || (slurl.getType() == LLSLURL::LOCATION + && slurl.getGrid() != LLGridManager::getInstance()->getGrid()) + ) { // 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); + onLocationSLURL(); } } break; @@ -1077,3 +1393,34 @@ bool LLPanelLogin::getShowFavorites() { return gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"); } + +// static +std::string LLPanelLogin::getUserName(LLPointer<LLCredential> &cred) +{ + if (cred.isNull()) + { + return "unknown"; + } + const LLSD &ident = cred->getIdentifier(); + + if (!ident.isMap()) + { + return "unknown"; + } + else if ((std::string)ident["type"] == "agent") + { + std::string second_name = ident["last_name"]; + if (second_name == "resident" || second_name == "Resident") + { + return (std::string)ident["first_name"]; + } + return (std::string)ident["first_name"] + " " + (std::string)ident["last_name"]; + } + else if ((std::string)ident["type"] == "account") + { + return LLCacheName::cleanFullName((std::string)ident["account_name"]); + } + + return "unknown"; +} + diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index c633582d89..c5e6b41def 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -54,10 +54,11 @@ public: static void show(const LLRect &rect, void (*callback)(S32 option, void* user_data), void* callback_data); + static void reshapePanel(); - static void setFields(LLPointer<LLCredential> credential, BOOL remember); - - static void getFields(LLPointer<LLCredential>& credential, BOOL& remember); + static void populateFields(LLPointer<LLCredential> credential, bool remember_user, bool remember_psswrd); + static void resetFields(); + static void getFields(LLPointer<LLCredential>& credential, bool& remember_user, bool& remember_psswrd); static BOOL isCredentialSet() { return sCredentialSet; } @@ -72,8 +73,6 @@ public: void setSiteIsAlive( bool alive ); - void showLoginWidgets(); - static void loadLoginPage(); static void giveFocus(); static void setAlwaysRefresh(bool refresh); @@ -88,6 +87,9 @@ public: // called from prefs when initializing panel static bool getShowFavorites(); + // extract name from cred in a format apropriate for username field + static std::string getUserName(LLPointer<LLCredential> &cred); + private: friend class LLPanelLoginListener; void addFavoritesToStartLocation(); @@ -95,11 +97,16 @@ private: void onSelectServer(); void onLocationSLURL(); - static void onClickConnect(void*); + static void setFields(LLPointer<LLCredential> credential); + + static void onClickConnect(bool commit_fields = true); static void onClickNewAccount(void*); static void onClickVersion(void*); static void onClickForgotPassword(void*); static void onClickSignUp(void*); + static void onUserNameTextEnty(void*); + static void onUserListCommit(void*); + static void onRememberUserCheck(void*); static void onPassKey(LLLineEditor* caller, void* user_data); static void updateServerCombo(); @@ -107,6 +114,7 @@ private: boost::scoped_ptr<LLPanelLoginListener> mListener; void updateLoginButtons(); + void populateUserList(LLPointer<LLCredential> credential); void (*mCallback)(S32 option, void *userdata); void* mCallbackData; diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index f63e604927..e9c9c451a2 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -28,12 +28,12 @@ #include "llpanelmaininventory.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llagentcamera.h" #include "llavataractions.h" #include "llcheckboxctrl.h" #include "llcombobox.h" #include "lldndbutton.h" -#include "lleconomy.h" #include "llfilepicker.h" #include "llinventorybridge.h" #include "llinventoryfunctions.h" @@ -58,6 +58,7 @@ #include "llsidepanelinventory.h" #include "llfolderview.h" #include "llradiogroup.h" +#include "llenvironment.h" const std::string FILTERS_FILENAME("filters.xml"); @@ -114,6 +115,7 @@ LLPanelMainInventory::LLPanelMainInventory(const LLPanel::Params& p) mSavedFolderState(NULL), mFilterText(""), mMenuGearDefault(NULL), + mMenuVisibility(NULL), mMenuAddHandle(), mNeedUploadCost(true) { @@ -128,6 +130,9 @@ LLPanelMainInventory::LLPanelMainInventory(const LLPanel::Params& p) mCommitCallbackRegistrar.add("Inventory.SetSortBy", boost::bind(&LLPanelMainInventory::setSortBy, this, _2)); mCommitCallbackRegistrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, this)); + mEnableCallbackRegistrar.add("Inventory.EnvironmentEnabled", [](LLUICtrl *, const LLSD &) { return LLPanelMainInventory::hasSettingsInventory(); }); + + mSavedFolderState = new LLSaveFolderState(); mSavedFolderState->setApply(FALSE); } @@ -161,6 +166,7 @@ BOOL LLPanelMainInventory::postBuild() recent_items_panel->setSinceLogoff(TRUE); recent_items_panel->setSortOrder(LLInventoryFilter::SO_DATE); recent_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); + recent_items_panel->setFilterLinks(LLInventoryFilter::FILTERLINK_EXCLUDE_LINKS); LLInventoryFilter& recent_filter = recent_items_panel->getFilter(); recent_filter.setFilterObjectTypes(recent_filter.getFilterObjectTypes() & ~(0x1 << LLInventoryType::IT_CATEGORY)); recent_filter.setEmptyLookupMessage("InventoryNoMatchingRecentItems"); @@ -214,6 +220,17 @@ BOOL LLPanelMainInventory::postBuild() recent_items_panel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::RECENTITEMS_SORT_ORDER)); } } + if(mActivePanel) + { + if(savedFilterState.has(mActivePanel->getFilter().getName())) + { + LLSD items = savedFilterState.get(mActivePanel->getFilter().getName()); + LLInventoryFilter::Params p; + LLParamSDParser parser; + parser.readSD(items, p); + mActivePanel->getFilter().setSearchVisibilityTypes(p); + } + } } @@ -224,19 +241,20 @@ BOOL LLPanelMainInventory::postBuild() } mGearMenuButton = getChild<LLMenuButton>("options_gear_btn"); + mVisibilityMenuButton = getChild<LLMenuButton>("options_visibility_btn"); initListCommandsHandlers(); - // *TODO:Get the cost info from the server - const std::string upload_cost("10"); + const std::string texture_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()); + const std::string sound_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getSoundUploadCost()); + const std::string animation_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getAnimationUploadCost()); LLMenuGL* menu = (LLMenuGL*)mMenuAddHandle.get(); if (menu) { - menu->getChild<LLMenuItemGL>("Upload Image")->setLabelArg("[COST]", upload_cost); - menu->getChild<LLMenuItemGL>("Upload Sound")->setLabelArg("[COST]", upload_cost); - menu->getChild<LLMenuItemGL>("Upload Animation")->setLabelArg("[COST]", upload_cost); - menu->getChild<LLMenuItemGL>("Bulk Upload")->setLabelArg("[COST]", upload_cost); + menu->getChild<LLMenuItemGL>("Upload Image")->setLabelArg("[COST]", texture_upload_cost_str); + menu->getChild<LLMenuItemGL>("Upload Sound")->setLabelArg("[COST]", sound_upload_cost_str); + menu->getChild<LLMenuItemGL>("Upload Animation")->setLabelArg("[COST]", animation_upload_cost_str); } // Trigger callback for focus received so we can deselect items in inbox/outbox @@ -249,6 +267,9 @@ BOOL LLPanelMainInventory::postBuild() LLPanelMainInventory::~LLPanelMainInventory( void ) { // Save the filters state. + // Some params types cannot be saved this way + // for example, LLParamSDParser doesn't know about U64, + // so some FilterOps params should be revised. LLSD filterRoot; LLInventoryPanel* all_items_panel = getChild<LLInventoryPanel>("All Items"); if (all_items_panel) @@ -904,6 +925,7 @@ void LLFloaterInventoryFinder::updateElementsFromFilter() getChild<LLUICtrl>("check_sound")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_SOUND)); getChild<LLUICtrl>("check_texture")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_TEXTURE)); getChild<LLUICtrl>("check_snapshot")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_SNAPSHOT)); + getChild<LLUICtrl>("check_settings")->setValue((S32)(filter_types & 0x1 << LLInventoryType::IT_SETTINGS)); getChild<LLUICtrl>("check_show_empty")->setValue(show_folders == LLInventoryFilter::SHOW_ALL_FOLDERS); getChild<LLUICtrl>("check_created_by_me")->setValue(show_created_by_me); @@ -990,6 +1012,12 @@ void LLFloaterInventoryFinder::draw() filtered_by_all_types = FALSE; } + if (!getChild<LLUICtrl>("check_settings")->getValue()) + { + filter &= ~(0x1 << LLInventoryType::IT_SETTINGS); + filtered_by_all_types = FALSE; + } + if (!filtered_by_all_types || (mPanelMainInventory->getPanel()->getFilter().getFilterTypes() & LLInventoryFilter::FILTERTYPE_DATE)) { // don't include folders in filter, unless I've selected everything or filtering by date @@ -1107,6 +1135,7 @@ void LLFloaterInventoryFinder::selectAllTypes(void* user_data) self->getChild<LLUICtrl>("check_sound")->setValue(TRUE); self->getChild<LLUICtrl>("check_texture")->setValue(TRUE); self->getChild<LLUICtrl>("check_snapshot")->setValue(TRUE); + self->getChild<LLUICtrl>("check_settings")->setValue(TRUE); } //static @@ -1126,6 +1155,7 @@ void LLFloaterInventoryFinder::selectNoTypes(void* user_data) self->getChild<LLUICtrl>("check_sound")->setValue(FALSE); self->getChild<LLUICtrl>("check_texture")->setValue(FALSE); self->getChild<LLUICtrl>("check_snapshot")->setValue(FALSE); + self->getChild<LLUICtrl>("check_settings")->setValue(FALSE); } ////////////////////////////////////////////////////////////////////////////////// @@ -1151,6 +1181,10 @@ void LLPanelMainInventory::initListCommandsHandlers() LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_inventory_add.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); mMenuAddHandle = menu->getHandle(); + mMenuVisibility = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_inventory_search_visibility.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mVisibilityMenuButton->setMenu(mMenuVisibility); + mVisibilityMenuButton->setMenuPosition(LLMenuButton::MP_BOTTOM_LEFT); + // Update the trash button when selected item(s) get worn or taken off. LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&LLPanelMainInventory::updateListCommands, this)); } @@ -1340,6 +1374,21 @@ void LLPanelMainInventory::onCustomAction(const LLSD& userdata) } LLFloaterReg::showInstance("linkreplace", params); } + + if (command_name == "toggle_search_trash") + { + mActivePanel->getFilter().toggleSearchVisibilityTrash(); + } + + if (command_name == "toggle_search_library") + { + mActivePanel->getFilter().toggleSearchVisibilityLibrary(); + } + + if (command_name == "include_links") + { + mActivePanel->getFilter().toggleSearchVisibilityLinks(); + } } void LLPanelMainInventory::onVisibilityChange( BOOL new_visibility ) @@ -1485,6 +1534,21 @@ BOOL LLPanelMainInventory::isActionChecked(const LLSD& userdata) return sort_order_mask & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP; } + if (command_name == "toggle_search_trash") + { + return (mActivePanel->getFilter().getSearchVisibilityTypes() & LLInventoryFilter::VISIBILITY_TRASH) != 0; + } + + if (command_name == "toggle_search_library") + { + return (mActivePanel->getFilter().getSearchVisibilityTypes() & LLInventoryFilter::VISIBILITY_LIBRARY) != 0; + } + + if (command_name == "include_links") + { + return (mActivePanel->getFilter().getSearchVisibilityTypes() & LLInventoryFilter::VISIBILITY_LINKS) != 0; + } + return FALSE; } @@ -1504,38 +1568,23 @@ bool LLPanelMainInventory::handleDragAndDropToTrash(BOOL drop, EDragAndDropType void LLPanelMainInventory::setUploadCostIfNeeded() { - // *NOTE dzaporozhan - // Upload cost is set in process_economy_data() (llviewermessage.cpp). But since we - // have two instances of Inventory panel at the moment(and two instances of context menu), - // call to gMenuHolder->childSetLabelArg() sets upload cost only for one of the instances. - LLMenuGL* menu = (LLMenuGL*)mMenuAddHandle.get(); if(mNeedUploadCost && menu) { - LLMenuItemBranchGL* upload_menu = menu->findChild<LLMenuItemBranchGL>("upload"); - if(upload_menu) - { - S32 upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload(); - std::string cost_str; - - // getPriceUpload() returns -1 if no data available yet. - if(upload_cost >= 0) - { - mNeedUploadCost = false; - cost_str = llformat("%d", upload_cost); - } - else - { - cost_str = llformat("%d", gSavedSettings.getU32("DefaultUploadCost")); - } + const std::string texture_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()); + const std::string sound_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getSoundUploadCost()); + const std::string animation_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getAnimationUploadCost()); - upload_menu->getChild<LLView>("Upload Image")->setLabelArg("[COST]", cost_str); - upload_menu->getChild<LLView>("Upload Sound")->setLabelArg("[COST]", cost_str); - upload_menu->getChild<LLView>("Upload Animation")->setLabelArg("[COST]", cost_str); - upload_menu->getChild<LLView>("Bulk Upload")->setLabelArg("[COST]", cost_str); - } + menu->getChild<LLView>("Upload Image")->setLabelArg("[COST]", texture_upload_cost_str); + menu->getChild<LLView>("Upload Sound")->setLabelArg("[COST]", sound_upload_cost_str); + menu->getChild<LLView>("Upload Animation")->setLabelArg("[COST]", animation_upload_cost_str); } } +bool LLPanelMainInventory::hasSettingsInventory() +{ + return LLEnvironment::instance().isInventoryEnabled(); +} + // List Commands // //////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index 732a3b04e3..dfb8db9d12 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -93,6 +93,8 @@ public: void toggleFindOptions(); + void resetFilters(); + protected: // // Misc functions @@ -117,7 +119,6 @@ protected: void doToSelected(const LLSD& userdata); void closeAllFolders(); void doCreate(const LLSD& userdata); - void resetFilters(); void setSortBy(const LLSD& userdata); void saveTexture(const LLSD& userdata); bool isSaveTextureEnabled(const LLSD& userdata); @@ -161,6 +162,7 @@ protected: BOOL isActionChecked(const LLSD& userdata); void onCustomAction(const LLSD& command_name); bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept); + static bool hasSettingsInventory(); /** * Set upload cost in "Upload" sub menu. */ @@ -168,7 +170,9 @@ protected: private: LLDragAndDropButton* mTrashButton; LLToggleableMenu* mMenuGearDefault; + LLToggleableMenu* mMenuVisibility; LLMenuButton* mGearMenuButton; + LLMenuButton* mVisibilityMenuButton; LLHandle<LLView> mMenuAddHandle; bool mNeedUploadCost; diff --git a/indra/newview/llpanelmarketplaceinboxinventory.cpp b/indra/newview/llpanelmarketplaceinboxinventory.cpp index cea7054d6a..7a6631448b 100644 --- a/indra/newview/llpanelmarketplaceinboxinventory.cpp +++ b/indra/newview/llpanelmarketplaceinboxinventory.cpp @@ -36,12 +36,15 @@ #include "llpanellandmarks.h" #include "llplacesinventorybridge.h" #include "llviewerfoldertype.h" +#include "llsdserialize.h" #define DEBUGGING_FRESHNESS 0 const LLColor4U DEFAULT_WHITE(255, 255, 255); +const std::string NEW_INBOX_FILENAME("inbox_new_items.xml"); + // // statics // @@ -57,7 +60,9 @@ static LLDefaultChildRegistry::Register<LLInboxFolderViewItem> r3("inbox_folder_ LLInboxInventoryPanel::LLInboxInventoryPanel(const LLInboxInventoryPanel::Params& p) : LLInventoryPanel(p) -{} +{ + LLInboxNewItemsStorage::getInstance()->load(); +} LLInboxInventoryPanel::~LLInboxInventoryPanel() {} @@ -127,7 +132,7 @@ void LLInboxFolderViewFolder::addItem(LLFolderViewItem* item) } // Compute freshness if our parent is the root folder for the inbox - if (mParentFolder == mRoot) + if ((mParentFolder == mRoot) && !mFresh) { computeFreshness(); } @@ -145,6 +150,12 @@ void LLInboxFolderViewFolder::draw() setBadgeVisibility(mFresh); LLFolderViewFolder::draw(); + + if (mFresh) + { + reshapeBadge(getRect()); + } + } BOOL LLInboxFolderViewFolder::handleMouseDown( S32 x, S32 y, MASK mask ) @@ -167,11 +178,12 @@ void LLInboxFolderViewFolder::selectItem() void LLInboxFolderViewFolder::computeFreshness() { + LLFolderViewModelItemInventory* view_model = static_cast<LLFolderViewModelItemInventory*>(getViewModelItem()); const U32 last_expansion_utc = gSavedPerAccountSettings.getU32("LastInventoryInboxActivity"); if (last_expansion_utc > 0) { - mFresh = (static_cast<LLFolderViewModelItemInventory*>(getViewModelItem())->getCreationDate() > last_expansion_utc); + mFresh = (view_model->getCreationDate() > last_expansion_utc) || LLInboxNewItemsStorage::getInstance()->isItemFresh(view_model->getUUID()); #if DEBUGGING_FRESHNESS if (mFresh) @@ -184,6 +196,11 @@ void LLInboxFolderViewFolder::computeFreshness() { mFresh = true; } + + if (mFresh) + { + LLInboxNewItemsStorage::getInstance()->addFreshItem(view_model->getUUID()); + } } void LLInboxFolderViewFolder::deFreshify() @@ -191,6 +208,7 @@ void LLInboxFolderViewFolder::deFreshify() mFresh = false; gSavedPerAccountSettings.setU32("LastInventoryInboxActivity", time_corrected()); + LLInboxNewItemsStorage::getInstance()->removeItem(static_cast<LLFolderViewModelItemInventory*>(getViewModelItem())->getUUID()); } // @@ -271,5 +289,55 @@ void LLInboxFolderViewItem::deFreshify() gSavedPerAccountSettings.setU32("LastInventoryInboxActivity", time_corrected()); } +LLInboxNewItemsStorage::LLInboxNewItemsStorage() +{ +} + +// static +void LLInboxNewItemsStorage::destroyClass() +{ + LLInboxNewItemsStorage::getInstance()->saveNewItemsIds(); +} + +void LLInboxNewItemsStorage::saveNewItemsIds() +{ + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, NEW_INBOX_FILENAME); + if (!filename.empty()) + { + LLSD uuids_data; + for (std::set<LLUUID>::const_iterator it = mNewItemsIDs.begin(); it != mNewItemsIDs.end(); it++) + { + uuids_data.append((*it)); + } + llofstream file; + file.open(filename.c_str()); + if ( file.is_open() ) + { + LLSDSerialize::toPrettyXML(uuids_data, file); + file.close(); + } + } +} + +void LLInboxNewItemsStorage::load() +{ + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, NEW_INBOX_FILENAME); + if (!filename.empty()) + { + llifstream in_file; + in_file.open(filename.c_str()); + + LLSD uuids_data; + if (in_file.is_open()) + { + LLSDSerialize::fromXML(uuids_data, in_file); + in_file.close(); + for (LLSD::array_iterator i = uuids_data.beginArray(); i != uuids_data.endArray(); ++i) + { + mNewItemsIDs.insert((*i).asUUID()); + } + } + } +} // eof diff --git a/indra/newview/llpanelmarketplaceinboxinventory.h b/indra/newview/llpanelmarketplaceinboxinventory.h index 0b27818c95..3e508e801b 100644 --- a/indra/newview/llpanelmarketplaceinboxinventory.h +++ b/indra/newview/llpanelmarketplaceinboxinventory.h @@ -113,4 +113,23 @@ protected: bool mFresh; }; +class LLInboxNewItemsStorage : public LLSingleton<LLInboxNewItemsStorage> + , public LLDestroyClass<LLInboxNewItemsStorage> +{ + LLSINGLETON(LLInboxNewItemsStorage); + LOG_CLASS(LLInboxNewItemsStorage); +public: + static void destroyClass(); + void saveNewItemsIds(); + + void load(); + + void addFreshItem(const LLUUID& id) { mNewItemsIDs.insert(id); } + void removeItem(const LLUUID& id) { mNewItemsIDs.erase(id); } + bool isItemFresh(const LLUUID& id) { return (mNewItemsIDs.find(id) != mNewItemsIDs.end()); } + +private: + std::set<LLUUID> mNewItemsIDs; +}; + #endif //LL_INBOXINVENTORYPANEL_H diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp index 3522189842..9730f0f16d 100644 --- a/indra/newview/llpanelmediasettingsgeneral.cpp +++ b/indra/newview/llpanelmediasettingsgeneral.cpp @@ -457,7 +457,7 @@ bool LLPanelMediaSettingsGeneral::navigateHomeSelectedFace(bool only_if_current_ if (!only_if_current_is_empty || (media_data->getCurrentURL().empty() && media_data->getAutoPlay())) { viewer_media_t media_impl = - LLViewerMedia::getMediaImplFromTextureID(object->getTE(face)->getMediaData()->getMediaID()); + LLViewerMedia::getInstance()->getMediaImplFromTextureID(object->getTE(face)->getMediaData()->getMediaID()); if(media_impl) { media_impl->navigateHome(); diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp index f3a2ed9408..02911313ed 100644 --- a/indra/newview/llpanelnearbymedia.cpp +++ b/indra/newview/llpanelnearbymedia.cpp @@ -43,6 +43,7 @@ #include "llbutton.h" #include "lltextbox.h" #include "llviewermedia.h" +#include "llviewerparcelaskplay.h" #include "llviewerparcelmedia.h" #include "llviewerregion.h" #include "llviewermediafocus.h" @@ -65,9 +66,6 @@ extern LLControlGroup gSavedSettings; static const LLUUID PARCEL_MEDIA_LIST_ITEM_UUID = LLUUID("CAB5920F-E484-4233-8621-384CF373A321"); static const LLUUID PARCEL_AUDIO_LIST_ITEM_UUID = LLUUID("DF4B020D-8A24-4B95-AB5D-CA970D694822"); -const F32 AUTO_CLOSE_FADE_TIME_START= 2.0f; -const F32 AUTO_CLOSE_FADE_TIME_END = 3.0f; - // // LLPanelNearByMedia // @@ -81,12 +79,11 @@ LLPanelNearByMedia::LLPanelNearByMedia() mParcelMediaItem(NULL), mParcelAudioItem(NULL) { - mHoverTimer.stop(); - - mParcelAudioAutoStart = gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && - gSavedSettings.getBOOL("MediaTentativeAutoPlay"); + // This is just an initial value, mParcelAudioAutoStart does not affect ParcelMediaAutoPlayEnable + mParcelAudioAutoStart = gSavedSettings.getS32("ParcelMediaAutoPlayEnable") != 0 + && gSavedSettings.getBOOL("MediaTentativeAutoPlay"); - gSavedSettings.getControl(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING)->getSignal()->connect(boost::bind(&LLPanelNearByMedia::handleMediaAutoPlayChanged, this, _2)); + gSavedSettings.getControl("ParcelMediaAutoPlayEnable")->getSignal()->connect(boost::bind(&LLPanelNearByMedia::handleMediaAutoPlayChanged, this, _2)); mCommitCallbackRegistrar.add("MediaListCtrl.EnableAll", boost::bind(&LLPanelNearByMedia::onClickEnableAll, this)); mCommitCallbackRegistrar.add("MediaListCtrl.DisableAll", boost::bind(&LLPanelNearByMedia::onClickDisableAll, this)); @@ -109,7 +106,7 @@ LLPanelNearByMedia::~LLPanelNearByMedia() BOOL LLPanelNearByMedia::postBuild() { - LLPanel::postBuild(); + LLPanelPulldown::postBuild(); const S32 RESIZE_BAR_THICKNESS = 6; LLResizeBar::Params p; @@ -177,50 +174,24 @@ BOOL LLPanelNearByMedia::postBuild() void LLPanelNearByMedia::handleMediaAutoPlayChanged(const LLSD& newvalue) { - // update mParcelAudioAutoStart if AUTO_PLAY_MEDIA_SETTING changes - mParcelAudioAutoStart = gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && - gSavedSettings.getBOOL("MediaTentativeAutoPlay"); -} - -/*virtual*/ -void LLPanelNearByMedia::onMouseEnter(S32 x, S32 y, MASK mask) -{ - mHoverTimer.stop(); - LLPanel::onMouseEnter(x,y,mask); -} - - -/*virtual*/ -void LLPanelNearByMedia::onMouseLeave(S32 x, S32 y, MASK mask) -{ - mHoverTimer.start(); - LLPanel::onMouseLeave(x,y,mask); -} - -/*virtual*/ -void LLPanelNearByMedia::onTopLost() -{ - setVisible(FALSE); -} - - -/*virtual*/ -void LLPanelNearByMedia::onVisibilityChange ( BOOL new_visibility ) -{ - if (new_visibility) - { - mHoverTimer.start(); // timer will be stopped when mouse hovers over panel - } - else - { - mHoverTimer.stop(); - } + // update mParcelAudioAutoStartMode if "ParcelMediaAutoPlayEnable" changes + S32 value = gSavedSettings.getS32("ParcelMediaAutoPlayEnable"); + mParcelAudioAutoStart = value != 0 + && gSavedSettings.getBOOL("MediaTentativeAutoPlay"); + + LLViewerParcelAskPlay *inst = LLViewerParcelAskPlay::getInstance(); + if (value == 2 && !inst->hasData()) + { + // Init if nessesary + inst->loadSettings(); + } + inst->cancelNotification(); } /*virtual*/ void LLPanelNearByMedia::reshape(S32 width, S32 height, BOOL called_from_parent) { - LLPanel::reshape(width, height, called_from_parent); + LLPanelPulldown::reshape(width, height, called_from_parent); LLButton* more_btn = findChild<LLButton>("more_btn"); if (more_btn && more_btn->getValue().asBoolean()) @@ -244,24 +215,14 @@ void LLPanelNearByMedia::draw() refreshList(); updateControls(); - - F32 alpha = mHoverTimer.getStarted() - ? clamp_rescale(mHoverTimer.getElapsedTimeF32(), AUTO_CLOSE_FADE_TIME_START, AUTO_CLOSE_FADE_TIME_END, 1.f, 0.f) - : 1.0f; - LLViewDrawContext context(alpha); - LLPanel::draw(); - - if (alpha == 0.f) - { - setVisible(false); - } + LLPanelPulldown::draw(); } /*virtual*/ BOOL LLPanelNearByMedia::handleHover(S32 x, S32 y, MASK mask) { - LLPanel::handleHover(x, y, mask); + LLPanelPulldown::handleHover(x, y, mask); // If we are hovering over this panel, make sure to clear any hovered media // ID. Note that the more general solution would be to clear this ID when @@ -543,9 +504,10 @@ void LLPanelNearByMedia::refreshParcelItems() // Only show "special parcel items" if "All" or "Within" filter // (and if media is "enabled") bool should_include = (choice == MEDIA_CLASS_ALL || choice == MEDIA_CLASS_WITHIN_PARCEL); - + LLViewerMedia* media_inst = LLViewerMedia::getInstance(); + // First Parcel Media: add or remove it as necessary - if (gSavedSettings.getBOOL("AudioStreamingMedia") &&should_include && LLViewerMedia::hasParcelMedia()) + if (gSavedSettings.getBOOL("AudioStreamingMedia") && should_include && media_inst->hasParcelMedia()) { // Yes, there is parcel media. if (NULL == mParcelMediaItem) @@ -566,7 +528,7 @@ void LLPanelNearByMedia::refreshParcelItems() if (NULL != mParcelMediaItem) { std::string name, url, tooltip; - getNameAndUrlHelper(LLViewerParcelMedia::getParcelMedia(), name, url, ""); + getNameAndUrlHelper(LLViewerParcelMedia::getInstance()->getParcelMedia(), name, url, ""); if (name.empty() || name == url) { tooltip = url; @@ -575,20 +537,20 @@ void LLPanelNearByMedia::refreshParcelItems() { tooltip = name + " : " + url; } - LLViewerMediaImpl *impl = LLViewerParcelMedia::getParcelMedia(); + LLViewerMediaImpl *impl = LLViewerParcelMedia::getInstance()->getParcelMedia(); updateListItem(mParcelMediaItem, mParcelMediaName, tooltip, -2, // Proximity closer than anything else, before Parcel Audio impl == NULL || impl->isMediaDisabled(), - impl != NULL && !LLViewerParcelMedia::getURL().empty(), + impl != NULL && !LLViewerParcelMedia::getInstance()->getURL().empty(), impl != NULL && impl->isMediaTimeBased() && impl->isMediaPlaying(), MEDIA_CLASS_ALL, "parcel media"); } // Next Parcel Audio: add or remove it as necessary (don't show if disabled in prefs) - if (should_include && LLViewerMedia::hasParcelAudio() && gSavedSettings.getBOOL("AudioStreamingMusic")) + if (should_include && media_inst->hasParcelAudio() && gSavedSettings.getBOOL("AudioStreamingMusic")) { // Yes, there is parcel audio. if (NULL == mParcelAudioItem) @@ -608,10 +570,10 @@ void LLPanelNearByMedia::refreshParcelItems() // ... then update it if (NULL != mParcelAudioItem) { - bool is_playing = LLViewerMedia::isParcelAudioPlaying(); + bool is_playing = media_inst->isParcelAudioPlaying(); std::string url; - url = LLViewerMedia::getParcelAudioURL(); + url = media_inst->getParcelAudioURL(); updateListItem(mParcelAudioItem, mParcelAudioName, @@ -653,7 +615,8 @@ void LLPanelNearByMedia::refreshList() refreshParcelItems(); // Get the canonical list from LLViewerMedia - LLViewerMedia::impl_list impls = LLViewerMedia::getPriorityList(); + LLViewerMedia* media_inst = LLViewerMedia::getInstance(); + LLViewerMedia::impl_list impls = media_inst->getPriorityList(); LLViewerMedia::impl_list::iterator priority_iter; U32 enabled_count = 0; @@ -706,17 +669,17 @@ void LLPanelNearByMedia::refreshList() } mDisableAllCtrl->setEnabled((gSavedSettings.getBOOL("AudioStreamingMusic") || gSavedSettings.getBOOL("AudioStreamingMedia")) && - (LLViewerMedia::isAnyMediaShowing() || - LLViewerMedia::isParcelMediaPlaying() || - LLViewerMedia::isParcelAudioPlaying())); + (media_inst->isAnyMediaShowing() || + media_inst->isParcelMediaPlaying() || + media_inst->isParcelAudioPlaying())); mEnableAllCtrl->setEnabled( (gSavedSettings.getBOOL("AudioStreamingMusic") || gSavedSettings.getBOOL("AudioStreamingMedia")) && (disabled_count > 0 || // parcel media (if we have it, and it isn't playing, enable "start") - (LLViewerMedia::hasParcelMedia() && ! LLViewerMedia::isParcelMediaPlaying()) || + (media_inst->hasParcelMedia() && ! media_inst->isParcelMediaPlaying()) || // parcel audio (if we have it, and it isn't playing, enable "start") - (LLViewerMedia::hasParcelAudio() && ! LLViewerMedia::isParcelAudioPlaying()))); + (media_inst->hasParcelAudio() && ! media_inst->isParcelAudioPlaying()))); // Iterate over the rows in the control, updating ones whose impl exists, and deleting ones whose impl has gone away. std::vector<LLScrollListItem*> items = mMediaList->getAllData(); @@ -731,7 +694,7 @@ void LLPanelNearByMedia::refreshList() if (row_id != PARCEL_MEDIA_LIST_ITEM_UUID && row_id != PARCEL_AUDIO_LIST_ITEM_UUID) { - LLViewerMediaImpl* impl = LLViewerMedia::getMediaImplFromTextureID(row_id); + LLViewerMediaImpl* impl = media_inst->getMediaImplFromTextureID(row_id); if(impl) { updateListItem(item, impl); @@ -776,26 +739,26 @@ void LLPanelNearByMedia::updateColumns() void LLPanelNearByMedia::onClickEnableAll() { - LLViewerMedia::setAllMediaEnabled(true); + LLViewerMedia::getInstance()->setAllMediaEnabled(true); } void LLPanelNearByMedia::onClickDisableAll() { - LLViewerMedia::setAllMediaEnabled(false); + LLViewerMedia::getInstance()->setAllMediaEnabled(false); } void LLPanelNearByMedia::onClickEnableParcelMedia() { - if ( ! LLViewerMedia::isParcelMediaPlaying() ) + if ( ! LLViewerMedia::getInstance()->isParcelMediaPlaying() ) { - LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel()); + LLViewerParcelMedia::getInstance()->play(LLViewerParcelMgr::getInstance()->getAgentParcel()); } } void LLPanelNearByMedia::onClickDisableParcelMedia() { // This actually unloads the impl, as opposed to "stop"ping the media - LLViewerParcelMedia::stop(); + LLViewerParcelMedia::getInstance()->stop(); } void LLPanelNearByMedia::onCheckItem(LLUICtrl* ctrl, const LLUUID &row_id) @@ -832,7 +795,7 @@ bool LLPanelNearByMedia::setDisabled(const LLUUID &row_id, bool disabled) return true; } else { - LLViewerMediaImpl* impl = LLViewerMedia::getMediaImplFromTextureID(row_id); + LLViewerMediaImpl* impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(row_id); if(impl) { impl->setDisabled(disabled, true); @@ -853,22 +816,22 @@ void LLPanelNearByMedia::onZoomMedia(void* user_data) void LLPanelNearByMedia::onClickParcelMediaPlay() { - LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel()); + LLViewerParcelMedia::getInstance()->play(LLViewerParcelMgr::getInstance()->getAgentParcel()); } void LLPanelNearByMedia::onClickParcelMediaStop() { - if (LLViewerParcelMedia::getParcelMedia()) + if (LLViewerParcelMedia::getInstance()->getParcelMedia()) { // This stops the media playing, as opposed to unloading it like // LLViewerParcelMedia::stop() does - LLViewerParcelMedia::getParcelMedia()->stop(); + LLViewerParcelMedia::getInstance()->getParcelMedia()->stop(); } } void LLPanelNearByMedia::onClickParcelMediaPause() { - LLViewerParcelMedia::pause(); + LLViewerParcelMedia::getInstance()->pause(); } void LLPanelNearByMedia::onClickParcelAudioPlay() @@ -889,7 +852,7 @@ void LLPanelNearByMedia::onClickParcelAudioPlay() } else { - LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLViewerMedia::getParcelAudioURL()); + LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLViewerMedia::getInstance()->getParcelAudioURL()); } } @@ -981,16 +944,17 @@ void LLPanelNearByMedia::onMoreLess() void LLPanelNearByMedia::updateControls() { LLUUID selected_media_id = mMediaList->getValue().asUUID(); + LLViewerMedia* media_inst = LLViewerMedia::getInstance(); if (selected_media_id == PARCEL_AUDIO_LIST_ITEM_UUID) { - if (!LLViewerMedia::hasParcelAudio() || !gSavedSettings.getBOOL("AudioStreamingMusic")) + if (!media_inst->getInstance()->hasParcelAudio() || !gSavedSettings.getBOOL("AudioStreamingMusic")) { // disable controls if audio streaming music is disabled from preference showDisabledControls(); } else { - showTimeBasedControls(LLViewerMedia::isParcelAudioPlaying(), + showTimeBasedControls(media_inst->isParcelAudioPlaying(), false, // include_zoom false, // is_zoomed gSavedSettings.getBOOL("MuteMusic"), @@ -999,13 +963,13 @@ void LLPanelNearByMedia::updateControls() } else if (selected_media_id == PARCEL_MEDIA_LIST_ITEM_UUID) { - if (!LLViewerMedia::hasParcelMedia() || !gSavedSettings.getBOOL("AudioStreamingMedia")) + if (!media_inst->hasParcelMedia() || !gSavedSettings.getBOOL("AudioStreamingMedia")) { // disable controls if audio streaming media is disabled from preference showDisabledControls(); } else { - LLViewerMediaImpl* impl = LLViewerParcelMedia::getParcelMedia(); + LLViewerMediaImpl* impl = LLViewerParcelMedia::getInstance()->getParcelMedia(); if (NULL == impl) { // Just means it hasn't started yet @@ -1021,7 +985,7 @@ void LLPanelNearByMedia::updateControls() } else { // non-time-based parcel media - showBasicControls(LLViewerMedia::isParcelMediaPlaying(), + showBasicControls(media_inst->isParcelMediaPlaying(), false, false, impl->getVolume() == 0.0, @@ -1030,7 +994,7 @@ void LLPanelNearByMedia::updateControls() } } else { - LLViewerMediaImpl* impl = LLViewerMedia::getMediaImplFromTextureID(selected_media_id); + LLViewerMediaImpl* impl = media_inst->getMediaImplFromTextureID(selected_media_id); if (NULL == impl || !gSavedSettings.getBOOL("AudioStreamingMedia")) { @@ -1116,7 +1080,7 @@ void LLPanelNearByMedia::onClickSelectedMediaPlay() if (selected_media_id != PARCEL_AUDIO_LIST_ITEM_UUID) { LLViewerMediaImpl *impl = (selected_media_id == PARCEL_MEDIA_LIST_ITEM_UUID) ? - ((LLViewerMediaImpl*)LLViewerParcelMedia::getParcelMedia()) : LLViewerMedia::getMediaImplFromTextureID(selected_media_id); + ((LLViewerMediaImpl*)LLViewerParcelMedia::getInstance()->getParcelMedia()) : LLViewerMedia::getInstance()->getMediaImplFromTextureID(selected_media_id); if (NULL != impl) { if (impl->isMediaTimeBased() && impl->isMediaPaused()) @@ -1127,7 +1091,7 @@ void LLPanelNearByMedia::onClickSelectedMediaPlay() } else if (impl->isParcelMedia()) { - LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel()); + LLViewerParcelMedia::getInstance()->play(LLViewerParcelMgr::getInstance()->getAgentParcel()); } } } @@ -1145,7 +1109,7 @@ void LLPanelNearByMedia::onClickSelectedMediaPause() onClickParcelMediaPause(); } else { - LLViewerMediaImpl* impl = LLViewerMedia::getMediaImplFromTextureID(selected_media_id); + LLViewerMediaImpl* impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(selected_media_id); if (NULL != impl && impl->isMediaTimeBased() && impl->isMediaPlaying()) { impl->pause(); @@ -1162,7 +1126,7 @@ void LLPanelNearByMedia::onClickSelectedMediaMute() } else { LLViewerMediaImpl* impl = (selected_media_id == PARCEL_MEDIA_LIST_ITEM_UUID) ? - ((LLViewerMediaImpl*)LLViewerParcelMedia::getParcelMedia()) : LLViewerMedia::getMediaImplFromTextureID(selected_media_id); + ((LLViewerMediaImpl*)LLViewerParcelMedia::getInstance()->getParcelMedia()) : LLViewerMedia::getInstance()->getMediaImplFromTextureID(selected_media_id); if (NULL != impl) { F32 volume = impl->getVolume(); @@ -1193,7 +1157,7 @@ void LLPanelNearByMedia::onCommitSelectedMediaVolume() } else { LLViewerMediaImpl* impl = (selected_media_id == PARCEL_MEDIA_LIST_ITEM_UUID) ? - ((LLViewerMediaImpl*)LLViewerParcelMedia::getParcelMedia()) : LLViewerMedia::getMediaImplFromTextureID(selected_media_id); + ((LLViewerMediaImpl*)LLViewerParcelMedia::getInstance()->getParcelMedia()) : LLViewerMedia::getInstance()->getMediaImplFromTextureID(selected_media_id); if (NULL != impl) { impl->setVolume(mVolumeSlider->getValueF32()); diff --git a/indra/newview/llpanelnearbymedia.h b/indra/newview/llpanelnearbymedia.h index a9c1b190cf..2d898d0aa1 100644 --- a/indra/newview/llpanelnearbymedia.h +++ b/indra/newview/llpanelnearbymedia.h @@ -27,7 +27,7 @@ #ifndef LL_LLPANELNEARBYMEDIA_H #define LL_LLPANELNEARBYMEDIA_H -#include "llpanel.h" +#include "llpanelpulldown.h" class LLPanelNearbyMedia; class LLButton; @@ -39,16 +39,12 @@ class LLTextBox; class LLComboBox; class LLViewerMediaImpl; -class LLPanelNearByMedia : public LLPanel +class LLPanelNearByMedia : public LLPanelPulldown { public: /*virtual*/ BOOL postBuild(); /*virtual*/ void draw(); - /*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask); - /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask); - /*virtual*/ void onTopLost(); - /*virtual*/ void onVisibilityChange ( BOOL new_visibility ); /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent); /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); @@ -173,7 +169,6 @@ private: LLRect mMoreRect; LLRect mLessRect; - LLFrameTimer mHoverTimer; LLScrollListItem* mParcelMediaItem; LLScrollListItem* mParcelAudioItem; }; diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 3665910c63..6bff95ab36 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -30,7 +30,6 @@ #include "llpanelobject.h" // linden library includes -#include "lleconomy.h" #include "llerror.h" #include "llfontgl.h" #include "llpermissionsflags.h" diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 6702dae4d6..ecadc9443b 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -143,6 +143,7 @@ public: 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 LLSettingsType::type_e getSettingsType() const { return LLSettingsType::ST_NONE; } virtual EInventorySortGroup getSortGroup() const { return SG_ITEM; } virtual LLInventoryObject* getInventoryObject() const { return findInvObject(); } @@ -702,6 +703,7 @@ BOOL LLTaskCategoryBridge::dragOrDrop(MASK mask, BOOL drop, case DAD_GESTURE: case DAD_CALLINGCARD: case DAD_MESH: + case DAD_SETTINGS: accept = LLToolDragAndDrop::isInventoryDropAcceptable(object, (LLViewerInventoryItem*)cargo_data); if(accept && drop) { @@ -1122,6 +1124,33 @@ LLUIImagePtr LLTaskWearableBridge::getIcon() const } ///---------------------------------------------------------------------------- +/// Class LLTaskSettingsBridge +///---------------------------------------------------------------------------- + +class LLTaskSettingsBridge : public LLTaskInvFVBridge +{ +public: + LLTaskSettingsBridge(LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name, + U32 flags) : + LLTaskInvFVBridge(panel, uuid, name, flags) {} + + virtual LLUIImagePtr getIcon() const; + virtual LLSettingsType::type_e getSettingsType() const; +}; + +LLUIImagePtr LLTaskSettingsBridge::getIcon() const +{ + return LLInventoryIcon::getIcon(mAssetType, mInventoryType, mFlags, FALSE); +} + +LLSettingsType::type_e LLTaskSettingsBridge::getSettingsType() const +{ + return LLSettingsType::ST_NONE; +} + +///---------------------------------------------------------------------------- /// LLTaskInvFVBridge impl //---------------------------------------------------------------------------- @@ -1202,6 +1231,12 @@ LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory* object_id, object_name); break; + case LLAssetType::AT_SETTINGS: + new_bridge = new LLTaskSettingsBridge(panel, + object_id, + object_name, + itemflags); + break; default: LL_INFOS() << "Unhandled inventory type (llassetstorage.h): " << (S32)type << LL_ENDL; @@ -1561,12 +1596,13 @@ void LLPanelObjectInventory::refresh() //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); - if(node) + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + LLSelectNode* node = selection->getFirstRootNode(NULL, non_root_ok); + if(node && node->mValid) { LLViewerObject* object = node->getObject(); - if(object && ((LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() == 1) - || (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1))) + if(object && ((selection->getRootObjectCount() == 1) + || (selection->getObjectCount() == 1))) { // determine if we need to make a request. Start with a // default based on if we have inventory at all. diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 1d87aa6f5d..5be9ab6095 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -58,7 +58,6 @@ #include "llmenubutton.h" #include "llpaneloutfitsinventory.h" #include "lluiconstants.h" -#include "llsaveoutfitcombobtn.h" #include "llscrolllistctrl.h" #include "lltextbox.h" #include "lltoggleablemenu.h" @@ -80,6 +79,8 @@ const U64 ATTACHMENT_MASK = (1LL << LLInventoryType::IT_ATTACHMENT) | (1LL << LL const U64 ALL_ITEMS_MASK = WEARABLE_MASK | ATTACHMENT_MASK; static const std::string REVERT_BTN("revert_btn"); +static const std::string SAVE_AS_BTN("save_as_btn"); +static const std::string SAVE_BTN("save_btn"); /////////////////////////////////////////////////////////////////////////////// @@ -562,7 +563,10 @@ BOOL LLPanelOutfitEdit::postBuild() mGearMenu = LLPanelOutfitEditGearMenu::create(); mGearMenuBtn->setMenu(mGearMenu); - mSaveComboBtn.reset(new LLSaveOutfitComboBtn(this)); + getChild<LLButton>(SAVE_BTN)->setCommitCallback(boost::bind(&LLPanelOutfitEdit::saveOutfit, this, false)); + getChild<LLButton>(SAVE_AS_BTN)->setCommitCallback(boost::bind(&LLPanelOutfitEdit::saveOutfit, this, true)); + + onOutfitChanging(gAgentWearables.isCOFChangeInProgress()); return TRUE; } @@ -703,6 +707,10 @@ void LLPanelOutfitEdit::onListViewFilterCommitted(LLUICtrl* ctrl) S32 curr_filter_type = mListViewFilterCmbBox->getCurrentIndex(); if (curr_filter_type < 0) return; + if (curr_filter_type >= LVIT_SHAPE) + { + mWearableItemsList->setMenuWearableType(LLWearableType::EType(curr_filter_type - LVIT_SHAPE)); + } mWearableListManager->setFilterCollector(mListViewItemTypes[curr_filter_type]->collector); } @@ -1233,11 +1241,9 @@ void LLPanelOutfitEdit::updateVerbs() bool outfit_locked = LLAppearanceMgr::getInstance()->isOutfitLocked(); bool has_baseoutfit = LLAppearanceMgr::getInstance()->getBaseOutfitUUID().notNull(); - mSaveComboBtn->setSaveBtnEnabled(!outfit_locked && outfit_is_dirty); + getChildView(SAVE_BTN)->setEnabled(!outfit_locked && outfit_is_dirty); getChildView(REVERT_BTN)->setEnabled(outfit_is_dirty && has_baseoutfit); - mSaveComboBtn->setMenuItemEnabled("save_outfit", !outfit_locked && outfit_is_dirty); - mStatus->setText(outfit_is_dirty ? getString("unsaved_changes") : getString("now_editing")); updateCurrentOutfitName(); @@ -1282,6 +1288,7 @@ void LLPanelOutfitEdit::showFilteredWearablesListView(LLWearableType::EType type //e_list_view_item_type implicitly contains LLWearableType::EType starting from LVIT_SHAPE applyListViewFilter(static_cast<EListViewItemType>(LVIT_SHAPE + type)); + mWearableItemsList->setMenuWearableType(type); } static void update_status_widget_rect(LLView * widget, S32 right_border) @@ -1422,4 +1429,13 @@ void LLPanelOutfitEdit::saveListSelection() } } +void LLPanelOutfitEdit::saveOutfit(bool as_new) +{ + LLPanelOutfitsInventory* panel_outfits_inventory = LLPanelOutfitsInventory::findInstance(); + if (panel_outfits_inventory) + { + panel_outfits_inventory->saveOutfit(as_new); + } +} + // EOF diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h index 3c6efac0e7..d0597fb72b 100644 --- a/indra/newview/llpaneloutfitedit.h +++ b/indra/newview/llpaneloutfitedit.h @@ -58,7 +58,6 @@ class LLMenuButton; class LLMenuGL; class LLFindNonLinksByMask; class LLFindWearablesOfType; -class LLSaveOutfitComboBtn; class LLWearableItemTypeNameComparator; class LLPanelOutfitEdit : public LLPanel @@ -195,6 +194,7 @@ private: void getSelectedItemsUUID(uuid_vec_t& uuid_list); void getCurrentItemUUID(LLUUID& selected_id); void onCOFChanged(); + void saveOutfit(bool as_new = false); /** * Method preserves selection while switching between folder/list view modes @@ -237,7 +237,6 @@ private: LLToggleableMenu* mGearMenu; LLToggleableMenu* mAddWearablesGearMenu; bool mInitialized; - std::auto_ptr<LLSaveOutfitComboBtn> mSaveComboBtn; LLMenuButton* mWearablesGearMenuBtn; LLMenuButton* mGearMenuBtn; diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index 8019335f97..531073526b 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -40,7 +40,6 @@ #include "lloutfitgallery.h" #include "lloutfitslist.h" #include "llpanelwearing.h" -#include "llsaveoutfitcombobtn.h" #include "llsidepanelappearance.h" #include "llviewercontrol.h" #include "llviewerfoldertype.h" @@ -49,12 +48,16 @@ static const std::string OUTFITS_TAB_NAME = "outfitslist_tab"; static const std::string OUTFIT_GALLERY_TAB_NAME = "outfit_gallery_tab"; static const std::string COF_TAB_NAME = "cof_tab"; +static const std::string SAVE_AS_BTN("save_as_btn"); +static const std::string SAVE_BTN("save_btn"); + static LLPanelInjector<LLPanelOutfitsInventory> t_inventory("panel_outfits_inventory"); LLPanelOutfitsInventory::LLPanelOutfitsInventory() : mMyOutfitsPanel(NULL), mCurrentOutfitPanel(NULL), mActivePanel(NULL), + mAppearanceTabs(NULL), mInitialized(false) { gAgentWearables.addLoadedCallback(boost::bind(&LLPanelOutfitsInventory::onWearablesLoaded, this)); @@ -89,8 +92,9 @@ BOOL LLPanelOutfitsInventory::postBuild() { LLInventoryModelBackgroundFetch::instance().start(outfits_cat); } - - mSaveComboBtn.reset(new LLSaveOutfitComboBtn(this, true)); + + getChild<LLButton>(SAVE_BTN)->setCommitCallback(boost::bind(&LLPanelOutfitsInventory::saveOutfit, this, false)); + getChild<LLButton>(SAVE_AS_BTN)->setCommitCallback(boost::bind(&LLPanelOutfitsInventory::saveOutfit, this, true)); return TRUE; } @@ -245,6 +249,12 @@ LLPanelOutfitsInventory* LLPanelOutfitsInventory::findInstance() return dynamic_cast<LLPanelOutfitsInventory*>(LLFloaterSidePanelContainer::getPanel("appearance", "panel_outfits_inventory")); } +void LLPanelOutfitsInventory::openApearanceTab(const std::string& tab_name) +{ + if (!mAppearanceTabs) return; + mAppearanceTabs->selectTabByName(tab_name); +} + ////////////////////////////////////////////////////////////////////////////////// // List Commands // @@ -268,7 +278,7 @@ void LLPanelOutfitsInventory::updateListCommands() mOutfitGalleryPanel->childSetEnabled("trash_btn", trash_enabled); wear_btn->setEnabled(wear_enabled); wear_btn->setVisible(wear_visible); - mSaveComboBtn->setMenuItemEnabled("save_outfit", make_outfit_enabled); + getChild<LLButton>(SAVE_BTN)->setEnabled(make_outfit_enabled); wear_btn->setToolTip(getString((!isOutfitsGalleryPanelActive() && mMyOutfitsPanel->hasItemSelected()) ? "wear_items_tooltip" : "wear_outfit_tooltip")); } @@ -312,6 +322,7 @@ void LLPanelOutfitsInventory::initTabPanels() void LLPanelOutfitsInventory::onTabChange() { + if (!mAppearanceTabs) return; mActivePanel = dynamic_cast<LLPanelAppearanceTab*>(mAppearanceTabs->getCurrentPanel()); if (!mActivePanel) return; @@ -366,3 +377,15 @@ LLSidepanelAppearance* LLPanelOutfitsInventory::getAppearanceSP() dynamic_cast<LLSidepanelAppearance*>(LLFloaterSidePanelContainer::getPanel("appearance")); return panel_appearance; } + +void LLPanelOutfitsInventory::saveOutfit(bool as_new) +{ + if (!as_new && LLAppearanceMgr::getInstance()->updateBaseOutfit()) + { + // we don't need to ask for an outfit name, and updateBaseOutfit() successfully saved. + // If updateBaseOutfit fails, ask for an outfit name anyways + return; + } + + onSave(); +} diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h index 6a0ea04fa6..50d7074d4b 100644 --- a/indra/newview/llpaneloutfitsinventory.h +++ b/indra/newview/llpaneloutfitsinventory.h @@ -38,7 +38,6 @@ class LLPanelWearing; class LLMenuGL; class LLSidepanelAppearance; class LLTabContainer; -class LLSaveOutfitComboBtn; class LLPanelOutfitsInventory : public LLPanel { @@ -52,6 +51,7 @@ public: void onSearchEdit(const std::string& string); void onSave(); + void saveOutfit(bool as_new = false); bool onSaveCommit(const LLSD& notification, const LLSD& response); @@ -59,13 +59,14 @@ public: static LLPanelOutfitsInventory* findInstance(); + void openApearanceTab(const std::string& tab_name); + protected: void updateVerbs(); private: LLTabContainer* mAppearanceTabs; std::string mFilterSubString; - std::auto_ptr<LLSaveOutfitComboBtn> mSaveComboBtn; ////////////////////////////////////////////////////////////////////////////////// // tab panels // diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index be174475e1..5997d522c4 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -47,6 +47,7 @@ #include "llaccordionctrl.h" #include "llaccordionctrltab.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llavataractions.h" #include "llavatarlist.h" #include "llavatarlistitem.h" @@ -85,11 +86,6 @@ static const std::string RECENT_TAB_NAME = "recent_panel"; static const std::string BLOCKED_TAB_NAME = "blocked_panel"; // blocked avatars static const std::string COLLAPSED_BY_USER = "collapsed_by_user"; -const S32 BASE_MAX_AGENT_GROUPS = 42; -const S32 PREMIUM_MAX_AGENT_GROUPS = 60; - -extern S32 gMaxAgentGroups; - /** Comparator for comparing avatar items by last interaction date */ class LLAvatarItemRecentComparator : public LLAvatarItemComparator { @@ -612,26 +608,17 @@ void LLPanelPeople::removePicker() BOOL LLPanelPeople::postBuild() { - S32 max_premium = PREMIUM_MAX_AGENT_GROUPS; - if (gAgent.getRegion()) - { - LLSD features; - gAgent.getRegion()->getSimulatorFeatures(features); - if (features.has("MaxAgentGroupsPremium")) - { - max_premium = features["MaxAgentGroupsPremium"].asInteger(); - } - } + S32 max_premium = LLAgentBenefitsMgr::get("Premium").getGroupMembershipLimit(); getChild<LLFilterEditor>("nearby_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); getChild<LLFilterEditor>("friends_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); getChild<LLFilterEditor>("groups_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); getChild<LLFilterEditor>("recent_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); - if(gMaxAgentGroups < max_premium) + if(LLAgentBenefitsMgr::current().getGroupMembershipLimit() < max_premium) { - getChild<LLTextBox>("groupcount")->setText(getString("GroupCountWithInfo")); - getChild<LLTextBox>("groupcount")->setURLClickedCallback(boost::bind(&LLPanelPeople::onGroupLimitInfo, this)); + getChild<LLTextBox>("groupcount")->setText(getString("GroupCountWithInfo")); + getChild<LLTextBox>("groupcount")->setURLClickedCallback(boost::bind(&LLPanelPeople::onGroupLimitInfo, this)); } mTabContainer = getChild<LLTabContainer>("tabs"); @@ -674,6 +661,7 @@ BOOL LLPanelPeople::postBuild() mRecentList->setShowIcons("RecentListShowIcons"); mGroupList = getChild<LLGroupList>("group_list"); + mGroupList->setNoItemsCommentText(getString("no_groups_msg")); mGroupList->setNoItemsMsg(getString("no_groups_msg")); mGroupList->setNoFilteredItemsMsg(getString("no_filtered_groups_msg")); @@ -876,9 +864,10 @@ void LLPanelPeople::updateButtons() groups_panel->getChildView("minus_btn")->setEnabled(item_selected && selected_id.notNull()); // a real group selected U32 groups_count = gAgent.mGroups.size(); - U32 groups_ramaining = gMaxAgentGroups > groups_count ? gMaxAgentGroups - groups_count : 0; + S32 max_groups = LLAgentBenefitsMgr::current().getGroupMembershipLimit(); + U32 groups_remaining = max_groups > groups_count ? max_groups - groups_count : 0; groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d", groups_count)); - groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[REMAINING]", llformat("%d", groups_ramaining)); + groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[REMAINING]", llformat("%d", groups_remaining)); } else { @@ -1095,25 +1084,22 @@ void LLPanelPeople::onGroupLimitInfo() { LLSD args; - S32 max_basic = BASE_MAX_AGENT_GROUPS; - S32 max_premium = PREMIUM_MAX_AGENT_GROUPS; - if (gAgent.getRegion()) + S32 max_basic = LLAgentBenefitsMgr::get("Base").getGroupMembershipLimit(); + S32 max_premium = LLAgentBenefitsMgr::get("Premium").getGroupMembershipLimit(); + + args["MAX_BASIC"] = max_basic; + args["MAX_PREMIUM"] = max_premium; + + if (LLAgentBenefitsMgr::has("Premium Plus")) { - LLSD features; - gAgent.getRegion()->getSimulatorFeatures(features); - if (features.has("MaxAgentGroupsBasic")) - { - max_basic = features["MaxAgentGroupsBasic"].asInteger(); - } - if (features.has("MaxAgentGroupsPremium")) - { - max_premium = features["MaxAgentGroupsPremium"].asInteger(); - } + S32 max_premium_plus = LLAgentBenefitsMgr::get("Premium Plus").getGroupMembershipLimit(); + args["MAX_PREMIUM_PLUS"] = max_premium_plus; + LLNotificationsUtil::add("GroupLimitInfoPlus", args); } - args["MAX_BASIC"] = max_basic; - args["MAX_PREMIUM"] = max_premium; - - LLNotificationsUtil::add("GroupLimitInfo", args); + else + { + LLNotificationsUtil::add("GroupLimitInfo", args); + } } void LLPanelPeople::onTabSelected(const LLSD& param) diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp index ef16427713..3e770958da 100644 --- a/indra/newview/llpanelpermissions.cpp +++ b/indra/newview/llpanelpermissions.cpp @@ -972,13 +972,45 @@ void LLPanelPermissions::refresh() getChildView("clickaction")->setEnabled(is_perm_modify && is_nonpermanent_enforced && all_volume); } +// Shorten name if it doesn't fit into max_pixels of two lines +void shorten_name(std::string &name, const LLStyle::Params& style_params, S32 max_pixels) +{ + const LLFontGL* font = style_params.font(); + + LLWString wline = utf8str_to_wstring(name); + // panel supports two lines long names + S32 segment_length = font->maxDrawableChars(wline.c_str(), max_pixels, wline.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE); + if (segment_length == wline.length()) + { + // no work needed + return; + } + + S32 first_line_length = segment_length; + segment_length = font->maxDrawableChars(wline.substr(first_line_length).c_str(), max_pixels, wline.length(), LLFontGL::ANYWHERE); + if (segment_length + first_line_length == wline.length()) + { + // no work needed + return; + } + + // name does not fit, cut it, add ... + const LLWString dots_pad(utf8str_to_wstring(std::string("...."))); + S32 elipses_width = font->getWidthF32(dots_pad.c_str()); + segment_length = font->maxDrawableChars(wline.substr(first_line_length).c_str(), max_pixels - elipses_width, wline.length(), LLFontGL::ANYWHERE); + + name = name.substr(0, segment_length + first_line_length) + std::string("..."); +} + void LLPanelPermissions::updateOwnerName(const LLUUID& owner_id, const LLAvatarName& owner_name, const LLStyle::Params& style_params) { if (mOwnerCacheConnection.connected()) { mOwnerCacheConnection.disconnect(); } - mLabelOwnerName->setText(owner_name.getCompleteName(), style_params); + std::string name = owner_name.getCompleteName(); + shorten_name(name, style_params, mLabelOwnerName->getLocalRect().getWidth()); + mLabelOwnerName->setText(name, style_params); } void LLPanelPermissions::updateCreatorName(const LLUUID& creator_id, const LLAvatarName& creator_name, const LLStyle::Params& style_params) @@ -987,7 +1019,9 @@ void LLPanelPermissions::updateCreatorName(const LLUUID& creator_id, const LLAva { mCreatorCacheConnection.disconnect(); } - mLabelCreatorName->setText(creator_name.getCompleteName(), style_params); + std::string name = creator_name.getCompleteName(); + shorten_name(name, style_params, mLabelCreatorName->getLocalRect().getWidth()); + mLabelCreatorName->setText(name, style_params); } // static diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp index 77bc99da83..8294977f99 100644 --- a/indra/newview/llpanelpicks.cpp +++ b/indra/newview/llpanelpicks.cpp @@ -37,6 +37,7 @@ #include "llfloatersidepanelcontainer.h" #include "llfloaterworldmap.h" #include "llnotificationsutil.h" +#include "llstartup.h" #include "lltexturectrl.h" #include "lltoggleablemenu.h" #include "lltrans.h" @@ -84,7 +85,12 @@ public: bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) { - if (!LLUI::sSettingGroups["config"]->getBOOL("EnablePicks")) + if (LLStartUp::getStartupState() < STATE_STARTED) + { + return true; + } + + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnablePicks")) { LLNotificationsUtil::add("NoPicks", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); return true; @@ -198,7 +204,12 @@ public: bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) { - if (!LLUI::sSettingGroups["config"]->getBOOL("EnableClassifieds")) + if (LLStartUp::getStartupState() < STATE_STARTED) + { + return true; + } + + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableClassifieds")) { LLNotificationsUtil::add("NoClassifieds", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); return true; @@ -472,19 +483,7 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type) mNoClassifieds = !mClassifiedsList->size(); } - bool no_data = mNoPicks && mNoClassifieds; - mNoItemsLabel->setVisible(no_data); - if (no_data) - { - if(getAvatarId() == gAgentID) - { - mNoItemsLabel->setValue(LLTrans::getString("NoPicksClassifiedsText")); - } - else - { - mNoItemsLabel->setValue(LLTrans::getString("NoAvatarPicksClassifiedsText")); - } - } + updateNoItemsLabel(); } LLPickItem* LLPanelPicks::getSelectedPickItem() @@ -713,6 +712,13 @@ bool LLPanelPicks::callbackDeletePick(const LLSD& notification, const LLSD& resp { LLAvatarPropertiesProcessor::instance().sendPickDelete(pick_value[PICK_ID]); mPicksList->removeItemByValue(pick_value); + + mNoPicks = !mPicksList->size(); + if (mNoPicks) + { + showAccordion("tab_picks", false); + } + updateNoItemsLabel(); } updateButtons(); return false; @@ -727,6 +733,13 @@ bool LLPanelPicks::callbackDeleteClassified(const LLSD& notification, const LLSD { LLAvatarPropertiesProcessor::instance().sendClassifiedDelete(value[CLASSIFIED_ID]); mClassifiedsList->removeItemByValue(value); + + mNoClassifieds = !mClassifiedsList->size(); + if (mNoClassifieds) + { + showAccordion("tab_classifieds", false); + } + updateNoItemsLabel(); } updateButtons(); return false; @@ -840,6 +853,23 @@ void LLPanelPicks::updateButtons() } } +void LLPanelPicks::updateNoItemsLabel() +{ + bool no_data = mNoPicks && mNoClassifieds; + mNoItemsLabel->setVisible(no_data); + if (no_data) + { + if (getAvatarId() == gAgentID) + { + mNoItemsLabel->setValue(LLTrans::getString("NoPicksClassifiedsText")); + } + else + { + mNoItemsLabel->setValue(LLTrans::getString("NoAvatarPicksClassifiedsText")); + } + } +} + void LLPanelPicks::setProfilePanel(LLPanelProfile* profile_panel) { mProfilePanel = profile_panel; diff --git a/indra/newview/llpanelpicks.h b/indra/newview/llpanelpicks.h index 3bb7413ac3..fd7688b99d 100644 --- a/indra/newview/llpanelpicks.h +++ b/indra/newview/llpanelpicks.h @@ -87,6 +87,7 @@ public: protected: /*virtual*/void updateButtons(); + void updateNoItemsLabel(); private: void onClickDelete(); diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp index 0c70aa87c2..9157df789f 100644 --- a/indra/newview/llpanelplaceinfo.cpp +++ b/indra/newview/llpanelplaceinfo.cpp @@ -43,6 +43,7 @@ #include "llagent.h" #include "llexpandabletextbox.h" #include "llpanelpick.h" +#include "llslurl.h" #include "lltexturectrl.h" #include "llviewerregion.h" #include "llhttpconstants.h" @@ -78,6 +79,7 @@ BOOL LLPanelPlaceInfo::postBuild() mSnapshotCtrl = getChild<LLTextureCtrl>("logo"); mRegionName = getChild<LLTextBox>("region_title"); mParcelName = getChild<LLTextBox>("parcel_title"); + mParcelOwner = getChild<LLTextBox>("parcel_owner"); mDescEditor = getChild<LLExpandableTextBox>("description"); mMaturityRatingIcon = getChild<LLIconCtrl>("maturity_icon"); @@ -98,11 +100,13 @@ void LLPanelPlaceInfo::resetLocation() mParcelID.setNull(); mRequestedID.setNull(); mPosRegion.clearVec(); + mRegionTitle.clear(); std::string loading = LLTrans::getString("LoadingData"); mMaturityRatingText->setValue(loading); - mRegionName->setText(loading); + mRegionName->setTextArg("[REGIONAMEPOS]", loading); mParcelName->setText(loading); + mParcelOwner->setText(loading); mDescEditor->setText(loading); mMaturityRatingIcon->setValue(LLUUID::null); @@ -182,9 +186,11 @@ void LLPanelPlaceInfo::setErrorStatus(S32 status, const std::string& reason) std::string not_available = getString("not_available"); mMaturityRatingText->setValue(not_available); - mRegionName->setText(not_available); + mRegionName->setTextArg("[REGIONAMEPOS]", not_available); mParcelName->setText(not_available); + mParcelOwner->setText(not_available); mMaturityRatingIcon->setValue(LLUUID::null); + mRegionTitle.clear(); // Enable "Back" button that was disabled when parcel request was sent. getChild<LLButton>("back_btn")->setEnabled(TRUE); @@ -198,12 +204,34 @@ void LLPanelPlaceInfo::processParcelInfo(const LLParcelData& parcel_data) mSnapshotCtrl->setImageAssetID(parcel_data.snapshot_id); } - if(!parcel_data.sim_name.empty()) - { - mRegionName->setText(parcel_data.sim_name); + S32 region_x; + S32 region_y; + S32 region_z; + + // If the region position is zero, grab position from the global + if (mPosRegion.isExactlyZero()) + { + 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); + } + else + { + region_x = ll_round(mPosRegion.mV[VX]); + region_y = ll_round(mPosRegion.mV[VY]); + region_z = ll_round(mPosRegion.mV[VZ]); + } + + if (!parcel_data.sim_name.empty()) + { + mRegionTitle = parcel_data.sim_name; + std::string name_and_pos = llformat("%s (%d, %d, %d)", + mRegionTitle.c_str(), region_x, region_y, region_z); + mRegionName->setTextArg("[REGIONAMEPOS]", name_and_pos); } else { + mRegionTitle.clear(); mRegionName->setText(LLStringUtil::null); } @@ -216,30 +244,11 @@ void LLPanelPlaceInfo::processParcelInfo(const LLParcelData& parcel_data) mDescEditor->setText(getString("not_available")); } - S32 region_x; - S32 region_y; - S32 region_z; - - // If the region position is zero, grab position from the global - if(mPosRegion.isExactlyZero()) - { - 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); - } - else - { - region_x = ll_round(mPosRegion.mV[VX]); - region_y = ll_round(mPosRegion.mV[VY]); - region_z = ll_round(mPosRegion.mV[VZ]); - } - if (!parcel_data.name.empty()) { mParcelTitle = parcel_data.name; - mParcelName->setText(llformat("%s (%d, %d, %d)", - mParcelTitle.c_str(), region_x, region_y, region_z)); + mParcelName->setText(mParcelTitle); } else { @@ -280,12 +289,10 @@ void LLPanelPlaceInfo::reshape(S32 width, S32 height, BOOL called_from_parent) void LLPanelPlaceInfo::createPick(const LLVector3d& pos_global, LLPanelPickEdit* pick_panel) { - std::string region_name = mRegionName->getText(); - LLPickData data; data.pos_global = pos_global; - data.name = mParcelTitle.empty() ? region_name : mParcelTitle; - data.sim_name = region_name; + data.name = mParcelTitle.empty() ? mRegionTitle : mParcelTitle; + data.sim_name = mRegionTitle; data.desc = mDescEditor->getText(); data.snapshot_id = mSnapshotCtrl->getImageAssetID(); data.parcel_id = mParcelID; diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h index 30327378ef..8bf67cfe7d 100644 --- a/indra/newview/llpanelplaceinfo.h +++ b/indra/newview/llpanelplaceinfo.h @@ -109,6 +109,7 @@ protected: LLUUID mRequestedID; LLVector3 mPosRegion; std::string mParcelTitle; // used for pick title without coordinates + std::string mRegionTitle; std::string mCurrentTitle; S32 mScrollingPanelMinHeight; S32 mScrollingPanelWidth; @@ -120,6 +121,7 @@ protected: LLTextureCtrl* mSnapshotCtrl; LLTextBox* mRegionName; LLTextBox* mParcelName; + LLTextBox* mParcelOwner; LLExpandableTextBox* mDescEditor; LLIconCtrl* mMaturityRatingIcon; LLTextBox* mMaturityRatingText; diff --git a/indra/newview/llpanelplaceprofile.cpp b/indra/newview/llpanelplaceprofile.cpp index 104316e253..9283dfa218 100644 --- a/indra/newview/llpanelplaceprofile.cpp +++ b/indra/newview/llpanelplaceprofile.cpp @@ -104,8 +104,6 @@ BOOL LLPanelPlaceProfile::postBuild() mForSalePanel->getChild<LLIconCtrl>("icon_for_sale")-> setMouseDownCallback(boost::bind(&LLPanelPlaceProfile::onForSaleBannerClick, this)); - mParcelOwner = getChild<LLTextBox>("owner_value"); - mParcelRatingIcon = getChild<LLIconCtrl>("rating_icon"); mParcelRatingText = getChild<LLTextBox>("rating_value"); mVoiceIcon = getChild<LLIconCtrl>("voice_icon"); @@ -183,7 +181,6 @@ void LLPanelPlaceProfile::resetLocation() mYouAreHerePanel->setVisible(FALSE); std::string loading = LLTrans::getString("LoadingData"); - mParcelOwner->setValue(loading); mParcelRatingIcon->setValue(loading); mParcelRatingText->setText(loading); @@ -248,14 +245,14 @@ void LLPanelPlaceProfile::setInfoType(EInfoType type) const S32 SEARCH_DESC_HEIGHT = 150; // Remember original geometry (once). - static const S32 sOrigDescVPad = getChildView("parcel_title")->getRect().mBottom - mDescEditor->getRect().mTop; + static const S32 sOrigDescVPad = getChildView("owner_label")->getRect().mBottom - mDescEditor->getRect().mTop; static const S32 sOrigDescHeight = mDescEditor->getRect().getHeight(); static const S32 sOrigMRIconVPad = mDescEditor->getRect().mBottom - mMaturityRatingIcon->getRect().mTop; static const S32 sOrigMRTextVPad = mDescEditor->getRect().mBottom - mMaturityRatingText->getRect().mTop; // Resize the description. const S32 desc_height = is_info_type_agent ? sOrigDescHeight : SEARCH_DESC_HEIGHT; - const S32 desc_top = getChildView("parcel_title")->getRect().mBottom - sOrigDescVPad; + const S32 desc_top = getChildView("owner_label")->getRect().mBottom - sOrigDescVPad; LLRect desc_rect = mDescEditor->getRect(); desc_rect.setOriginAndSize(desc_rect.mLeft, desc_top - desc_height, desc_rect.getWidth(), desc_height); mDescEditor->reshape(desc_rect.getWidth(), desc_rect.getHeight()); @@ -401,6 +398,7 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel, parcel_data.global_x = pos_global.mdV[VX]; parcel_data.global_y = pos_global.mdV[VY]; parcel_data.global_z = pos_global.mdV[VZ]; + parcel_data.owner_id = parcel->getOwnerID(); std::string on = getString("on"); std::string off = getString("off"); diff --git a/indra/newview/llpanelplaceprofile.h b/indra/newview/llpanelplaceprofile.h index 3d2654fc12..16478bc179 100644 --- a/indra/newview/llpanelplaceprofile.h +++ b/indra/newview/llpanelplaceprofile.h @@ -76,8 +76,6 @@ private: LLPanel* mForSalePanel; LLPanel* mYouAreHerePanel; - LLTextBox* mParcelOwner; - LLIconCtrl* mParcelRatingIcon; LLTextBox* mParcelRatingText; LLIconCtrl* mVoiceIcon; diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 48dd45480e..9c67ec40fe 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -53,12 +53,14 @@ #include "llagentpicksinfo.h" #include "llavatarpropertiesprocessor.h" #include "llcommandhandler.h" +#include "lldndbutton.h" #include "llfloaterworldmap.h" #include "llinventorybridge.h" #include "llinventoryobserver.h" #include "llinventorymodel.h" #include "lllandmarkactions.h" #include "lllandmarklist.h" +#include "lllayoutstack.h" #include "llpanellandmarkinfo.h" #include "llpanellandmarks.h" #include "llpanelpick.h" @@ -78,6 +80,7 @@ static const F32 PLACE_INFO_UPDATE_INTERVAL = 3.0; static const std::string AGENT_INFO_TYPE = "agent"; static const std::string CREATE_LANDMARK_INFO_TYPE = "create_landmark"; +static const std::string CREATE_PICK_TYPE = "create_pick"; static const std::string LANDMARK_INFO_TYPE = "landmark"; static const std::string REMOTE_PLACE_INFO_TYPE = "remote_place"; static const std::string TELEPORT_HISTORY_INFO_TYPE = "teleport_history"; @@ -97,7 +100,7 @@ public: return false; } - if (!LLUI::sSettingGroups["config"]->getBOOL("EnablePlaceProfile")) + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnablePlaceProfile")) { LLNotificationsUtil::add("NoPlaceInfo", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); return true; @@ -280,9 +283,6 @@ BOOL LLPanelPlaces::postBuild() mShowOnMapBtn = getChild<LLButton>("map_btn"); mShowOnMapBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onShowOnMapButtonClicked, this)); - mEditBtn = getChild<LLButton>("edit_btn"); - mEditBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onEditButtonClicked, this)); - mSaveBtn = getChild<LLButton>("save_btn"); mSaveBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onSaveButtonClicked, this)); @@ -295,8 +295,25 @@ BOOL LLPanelPlaces::postBuild() mOverflowBtn = getChild<LLMenuButton>("overflow_btn"); mOverflowBtn->setMouseDownCallback(boost::bind(&LLPanelPlaces::onOverflowButtonClicked, this)); - mPlaceInfoBtn = getChild<LLButton>("profile_btn"); - mPlaceInfoBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onProfileButtonClicked, this)); + mGearMenuButton = getChild<LLMenuButton>("options_gear_btn"); + mGearMenuButton->setMouseDownCallback(boost::bind(&LLPanelPlaces::onGearMenuClick, this)); + + mSortingMenuButton = getChild<LLMenuButton>("sorting_menu_btn"); + mSortingMenuButton->setMouseDownCallback(boost::bind(&LLPanelPlaces::onSortingMenuClick, this)); + + mAddMenuButton = getChild<LLMenuButton>("add_menu_btn"); + mAddMenuButton->setMouseDownCallback(boost::bind(&LLPanelPlaces::onAddMenuClick, this)); + + mRemoveSelectedBtn = getChild<LLButton>("trash_btn"); + mRemoveSelectedBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onRemoveButtonClicked, this)); + + LLDragAndDropButton* trash_btn = (LLDragAndDropButton*)mRemoveSelectedBtn; + trash_btn->setDragAndDropHandler(boost::bind(&LLPanelPlaces::handleDragAndDropToTrash, this + , _4 // BOOL drop + , _5 // EDragAndDropType cargo_type + , _6 // void* cargo_data + , _7 // EAcceptance* accept + )); LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; registrar.add("Places.OverflowMenu.Action", boost::bind(&LLPanelPlaces::onOverflowMenuItemClicked, this, _2)); @@ -325,6 +342,10 @@ BOOL LLPanelPlaces::postBuild() mTabContainer->setCommitCallback(boost::bind(&LLPanelPlaces::onTabSelected, this)); } + mButtonsContainer = getChild<LLPanel>("button_layout_panel"); + mButtonsContainer->setVisible(FALSE); + mFilterContainer = getChild<LLLayoutStack>("top_menu_panel"); + mFilterEditor = getChild<LLFilterEditor>("Filter"); if (mFilterEditor) { @@ -355,6 +376,9 @@ BOOL LLPanelPlaces::postBuild() LLComboBox* folder_combo = mLandmarkInfo->getChild<LLComboBox>("folder_combo"); folder_combo->setCommitCallback(boost::bind(&LLPanelPlaces::onEditButtonClicked, this)); + LLButton* edit_btn = mLandmarkInfo->getChild<LLButton>("edit_btn"); + edit_btn->setCommitCallback(boost::bind(&LLPanelPlaces::onEditButtonClicked, this)); + createTabs(); updateVerbs(); @@ -387,7 +411,22 @@ void LLPanelPlaces::onOpen(const LLSD& key) // Update the buttons at the bottom of the panel updateVerbs(); } - else + else if (key_type == CREATE_PICK_TYPE) + { + LLUUID item_id = key["item_id"]; + + LLLandmarksPanel* landmarks_panel = + dynamic_cast<LLLandmarksPanel*>(mTabContainer->getPanelByName("Landmarks")); + if (landmarks_panel && item_id.notNull()) + { + LLLandmark* landmark = LLLandmarkActions::getLandmark(item_id, boost::bind(&LLLandmarksPanel::doCreatePick, landmarks_panel, _1, item_id)); + if (landmark) + { + landmarks_panel->doCreatePick(landmark, item_id); + } + } + } + else // "create_landmark" { mFilterEditor->clear(); onFilterEdit("", false); @@ -408,7 +447,8 @@ void LLPanelPlaces::onOpen(const LLSD& key) } else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE) { - mLandmarkInfo->setInfoType(LLPanelPlaceInfo::CREATE_LANDMARK); + LLUUID dest_folder = key["dest_folder"]; + mLandmarkInfo->setInfoAndCreateLandmark(dest_folder); if (key.has("x") && key.has("y") && key.has("z")) { @@ -532,7 +572,6 @@ void LLPanelPlaces::setItem(LLInventoryItem* item) BOOL is_landmark_editable = gInventory.isObjectDescendentOf(mItem->getUUID(), gInventory.getRootFolderID()) && mItem->getPermissions().allowModifyBy(gAgent.getID()); - mEditBtn->setEnabled(is_landmark_editable); mSaveBtn->setEnabled(is_landmark_editable); if (is_landmark_editable) @@ -612,6 +651,23 @@ void LLPanelPlaces::onTabSelected() onFilterEdit(mActivePanel->getFilterSubString(), true); mActivePanel->updateVerbs(); + + // History panel does not support deletion nor creation + // Hide menus + bool supports_create = mActivePanel->getCreateMenu() != NULL; + childSetVisible("add_btn_panel", supports_create); + + // favorites and inventory can remove items, history can clear history + childSetVisible("trash_btn_panel", TRUE); + + if (supports_create) + { + mRemoveSelectedBtn->setToolTip(getString("tooltip_trash_items")); + } + else + { + mRemoveSelectedBtn->setToolTip(getString("tooltip_trash_history")); + } } void LLPanelPlaces::onTeleportButtonClicked() @@ -675,6 +731,12 @@ void LLPanelPlaces::onShowOnMapButtonClicked() } else if (mPlaceInfoType == LANDMARK_INFO_TYPE) { + if (mItem.isNull()) + { + LL_WARNS() << "NULL landmark item" << LL_ENDL; + llassert(mItem.notNull()); + return; + } LLLandmark* landmark = gLandmarkList.getAsset(mItem->getAssetUUID()); if (!landmark) return; @@ -722,34 +784,6 @@ void LLPanelPlaces::onEditButtonClicked() updateVerbs(); } -class LLUpdateLandmarkParent : public LLInventoryCallback -{ -public: - LLUpdateLandmarkParent(LLPointer<LLViewerInventoryItem> item, LLUUID new_parent) : - mItem(item), - mNewParentId(new_parent) - {}; - /* virtual */ void fire(const LLUUID& inv_item_id) - { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(mItem->getParentUUID(), -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(mNewParentId, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - - mItem->setParent(mNewParentId); - mItem->updateParentOnServer(FALSE); - - gInventory.updateItem(mItem); - gInventory.notifyObservers(); - } - -private: - LLPointer<LLViewerInventoryItem> mItem; - LLUUID mNewParentId; -}; - void LLPanelPlaces::onSaveButtonClicked() { if (!mLandmarkInfo || mItem.isNull()) @@ -879,14 +913,6 @@ void LLPanelPlaces::onOverflowButtonClicked() mOverflowBtn->setMenu(menu, LLMenuButton::MP_TOP_RIGHT); } -void LLPanelPlaces::onProfileButtonClicked() -{ - if (!mActivePanel) - return; - - mActivePanel->onShowProfile(); -} - bool LLPanelPlaces::onOverflowMenuItemEnable(const LLSD& param) { std::string value = param.asString(); @@ -975,6 +1001,50 @@ void LLPanelPlaces::onBackButtonClicked() updateVerbs(); } +void LLPanelPlaces::onGearMenuClick() +{ + if (mActivePanel) + { + LLToggleableMenu* menu = mActivePanel->getSelectionMenu(); + mGearMenuButton->setMenu(menu, LLMenuButton::MP_BOTTOM_LEFT); + } +} + +void LLPanelPlaces::onSortingMenuClick() +{ + if (mActivePanel) + { + LLToggleableMenu* menu = mActivePanel->getSortingMenu(); + mSortingMenuButton->setMenu(menu, LLMenuButton::MP_BOTTOM_LEFT); + } +} + +void LLPanelPlaces::onAddMenuClick() +{ + if (mActivePanel) + { + LLToggleableMenu* menu = mActivePanel->getCreateMenu(); + mAddMenuButton->setMenu(menu, LLMenuButton::MP_BOTTOM_LEFT); + } +} + +void LLPanelPlaces::onRemoveButtonClicked() +{ + if (mActivePanel) + { + mActivePanel->onRemoveSelected(); + } +} + +bool LLPanelPlaces::handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept) +{ + if (mActivePanel) + { + return mActivePanel->handleDragAndDropToTrash(drop, cargo_type, cargo_data, accept); + } + return false; +} + void LLPanelPlaces::togglePickPanel(BOOL visible) { if (mPickPanel) @@ -991,8 +1061,9 @@ void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible) if (!mPlaceProfile || !mLandmarkInfo) return; - mFilterEditor->setVisible(!visible); mTabContainer->setVisible(!visible); + mButtonsContainer->setVisible(visible); + mFilterContainer->setVisible(!visible); if (mPlaceInfoType == AGENT_INFO_TYPE || mPlaceInfoType == REMOTE_PLACE_INFO_TYPE || @@ -1008,10 +1079,6 @@ void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible) // to avoid text blinking. mResetInfoTimer.setTimerExpirySec(PLACE_INFO_UPDATE_INTERVAL); - LLRect rect = getRect(); - LLRect new_rect = LLRect(rect.mLeft, rect.mTop, rect.mRight, mTabContainer->getRect().mBottom); - mPlaceProfile->reshape(new_rect.getWidth(), new_rect.getHeight()); - mLandmarkInfo->setVisible(FALSE); } else if (mPlaceInfoType == AGENT_INFO_TYPE) @@ -1032,15 +1099,19 @@ void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible) if (visible) { mLandmarkInfo->resetLocation(); - - LLRect rect = getRect(); - LLRect new_rect = LLRect(rect.mLeft, rect.mTop, rect.mRight, mTabContainer->getRect().mBottom); - mLandmarkInfo->reshape(new_rect.getWidth(), new_rect.getHeight()); } else { - LLLandmarksPanel* landmarks_panel = - dynamic_cast<LLLandmarksPanel*>(mTabContainer->getPanelByName("Landmarks")); + std::string tab_panel_name("Landmarks"); + if (mItem.notNull()) + { + if (gInventory.isObjectDescendentOf(mItem->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE))) + { + tab_panel_name = "Favorites"; + } + } + + LLLandmarksPanel* landmarks_panel = dynamic_cast<LLLandmarksPanel*>(mTabContainer->getPanelByName(tab_panel_name)); if (landmarks_panel) { // If a landmark info is being closed we open the landmarks tab @@ -1050,6 +1121,10 @@ void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible) { landmarks_panel->setItemSelected(mItem->getUUID(), TRUE); } + else + { + landmarks_panel->resetSelection(); + } } } } @@ -1117,11 +1192,19 @@ void LLPanelPlaces::createTabs() if (!(gInventory.isInventoryUsable() && LLTeleportHistory::getInstance() && !mTabsCreated)) return; + LLFavoritesPanel* favorites_panel = new LLFavoritesPanel(); + if (favorites_panel) + { + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(favorites_panel). + label(getString("favorites_tab_title")). + insert_at(LLTabContainer::END)); + } + LLLandmarksPanel* landmarks_panel = new LLLandmarksPanel(); if (landmarks_panel) { - landmarks_panel->setPanelPlacesButtons(this); - mTabContainer->addTabPanel( LLTabContainer::TabPanelParams(). panel(landmarks_panel). @@ -1132,8 +1215,6 @@ void LLPanelPlaces::createTabs() LLTeleportHistoryPanel* teleport_history_panel = new LLTeleportHistoryPanel(); if (teleport_history_panel) { - teleport_history_panel->setPanelPlacesButtons(this); - mTabContainer->addTabPanel( LLTabContainer::TabPanelParams(). panel(teleport_history_panel). @@ -1145,9 +1226,31 @@ void LLPanelPlaces::createTabs() mActivePanel = dynamic_cast<LLPanelPlacesTab*>(mTabContainer->getCurrentPanel()); - // Filter applied to show all items. - if (mActivePanel) - mActivePanel->onSearchEdit(mActivePanel->getFilterSubString()); + if (mActivePanel) + { + // Filter applied to show all items. + mActivePanel->onSearchEdit(mActivePanel->getFilterSubString()); + + // History panel does not support deletion nor creation + // Hide menus + bool supports_create = mActivePanel->getCreateMenu() != NULL; + childSetVisible("add_btn_panel", supports_create); + + // favorites and inventory can remove items, history can clear history + childSetVisible("trash_btn_panel", TRUE); + + if (supports_create) + { + mRemoveSelectedBtn->setToolTip(getString("tooltip_trash_items")); + } + else + { + mRemoveSelectedBtn->setToolTip(getString("tooltip_trash_history")); + } + + mActivePanel->setRemoveBtn(mRemoveSelectedBtn); + mActivePanel->updateVerbs(); + } mTabsCreated = true; } @@ -1210,14 +1313,14 @@ void LLPanelPlaces::updateVerbs() mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible); mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible); - mOverflowBtn->setVisible(is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn); - mEditBtn->setVisible(mPlaceInfoType == LANDMARK_INFO_TYPE && !isLandmarkEditModeOn); mSaveBtn->setVisible(isLandmarkEditModeOn); mCancelBtn->setVisible(isLandmarkEditModeOn); mCloseBtn->setVisible(is_create_landmark_visible && !isLandmarkEditModeOn); - mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible); - mPlaceInfoBtn->setEnabled(!is_create_landmark_visible && !isLandmarkEditModeOn && have_3d_pos); + bool show_options_btn = is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn; + mOverflowBtn->setVisible(show_options_btn); + getChild<LLLayoutPanel>("lp_options")->setVisible(show_options_btn); + getChild<LLLayoutPanel>("lp2")->setVisible(!show_options_btn); if (is_place_info_visible) { diff --git a/indra/newview/llpanelplaces.h b/indra/newview/llpanelplaces.h index 27f991c202..3b87eb6cb9 100644 --- a/indra/newview/llpanelplaces.h +++ b/indra/newview/llpanelplaces.h @@ -48,6 +48,7 @@ class LLRemoteParcelInfoObserver; class LLTabContainer; class LLToggleableMenu; class LLMenuButton; +class LLLayoutStack; typedef std::pair<LLUUID, std::string> folder_pair_t; @@ -96,7 +97,12 @@ private: bool onOverflowMenuItemEnable(const LLSD& param); void onCreateLandmarkButtonClicked(const LLUUID& folder_id); void onBackButtonClicked(); - void onProfileButtonClicked(); + void onGearMenuClick(); + void onSortingMenuClick(); + void onAddMenuClick(); + void onRemoveButtonClicked(); + bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept); + void toggleMediaPanel(); void togglePickPanel(BOOL visible); @@ -111,6 +117,8 @@ private: LLFilterEditor* mFilterEditor; LLPanelPlacesTab* mActivePanel; LLTabContainer* mTabContainer; + LLPanel* mButtonsContainer; + LLLayoutStack* mFilterContainer; LLPanelPlaceProfile* mPlaceProfile; LLPanelLandmarkInfo* mLandmarkInfo; @@ -121,12 +129,16 @@ private: LLButton* mPlaceProfileBackBtn; LLButton* mTeleportBtn; LLButton* mShowOnMapBtn; - LLButton* mEditBtn; LLButton* mSaveBtn; LLButton* mCancelBtn; LLButton* mCloseBtn; LLMenuButton* mOverflowBtn; - LLButton* mPlaceInfoBtn; + + // Top menu + LLMenuButton* mGearMenuButton; + LLMenuButton* mSortingMenuButton; + LLMenuButton* mAddMenuButton; + LLButton* mRemoveSelectedBtn; LLPlacesInventoryObserver* mInventoryObserver; LLPlacesParcelObserver* mParcelObserver; diff --git a/indra/newview/llpanelplacestab.cpp b/indra/newview/llpanelplacestab.cpp index 9644b7518e..748a917147 100644 --- a/indra/newview/llpanelplacestab.cpp +++ b/indra/newview/llpanelplacestab.cpp @@ -38,6 +38,7 @@ #include "llworldmap.h" std::string LLPanelPlacesTab::sFilterSubString = LLStringUtil::null; +LLButton* LLPanelPlacesTab::sRemoveBtn = NULL; bool LLPanelPlacesTab::isTabVisible() { @@ -47,13 +48,6 @@ bool LLPanelPlacesTab::isTabVisible() return true; } -void LLPanelPlacesTab::setPanelPlacesButtons(LLPanelPlaces* panel) -{ - mTeleportBtn = panel->getChild<LLButton>("teleport_btn"); - mShowOnMapBtn = panel->getChild<LLButton>("map_btn"); - mShowProfile = panel->getChild<LLButton>("profile_btn"); -} - void LLPanelPlacesTab::onRegionResponse(const LLVector3d& landmark_global_pos, U64 region_handle, const std::string& url, diff --git a/indra/newview/llpanelplacestab.h b/indra/newview/llpanelplacestab.h index 367ce46e2e..aab1c130c1 100644 --- a/indra/newview/llpanelplacestab.h +++ b/indra/newview/llpanelplacestab.h @@ -30,6 +30,7 @@ #include "llpanel.h" class LLPanelPlaces; +class LLToggleableMenu; class LLPanelPlacesTab : public LLPanel { @@ -42,11 +43,21 @@ public: virtual void onShowOnMap() = 0; virtual void onShowProfile() = 0; virtual void onTeleport() = 0; + virtual void onRemoveSelected() = 0; virtual bool isSingleItemSelected() = 0; + // returns menu for current selection + virtual LLToggleableMenu* getSelectionMenu() = 0; + virtual LLToggleableMenu* getSortingMenu() = 0; + virtual LLToggleableMenu* getCreateMenu() = 0; + + /** + * Processes drag-n-drop of the Landmarks and folders into trash button. + */ + virtual bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept) = 0; + bool isTabVisible(); // Check if parent TabContainer is visible. - void setPanelPlacesButtons(LLPanelPlaces* panel); void onRegionResponse(const LLVector3d& landmark_global_pos, U64 region_handle, const std::string& url, @@ -56,13 +67,12 @@ public: const std::string& getFilterSubString() { return sFilterSubString; } void setFilterSubString(const std::string& string) { sFilterSubString = string; } -protected: - LLButton* mTeleportBtn; - LLButton* mShowOnMapBtn; - LLButton* mShowProfile; + void setRemoveBtn(LLButton* trash_btn) { sRemoveBtn = trash_btn; } +protected: // Search string for filtering landmarks and teleport history locations static std::string sFilterSubString; + static LLButton* sRemoveBtn; }; #endif //LL_LLPANELPLACESTAB_H diff --git a/indra/newview/llpanelpresetscamerapulldown.cpp b/indra/newview/llpanelpresetscamerapulldown.cpp new file mode 100644 index 0000000000..183123e534 --- /dev/null +++ b/indra/newview/llpanelpresetscamerapulldown.cpp @@ -0,0 +1,149 @@ +/** + * @file llpanelpresetscamerapulldown.cpp + * @brief A panel showing a quick way to pick camera presets + * + * $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 "llpanelpresetscamerapulldown.h" + +#include "llviewercontrol.h" +#include "llstatusbar.h" + +#include "llbutton.h" +#include "lltabcontainer.h" +#include "llfloatercamera.h" +#include "llfloaterreg.h" +#include "llfloaterpreference.h" +#include "llpresetsmanager.h" +#include "llsliderctrl.h" +#include "llscrolllistctrl.h" +#include "lltrans.h" + +///---------------------------------------------------------------------------- +/// Class LLPanelPresetsCameraPulldown +///---------------------------------------------------------------------------- + +// Default constructor +LLPanelPresetsCameraPulldown::LLPanelPresetsCameraPulldown() +{ + mCommitCallbackRegistrar.add("Presets.toggleCameraFloater", boost::bind(&LLPanelPresetsCameraPulldown::onViewButtonClick, this, _2)); + mCommitCallbackRegistrar.add("PresetsCamera.RowClick", boost::bind(&LLPanelPresetsCameraPulldown::onRowClick, this, _2)); + + buildFromFile( "panel_presets_camera_pulldown.xml"); +} + +BOOL LLPanelPresetsCameraPulldown::postBuild() +{ + LLPresetsManager* presetsMgr = LLPresetsManager::getInstance(); + if (presetsMgr) + { + // Make sure there is a default preference file + presetsMgr->createMissingDefault(PRESETS_CAMERA); + + presetsMgr->startWatching(PRESETS_CAMERA); + + presetsMgr->setPresetListChangeCameraCallback(boost::bind(&LLPanelPresetsCameraPulldown::populatePanel, this)); + } + + populatePanel(); + + return LLPanelPulldown::postBuild(); +} + +void LLPanelPresetsCameraPulldown::populatePanel() +{ + LLPresetsManager::getInstance()->loadPresetNamesFromDir(PRESETS_CAMERA, mPresetNames, DEFAULT_BOTTOM); + + LLScrollListCtrl* scroll = getChild<LLScrollListCtrl>("preset_camera_list"); + + if (scroll && mPresetNames.begin() != mPresetNames.end()) + { + scroll->clearRows(); + + std::string active_preset = gSavedSettings.getString("PresetCameraActive"); + if (active_preset == PRESETS_DEFAULT) + { + active_preset = LLTrans::getString(PRESETS_DEFAULT); + } + + for (std::list<std::string>::const_iterator it = mPresetNames.begin(); it != mPresetNames.end(); ++it) + { + const std::string& name = *it; + LL_DEBUGS() << "adding '" << name << "'" << LL_ENDL; + + LLSD row; + row["columns"][0]["column"] = "preset_name"; + row["columns"][0]["value"] = name; + + bool is_selected_preset = false; + if (name == active_preset) + { + row["columns"][1]["column"] = "icon"; + row["columns"][1]["type"] = "icon"; + row["columns"][1]["value"] = "Check_Mark"; + + is_selected_preset = true; + } + + LLScrollListItem* new_item = scroll->addElement(row); + new_item->setSelected(is_selected_preset); + } + } +} + +void LLPanelPresetsCameraPulldown::onRowClick(const LLSD& user_data) +{ + LLScrollListCtrl* scroll = getChild<LLScrollListCtrl>("preset_camera_list"); + + if (scroll) + { + LLScrollListItem* item = scroll->getFirstSelected(); + if (item) + { + std::string name = item->getColumn(1)->getValue().asString(); + + LL_DEBUGS() << "selected '" << name << "'" << LL_ENDL; + LLFloaterCamera::switchToPreset(name); + + setVisible(FALSE); + } + else + { + LL_DEBUGS() << "none selected" << LL_ENDL; + } + } + else + { + LL_DEBUGS() << "no scroll" << LL_ENDL; + } +} + +void LLPanelPresetsCameraPulldown::onViewButtonClick(const LLSD& user_data) +{ + // close the minicontrol, we're bringing up the big one + setVisible(FALSE); + + LLFloaterReg::toggleInstanceOrBringToFront("camera"); +} diff --git a/indra/newview/llpanelpresetscamerapulldown.h b/indra/newview/llpanelpresetscamerapulldown.h new file mode 100644 index 0000000000..c49bab042e --- /dev/null +++ b/indra/newview/llpanelpresetscamerapulldown.h @@ -0,0 +1,49 @@ +/** + * @file llpanelpresetscamerapulldown.h + * @brief A panel showing a quick way to pick camera presets + * + * $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_LLPANELPRESETSCAMERAPULLDOWN_H +#define LL_LLPANELPRESETSCAMERAPULLDOWN_H + +#include "linden_common.h" + +#include "llpanelpulldown.h" + +class LLPanelPresetsCameraPulldown : public LLPanelPulldown +{ + public: + LLPanelPresetsCameraPulldown(); + /*virtual*/ BOOL postBuild(); + void populatePanel(); + + private: + void onViewButtonClick(const LLSD& user_data); + void onRowClick(const LLSD& user_data); + + std::list<std::string> mPresetNames; + LOG_CLASS(LLPanelPresetsCameraPulldown); +}; + +#endif // LL_LLPANELPRESETSCAMERAPULLDOWN_H diff --git a/indra/newview/llpanelpresetspulldown.cpp b/indra/newview/llpanelpresetspulldown.cpp index 9b4dc5474a..d52ad8056f 100644 --- a/indra/newview/llpanelpresetspulldown.cpp +++ b/indra/newview/llpanelpresetspulldown.cpp @@ -33,16 +33,13 @@ #include "llbutton.h" #include "lltabcontainer.h" +#include "llfloater.h" #include "llfloaterreg.h" -#include "llfloaterpreference.h" #include "llpresetsmanager.h" #include "llsliderctrl.h" #include "llscrolllistctrl.h" #include "lltrans.h" -/* static */ const F32 LLPanelPresetsPulldown::sAutoCloseFadeStartTimeSec = 2.0f; -/* static */ const F32 LLPanelPresetsPulldown::sAutoCloseTotalTimeSec = 3.0f; - ///---------------------------------------------------------------------------- /// Class LLPanelPresetsPulldown ///---------------------------------------------------------------------------- @@ -63,17 +60,16 @@ BOOL LLPanelPresetsPulldown::postBuild() LLPresetsManager* presetsMgr = LLPresetsManager::getInstance(); presetsMgr->setPresetListChangeCallback(boost::bind(&LLPanelPresetsPulldown::populatePanel, this)); // Make sure there is a default preference file - presetsMgr->createMissingDefault(); + presetsMgr->createMissingDefault(PRESETS_GRAPHIC); populatePanel(); - return LLPanel::postBuild(); + return LLPanelPulldown::postBuild(); } void LLPanelPresetsPulldown::populatePanel() { - std::string presets_dir = LLPresetsManager::getInstance()->getPresetsDir(PRESETS_GRAPHIC); - LLPresetsManager::getInstance()->loadPresetNamesFromDir(presets_dir, mPresetNames, DEFAULT_TOP); + LLPresetsManager::getInstance()->loadPresetNamesFromDir(PRESETS_GRAPHIC, mPresetNames, DEFAULT_TOP); LLScrollListCtrl* scroll = getChild<LLScrollListCtrl>("preset_list"); @@ -112,61 +108,6 @@ void LLPanelPresetsPulldown::populatePanel() } } -/*virtual*/ -void LLPanelPresetsPulldown::onMouseEnter(S32 x, S32 y, MASK mask) -{ - mHoverTimer.stop(); - LLPanel::onMouseEnter(x,y,mask); -} - -/*virtual*/ -void LLPanelPresetsPulldown::onTopLost() -{ - setVisible(FALSE); -} - -/*virtual*/ -BOOL LLPanelPresetsPulldown::handleMouseDown(S32 x, S32 y, MASK mask) -{ - LLPanel::handleMouseDown(x,y,mask); - return TRUE; -} - -/*virtual*/ -BOOL LLPanelPresetsPulldown::handleRightMouseDown(S32 x, S32 y, MASK mask) -{ - LLPanel::handleRightMouseDown(x, y, mask); - return TRUE; -} - -/*virtual*/ -BOOL LLPanelPresetsPulldown::handleDoubleClick(S32 x, S32 y, MASK mask) -{ - LLPanel::handleDoubleClick(x, y, mask); - return TRUE; -} - -/*virtual*/ -void LLPanelPresetsPulldown::onMouseLeave(S32 x, S32 y, MASK mask) -{ - mHoverTimer.start(); - LLPanel::onMouseLeave(x,y,mask); -} - -/*virtual*/ -void LLPanelPresetsPulldown::onVisibilityChange ( BOOL new_visibility ) -{ - if (new_visibility) - { - mHoverTimer.start(); // timer will be stopped when mouse hovers over panel - } - else - { - mHoverTimer.stop(); - - } -} - void LLPanelPresetsPulldown::onRowClick(const LLSD& user_data) { LLScrollListCtrl* scroll = getChild<LLScrollListCtrl>("preset_list"); @@ -213,19 +154,3 @@ void LLPanelPresetsPulldown::onGraphicsButtonClick(const LLSD& user_data) } } } - -//virtual -void LLPanelPresetsPulldown::draw() -{ - F32 alpha = mHoverTimer.getStarted() - ? clamp_rescale(mHoverTimer.getElapsedTimeF32(), sAutoCloseFadeStartTimeSec, sAutoCloseTotalTimeSec, 1.f, 0.f) - : 1.0f; - LLViewDrawContext context(alpha); - - LLPanel::draw(); - - if (alpha == 0.f) - { - setVisible(FALSE); - } -} diff --git a/indra/newview/llpanelpresetspulldown.h b/indra/newview/llpanelpresetspulldown.h index 322bf5a58f..c0d32b9b21 100644 --- a/indra/newview/llpanelpresetspulldown.h +++ b/indra/newview/llpanelpresetspulldown.h @@ -29,22 +29,13 @@ #include "linden_common.h" -#include "llpanel.h" +#include "llpanelpulldown.h" -class LLFrameTimer; -class LLPanelPresetsPulldown : public LLPanel +class LLPanelPresetsPulldown : public LLPanelPulldown { public: LLPanelPresetsPulldown(); - /*virtual*/ void draw(); - /*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 handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - /*virtual*/ void onTopLost(); - /*virtual*/ void onVisibilityChange ( BOOL new_visibility ); /*virtual*/ BOOL postBuild(); void populatePanel(); @@ -53,9 +44,6 @@ class LLPanelPresetsPulldown : public LLPanel void onRowClick(const LLSD& user_data); std::list<std::string> mPresetNames; - LLFrameTimer mHoverTimer; - static const F32 sAutoCloseFadeStartTimeSec; - static const F32 sAutoCloseTotalTimeSec; LOG_CLASS(LLPanelPresetsPulldown); }; diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp index 5f413fc3c0..c42cd6c6ba 100644 --- a/indra/newview/llpanelprimmediacontrols.cpp +++ b/indra/newview/llpanelprimmediacontrols.cpp @@ -64,8 +64,8 @@ #include "llvector4a.h" // Functions pulled from pipeline.cpp -glh::matrix4f glh_get_current_modelview(); -glh::matrix4f glh_get_current_projection(); +glh::matrix4f get_current_modelview(); +glh::matrix4f get_current_projection(); // Functions pulled from llviewerdisplay.cpp bool get_hud_matrices(glh::matrix4f &proj, glh::matrix4f &model); @@ -73,6 +73,9 @@ bool get_hud_matrices(glh::matrix4f &proj, glh::matrix4f &model); const LLPanelPrimMediaControls::EZoomLevel LLPanelPrimMediaControls::kZoomLevels[] = { ZOOM_NONE, ZOOM_MEDIUM }; const int LLPanelPrimMediaControls::kNumZoomLevels = 2; +const F32 EXCEEDING_ZOOM_DISTANCE = 0.5f; +const S32 ADDR_LEFT_PAD = 3; + // // LLPanelPrimMediaControls // @@ -93,6 +96,7 @@ LLPanelPrimMediaControls::LLPanelPrimMediaControls() : mZoomObjectID(LLUUID::null), mZoomObjectFace(0), mVolumeSliderVisible(0), + mZoomedCameraPos(), mWindowShade(NULL), mHideImmediately(false), mSecureURL(false), @@ -154,7 +158,7 @@ BOOL LLPanelPrimMediaControls::postBuild() mMediaProgressPanel = getChild<LLPanel>("media_progress_indicator"); mMediaProgressBar = getChild<LLProgressBar>("media_progress_bar"); mMediaAddressCtrl = getChild<LLUICtrl>("media_address"); - mMediaAddress = getChild<LLUICtrl>("media_address_url"); + mMediaAddress = getChild<LLLineEditor>("media_address_url"); mMediaPlaySliderPanel = getChild<LLUICtrl>("media_play_position"); mMediaPlaySliderCtrl = getChild<LLUICtrl>("media_play_slider"); mSkipFwdCtrl = getChild<LLUICtrl>("skip_forward"); @@ -256,7 +260,7 @@ void LLPanelPrimMediaControls::focusOnTarget() LLViewerMediaImpl* media_impl = getTargetMediaImpl(); if(media_impl) { - if(!media_impl->hasFocus()) + if (!media_impl->hasFocus()) { // The current target doesn't have media focus -- focus on it. LLViewerObject* objectp = getTargetObject(); @@ -267,7 +271,7 @@ void LLPanelPrimMediaControls::focusOnTarget() LLViewerMediaImpl* LLPanelPrimMediaControls::getTargetMediaImpl() { - return LLViewerMedia::getMediaImplFromTextureID(mTargetImplID); + return LLViewerMedia::getInstance()->getMediaImplFromTextureID(mTargetImplID); } LLViewerObject* LLPanelPrimMediaControls::getTargetObject() @@ -307,7 +311,8 @@ void LLPanelPrimMediaControls::updateShape() bool can_navigate = parcel->getMediaAllowNavigate(); bool enabled = false; - bool is_zoomed = (mCurrentZoom != ZOOM_NONE) && (mTargetObjectID == mZoomObjectID) && (mTargetObjectFace == mZoomObjectFace); + bool is_zoomed = (mCurrentZoom != ZOOM_NONE) && (mTargetObjectID == mZoomObjectID) && (mTargetObjectFace == mZoomObjectFace) && !isZoomDistExceeding(); + // There is no such thing as "has_focus" being different from normal controls set // anymore (as of user feedback from bri 10/09). So we cheat here and force 'has_focus' // to 'true' (or, actually, we use a setting) @@ -498,8 +503,10 @@ void LLPanelPrimMediaControls::updateShape() std::string test_prefix = mCurrentURL.substr(0, prefix.length()); LLStringUtil::toLower(test_prefix); mSecureURL = has_focus && (test_prefix == prefix); - mCurrentURL = (mSecureURL ? " " + mCurrentURL : mCurrentURL); - + + S32 left_pad = mSecureURL ? mSecureLockIcon->getRect().getWidth() : ADDR_LEFT_PAD; + mMediaAddress->setTextPadding(left_pad, 0); + if(mCurrentURL!=mPreviousURL) { setCurrentURL(); @@ -547,17 +554,17 @@ 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: @@ -642,7 +649,7 @@ void LLPanelPrimMediaControls::updateShape() glh::matrix4f mat; if (!is_hud) { - mat = glh_get_current_projection() * glh_get_current_modelview(); + mat = get_current_projection() * get_current_modelview(); } else { glh::matrix4f proj, modelview; @@ -829,8 +836,32 @@ void LLPanelPrimMediaControls::draw() BOOL LLPanelPrimMediaControls::handleScrollWheel(S32 x, S32 y, S32 clicks) { - mInactivityTimer.start(); - return LLViewerMediaFocus::getInstance()->handleScrollWheel(x, y, clicks); + mInactivityTimer.start(); + BOOL res = FALSE; + + // Unlike other mouse events, we need to handle scroll here otherwise + // it will be intercepted by camera and won't reach toolpie + if (LLViewerMediaFocus::getInstance()->isHoveringOverFocused()) + { + // either let toolpie handle this or expose mHoverPick.mUVCoords in some way + res = LLToolPie::getInstance()->handleScrollWheel(x, y, clicks); + } + + return res; +} + +BOOL LLPanelPrimMediaControls::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + mInactivityTimer.start(); + BOOL res = FALSE; + + if (LLViewerMediaFocus::getInstance()->isHoveringOverFocused()) + { + // either let toolpie handle this or expose mHoverPick.mUVCoords in some way + res = LLToolPie::getInstance()->handleScrollHWheel(x, y, clicks); + } + + return res; } BOOL LLPanelPrimMediaControls::handleMouseDown(S32 x, S32 y, MASK mask) @@ -1117,7 +1148,7 @@ void LLPanelPrimMediaControls::updateZoom() if (zoom_padding > 0.0f) { // since we only zoom into medium for now, always set zoom_in constraint to true - LLViewerMediaFocus::setCameraZoom(getTargetObject(), mTargetObjectNormal, zoom_padding, true); + mZoomedCameraPos = LLViewerMediaFocus::setCameraZoom(getTargetObject(), mTargetObjectNormal, zoom_padding, true); } // Remember the object ID/face we zoomed into, so we can update the zoom icon appropriately @@ -1134,7 +1165,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) @@ -1151,7 +1182,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); } } @@ -1170,7 +1201,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); } } @@ -1189,7 +1220,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) @@ -1377,6 +1408,10 @@ bool LLPanelPrimMediaControls::shouldVolumeSliderBeVisible() return mVolumeSliderVisible > 0; } +bool LLPanelPrimMediaControls::isZoomDistExceeding() +{ + return (gAgentCamera.getCameraPositionGlobal() - mZoomedCameraPos).normalize() >= EXCEEDING_ZOOM_DISTANCE; +} void LLPanelPrimMediaControls::clearFaceOnFade() { diff --git a/indra/newview/llpanelprimmediacontrols.h b/indra/newview/llpanelprimmediacontrols.h index 21d5236074..dd0e4ff095 100644 --- a/indra/newview/llpanelprimmediacontrols.h +++ b/indra/newview/llpanelprimmediacontrols.h @@ -39,6 +39,7 @@ class LLProgressBar; class LLSliderCtrl; class LLViewerMediaImpl; class LLWindowShade; +class LLLineEditor; class LLPanelPrimMediaControls : public LLPanel { @@ -48,6 +49,7 @@ public: /*virtual*/ BOOL postBuild(); virtual void draw(); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + virtual BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); @@ -118,6 +120,8 @@ private: void showVolumeSlider(); void hideVolumeSlider(); bool shouldVolumeSliderBeVisible(); + + bool isZoomDistExceeding(); static void onScrollUp(void* user_data); static void onScrollUpHeld(void* user_data); @@ -161,7 +165,7 @@ private: LLPanel *mMediaProgressPanel; LLProgressBar *mMediaProgressBar; LLUICtrl *mMediaAddressCtrl; - LLUICtrl *mMediaAddress; + LLLineEditor *mMediaAddress; LLUICtrl *mMediaPlaySliderPanel; LLUICtrl *mMediaPlaySliderCtrl; LLUICtrl *mVolumeCtrl; @@ -182,6 +186,8 @@ private: F32 mZoomMediumPadding; F32 mZoomFarPadding; S32 mTopWorldViewAvoidZone; + + LLVector3d mZoomedCameraPos; LLUICtrl *mMediaPanelScroll; LLButton *mScrollUpCtrl; diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 8afa35efa0..5f13b223fb 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -110,7 +110,7 @@ public: if (verb == "pay") { - if (!LLUI::sSettingGroups["config"]->getBOOL("EnableAvatarPay")) + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableAvatarPay")) { LLNotificationsUtil::add("NoAvatarPay", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); return true; diff --git a/indra/newview/llpanelpulldown.cpp b/indra/newview/llpanelpulldown.cpp new file mode 100644 index 0000000000..4de6ee8182 --- /dev/null +++ b/indra/newview/llpanelpulldown.cpp @@ -0,0 +1,118 @@ +/** +* @file llpanelpulldown.cpp +* @brief A panel that serves as a basis for multiple toolbar pulldown panels +* +* $LicenseInfo:firstyear=2020&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2020, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* 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 "llpanelpulldown.h" + +const F32 AUTO_CLOSE_FADE_TIME_START_SEC = 2.0f; +const F32 AUTO_CLOSE_FADE_TIME_END_SEC = 3.0f; + +///---------------------------------------------------------------------------- +/// Class LLPanelPresetsCameraPulldown +///---------------------------------------------------------------------------- + +// Default constructor +LLPanelPulldown::LLPanelPulldown() +{ + mHoverTimer.stop(); +} + +/*virtual*/ +void LLPanelPulldown::onMouseEnter(S32 x, S32 y, MASK mask) +{ + mHoverTimer.stop(); + LLPanel::onMouseEnter(x, y, mask); +} + +/*virtual*/ +void LLPanelPulldown::onTopLost() +{ + setVisible(FALSE); +} + +/*virtual*/ +BOOL LLPanelPulldown::handleMouseDown(S32 x, S32 y, MASK mask) +{ + LLPanel::handleMouseDown(x, y, mask); + return TRUE; +} + +/*virtual*/ +BOOL LLPanelPulldown::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + LLPanel::handleRightMouseDown(x, y, mask); + return TRUE; +} + +/*virtual*/ +BOOL LLPanelPulldown::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + LLPanel::handleDoubleClick(x, y, mask); + return TRUE; +} + +BOOL LLPanelPulldown::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + LLPanel::handleScrollWheel(x, y, clicks); + return TRUE; //If we got here, then we are in Pulldown's rect, consume the event. +} + +/*virtual*/ +void LLPanelPulldown::onMouseLeave(S32 x, S32 y, MASK mask) +{ + mHoverTimer.start(); + LLPanel::onMouseLeave(x, y, mask); +} + +/*virtual*/ +void LLPanelPulldown::onVisibilityChange(BOOL new_visibility) +{ + if (new_visibility) + { + mHoverTimer.start(); // timer will be stopped when mouse hovers over panel + } + else + { + mHoverTimer.stop(); + } +} + +//virtual +void LLPanelPulldown::draw() +{ + F32 alpha = mHoverTimer.getStarted() + ? clamp_rescale(mHoverTimer.getElapsedTimeF32(), AUTO_CLOSE_FADE_TIME_START_SEC, AUTO_CLOSE_FADE_TIME_END_SEC, 1.f, 0.f) + : 1.0f; + LLViewDrawContext context(alpha); + + LLPanel::draw(); + + if (alpha == 0.f) + { + setVisible(FALSE); + } +} diff --git a/indra/newview/llpanelpulldown.h b/indra/newview/llpanelpulldown.h new file mode 100644 index 0000000000..705e76d0ab --- /dev/null +++ b/indra/newview/llpanelpulldown.h @@ -0,0 +1,55 @@ +/** + * @file llpanelpulldown.h + * @brief A panel that serves as a basis for multiple toolbar pulldown panels + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2020, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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_LLPANELPULLDOWN_H +#define LL_LLPANELPULLDOWN_H + +#include "linden_common.h" + +#include "llpanel.h" + +class LLFrameTimer; + +class LLPanelPulldown : public LLPanel +{ +public: + LLPanelPulldown(); + /*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 handleRightMouseDown(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*/ void onTopLost(); + /*virtual*/ void onVisibilityChange(BOOL new_visibility); + + /*virtual*/ void draw(); + +protected: + LLFrameTimer mHoverTimer; +}; + +#endif // LL_LLPANELPULLDOWN_H diff --git a/indra/newview/llpanelsnapshot.cpp b/indra/newview/llpanelsnapshot.cpp index a17e3f9e78..c3524a8c87 100644 --- a/indra/newview/llpanelsnapshot.cpp +++ b/indra/newview/llpanelsnapshot.cpp @@ -39,6 +39,8 @@ #include "llsidetraypanelcontainer.h" #include "llviewercontrol.h" // gSavedSettings +#include "llagentbenefits.h" + const S32 MAX_TEXTURE_SIZE = 512 ; //max upload texture size 512 * 512 S32 power_of_two(S32 sz, S32 upper) @@ -59,6 +61,7 @@ LLPanelSnapshot::LLPanelSnapshot() // virtual BOOL LLPanelSnapshot::postBuild() { + getChild<LLUICtrl>("save_btn")->setLabelArg("[UPLOAD_COST]", std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost())); getChild<LLUICtrl>(getImageSizeComboName())->setCommitCallback(boost::bind(&LLPanelSnapshot::onResolutionComboCommit, this, _1)); if (!getWidthSpinnerName().empty()) { diff --git a/indra/newview/llpanelsnapshotinventory.cpp b/indra/newview/llpanelsnapshotinventory.cpp index 21ac7604ff..9e56a04b3b 100644 --- a/indra/newview/llpanelsnapshotinventory.cpp +++ b/indra/newview/llpanelsnapshotinventory.cpp @@ -27,7 +27,6 @@ #include "llviewerprecompiledheaders.h" #include "llcombobox.h" -#include "lleconomy.h" #include "llsidetraypanelcontainer.h" #include "llspinctrl.h" @@ -38,6 +37,8 @@ #include "llstatusbar.h" // can_afford_transaction() #include "llnotificationsutil.h" +#include "llagentbenefits.h" + /** * The panel provides UI for saving snapshot as an inventory texture. */ @@ -135,7 +136,6 @@ BOOL LLPanelSnapshotInventory::postBuild() // virtual void LLPanelSnapshotInventory::onOpen(const LLSD& key) { - getChild<LLUICtrl>("hint_lbl")->setTextArg("[UPLOAD_COST]", llformat("%d", LLGlobalEconomy::getInstance()->getPriceUpload())); LLPanelSnapshot::onOpen(key); } @@ -155,7 +155,7 @@ void LLPanelSnapshotInventory::onResolutionCommit(LLUICtrl* ctrl) void LLPanelSnapshotInventoryBase::onSend() { - S32 expected_upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload(); + S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); if (can_afford_transaction(expected_upload_cost)) { if (mSnapshotFloater) @@ -191,7 +191,7 @@ BOOL LLPanelOutfitSnapshotInventory::postBuild() // virtual void LLPanelOutfitSnapshotInventory::onOpen(const LLSD& key) { - getChild<LLUICtrl>("hint_lbl")->setTextArg("[UPLOAD_COST]", llformat("%d", LLGlobalEconomy::getInstance()->getPriceUpload())); + getChild<LLUICtrl>("hint_lbl")->setTextArg("[UPLOAD_COST]", llformat("%d", LLAgentBenefitsMgr::current().getTextureUploadCost())); LLPanelSnapshot::onOpen(key); } diff --git a/indra/newview/llpanelsnapshotoptions.cpp b/indra/newview/llpanelsnapshotoptions.cpp index 23747a8efd..8cc2fbc770 100644 --- a/indra/newview/llpanelsnapshotoptions.cpp +++ b/indra/newview/llpanelsnapshotoptions.cpp @@ -26,21 +26,20 @@ #include "llviewerprecompiledheaders.h" -#include "lleconomy.h" #include "llpanel.h" #include "llsidetraypanelcontainer.h" #include "llfloatersnapshot.h" // FIXME: create a snapshot model #include "llfloaterreg.h" -#include "llfloaterflickr.h" -#include "llfloatertwitter.h" + +#include "llagentbenefits.h" + /** * Provides several ways to save a snapshot. */ class LLPanelSnapshotOptions : public LLPanel -, public LLEconomyObserver { LOG_CLASS(LLPanelSnapshotOptions); @@ -49,7 +48,6 @@ public: ~LLPanelSnapshotOptions(); /*virtual*/ BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); - /*virtual*/ void onEconomyDataChange() { updateUploadCost(); } private: void updateUploadCost(); @@ -58,8 +56,6 @@ private: void onSaveToEmail(); void onSaveToInventory(); void onSaveToComputer(); - void onSendToTwitter(); - void onSendToFlickr(); LLFloaterSnapshotBase* mSnapshotFloater; }; @@ -72,14 +68,10 @@ LLPanelSnapshotOptions::LLPanelSnapshotOptions() mCommitCallbackRegistrar.add("Snapshot.SaveToEmail", boost::bind(&LLPanelSnapshotOptions::onSaveToEmail, this)); mCommitCallbackRegistrar.add("Snapshot.SaveToInventory", boost::bind(&LLPanelSnapshotOptions::onSaveToInventory, this)); mCommitCallbackRegistrar.add("Snapshot.SaveToComputer", boost::bind(&LLPanelSnapshotOptions::onSaveToComputer, this)); - mCommitCallbackRegistrar.add("Snapshot.SendToTwitter", boost::bind(&LLPanelSnapshotOptions::onSendToTwitter, this)); - mCommitCallbackRegistrar.add("Snapshot.SendToFlickr", boost::bind(&LLPanelSnapshotOptions::onSendToFlickr, this)); - LLGlobalEconomy::getInstance()->addObserver(this); } LLPanelSnapshotOptions::~LLPanelSnapshotOptions() { - LLGlobalEconomy::getInstance()->removeObserver(this); } // virtual @@ -97,7 +89,7 @@ void LLPanelSnapshotOptions::onOpen(const LLSD& key) void LLPanelSnapshotOptions::updateUploadCost() { - S32 upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload(); + S32 upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); getChild<LLUICtrl>("save_to_inventory_btn")->setLabelArg("[AMOUNT]", llformat("%d", upload_cost)); } @@ -135,26 +127,3 @@ void LLPanelSnapshotOptions::onSaveToComputer() openPanel("panel_snapshot_local"); } -void LLPanelSnapshotOptions::onSendToTwitter() -{ - LLFloaterReg::hideInstance("snapshot"); - - LLFloaterTwitter* twitter_floater = dynamic_cast<LLFloaterTwitter*>(LLFloaterReg::getInstance("twitter")); - if (twitter_floater) - { - twitter_floater->showPhotoPanel(); - } - LLFloaterReg::showInstance("twitter"); -} - -void LLPanelSnapshotOptions::onSendToFlickr() -{ - LLFloaterReg::hideInstance("snapshot"); - - LLFloaterFlickr* flickr_floater = dynamic_cast<LLFloaterFlickr*>(LLFloaterReg::getInstance("flickr")); - if (flickr_floater) - { - flickr_floater->showPhotoPanel(); - } - LLFloaterReg::showInstance("flickr"); -} diff --git a/indra/newview/llpanelsnapshotpostcard.cpp b/indra/newview/llpanelsnapshotpostcard.cpp index f3a4cf36ee..b8aa976657 100644 --- a/indra/newview/llpanelsnapshotpostcard.cpp +++ b/indra/newview/llpanelsnapshotpostcard.cpp @@ -170,14 +170,16 @@ void LLPanelSnapshotPostcard::sendPostcard() std::string url = gAgent.getRegion()->getCapability("SendPostcard"); if (!url.empty()) { - LLResourceUploadInfo::ptr_t uploadInfo(new LLPostcardUploadInfo( + LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLPostcardUploadInfo>( getChild<LLUICtrl>("name_form")->getValue().asString(), getChild<LLUICtrl>("to_form")->getValue().asString(), getChild<LLUICtrl>("subject_form")->getValue().asString(), getChild<LLUICtrl>("msg_form")->getValue().asString(), mSnapshotFloater->getPosTakenGlobal(), mSnapshotFloater->getImageData(), - boost::bind(&LLPanelSnapshotPostcard::sendPostcardFinished, _4))); + [](LLUUID, LLUUID, LLUUID, LLSD response) { + LLPanelSnapshotPostcard::sendPostcardFinished(response); + })); LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); } diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index fe0608d544..b938b30479 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -56,7 +56,7 @@ static const std::string COLLAPSED_BY_USER = "collapsed_by_user"; class LLTeleportHistoryFlatItem : public LLPanel { public: - LLTeleportHistoryFlatItem(S32 index, LLTeleportHistoryPanel::ContextMenu *context_menu, const std::string ®ion_name, + LLTeleportHistoryFlatItem(S32 index, LLToggleableMenu *menu, const std::string ®ion_name, LLDate date, const std::string &hl); virtual ~LLTeleportHistoryFlatItem(); @@ -86,12 +86,13 @@ public: private: void onProfileBtnClick(); + void showMenu(S32 x, S32 y); LLButton* mProfileBtn; LLTextBox* mTitle; LLTextBox* mTimeTextBox; - LLTeleportHistoryPanel::ContextMenu *mContextMenu; + LLToggleableMenu *mMenu; S32 mIndex; std::string mRegionName; @@ -112,7 +113,7 @@ protected: public: LLTeleportHistoryFlatItem* getFlatItemForPersistentItem ( - LLTeleportHistoryPanel::ContextMenu *context_menu, + LLToggleableMenu *menu, const LLTeleportHistoryPersistentItem& persistent_item, const S32 cur_item_index, const std::string &hl); @@ -130,16 +131,16 @@ private: //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -LLTeleportHistoryFlatItem::LLTeleportHistoryFlatItem(S32 index, LLTeleportHistoryPanel::ContextMenu *context_menu, const std::string ®ion_name, +LLTeleportHistoryFlatItem::LLTeleportHistoryFlatItem(S32 index, LLToggleableMenu *menu, const std::string ®ion_name, LLDate date, const std::string &hl) : LLPanel(), mIndex(index), - mContextMenu(context_menu), + mMenu(menu), mRegionName(region_name), mDate(date), mHighlight(hl) { - buildFromFile( "panel_teleport_history_item.xml"); + buildFromFile("panel_teleport_history_item.xml"); } LLTeleportHistoryFlatItem::~LLTeleportHistoryFlatItem() @@ -266,10 +267,9 @@ void LLTeleportHistoryFlatItem::onMouseLeave(S32 x, S32 y, MASK mask) // virtual BOOL LLTeleportHistoryFlatItem::handleRightMouseDown(S32 x, S32 y, MASK mask) { - if (mContextMenu) - mContextMenu->show(this, mIndex, x, y); - - return LLPanel::handleRightMouseDown(x, y, mask); + LLPanel::handleRightMouseDown(x, y, mask); + showMenu(x, y); + return TRUE; } void LLTeleportHistoryFlatItem::showPlaceInfoPanel(S32 index) @@ -286,13 +286,23 @@ void LLTeleportHistoryFlatItem::onProfileBtnClick() LLTeleportHistoryFlatItem::showPlaceInfoPanel(mIndex); } +void LLTeleportHistoryFlatItem::showMenu(S32 x, S32 y) +{ + mMenu->setButtonRect(this); + mMenu->buildDrawLabels(); + mMenu->arrangeAndClear(); + mMenu->updateParent(LLMenuGL::sMenuContainer); + + LLMenuGL::showPopup(this, mMenu, x, y); +} + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// LLTeleportHistoryFlatItem* LLTeleportHistoryFlatItemStorage::getFlatItemForPersistentItem ( - LLTeleportHistoryPanel::ContextMenu *context_menu, + LLToggleableMenu *menu, const LLTeleportHistoryPersistentItem& persistent_item, const S32 cur_item_index, const std::string &hl) @@ -321,7 +331,7 @@ LLTeleportHistoryFlatItemStorage::getFlatItemForPersistentItem ( if ( !item ) { item = new LLTeleportHistoryFlatItem(cur_item_index, - context_menu, + menu, persistent_item.mTitle, persistent_item.mDate, hl); @@ -365,74 +375,6 @@ void LLTeleportHistoryFlatItemStorage::purge() //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -LLTeleportHistoryPanel::ContextMenu::ContextMenu() : - mMenu(NULL), mIndex(0) -{ -} - -void LLTeleportHistoryPanel::ContextMenu::show(LLView* spawning_view, S32 index, S32 x, S32 y) -{ - if (mMenu) - { - //preventing parent (menu holder) from deleting already "dead" context menus on exit - LLView* parent = mMenu->getParent(); - if (parent) - { - parent->removeChild(mMenu); - } - delete mMenu; - } - - mIndex = index; - mMenu = createMenu(); - - mMenu->show(x, y); - LLMenuGL::showPopup(spawning_view, mMenu, x, y); -} - -LLContextMenu* LLTeleportHistoryPanel::ContextMenu::createMenu() -{ - // set up the callbacks for all of the avatar menu items - // (N.B. callbacks don't take const refs as mID is local scope) - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; - - registrar.add("TeleportHistory.Teleport", boost::bind(&LLTeleportHistoryPanel::ContextMenu::onTeleport, this)); - registrar.add("TeleportHistory.MoreInformation",boost::bind(&LLTeleportHistoryPanel::ContextMenu::onInfo, this)); - registrar.add("TeleportHistory.CopyToClipboard",boost::bind(&LLTeleportHistoryPanel::ContextMenu::onCopyToClipboard, this)); - - // create the context menu from the XUI - llassert(LLMenuGL::sMenuContainer != NULL); - return LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( - "menu_teleport_history_item.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance()); -} - -void LLTeleportHistoryPanel::ContextMenu::onTeleport() -{ - confirmTeleport(mIndex); -} - -void LLTeleportHistoryPanel::ContextMenu::onInfo() -{ - LLTeleportHistoryFlatItem::showPlaceInfoPanel(mIndex); -} - -//static -void LLTeleportHistoryPanel::ContextMenu::gotSLURLCallback(const std::string& slurl) -{ - LLClipboard::instance().copyToClipboard(utf8str_to_wstring(slurl),0,slurl.size()); - - LLSD args; - args["SLURL"] = slurl; - - LLNotificationsUtil::add("CopySLURL", args); -} - -void LLTeleportHistoryPanel::ContextMenu::onCopyToClipboard() -{ - LLVector3d globalPos = LLTeleportHistoryStorage::getInstance()->getItems()[mIndex].mGlobalPos; - LLLandmarkActions::getSLURLfromPosGlobal(globalPos, - boost::bind(&LLTeleportHistoryPanel::ContextMenu::gotSLURLCallback, _1)); -} // Not yet implemented; need to remove buildPanel() from constructor when we switch //static LLRegisterPanelClassWrapper<LLTeleportHistoryPanel> t_teleport_history("panel_teleport_history"); @@ -446,7 +388,8 @@ LLTeleportHistoryPanel::LLTeleportHistoryPanel() mAccordionTabMenu(NULL), mLastSelectedFlatlList(NULL), mLastSelectedItemIndex(-1), - mMenuGearButton(NULL) + mGearItemMenu(NULL), + mSortingMenu(NULL) { buildFromFile( "panel_teleport_history.xml"); } @@ -454,12 +397,19 @@ LLTeleportHistoryPanel::LLTeleportHistoryPanel() LLTeleportHistoryPanel::~LLTeleportHistoryPanel() { LLTeleportHistoryFlatItemStorage::instance().purge(); - if (mGearMenuHandle.get()) mGearMenuHandle.get()->die(); mTeleportHistoryChangedConnection.disconnect(); } BOOL LLTeleportHistoryPanel::postBuild() { + mCommitCallbackRegistrar.add("TeleportHistory.GearMenu.Action", boost::bind(&LLTeleportHistoryPanel::onGearMenuAction, this, _2)); + mEnableCallbackRegistrar.add("TeleportHistory.GearMenu.Enable", boost::bind(&LLTeleportHistoryPanel::isActionEnabled, this, _2)); + + // init menus before list, since menus are passed to list + mGearItemMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_teleport_history_item.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mGearItemMenu->setAlwaysShowMenu(TRUE); // all items can be disabled if nothing is selected, show anyway + mSortingMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_teleport_history_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mTeleportHistory = LLTeleportHistoryStorage::getInstance(); if (mTeleportHistory) { @@ -511,22 +461,6 @@ BOOL LLTeleportHistoryPanel::postBuild() } } - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; - - registrar.add("TeleportHistory.ExpandAllFolders", boost::bind(&LLTeleportHistoryPanel::onExpandAllFolders, this)); - registrar.add("TeleportHistory.CollapseAllFolders", boost::bind(&LLTeleportHistoryPanel::onCollapseAllFolders, this)); - registrar.add("TeleportHistory.ClearTeleportHistory", boost::bind(&LLTeleportHistoryPanel::onClearTeleportHistory, this)); - mEnableCallbackRegistrar.add("TeleportHistory.GearMenu.Enable", boost::bind(&LLTeleportHistoryPanel::isActionEnabled, this, _2)); - - mMenuGearButton = getChild<LLMenuButton>("gear_btn"); - - LLToggleableMenu* gear_menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_teleport_history_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());; - if(gear_menu) - { - mGearMenuHandle = gear_menu->getHandle(); - mMenuGearButton->setMenu(gear_menu); - } - return TRUE; } @@ -600,6 +534,12 @@ void LLTeleportHistoryPanel::onTeleport() confirmTeleport(itemp->getIndex()); } +// virtual +void LLTeleportHistoryPanel::onRemoveSelected() +{ + LLNotificationsUtil::add("ConfirmClearTeleportHistory", LLSD(), LLSD(), boost::bind(&LLTeleportHistoryPanel::onClearTeleportHistoryDialog, this, _1, _2)); +} + /* // virtual void LLTeleportHistoryPanel::onCopySLURL() @@ -630,19 +570,28 @@ void LLTeleportHistoryPanel::updateVerbs() if (!isTabVisible()) return; - if (!mLastSelectedFlatlList) + if (sRemoveBtn) { - mTeleportBtn->setEnabled(false); - mShowProfile->setEnabled(false); - mShowOnMapBtn->setEnabled(false); - return; + sRemoveBtn->setEnabled(true); } +} - LLTeleportHistoryFlatItem* itemp = dynamic_cast<LLTeleportHistoryFlatItem *> (mLastSelectedFlatlList->getSelectedItem()); +// virtual +LLToggleableMenu* LLTeleportHistoryPanel::getSelectionMenu() +{ + return mGearItemMenu; +} + +// virtual +LLToggleableMenu* LLTeleportHistoryPanel::getSortingMenu() +{ + return mSortingMenu; +} - mTeleportBtn->setEnabled(NULL != itemp); - mShowProfile->setEnabled(NULL != itemp); - mShowOnMapBtn->setEnabled(NULL != itemp); +// virtual +LLToggleableMenu* LLTeleportHistoryPanel::getCreateMenu() +{ + return NULL; } void LLTeleportHistoryPanel::getNextTab(const LLDate& item_date, S32& tab_idx, LLDate& tab_date) @@ -778,7 +727,7 @@ void LLTeleportHistoryPanel::refresh() { LLTeleportHistoryFlatItem* item = LLTeleportHistoryFlatItemStorage::instance() - .getFlatItemForPersistentItem(&mContextMenu, + .getFlatItemForPersistentItem(mGearItemMenu, items[mCurrentItem], mCurrentItem, filter_string); @@ -847,7 +796,7 @@ void LLTeleportHistoryPanel::replaceItem(S32 removed_index) const LLTeleportHistoryStorage::slurl_list_t& history_items = mTeleportHistory->getItems(); LLTeleportHistoryFlatItem* item = LLTeleportHistoryFlatItemStorage::instance() - .getFlatItemForPersistentItem(&mContextMenu, + .getFlatItemForPersistentItem(mGearItemMenu, history_items[history_items.size() - 1], // Most recent item, it was added instead of removed history_items.size(), // index will be decremented inside loop below sFilterSubString); @@ -1019,38 +968,6 @@ void LLTeleportHistoryPanel::onAccordionTabClose(LLAccordionCtrlTab *tab) mHistoryAccordion->arrange(); } -void LLTeleportHistoryPanel::onExpandAllFolders() -{ - S32 tabs_cnt = mItemContainers.size(); - - for (S32 n = 0; n < tabs_cnt; n++) - { - mItemContainers.at(n)->setDisplayChildren(true); - } - mHistoryAccordion->arrange(); -} - -void LLTeleportHistoryPanel::onCollapseAllFolders() -{ - S32 tabs_cnt = mItemContainers.size(); - - for (S32 n = 0; n < tabs_cnt; n++) - { - mItemContainers.at(n)->setDisplayChildren(false); - } - mHistoryAccordion->arrange(); - - if (mLastSelectedFlatlList) - { - mLastSelectedFlatlList->resetSelection(); - } -} - -void LLTeleportHistoryPanel::onClearTeleportHistory() -{ - LLNotificationsUtil::add("ConfirmClearTeleportHistory", LLSD(), LLSD(), boost::bind(&LLTeleportHistoryPanel::onClearTeleportHistoryDialog, this, _1, _2)); -} - bool LLTeleportHistoryPanel::onClearTeleportHistoryDialog(const LLSD& notification, const LLSD& response) { @@ -1082,45 +999,137 @@ LLFlatListView* LLTeleportHistoryPanel::getFlatListViewFromTab(LLAccordionCtrlTa return NULL; } -bool LLTeleportHistoryPanel::isActionEnabled(const LLSD& userdata) const +void LLTeleportHistoryPanel::gotSLURLCallback(const std::string& slurl) { - S32 tabs_cnt = mItemContainers.size(); - - bool has_expanded_tabs = false; - bool has_collapsed_tabs = false; - - for (S32 n = 0; n < tabs_cnt; n++) - { - LLAccordionCtrlTab* tab = mItemContainers.at(n); - if (!tab->getVisible()) - continue; - - if (tab->getDisplayChildren()) - { - has_expanded_tabs = true; - } - else - { - has_collapsed_tabs = true; - } + LLClipboard::instance().copyToClipboard(utf8str_to_wstring(slurl), 0, slurl.size()); - if (has_expanded_tabs && has_collapsed_tabs) - { - break; - } - } + LLSD args; + args["SLURL"] = slurl; - std::string command_name = userdata.asString(); + LLNotificationsUtil::add("CopySLURL", args); +} - if (has_expanded_tabs && command_name == "collapse_all") - { - return true; - } +void LLTeleportHistoryPanel::onGearMenuAction(const LLSD& userdata) +{ + std::string command_name = userdata.asString(); + + if ("expand_all" == command_name) + { + S32 tabs_cnt = mItemContainers.size(); + + for (S32 n = 0; n < tabs_cnt; n++) + { + mItemContainers.at(n)->setDisplayChildren(true); + } + mHistoryAccordion->arrange(); + } + else if ("collapse_all" == command_name) + { + S32 tabs_cnt = mItemContainers.size(); + + for (S32 n = 0; n < tabs_cnt; n++) + { + mItemContainers.at(n)->setDisplayChildren(false); + } + mHistoryAccordion->arrange(); + + if (mLastSelectedFlatlList) + { + mLastSelectedFlatlList->resetSelection(); + } + } + + S32 index = -1; + if (mLastSelectedFlatlList) + { + LLTeleportHistoryFlatItem* itemp = dynamic_cast<LLTeleportHistoryFlatItem *> (mLastSelectedFlatlList->getSelectedItem()); + if (itemp) + { + index = itemp->getIndex(); + } + } + + if ("teleport" == command_name) + { + confirmTeleport(index); + } + else if ("view" == command_name) + { + LLTeleportHistoryFlatItem::showPlaceInfoPanel(index); + } + else if ("show_on_map" == command_name) + { + LLTeleportHistoryStorage::getInstance()->showItemOnMap(index); + } + else if ("copy_slurl" == command_name) + { + LLVector3d globalPos = LLTeleportHistoryStorage::getInstance()->getItems()[index].mGlobalPos; + LLLandmarkActions::getSLURLfromPosGlobal(globalPos, + boost::bind(&LLTeleportHistoryPanel::gotSLURLCallback, _1)); + } +} - if (has_collapsed_tabs && command_name == "expand_all") - { - return true; - } +bool LLTeleportHistoryPanel::isActionEnabled(const LLSD& userdata) const +{ + std::string command_name = userdata.asString(); + + if (command_name == "collapse_all" + || command_name == "expand_all") + { + S32 tabs_cnt = mItemContainers.size(); + + bool has_expanded_tabs = false; + bool has_collapsed_tabs = false; + + for (S32 n = 0; n < tabs_cnt; n++) + { + LLAccordionCtrlTab* tab = mItemContainers.at(n); + if (!tab->getVisible()) + continue; + + if (tab->getDisplayChildren()) + { + has_expanded_tabs = true; + } + else + { + has_collapsed_tabs = true; + } + + if (has_expanded_tabs && has_collapsed_tabs) + { + break; + } + } + + if (command_name == "collapse_all") + { + return has_expanded_tabs; + } + + if (command_name == "expand_all") + { + return has_collapsed_tabs; + } + } + + if (command_name == "clear_history") + { + return mTeleportHistory->getItems().size() > 0; + } + + if ("teleport" == command_name + || "view" == command_name + || "show_on_map" == command_name + || "copy_slurl" == command_name) + { + if (!mLastSelectedFlatlList) + { + return false; + } + LLTeleportHistoryFlatItem* itemp = dynamic_cast<LLTeleportHistoryFlatItem *> (mLastSelectedFlatlList->getSelectedItem()); + return itemp != NULL; + } return false; } diff --git a/indra/newview/llpanelteleporthistory.h b/indra/newview/llpanelteleporthistory.h index b88861c5c6..058fee0170 100644 --- a/indra/newview/llpanelteleporthistory.h +++ b/indra/newview/llpanelteleporthistory.h @@ -43,38 +43,26 @@ class LLMenuButton; class LLTeleportHistoryPanel : public LLPanelPlacesTab { public: - // *TODO: derive from LLListContextMenu? - class ContextMenu - { - public: - ContextMenu(); - void show(LLView* spawning_view, S32 index, S32 x, S32 y); - - private: - LLContextMenu* createMenu(); - void onTeleport(); - void onInfo(); - void onCopyToClipboard(); - - static void gotSLURLCallback(const std::string& slurl); - - LLContextMenu* mMenu; - S32 mIndex; - }; - LLTeleportHistoryPanel(); virtual ~LLTeleportHistoryPanel(); - /*virtual*/ BOOL postBuild(); - /*virtual*/ void draw(); + BOOL postBuild() override; + void draw() override; - /*virtual*/ void onSearchEdit(const std::string& string); - /*virtual*/ void onShowOnMap(); - /*virtual*/ void onShowProfile(); - /*virtual*/ void onTeleport(); - ///*virtual*/ void onCopySLURL(); - /*virtual*/ void updateVerbs(); - /*virtual*/ bool isSingleItemSelected(); + void onSearchEdit(const std::string& string) override; + void onShowOnMap() override; + void onShowProfile() override; + void onTeleport() override; + ///*virtual*/ void onCopySLURL(); + void onRemoveSelected() override; + void updateVerbs() override; + bool isSingleItemSelected() override; + + LLToggleableMenu* getSelectionMenu() override; + LLToggleableMenu* getSortingMenu() override; + LLToggleableMenu* getCreateMenu() override; + + bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept) override { return false; } private: @@ -88,13 +76,15 @@ private: void onClearTeleportHistory(); bool onClearTeleportHistoryDialog(const LLSD& notification, const LLSD& response); - void refresh(); + void refresh() override; void getNextTab(const LLDate& item_date, S32& curr_tab, LLDate& tab_date); void onTeleportHistoryChange(S32 removed_index); void replaceItem(S32 removed_index); void showTeleportHistory(); void handleItemSelect(LLFlatListView* ); LLFlatListView* getFlatListViewFromTab(LLAccordionCtrlTab *); + static void gotSLURLCallback(const std::string& slurl); + void onGearMenuAction(const LLSD& userdata); bool isActionEnabled(const LLSD& userdata) const; void setAccordionCollapsedByUser(LLUICtrl* acc_tab, bool collapsed); @@ -115,10 +105,10 @@ private: typedef std::vector<LLAccordionCtrlTab*> item_containers_t; item_containers_t mItemContainers; - ContextMenu mContextMenu; LLContextMenu* mAccordionTabMenu; - LLHandle<LLView> mGearMenuHandle; - LLMenuButton* mMenuGearButton; + + LLToggleableMenu* mGearItemMenu; + LLToggleableMenu* mSortingMenu; boost::signals2::connection mTeleportHistoryChangedConnection; }; diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp index 109013498e..0723a78704 100644 --- a/indra/newview/llpaneltopinfobar.cpp +++ b/indra/newview/llpaneltopinfobar.cpp @@ -31,6 +31,7 @@ #include "llagent.h" #include "llagentui.h" #include "llclipboard.h" +#include "llfloaterreg.h" #include "llfloatersidepanelcontainer.h" #include "lllandmarkactions.h" #include "lllocationinputctrl.h" @@ -456,7 +457,7 @@ void LLPanelTopInfoBar::onContextMenuItemClicked(const LLSD::String& item) if(landmark == NULL) { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); + LLFloaterReg::showInstance("add_landmark"); } else { diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 735eaa423d..05d9346f89 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -31,7 +31,6 @@ // linden library includes #include "llclickaction.h" -#include "lleconomy.h" #include "llerror.h" #include "llfontgl.h" #include "llflexibleobject.h" @@ -82,8 +81,11 @@ #include <boost/bind.hpp> -// "Features" Tab +const F32 DEFAULT_GRAVITY_MULTIPLIER = 1.f; +const F32 DEFAULT_DENSITY = 1000.f; + +// "Features" Tab BOOL LLPanelVolume::postBuild() { // Flexible Objects Parameters @@ -298,7 +300,7 @@ void LLPanelVolume::getState( ) { LightColorSwatch->setEnabled( TRUE ); LightColorSwatch->setValid( TRUE ); - LightColorSwatch->set(volobjp->getLightBaseColor()); + LightColorSwatch->set(volobjp->getLightSRGBBaseColor()); } LLTextureCtrl* LightTextureCtrl = getChild<LLTextureCtrl>("light texture control"); @@ -326,7 +328,7 @@ void LLPanelVolume::getState( ) getChild<LLUICtrl>("Light Focus")->setValue(params.mV[1]); getChild<LLUICtrl>("Light Ambiance")->setValue(params.mV[2]); - mLightSavedColor = volobjp->getLightColor(); + mLightSavedColor = volobjp->getLightSRGBBaseColor(); } else { @@ -583,7 +585,7 @@ void LLPanelVolume::refresh() mRootObject = NULL; } - BOOL visible = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 0 ? TRUE : FALSE; + BOOL visible = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 0 ? TRUE : FALSE; getChildView("Light FOV")->setVisible( visible); getChildView("Light Focus")->setVisible( visible); @@ -805,7 +807,7 @@ void LLPanelVolume::onLightSelectColor(const LLSD& data) { LLColor4 clr = LightColorSwatch->get(); LLColor3 clr3( clr ); - volobjp->setLightColor(clr3); + volobjp->setLightSRGBColor(clr3); mLightSavedColor = clr; } } @@ -830,7 +832,7 @@ void LLPanelVolume::onLightSelectTexture(const LLSD& data) // static void LLPanelVolume::onCommitMaterial( LLUICtrl* ctrl, void* userdata ) { - //LLPanelObject* self = (LLPanelObject*) userdata; + LLPanelVolume* self = (LLPanelVolume*)userdata; LLComboBox* box = (LLComboBox*) ctrl; if (box) @@ -841,6 +843,19 @@ void LLPanelVolume::onCommitMaterial( LLUICtrl* ctrl, void* userdata ) if (material_name != LEGACY_FULLBRIGHT_DESC) { U8 material_code = LLMaterialTable::basic.getMCode(material_name); + if (self) + { + LLViewerObject* objectp = self->mObject; + if (objectp) + { + objectp->setPhysicsGravity(DEFAULT_GRAVITY_MULTIPLIER); + objectp->setPhysicsFriction(LLMaterialTable::basic.getFriction(material_code)); + //currently density is always set to 1000 serverside regardless of chosen material, + //actual material density should be used here, if this behavior change + objectp->setPhysicsDensity(DEFAULT_DENSITY); + objectp->setPhysicsRestitution(LLMaterialTable::basic.getRestitution(material_code)); + } + } LLSelectMgr::getInstance()->selectionSetMaterial(material_code); } } @@ -866,7 +881,7 @@ void LLPanelVolume::onCommitLight( LLUICtrl* ctrl, void* userdata ) if(LightColorSwatch) { LLColor4 clr = LightColorSwatch->get(); - volobjp->setLightColor(LLColor3(clr)); + volobjp->setLightSRGBColor(LLColor3(clr)); } LLTextureCtrl* LightTextureCtrl = self->getChild<LLTextureCtrl>("light texture control"); diff --git a/indra/newview/llpanelvolumepulldown.cpp b/indra/newview/llpanelvolumepulldown.cpp index 6792137350..6f11e76a72 100644 --- a/indra/newview/llpanelvolumepulldown.cpp +++ b/indra/newview/llpanelvolumepulldown.cpp @@ -41,9 +41,6 @@ #include "llfloaterpreference.h" #include "llsliderctrl.h" -/* static */ const F32 LLPanelVolumePulldown::sAutoCloseFadeStartTimeSec = 2.0f; -/* static */ const F32 LLPanelVolumePulldown::sAutoCloseTotalTimeSec = 3.0f; - ///---------------------------------------------------------------------------- /// Class LLPanelVolumePulldown ///---------------------------------------------------------------------------- @@ -51,8 +48,6 @@ // Default constructor LLPanelVolumePulldown::LLPanelVolumePulldown() { - mHoverTimer.stop(); - mCommitCallbackRegistrar.add("Vol.setControlFalse", boost::bind(&LLPanelVolumePulldown::setControlFalse, this, _2)); mCommitCallbackRegistrar.add("Vol.SetSounds", boost::bind(&LLPanelVolumePulldown::onClickSetSounds, this)); mCommitCallbackRegistrar.add("Vol.updateMediaAutoPlayCheckbox", boost::bind(&LLPanelVolumePulldown::updateMediaAutoPlayCheckbox, this, _1)); @@ -62,41 +57,7 @@ LLPanelVolumePulldown::LLPanelVolumePulldown() BOOL LLPanelVolumePulldown::postBuild() { - return LLPanel::postBuild(); -} - -/*virtual*/ -void LLPanelVolumePulldown::onMouseEnter(S32 x, S32 y, MASK mask) -{ - mHoverTimer.stop(); - LLPanel::onMouseEnter(x,y,mask); -} - -/*virtual*/ -void LLPanelVolumePulldown::onTopLost() -{ - setVisible(FALSE); -} - -/*virtual*/ -void LLPanelVolumePulldown::onMouseLeave(S32 x, S32 y, MASK mask) -{ - mHoverTimer.start(); - LLPanel::onMouseLeave(x,y,mask); -} - -/*virtual*/ -void LLPanelVolumePulldown::onVisibilityChange ( BOOL new_visibility ) -{ - if (new_visibility) - { - mHoverTimer.start(); // timer will be stopped when mouse hovers over panel - } - else - { - mHoverTimer.stop(); - - } + return LLPanelPulldown::postBuild(); } void LLPanelVolumePulldown::onAdvancedButtonClick(const LLSD& user_data) @@ -140,7 +101,7 @@ void LLPanelVolumePulldown::updateMediaAutoPlayCheckbox(LLUICtrl* ctrl) bool music_enabled = getChild<LLCheckBoxCtrl>("enable_music")->get(); bool media_enabled = getChild<LLCheckBoxCtrl>("enable_media")->get(); - getChild<LLCheckBoxCtrl>("media_auto_play_btn")->setEnabled(music_enabled || media_enabled); + getChild<LLCheckBoxCtrl>("media_auto_play_combo")->setEnabled(music_enabled || media_enabled); } } @@ -150,20 +111,3 @@ void LLPanelVolumePulldown::onClickSetSounds() // or if sound effects are disabled. getChild<LLCheckBoxCtrl>("gesture_audio_play_btn")->setEnabled(!gSavedSettings.getBOOL("MuteSounds")); } - -//virtual -void LLPanelVolumePulldown::draw() -{ - F32 alpha = mHoverTimer.getStarted() - ? clamp_rescale(mHoverTimer.getElapsedTimeF32(), sAutoCloseFadeStartTimeSec, sAutoCloseTotalTimeSec, 1.f, 0.f) - : 1.0f; - LLViewDrawContext context(alpha); - - LLPanel::draw(); - - if (alpha == 0.f) - { - setVisible(FALSE); - } -} - diff --git a/indra/newview/llpanelvolumepulldown.h b/indra/newview/llpanelvolumepulldown.h index 4f23112f50..e907bb0c78 100644 --- a/indra/newview/llpanelvolumepulldown.h +++ b/indra/newview/llpanelvolumepulldown.h @@ -30,19 +30,12 @@ #include "linden_common.h" -#include "llpanel.h" +#include "llpanelpulldown.h" -class LLFrameTimer; - -class LLPanelVolumePulldown : public LLPanel +class LLPanelVolumePulldown : public LLPanelPulldown { public: LLPanelVolumePulldown(); - /*virtual*/ void draw(); - /*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask); - /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask); - /*virtual*/ void onTopLost(); - /*virtual*/ void onVisibilityChange ( BOOL new_visibility ); /*virtual*/ BOOL postBuild(); private: @@ -52,10 +45,6 @@ class LLPanelVolumePulldown : public LLPanel // "Streaming Music" and "Media" are unchecked. Otherwise enables it. void updateMediaAutoPlayCheckbox(LLUICtrl* ctrl); void onAdvancedButtonClick(const LLSD& user_data); - - LLFrameTimer mHoverTimer; - static const F32 sAutoCloseFadeStartTimeSec; - static const F32 sAutoCloseTotalTimeSec; }; diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index 89cb495db9..3347c40687 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -64,7 +64,9 @@ public: LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; - registrar.add("Gear.Edit", boost::bind(&edit_outfit)); + registrar.add("Gear.TouchAttach", boost::bind(&LLWearingGearMenu::handleMultiple, this, handle_attachment_touch)); + registrar.add("Gear.EditItem", boost::bind(&LLWearingGearMenu::handleMultiple, this, handle_item_edit)); + registrar.add("Gear.EditOutfit", boost::bind(&edit_outfit)); registrar.add("Gear.TakeOff", boost::bind(&LLPanelWearing::onRemoveItem, mPanelWearing)); registrar.add("Gear.Copy", boost::bind(&LLPanelWearing::copyToClipboard, mPanelWearing)); @@ -78,6 +80,16 @@ public: LLToggleableMenu* getMenu() { return mMenu; } private: + void handleMultiple(std::function<void(const LLUUID& id)> functor) + { + uuid_vec_t selected_item_ids; + mPanelWearing->getSelectedItemsUUIDs(selected_item_ids); + + for (const LLUUID& item_id : selected_item_ids) + { + functor(item_id); + } + } LLToggleableMenu* mMenu; LLPanelWearing* mPanelWearing; @@ -92,7 +104,9 @@ protected: { LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; - registrar.add("Wearing.Edit", boost::bind(&edit_outfit)); + registrar.add("Wearing.TouchAttach", boost::bind(handleMultiple, handle_attachment_touch, mUUIDs)); + registrar.add("Wearing.EditItem", boost::bind(handleMultiple, handle_item_edit, mUUIDs)); + registrar.add("Wearing.EditOutfit", boost::bind(&edit_outfit)); registrar.add("Wearing.ShowOriginal", boost::bind(show_item_original, mUUIDs.front())); registrar.add("Wearing.TakeOff", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs)); @@ -138,14 +152,19 @@ protected: } // Enable/disable some menu items depending on the selection. + bool show_touch = !bp_selected && !clothes_selected && attachments_selected; + bool show_edit = bp_selected || clothes_selected || attachments_selected; bool allow_detach = !bp_selected && !clothes_selected && attachments_selected; bool allow_take_off = !bp_selected && clothes_selected && !attachments_selected; + menu->setItemVisible("touch_attach", show_touch); + menu->setItemEnabled("touch_attach", 1 == mUUIDs.size() && enable_attachment_touch(mUUIDs.front())); + menu->setItemVisible("edit_item", show_edit); + menu->setItemEnabled("edit_item", 1 == mUUIDs.size() && get_is_item_editable(mUUIDs.front())); menu->setItemVisible("take_off", allow_take_off); menu->setItemVisible("detach", allow_detach); - menu->setItemVisible("edit_outfit_separator", allow_take_off || allow_detach); + menu->setItemVisible("edit_outfit_separator", show_touch | show_edit | allow_take_off || allow_detach); menu->setItemVisible("show_original", mUUIDs.size() == 1); - menu->setItemVisible("edit_item", FALSE); } }; @@ -173,12 +192,15 @@ protected: void updateMenuItemsVisibility(LLContextMenu* menu) { + menu->setItemVisible("touch_attach", TRUE); + menu->setItemEnabled("touch_attach", 1 == mUUIDs.size()); + menu->setItemVisible("edit_item", TRUE); + menu->setItemEnabled("edit_item", 1 == mUUIDs.size()); menu->setItemVisible("take_off", FALSE); menu->setItemVisible("detach", TRUE); - menu->setItemVisible("edit_outfit_separator", TRUE); + menu->setItemVisible("edit_outfit_separator", FALSE); menu->setItemVisible("show_original", FALSE); - menu->setItemVisible("edit_item", TRUE); - menu->setItemVisible("edit", FALSE); + menu->setItemVisible("edit_outfit", FALSE); } LLPanelWearing* mPanelWearing; @@ -350,6 +372,18 @@ bool LLPanelWearing::isActionEnabled(const LLSD& userdata) } } + uuid_vec_t selected_uuids; + getSelectedItemsUUIDs(selected_uuids); + + if (command_name == "touch_attach") + { + return (1 == selected_uuids.size()) && (enable_attachment_touch(selected_uuids.front())); + } + else if (command_name == "edit_item") + { + return (1 == selected_uuids.size()) && (get_is_item_editable(selected_uuids.front())); + } + return false; } diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index ee6893907e..94d20828ec 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -259,11 +259,7 @@ LLParticipantList::~LLParticipantList() */ void LLParticipantList::onAvalineCallerFound(const LLUUID& participant_id) { - LLConversationItemParticipant* participant = findParticipant(participant_id); - if (participant) - { - removeParticipant(participant); - } + removeParticipant(participant_id); // re-add avaline caller with a correct class instance. addAvatarIDExceptAgent(participant_id); } @@ -397,6 +393,7 @@ void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id) // Hack for this: LLAvatarTracker::instance().isBuddyOnline(avatar_id)) // Add the participant model to the session's children list + // This will post "add_participant" event addParticipant(participant); adjustParticipant(avatar_id); diff --git a/indra/newview/llpersistentnotificationstorage.cpp b/indra/newview/llpersistentnotificationstorage.cpp index 264382ae82..f95ab9928d 100644 --- a/indra/newview/llpersistentnotificationstorage.cpp +++ b/indra/newview/llpersistentnotificationstorage.cpp @@ -40,6 +40,7 @@ LLPersistentNotificationStorage::LLPersistentNotificationStorage(): LLNotificationStorage("") , mLoaded(false) { + initialize(); } LLPersistentNotificationStorage::~LLPersistentNotificationStorage() diff --git a/indra/newview/llpersistentnotificationstorage.h b/indra/newview/llpersistentnotificationstorage.h index 40c9923c74..1fb4487286 100644 --- a/indra/newview/llpersistentnotificationstorage.h +++ b/indra/newview/llpersistentnotificationstorage.h @@ -43,7 +43,7 @@ class LLSD; // be a) serializable(implement LLNotificationResponderInterface), // b) registered with LLResponderRegistry (found in llpersistentnotificationstorage.cpp). -class LLPersistentNotificationStorage : public LLSingleton<LLPersistentNotificationStorage>, public LLNotificationStorage +class LLPersistentNotificationStorage : public LLParamSingleton<LLPersistentNotificationStorage>, public LLNotificationStorage { LLSINGLETON(LLPersistentNotificationStorage); ~LLPersistentNotificationStorage(); @@ -53,11 +53,11 @@ public: void saveNotifications(); void loadNotifications(); - void initialize(); - protected: private: + void initialize(); + bool onPersistentChannelChanged(const LLSD& payload); bool mLoaded; }; diff --git a/indra/newview/llplacesinventorypanel.cpp b/indra/newview/llplacesinventorypanel.cpp index 5eadd65884..1c14acd843 100644 --- a/indra/newview/llplacesinventorypanel.cpp +++ b/indra/newview/llplacesinventorypanel.cpp @@ -43,9 +43,8 @@ static LLDefaultChildRegistry::Register<LLPlacesInventoryPanel> r("places_invent static const LLPlacesInventoryBridgeBuilder PLACES_INVENTORY_BUILDER; LLPlacesInventoryPanel::LLPlacesInventoryPanel(const Params& p) : - LLInventoryPanel(p), + LLAssetFilteredInventoryPanel(p), mSavedFolderState(NULL) - { mInvFVBridgeBuilder = &PLACES_INVENTORY_BUILDER; mSavedFolderState = new LLSaveFolderState(); @@ -78,6 +77,7 @@ LLFolderView * LLPlacesInventoryPanel::createFolderRoot(LLUUID root_id ) p.view_model = &mInventoryViewModel; p.use_label_suffix = mParams.use_label_suffix; p.allow_multiselect = mAllowMultiSelect; + p.allow_drag = mAllowDrag; p.show_empty_message = mShowEmptyMessage; p.show_item_link_overlays = mShowItemLinkOverlays; p.root = NULL; diff --git a/indra/newview/llplacesinventorypanel.h b/indra/newview/llplacesinventorypanel.h index 27d9b83bd1..5629438415 100644 --- a/indra/newview/llplacesinventorypanel.h +++ b/indra/newview/llplacesinventorypanel.h @@ -32,14 +32,16 @@ class LLLandmarksPanel; class LLFolderView; -class LLPlacesInventoryPanel : public LLInventoryPanel +class LLPlacesInventoryPanel : public LLAssetFilteredInventoryPanel { public: struct Params - : public LLInitParam::Block<Params, LLInventoryPanel::Params> + : public LLInitParam::Block<Params, LLAssetFilteredInventoryPanel::Params> { Params() - {} + { + filter_asset_type = "landmark"; + } }; LLPlacesInventoryPanel(const Params& p); diff --git a/indra/newview/llpopupview.cpp b/indra/newview/llpopupview.cpp index 153f0930c2..d1a9ca229f 100644 --- a/indra/newview/llpopupview.cpp +++ b/indra/newview/llpopupview.cpp @@ -44,13 +44,13 @@ LLPopupView::LLPopupView(const LLPopupView::Params& p) : LLPanel(p) { // register ourself as handler of UI popups - LLUI::setPopupFuncs(boost::bind(&LLPopupView::addPopup, this, _1), boost::bind(&LLPopupView::removePopup, this, _1), boost::bind(&LLPopupView::clearPopups, this)); + LLUI::getInstance()->setPopupFuncs(boost::bind(&LLPopupView::addPopup, this, _1), boost::bind(&LLPopupView::removePopup, this, _1), boost::bind(&LLPopupView::clearPopups, this)); } LLPopupView::~LLPopupView() { // set empty callback function so we can't handle popups anymore - LLUI::setPopupFuncs(LLUI::add_popup_t(), LLUI::remove_popup_t(), LLUI::clear_popups_t()); + LLUI::getInstance()->setPopupFuncs(LLUI::add_popup_t(), LLUI::remove_popup_t(), LLUI::clear_popups_t()); } void LLPopupView::draw() diff --git a/indra/newview/llpresetsmanager.cpp b/indra/newview/llpresetsmanager.cpp index df93572508..c267c3c699 100644 --- a/indra/newview/llpresetsmanager.cpp +++ b/indra/newview/llpresetsmanager.cpp @@ -39,6 +39,8 @@ #include "llfloaterpreference.h" #include "llfloaterreg.h" #include "llfeaturemanager.h" +#include "llagentcamera.h" +#include "llfile.h" LLPresetsManager::LLPresetsManager() { @@ -46,6 +48,12 @@ LLPresetsManager::LLPresetsManager() LLPresetsManager::~LLPresetsManager() { + mCameraChangedSignal.disconnect(); +} + +void LLPresetsManager::triggerChangeCameraSignal() +{ + mPresetListChangeCameraSignal(); } void LLPresetsManager::triggerChangeSignal() @@ -53,41 +61,92 @@ void LLPresetsManager::triggerChangeSignal() mPresetListChangeSignal(); } -void LLPresetsManager::createMissingDefault() +void LLPresetsManager::createMissingDefault(const std::string& subdirectory) { if(gDirUtilp->getLindenUserDir().empty()) { return; } - std::string default_file = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR, PRESETS_GRAPHIC, PRESETS_DEFAULT + ".xml"); + + if (PRESETS_CAMERA == subdirectory) + { + createCameraDefaultPresets(); + return; + } + + std::string default_file = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR, + subdirectory, PRESETS_DEFAULT + ".xml"); if (!gDirUtilp->fileExists(default_file)) { LL_INFOS() << "No default preset found -- creating one at " << default_file << LL_ENDL; - // Write current graphic settings as the default - savePreset(PRESETS_GRAPHIC, PRESETS_DEFAULT, true); + // Write current settings as the default + savePreset(subdirectory, PRESETS_DEFAULT, true); + } + else + { + LL_DEBUGS() << "default preset exists; no-op" << LL_ENDL; + } +} + +void LLPresetsManager::createCameraDefaultPresets() +{ + bool is_default_created = createDefaultCameraPreset(PRESETS_REAR_VIEW); + is_default_created |= createDefaultCameraPreset(PRESETS_FRONT_VIEW); + is_default_created |= createDefaultCameraPreset(PRESETS_SIDE_VIEW); + + if (is_default_created) + { + triggerChangeCameraSignal(); + } +} + +void LLPresetsManager::startWatching(const std::string& subdirectory) +{ + if (PRESETS_CAMERA == subdirectory) + { + std::vector<std::string> name_list; + getControlNames(name_list); + + for (std::vector<std::string>::iterator it = name_list.begin(); it != name_list.end(); ++it) + { + std::string ctrl_name = *it; + if (gSavedSettings.controlExists(ctrl_name)) + { + LLPointer<LLControlVariable> cntrl_ptr = gSavedSettings.getControl(ctrl_name); + if (cntrl_ptr.isNull()) + { + LL_WARNS("Init") << "Unable to set signal on global setting '" << ctrl_name + << "'" << LL_ENDL; + } + else + { + mCameraChangedSignal = cntrl_ptr->getCommitSignal()->connect(boost::bind(&settingChanged)); + } + } + } } - else - { - LL_DEBUGS() << "default preset exists; no-op" << LL_ENDL; - } } std::string LLPresetsManager::getPresetsDir(const std::string& subdirectory) { std::string presets_path = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR); - std::string full_path; LLFile::mkdir(presets_path); - full_path = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR, subdirectory); - LLFile::mkdir(full_path); + std::string dest_path = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR, subdirectory); + if (!gDirUtilp->fileExists(dest_path)) + LLFile::mkdir(dest_path); - return full_path; + return dest_path; } -void LLPresetsManager::loadPresetNamesFromDir(const std::string& dir, preset_name_list_t& presets, EDefaultOptions default_option) +void LLPresetsManager::loadPresetNamesFromDir(const std::string& subdirectory, preset_name_list_t& presets, EDefaultOptions default_option) { + bool IS_CAMERA = (PRESETS_CAMERA == subdirectory); + bool IS_GRAPHIC = (PRESETS_GRAPHIC == subdirectory); + + std::string dir = LLPresetsManager::getInstance()->getPresetsDir(subdirectory); LL_INFOS("AppInit") << "Loading list of preset names from " << dir << LL_ENDL; mPresetNames.clear(); @@ -103,16 +162,33 @@ void LLPresetsManager::loadPresetNamesFromDir(const std::string& dir, preset_nam { std::string path = gDirUtilp->add(dir, file); std::string name = LLURI::unescape(gDirUtilp->getBaseFileName(path, /*strip_exten = */ true)); - LL_DEBUGS() << " Found preset '" << name << "'" << LL_ENDL; + LL_DEBUGS() << " Found preset '" << name << "'" << LL_ENDL; - if (PRESETS_DEFAULT != name) + if (IS_CAMERA) { + if (isTemplateCameraPreset(name)) + { + continue; + } + if ((default_option == DEFAULT_HIDE) || (default_option == DEFAULT_BOTTOM)) + { + if (isDefaultCameraPreset(name)) + { + continue; + } + } mPresetNames.push_back(name); } - else + if (IS_GRAPHIC) { - switch (default_option) + if (PRESETS_DEFAULT != name) { + mPresetNames.push_back(name); + } + else + { + switch (default_option) + { case DEFAULT_SHOW: mPresetNames.push_back(LLTrans::getString(PRESETS_DEFAULT)); break; @@ -124,16 +200,77 @@ void LLPresetsManager::loadPresetNamesFromDir(const std::string& dir, preset_nam case DEFAULT_HIDE: default: break; + } } } } } + if (IS_CAMERA) + { + mPresetNames.sort(LLStringUtil::precedesDict); + if (default_option == DEFAULT_BOTTOM) + { + mPresetNames.push_back(PRESETS_FRONT_VIEW); + mPresetNames.push_back(PRESETS_REAR_VIEW); + mPresetNames.push_back(PRESETS_SIDE_VIEW); + } + } + presets = mPresetNames; } +bool LLPresetsManager::mCameraDirty = false; +bool LLPresetsManager::mIgnoreChangedSignal = false; + +void LLPresetsManager::setCameraDirty(bool dirty) +{ + mCameraDirty = dirty; +} + +bool LLPresetsManager::isCameraDirty() +{ + return mCameraDirty; +} + +void LLPresetsManager::settingChanged() +{ + setCameraDirty(true); + + static LLCachedControl<std::string> preset_camera_active(gSavedSettings, "PresetCameraActive", ""); + std::string preset_name = preset_camera_active; + if (!preset_name.empty() && !mIgnoreChangedSignal) + { + gSavedSettings.setString("PresetCameraActive", ""); + + // Hack call because this is a static routine + LLPresetsManager::getInstance()->triggerChangeCameraSignal(); + } +} + +void LLPresetsManager::getControlNames(std::vector<std::string>& names) +{ + const std::vector<std::string> camera_controls = boost::assign::list_of + // From panel_preferences_move.xml + ("CameraAngle") + ("CameraOffsetScale") + ("EditCameraMovement") + ("AppearanceCameraMovement") + // From llagentcamera.cpp + ("CameraOffsetBuild") + ("TrackFocusObject") + ("CameraOffsetRearView") + ("FocusOffsetRearView") + ("AvatarSitRotation") + ; + names = camera_controls; +} + bool LLPresetsManager::savePreset(const std::string& subdirectory, std::string name, bool createDefault) { + bool IS_CAMERA = (PRESETS_CAMERA == subdirectory); + bool IS_GRAPHIC = (PRESETS_GRAPHIC == subdirectory); + if (LLTrans::getString(PRESETS_DEFAULT) == name) { name = PRESETS_DEFAULT; @@ -144,126 +281,174 @@ bool LLPresetsManager::savePreset(const std::string& subdirectory, std::string n return false; } + if (isTemplateCameraPreset(name)) + { + LL_WARNS() << "Should not overwrite template presets" << LL_ENDL; + return false; + } + bool saved = false; std::vector<std::string> name_list; - if(PRESETS_GRAPHIC == subdirectory) + if (IS_GRAPHIC) { LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); if (instance && !createDefault) { - gSavedSettings.setString("PresetGraphicActive", name); + gSavedSettings.setString("PresetGraphicActive", name); instance->getControlNames(name_list); - LL_DEBUGS() << "saving preset '" << name << "'; " << name_list.size() << " names" << LL_ENDL; + LL_DEBUGS() << "saving preset '" << name << "'; " << name_list.size() << " names" << LL_ENDL; name_list.push_back("PresetGraphicActive"); } - else + else { - LL_WARNS() << "preferences floater instance not found" << LL_ENDL; - } + LL_WARNS("Presets") << "preferences floater instance not found" << LL_ENDL; + } } - else if(PRESETS_CAMERA == subdirectory) + else if (IS_CAMERA) { name_list.clear(); - name_list.push_back("Placeholder"); + getControlNames(name_list); + name_list.push_back("PresetCameraActive"); } - else - { - LL_ERRS() << "Invalid presets directory '" << subdirectory << "'" << LL_ENDL; - } - - if (name_list.size() > 1 // if the active preset name is the only thing in the list, don't save the list - || (createDefault && name == PRESETS_DEFAULT && subdirectory == PRESETS_GRAPHIC)) // or create a default graphics preset from hw recommended settings - { - // make an empty llsd - LLSD paramsData(LLSD::emptyMap()); + else + { + LL_ERRS() << "Invalid presets directory '" << subdirectory << "'" << LL_ENDL; + } + + // make an empty llsd + LLSD paramsData(LLSD::emptyMap()); - if (createDefault) - { - paramsData = LLFeatureManager::getInstance()->getRecommendedSettingsMap(); - if (gSavedSettings.getU32("RenderAvatarMaxComplexity") == 0) - { - // use the recommended setting as an initial one (MAINT-6435) - gSavedSettings.setU32("RenderAvatarMaxComplexity", paramsData["RenderAvatarMaxComplexity"]["Value"].asInteger()); - } - } - else - { - for (std::vector<std::string>::iterator it = name_list.begin(); it != name_list.end(); ++it) - { - std::string ctrl_name = *it; - LLControlVariable* ctrl = gSavedSettings.getControl(ctrl_name).get(); - std::string comment = ctrl->getComment(); - std::string type = LLControlGroup::typeEnumToString(ctrl->type()); - LLSD value = ctrl->getValue(); - - paramsData[ctrl_name]["Comment"] = comment; - paramsData[ctrl_name]["Persist"] = 1; - paramsData[ctrl_name]["Type"] = type; - paramsData[ctrl_name]["Value"] = value; - } - } - - std::string pathName(getPresetsDir(subdirectory) + gDirUtilp->getDirDelimiter() + LLURI::escape(name) + ".xml"); - - // write to file - llofstream presetsXML(pathName.c_str()); - if (presetsXML.is_open()) - { - - LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter(); - formatter->format(paramsData, presetsXML, LLSDFormatter::OPTIONS_PRETTY); - presetsXML.close(); - saved = true; + // Create a default graphics preset from hw recommended settings + if (IS_GRAPHIC && createDefault && name == PRESETS_DEFAULT) + { + paramsData = LLFeatureManager::getInstance()->getRecommendedSettingsMap(); + if (gSavedSettings.getU32("RenderAvatarMaxComplexity") == 0) + { + // use the recommended setting as an initial one (MAINT-6435) + gSavedSettings.setU32("RenderAvatarMaxComplexity", paramsData["RenderAvatarMaxComplexity"]["Value"].asInteger()); + } + } + else + { + ECameraPreset new_camera_preset = (ECameraPreset)gSavedSettings.getU32("CameraPresetType"); + bool new_camera_offsets = false; + if (IS_CAMERA) + { + if (isDefaultCameraPreset(name)) + { + if (PRESETS_REAR_VIEW == name) + { + new_camera_preset = CAMERA_PRESET_REAR_VIEW; + } + else if (PRESETS_SIDE_VIEW == name) + { + new_camera_preset = CAMERA_PRESET_GROUP_VIEW; + } + else if (PRESETS_FRONT_VIEW == name) + { + new_camera_preset = CAMERA_PRESET_FRONT_VIEW; + } + } + else + { + new_camera_preset = CAMERA_PRESET_CUSTOM; + } + new_camera_offsets = (!isDefaultCameraPreset(name) || (ECameraPreset)gSavedSettings.getU32("CameraPresetType") != new_camera_preset); + } + for (std::vector<std::string>::iterator it = name_list.begin(); it != name_list.end(); ++it) + { + std::string ctrl_name = *it; + + LLControlVariable* ctrl = gSavedSettings.getControl(ctrl_name).get(); + if (ctrl) + { + std::string comment = ctrl->getComment(); + std::string type = LLControlGroup::typeEnumToString(ctrl->type()); + LLSD value = ctrl->getValue(); + + paramsData[ctrl_name]["Comment"] = comment; + paramsData[ctrl_name]["Persist"] = 1; + paramsData[ctrl_name]["Type"] = type; + paramsData[ctrl_name]["Value"] = value; + } + } + if (IS_CAMERA) + { + gSavedSettings.setU32("CameraPresetType", new_camera_preset); + } + } + + std::string pathName(getPresetsDir(subdirectory) + gDirUtilp->getDirDelimiter() + LLURI::escape(name) + ".xml"); + + // If the active preset name is the only thing in the list, don't save the list + if (paramsData.size() > 1) + { + // write to file + llofstream presetsXML(pathName.c_str()); + if (presetsXML.is_open()) + { + LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter(); + formatter->format(paramsData, presetsXML, LLSDFormatter::OPTIONS_PRETTY); + presetsXML.close(); + saved = true; - LL_DEBUGS() << "saved preset '" << name << "'; " << paramsData.size() << " parameters" << LL_ENDL; - - if (!createDefault) - { - gSavedSettings.setString("PresetGraphicActive", name); - // signal interested parties - triggerChangeSignal(); - } - } - else - { - LL_WARNS("Presets") << "Cannot open for output preset file " << pathName << LL_ENDL; - } - } + LL_DEBUGS() << "saved preset '" << name << "'; " << paramsData.size() << " parameters" << LL_ENDL; + + if (IS_GRAPHIC) + { + gSavedSettings.setString("PresetGraphicActive", name); + // signal interested parties + triggerChangeSignal(); + } + + if (IS_CAMERA) + { + gSavedSettings.setString("PresetCameraActive", name); + setCameraDirty(false); + // signal interested parties + triggerChangeCameraSignal(); + } + } + else + { + LL_WARNS("Presets") << "Cannot open for output preset file " << pathName << LL_ENDL; + } + } else - { - LL_INFOS() << "No settings found; preferences floater has not yet been created" << LL_ENDL; - } + { + LL_INFOS() << "No settings available to be saved" << LL_ENDL; + } return saved; } -void LLPresetsManager::setPresetNamesInComboBox(const std::string& subdirectory, LLComboBox* combo, EDefaultOptions default_option) +bool LLPresetsManager::setPresetNamesInComboBox(const std::string& subdirectory, LLComboBox* combo, EDefaultOptions default_option) { + bool sts = true; + combo->clearRows(); + combo->setEnabled(TRUE); - std::string presets_dir = getPresetsDir(subdirectory); + std::list<std::string> preset_names; + loadPresetNamesFromDir(subdirectory, preset_names, default_option); - if (!presets_dir.empty()) + if (preset_names.begin() != preset_names.end()) { - std::list<std::string> preset_names; - loadPresetNamesFromDir(presets_dir, preset_names, default_option); - - std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive"); - - if (preset_names.begin() != preset_names.end()) - { - for (std::list<std::string>::const_iterator it = preset_names.begin(); it != preset_names.end(); ++it) - { - const std::string& name = *it; - combo->add(name, LLSD().with(0, name)); - } - } - else + for (std::list<std::string>::const_iterator it = preset_names.begin(); it != preset_names.end(); ++it) { - combo->setLabel(LLTrans::getString("preset_combo_label")); + const std::string& name = *it; + combo->add(name, name); } } + else + { + combo->setLabel(LLTrans::getString("preset_combo_label")); + combo->setEnabled(PRESETS_CAMERA != subdirectory); + sts = false; + } + + return sts; } void LLPresetsManager::loadPreset(const std::string& subdirectory, std::string name) @@ -277,24 +462,32 @@ void LLPresetsManager::loadPreset(const std::string& subdirectory, std::string n LL_DEBUGS() << "attempting to load preset '"<<name<<"' from '"<<full_path<<"'" << LL_ENDL; + mIgnoreChangedSignal = true; if(gSavedSettings.loadFromFile(full_path, false, true) > 0) { + mIgnoreChangedSignal = false; if(PRESETS_GRAPHIC == subdirectory) { gSavedSettings.setString("PresetGraphicActive", name); - } - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); - if (instance) + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->refreshEnabledGraphics(); + } + triggerChangeSignal(); + } + if(PRESETS_CAMERA == subdirectory) { - instance->refreshEnabledGraphics(); + gSavedSettings.setString("PresetCameraActive", name); + triggerChangeCameraSignal(); } - triggerChangeSignal(); } - else - { - LL_WARNS() << "failed to load preset '"<<name<<"' from '"<<full_path<<"'" << LL_ENDL; - } + else + { + mIgnoreChangedSignal = false; + LL_WARNS("Presets") << "failed to load preset '"<<name<<"' from '"<<full_path<<"'" << LL_ENDL; + } } bool LLPresetsManager::deletePreset(const std::string& subdirectory, std::string name) @@ -320,17 +513,70 @@ bool LLPresetsManager::deletePreset(const std::string& subdirectory, std::string } // If you delete the preset that is currently marked as loaded then also indicate that no preset is loaded. - if (gSavedSettings.getString("PresetGraphicActive") == name) + if(PRESETS_GRAPHIC == subdirectory) { - gSavedSettings.setString("PresetGraphicActive", ""); + if (gSavedSettings.getString("PresetGraphicActive") == name) + { + gSavedSettings.setString("PresetGraphicActive", ""); + } + // signal interested parties + triggerChangeSignal(); } - // signal interested parties - triggerChangeSignal(); + if(PRESETS_CAMERA == subdirectory) + { + if (gSavedSettings.getString("PresetCameraActive") == name) + { + gSavedSettings.setString("PresetCameraActive", ""); + } + // signal interested parties + triggerChangeCameraSignal(); + } return sts; } +bool LLPresetsManager::isDefaultCameraPreset(std::string preset_name) +{ + return (preset_name == PRESETS_REAR_VIEW || preset_name == PRESETS_SIDE_VIEW || preset_name == PRESETS_FRONT_VIEW); +} + +bool LLPresetsManager::isTemplateCameraPreset(std::string preset_name) +{ + return (preset_name == PRESETS_REAR || preset_name == PRESETS_SIDE || preset_name == PRESETS_FRONT); +} + +void LLPresetsManager::resetCameraPreset(std::string preset_name) +{ + if (isDefaultCameraPreset(preset_name)) + { + createDefaultCameraPreset(preset_name, true); + + if (gSavedSettings.getString("PresetCameraActive") == preset_name) + { + loadPreset(PRESETS_CAMERA, preset_name); + } + } +} + +bool LLPresetsManager::createDefaultCameraPreset(std::string preset_name, bool force_reset) +{ + std::string preset_file = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR, + PRESETS_CAMERA, LLURI::escape(preset_name) + ".xml"); + if (!gDirUtilp->fileExists(preset_file) || force_reset) + { + std::string template_name = preset_name.substr(0, preset_name.size() - PRESETS_VIEW_SUFFIX.size()); + std::string default_template_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, PRESETS_CAMERA, template_name + ".xml"); + return LLFile::copy(default_template_file, preset_file); + } + return false; +} + +boost::signals2::connection LLPresetsManager::setPresetListChangeCameraCallback(const preset_list_signal_t::slot_type& cb) +{ + return mPresetListChangeCameraSignal.connect(cb); +} + boost::signals2::connection LLPresetsManager::setPresetListChangeCallback(const preset_list_signal_t::slot_type& cb) { return mPresetListChangeSignal.connect(cb); diff --git a/indra/newview/llpresetsmanager.h b/indra/newview/llpresetsmanager.h index 0014e32267..0de30e9e01 100644 --- a/indra/newview/llpresetsmanager.h +++ b/indra/newview/llpresetsmanager.h @@ -33,14 +33,23 @@ #include <map> static const std::string PRESETS_DEFAULT = "Default"; +static const std::string PRESETS_DEFAULT_UPPER = "DEFAULT"; static const std::string PRESETS_DIR = "presets"; static const std::string PRESETS_GRAPHIC = "graphic"; static const std::string PRESETS_CAMERA = "camera"; +static const std::string PRESETS_REAR = "Rear"; +static const std::string PRESETS_FRONT = "Front"; +static const std::string PRESETS_SIDE = "Side"; +static const std::string PRESETS_VIEW_SUFFIX = " View"; +static const std::string PRESETS_REAR_VIEW = PRESETS_REAR + PRESETS_VIEW_SUFFIX; +static const std::string PRESETS_FRONT_VIEW = PRESETS_FRONT + PRESETS_VIEW_SUFFIX; +static const std::string PRESETS_SIDE_VIEW = PRESETS_SIDE + PRESETS_VIEW_SUFFIX; enum EDefaultOptions { DEFAULT_SHOW, DEFAULT_TOP, + DEFAULT_BOTTOM, DEFAULT_HIDE // Do not display "Default" in a list }; @@ -54,26 +63,47 @@ public: typedef std::list<std::string> preset_name_list_t; typedef boost::signals2::signal<void()> preset_list_signal_t; - void createMissingDefault(); + void createMissingDefault(const std::string& subdirectory); + void startWatching(const std::string& subdirectory); + void triggerChangeCameraSignal(); void triggerChangeSignal(); static std::string getPresetsDir(const std::string& subdirectory); - void setPresetNamesInComboBox(const std::string& subdirectory, LLComboBox* combo, EDefaultOptions default_option); - void loadPresetNamesFromDir(const std::string& dir, preset_name_list_t& presets, EDefaultOptions default_option); + bool setPresetNamesInComboBox(const std::string& subdirectory, LLComboBox* combo, EDefaultOptions default_option); + void loadPresetNamesFromDir(const std::string& subdirectory, preset_name_list_t& presets, EDefaultOptions default_option); bool savePreset(const std::string& subdirectory, std::string name, bool createDefault = false); void loadPreset(const std::string& subdirectory, std::string name); bool deletePreset(const std::string& subdirectory, std::string name); + bool isCameraDirty(); + static void setCameraDirty(bool dirty); + + void createCameraDefaultPresets(); + + bool isTemplateCameraPreset(std::string preset_name); + bool isDefaultCameraPreset(std::string preset_name); + void resetCameraPreset(std::string preset_name); + bool createDefaultCameraPreset(std::string preset_name, bool force_reset = false); // Emitted when a preset gets loaded, deleted, or saved. + boost::signals2::connection setPresetListChangeCameraCallback(const preset_list_signal_t::slot_type& cb); boost::signals2::connection setPresetListChangeCallback(const preset_list_signal_t::slot_type& cb); // Emitted when a preset gets loaded or saved. preset_name_list_t mPresetNames; + preset_list_signal_t mPresetListChangeCameraSignal; preset_list_signal_t mPresetListChangeSignal; private: - LOG_CLASS(LLPresetsManager); + LOG_CLASS(LLPresetsManager); + + void getControlNames(std::vector<std::string>& names); + static void settingChanged(); + + boost::signals2::connection mCameraChangedSignal; + + static bool mCameraDirty; + static bool mIgnoreChangedSignal; }; #endif // LL_PRESETSMANAGER_H diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index 787bd68e58..18c2fb5452 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -373,11 +373,11 @@ BOOL LLPreviewGesture::postBuild() mReplaceEditor = edit; combo = getChild<LLComboBox>( "modifier_combo"); - combo->setCommitCallback(onCommitSetDirty, this); + combo->setCommitCallback(boost::bind(&LLPreviewGesture::onCommitKeyorModifier, this)); mModifierCombo = combo; combo = getChild<LLComboBox>( "key_combo"); - combo->setCommitCallback(onCommitSetDirty, this); + combo->setCommitCallback(boost::bind(&LLPreviewGesture::onCommitKeyorModifier, this)); mKeyCombo = combo; list = getChild<LLScrollListCtrl>("library_list"); @@ -937,12 +937,16 @@ void LLPreviewGesture::loadUIFromGesture(LLMultiGesture* gesture) break; } + mModifierCombo->setEnabledByValue(CTRL_LABEL, gesture->mKey != KEY_F10); + mKeyCombo->setCurrentByIndex(0); if (gesture->mKey != KEY_NONE) { mKeyCombo->setSimple(LLKeyboard::stringFromKey(gesture->mKey)); } + mKeyCombo->setEnabledByValue(LLKeyboard::stringFromKey(KEY_F10), gesture->mMask != MASK_CONTROL); + // Make UI steps for each gesture step S32 i; S32 count = gesture->mSteps.size(); @@ -1091,7 +1095,7 @@ void LLPreviewGesture::saveIfNeeded() const LLViewerRegion* region = gAgent.getRegion(); if (!region) { - LL_WARNS() << "Not connected to a region, cannot save notecard." << LL_ENDL; + LL_WARNS() << "Not connected to a region, cannot save gesture." << LL_ENDL; return; } std::string agent_url = region->getCapability("UpdateGestureAgentInventory"); @@ -1111,13 +1115,15 @@ void LLPreviewGesture::saveIfNeeded() refresh(); item->setComplete(true); - uploadInfo = LLResourceUploadInfo::ptr_t(new LLBufferedAssetUploadInfo(mItemUUID, LLAssetType::AT_GESTURE, buffer, - boost::bind(&LLPreviewGesture::finishInventoryUpload, _1, _2))); + uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mItemUUID, LLAssetType::AT_GESTURE, buffer, + [](LLUUID itemId, LLUUID newAssetId, LLUUID, LLSD) { + LLPreviewGesture::finishInventoryUpload(itemId, newAssetId); + }); url = agent_url; } else if (!mObjectUUID.isNull() && !task_url.empty()) { - uploadInfo = LLResourceUploadInfo::ptr_t(new LLBufferedAssetUploadInfo(mObjectUUID, mItemUUID, LLAssetType::AT_GESTURE, buffer, NULL)); + uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mObjectUUID, mItemUUID, LLAssetType::AT_GESTURE, buffer, nullptr); url = task_url; } @@ -1336,6 +1342,17 @@ LLMultiGesture* LLPreviewGesture::createGesture() } +void LLPreviewGesture::onCommitKeyorModifier() +{ + // SL-14139: ctrl-F10 is currently used to access top menu, + // so don't allow to bound gestures to this combination. + + mKeyCombo->setEnabledByValue(LLKeyboard::stringFromKey(KEY_F10), mModifierCombo->getSimple() != CTRL_LABEL); + mModifierCombo->setEnabledByValue(CTRL_LABEL, mKeyCombo->getSimple() != LLKeyboard::stringFromKey(KEY_F10)); + mDirty = TRUE; + refresh(); +} + // static void LLPreviewGesture::updateLabel(LLScrollListItem* item) { diff --git a/indra/newview/llpreviewgesture.h b/indra/newview/llpreviewgesture.h index 3ba4f56295..ffcada4cc2 100644 --- a/indra/newview/llpreviewgesture.h +++ b/indra/newview/llpreviewgesture.h @@ -103,6 +103,8 @@ protected: LLScrollListItem* addStep(const enum EStepType step_type); void onVisibilityChanged ( const LLSD& new_visibility ); + + void onCommitKeyorModifier(); static std::string getLabel(std::vector<std::string> labels); static void updateLabel(LLScrollListItem* item); diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 1533a27469..1b60610668 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -307,6 +307,7 @@ void LLPreviewNotecard::loadAsset() { editor->setEnabled(FALSE); getChildView("lock")->setVisible( TRUE); + getChildView("Edit")->setEnabled(FALSE); } if((allow_modify || is_owner) && !source_library) @@ -367,6 +368,7 @@ void LLPreviewNotecard::onLoadComplete(LLVFS *vfs, previewEditor->makePristine(); BOOL modifiable = preview->canModify(preview->mObjectID, preview->getItem()); preview->setEnabled(modifiable); + preview->syncExternal(); preview->mAssetStatus = PREVIEW_ASSET_LOADED; } else @@ -503,10 +505,6 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem, bool sync) } editor->makePristine(); - if (sync) - { - syncExternal(); - } const LLInventoryItem* item = getItem(); // save it out to database if (item) @@ -527,14 +525,19 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem, bool sync) if (mObjectUUID.isNull() && !agent_url.empty()) { - uploadInfo = LLResourceUploadInfo::ptr_t(new LLBufferedAssetUploadInfo(mItemUUID, LLAssetType::AT_NOTECARD, buffer, - boost::bind(&LLPreviewNotecard::finishInventoryUpload, _1, _2, _3))); + uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mItemUUID, LLAssetType::AT_NOTECARD, buffer, + [](LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD) { + LLPreviewNotecard::finishInventoryUpload(itemId, newAssetId, newItemId); + }); url = agent_url; } else if (!mObjectUUID.isNull() && !task_url.empty()) { - uploadInfo = LLResourceUploadInfo::ptr_t(new LLBufferedAssetUploadInfo(mObjectUUID, mItemUUID, LLAssetType::AT_NOTECARD, buffer, - boost::bind(&LLPreviewNotecard::finishTaskUpload, _1, _3, mObjectUUID))); + LLUUID object_uuid(mObjectUUID); + uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mObjectUUID, mItemUUID, LLAssetType::AT_NOTECARD, buffer, + [object_uuid](LLUUID itemId, LLUUID, LLUUID newAssetId, LLSD) { + LLPreviewNotecard::finishTaskUpload(itemId, newAssetId, object_uuid); + }); url = task_url; } @@ -755,6 +758,7 @@ void LLPreviewNotecard::openInExternalEditor() // Start watching file changes. mLiveFile = new LLLiveLSLFile(filename, boost::bind(&LLPreviewNotecard::onExternalChange, this, _1)); + mLiveFile->ignoreNextUpdate(); mLiveFile->addToEventTimer(); // Open it in external editor. diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index f1bb0bc27d..f13910cde5 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -33,7 +33,6 @@ #include "llcheckboxctrl.h" #include "llcombobox.h" #include "lldir.h" -#include "llenvmanager.h" #include "llexternaleditor.h" #include "llfilepicker.h" #include "llfloaterreg.h" @@ -545,9 +544,6 @@ void LLScriptEdCore::initMenu() menuItem = getChild<LLMenuItemCallGL>("Go to line..."); menuItem->setClickCallback(boost::bind(&LLFloaterGotoLine::show, this)); - menuItem = getChild<LLMenuItemCallGL>("Help..."); - menuItem->setClickCallback(boost::bind(&LLScriptEdCore::onBtnHelp, this)); - menuItem = getChild<LLMenuItemCallGL>("Keyword Help..."); menuItem->setClickCallback(boost::bind(&LLScriptEdCore::onBtnDynamicHelp, this)); @@ -640,14 +636,17 @@ bool LLScriptEdCore::writeToFile(const std::string& filename) void LLScriptEdCore::sync() { - // Sync with external editor. - std::string tmp_file = mContainer->getTmpFileName(); - llstat s; - if (LLFile::stat(tmp_file, &s) == 0) // file exists - { - if (mLiveFile) mLiveFile->ignoreNextUpdate(); - writeToFile(tmp_file); - } + // Sync with external editor. + if (mLiveFile) + { + std::string tmp_file = mLiveFile->filename(); + llstat s; + if (LLFile::stat(tmp_file, &s) == 0) // file exists + { + mLiveFile->ignoreNextUpdate(); + writeToFile(tmp_file); + } + } } bool LLScriptEdCore::hasChanged() @@ -737,7 +736,10 @@ void LLScriptEdCore::updateDynamicHelp(BOOL immediate) } if (immediate || (mLiveHelpTimer.getStarted() && mLiveHelpTimer.getElapsedTimeF32() > LIVE_HELP_REFRESH_TIME)) { - std::string help_string = mEditor->getText().substr(segment->getStart(), segment->getEnd() - segment->getStart()); + // Use Wtext since segment's start/end are made for wstring and will + // result in a shift for case of multi-byte symbols inside std::string. + LLWString segment_text = mEditor->getWText().substr(segment->getStart(), segment->getEnd() - segment->getStart()); + std::string help_string = wstring_to_utf8str(segment_text); setHelpPage(help_string); mLiveHelpTimer.stop(); } @@ -883,11 +885,6 @@ bool LLScriptEdCore::handleSaveChangesDialog(const LLSD& notification, const LLS return false; } -void LLScriptEdCore::onBtnHelp() -{ - LLUI::sHelpImpl->showTopic(HELP_LSL_PORTAL_TOPIC); -} - void LLScriptEdCore::onBtnDynamicHelp() { LLFloater* live_help_floater = mLiveHelpHandle.get(); @@ -1033,9 +1030,25 @@ void LLScriptEdCore::openInExternalEditor() { delete mLiveFile; // deletes file - // Save the script to a temporary file. - std::string filename = mContainer->getTmpFileName(); - writeToFile(filename); + // Generate a suitable filename + std::string script_name = mScriptName; + std::string forbidden_chars = "<>:\"\\/|?*"; + for (std::string::iterator c = forbidden_chars.begin(); c != forbidden_chars.end(); c++) + { + script_name.erase(std::remove(script_name.begin(), script_name.end(), *c), script_name.end()); + } + std::string filename = mContainer->getTmpFileName(script_name); + + // Save the script to a temporary file. + if (!writeToFile(filename)) + { + // In case some characters from script name are forbidden + // and not accounted for, name is too long or some other issue, + // try file that doesn't include script name + script_name.clear(); + filename = mContainer->getTmpFileName(script_name); + writeToFile(filename); + } // Start watching file changes. mLiveFile = new LLLiveLSLFile(filename, boost::bind(&LLScriptEdContainer::onExternalChange, mContainer, _1)); @@ -1425,7 +1438,7 @@ LLScriptEdContainer::LLScriptEdContainer(const LLSD& key) : { } -std::string LLScriptEdContainer::getTmpFileName() +std::string LLScriptEdContainer::getTmpFileName(const std::string& script_name) { // Take script inventory item id (within the object inventory) // to consideration so that it's possible to edit multiple scripts @@ -1437,7 +1450,14 @@ std::string LLScriptEdContainer::getTmpFileName() LLMD5 script_id_hash((const U8 *)script_id.c_str()); script_id_hash.hex_digest(script_id_hash_str); - return std::string(LLFile::tmpdir()) + "sl_script_" + script_id_hash_str + ".lsl"; + if (script_name.empty()) + { + return std::string(LLFile::tmpdir()) + "sl_script_" + script_id_hash_str + ".lsl"; + } + else + { + return std::string(LLFile::tmpdir()) + "sl_script_" + script_name + "_" + script_id_hash_str + ".lsl"; + } } bool LLScriptEdContainer::onExternalChange(const std::string& filename) @@ -1693,9 +1713,11 @@ void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/) if (!url.empty()) { std::string buffer(mScriptEd->mEditor->getText()); - LLBufferedAssetUploadInfo::invnUploadFinish_f proc = boost::bind(&LLPreviewLSL::finishedLSLUpload, _1, _4); - LLResourceUploadInfo::ptr_t uploadInfo(new LLScriptAssetUpload(mItemUUID, buffer, proc)); + LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLScriptAssetUpload>(mItemUUID, buffer, + [](LLUUID itemId, LLUUID, LLUUID, LLSD response) { + LLPreviewLSL::finishedLSLUpload(itemId, response); + })); LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); } @@ -2243,11 +2265,13 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/) if (!url.empty()) { std::string buffer(mScriptEd->mEditor->getText()); - LLBufferedAssetUploadInfo::taskUploadFinish_f proc = boost::bind(&LLLiveLSLEditor::finishLSLUpload, _1, _2, _3, _4, isRunning); - LLResourceUploadInfo::ptr_t uploadInfo(new LLScriptAssetUpload(mObjectUUID, mItemUUID, + LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLScriptAssetUpload>(mObjectUUID, mItemUUID, monoChecked() ? LLScriptAssetUpload::MONO : LLScriptAssetUpload::LSL2, - isRunning, mScriptEd->getAssociatedExperience(), buffer, proc)); + isRunning, mScriptEd->getAssociatedExperience(), buffer, + [isRunning](LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response) { + LLLiveLSLEditor::finishLSLUpload(itemId, taskId, newAssetId, response, isRunning); + })); LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); } diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index 74e4c00d43..c1fea31063 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -144,7 +144,6 @@ public: void setItemRemoved(bool script_removed){mScriptRemoved = script_removed;}; private: - void onBtnHelp(); void onBtnDynamicHelp(); void onBtnUndoChanges(); @@ -206,7 +205,7 @@ public: LLScriptEdContainer(const LLSD& key, const bool live); protected: - std::string getTmpFileName(); + std::string getTmpFileName(const std::string& script_name); bool onExternalChange(const std::string& filename); virtual void saveIfNeeded(bool sync = true) = 0; diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index 9d8be4b2fe..1e91da529c 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -401,7 +401,7 @@ void LLPreviewTexture::onFileLoadedForSave(BOOL success, { const U32 ext_length = 3; std::string extension = self->mSaveFileName.substr( self->mSaveFileName.length() - ext_length); - + LLStringUtil::toLower(extension); // We only support saving in PNG or TGA format LLPointer<LLImageFormatted> image; if(extension == "png") diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index c17b86783d..416848f9af 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -86,7 +86,7 @@ BOOL LLProgressView::postBuild() mMediaCtrl->setVisible( false ); // hidden initially mMediaCtrl->addObserver( this ); // watch events - LLViewerMedia::setOnlyAudibleMediaTextureID(mMediaCtrl->getTextureID()); + LLViewerMedia::getInstance()->setOnlyAudibleMediaTextureID(mMediaCtrl->getTextureID()); mCancelBtn = getChild<LLButton>("cancel_btn"); mCancelBtn->setClickedCallback( LLProgressView::onCancelButtonClicked, NULL ); @@ -229,6 +229,33 @@ void LLProgressView::drawStartTexture(F32 alpha) gGL.popMatrix(); } +void LLProgressView::drawLogos(F32 alpha) +{ + if (mLogosList.empty()) + { + return; + } + + // logos are tied to label, + // due to potential resizes we have to figure offsets out on draw or resize + LLTextBox *logos_label = getChild<LLTextBox>("logos_lbl"); + S32 offset_x, offset_y; + logos_label->localPointToScreen(0, 0, &offset_x, &offset_y); + std::vector<TextureData>::const_iterator iter = mLogosList.begin(); + std::vector<TextureData>::const_iterator end = mLogosList.end(); + for (; iter != end; iter++) + { + gl_draw_scaled_image_with_border(iter->mDrawRect.mLeft + offset_x, + iter->mDrawRect.mBottom + offset_y, + iter->mDrawRect.getWidth(), + iter->mDrawRect.getHeight(), + iter->mTexturep.get(), + UI_VERTEX_COLOR % alpha, + FALSE, + iter->mClipRect, + iter->mOffsetRect); + } +} void LLProgressView::draw() { @@ -245,6 +272,7 @@ void LLProgressView::draw() } LLPanel::draw(); + drawLogos(alpha); return; } @@ -257,13 +285,14 @@ void LLProgressView::draw() drawStartTexture(alpha); LLPanel::draw(); + drawLogos(alpha); // faded out completely - remove panel and reveal world if (mFadeToWorldTimer.getElapsedTimeF32() > FADE_TO_WORLD_TIME ) { mFadeToWorldTimer.stop(); - LLViewerMedia::setOnlyAudibleMediaTextureID(LLUUID::null); + LLViewerMedia::getInstance()->setOnlyAudibleMediaTextureID(LLUUID::null); // Fade is complete, release focus gFocusMgr.releaseFocusIfNeeded( this ); @@ -283,7 +312,7 @@ void LLProgressView::draw() // FIXME: this causes a crash that i haven't been able to fix mMediaCtrl->unloadMediaSource(); - gStartTexture = NULL; + releaseTextures(); } return; } @@ -291,6 +320,7 @@ void LLProgressView::draw() drawStartTexture(1.0f); // draw children LLPanel::draw(); + drawLogos(1.0f); } void LLProgressView::setText(const std::string& text) @@ -309,6 +339,199 @@ void LLProgressView::setMessage(const std::string& msg) getChild<LLUICtrl>("message_text")->setValue(mMessage); } +void LLProgressView::loadLogo(const std::string &path, + const U8 image_codec, + const LLRect &pos_rect, + const LLRectf &clip_rect, + const LLRectf &offset_rect) +{ + // We need these images very early, so we have to force-load them, otherwise they might not load in time. + if (!gDirUtilp->fileExists(path)) + { + return; + } + + LLPointer<LLImageFormatted> start_image_frmted = LLImageFormatted::createFromType(image_codec); + if (!start_image_frmted->load(path)) + { + LL_WARNS("AppInit") << "Image load failed: " << path << LL_ENDL; + return; + } + + LLPointer<LLImageRaw> raw = new LLImageRaw; + if (!start_image_frmted->decode(raw, 0.0f)) + { + LL_WARNS("AppInit") << "Image decode failed " << path << LL_ENDL; + return; + } + // HACK: getLocalTexture allows only power of two dimentions + raw->expandToPowerOfTwo(); + + TextureData data; + data.mTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); + data.mDrawRect = pos_rect; + data.mClipRect = clip_rect; + data.mOffsetRect = offset_rect; + mLogosList.push_back(data); +} + +void LLProgressView::initLogos() +{ + mLogosList.clear(); + + const U8 image_codec = IMG_CODEC_PNG; + const LLRectf default_clip(0.f, 1.f, 1.f, 0.f); + const S32 default_height = 28; + const S32 default_pad = 15; + + S32 icon_width, icon_height; + + // We don't know final screen rect yet, so we can't precalculate position fully + LLTextBox *logos_label = getChild<LLTextBox>("logos_lbl"); + S32 texture_start_x = logos_label->getFont()->getWidthF32(logos_label->getText()) + default_pad; + S32 texture_start_y = -7; + + // Normally we would just preload these textures from textures.xml, + // and display them via icon control, but they are only needed on + // startup and preloaded/UI ones stay forever + // (and this code was done already so simply reused it) + std::string temp_str = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "textures", "3p_icons"); + + temp_str += gDirUtilp->getDirDelimiter(); + +#ifdef LL_FMODSTUDIO + // original image size is 264x96, it is on longer side but + // with no internal paddings so it gets additional padding + icon_width = 77; + icon_height = 21; + S32 pad_fmod_y = 4; + texture_start_x++; + loadLogo(temp_str + "fmod_logo.png", + image_codec, + LLRect(texture_start_x, texture_start_y + pad_fmod_y + icon_height, texture_start_x + icon_width, texture_start_y + pad_fmod_y), + default_clip, + default_clip); + + texture_start_x += icon_width + default_pad + 1; +#endif //LL_FMODSTUDIO +#ifdef LL_HAVOK + // original image size is 342x113, central element is on a larger side + // plus internal padding, so it gets slightly more height than desired 32 + icon_width = 88; + icon_height = 29; + S32 pad_havok_y = -1; + loadLogo(temp_str + "havok_logo.png", + image_codec, + LLRect(texture_start_x, texture_start_y + pad_havok_y + icon_height, texture_start_x + icon_width, texture_start_y + pad_havok_y), + default_clip, + default_clip); + + texture_start_x += icon_width + default_pad; +#endif //LL_HAVOK + + // 108x41 + icon_width = 74; + icon_height = default_height; + loadLogo(temp_str + "vivox_logo.png", + image_codec, + LLRect(texture_start_x, texture_start_y + icon_height, texture_start_x + icon_width, texture_start_y), + default_clip, + default_clip); +} + +void LLProgressView::initStartTexture(S32 location_id, bool is_in_production) +{ + if (gStartTexture.notNull()) + { + gStartTexture = NULL; + LL_INFOS("AppInit") << "re-initializing start screen" << LL_ENDL; + } + + LL_DEBUGS("AppInit") << "Loading startup bitmap..." << LL_ENDL; + + U8 image_codec = IMG_CODEC_PNG; + std::string temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter(); + + if ((S32)START_LOCATION_ID_LAST == location_id) + { + temp_str += LLStartUp::getScreenLastFilename(); + } + else + { + std::string path = temp_str + LLStartUp::getScreenHomeFilename(); + + if (!gDirUtilp->fileExists(path) && is_in_production) + { + // Fallback to old file, can be removed later + // Home image only sets when user changes home, so it will take time for users to switch to pngs + temp_str += "screen_home.bmp"; + image_codec = IMG_CODEC_BMP; + } + else + { + temp_str = path; + } + } + + LLPointer<LLImageFormatted> start_image_frmted = LLImageFormatted::createFromType(image_codec); + + // Turn off start screen to get around the occasional readback + // driver bug + if (!gSavedSettings.getBOOL("UseStartScreen")) + { + LL_INFOS("AppInit") << "Bitmap load disabled" << LL_ENDL; + return; + } + else if (!start_image_frmted->load(temp_str)) + { + LL_WARNS("AppInit") << "Bitmap load failed" << LL_ENDL; + gStartTexture = NULL; + } + else + { + gStartImageWidth = start_image_frmted->getWidth(); + gStartImageHeight = start_image_frmted->getHeight(); + + LLPointer<LLImageRaw> raw = new LLImageRaw; + if (!start_image_frmted->decode(raw, 0.0f)) + { + LL_WARNS("AppInit") << "Bitmap decode failed" << LL_ENDL; + gStartTexture = NULL; + } + else + { + // HACK: getLocalTexture allows only power of two dimentions + raw->expandToPowerOfTwo(); + gStartTexture = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); + } + } + + if (gStartTexture.isNull()) + { + gStartTexture = LLViewerTexture::sBlackImagep; + gStartImageWidth = gStartTexture->getWidth(); + gStartImageHeight = gStartTexture->getHeight(); + } +} + +void LLProgressView::initTextures(S32 location_id, bool is_in_production) +{ + initStartTexture(location_id, is_in_production); + initLogos(); + + childSetVisible("panel_icons", mLogosList.empty() ? FALSE : TRUE); + childSetVisible("panel_top_spacer", mLogosList.empty() ? TRUE : FALSE); +} + +void LLProgressView::releaseTextures() +{ + gStartTexture = NULL; + mLogosList.clear(); + + childSetVisible("panel_top_spacer", TRUE); + childSetVisible("panel_icons", FALSE); +} + void LLProgressView::setCancelButtonVisible(BOOL b, const std::string& label) { mCancelBtn->setVisible( b ); @@ -325,6 +548,7 @@ void LLProgressView::onCancelButtonClicked(void*) // cancel is pressed while teleporting inside region (EXT-4911) if (LLStartUp::getStartupState() < STATE_STARTED) { + LL_INFOS() << "User requesting quit during login" << LL_ENDL; LLAppViewer::instance()->requestQuit(); } else diff --git a/indra/newview/llprogressview.h b/indra/newview/llprogressview.h index 813576b21d..56377a5889 100644 --- a/indra/newview/llprogressview.h +++ b/indra/newview/llprogressview.h @@ -35,6 +35,7 @@ class LLImageRaw; class LLButton; class LLProgressBar; +class LLViewerTexture; class LLProgressView : public LLPanel, @@ -51,6 +52,7 @@ public: /*virtual*/ void draw(); void drawStartTexture(F32 alpha); + void drawLogos(F32 alpha); /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); @@ -70,6 +72,10 @@ public: void setStartupComplete(); + // we have to preload local textures to make sure they won't be grey + void initTextures(S32 location_id, bool is_in_production); + void releaseTextures(); + void setCancelButtonVisible(BOOL b, const std::string& label); static void onCancelButtonClicked( void* ); @@ -95,6 +101,25 @@ protected: bool handleUpdate(const LLSD& event_data); static void onIdle(void* user_data); + void loadLogo(const std::string &path, const U8 image_codec, const LLRect &pos_rect, const LLRectf &clip_rect, const LLRectf &offset_rect); + // logos have unusual location and need to be preloaded to not appear grey, then deleted + void initLogos(); + // Loads a bitmap to display during load + void initStartTexture(S32 location_id, bool is_in_production); + +private: + // We need to draw textures on login, but only once. + // So this vector gets filled up for textures to render and gets cleaned later + // Some textures have unusual requirements, so we are rendering directly + class TextureData + { + public: + LLPointer<LLViewerTexture> mTexturep; + LLRect mDrawRect; + LLRectf mClipRect; + LLRectf mOffsetRect; + }; + std::vector<TextureData> mLogosList; }; #endif // LL_LLPROGRESSVIEW_H diff --git a/indra/newview/llrecentpeople.h b/indra/newview/llrecentpeople.h index 1b4295ddad..18b669ff4f 100644 --- a/indra/newview/llrecentpeople.h +++ b/indra/newview/llrecentpeople.h @@ -53,7 +53,7 @@ class LLRecentPeople: public LLSingleton<LLRecentPeople>, public LLOldEvents::LL LLSINGLETON_EMPTY_CTOR(LLRecentPeople); LOG_CLASS(LLRecentPeople); public: - typedef std::map <LLUUID, F32> id_to_time_map_t; + typedef std::map <LLUUID, F64> id_to_time_map_t; typedef boost::signals2::signal<void ()> signal_t; /** diff --git a/indra/newview/llremoteparcelrequest.h b/indra/newview/llremoteparcelrequest.h index 5b0d189137..70c117be44 100644 --- a/indra/newview/llremoteparcelrequest.h +++ b/indra/newview/llremoteparcelrequest.h @@ -45,7 +45,7 @@ struct LLParcelData std::string desc; S32 actual_area; S32 billable_area; - U8 flags; + U8 flags; // group owned, maturity F32 global_x; F32 global_y; F32 global_z; diff --git a/indra/newview/llsaveoutfitcombobtn.cpp b/indra/newview/llsaveoutfitcombobtn.cpp index 32295cd96f..b1cb6d08d0 100644 --- a/indra/newview/llsaveoutfitcombobtn.cpp +++ b/indra/newview/llsaveoutfitcombobtn.cpp @@ -56,7 +56,7 @@ LLSaveOutfitComboBtn::LLSaveOutfitComboBtn(LLPanel* parent, bool saveAsDefaultAc void LLSaveOutfitComboBtn::showSaveMenu() { S32 x, y; - LLUI::getMousePositionLocal(mParent, &x, &y); + LLUI::getInstance()->getMousePositionLocal(mParent, &x, &y); mSaveMenu->updateParent(LLMenuGL::sMenuContainer); LLMenuGL::showPopup(mParent, mSaveMenu, x, y); diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp index 5ab0013055..f9baf5fbd3 100644 --- a/indra/newview/llscenemonitor.cpp +++ b/indra/newview/llscenemonitor.cpp @@ -526,170 +526,167 @@ void LLSceneMonitor::fetchQueryResult() //dump results to a file _scene_xmonitor_results.csv void LLSceneMonitor::dumpToFile(std::string file_name) -{ using namespace LLTrace; - +{ if (!hasResults()) return; LL_INFOS("SceneMonitor") << "Saving scene load stats to " << file_name << LL_ENDL; - - llofstream os(file_name.c_str()); - - os << std::setprecision(10); - - PeriodicRecording& scene_load_recording = mSceneLoadRecording.getResults(); - const U32 frame_count = scene_load_recording.getNumRecordedPeriods(); - - F64Seconds frame_time; - - os << "Stat"; - for (S32 frame = 1; frame <= frame_count; frame++) - { - frame_time += scene_load_recording.getPrevRecording(frame_count - frame).getDuration(); - os << ", " << frame_time.value(); - } - os << '\n'; - - os << "Sample period(s)"; - for (S32 frame = 1; frame <= frame_count; frame++) + try { - frame_time = scene_load_recording.getPrevRecording(frame_count - frame).getDuration(); - os << ", " << frame_time.value(); - } - os << '\n'; + llofstream os(file_name.c_str()); + os << std::setprecision(10); - typedef StatType<CountAccumulator> trace_count; - for (trace_count::instance_iter it = trace_count::beginInstances(), end_it = trace_count::endInstances(); - it != end_it; - ++it) - { - std::ostringstream row; - row << std::setprecision(10); + LLTrace::PeriodicRecording& scene_load_recording = mSceneLoadRecording.getResults(); + const U32 frame_count = scene_load_recording.getNumRecordedPeriods(); - row << it->getName(); + F64Seconds frame_time; - const char* unit_label = it->getUnitLabel(); - if(unit_label[0]) + os << "Stat"; + for (S32 frame = 1; frame <= frame_count; frame++) { - row << "(" << unit_label << ")"; + frame_time += scene_load_recording.getPrevRecording(frame_count - frame).getDuration(); + os << ", " << frame_time.value(); } + os << '\n'; - S32 samples = 0; - + os << "Sample period(s)"; for (S32 frame = 1; frame <= frame_count; frame++) { - Recording& recording = scene_load_recording.getPrevRecording(frame_count - frame); - samples += recording.getSampleCount(*it); - row << ", " << recording.getSum(*it); + frame_time = scene_load_recording.getPrevRecording(frame_count - frame).getDuration(); + os << ", " << frame_time.value(); } + os << '\n'; - row << '\n'; - if (samples > 0) + typedef LLTrace::StatType<LLTrace::CountAccumulator> trace_count; + for (auto& it : trace_count::instance_snapshot()) { - os << row.str(); - } - } + std::ostringstream row; + row << std::setprecision(10); - typedef StatType<EventAccumulator> trace_event; + row << it.getName(); - for (trace_event::instance_iter it = trace_event::beginInstances(), end_it = trace_event::endInstances(); - it != end_it; - ++it) - { - std::ostringstream row; - row << std::setprecision(10); - row << it->getName(); - - const char* unit_label = it->getUnitLabel(); - if(unit_label[0]) - { - row << "(" << unit_label << ")"; - } + const char* unit_label = it.getUnitLabel(); + if (unit_label[0]) + { + row << "(" << unit_label << ")"; + } - S32 samples = 0; + S32 samples = 0; - for (S32 frame = 1; frame <= frame_count; frame++) - { - Recording& recording = scene_load_recording.getPrevRecording(frame_count - frame); - samples += recording.getSampleCount(*it); - F64 mean = recording.getMean(*it); - if (llisnan(mean)) + for (S32 frame = 1; frame <= frame_count; frame++) { - row << ", n/a"; + LLTrace::Recording& recording = scene_load_recording.getPrevRecording(frame_count - frame); + samples += recording.getSampleCount(it); + row << ", " << recording.getSum(it); } - else + + row << '\n'; + + if (samples > 0) { - row << ", " << mean; + os << row.str(); } } - row << '\n'; + typedef LLTrace::StatType<LLTrace::EventAccumulator> trace_event; - if (samples > 0) + for (auto& it : trace_event::instance_snapshot()) { - os << row.str(); - } - } + std::ostringstream row; + row << std::setprecision(10); + row << it.getName(); - typedef StatType<SampleAccumulator> trace_sample; + const char* unit_label = it.getUnitLabel(); + if (unit_label[0]) + { + row << "(" << unit_label << ")"; + } - for (trace_sample::instance_iter it = trace_sample::beginInstances(), end_it = trace_sample::endInstances(); - it != end_it; - ++it) - { - std::ostringstream row; - row << std::setprecision(10); - row << it->getName(); + S32 samples = 0; - const char* unit_label = it->getUnitLabel(); - if(unit_label[0]) - { - row << "(" << unit_label << ")"; + for (S32 frame = 1; frame <= frame_count; frame++) + { + LLTrace::Recording& recording = scene_load_recording.getPrevRecording(frame_count - frame); + samples += recording.getSampleCount(it); + F64 mean = recording.getMean(it); + if (llisnan(mean)) + { + row << ", n/a"; + } + else + { + row << ", " << mean; + } + } + + row << '\n'; + + if (samples > 0) + { + os << row.str(); + } } - S32 samples = 0; + typedef LLTrace::StatType<LLTrace::SampleAccumulator> trace_sample; - for (S32 frame = 1; frame <= frame_count; frame++) + for (auto& it : trace_sample::instance_snapshot()) { - Recording& recording = scene_load_recording.getPrevRecording(frame_count - frame); - samples += recording.getSampleCount(*it); - F64 mean = recording.getMean(*it); - if (llisnan(mean)) + std::ostringstream row; + row << std::setprecision(10); + row << it.getName(); + + const char* unit_label = it.getUnitLabel(); + if (unit_label[0]) { - row << ", n/a"; + row << "(" << unit_label << ")"; } - else + + S32 samples = 0; + + for (S32 frame = 1; frame <= frame_count; frame++) { - row << ", " << mean; + LLTrace::Recording& recording = scene_load_recording.getPrevRecording(frame_count - frame); + samples += recording.getSampleCount(it); + F64 mean = recording.getMean(it); + if (llisnan(mean)) + { + row << ", n/a"; + } + else + { + row << ", " << mean; + } } - } - row << '\n'; + row << '\n'; - if (samples > 0) - { - os << row.str(); + if (samples > 0) + { + os << row.str(); + } } - } - - typedef StatType<MemAccumulator> trace_mem; - for (trace_mem::instance_iter it = trace_mem::beginInstances(), end_it = trace_mem::endInstances(); - it != end_it; - ++it) - { - os << it->getName() << "(KiB)"; - for (S32 frame = 1; frame <= frame_count; frame++) + typedef LLTrace::StatType<LLTrace::MemAccumulator> trace_mem; + for (auto& it : trace_mem::instance_snapshot()) { - os << ", " << scene_load_recording.getPrevRecording(frame_count - frame).getMax(*it).valueInUnits<LLUnits::Kilobytes>(); + os << it.getName() << "(KiB)"; + + for (S32 frame = 1; frame <= frame_count; frame++) + { + os << ", " << scene_load_recording.getPrevRecording(frame_count - frame).getMax(it).valueInUnits<LLUnits::Kilobytes>(); + } + + os << '\n'; } - os << '\n'; + os.flush(); + os.close(); + } + catch (const std::ios_base::failure &e) + { + LL_WARNS() << "Unable to dump scene monitor results: " << e.what() << LL_ENDL; } - - os.flush(); - os.close(); } //------------------------------------------------------------------------------------------------------------- diff --git a/indra/newview/llscriptruntimeperms.h b/indra/newview/llscriptruntimeperms.h index 51f57afdc9..f692c0ad01 100644 --- a/indra/newview/llscriptruntimeperms.h +++ b/indra/newview/llscriptruntimeperms.h @@ -37,7 +37,7 @@ typedef struct _script_perm { question(q), permbit(b), caution(c) {} } script_perm_t; -const U32 NUM_SCRIPT_PERMISSIONS = 16; +const U32 NUM_SCRIPT_PERMISSIONS = 18; const S32 SCRIPT_PERMISSION_DEBIT = 0; const S32 SCRIPT_PERMISSION_TRIGGER_ANIMATION = 3; const S32 SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS = 14; @@ -58,7 +58,9 @@ static const boost::array<script_perm_t, NUM_SCRIPT_PERMISSIONS> SCRIPT_PERMISSI _script_perm("JoinAnExperience", (0x1 << 13), false), _script_perm("SilentlyManageEstateAccess", (0x1 << 14), false), _script_perm("OverrideYourAnimations", (0x1 << 15), false), - _script_perm("ScriptReturnObjects", (0x1 << 16), false) -}}; + _script_perm("ScriptReturnObjects", (0x1 << 16), false), + _script_perm("ForceSitAvatar", (0x1 << 17), false), + _script_perm("ChangeEnvSettings", (0x1 << 18), false) + } }; #endif // LL_LLSCRIPTRUNTIME_PERMS_H diff --git a/indra/newview/llsearchableui.cpp b/indra/newview/llsearchableui.cpp index 93143eb33f..1119e80005 100644 --- a/indra/newview/llsearchableui.cpp +++ b/indra/newview/llsearchableui.cpp @@ -68,7 +68,10 @@ ll::prefs::PanelData::~PanelData() bool ll::prefs::PanelData::hightlightAndHide( LLWString const &aFilter ) { for( tSearchableItemList::iterator itr = mChildren.begin(); itr != mChildren.end(); ++itr ) - (*itr)->setNotHighlighted( ); + (*itr)->setNotHighlighted(); + + for (tPanelDataList::iterator itr = mChildPanel.begin(); itr != mChildPanel.end(); ++itr) + (*itr)->setNotHighlighted(); if (aFilter.empty()) { @@ -85,6 +88,15 @@ bool ll::prefs::PanelData::hightlightAndHide( LLWString const &aFilter ) return bVisible; } +void ll::prefs::PanelData::setNotHighlighted() +{ + for (tSearchableItemList::iterator itr = mChildren.begin(); itr != mChildren.end(); ++itr) + (*itr)->setNotHighlighted(); + + for (tPanelDataList::iterator itr = mChildPanel.begin(); itr != mChildPanel.end(); ++itr) + (*itr)->setNotHighlighted(); +} + bool ll::prefs::TabContainerData::hightlightAndHide( LLWString const &aFilter ) { for( tSearchableItemList::iterator itr = mChildren.begin(); itr != mChildren.end(); ++itr ) diff --git a/indra/newview/llsearchableui.h b/indra/newview/llsearchableui.h index 9741557e49..e033cae3ab 100644 --- a/indra/newview/llsearchableui.h +++ b/indra/newview/llsearchableui.h @@ -73,6 +73,7 @@ namespace ll virtual ~PanelData(); + void setNotHighlighted(); virtual bool hightlightAndHide( LLWString const &aFilter ); }; diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp index 72d7cf1e45..aba8ca5a4a 100644 --- a/indra/newview/llsecapi.cpp +++ b/indra/newview/llsecapi.cpp @@ -64,7 +64,7 @@ void initializeSecHandler() { handler->init(); } - catch (LLProtectedDataException e) + catch (LLProtectedDataException& e) { exception_msg = e.what(); } @@ -75,6 +75,12 @@ void initializeSecHandler() } } + +void clearSecHandler() +{ + gSecAPIHandler = NULL; + gHandlerMap.clear(); +} // start using a given security api handler. If the string is empty // the default is used LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type) @@ -117,7 +123,7 @@ LLSD LLCredential::getLoginParams() else if (mIdentifier["type"].asString() == "account") { result["username"] = mIdentifier["account_name"]; - result["passwd"] = mAuthenticator["secret"]; + result["passwd"] = mAuthenticator["secret"].asString(); username = result["username"].asString(); } } @@ -154,3 +160,10 @@ void LLCredential::authenticatorType(std::string &idType) } } + +LLCertException::LLCertException(const LLSD& cert_data, const std::string& msg) + : LLException(msg), + mCertData(cert_data) +{ + LL_WARNS("SECAPI") << "Certificate Error: " << msg << LL_ENDL; +} diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index d207f3b5b7..410737b27f 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -75,6 +75,7 @@ #define CERT_EXTENDED_KEY_USAGE "extendedKeyUsage" #define CERT_EKU_SERVER_AUTH SN_server_auth +#define CERT_EKU_TLS_SERVER_AUTH LN_server_auth #define CERT_SUBJECT_KEY_IDENTFIER "subjectKeyIdentifier" #define CERT_AUTHORITY_KEY_IDENTIFIER "authorityKeyIdentifier" @@ -334,17 +335,23 @@ std::ostream& operator <<(std::ostream& s, const LLCredential& cred); class LLCertException: public LLException { public: - LLCertException(const LLSD& cert_data, const std::string& msg): LLException(msg), - mCertData(cert_data) - { - LL_WARNS("SECAPI") << "Certificate Error: " << msg << LL_ENDL; - } + LLCertException(const LLSD& cert_data, const std::string& msg); virtual ~LLCertException() throw() {} LLSD getCertData() const { return mCertData; } protected: LLSD mCertData; }; +class LLAllocationCertException : public LLCertException +{ +public: + LLAllocationCertException(const LLSD& cert_data) : LLCertException(cert_data, "CertAllocationFailure") + { + } + virtual ~LLAllocationCertException() throw() {} +protected: +}; + class LLInvalidCertificate : public LLCertException { public: @@ -445,7 +452,7 @@ public: virtual LLPointer<LLCertificate> getCertificate(X509* openssl_cert)=0; // instantiate a chain from an X509_STORE_CTX - virtual LLPointer<LLCertificateChain> getCertificateChain(const X509_STORE_CTX* chain)=0; + virtual LLPointer<LLCertificateChain> getCertificateChain(X509_STORE_CTX* chain)=0; // instantiate a cert store given it's id. if a persisted version // exists, it'll be loaded. If not, one will be created (but not @@ -464,7 +471,19 @@ public: // delete a protected data item from the store virtual void deleteProtectedData(const std::string& data_type, const std::string& data_id)=0; - + + // persist data in a protected store's map + virtual void addToProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem, + const LLSD& data)=0; + + // remove data from protected store's map + virtual void removeFromProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem)=0; + +public: virtual LLPointer<LLCredential> createCredential(const std::string& grid, const LLSD& identifier, const LLSD& authenticator)=0; @@ -474,10 +493,48 @@ public: virtual void saveCredential(LLPointer<LLCredential> cred, bool save_authenticator)=0; virtual void deleteCredential(LLPointer<LLCredential> cred)=0; + + // has map of credentials declared as specific storage + virtual bool hasCredentialMap(const std::string& storage, + const std::string& grid)=0; + + // returns true if map is empty or does not exist + virtual bool emptyCredentialMap(const std::string& storage, + const std::string& grid)=0; + + // load map of credentials from specific storage + typedef std::map<std::string, LLPointer<LLCredential> > credential_map_t; + virtual void loadCredentialMap(const std::string& storage, + const std::string& grid, + credential_map_t& credential_map)=0; + + // load single username from map of credentials from specific storage + virtual LLPointer<LLCredential> loadFromCredentialMap(const std::string& storage, + const std::string& grid, + const std::string& userid)=0; + + // add item to map of credentials from specific storage + virtual void addToCredentialMap(const std::string& storage, + LLPointer<LLCredential> cred, + bool save_authenticator)=0; + + // remove item from map of credentials from specific storage + virtual void removeFromCredentialMap(const std::string& storage, + LLPointer<LLCredential> cred)=0; + + // remove item from map of credentials from specific storage + virtual void removeFromCredentialMap(const std::string& storage, + const std::string& grid, + const std::string& userid)=0; + + virtual void removeCredentialMap(const std::string& storage, + const std::string& grid)=0; }; void initializeSecHandler(); + +void clearSecHandler(); // retrieve a security api depending on the api type LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type); diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index 9ab9e4a1a2..b4853d270a 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -52,6 +52,7 @@ #include "llmachineid.h" +static const std::string DEFAULT_CREDENTIAL_STORAGE = "credential"; // 128 bits of salt data... #define STORE_SALT_SIZE 16 @@ -77,16 +78,16 @@ LLBasicCertificate::LLBasicCertificate(const std::string& pem_cert, BIO * pem_bio = BIO_new_mem_buf((void*)pem_cert.c_str(), pem_cert.length()); if(pem_bio == NULL) { - LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL; - LLTHROW(LLInvalidCertificate(LLSD::emptyMap())); + LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL; + LLTHROW(LLAllocationCertException(LLSD::emptyMap())); } mCert = NULL; PEM_read_bio_X509(pem_bio, &mCert, 0, NULL); BIO_free(pem_bio); if (!mCert) { - LL_WARNS("SECAPI") << "Could not decode certificate to x509." << LL_ENDL; - LLTHROW(LLInvalidCertificate(LLSD::emptyMap())); + LL_WARNS("SECAPI") << "Could not decode certificate to x509." << LL_ENDL; + LLTHROW(LLInvalidCertificate(LLSD::emptyMap())); } } @@ -94,7 +95,7 @@ LLBasicCertificate::LLBasicCertificate(const std::string& pem_cert, LLBasicCertificate::LLBasicCertificate(X509* pCert, const LLSD* validation_params) { - if (!pCert || !pCert->cert_info) + if (!pCert) { LLTHROW(LLInvalidCertificate(LLSD::emptyMap())); } @@ -354,8 +355,8 @@ LLSD cert_name_from_X509_NAME(X509_NAME* name) char buffer[32]; X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, entry_index); - std::string name_value = std::string((const char*)M_ASN1_STRING_data(X509_NAME_ENTRY_get_data(entry)), - M_ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry))); + std::string name_value = std::string((const char*)ASN1_STRING_data(X509_NAME_ENTRY_get_data(entry)), + ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry))); ASN1_OBJECT* name_obj = X509_NAME_ENTRY_get_object(entry); OBJ_obj2txt(buffer, sizeof(buffer), name_obj, 0); @@ -682,29 +683,29 @@ std::string LLBasicCertificateStore::storeId() const // LLBasicCertificateChain // This class represents a chain of certs, each cert being signed by the next cert // in the chain. Certs must be properly signed by the parent -LLBasicCertificateChain::LLBasicCertificateChain(const X509_STORE_CTX* store) +LLBasicCertificateChain::LLBasicCertificateChain(X509_STORE_CTX* store) { // we're passed in a context, which contains a cert, and a blob of untrusted // certificates which compose the chain. - if((store == NULL) || (store->cert == NULL)) + if((store == NULL) || X509_STORE_CTX_get0_cert(store) == NULL) { LL_WARNS("SECAPI") << "An invalid store context was passed in when trying to create a certificate chain" << LL_ENDL; return; } // grab the child cert - LLPointer<LLCertificate> current = new LLBasicCertificate(store->cert); + LLPointer<LLCertificate> current = new LLBasicCertificate(X509_STORE_CTX_get0_cert(store)); add(current); - if(store->untrusted != NULL) + if(X509_STORE_CTX_get0_untrusted(store) != NULL) { // if there are other certs in the chain, we build up a vector // of untrusted certs so we can search for the parents of each // consecutive cert. LLBasicCertificateVector untrusted_certs; - for(int i = 0; i < sk_X509_num(store->untrusted); i++) + for(int i = 0; i < sk_X509_num(X509_STORE_CTX_get0_untrusted(store)); i++) { - LLPointer<LLCertificate> cert = new LLBasicCertificate(sk_X509_value(store->untrusted, i)); + LLPointer<LLCertificate> cert = new LLBasicCertificate(sk_X509_value(X509_STORE_CTX_get0_untrusted(store), i)); untrusted_certs.add(cert); } @@ -914,18 +915,30 @@ void _validateCert(int validation_policy, } if (validation_policy & VALIDATION_POLICY_SSL_KU) { + // This stanza of code was changed 2021-06-09 as per details in SL-15370. + // Brief summary: a renewed certificate from Akamai only contains the + // 'Digital Signature' field and not the 'Key Encipherment' one. This code + // used to look for both and throw an exception at startup (ignored) and + // (for example) when buying L$ in the Viewer (fails with a UI message + // and an entry in the Viewer log). This modified code removes the second + // check for the 'Key Encipherment' field. If Akamai can provide a + // replacement certificate that has both fields, then this modified code + // will not be required. if (current_cert_info.has(CERT_KEY_USAGE) && current_cert_info[CERT_KEY_USAGE].isArray() && - (!(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], - LLSD((std::string)CERT_KU_DIGITAL_SIGNATURE))) || !(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], - LLSD((std::string)CERT_KU_KEY_ENCIPHERMENT))))) + LLSD((std::string)CERT_KU_DIGITAL_SIGNATURE))) + ) { LLTHROW(LLCertKeyUsageValidationException(current_cert_info)); } // only validate EKU if the cert has it - if(current_cert_info.has(CERT_EXTENDED_KEY_USAGE) && current_cert_info[CERT_EXTENDED_KEY_USAGE].isArray() && - (!_LLSDArrayIncludesValue(current_cert_info[CERT_EXTENDED_KEY_USAGE], - LLSD((std::string)CERT_EKU_SERVER_AUTH)))) + if(current_cert_info.has(CERT_EXTENDED_KEY_USAGE) + && current_cert_info[CERT_EXTENDED_KEY_USAGE].isArray() + && (!_LLSDArrayIncludesValue(current_cert_info[CERT_EXTENDED_KEY_USAGE], + LLSD((std::string)CERT_EKU_TLS_SERVER_AUTH))) + && (!_LLSDArrayIncludesValue(current_cert_info[CERT_EXTENDED_KEY_USAGE], + LLSD((std::string)CERT_EKU_SERVER_AUTH))) + ) { LLTHROW(LLCertKeyUsageValidationException(current_cert_info)); } @@ -1335,9 +1348,10 @@ void LLSecAPIBasicHandler::_readProtectedData() // read in the rest of the file. - EVP_CIPHER_CTX ctx; - EVP_CIPHER_CTX_init(&ctx); - EVP_DecryptInit(&ctx, EVP_rc4(), salt, NULL); + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + // todo: ctx error handling + + EVP_DecryptInit(ctx, EVP_rc4(), salt, NULL); // allocate memory: std::string decrypted_data; @@ -1345,14 +1359,14 @@ void LLSecAPIBasicHandler::_readProtectedData() // read data as a block: protected_data_stream.read((char *)buffer, BUFFER_READ_SIZE); - EVP_DecryptUpdate(&ctx, decrypted_buffer, &decrypted_length, + EVP_DecryptUpdate(ctx, decrypted_buffer, &decrypted_length, buffer, protected_data_stream.gcount()); decrypted_data.append((const char *)decrypted_buffer, protected_data_stream.gcount()); } // RC4 is a stream cipher, so we don't bother to EVP_DecryptFinal, as there is // no block padding. - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); std::istringstream parse_stream(decrypted_data); if (parser->parse(parse_stream, mProtectedDataMap, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) @@ -1388,12 +1402,14 @@ void LLSecAPIBasicHandler::_writeProtectedData() llofstream protected_data_stream(tmp_filename.c_str(), std::ios_base::binary); + EVP_CIPHER_CTX *ctx = NULL; try { - EVP_CIPHER_CTX ctx; - EVP_CIPHER_CTX_init(&ctx); - EVP_EncryptInit(&ctx, EVP_rc4(), salt, NULL); + ctx = EVP_CIPHER_CTX_new(); + // todo: ctx error handling + + EVP_EncryptInit(ctx, EVP_rc4(), salt, NULL); unsigned char unique_id[MAC_ADDRESS_BYTES]; LLMachineID::getUniqueID(unique_id, sizeof(unique_id)); LLXORCipher cipher(unique_id, sizeof(unique_id)); @@ -1408,13 +1424,13 @@ void LLSecAPIBasicHandler::_writeProtectedData() break; } int encrypted_length; - EVP_EncryptUpdate(&ctx, encrypted_buffer, &encrypted_length, + EVP_EncryptUpdate(ctx, encrypted_buffer, &encrypted_length, buffer, formatted_data_istream.gcount()); protected_data_stream.write((const char *)encrypted_buffer, encrypted_length); } // no EVP_EncrypteFinal, as this is a stream cipher - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); protected_data_stream.close(); } @@ -1426,6 +1442,11 @@ void LLSecAPIBasicHandler::_writeProtectedData() // it may be, however. LLFile::remove(tmp_filename); + if (ctx) + { + EVP_CIPHER_CTX_free(ctx); + } + // EXP-1825 crash in LLSecAPIBasicHandler::_writeProtectedData() // Decided throwing an exception here was overkill until we figure out why this happens //LLTHROW(LLProtectedDataException("Error writing Protected Data Store")); @@ -1478,7 +1499,7 @@ LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(X509* openssl_cert } // instantiate a chain from an X509_STORE_CTX -LLPointer<LLCertificateChain> LLSecAPIBasicHandler::getCertificateChain(const X509_STORE_CTX* chain) +LLPointer<LLCertificateChain> LLSecAPIBasicHandler::getCertificateChain(X509_STORE_CTX* chain) { LLPointer<LLCertificateChain> result = new LLBasicCertificateChain(chain); return result; @@ -1533,6 +1554,38 @@ void LLSecAPIBasicHandler::setProtectedData(const std::string& data_type, mProtectedDataMap[data_type][data_id] = data; } +// persist data in a protected store's map +void LLSecAPIBasicHandler::addToProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem, + const LLSD& data) +{ + if (!mProtectedDataMap.has(data_type) || !mProtectedDataMap[data_type].isMap()) { + mProtectedDataMap[data_type] = LLSD::emptyMap(); + } + + if (!mProtectedDataMap[data_type].has(data_id) || !mProtectedDataMap[data_type][data_id].isMap()) { + mProtectedDataMap[data_type][data_id] = LLSD::emptyMap(); + } + + mProtectedDataMap[data_type][data_id][map_elem] = data; +} + +// remove data from protected store's map +void LLSecAPIBasicHandler::removeFromProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem) +{ + if (mProtectedDataMap.has(data_type) && + mProtectedDataMap[data_type].isMap() && + mProtectedDataMap[data_type].has(data_id) && + mProtectedDataMap[data_type][data_id].isMap() && + mProtectedDataMap[data_type][data_id].has(map_elem)) + { + mProtectedDataMap[data_type][data_id].erase(map_elem); + } +} + // // Create a credential object from an identifier and authenticator. credentials are // per grid. @@ -1545,10 +1598,10 @@ LLPointer<LLCredential> LLSecAPIBasicHandler::createCredential(const std::string return result; } -// Load a credential from the credential store, given the grid +// Load a credential from default credential store, given the grid LLPointer<LLCredential> LLSecAPIBasicHandler::loadCredential(const std::string& grid) { - LLSD credential = getProtectedData("credential", grid); + LLSD credential = getProtectedData(DEFAULT_CREDENTIAL_STORAGE, grid); LLPointer<LLSecAPIBasicCredential> result = new LLSecAPIBasicCredential(grid); if(credential.isMap() && credential.has("identifier")) @@ -1603,7 +1656,7 @@ void LLSecAPIBasicHandler::saveCredential(LLPointer<LLCredential> cred, bool sav credential["authenticator"] = cred->getAuthenticator(); } LL_DEBUGS("SECAPI") << "Saving Credential " << cred->getGrid() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL; - setProtectedData("credential", cred->getGrid(), credential); + setProtectedData(DEFAULT_CREDENTIAL_STORAGE, cred->getGrid(), credential); //*TODO: If we're saving Agni credentials, should we write the // credentials to the legacy password.dat/etc? _writeProtectedData(); @@ -1613,11 +1666,150 @@ void LLSecAPIBasicHandler::saveCredential(LLPointer<LLCredential> cred, bool sav void LLSecAPIBasicHandler::deleteCredential(LLPointer<LLCredential> cred) { LLSD undefVal; - deleteProtectedData("credential", cred->getGrid()); + deleteProtectedData(DEFAULT_CREDENTIAL_STORAGE, cred->getGrid()); cred->setCredentialData(undefVal, undefVal); _writeProtectedData(); } +// has map of credentials declared as specific storage +bool LLSecAPIBasicHandler::hasCredentialMap(const std::string& storage, const std::string& grid) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD credential = getProtectedData(storage, grid); + + return credential.isMap(); +} + +// returns true if map is empty or does not exist +bool LLSecAPIBasicHandler::emptyCredentialMap(const std::string& storage, const std::string& grid) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD credential = getProtectedData(storage, grid); + + return !credential.isMap() || credential.size() == 0; +} + +// Load map of credentials from specified credential store, given the grid +void LLSecAPIBasicHandler::loadCredentialMap(const std::string& storage, const std::string& grid, credential_map_t& credential_map) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD credential = getProtectedData(storage, grid); + if (credential.isMap()) + { + LLSD::map_const_iterator crd_it = credential.beginMap(); + for (; crd_it != credential.endMap(); crd_it++) + { + LLSD::String name = crd_it->first; + const LLSD &link_map = crd_it->second; + LLPointer<LLSecAPIBasicCredential> result = new LLSecAPIBasicCredential(grid); + if (link_map.has("identifier")) + { + LLSD identifier = link_map["identifier"]; + LLSD authenticator; + if (link_map.has("authenticator")) + { + authenticator = link_map["authenticator"]; + } + result->setCredentialData(identifier, authenticator); + } + credential_map[name] = result; + } + } +} + +LLPointer<LLCredential> LLSecAPIBasicHandler::loadFromCredentialMap(const std::string& storage, const std::string& grid, const std::string& userkey) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLPointer<LLSecAPIBasicCredential> result = new LLSecAPIBasicCredential(grid); + + LLSD credential = getProtectedData(storage, grid); + if (credential.isMap() && credential.has(userkey) && credential[userkey].has("identifier")) + { + LLSD identifier = credential[userkey]["identifier"]; + LLSD authenticator; + if (credential[userkey].has("authenticator")) + { + authenticator = credential[userkey]["authenticator"]; + } + result->setCredentialData(identifier, authenticator); + } + + return result; +} + +// add item to map of credentials from specific storage +void LLSecAPIBasicHandler::addToCredentialMap(const std::string& storage, LLPointer<LLCredential> cred, bool save_authenticator) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + std::string user_id = cred->userID(); + LLSD credential = LLSD::emptyMap(); + credential["identifier"] = cred->getIdentifier(); + if (save_authenticator) + { + credential["authenticator"] = cred->getAuthenticator(); + } + LL_DEBUGS("SECAPI") << "Saving Credential " << cred->getGrid() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL; + addToProtectedMap(storage, cred->getGrid(), user_id, credential); + + _writeProtectedData(); +} + +// remove item from map of credentials from specific storage +void LLSecAPIBasicHandler::removeFromCredentialMap(const std::string& storage, LLPointer<LLCredential> cred) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD undefVal; + removeFromProtectedMap(storage, cred->getGrid(), cred->userID()); + cred->setCredentialData(undefVal, undefVal); + _writeProtectedData(); +} + +// remove item from map of credentials from specific storage +void LLSecAPIBasicHandler::removeFromCredentialMap(const std::string& storage, const std::string& grid, const std::string& userkey) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD undefVal; + LLPointer<LLCredential> cred = loadFromCredentialMap(storage, grid, userkey); + removeFromProtectedMap(storage, grid, userkey); + cred->setCredentialData(undefVal, undefVal); + _writeProtectedData(); +} + +// remove item from map of credentials from specific storage +void LLSecAPIBasicHandler::removeCredentialMap(const std::string& storage, const std::string& grid) +{ + deleteProtectedData(storage, grid); + _writeProtectedData(); +} + // load the legacy hash for agni, and decrypt it given the // mac address std::string LLSecAPIBasicHandler::_legacyLoadPassword() @@ -1656,15 +1848,18 @@ std::string LLSecAPIBasicCredential::userID() const } else if ((std::string)mIdentifier["type"] == "agent") { - return (std::string)mIdentifier["first_name"] + "_" + (std::string)mIdentifier["last_name"]; + std::string id = (std::string)mIdentifier["first_name"] + "_" + (std::string)mIdentifier["last_name"]; + LLStringUtil::toLower(id); + return id; } else if ((std::string)mIdentifier["type"] == "account") { - return (std::string)mIdentifier["account_name"]; + std::string id = (std::string)mIdentifier["account_name"]; + LLStringUtil::toLower(id); + return id; } return "unknown"; - } // return a printable user identifier diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h index c35617f564..82670f9083 100644 --- a/indra/newview/llsechandler_basic.h +++ b/indra/newview/llsechandler_basic.h @@ -197,7 +197,7 @@ class LLBasicCertificateChain : virtual public LLBasicCertificateVector, public { public: - LLBasicCertificateChain(const X509_STORE_CTX * store); + LLBasicCertificateChain(X509_STORE_CTX * store); virtual ~LLBasicCertificateChain() {} @@ -211,8 +211,9 @@ class LLSecAPIBasicCredential : public LLCredential public: LLSecAPIBasicCredential(const std::string& grid) : LLCredential(grid) {} virtual ~LLSecAPIBasicCredential() {} - // return a value representing the user id, (could be guid, name, whatever) - virtual std::string userID() const; + // return a value representing the user id, used for server and voice + // (could be guid, name in format "name_resident", whatever) + virtual std::string userID() const; // printible string identifying the credential. virtual std::string asString() const; @@ -240,13 +241,16 @@ public: virtual LLPointer<LLCertificate> getCertificate(X509* openssl_cert); // instantiate a chain from an X509_STORE_CTX - virtual LLPointer<LLCertificateChain> getCertificateChain(const X509_STORE_CTX* chain); + virtual LLPointer<LLCertificateChain> getCertificateChain(X509_STORE_CTX* chain); // instantiate a cert store given it's id. if a persisted version // exists, it'll be loaded. If not, one will be created (but not // persisted) virtual LLPointer<LLCertificateStore> getCertificateStore(const std::string& store_id); - + + // protectedData functions technically should be pretected or private, + // they are not because of llsechandler_basic_test imlementation + // persist data in a protected store virtual void setProtectedData(const std::string& data_type, const std::string& data_id, @@ -259,19 +263,68 @@ public: // delete a protected data item from the store virtual void deleteProtectedData(const std::string& data_type, const std::string& data_id); - + + // persist data in a protected store's map + virtual void addToProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem, + const LLSD& data); + + // remove data from protected store's map + virtual void removeFromProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem); + // credential management routines virtual LLPointer<LLCredential> createCredential(const std::string& grid, const LLSD& identifier, const LLSD& authenticator); - + + // load single credencial from default storage virtual LLPointer<LLCredential> loadCredential(const std::string& grid); + // save credencial to default storage virtual void saveCredential(LLPointer<LLCredential> cred, bool save_authenticator); virtual void deleteCredential(LLPointer<LLCredential> cred); - + + // has map of credentials declared as specific storage + virtual bool hasCredentialMap(const std::string& storage, + const std::string& grid); + + // returns true if map is empty or does not exist + virtual bool emptyCredentialMap(const std::string& storage, + const std::string& grid); + + // load map of credentials from specific storage + virtual void loadCredentialMap(const std::string& storage, + const std::string& grid, + credential_map_t& credential_map); + + // load single username from map of credentials from specific storage + virtual LLPointer<LLCredential> loadFromCredentialMap(const std::string& storage, + const std::string& grid, + const std::string& userid); + + // add item to map of credentials from specific storage + virtual void addToCredentialMap(const std::string& storage, + LLPointer<LLCredential> cred, + bool save_authenticator); + + // remove item from map of credentials from specific storage + virtual void removeFromCredentialMap(const std::string& storage, + LLPointer<LLCredential> cred); + + // remove item from map of credentials from specific storage + virtual void removeFromCredentialMap(const std::string& storage, + const std::string& grid, + const std::string& userid); + + virtual void removeCredentialMap(const std::string& storage, + const std::string& grid); + + protected: void _readProtectedData(); void _writeProtectedData(); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 90f8f84ea4..50884762a8 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -35,7 +35,6 @@ #include "llcachename.h" #include "llavatarnamecache.h" #include "lldbstrings.h" -#include "lleconomy.h" #include "llgl.h" #include "llmediaentry.h" #include "llrender.h" @@ -153,6 +152,53 @@ struct LLDeRezInfo // Imports // +//----------------------------------------------------------------------------- +// ~LLSelectionCallbackData() +//----------------------------------------------------------------------------- + +LLSelectionCallbackData::LLSelectionCallbackData() +{ + LLSelectMgr *instance = LLSelectMgr::getInstance(); + LLObjectSelectionHandle selection = instance->getSelection(); + if (!selection->getNumNodes()) + { + return; + } + mSelectedObjects = new LLObjectSelection(); + + for (LLObjectSelection::iterator iter = selection->begin(); + iter != selection->end();) + { + LLObjectSelection::iterator curiter = iter++; + + LLSelectNode *nodep = *curiter; + LLViewerObject* objectp = nodep->getObject(); + + if (!objectp) + { + mSelectedObjects->mSelectType = SELECT_TYPE_WORLD; + } + else + { + LLSelectNode* new_nodep = new LLSelectNode(*nodep); + mSelectedObjects->addNode(new_nodep); + + if (objectp->isHUDAttachment()) + { + mSelectedObjects->mSelectType = SELECT_TYPE_HUD; + } + else if (objectp->isAttachment()) + { + mSelectedObjects->mSelectType = SELECT_TYPE_ATTACHMENT; + } + else + { + mSelectedObjects->mSelectType = SELECT_TYPE_WORLD; + } + } + } +} + // // Functions @@ -257,6 +303,27 @@ void LLSelectMgr::updateEffects() } } +void LLSelectMgr::resetObjectOverrides() +{ + resetObjectOverrides(getSelection()); +} + +void LLSelectMgr::resetObjectOverrides(LLObjectSelectionHandle selected_handle) +{ + struct f : public LLSelectedNodeFunctor + { + virtual bool apply(LLSelectNode* node) + { + node->mLastPositionLocal.setVec(0, 0, 0); + node->mLastRotation = LLQuaternion(); + node->mLastScale.setVec(0, 0, 0); + return true; + } + } func; + + selected_handle->applyToNodes(&func); +} + void LLSelectMgr::overrideObjectUpdates() { //override any position updates from simulator on objects being edited @@ -3864,11 +3931,11 @@ BOOL LLSelectMgr::selectGetAggregateTexturePermissions(LLAggregatePermissions& r return TRUE; } -BOOL LLSelectMgr::isSelfAvatarSelected() +BOOL LLSelectMgr::isMovableAvatarSelected() { if (mAllowSelectAvatar) { - return (getSelection()->getObjectCount() == 1) && (getSelection()->getFirstRootObject() == gAgentAvatarp); + return (getSelection()->getObjectCount() == 1) && (getSelection()->getFirstRootObject()->isAvatar()) && getSelection()->getFirstMoveableNode(TRUE); } return FALSE; } @@ -4119,20 +4186,20 @@ void LLSelectMgr::packMultipleUpdate(LLSelectNode* node, void *user_data) if (type & UPD_POSITION) { - htonmemcpy(&data[offset], &(object->getPosition().mV), MVT_LLVector3, 12); + htolememcpy(&data[offset], &(object->getPosition().mV), MVT_LLVector3, 12); offset += 12; } if (type & UPD_ROTATION) { LLQuaternion quat = object->getRotation(); LLVector3 vec = quat.packToVector3(); - htonmemcpy(&data[offset], &(vec.mV), MVT_LLQuaternion, 12); + htolememcpy(&data[offset], &(vec.mV), MVT_LLQuaternion, 12); offset += 12; } if (type & UPD_SCALE) { //LL_INFOS() << "Sending object scale " << object->getScale() << LL_ENDL; - htonmemcpy(&data[offset], &(object->getScale().mV), MVT_LLVector3, 12); + htolememcpy(&data[offset], &(object->getScale().mV), MVT_LLVector3, 12); offset += 12; } gMessageSystem->addBinaryDataFast(_PREHASH_Data, data, offset); @@ -4475,9 +4542,19 @@ void LLSelectMgr::selectionSetObjectSaleInfo(const LLSaleInfo& sale_info) void LLSelectMgr::sendAttach(U8 attachment_point, bool replace) { - LLViewerObject* attach_object = mSelectedObjects->getFirstRootObject(); + sendAttach(mSelectedObjects, attachment_point, replace); +} - if (!attach_object || !isAgentAvatarValid() || mSelectedObjects->mSelectType != SELECT_TYPE_WORLD) +void LLSelectMgr::sendAttach(LLObjectSelectionHandle selection_handle, U8 attachment_point, bool replace) +{ + if (selection_handle.isNull()) + { + return; + } + + LLViewerObject* attach_object = selection_handle->getFirstRootObject(); + + if (!attach_object || !isAgentAvatarValid() || selection_handle->mSelectType != SELECT_TYPE_WORLD) { return; } @@ -4495,6 +4572,7 @@ void LLSelectMgr::sendAttach(U8 attachment_point, bool replace) } sendListToRegions( + selection_handle, "ObjectAttach", packAgentIDAndSessionAndAttachment, packObjectIDAndRotation, @@ -4506,6 +4584,7 @@ void LLSelectMgr::sendAttach(U8 attachment_point, bool replace) // 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 + // Still unsubscribe even in case selection_handle is not current selection deselectAll(); } } @@ -5047,7 +5126,17 @@ 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 (*log_func)(LLSelectNode* node, void *user_data), + void *user_data, + ESendType send_type) +{ + sendListToRegions(mSelectedObjects, message_name, pack_header, pack_body, log_func, user_data, send_type); +} +void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle, + 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) { @@ -5062,18 +5151,27 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name, bool link_operation = message_name == "ObjectLink"; - //clear update override data (allow next update through) - struct f : public LLSelectedNodeFunctor - { - virtual bool apply(LLSelectNode* node) - { - node->mLastPositionLocal.setVec(0,0,0); - node->mLastRotation = LLQuaternion(); - node->mLastScale.setVec(0,0,0); - return true; - } - } func; - getSelection()->applyToNodes(&func); + if (mAllowSelectAvatar) + { + if (selected_handle->getObjectCount() == 1 + && selected_handle->getFirstObject() != NULL + && selected_handle->getFirstObject()->isAvatar()) + { + // Server doesn't move avatars at the moment, it is a local debug feature, + // but server does update position regularly, so do not drop mLastPositionLocal + // Position override for avatar gets reset in LLAgentCamera::resetView(). + } + else + { + // drop mLastPositionLocal (allow next update through) + resetObjectOverrides(selected_handle); + } + } + else + { + //clear update override data (allow next update through) + resetObjectOverrides(selected_handle); + } std::queue<LLSelectNode*> nodes_to_send; @@ -5116,25 +5214,25 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name, { case SEND_ONLY_ROOTS: if(message_name == "ObjectBuy") - getSelection()->applyToRootNodes(&pushroots); + selected_handle->applyToRootNodes(&pushroots); else - getSelection()->applyToRootNodes(&pushall); + selected_handle->applyToRootNodes(&pushall); break; case SEND_INDIVIDUALS: - getSelection()->applyToNodes(&pushall); + selected_handle->applyToNodes(&pushall); break; case SEND_ROOTS_FIRST: // first roots... - getSelection()->applyToNodes(&pushroots); + selected_handle->applyToNodes(&pushroots); // then children... - getSelection()->applyToNodes(&pushnonroots); + selected_handle->applyToNodes(&pushnonroots); break; case SEND_CHILDREN_FIRST: // first children... - getSelection()->applyToNodes(&pushnonroots); + selected_handle->applyToNodes(&pushnonroots); // then roots... - getSelection()->applyToNodes(&pushroots); + selected_handle->applyToNodes(&pushroots); break; default: @@ -5357,7 +5455,7 @@ void LLSelectMgr::processObjectProperties(LLMessageSystem* msg, void** user_data } else { - if (node->mInventorySerial != inv_serial) + if (node->mInventorySerial != inv_serial && node->getObject()) { node->getObject()->dirtyInventory(); } @@ -6686,8 +6784,7 @@ void LLSelectMgr::updateSelectionCenter() if (mSelectedObjects->mSelectType != SELECT_TYPE_HUD && isAgentAvatarValid()) { // reset hud ZOOM - gAgentCamera.mHUDTargetZoom = 1.f; - gAgentCamera.mHUDCurZoom = 1.f; + resetAgentHUDZoom(); } mShowSelection = FALSE; @@ -6784,51 +6881,26 @@ void LLSelectMgr::pauseAssociatedAvatars() mSelectedObjects->mSelectType = getSelectTypeForObject(object); - bool is_attached = false; - if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT && - isAgentAvatarValid()) + LLVOAvatar* parent_av = NULL; + if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT) { // Selection can be obsolete, confirm that this is an attachment - LLViewerObject* parent = (LLViewerObject*)object->getParent(); - while (parent != NULL) - { - if (parent->isAvatar()) - { - is_attached = true; - break; - } - else - { - parent = (LLViewerObject*)parent->getParent(); - } - } + // and find parent avatar + parent_av = object->getAvatarAncestor(); } - - if (is_attached) + // Can be both an attachment and animated object + if (parent_av) { - if (object->isAnimatedObject()) - { - // Is an animated object attachment. - // Pause both the control avatar and the avatar it's attached to. - if (object->getControlAvatar()) - { - mPauseRequests.push_back(object->getControlAvatar()->requestPause()); - } - mPauseRequests.push_back(gAgentAvatarp->requestPause()); - } - else - { - // Is a regular attachment. Pause the avatar it's attached to. - mPauseRequests.push_back(gAgentAvatarp->requestPause()); - } + // It's an attachment. Pause the avatar it's attached to. + mPauseRequests.push_back(parent_av->requestPause()); } - else if (object && object->isAnimatedObject() && object->getControlAvatar()) + + if (object->isAnimatedObject() && object->getControlAvatar()) { - // Is a non-attached animated object. Pause the control avatar. + // It's an animated object. Pause the control avatar. mPauseRequests.push_back(object->getControlAvatar()->requestPause()); } - } } @@ -7060,8 +7132,11 @@ BOOL LLSelectMgr::setForceSelection(BOOL force) void LLSelectMgr::resetAgentHUDZoom() { - gAgentCamera.mHUDTargetZoom = 1.f; - gAgentCamera.mHUDCurZoom = 1.f; + if (gAgentCamera.mHUDTargetZoom != 1) + { + gAgentCamera.mHUDTargetZoom = 1.f; + gAgentCamera.mHUDCurZoom = 1.f; + } } void LLSelectMgr::getAgentHUDZoom(F32 &target_zoom, F32 ¤t_zoom) const diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 3e8bfdb00e..57fdfce152 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -239,6 +239,7 @@ class LLObjectSelection : public LLRefCount { friend class LLSelectMgr; friend class LLSafeHandle<LLObjectSelection>; + friend class LLSelectionCallbackData; protected: ~LLObjectSelection(); @@ -396,6 +397,16 @@ extern template class LLSelectMgr* LLSingleton<class LLSelectMgr>::getInstance() // For use with getFirstTest() struct LLSelectGetFirstTest; +// temporary storage, Ex: to attach objects after autopilot +class LLSelectionCallbackData +{ +public: + LLSelectionCallbackData(); + LLObjectSelectionHandle getSelection() { return mSelectedObjects; } +private: + LLObjectSelectionHandle mSelectedObjects; +}; + class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr> { LLSINGLETON(LLSelectMgr); @@ -447,6 +458,13 @@ public: void clearSelections(); void update(); void updateEffects(); // Update HUD effects + + // When we edit object's position/rotation/scale we set local + // overrides and ignore any updates (override received valeus). + // When we send data to server, we send local values and reset + // overrides + void resetObjectOverrides(); + void resetObjectOverrides(LLObjectSelectionHandle selected_handle); void overrideObjectUpdates(); // Returns the previous value of mForceSelection @@ -714,7 +732,7 @@ public: LLPermissions* findObjectPermissions(const LLViewerObject* object); - BOOL isSelfAvatarSelected(); + BOOL isMovableAvatarSelected(); void selectDelete(); // Delete on simulator void selectForceDelete(); // just delete, no into trash @@ -740,6 +758,7 @@ public: // canceled void sendBuy(const LLUUID& buyer_id, const LLUUID& category_id, const LLSaleInfo sale_info); void sendAttach(U8 attachment_point, bool replace); + void sendAttach(LLObjectSelectionHandle selection_handle, U8 attachment_point, bool replace); void sendDetach(); void sendDropAttachment(); void sendLink(); @@ -787,6 +806,13 @@ private: void (*log_func)(LLSelectNode* node, void *user_data), void *user_data, ESendType send_type); + void sendListToRegions( LLObjectSelectionHandle selected_handle, + 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); static void packAgentID( void *); diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp new file mode 100644 index 0000000000..4b36822e9a --- /dev/null +++ b/indra/newview/llsetkeybinddialog.cpp @@ -0,0 +1,380 @@ +/** + * @file llsetkeybinddialog.cpp + * @brief LLSetKeyBindDialog class implementation. + * + * $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 "llsetkeybinddialog.h" + +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "lleventtimer.h" +#include "llfloaterreg.h" +#include "llfocusmgr.h" +#include "llkeyconflict.h" +#include "llviewercontrol.h" + +class LLSetKeyBindDialog::Updater : public LLEventTimer +{ +public: + + typedef boost::function<void(MASK)> callback_t; + + Updater(callback_t cb, F32 period, MASK mask) + :LLEventTimer(period), + mMask(mask), + mCallback(cb) + { + mEventTimer.start(); + } + + virtual ~Updater(){} + +protected: + BOOL tick() + { + mCallback(mMask); + // Deletes itseft after execution + return TRUE; + } + +private: + MASK mMask; + callback_t mCallback; +}; + +bool LLSetKeyBindDialog::sRecordKeys = false; + +LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key) + : LLModalDialog(key), + pParent(NULL), + mKeyFilterMask(DEFAULT_KEY_FILTER), + pUpdater(NULL), + mLastMaskKey(0), + mContextConeOpacity(0.f), + mContextConeInAlpha(0.f), + mContextConeOutAlpha(0.f), + mContextConeFadeTime(0.f) +{ + mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha"); + mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha"); + mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime"); +} + +LLSetKeyBindDialog::~LLSetKeyBindDialog() +{ +} + +//virtual +BOOL LLSetKeyBindDialog::postBuild() +{ + childSetAction("SetEmpty", onBlank, this); + childSetAction("Default", onDefault, this); + childSetAction("Cancel", onCancel, this); + getChild<LLUICtrl>("Cancel")->setFocus(TRUE); + + pCheckBox = getChild<LLCheckBoxCtrl>("apply_all"); + pDesription = getChild<LLTextBase>("descritption"); + + gFocusMgr.setKeystrokesOnly(TRUE); + + return TRUE; +} + +//virtual +void LLSetKeyBindDialog::onOpen(const LLSD& data) +{ + sRecordKeys = true; + LLModalDialog::onOpen(data); +} + +//virtual +void LLSetKeyBindDialog::onClose(bool app_quiting) +{ + sRecordKeys = false; + if (pParent) + { + pParent->onCancelKeyBind(); + pParent = NULL; + } + if (pUpdater) + { + // Doubleclick timer has't fired, delete it + delete pUpdater; + pUpdater = NULL; + } + LLModalDialog::onClose(app_quiting); +} + +void LLSetKeyBindDialog::drawFrustum() +{ + static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f); + drawConeToOwner(mContextConeOpacity, max_opacity, mFrustumOrigin.get(), mContextConeFadeTime, mContextConeInAlpha, mContextConeOutAlpha); +} + +//virtual +void LLSetKeyBindDialog::draw() +{ + drawFrustum(); + LLModalDialog::draw(); +} + +void LLSetKeyBindDialog::setParent(LLKeyBindResponderInterface* parent, LLView* frustum_origin, U32 key_mask) +{ + pParent = parent; + mFrustumOrigin = frustum_origin->getHandle(); + mKeyFilterMask = key_mask; + + std::string input; + if ((key_mask & ALLOW_MOUSE) != 0) + { + input = getString("mouse"); + } + if ((key_mask & ALLOW_KEYS) != 0) + { + if (!input.empty()) + { + input += ", "; + } + input += getString("keyboard"); + } + pDesription->setText(getString("basic_description")); + pDesription->setTextArg("[INPUT]", input); +} + +// static +bool LLSetKeyBindDialog::recordKey(KEY key, MASK mask, BOOL down) +{ + if (sRecordKeys) + { + LLSetKeyBindDialog* dialog = LLFloaterReg::getTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD()); + if (dialog && dialog->getVisible()) + { + return dialog->recordAndHandleKey(key, mask, down); + } + else + { + LL_WARNS() << "Key recording was set despite no open dialog" << LL_ENDL; + sRecordKeys = false; + } + } + return false; +} + +bool LLSetKeyBindDialog::recordAndHandleKey(KEY key, MASK mask, BOOL down) +{ + if ((key == 'Q' && mask == MASK_CONTROL) + || key == KEY_ESCAPE) + { + sRecordKeys = false; + closeFloater(); + return true; + } + + if (key == KEY_DELETE) + { + setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false); + sRecordKeys = false; + closeFloater(); + return false; + } + + // forbidden keys + if (key == KEY_NONE + || key == KEY_RETURN + || key == KEY_BACKSPACE) + { + return false; + } + + if (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT) + { + // Mask keys get special treatment + if ((mKeyFilterMask & ALLOW_MASKS) == 0) + { + // Masks by themself are not allowed + return false; + } + if (down == TRUE) + { + // Most keys are handled on 'down' event because menu is handled on 'down' + // masks are exceptions to let other keys be handled + mLastMaskKey = key; + return false; + } + if (mLastMaskKey != key) + { + // This was mask+key combination that got rejected, don't handle mask's key + // Or user did something like: press shift, press ctrl, release shift + return false; + } + // Mask up event often generates things like 'shift key + shift mask', filter it out. + if (key == KEY_CONTROL) + { + mask &= ~MASK_CONTROL; + } + if (key == KEY_SHIFT) + { + mask &= ~MASK_SHIFT; + } + if (key == KEY_ALT) + { + mask &= ~MASK_ALT; + } + } + if ((mKeyFilterMask & ALLOW_KEYS) == 0) + { + // basic keys not allowed + return false; + } + else if ((mKeyFilterMask & ALLOW_MASK_KEYS) == 0 && mask != 0) + { + // masked keys not allowed + return false; + } + + if (LLKeyConflictHandler::isReservedByMenu(key, mask)) + { + pDesription->setText(getString("reserved_by_menu")); + pDesription->setTextArg("[KEYSTR]", LLKeyboard::stringFromAccelerator(mask,key)); + mLastMaskKey = 0; + return true; + } + + setKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean()); + // Note/Todo: To warranty zero interference we should also consume + // an 'up' event if we recorded on 'down', not just close floater + // on first recorded combination. + sRecordKeys = false; + closeFloater(); + return true; +} + +BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) +{ + BOOL result = FALSE; + if (!pParent) + { + // we already processed 'down' event, this is 'up', consume + closeFloater(); + result = TRUE; + } + if (!result && clicktype == CLICK_LEFT) + { + // try handling buttons first + if (down) + { + result = LLView::handleMouseDown(x, y, mask); + } + else + { + result = LLView::handleMouseUp(x, y, mask); + } + if (result) + { + setFocus(TRUE); + gFocusMgr.setKeystrokesOnly(TRUE); + } + // ignore selection related combinations + else if (down && (mask & (MASK_SHIFT | MASK_CONTROL)) == 0) + { + // this can be a double click, wait a bit; + if (!pUpdater) + { + // Note: default doubleclick time is 500ms, but can stretch up to 5s + pUpdater = new Updater(boost::bind(&onClickTimeout, this, _1), 0.7f, mask); + result = TRUE; + } + } + } + + if (!result + && (clicktype != CLICK_LEFT) // subcases were handled above + && ((mKeyFilterMask & ALLOW_MOUSE) != 0) + && (clicktype != CLICK_RIGHT || mask != 0) // reassigning menu button is not supported + && ((mKeyFilterMask & ALLOW_MASK_MOUSE) != 0 || mask == 0)) // reserved for selection + { + setKeyBind(clicktype, KEY_NONE, mask, pCheckBox->getValue().asBoolean()); + result = TRUE; + if (!down) + { + // wait for 'up' event before closing + // alternative: set pUpdater + closeFloater(); + } + } + + return result; +} + +//static +void LLSetKeyBindDialog::onCancel(void* user_data) +{ + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; + self->closeFloater(); +} + +//static +void LLSetKeyBindDialog::onBlank(void* user_data) +{ + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; + // tmp needs 'no key' button + self->setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false); + self->closeFloater(); +} + +//static +void LLSetKeyBindDialog::onDefault(void* user_data) +{ + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; + if (self->pParent) + { + self->pParent->onDefaultKeyBind(self->pCheckBox->getValue().asBoolean()); + self->pParent = NULL; + } + self->closeFloater(); +} + +//static +void LLSetKeyBindDialog::onClickTimeout(void* user_data, MASK mask) +{ + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; + + // timer will delete itself after timeout + self->pUpdater = NULL; + + self->setKeyBind(CLICK_LEFT, KEY_NONE, mask, self->pCheckBox->getValue().asBoolean()); + self->closeFloater(); +} + +void LLSetKeyBindDialog::setKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes) +{ + if (pParent) + { + pParent->onSetKeyBind(click, key, mask, all_modes); + pParent = NULL; + } +} + diff --git a/indra/newview/llsetkeybinddialog.h b/indra/newview/llsetkeybinddialog.h new file mode 100644 index 0000000000..a34b952233 --- /dev/null +++ b/indra/newview/llsetkeybinddialog.h @@ -0,0 +1,106 @@ +/** + * @file llsetkeybinddialog.h + * @brief LLSetKeyBindDialog class definition + * + * $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_LLSETKEYBINDDIALOG_H +#define LL_LLSETKEYBINDDIALOG_H + +#include "llmodaldialog.h" + +class LLCheckBoxCtrl; +class LLTextBase; + +// Filters for LLSetKeyBindDialog +static const U32 ALLOW_MOUSE = 1; +static const U32 ALLOW_MASK_MOUSE = 2; +static const U32 ALLOW_KEYS = 4; //keyboard +static const U32 ALLOW_MASK_KEYS = 8; +static const U32 ALLOW_MASKS = 16; +static const U32 DEFAULT_KEY_FILTER = ALLOW_MOUSE | ALLOW_MASK_MOUSE | ALLOW_KEYS | ALLOW_MASKS | ALLOW_MASK_KEYS; + + +class LLKeyBindResponderInterface +{ +public: + virtual ~LLKeyBindResponderInterface() {}; + + virtual void onCancelKeyBind() = 0; + virtual void onDefaultKeyBind(bool all_modes) = 0; + // returns true if parent failed to set key due to key being in use + virtual bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes) = 0; +}; + +class LLSetKeyBindDialog : public LLModalDialog +{ +public: + LLSetKeyBindDialog(const LLSD& key); + ~LLSetKeyBindDialog(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& data); + /*virtual*/ void onClose(bool app_quiting); + /*virtual*/ void draw(); + + void setParent(LLKeyBindResponderInterface* parent, LLView* frustum_origin, U32 key_mask = DEFAULT_KEY_FILTER); + + // Wrapper around recordAndHandleKey + // It does not record, it handles, but handleKey function is already in use + static bool recordKey(KEY key, MASK mask, BOOL down); + + BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); + static void onCancel(void* user_data); + static void onBlank(void* user_data); + static void onDefault(void* user_data); + static void onClickTimeout(void* user_data, MASK mask); + + class Updater; + +private: + bool recordAndHandleKey(KEY key, MASK mask, BOOL down); + void setKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes); + LLKeyBindResponderInterface *pParent; + LLCheckBoxCtrl *pCheckBox; + LLTextBase *pDesription; + + U32 mKeyFilterMask; + Updater *pUpdater; + KEY mLastMaskKey; + + static bool sRecordKeys; // for convinience and not to check instance each time + + // drawFrustum +private: + void drawFrustum(); + + LLHandle <LLView> mFrustumOrigin; + F32 mContextConeOpacity; + F32 mContextConeInAlpha; + F32 mContextConeOutAlpha; + F32 mContextConeFadeTime; +}; + + +#endif // LL_LLSETKEYBINDDIALOG_H diff --git a/indra/newview/llsettingspicker.cpp b/indra/newview/llsettingspicker.cpp new file mode 100644 index 0000000000..d2d21063e7 --- /dev/null +++ b/indra/newview/llsettingspicker.cpp @@ -0,0 +1,509 @@ +/** +* @author Rider Linden +* @brief LLSettingsPicker class header file including related functions +* +* $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 "llviewerprecompiledheaders.h" + +#include "llsettingspicker.h" + +#include "llcombobox.h" +#include "llfiltereditor.h" +#include "llfolderviewmodel.h" +#include "llinventory.h" +#include "llinventorybridge.h" +#include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llinventoryobserver.h" +#include "llinventorypanel.h" +#include "llsettingsvo.h" + +#include "lldraghandle.h" +#include "llviewercontrol.h" +#include "llagent.h" + +//========================================================================= +namespace +{ + const std::string FLOATER_DEFINITION_XML("floater_settings_picker.xml"); + + const std::string FLT_INVENTORY_SEARCH("flt_inventory_search"); + const std::string CMB_TRACK_SELECTION("track_selection"); + const std::string PNL_INVENTORY("pnl_inventory"); + const std::string PNL_COMBO("pnl_combo"); + const std::string BTN_SELECT("btn_select"); + const std::string BTN_CANCEL("btn_cancel"); + + // strings in xml + + const std::string STR_TITLE_PREFIX = "pick title"; + const std::string STR_TITLE_TRACK = "pick_track"; + const std::string STR_TITLE_SETTINGS = "pick_settings"; + const std::string STR_TRACK_WATER = "track_water"; + const std::string STR_TRACK_GROUND = "track_ground"; + const std::string STR_TRACK_SKY = "track_sky"; +} +//========================================================================= + +LLFloaterSettingsPicker::LLFloaterSettingsPicker(LLView * owner, LLUUID initial_item_id, const LLSD ¶ms): + LLFloater(params), + mOwnerHandle(), + mActive(true), + mContextConeOpacity(0.0f), + mSettingItemID(initial_item_id), + mTrackMode(TRACK_NONE), + mImmediateFilterPermMask(PERM_NONE) +{ + mOwnerHandle = owner->getHandle(); + + buildFromFile(FLOATER_DEFINITION_XML); + setCanMinimize(FALSE); +} + + +LLFloaterSettingsPicker::~LLFloaterSettingsPicker() +{ + +} + +//------------------------------------------------------------------------- +BOOL LLFloaterSettingsPicker::postBuild() +{ + if (!LLFloater::postBuild()) + return FALSE; + + std::string prefix = getString(STR_TITLE_PREFIX); + std::string label = getString(STR_TITLE_SETTINGS); + setTitle(prefix + " " + label); + + mFilterEdit = getChild<LLFilterEditor>(FLT_INVENTORY_SEARCH); + mFilterEdit->setCommitCallback([this](LLUICtrl*, const LLSD& param){ onFilterEdit(param.asString()); }); + + mInventoryPanel = getChild<LLInventoryPanel>(PNL_INVENTORY); + if (mInventoryPanel) + { + U32 filter_types = 0x0; + filter_types |= 0x1 << LLInventoryType::IT_SETTINGS; + + mInventoryPanel->setFilterTypes(filter_types); + mInventoryPanel->setFilterPermMask(mImmediateFilterPermMask); + + mInventoryPanel->setSelectCallback([this](const LLFloaterSettingsPicker::itemlist_t &items, bool useraction){ onSelectionChange(items, useraction); }); + mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); + mInventoryPanel->setSuppressOpenItemAction(true); + + // Disable auto selecting first filtered item because it takes away + // selection from the item set by LLTextureCtrl owning this floater. + mInventoryPanel->getRootFolder()->setAutoSelectOverride(TRUE); + + // don't put keyboard focus on selected item, because the selection callback + // will assume that this was user input + if (!mSettingItemID.isNull()) + { + //todo: this is bad idea + mInventoryPanel->setSelection(mSettingItemID, TAKE_FOCUS_NO); + } + getChild<LLView>(BTN_SELECT)->setEnabled(mSettingItemID.notNull()); + } + + mNoCopySettingsSelected = FALSE; + + childSetAction(BTN_CANCEL, [this](LLUICtrl*, const LLSD& param){ onButtonCancel(); }); + childSetAction(BTN_SELECT, [this](LLUICtrl*, const LLSD& param){ onButtonSelect(); }); + + getChild<LLPanel>(PNL_COMBO)->setVisible(mTrackMode != TRACK_NONE); + + // update permission filter once UI is fully initialized + mSavedFolderState.setApply(FALSE); + + return TRUE; +} + +void LLFloaterSettingsPicker::onClose(bool app_quitting) +{ + if (app_quitting) + return; + + mCloseSignal(); + LLView *owner = mOwnerHandle.get(); + if (owner) + { + owner->setFocus(TRUE); + } + mSettingItemID.setNull(); + mInventoryPanel->getRootFolder()->clearSelection(); +} + +void LLFloaterSettingsPicker::setValue(const LLSD& value) +{ + mSettingItemID = value.asUUID(); +} + +LLSD LLFloaterSettingsPicker::getValue() const +{ + return LLSD(mSettingItemID); +} + +void LLFloaterSettingsPicker::setSettingsFilter(LLSettingsType::type_e type) +{ + U64 filter = 0xFFFFFFFFFFFFFFFF; + if (type != LLSettingsType::ST_NONE) + { + filter = static_cast<S64>(0x1) << static_cast<S64>(type); + } + + mInventoryPanel->setFilterSettingsTypes(filter); +} + +void LLFloaterSettingsPicker::setTrackMode(ETrackMode mode) +{ + mTrackMode = mode; + getChild<LLPanel>(PNL_COMBO)->setVisible(mode != TRACK_NONE); + + std::string prefix = getString(STR_TITLE_PREFIX); + std::string label; + if (mode != TRACK_NONE) + { + label = getString(STR_TITLE_TRACK); + } + else + { + label = getString(STR_TITLE_SETTINGS); + } + setTitle(prefix + " " + label); +} + +void LLFloaterSettingsPicker::draw() +{ + LLView *owner = mOwnerHandle.get(); + static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f); + drawConeToOwner(mContextConeOpacity, max_opacity, owner); + + LLFloater::draw(); +} + + +//========================================================================= +void LLFloaterSettingsPicker::onFilterEdit(const std::string& search_string) +{ + 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; + } + + 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->getFilter().isNotDefault()) + { + mSavedFolderState.setApply(FALSE); + mInventoryPanel->getRootFolder()->applyFunctorRecursively(mSavedFolderState); + } + } + + mInventoryPanel->setFilterSubString(search_string); +} + +void LLFloaterSettingsPicker::onSelectionChange(const LLFloaterSettingsPicker::itemlist_t &items, bool user_action) +{ + bool is_item = false; + LLUUID asset_id; + if (items.size()) + { + LLFolderViewItem* first_item = items.front(); + + mNoCopySettingsSelected = false; + if (first_item) + { + LLItemBridge *bridge_model = dynamic_cast<LLItemBridge *>(first_item->getViewModelItem()); + if (bridge_model && bridge_model->getItem()) + { + if (!bridge_model->isItemCopyable()) + { + mNoCopySettingsSelected = true; + } + setSettingsItemId(bridge_model->getItem()->getUUID(), false); + asset_id = bridge_model->getItem()->getAssetUUID(); + mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here? + is_item = true; + + if (user_action) + { + mChangeIDSignal(mSettingItemID); + } + } + } + } + bool track_picker_enabled = mTrackMode != TRACK_NONE; + + getChild<LLView>(CMB_TRACK_SELECTION)->setEnabled(is_item && track_picker_enabled && mSettingAssetID == asset_id); + getChild<LLView>(BTN_SELECT)->setEnabled(is_item && (!track_picker_enabled || mSettingAssetID == asset_id)); + if (track_picker_enabled && asset_id.notNull() && mSettingAssetID != asset_id) + { + LLUUID item_id = mSettingItemID; + LLHandle<LLFloater> handle = getHandle(); + LLSettingsVOBase::getSettingsAsset(asset_id, + [item_id, handle](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) { LLFloaterSettingsPicker::onAssetLoadedCb(handle, item_id, asset_id, settings, status); }); + } +} + +void LLFloaterSettingsPicker::onAssetLoadedCb(LLHandle<LLFloater> handle, LLUUID item_id, LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status) +{ + if (handle.isDead() || status) + { + return; + } + + LLFloaterSettingsPicker *picker = static_cast<LLFloaterSettingsPicker *>(handle.get()); + + if (picker->mSettingItemID != item_id) + { + return; + } + + picker->onAssetLoaded(asset_id, settings); +} + +void LLFloaterSettingsPicker::onAssetLoaded(LLUUID asset_id, LLSettingsBase::ptr_t settings) +{ + LLComboBox* track_selection = getChild<LLComboBox>(CMB_TRACK_SELECTION); + track_selection->clear(); + track_selection->removeall(); + if (!settings) + { + LL_WARNS() << "Failed to load asset " << asset_id << LL_ENDL; + return; + } + LLSettingsDay::ptr_t pday = std::dynamic_pointer_cast<LLSettingsDay>(settings); + + if (!pday) + { + LL_WARNS() << "Wrong asset type received by id " << asset_id << LL_ENDL; + return; + } + + if (mTrackMode == TRACK_WATER) + { + track_selection->add(getString(STR_TRACK_WATER), LLSD::Integer(LLSettingsDay::TRACK_WATER), ADD_TOP, true); + } + else if (mTrackMode == TRACK_SKY) + { + // track 1 always present + track_selection->add(getString(STR_TRACK_GROUND), LLSD::Integer(LLSettingsDay::TRACK_GROUND_LEVEL), ADD_TOP, true); + LLUIString formatted_label = getString(STR_TRACK_SKY); + for (int i = 2; i < LLSettingsDay::TRACK_MAX; i++) + { + if (!pday->isTrackEmpty(i)) + { + formatted_label.setArg("[NUM]", llformat("%d", i)); + track_selection->add(formatted_label.getString(), LLSD::Integer(i), ADD_TOP, true); + } + } + } + + mSettingAssetID = asset_id; + track_selection->setEnabled(true); + track_selection->selectFirstItem(); + getChild<LLView>(BTN_SELECT)->setEnabled(true); +} + +void LLFloaterSettingsPicker::onButtonCancel() +{ + closeFloater(); +} + +void LLFloaterSettingsPicker::onButtonSelect() +{ + if (mCommitSignal) + { + LLSD res; + res["ItemId"] = mSettingItemID; + res["Track"] = getChild<LLComboBox>(CMB_TRACK_SELECTION)->getValue(); + (*mCommitSignal)(this, res); + } + closeFloater(); +} + +BOOL LLFloaterSettingsPicker::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + BOOL result = FALSE; + if (mSettingItemID.notNull() + && mInventoryPanel) + { + S32 inventory_x = x - mInventoryPanel->getRect().mLeft; + S32 inventory_y = y - mInventoryPanel->getRect().mBottom; + if (mInventoryPanel->parentPointInView(inventory_x, inventory_y)) + { + // make sure item is selected and visible + LLFolderViewItem* item_viewp = mInventoryPanel->getItemByID(mSettingItemID); + if (item_viewp && item_viewp->getIsCurSelection() && item_viewp->getVisible()) + { + LLRect target_rect; + item_viewp->localRectToOtherView(item_viewp->getLocalRect(), &target_rect, this); + if (target_rect.pointInRect(x, y)) + { + // Quick-apply + if (mCommitSignal) + { + LLSD res; + res["ItemId"] = mSettingItemID; + res["Track"] = getChild<LLComboBox>(CMB_TRACK_SELECTION)->getValue(); + (*mCommitSignal)(this, res); + } + closeFloater(); + // hit inside panel on selected item, double click should do nothing + result = TRUE; + } + } + } + } + + if (!result) + { + result = LLFloater::handleDoubleClick(x, y, mask); + } + return result; +} + +BOOL LLFloaterSettingsPicker::handleKeyHere(KEY key, MASK mask) +{ + if ((key == KEY_RETURN) && (mask == MASK_NONE)) + { + LLFolderViewItem* item_viewp = mInventoryPanel->getItemByID(mSettingItemID); + if (item_viewp && item_viewp->getIsCurSelection() && item_viewp->getVisible()) + { + // Quick-apply + if (mCommitSignal) + { + LLSD res; + res["ItemId"] = mSettingItemID; + res["Track"] = getChild<LLComboBox>(CMB_TRACK_SELECTION)->getValue(); + (*mCommitSignal)(this, res); + } + closeFloater(); + return TRUE; + } + } + + return LLFloater::handleKeyHere(key, mask); +} + +void LLFloaterSettingsPicker::onFocusLost() +{ + if (isInVisibleChain()) + { + closeFloater(); + } +} + +//========================================================================= +void LLFloaterSettingsPicker::setActive(bool active) +{ + mActive = active; +} + +void LLFloaterSettingsPicker::setSettingsItemId(const LLUUID &settings_id, bool set_selection) +{ + if (mSettingItemID != settings_id && mActive) + { + mNoCopySettingsSelected = false; + mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here? + mSettingItemID = settings_id; + if (mSettingItemID.isNull()) + { + mInventoryPanel->getRootFolder()->clearSelection(); + } + else + { + LLInventoryItem* itemp = gInventory.getItem(settings_id); + if (itemp && !itemp->getPermissions().allowCopyBy(gAgent.getID())) + { + mNoCopySettingsSelected = true; + } + } + + if (set_selection) + { + mInventoryPanel->setSelection(settings_id, TAKE_FOCUS_NO); + } + } +} + +LLInventoryItem* LLFloaterSettingsPicker::findItem(const LLUUID& asset_id, bool copyable_only, bool ignore_library) +{ + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(asset_id); + + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + + if (items.size()) + { + // search for copyable version first + for (S32 i = 0; i < items.size(); i++) + { + LLInventoryItem* itemp = items[i]; + LLPermissions item_permissions = itemp->getPermissions(); + if (item_permissions.allowCopyBy(gAgent.getID(), gAgent.getGroupID())) + { + if(!ignore_library || !gInventory.isObjectDescendentOf(itemp->getUUID(),gInventory.getLibraryRootFolderID())) + { + return itemp; + } + } + } + // otherwise just return first instance, unless copyable requested + if (copyable_only) + { + return nullptr; + } + else + { + if(!ignore_library || !gInventory.isObjectDescendentOf(items[0]->getUUID(),gInventory.getLibraryRootFolderID())) + { + return items[0]; + } + } + } + + return nullptr; +} diff --git a/indra/newview/llsettingspicker.h b/indra/newview/llsettingspicker.h new file mode 100644 index 0000000000..859f92fbe8 --- /dev/null +++ b/indra/newview/llsettingspicker.h @@ -0,0 +1,137 @@ +/** + * @file llsettingspicker.h + * @author Rider Linden + * @brief LLSettingsPicker class header file including related functions + * + * $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$ + */ + +#ifndef LL_SETTINGSPICKER_H +#define LL_SETTINGSPICKER_H + +#include "llinventorysettings.h" +#include "llfloater.h" +#include "llpermissionsflags.h" +#include "llfolderview.h" +#include "llinventory.h" +#include "llsettingsdaycycle.h" + +#include <boost/signals2.hpp> + +//========================================================================= +class LLFilterEditor; +class LLInventoryPanel; + +//========================================================================= +class LLFloaterSettingsPicker : public LLFloater +{ +public: + enum ETrackMode + { + TRACK_NONE, + TRACK_WATER, + TRACK_SKY + }; + typedef std::function<void()> close_callback_t; + typedef std::function<void(const LLUUID& item_id)> id_changed_callback_t; + + LLFloaterSettingsPicker(LLView * owner, LLUUID setting_item_id, const LLSD ¶ms = LLSD()); + + virtual ~LLFloaterSettingsPicker() override; + + void setActive(bool active); + + virtual BOOL postBuild() override; + virtual void onClose(bool app_quitting) override; + virtual void draw() override; + + void setSettingsItemId(const LLUUID &settings_id, bool set_selection = true); + LLUUID getSettingsItemId() const { return mSettingItemID; } + + void setSettingsFilter(LLSettingsType::type_e type); + LLSettingsType::type_e getSettingsFilter() const { return mSettingsType; } + + // Only for day cycle + void setTrackMode(ETrackMode mode); + void setTrackWater() { mTrackMode = TRACK_WATER; } + void setTrackSky() { mTrackMode = TRACK_SKY; } + + // Takes a UUID, wraps get/setImageAssetID + virtual void setValue(const LLSD& value) override; + virtual LLSD getValue() const override; + + static LLUUID findItemID(const LLUUID& asset_id, bool copyable_only, bool ignore_library = false) + { + LLInventoryItem *pitem = findItem(asset_id, copyable_only, ignore_library); + if (pitem) + return pitem->getUUID(); + return LLUUID::null; + } + + static std::string findItemName(const LLUUID& asset_id, bool copyable_only, bool ignore_library = false) + { + LLInventoryItem *pitem = findItem(asset_id, copyable_only, ignore_library); + if (pitem) + return pitem->getName(); + return std::string(); + } + + static LLInventoryItem * findItem(const LLUUID& asset_id, bool copyable_only, bool ignore_library); + + +private: + typedef std::deque<LLFolderViewItem *> itemlist_t; + + void onFilterEdit(const std::string& search_string); + void onSelectionChange(const itemlist_t &items, bool user_action); + static void onAssetLoadedCb(LLHandle<LLFloater> handle, LLUUID item_id, LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status); + void onAssetLoaded(LLUUID asset_id, LLSettingsBase::ptr_t settings); + void onButtonCancel(); + void onButtonSelect(); + virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask) override; + BOOL handleKeyHere(KEY key, MASK mask) override; + void onFocusLost() override; + + + LLHandle<LLView> mOwnerHandle; + LLUUID mSettingItemID; + LLUUID mSettingAssetID; + ETrackMode mTrackMode; + + LLFilterEditor * mFilterEdit; + LLInventoryPanel * mInventoryPanel; + LLSettingsType::type_e mSettingsType; + + F32 mContextConeOpacity; + PermissionMask mImmediateFilterPermMask; + + bool mActive; + bool mNoCopySettingsSelected; + + LLSaveFolderState mSavedFolderState; + +// boost::signals2::signal<void(LLUUID id)> mCommitSignal; + boost::signals2::signal<void()> mCloseSignal; + boost::signals2::signal<void(const LLUUID& item_id)> mChangeIDSignal; +}; + +#endif // LL_LLTEXTURECTRL_H diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp new file mode 100644 index 0000000000..1e5b893cbc --- /dev/null +++ b/indra/newview/llsettingsvo.cpp @@ -0,0 +1,1462 @@ +/** +* @file llsettingsvo.cpp +* @author Rider Linden +* @brief Subclasses for viewer specific settings behaviors. +* +* $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 "llviewerprecompiledheaders.h" +#include "llviewercontrol.h" +#include "llsettingsvo.h" + +#include "pipeline.h" + +#include <algorithm> +#include <cstdio> +#include <boost/make_shared.hpp> +#include "lltrace.h" +#include "llfasttimer.h" +#include "v3colorutil.h" + +#include "llglslshader.h" +#include "llviewershadermgr.h" + +#include "llagent.h" +#include "llassettype.h" +#include "llfloaterperms.h" +#include "llnotificationsutil.h" + +#include "llviewerregion.h" +#include "llviewerassetupload.h" +#include "llviewerinventory.h" + +#include "llenvironment.h" +#include "llsky.h" + +#include "llpermissions.h" + +#include "llinventorymodel.h" +#include "llassetstorage.h" +#include "llvfile.h" +#include "lldrawpoolwater.h" + +#include <boost/algorithm/string/replace.hpp> +#include "llinventoryobserver.h" +#include "llinventorydefines.h" + +#include "lltrans.h" + +#undef VERIFY_LEGACY_CONVERSION + +//========================================================================= +namespace +{ + LLSD ensure_array_4(LLSD in, F32 fill); + LLSD read_legacy_preset_data(const std::string &name, const std::string& path, LLSD &messages); + + //------------------------------------------------------------------------- + class LLSettingsInventoryCB : public LLInventoryCallback + { + public: + typedef std::function<void(const LLUUID &)> callback_t; + + LLSettingsInventoryCB(callback_t cbfn) : + mCbfn(cbfn) + { } + + void fire(const LLUUID& inv_item) override { if (mCbfn) mCbfn(inv_item); } + + private: + callback_t mCbfn; + }; + + //------------------------------------------------------------------------- +} + + +//========================================================================= +void LLSettingsVOBase::createNewInventoryItem(LLSettingsType::type_e stype, const LLUUID &parent_id, inventory_result_fn callback) +{ + LLTransactionID tid; + U32 nextOwnerPerm = LLFloaterPerms::getNextOwnerPerms("Settings"); + nextOwnerPerm |= PERM_COPY; + + if (!LLEnvironment::instance().isInventoryEnabled()) + { + LL_WARNS("SETTINGS") << "Region does not support settings inventory objects." << LL_ENDL; + LLNotificationsUtil::add("SettingsUnsuported"); + return; + } + + tid.generate(); + + LLPointer<LLInventoryCallback> cb = new LLSettingsInventoryCB([callback](const LLUUID &inventoryId) { + LLSettingsVOBase::onInventoryItemCreated(inventoryId, LLSettingsBase::ptr_t(), callback); + }); + + create_inventory_settings(gAgent.getID(), gAgent.getSessionID(), + parent_id, LLTransactionID::tnull, + LLSettingsType::getDefaultName(stype), "", + stype, nextOwnerPerm, cb); +} + + +void LLSettingsVOBase::createInventoryItem(const LLSettingsBase::ptr_t &settings, const LLUUID &parent_id, std::string settings_name, inventory_result_fn callback) +{ + U32 nextOwnerPerm = LLPermissions::DEFAULT.getMaskNextOwner(); + createInventoryItem(settings, nextOwnerPerm, parent_id, settings_name, callback); +} + +void LLSettingsVOBase::createInventoryItem(const LLSettingsBase::ptr_t &settings, U32 next_owner_perm, const LLUUID &parent_id, std::string settings_name, inventory_result_fn callback) +{ + LLTransactionID tid; + + if (!LLEnvironment::instance().isInventoryEnabled()) + { + LL_WARNS("SETTINGS") << "Region does not support settings inventory objects." << LL_ENDL; + LLNotificationsUtil::add("SettingsUnsuported"); + return; + } + + tid.generate(); + + LLPointer<LLInventoryCallback> cb = new LLSettingsInventoryCB([settings, callback](const LLUUID &inventoryId) { + LLSettingsVOBase::onInventoryItemCreated(inventoryId, settings, callback); + }); + + if (settings_name.empty()) + { + settings_name = settings->getName(); + } + create_inventory_settings(gAgent.getID(), gAgent.getSessionID(), + parent_id, tid, + settings_name, "", + settings->getSettingsTypeValue(), next_owner_perm, cb); +} + +void LLSettingsVOBase::onInventoryItemCreated(const LLUUID &inventoryId, LLSettingsBase::ptr_t settings, inventory_result_fn callback) +{ + LLViewerInventoryItem *pitem = gInventory.getItem(inventoryId); + if (pitem) + { + LLPermissions perm = pitem->getPermissions(); + if (perm.getMaskEveryone() != PERM_COPY) + { + perm.setMaskEveryone(PERM_COPY); + pitem->setPermissions(perm); + pitem->updateServer(FALSE); + } + } + if (!settings) + { // The item was created as new with no settings passed in. Simulator should have given it the default for the type... check ID, + // no need to upload asset. + LLUUID asset_id; + if (pitem) + { + asset_id = pitem->getAssetUUID(); + } + if (callback) + callback(asset_id, inventoryId, LLUUID::null, LLSD()); + return; + } + // We need to update some inventory stuff here.... maybe. + updateInventoryItem(settings, inventoryId, callback, false); +} + +void LLSettingsVOBase::updateInventoryItem(const LLSettingsBase::ptr_t &settings, LLUUID inv_item_id, inventory_result_fn callback, bool update_name) +{ + const LLViewerRegion* region = gAgent.getRegion(); + if (!region) + { + LL_WARNS("SETTINGS") << "Not connected to a region, cannot save setting." << LL_ENDL; + return; + } + + std::string agent_url(region->getCapability("UpdateSettingsAgentInventory")); + + if (!LLEnvironment::instance().isInventoryEnabled()) + { + LL_WARNS("SETTINGS") << "Region does not support settings inventory objects." << LL_ENDL; + LLNotificationsUtil::add("SettingsUnsuported"); + return; + } + + LLViewerInventoryItem *inv_item = gInventory.getItem(inv_item_id); + if (inv_item) + { + bool need_update(false); + LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(inv_item); + + if (settings->getFlag(LLSettingsBase::FLAG_NOTRANS) && new_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID())) + { + LLPermissions perm(inv_item->getPermissions()); + perm.setBaseBits(LLUUID::null, FALSE, PERM_TRANSFER); + perm.setOwnerBits(LLUUID::null, FALSE, PERM_TRANSFER); + new_item->setPermissions(perm); + need_update |= true; + } + if (update_name && (settings->getName() != new_item->getName())) + { + new_item->rename(settings->getName()); + settings->setName(new_item->getName()); // account for corrections + need_update |= true; + } + if (need_update) + { + new_item->updateServer(FALSE); + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + } + } + + std::stringstream buffer; + LLSD settingdata(settings->getSettings()); + LLSDSerialize::serialize(settingdata, buffer, LLSDSerialize::LLSD_NOTATION); + + LLResourceUploadInfo::ptr_t uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(inv_item_id, LLAssetType::AT_SETTINGS, buffer.str(), + [settings, callback](LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD response) { + LLSettingsVOBase::onAgentAssetUploadComplete(itemId, newAssetId, newItemId, response, settings, callback); + }); + + LLViewerAssetUpload::EnqueueInventoryUpload(agent_url, uploadInfo); +} + +void LLSettingsVOBase::updateInventoryItem(const LLSettingsBase::ptr_t &settings, LLUUID object_id, LLUUID inv_item_id, inventory_result_fn callback) +{ + const LLViewerRegion* region = gAgent.getRegion(); + if (!region) + { + LL_WARNS("SETTINGS") << "Not connected to a region, cannot save setting." << LL_ENDL; + return; + } + + std::string agent_url(region->getCapability("UpdateSettingsAgentInventory")); + + if (!LLEnvironment::instance().isInventoryEnabled()) + { + LL_WARNS("SETTINGS") << "Region does not support settings inventory objects." << LL_ENDL; + LLNotificationsUtil::add("SettingsUnsuported"); + return; + } + + std::stringstream buffer; + LLSD settingdata(settings->getSettings()); + + LLSDSerialize::serialize(settingdata, buffer, LLSDSerialize::LLSD_NOTATION); + + LLResourceUploadInfo::ptr_t uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(object_id, inv_item_id, LLAssetType::AT_SETTINGS, buffer.str(), + [settings, callback](LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response) { + LLSettingsVOBase::onTaskAssetUploadComplete(itemId, taskId, newAssetId, response, settings, callback); + }); + + LLViewerAssetUpload::EnqueueInventoryUpload(agent_url, uploadInfo); +} + +void LLSettingsVOBase::onAgentAssetUploadComplete(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD response, LLSettingsBase::ptr_t psettings, inventory_result_fn callback) +{ + LL_INFOS("SETTINGS") << "itemId:" << itemId << " newAssetId:" << newAssetId << " newItemId:" << newItemId << " response:" << response << LL_ENDL; + psettings->setAssetId(newAssetId); + if (callback) + callback( newAssetId, itemId, LLUUID::null, response ); +} + +void LLSettingsVOBase::onTaskAssetUploadComplete(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, LLSettingsBase::ptr_t psettings, inventory_result_fn callback) +{ + LL_INFOS("SETTINGS") << "Upload to task complete!" << LL_ENDL; + psettings->setAssetId(newAssetId); + if (callback) + callback(newAssetId, itemId, taskId, response); +} + + +void LLSettingsVOBase::getSettingsAsset(const LLUUID &assetId, LLSettingsVOBase::asset_download_fn callback) +{ + gAssetStorage->getAssetData(assetId, LLAssetType::AT_SETTINGS, + [callback](LLVFS *vfs, const LLUUID &asset_id, LLAssetType::EType, void *, S32 status, LLExtStat ext_status) + { onAssetDownloadComplete(vfs, asset_id, status, ext_status, callback); }, + nullptr, true); + +} + +void LLSettingsVOBase::onAssetDownloadComplete(LLVFS *vfs, const LLUUID &asset_id, S32 status, LLExtStat ext_status, LLSettingsVOBase::asset_download_fn callback) +{ + LLSettingsBase::ptr_t settings; + if (!status) + { + LLVFile file(vfs, asset_id, LLAssetType::AT_SETTINGS, LLVFile::READ); + S32 size = file.getSize(); + + std::string buffer(size + 1, '\0'); + file.read((U8 *)buffer.data(), size); + + std::stringstream llsdstream(buffer); + LLSD llsdsettings; + + if (LLSDSerialize::deserialize(llsdsettings, llsdstream, -1)) + { + settings = createFromLLSD(llsdsettings); + } + + if (!settings) + { + status = 1; + LL_WARNS("SETTINGS") << "Unable to create settings object." << LL_ENDL; + } + else + { + settings->setAssetId(asset_id); + } + } + else + { + LL_WARNS("SETTINGS") << "Error retrieving asset " << asset_id << ". Status code=" << status << "(" << LLAssetStorage::getErrorString(status) << ") ext_status=" << (U32)ext_status << LL_ENDL; + } + if (callback) + callback(asset_id, settings, status, ext_status); +} + +void LLSettingsVOBase::getSettingsInventory(const LLUUID &inventoryId, inventory_download_fn callback) +{ + +} + +bool LLSettingsVOBase::exportFile(const LLSettingsBase::ptr_t &settings, const std::string &filename, LLSDSerialize::ELLSD_Serialize format) +{ + try + { + std::ofstream file(filename, std::ios::out | std::ios::trunc); + file.exceptions(std::ios_base::failbit | std::ios_base::badbit); + + if (!file) + { + LL_WARNS("SETTINGS") << "Unable to open '" << filename << "' for writing." << LL_ENDL; + return false; + } + + LLSDSerialize::serialize(settings->getSettings(), file, format); + } + catch (const std::ios_base::failure &e) + { + LL_WARNS("SETTINGS") << "Unable to save settings to file '" << filename << "': " << e.what() << LL_ENDL; + return false; + } + + return true; +} + +LLSettingsBase::ptr_t LLSettingsVOBase::importFile(const std::string &filename) +{ + LLSD settings; + + try + { + std::ifstream file(filename, std::ios::in); + file.exceptions(std::ios_base::failbit | std::ios_base::badbit); + + if (!file) + { + LL_WARNS("SETTINGS") << "Unable to open '" << filename << "' for reading." << LL_ENDL; + return LLSettingsBase::ptr_t(); + } + + if (!LLSDSerialize::deserialize(settings, file, -1)) + { + LL_WARNS("SETTINGS") << "Unable to deserialize settings from '" << filename << "'" << LL_ENDL; + return LLSettingsBase::ptr_t(); + } + } + catch (const std::ios_base::failure &e) + { + LL_WARNS("SETTINGS") << "Unable to save settings to file '" << filename << "': " << e.what() << LL_ENDL; + return LLSettingsBase::ptr_t(); + } + + return createFromLLSD(settings); +} + +LLSettingsBase::ptr_t LLSettingsVOBase::createFromLLSD(const LLSD &settings) +{ + if (!settings.has(SETTING_TYPE)) + { + LL_WARNS("SETTINGS") << "No settings type in LLSD" << LL_ENDL; + return LLSettingsBase::ptr_t(); + } + + std::string settingtype = settings[SETTING_TYPE].asString(); + + LLSettingsBase::ptr_t psetting; + + if (settingtype == "water") + { + return LLSettingsVOWater::buildWater(settings); + } + else if (settingtype == "sky") + { + return LLSettingsVOSky::buildSky(settings); + } + else if (settingtype == "daycycle") + { + return LLSettingsVODay::buildDay(settings); + } + + LL_WARNS("SETTINGS") << "Unable to determine settings type for '" << settingtype << "'." << LL_ENDL; + return LLSettingsBase::ptr_t(); + +} + +//========================================================================= +LLSettingsVOSky::LLSettingsVOSky(const LLSD &data, bool isAdvanced) +: LLSettingsSky(data) +, m_isAdvanced(isAdvanced) +{ +} + +LLSettingsVOSky::LLSettingsVOSky() +: LLSettingsSky() +, m_isAdvanced(false) +{ +} + +//------------------------------------------------------------------------- +LLSettingsSky::ptr_t LLSettingsVOSky::buildSky(LLSD settings) +{ + LLSettingsSky::validation_list_t validations = LLSettingsSky::validationList(); + + LLSD results = LLSettingsBase::settingValidation(settings, validations); + + if (!results["success"].asBoolean()) + { + LL_WARNS("SETTINGS") << "Sky setting validation failed!\n" << results << LL_ENDL; + LLSettingsSky::ptr_t(); + } + + return std::make_shared<LLSettingsVOSky>(settings, true); +} + + +LLSettingsSky::ptr_t LLSettingsVOSky::buildFromLegacyPreset(const std::string &name, const LLSD &oldsettings, LLSD &messages) +{ + + LLSD newsettings = LLSettingsSky::translateLegacySettings(oldsettings); + if (newsettings.isUndefined()) + { + messages["REASONS"] = LLTrans::getString("SettingTranslateError", LLSDMap("NAME", name)); + return LLSettingsSky::ptr_t(); + } + + newsettings[SETTING_NAME] = name; + + LLSettingsSky::validation_list_t validations = LLSettingsSky::validationList(); + LLSD results = LLSettingsBase::settingValidation(newsettings, validations); + if (!results["success"].asBoolean()) + { + messages["REASONS"] = LLTrans::getString("SettingValidationError", LLSDMap("NAME", name)); + LL_WARNS("SETTINGS") << "Sky setting validation failed!\n" << results << LL_ENDL; + LLSettingsSky::ptr_t(); + } + + LLSettingsSky::ptr_t skyp = std::make_shared<LLSettingsVOSky>(newsettings); + +#ifdef VERIFY_LEGACY_CONVERSION + LLSD oldsettings = LLSettingsVOSky::convertToLegacy(skyp, isAdvanced()); + + if (!llsd_equals(oldsettings, oldsettings)) + { + LL_WARNS("SKY") << "Conversion to/from legacy does not match!\n" + << "Old: " << oldsettings + << "new: " << oldsettings << LL_ENDL; + } + +#endif + + return skyp; +} + +LLSettingsSky::ptr_t LLSettingsVOSky::buildFromLegacyPresetFile(const std::string &name, const std::string &path, LLSD &messages) +{ + LLSD legacy_data = read_legacy_preset_data(name, path, messages); + + if (!legacy_data) + { // messages filled in by read_legacy_preset_data + LL_WARNS("SETTINGS") << "Could not load legacy Windlight \"" << name << "\" from " << path << LL_ENDL; + return ptr_t(); + } + + return buildFromLegacyPreset(LLURI::unescape(name), legacy_data, messages); +} + + +LLSettingsSky::ptr_t LLSettingsVOSky::buildDefaultSky() +{ + static LLSD default_settings; + + if (!default_settings.size()) + { + default_settings = LLSettingsSky::defaults(); + + default_settings[SETTING_NAME] = DEFAULT_SETTINGS_NAME; + + LLSettingsSky::validation_list_t validations = LLSettingsSky::validationList(); + LLSD results = LLSettingsBase::settingValidation(default_settings, validations); + if (!results["success"].asBoolean()) + { + LL_WARNS("SETTINGS") << "Sky setting validation failed!\n" << results << LL_ENDL; + LLSettingsSky::ptr_t(); + } + } + + LLSettingsSky::ptr_t skyp = std::make_shared<LLSettingsVOSky>(default_settings); + return skyp; +} + +LLSettingsSky::ptr_t LLSettingsVOSky::buildClone() const +{ + LLSD settings = cloneSettings(); + U32 flags = getFlags(); + + LLSettingsSky::validation_list_t validations = LLSettingsSky::validationList(); + LLSD results = LLSettingsBase::settingValidation(settings, validations); + if (!results["success"].asBoolean()) + { + LL_WARNS("SETTINGS") << "Sky setting validation failed!\n" << results << LL_ENDL; + LLSettingsSky::ptr_t(); + } + + LLSettingsSky::ptr_t skyp = std::make_shared<LLSettingsVOSky>(settings); + skyp->setFlags(flags); + return skyp; +} + +void LLSettingsVOSky::convertAtmosphericsToLegacy(LLSD& legacy, LLSD& settings) +{ + // These may need to be inferred from new settings' density profiles + // if the legacy settings values are not available. + if (settings.has(SETTING_LEGACY_HAZE)) + { + LLSD legacyhaze = settings[SETTING_LEGACY_HAZE]; + + // work-around for setter formerly putting ambient values in wrong loc... + if (legacyhaze.has(SETTING_AMBIENT)) + { + legacy[SETTING_AMBIENT] = ensure_array_4(legacyhaze[SETTING_AMBIENT], 1.0f); + } + else if (settings.has(SETTING_AMBIENT)) + { + legacy[SETTING_AMBIENT] = ensure_array_4(settings[SETTING_AMBIENT], 1.0f); + } + + legacy[SETTING_BLUE_DENSITY] = ensure_array_4(legacyhaze[SETTING_BLUE_DENSITY], 1.0); + legacy[SETTING_BLUE_HORIZON] = ensure_array_4(legacyhaze[SETTING_BLUE_HORIZON], 1.0); + + legacy[SETTING_DENSITY_MULTIPLIER] = LLSDArray(legacyhaze[SETTING_DENSITY_MULTIPLIER].asReal())(0.0f)(0.0f)(1.0f); + legacy[SETTING_DISTANCE_MULTIPLIER] = LLSDArray(legacyhaze[SETTING_DISTANCE_MULTIPLIER].asReal())(0.0f)(0.0f)(1.0f); + + legacy[SETTING_HAZE_DENSITY] = LLSDArray(legacyhaze[SETTING_HAZE_DENSITY])(0.0f)(0.0f)(1.0f); + legacy[SETTING_HAZE_HORIZON] = LLSDArray(legacyhaze[SETTING_HAZE_HORIZON])(0.0f)(0.0f)(1.0f); + } +} + +LLSD LLSettingsVOSky::convertToLegacy(const LLSettingsSky::ptr_t &psky, bool isAdvanced) +{ + LLSD legacy(LLSD::emptyMap()); + LLSD settings = psky->getSettings(); + + convertAtmosphericsToLegacy(legacy, settings); + + legacy[SETTING_CLOUD_COLOR] = ensure_array_4(settings[SETTING_CLOUD_COLOR], 1.0); + legacy[SETTING_CLOUD_POS_DENSITY1] = ensure_array_4(settings[SETTING_CLOUD_POS_DENSITY1], 1.0); + legacy[SETTING_CLOUD_POS_DENSITY2] = ensure_array_4(settings[SETTING_CLOUD_POS_DENSITY2], 1.0); + legacy[SETTING_CLOUD_SCALE] = LLSDArray(settings[SETTING_CLOUD_SCALE])(LLSD::Real(0.0))(LLSD::Real(0.0))(LLSD::Real(1.0)); + legacy[SETTING_CLOUD_SCROLL_RATE] = settings[SETTING_CLOUD_SCROLL_RATE]; + legacy[SETTING_LEGACY_ENABLE_CLOUD_SCROLL] = LLSDArray(LLSD::Boolean(!is_approx_zero(settings[SETTING_CLOUD_SCROLL_RATE][0].asReal()))) + (LLSD::Boolean(!is_approx_zero(settings[SETTING_CLOUD_SCROLL_RATE][1].asReal()))); + legacy[SETTING_CLOUD_SHADOW] = LLSDArray(settings[SETTING_CLOUD_SHADOW].asReal())(0.0f)(0.0f)(1.0f); + legacy[SETTING_GAMMA] = LLSDArray(settings[SETTING_GAMMA])(0.0f)(0.0f)(1.0f); + legacy[SETTING_GLOW] = ensure_array_4(settings[SETTING_GLOW], 1.0); + legacy[SETTING_LIGHT_NORMAL] = ensure_array_4(psky->getLightDirection().getValue(), 0.0f); + legacy[SETTING_MAX_Y] = LLSDArray(settings[SETTING_MAX_Y])(0.0f)(0.0f)(1.0f); + legacy[SETTING_STAR_BRIGHTNESS] = settings[SETTING_STAR_BRIGHTNESS].asReal() / 250.0f; // convert from 0-500 -> 0-2 ala pre-FS-compat changes + legacy[SETTING_SUNLIGHT_COLOR] = ensure_array_4(settings[SETTING_SUNLIGHT_COLOR], 1.0f); + + LLVector3 dir = psky->getLightDirection(); + + F32 phi = asin(dir.mV[2]); + F32 cos_phi = cosf(phi); + F32 theta = (cos_phi != 0) ? asin(dir.mV[1] / cos_phi) : 0.0f; + + theta = -theta; + + // get angles back into valid ranges for legacy viewer... + // + while (theta < 0) + { + theta += F_PI * 2; + } + + if (theta > 4 * F_PI) + { + theta = fmod(theta, 2 * F_PI); + } + + while (phi < -F_PI) + { + phi += 2 * F_PI; + } + + if (phi > 3 * F_PI) + { + phi = F_PI + fmod(phi - F_PI, 2 * F_PI); + } + + legacy[SETTING_LEGACY_EAST_ANGLE] = theta; + legacy[SETTING_LEGACY_SUN_ANGLE] = phi; + + return legacy; +} + +//------------------------------------------------------------------------- +void LLSettingsVOSky::updateSettings() +{ + LLSettingsSky::updateSettings(); + LLVector3 sun_direction = getSunDirection(); + LLVector3 moon_direction = getMoonDirection(); + + // Want the dot prod of sun w/ high noon vector (0,0,1), which is just the z component + F32 dp = llmax(sun_direction[2], 0.0f); // clamped to 0 when sun is down + + // Since WL scales everything by 2, there should always be at least a 2:1 brightness ratio + // between sunlight and point lights in windlight to normalize point lights. + // + // After some A/B comparison of relesae vs EEP, tweak to allow strength to fall below 2 + // at night, for better match. (mSceneLightStrength is a divisor, so lower value means brighter + // local lights) + F32 sun_dynamic_range = llmax(gSavedSettings.getF32("RenderSunDynamicRange"), 0.0001f); + mSceneLightStrength = 2.0f * (0.75f + sun_dynamic_range * dp); + + gSky.setSunAndMoonDirectionsCFR(sun_direction, moon_direction); + gSky.setSunTextures(getSunTextureId(), getNextSunTextureId()); + gSky.setMoonTextures(getMoonTextureId(), getNextMoonTextureId()); + gSky.setCloudNoiseTextures(getCloudNoiseTextureId(), getNextCloudNoiseTextureId()); + gSky.setBloomTextures(getBloomTextureId(), getNextBloomTextureId()); + + gSky.setSunScale(getSunScale()); + gSky.setMoonScale(getMoonScale()); +} + +void LLSettingsVOSky::applySpecial(void *ptarget, bool force) +{ + LLGLSLShader *shader = (LLGLSLShader *)ptarget; + + LLVector4 light_direction = LLEnvironment::instance().getClampedLightNorm(); + + if (shader->mShaderGroup == LLGLSLShader::SG_DEFAULT) + { + shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, light_direction.mV); + shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV); + } + else if (shader->mShaderGroup == LLGLSLShader::SG_SKY) + { + shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, light_direction.mV); + + // Legacy? SETTING_CLOUD_SCROLL_RATE("cloud_scroll_rate") + LLVector4 vect_c_p_d1(mSettings[SETTING_CLOUD_POS_DENSITY1]); + LLVector4 cloud_scroll( LLEnvironment::instance().getCloudScrollDelta() ); + + // SL-13084 EEP added support for custom cloud textures -- flip them horizontally to match the preview of Clouds > Cloud Scroll + // Keep in Sync! + // * indra\newview\llsettingsvo.cpp + // * indra\newview\app_settings\shaders\class2\windlight\cloudsV.glsl + // * indra\newview\app_settings\shaders\class1\deferred\cloudsV.glsl + cloud_scroll[0] = -cloud_scroll[0]; + vect_c_p_d1 += cloud_scroll; + shader->uniform4fv(LLShaderMgr::CLOUD_POS_DENSITY1, 1, vect_c_p_d1.mV); + + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + + LLColor4 sunDiffuse = psky->getSunlightColor(); + LLColor4 moonDiffuse = psky->getMoonlightColor(); + + shader->uniform4fv(LLShaderMgr::SUNLIGHT_COLOR, 1, sunDiffuse.mV); + shader->uniform4fv(LLShaderMgr::MOONLIGHT_COLOR, 1, moonDiffuse.mV); + + LLColor4 cloud_color(psky->getCloudColor(), 1.0); + shader->uniform4fv(LLShaderMgr::CLOUD_COLOR, 1, cloud_color.mV); + } + + shader->uniform1f(LLShaderMgr::SCENE_LIGHT_STRENGTH, mSceneLightStrength); + + LLColor4 ambient(getTotalAmbient()); + shader->uniform4fv(LLShaderMgr::AMBIENT, 1, ambient.mV); + + shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, getIsSunUp() ? 1 : 0); + shader->uniform1f(LLShaderMgr::SUN_MOON_GLOW_FACTOR, getSunMoonGlowFactor()); + shader->uniform1f(LLShaderMgr::DENSITY_MULTIPLIER, getDensityMultiplier()); + shader->uniform1f(LLShaderMgr::DISTANCE_MULTIPLIER, getDistanceMultiplier()); + + F32 g = getGamma(); + F32 display_gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); + + shader->uniform1f(LLShaderMgr::GAMMA, g); + shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, display_gamma); +} + +LLSettingsSky::parammapping_t LLSettingsVOSky::getParameterMap() const +{ + static parammapping_t param_map; + + if (param_map.empty()) + { +// LEGACY_ATMOSPHERICS + + // Todo: default 'legacy' values duplicate the ones from functions like getBlueDensity() find a better home for them + // There is LLSettingsSky::defaults(), but it doesn't contain everything since it is geared towards creating new settings. + param_map[SETTING_AMBIENT] = DefaultParam(LLShaderMgr::AMBIENT, LLColor3(0.25f, 0.25f, 0.25f).getValue()); + param_map[SETTING_BLUE_DENSITY] = DefaultParam(LLShaderMgr::BLUE_DENSITY, LLColor3(0.2447f, 0.4487f, 0.7599f).getValue()); + param_map[SETTING_BLUE_HORIZON] = DefaultParam(LLShaderMgr::BLUE_HORIZON, LLColor3(0.4954f, 0.4954f, 0.6399f).getValue()); + param_map[SETTING_HAZE_DENSITY] = DefaultParam(LLShaderMgr::HAZE_DENSITY, LLSD(0.7f)); + param_map[SETTING_HAZE_HORIZON] = DefaultParam(LLShaderMgr::HAZE_HORIZON, LLSD(0.19f)); + param_map[SETTING_DENSITY_MULTIPLIER] = DefaultParam(LLShaderMgr::DENSITY_MULTIPLIER, LLSD(0.0001f)); + param_map[SETTING_DISTANCE_MULTIPLIER] = DefaultParam(LLShaderMgr::DISTANCE_MULTIPLIER, LLSD(0.8f)); + + // Following values are always present, so we can just zero these ones, but used values from defaults() + LLSD sky_defaults = LLSettingsSky::defaults(); + + param_map[SETTING_CLOUD_POS_DENSITY2] = DefaultParam(LLShaderMgr::CLOUD_POS_DENSITY2, sky_defaults[SETTING_CLOUD_POS_DENSITY2]); + param_map[SETTING_CLOUD_SCALE] = DefaultParam(LLShaderMgr::CLOUD_SCALE, sky_defaults[SETTING_CLOUD_SCALE]); + param_map[SETTING_CLOUD_SHADOW] = DefaultParam(LLShaderMgr::CLOUD_SHADOW, sky_defaults[SETTING_CLOUD_SHADOW]); + param_map[SETTING_CLOUD_VARIANCE] = DefaultParam(LLShaderMgr::CLOUD_VARIANCE, sky_defaults[SETTING_CLOUD_VARIANCE]); + param_map[SETTING_GLOW] = DefaultParam(LLShaderMgr::GLOW, sky_defaults[SETTING_GLOW]); + param_map[SETTING_MAX_Y] = DefaultParam(LLShaderMgr::MAX_Y, sky_defaults[SETTING_MAX_Y]); + + //param_map[SETTING_SUNLIGHT_COLOR] = DefaultParam(LLShaderMgr::SUNLIGHT_COLOR, sky_defaults[SETTING_SUNLIGHT_COLOR]); + //param_map[SETTING_CLOUD_COLOR] = DefaultParam(LLShaderMgr::CLOUD_COLOR, sky_defaults[SETTING_CLOUD_COLOR]); + + param_map[SETTING_MOON_BRIGHTNESS] = DefaultParam(LLShaderMgr::MOON_BRIGHTNESS, sky_defaults[SETTING_MOON_BRIGHTNESS]); + param_map[SETTING_SKY_MOISTURE_LEVEL] = DefaultParam(LLShaderMgr::MOISTURE_LEVEL, sky_defaults[SETTING_SKY_MOISTURE_LEVEL]); + param_map[SETTING_SKY_DROPLET_RADIUS] = DefaultParam(LLShaderMgr::DROPLET_RADIUS, sky_defaults[SETTING_SKY_DROPLET_RADIUS]); + param_map[SETTING_SKY_ICE_LEVEL] = DefaultParam(LLShaderMgr::ICE_LEVEL, sky_defaults[SETTING_SKY_ICE_LEVEL]); + +// AdvancedAtmospherics TODO +// Provide mappings for new shader params here + } + + return param_map; +} + +//========================================================================= +const F32 LLSettingsVOWater::WATER_FOG_LIGHT_CLAMP(0.3f); + +//------------------------------------------------------------------------- +LLSettingsVOWater::LLSettingsVOWater(const LLSD &data) : + LLSettingsWater(data) +{ + +} + +LLSettingsVOWater::LLSettingsVOWater() : + LLSettingsWater() +{ + +} + +LLSettingsWater::ptr_t LLSettingsVOWater::buildWater(LLSD settings) +{ + LLSettingsWater::validation_list_t validations = LLSettingsWater::validationList(); + LLSD results = LLSettingsWater::settingValidation(settings, validations); + if (!results["success"].asBoolean()) + { + LL_WARNS("SETTINGS") << "Water setting validation failed!\n" << results << LL_ENDL; + LLSettingsWater::ptr_t(); + } + + return std::make_shared<LLSettingsVOWater>(settings); +} + +//------------------------------------------------------------------------- +LLSettingsWater::ptr_t LLSettingsVOWater::buildFromLegacyPreset(const std::string &name, const LLSD &oldsettings, LLSD &messages) +{ + LLSD newsettings(LLSettingsWater::translateLegacySettings(oldsettings)); + if (newsettings.isUndefined()) + { + messages["REASONS"] = LLTrans::getString("SettingTranslateError", LLSDMap("NAME", name)); + return LLSettingsWater::ptr_t(); + } + + newsettings[SETTING_NAME] = name; + LLSettingsWater::validation_list_t validations = LLSettingsWater::validationList(); + LLSD results = LLSettingsWater::settingValidation(newsettings, validations); + if (!results["success"].asBoolean()) + { + messages["REASONS"] = LLTrans::getString("SettingValidationError", name); + LL_WARNS("SETTINGS") << "Water setting validation failed!: " << results << LL_ENDL; + return LLSettingsWater::ptr_t(); + } + + LLSettingsWater::ptr_t waterp = std::make_shared<LLSettingsVOWater>(newsettings); + +#ifdef VERIFY_LEGACY_CONVERSION + LLSD oldsettings = LLSettingsVOWater::convertToLegacy(waterp); + + if (!llsd_equals(oldsettings, oldsettings)) + { + LL_WARNS("WATER") << "Conversion to/from legacy does not match!\n" + << "Old: " << oldsettings + << "new: " << oldsettings << LL_ENDL; + } + +#endif + return waterp; +} + +LLSettingsWater::ptr_t LLSettingsVOWater::buildFromLegacyPresetFile(const std::string &name, const std::string &path, LLSD &messages) +{ + LLSD legacy_data = read_legacy_preset_data(name, path, messages); + + if (!legacy_data) + { // messages filled in by read_legacy_preset_data + LL_WARNS("SETTINGS") << "Could not load legacy Windlight \"" << name << "\" from " << path << LL_ENDL; + return ptr_t(); + } + + return buildFromLegacyPreset(LLURI::unescape(name), legacy_data, messages); +} + + +LLSettingsWater::ptr_t LLSettingsVOWater::buildDefaultWater() +{ + static LLSD default_settings; + + if (!default_settings.size()) + { + default_settings = LLSettingsWater::defaults(); + + default_settings[SETTING_NAME] = DEFAULT_SETTINGS_NAME; + + LLSettingsWater::validation_list_t validations = LLSettingsWater::validationList(); + LLSD results = LLSettingsWater::settingValidation(default_settings, validations); + if (!results["success"].asBoolean()) + { + LL_WARNS("SETTINGS") << "Water setting validation failed!: " << results << LL_ENDL; + return LLSettingsWater::ptr_t(); + } + } + + LLSettingsWater::ptr_t waterp = std::make_shared<LLSettingsVOWater>(default_settings); + + return waterp; +} + +LLSettingsWater::ptr_t LLSettingsVOWater::buildClone() const +{ + LLSD settings = cloneSettings(); + U32 flags = getFlags(); + LLSettingsWater::validation_list_t validations = LLSettingsWater::validationList(); + LLSD results = LLSettingsWater::settingValidation(settings, validations); + if (!results["success"].asBoolean()) + { + LL_WARNS("SETTINGS") << "Water setting validation failed!: " << results << LL_ENDL; + return LLSettingsWater::ptr_t(); + } + + LLSettingsWater::ptr_t waterp = std::make_shared<LLSettingsVOWater>(settings); + waterp->setFlags(flags); + return waterp; +} + +LLSD LLSettingsVOWater::convertToLegacy(const LLSettingsWater::ptr_t &pwater) +{ + LLSD legacy(LLSD::emptyMap()); + LLSD settings = pwater->getSettings(); + + legacy[SETTING_LEGACY_BLUR_MULTIPLIER] = settings[SETTING_BLUR_MULTIPLIER]; + legacy[SETTING_LEGACY_FOG_COLOR] = ensure_array_4(settings[SETTING_FOG_COLOR], 1.0f); + legacy[SETTING_LEGACY_FOG_DENSITY] = settings[SETTING_FOG_DENSITY]; + legacy[SETTING_LEGACY_FOG_MOD] = settings[SETTING_FOG_MOD]; + legacy[SETTING_LEGACY_FRESNEL_OFFSET] = settings[SETTING_FRESNEL_OFFSET]; + legacy[SETTING_LEGACY_FRESNEL_SCALE] = settings[SETTING_FRESNEL_SCALE]; + legacy[SETTING_LEGACY_NORMAL_MAP] = settings[SETTING_NORMAL_MAP]; + legacy[SETTING_LEGACY_NORMAL_SCALE] = settings[SETTING_NORMAL_SCALE]; + legacy[SETTING_LEGACY_SCALE_ABOVE] = settings[SETTING_SCALE_ABOVE]; + legacy[SETTING_LEGACY_SCALE_BELOW] = settings[SETTING_SCALE_BELOW]; + legacy[SETTING_LEGACY_WAVE1_DIR] = settings[SETTING_WAVE1_DIR]; + legacy[SETTING_LEGACY_WAVE2_DIR] = settings[SETTING_WAVE2_DIR]; + + return legacy; +} +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- +void LLSettingsVOWater::applySpecial(void *ptarget, bool force) +{ + LLGLSLShader *shader = (LLGLSLShader *)ptarget; + + LLEnvironment& env = LLEnvironment::instance(); + + if (force || (shader->mShaderGroup == LLGLSLShader::SG_WATER)) + { + F32 water_height = env.getWaterHeight(); + + //transform water plane to eye space + glh::vec3f norm(0.f, 0.f, 1.f); + glh::vec3f p(0.f, 0.f, water_height + 0.1f); + + F32 modelView[16]; + for (U32 i = 0; i < 16; i++) + { + modelView[i] = (F32)gGLModelView[i]; + } + + 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); + + LLVector4 waterPlane(enorm.v[0], enorm.v[1], enorm.v[2], -ep.dot(enorm)); + + shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, waterPlane.mV); + + LLVector4 light_direction = env.getClampedLightNorm(); + + F32 waterFogKS = 1.f / llmax(light_direction.mV[2], WATER_FOG_LIGHT_CLAMP); + + shader->uniform1f(LLShaderMgr::WATER_FOGKS, waterFogKS); + + F32 eyedepth = LLViewerCamera::getInstance()->getOrigin().mV[2] - water_height; + bool underwater = (eyedepth <= 0.0f); + + F32 waterFogDensity = env.getCurrentWater()->getModifiedWaterFogDensity(underwater); + shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, waterFogDensity); + + LLColor4 fog_color(env.getCurrentWater()->getWaterFogColor(), 0.0f); + shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV); + + F32 blend_factor = env.getCurrentWater()->getBlendFactor(); + shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor); + + // update to normal lightnorm, water shader itself will use rotated lightnorm as necessary + shader->uniform4fv(LLShaderMgr::LIGHTNORM, 1, light_direction.mV); + } +} + +void LLSettingsVOWater::updateSettings() +{ + // base class clears dirty flag so as to not trigger recursive update + LLSettingsBase::updateSettings(); + + LLDrawPoolWater* pwaterpool = (LLDrawPoolWater*)gPipeline.getPool(LLDrawPool::POOL_WATER); + if (pwaterpool) + { + pwaterpool->setTransparentTextures(getTransparentTextureID(), getNextTransparentTextureID()); + pwaterpool->setOpaqueTexture(GetDefaultOpaqueTextureAssetId()); + pwaterpool->setNormalMaps(getNormalMapID(), getNextNormalMapID()); + } +} + +LLSettingsWater::parammapping_t LLSettingsVOWater::getParameterMap() const +{ + static parammapping_t param_map; + + if (param_map.empty()) + { + //LLSD water_defaults = LLSettingsWater::defaults(); + //param_map[SETTING_FOG_COLOR] = DefaultParam(LLShaderMgr::WATER_FOGCOLOR, water_defaults[SETTING_FOG_COLOR]); + // let this get set by LLSettingsVOWater::applySpecial so that it can properly reflect the underwater modifier + //param_map[SETTING_FOG_DENSITY] = DefaultParam(LLShaderMgr::WATER_FOGDENSITY, water_defaults[SETTING_FOG_DENSITY]); + } + return param_map; +} + +//========================================================================= +LLSettingsVODay::LLSettingsVODay(const LLSD &data): + LLSettingsDay(data) +{} + +LLSettingsVODay::LLSettingsVODay(): + LLSettingsDay() +{} + +LLSettingsDay::ptr_t LLSettingsVODay::buildDay(LLSD settings) +{ + LLSettingsDay::validation_list_t validations = LLSettingsDay::validationList(); + LLSD results = LLSettingsDay::settingValidation(settings, validations); + if (!results["success"].asBoolean()) + { + LL_WARNS("SETTINGS") << "Day setting validation failed!\n" << results << LL_ENDL; + LLSettingsDay::ptr_t(); + } + + LLSettingsDay::ptr_t pday = std::make_shared<LLSettingsVODay>(settings); + if (pday) + pday->initialize(); + + return pday; +} + +//------------------------------------------------------------------------- +LLSettingsDay::ptr_t LLSettingsVODay::buildFromLegacyPreset(const std::string &name, const std::string &path, const LLSD &oldsettings, LLSD &messages) +{ + LLSD newsettings(defaults()); + std::set<std::string> framenames; + std::set<std::string> notfound; + + std::string base_path(gDirUtilp->getDirName(path)); + std::string water_path(base_path); + std::string sky_path(base_path); + + gDirUtilp->append(water_path, "water"); + gDirUtilp->append(sky_path, "skies"); + + newsettings[SETTING_NAME] = name; + + LLSD watertrack = LLSDArray( + LLSDMap(SETTING_KEYKFRAME, LLSD::Real(0.0f)) + (SETTING_KEYNAME, "water:Default")); + + LLSD skytrack = LLSD::emptyArray(); + + for (LLSD::array_const_iterator it = oldsettings.beginArray(); it != oldsettings.endArray(); ++it) + { + std::string framename = (*it)[1].asString(); + LLSD entry = LLSDMap(SETTING_KEYKFRAME, (*it)[0].asReal()) + (SETTING_KEYNAME, "sky:" + framename); + framenames.insert(framename); + skytrack.append(entry); + } + + newsettings[SETTING_TRACKS] = LLSDArray(watertrack)(skytrack); + + LLSD frames(LLSD::emptyMap()); + + { + LLSettingsWater::ptr_t pwater = LLSettingsVOWater::buildFromLegacyPresetFile("Default", water_path, messages); + if (!pwater) + { // messages filled in by buildFromLegacyPresetFile + return LLSettingsDay::ptr_t(); + } + frames["water:Default"] = pwater->getSettings(); + } + + for (std::set<std::string>::iterator itn = framenames.begin(); itn != framenames.end(); ++itn) + { + LLSettingsSky::ptr_t psky = LLSettingsVOSky::buildFromLegacyPresetFile((*itn), sky_path, messages); + if (!psky) + { // messages filled in by buildFromLegacyPresetFile + return LLSettingsDay::ptr_t(); + } + frames["sky:" + (*itn)] = psky->getSettings(); + } + + newsettings[SETTING_FRAMES] = frames; + + LLSettingsDay::validation_list_t validations = LLSettingsDay::validationList(); + LLSD results = LLSettingsDay::settingValidation(newsettings, validations); + if (!results["success"].asBoolean()) + { + messages["REASONS"] = LLTrans::getString("SettingValidationError", LLSDMap("NAME", name)); + LL_WARNS("SETTINGS") << "Day setting validation failed!: " << results << LL_ENDL; + return LLSettingsDay::ptr_t(); + } + + LLSettingsDay::ptr_t dayp = std::make_shared<LLSettingsVODay>(newsettings); + +#ifdef VERIFY_LEGACY_CONVERSION + LLSD testsettings = LLSettingsVODay::convertToLegacy(dayp); + + if (!llsd_equals(oldsettings, testsettings)) + { + LL_WARNS("DAYCYCLE") << "Conversion to/from legacy does not match!\n" + << "Old: " << oldsettings + << "new: " << testsettings << LL_ENDL; + } + +#endif + + dayp->initialize(); + + return dayp; +} + +LLSettingsDay::ptr_t LLSettingsVODay::buildFromLegacyPresetFile(const std::string &name, const std::string &path, LLSD &messages) +{ + LLSD legacy_data = read_legacy_preset_data(name, path, messages); + + if (!legacy_data) + { // messages filled in by read_legacy_preset_data + LL_WARNS("SETTINGS") << "Could not load legacy Windlight \"" << name << "\" from " << path << LL_ENDL; + return ptr_t(); + } + // Name for LLSettingsDay only, path to get related files from filesystem + return buildFromLegacyPreset(LLURI::unescape(name), path, legacy_data, messages); +} + + + +LLSettingsDay::ptr_t LLSettingsVODay::buildFromLegacyMessage(const LLUUID ®ionId, LLSD daycycle, LLSD skydefs, LLSD waterdef) +{ + LLSD frames(LLSD::emptyMap()); + + for (LLSD::map_iterator itm = skydefs.beginMap(); itm != skydefs.endMap(); ++itm) + { + std::string newname = "sky:" + (*itm).first; + LLSD newsettings = LLSettingsSky::translateLegacySettings((*itm).second); + + newsettings[SETTING_NAME] = newname; + frames[newname] = newsettings; + + LL_WARNS("SETTINGS") << "created region sky '" << newname << "'" << LL_ENDL; + } + + LLSD watersettings = LLSettingsWater::translateLegacySettings(waterdef); + std::string watername = "water:"+ watersettings[SETTING_NAME].asString(); + watersettings[SETTING_NAME] = watername; + frames[watername] = watersettings; + + LLSD watertrack = LLSDArray( + LLSDMap(SETTING_KEYKFRAME, LLSD::Real(0.0f)) + (SETTING_KEYNAME, watername)); + + LLSD skytrack(LLSD::emptyArray()); + for (LLSD::array_const_iterator it = daycycle.beginArray(); it != daycycle.endArray(); ++it) + { + LLSD entry = LLSDMap(SETTING_KEYKFRAME, (*it)[0].asReal()) + (SETTING_KEYNAME, "sky:" + (*it)[1].asString()); + skytrack.append(entry); + } + + LLSD newsettings = LLSDMap + ( SETTING_NAME, "Region (legacy)" ) + ( SETTING_TRACKS, LLSDArray(watertrack)(skytrack)) + ( SETTING_FRAMES, frames ) + ( SETTING_TYPE, "daycycle" ); + + LLSettingsSky::validation_list_t validations = LLSettingsDay::validationList(); + LLSD results = LLSettingsDay::settingValidation(newsettings, validations); + if (!results["success"].asBoolean()) + { + LL_WARNS("SETTINGS") << "Day setting validation failed!:" << results << LL_ENDL; + return LLSettingsDay::ptr_t(); + } + + LLSettingsDay::ptr_t dayp = std::make_shared<LLSettingsVODay>(newsettings); + + if (dayp) + { + // true for validation - either validate here, or when cloning for floater. + dayp->initialize(true); + } + return dayp; +} + + + +LLSettingsDay::ptr_t LLSettingsVODay::buildDefaultDayCycle() +{ + static LLSD default_settings; + + if (!default_settings.size()) + { + default_settings = LLSettingsDay::defaults(); + default_settings[SETTING_NAME] = DEFAULT_SETTINGS_NAME; + + LLSettingsDay::validation_list_t validations = LLSettingsDay::validationList(); + LLSD results = LLSettingsDay::settingValidation(default_settings, validations); + if (!results["success"].asBoolean()) + { + LL_WARNS("SETTINGS") << "Day setting validation failed!\n" << results << LL_ENDL; + LLSettingsDay::ptr_t(); + } + } + + LLSettingsDay::ptr_t dayp = std::make_shared<LLSettingsVODay>(default_settings); + + dayp->initialize(); + return dayp; +} + +LLSettingsDay::ptr_t LLSettingsVODay::buildFromEnvironmentMessage(LLSD settings) +{ + LLSettingsDay::validation_list_t validations = LLSettingsDay::validationList(); + LLSD results = LLSettingsDay::settingValidation(settings, validations); + if (!results["success"].asBoolean()) + { + LL_WARNS("SETTINGS") << "Day setting validation failed!\n" << results << LL_ENDL; + LLSettingsDay::ptr_t(); + } + + LLSettingsDay::ptr_t dayp = std::make_shared<LLSettingsVODay>(settings); + + dayp->initialize(); + return dayp; +} + + +void LLSettingsVODay::buildFromOtherSetting(LLSettingsBase::ptr_t settings, LLSettingsVODay::asset_built_fn cb) +{ + if (settings->getSettingsType() == "daycycle") + { + if (cb) + cb(std::static_pointer_cast<LLSettingsDay>(settings)); + } + else + { + LLSettingsVOBase::getSettingsAsset(LLSettingsDay::GetDefaultAssetId(), + [settings, cb](LLUUID, LLSettingsBase::ptr_t pday, S32, LLExtStat){ combineIntoDayCycle(std::static_pointer_cast<LLSettingsDay>(pday), settings, cb); }); + } +} + +void LLSettingsVODay::combineIntoDayCycle(LLSettingsDay::ptr_t pday, LLSettingsBase::ptr_t settings, asset_built_fn cb) +{ + if (settings->getSettingsType() == "sky") + { + pday->setName("sky: " + settings->getName()); + pday->clearCycleTrack(1); + pday->setSettingsAtKeyframe(settings, 0.0, 1); + } + else if (settings->getSettingsType() == "water") + { + pday->setName("water: " + settings->getName()); + pday->clearCycleTrack(0); + pday->setSettingsAtKeyframe(settings, 0.0, 0); + } + else + { + pday.reset(); + } + + if (cb) + cb(pday); +} + + +LLSettingsDay::ptr_t LLSettingsVODay::buildClone() const +{ + LLSD settings = cloneSettings(); + + LLSettingsDay::validation_list_t validations = LLSettingsDay::validationList(); + LLSD results = LLSettingsDay::settingValidation(settings, validations); + if (!results["success"].asBoolean()) + { + LL_WARNS("SETTINGS") << "Day setting validation failed!\n" << results << LL_ENDL; + LLSettingsDay::ptr_t(); + } + + LLSettingsDay::ptr_t dayp = std::make_shared<LLSettingsVODay>(settings); + + U32 flags = getFlags(); + if (flags) + dayp->setFlags(flags); + + dayp->initialize(); + return dayp; +} + +LLSettingsDay::ptr_t LLSettingsVODay::buildDeepCloneAndUncompress() const +{ + // no need for SETTING_TRACKS or SETTING_FRAMES, so take base LLSD + LLSD settings = llsd_clone(mSettings); + + U32 flags = getFlags(); + LLSettingsDay::ptr_t day_clone = std::make_shared<LLSettingsVODay>(settings); + + for (S32 i = 0; i < LLSettingsDay::TRACK_MAX; ++i) + { + const LLSettingsDay::CycleTrack_t& track = getCycleTrackConst(i); + LLSettingsDay::CycleTrack_t::const_iterator iter = track.begin(); + while (iter != track.end()) + { + // 'Unpack', usually for editing + // - frames 'share' settings multiple times + // - settings can reuse LLSDs they were initialized from + // We do not want for edited frame to change multiple frames in same track, so do a clone + day_clone->setSettingsAtKeyframe(iter->second->buildDerivedClone(), iter->first, i); + iter++; + } + } + day_clone->setFlags(flags); + return day_clone; +} + +LLSD LLSettingsVODay::convertToLegacy(const LLSettingsVODay::ptr_t &pday) +{ + CycleTrack_t &trackwater = pday->getCycleTrack(TRACK_WATER); + + LLSettingsWater::ptr_t pwater; + if (!trackwater.empty()) + { + pwater = std::static_pointer_cast<LLSettingsWater>((*trackwater.begin()).second); + } + + if (!pwater) + pwater = LLSettingsVOWater::buildDefaultWater(); + + LLSD llsdwater = LLSettingsVOWater::convertToLegacy(pwater); + + CycleTrack_t &tracksky = pday->getCycleTrack(1); // first sky track + std::map<std::string, LLSettingsSky::ptr_t> skys; + + LLSD llsdcycle(LLSD::emptyArray()); + + for(CycleTrack_t::iterator it = tracksky.begin(); it != tracksky.end(); ++it) + { + size_t hash = (*it).second->getHash(); + std::stringstream name; + + name << hash; + + skys[name.str()] = std::static_pointer_cast<LLSettingsSky>((*it).second); + + F32 frame = ((tracksky.size() == 1) && (it == tracksky.begin())) ? -1.0f : (*it).first; + llsdcycle.append( LLSDArray(LLSD::Real(frame))(name.str()) ); + } + + LLSD llsdskylist(LLSD::emptyMap()); + + for (std::map<std::string, LLSettingsSky::ptr_t>::iterator its = skys.begin(); its != skys.end(); ++its) + { + LLSD llsdsky = LLSettingsVOSky::convertToLegacy((*its).second, false); + llsdsky[SETTING_NAME] = (*its).first; + + llsdskylist[(*its).first] = llsdsky; + } + + return LLSDArray(LLSD::emptyMap())(llsdcycle)(llsdskylist)(llsdwater); +} + +LLSettingsSkyPtr_t LLSettingsVODay::getDefaultSky() const +{ + return LLSettingsVOSky::buildDefaultSky(); +} + +LLSettingsWaterPtr_t LLSettingsVODay::getDefaultWater() const +{ + return LLSettingsVOWater::buildDefaultWater(); +} + +LLSettingsSkyPtr_t LLSettingsVODay::buildSky(LLSD settings) const +{ + LLSettingsSky::ptr_t skyp = std::make_shared<LLSettingsVOSky>(settings); + + if (skyp->validate()) + return skyp; + + return LLSettingsSky::ptr_t(); +} + +LLSettingsWaterPtr_t LLSettingsVODay::buildWater(LLSD settings) const +{ + LLSettingsWater::ptr_t waterp = std::make_shared<LLSettingsVOWater>(settings); + + if (waterp->validate()) + return waterp; + + return LLSettingsWater::ptr_t(); +} + +//========================================================================= +namespace +{ + LLSD ensure_array_4(LLSD in, F32 fill) + { + if (in.size() >= 4) + return in; + + LLSD out(LLSD::emptyArray()); + + for (S32 idx = 0; idx < in.size(); ++idx) + { + out.append(in[idx]); + } + + while (out.size() < 4) + { + out.append(LLSD::Real(fill)); + } + return out; + } + + // This is a disturbing hack + std::string legacy_name_to_filename(const std::string &name, bool convertdash = false) + { + std::string fixedname(LLURI::escape(name)); + + if (convertdash) + boost::algorithm::replace_all(fixedname, "-", "%2D"); + + return fixedname; + } + + //--------------------------------------------------------------------- + LLSD read_legacy_preset_data(const std::string &name, const std::string& path, LLSD &messages) + { + llifstream xml_file; + + std::string full_path(path); + std::string full_name(name); + full_name += ".xml"; + gDirUtilp->append(full_path, full_name); + + xml_file.open(full_path.c_str()); + if (!xml_file) + { + std::string bad_path(full_path); + full_path = path; + full_name = legacy_name_to_filename(name); + full_name += ".xml"; + gDirUtilp->append(full_path, full_name); + + LL_INFOS("LEGACYSETTING") << "Could not open \"" << bad_path << "\" trying escaped \"" << full_path << "\"" << LL_ENDL; + + xml_file.open(full_path.c_str()); + if (!xml_file) + { + LL_WARNS("LEGACYSETTING") << "Unable to open legacy windlight \"" << name << "\" from " << path << LL_ENDL; + + full_path = path; + full_name = legacy_name_to_filename(name, true); + full_name += ".xml"; + gDirUtilp->append(full_path, full_name); + xml_file.open(full_path.c_str()); + if (!xml_file) + { + messages["REASONS"] = LLTrans::getString("SettingImportFileError", LLSDMap("FILE", bad_path)); + LL_WARNS("LEGACYSETTING") << "Unable to open legacy windlight \"" << name << "\" from " << path << LL_ENDL; + return LLSD(); + } + } + } + + LLSD params_data; + LLPointer<LLSDParser> parser = new LLSDXMLParser(); + if (parser->parse(xml_file, params_data, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) + { + xml_file.close(); + messages["REASONS"] = LLTrans::getString("SettingParseFileError", LLSDMap("FILE", full_path)); + return LLSD(); + } + xml_file.close(); + + return params_data; + } +} diff --git a/indra/newview/llsettingsvo.h b/indra/newview/llsettingsvo.h new file mode 100644 index 0000000000..65136ad2f5 --- /dev/null +++ b/indra/newview/llsettingsvo.h @@ -0,0 +1,192 @@ +/** +* @file llsettingsvo.h +* @author Rider Linden +* @brief Subclasses for viewer specific settings behaviors. +* +* $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_VO_H +#define LL_SETTINGS_VO_H + +#include "llsettingsbase.h" +#include "llsettingssky.h" +#include "llsettingswater.h" +#include "llsettingsdaycycle.h" + +#include "llsdserialize.h" + +#include "llextendedstatus.h" +#include <boost/signals2.hpp> + +class LLVFS; +class LLInventoryItem; +class LLGLSLShader; + +//========================================================================= +class LLSettingsVOBase : public LLSettingsBase +{ +public: + typedef std::function<void(LLUUID asset_id, LLSettingsBase::ptr_t settins, S32 status, LLExtStat extstat)> asset_download_fn; + typedef std::function<void(LLInventoryItem *inv_item, LLSettingsBase::ptr_t settings, S32 status, LLExtStat extstat)> inventory_download_fn; + typedef std::function<void(LLUUID asset_id, LLUUID inventory_id, LLUUID object_id, LLSD results)> inventory_result_fn; + + static void createNewInventoryItem(LLSettingsType::type_e stype, const LLUUID &parent_id, inventory_result_fn callback = inventory_result_fn()); + static void createInventoryItem(const LLSettingsBase::ptr_t &settings, const LLUUID &parent_id, std::string settings_name, inventory_result_fn callback = inventory_result_fn()); + static void createInventoryItem(const LLSettingsBase::ptr_t &settings, U32 next_owner_perm, const LLUUID &parent_id, std::string settings_name, inventory_result_fn callback = inventory_result_fn()); + + static void updateInventoryItem(const LLSettingsBase::ptr_t &settings, LLUUID inv_item_id, inventory_result_fn callback = inventory_result_fn(), bool update_name = true); + static void updateInventoryItem(const LLSettingsBase::ptr_t &settings, LLUUID object_id, LLUUID inv_item_id, inventory_result_fn callback = inventory_result_fn()); + + static void getSettingsAsset(const LLUUID &assetId, asset_download_fn callback); + static void getSettingsInventory(const LLUUID &inventoryId, inventory_download_fn callback = inventory_download_fn()); + + static bool exportFile(const LLSettingsBase::ptr_t &settings, const std::string &filename, LLSDSerialize::ELLSD_Serialize format = LLSDSerialize::LLSD_NOTATION); + static LLSettingsBase::ptr_t importFile(const std::string &filename); + static LLSettingsBase::ptr_t createFromLLSD(const LLSD &settings); + +private: + struct SettingsSaveData + { + typedef std::shared_ptr<SettingsSaveData> ptr_t; + std::string mType; + std::string mTempFile; + LLSettingsBase::ptr_t mSettings; + LLTransactionID mTransId; + }; + + LLSettingsVOBase() {} + + static void onInventoryItemCreated(const LLUUID &inventoryId, LLSettingsBase::ptr_t settings, inventory_result_fn callback); + + static void onAgentAssetUploadComplete(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD response, LLSettingsBase::ptr_t psettings, inventory_result_fn callback); + static void onTaskAssetUploadComplete(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, LLSettingsBase::ptr_t psettings, inventory_result_fn callback); + + static void onAssetDownloadComplete(LLVFS *vfs, const LLUUID &asset_id, S32 status, LLExtStat ext_status, asset_download_fn callback); +}; + +//========================================================================= +class LLSettingsVOSky : public LLSettingsSky +{ +public: + LLSettingsVOSky(const LLSD &data, bool advanced = false); + + static ptr_t buildSky(LLSD settings); + + static ptr_t buildFromLegacyPreset(const std::string &name, const LLSD &oldsettings, LLSD &messages); + static ptr_t buildDefaultSky(); + virtual ptr_t buildClone() const SETTINGS_OVERRIDE; + + static ptr_t buildFromLegacyPresetFile(const std::string &name, const std::string &path, LLSD &messages); + + static LLSD convertToLegacy(const ptr_t &, bool isAdvanced); + + bool isAdvanced() const { return m_isAdvanced; } + + virtual void updateShader(LLGLSLShader* shader) { applySpecial(shader, true); } + +protected: + LLSettingsVOSky(); + + // Interpret new settings in terms of old atmospherics params + static void convertAtmosphericsToLegacy(LLSD& legacy, LLSD& settings); + + virtual void updateSettings() override; + + virtual void applySpecial(void *, bool) override; + + virtual parammapping_t getParameterMap() const override; + + bool m_isAdvanced = false; + F32 mSceneLightStrength = 3.0f; +}; + +//========================================================================= +class LLSettingsVOWater : public LLSettingsWater +{ +public: + LLSettingsVOWater(const LLSD &data); + + static ptr_t buildWater(LLSD settings); + + static ptr_t buildFromLegacyPreset(const std::string &name, const LLSD &oldsettings, LLSD &messages); + static ptr_t buildDefaultWater(); + virtual ptr_t buildClone() const SETTINGS_OVERRIDE; + + static ptr_t buildFromLegacyPresetFile(const std::string &name, const std::string &path, LLSD &messages); + + static LLSD convertToLegacy(const ptr_t &); + + virtual void updateShader(LLGLSLShader* shader) { applySpecial(shader, true); } + +protected: + LLSettingsVOWater(); + + virtual void updateSettings() override; + virtual void applySpecial(void *, bool) override; + + virtual parammapping_t getParameterMap() const override; + + +private: + static const F32 WATER_FOG_LIGHT_CLAMP; + +}; + +//========================================================================= +class LLSettingsVODay : public LLSettingsDay +{ +public: + typedef std::function<void(LLSettingsDay::ptr_t day)> asset_built_fn; + + // Todo: find a way to make this cnstructor private + // It shouldn't be used outside shared_prt and LLSettingsVODay + // outside of settings only use buildDay(settings) + LLSettingsVODay(const LLSD &data); + + static ptr_t buildDay(LLSD settings); + + static ptr_t buildFromLegacyPreset(const std::string &name, const std::string &path, const LLSD &oldsettings, LLSD &messages); + static ptr_t buildFromLegacyPresetFile(const std::string &name, const std::string &path, LLSD &messages); + static ptr_t buildFromLegacyMessage(const LLUUID ®ionId, LLSD daycycle, LLSD skys, LLSD water); + static ptr_t buildDefaultDayCycle(); + static ptr_t buildFromEnvironmentMessage(LLSD settings); + static void buildFromOtherSetting(LLSettingsBase::ptr_t settings, asset_built_fn cb); + virtual ptr_t buildClone() const SETTINGS_OVERRIDE; + virtual ptr_t buildDeepCloneAndUncompress() const SETTINGS_OVERRIDE; + + static LLSD convertToLegacy(const ptr_t &); + + virtual LLSettingsSkyPtr_t getDefaultSky() const override; + virtual LLSettingsWaterPtr_t getDefaultWater() const override; + virtual LLSettingsSkyPtr_t buildSky(LLSD) const override; + virtual LLSettingsWaterPtr_t buildWater(LLSD) const override; + +protected: + LLSettingsVODay(); + +private: + static void combineIntoDayCycle(LLSettingsDay::ptr_t, LLSettingsBase::ptr_t, asset_built_fn); +}; + + +#endif diff --git a/indra/newview/llshareavatarhandler.cpp b/indra/newview/llshareavatarhandler.cpp index 6b4f1d3dc6..142e00c3f7 100644 --- a/indra/newview/llshareavatarhandler.cpp +++ b/indra/newview/llshareavatarhandler.cpp @@ -40,7 +40,7 @@ public: bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) { - if (!LLUI::sSettingGroups["config"]->getBOOL("EnableAvatarShare")) + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableAvatarShare")) { LLNotificationsUtil::add("NoAvatarShare", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); return true; diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index 4ebcffa554..6dfe40c29a 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -140,6 +140,8 @@ BOOL LLSidepanelAppearance::postBuild() setVisibleCallback(boost::bind(&LLSidepanelAppearance::onVisibilityChanged,this,_2)); + setWearablesLoading(gAgentWearables.isCOFChangeInProgress()); + return TRUE; } @@ -162,8 +164,12 @@ void LLSidepanelAppearance::onOpen(const LLSD& key) std::string type = key["type"].asString(); if (type == "my_outfits") { - showOutfitsInventoryPanel(); + showOutfitsInventoryPanel("outfitslist_tab"); } + else if (type == "now_wearing") + { + showOutfitsInventoryPanel("cof_tab"); + } else if (type == "edit_outfit") { showOutfitEditPanel(); @@ -285,7 +291,14 @@ void LLSidepanelAppearance::showOutfitsInventoryPanel() { toggleWearableEditPanel(FALSE); toggleOutfitEditPanel(FALSE); - toggleMyOutfitsPanel(TRUE); + toggleMyOutfitsPanel(TRUE, ""); +} + +void LLSidepanelAppearance::showOutfitsInventoryPanel(const std::string &tab_name) +{ + toggleWearableEditPanel(FALSE); + toggleOutfitEditPanel(FALSE); + toggleMyOutfitsPanel(TRUE, tab_name); } void LLSidepanelAppearance::showOutfitEditPanel() @@ -310,37 +323,42 @@ void LLSidepanelAppearance::showOutfitEditPanel() return; } - toggleMyOutfitsPanel(FALSE); + toggleMyOutfitsPanel(FALSE, ""); toggleWearableEditPanel(FALSE, NULL, TRUE); // don't switch out of edit appearance mode toggleOutfitEditPanel(TRUE); } void LLSidepanelAppearance::showWearableEditPanel(LLViewerWearable *wearable /* = NULL*/, BOOL disable_camera_switch) { - toggleMyOutfitsPanel(FALSE); + toggleMyOutfitsPanel(FALSE, ""); toggleOutfitEditPanel(FALSE, TRUE); // don't switch out of edit appearance mode toggleWearableEditPanel(TRUE, wearable, disable_camera_switch); } -void LLSidepanelAppearance::toggleMyOutfitsPanel(BOOL visible) +void LLSidepanelAppearance::toggleMyOutfitsPanel(BOOL visible, const std::string& tab_name) { - if (!mPanelOutfitsInventory || mPanelOutfitsInventory->getVisible() == visible) - { - // visibility isn't changing, hence nothing to do - return; - } - - mPanelOutfitsInventory->setVisible(visible); - - // *TODO: Move these controls to panel_outfits_inventory.xml - // so that we don't need to toggle them explicitly. - mFilterEditor->setVisible(visible); - mCurrOutfitPanel->setVisible(visible); - - if (visible) - { - mPanelOutfitsInventory->onOpen(LLSD()); - } + if (!mPanelOutfitsInventory + || (mPanelOutfitsInventory->getVisible() == visible && tab_name.empty())) + { + // visibility isn't changing, hence nothing to do + return; + } + + mPanelOutfitsInventory->setVisible(visible); + + // *TODO: Move these controls to panel_outfits_inventory.xml + // so that we don't need to toggle them explicitly. + mFilterEditor->setVisible(visible); + mCurrOutfitPanel->setVisible(visible); + + if (visible) + { + mPanelOutfitsInventory->onOpen(LLSD()); + if (!tab_name.empty()) + { + mPanelOutfitsInventory->openApearanceTab(tab_name); + } + } } void LLSidepanelAppearance::toggleOutfitEditPanel(BOOL visible, BOOL disable_camera_switch) @@ -485,7 +503,7 @@ void LLSidepanelAppearance::fetchInventory() attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - LLViewerObject* attached_object = (*attachment_iter); + LLViewerObject* attached_object = attachment_iter->get(); if (!attached_object) continue; const LLUUID& item_id = attached_object->getAttachmentItemID(); if (item_id.isNull()) continue; diff --git a/indra/newview/llsidepanelappearance.h b/indra/newview/llsidepanelappearance.h index 7817fd317c..bb9709a2b8 100644 --- a/indra/newview/llsidepanelappearance.h +++ b/indra/newview/llsidepanelappearance.h @@ -56,7 +56,8 @@ public: void fetchInventory(); void inventoryFetched(); - void showOutfitsInventoryPanel(); + void showOutfitsInventoryPanel(); // last selected + void showOutfitsInventoryPanel(const std::string& tab_name); void showOutfitEditPanel(); void showWearableEditPanel(LLViewerWearable *wearable = NULL, BOOL disable_camera_switch = FALSE); void setWearablesLoading(bool val); @@ -72,7 +73,7 @@ private: void onOpenOutfitButtonClicked(); void onEditAppearanceButtonClicked(); - void toggleMyOutfitsPanel(BOOL visible); + void toggleMyOutfitsPanel(BOOL visible, const std::string& tab_name); void toggleOutfitEditPanel(BOOL visible, BOOL disable_camera_switch = FALSE); void toggleWearableEditPanel(BOOL visible, LLViewerWearable* wearable = NULL, BOOL disable_camera_switch = FALSE); diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp index 2503e2a5e2..b23e24a222 100644 --- a/indra/newview/llsidepaneliteminfo.cpp +++ b/indra/newview/llsidepaneliteminfo.cpp @@ -49,6 +49,29 @@ #include "llviewerregion.h" +class PropertiesChangedCallback : public LLInventoryCallback +{ +public: + PropertiesChangedCallback(LLHandle<LLPanel> sidepanel_handle, LLUUID &item_id, S32 id) + : mHandle(sidepanel_handle), mItemId(item_id), mId(id) + {} + + void fire(const LLUUID &inv_item) + { + // inv_item can be null for some reason + LLSidepanelItemInfo* sidepanel = dynamic_cast<LLSidepanelItemInfo*>(mHandle.get()); + if (sidepanel) + { + // sidepanel waits only for most recent update + sidepanel->onUpdateCallback(mItemId, mId); + } + } +private: + LLHandle<LLPanel> mHandle; + LLUUID mItemId; + S32 mId; +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLItemPropertiesObserver // @@ -68,7 +91,7 @@ public: } virtual void changed(U32 mask); private: - LLSidepanelItemInfo* mFloater; + LLSidepanelItemInfo* mFloater; // Not a handle because LLSidepanelItemInfo is managing LLItemPropertiesObserver }; void LLItemPropertiesObserver::changed(U32 mask) @@ -115,7 +138,7 @@ public: S32 serial_num, void* user_data); private: - LLSidepanelItemInfo* mFloater; + LLSidepanelItemInfo* mFloater; // Not a handle because LLSidepanelItemInfo is managing LLObjectInventoryObserver }; /*virtual*/ @@ -138,6 +161,7 @@ LLSidepanelItemInfo::LLSidepanelItemInfo(const LLPanel::Params& p) : LLSidepanelInventorySubpanel(p) , mItemID(LLUUID::null) , mObjectInventoryObserver(NULL) + , mUpdatePendingId(-1) { mPropertiesObserver = new LLItemPropertiesObserver(this); } @@ -168,19 +192,19 @@ BOOL LLSidepanelItemInfo::postBuild() // owner permissions // Permissions debug text // group permissions - getChild<LLUICtrl>("CheckShareWithGroup")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this)); + getChild<LLUICtrl>("CheckShareWithGroup")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this, _1)); // everyone permissions - getChild<LLUICtrl>("CheckEveryoneCopy")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this)); + getChild<LLUICtrl>("CheckEveryoneCopy")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this, _1)); // next owner permissions - getChild<LLUICtrl>("CheckNextOwnerModify")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this)); - getChild<LLUICtrl>("CheckNextOwnerCopy")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this)); - getChild<LLUICtrl>("CheckNextOwnerTransfer")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this)); + getChild<LLUICtrl>("CheckNextOwnerModify")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this, _1)); + getChild<LLUICtrl>("CheckNextOwnerCopy")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this, _1)); + getChild<LLUICtrl>("CheckNextOwnerTransfer")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this, _1)); // Mark for sale or not, and sale info - getChild<LLUICtrl>("CheckPurchase")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitSaleInfo, this)); + getChild<LLUICtrl>("CheckPurchase")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitSaleInfo, this, _1)); // Change sale type, and sale info - getChild<LLUICtrl>("ComboBoxSaleType")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitSaleInfo, this)); + getChild<LLUICtrl>("ComboBoxSaleType")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitSaleInfo, this, _1)); // "Price" label for edit - getChild<LLUICtrl>("Edit Cost")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitSaleInfo, this)); + getChild<LLUICtrl>("Edit Cost")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitSaleInfo, this, _1)); refresh(); return TRUE; } @@ -192,11 +216,16 @@ void LLSidepanelItemInfo::setObjectID(const LLUUID& object_id) // Start monitoring changes in the object inventory to update // selected inventory item properties in Item Profile panel. See STORM-148. startObjectInventoryObserver(); + mUpdatePendingId = -1; } void LLSidepanelItemInfo::setItemID(const LLUUID& item_id) { - mItemID = item_id; + if (mItemID != item_id) + { + mItemID = item_id; + mUpdatePendingId = -1; + } } const LLUUID& LLSidepanelItemInfo::getObjectID() const @@ -209,6 +238,15 @@ const LLUUID& LLSidepanelItemInfo::getItemID() const return mItemID; } +void LLSidepanelItemInfo::onUpdateCallback(const LLUUID& item_id, S32 received_update_id) +{ + if (mItemID == item_id && mUpdatePendingId == received_update_id) + { + mUpdatePendingId = -1; + refresh(); + } +} + void LLSidepanelItemInfo::reset() { LLSidepanelInventorySubpanel::reset(); @@ -242,24 +280,16 @@ void LLSidepanelItemInfo::refresh() "LabelItemName", "LabelItemDesc", "LabelCreatorName", - "LabelOwnerName", - "CheckOwnerModify", - "CheckOwnerCopy", - "CheckOwnerTransfer", - "CheckShareWithGroup", - "CheckEveryoneCopy", - "CheckNextOwnerModify", - "CheckNextOwnerCopy", - "CheckNextOwnerTransfer", - "CheckPurchase", - "Edit Cost" + "LabelOwnerName" }; for(size_t t=0; t<LL_ARRAY_SIZE(no_item_names); ++t) { getChildView(no_item_names[t])->setEnabled(false); } - + + setPropertiesFieldsEnabled(false); + const std::string hide_names[]={ "BaseMaskDebug", "OwnerMaskDebug", @@ -297,10 +327,16 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) llassert(item); if (!item) return; + if (mUpdatePendingId != -1) + { + return; + } + // do not enable the UI for incomplete items. BOOL is_complete = item->isFinished(); const BOOL cannot_restrict_permissions = LLInventoryType::cannotRestrictPermissions(item->getInventoryType()); const BOOL is_calling_card = (item->getInventoryType() == LLInventoryType::IT_CALLINGCARD); + const BOOL is_settings = (item->getInventoryType() == LLInventoryType::IT_SETTINGS); const LLPermissions& perm = item->getPermissions(); const BOOL can_agent_manipulate = gAgent.allowOperation(PERM_OWNER, perm, GP_OBJECT_MANIPULATE); @@ -630,14 +666,14 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) LLUICtrl* edit_cost = getChild<LLUICtrl>("Edit Cost"); // Check for ability to change values. - if (is_obj_modify && can_agent_sell + if (is_obj_modify && can_agent_sell && gAgent.allowOperation(PERM_TRANSFER, perm, GP_OBJECT_MANIPULATE)) { getChildView("CheckPurchase")->setEnabled(is_complete); getChildView("NextOwnerLabel")->setEnabled(TRUE); getChildView("CheckNextOwnerModify")->setEnabled((base_mask & PERM_MODIFY) && !cannot_restrict_permissions); - getChildView("CheckNextOwnerCopy")->setEnabled((base_mask & PERM_COPY) && !cannot_restrict_permissions); + getChildView("CheckNextOwnerCopy")->setEnabled((base_mask & PERM_COPY) && !cannot_restrict_permissions && !is_settings); getChildView("CheckNextOwnerTransfer")->setEnabled((next_owner_mask & PERM_COPY) && !cannot_restrict_permissions); combo_sale_type->setEnabled(is_complete && is_for_sale); @@ -656,6 +692,25 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) edit_cost->setEnabled(FALSE); } + // Hide any properties that are not relevant to settings + if (is_settings) + { + getChild<LLUICtrl>("GroupLabel")->setEnabled(false); + getChild<LLUICtrl>("GroupLabel")->setVisible(false); + getChild<LLUICtrl>("CheckShareWithGroup")->setEnabled(false); + getChild<LLUICtrl>("CheckShareWithGroup")->setVisible(false); + getChild<LLUICtrl>("AnyoneLabel")->setEnabled(false); + getChild<LLUICtrl>("AnyoneLabel")->setVisible(false); + getChild<LLUICtrl>("CheckEveryoneCopy")->setEnabled(false); + getChild<LLUICtrl>("CheckEveryoneCopy")->setVisible(false); + getChild<LLUICtrl>("CheckPurchase")->setEnabled(false); + getChild<LLUICtrl>("CheckPurchase")->setVisible(false); + getChild<LLUICtrl>("ComboBoxSaleType")->setEnabled(false); + getChild<LLUICtrl>("ComboBoxSaleType")->setVisible(false); + getChild<LLUICtrl>("Edit Cost")->setEnabled(false); + getChild<LLUICtrl>("Edit Cost")->setVisible(false); + } + // Set values. getChild<LLUICtrl>("CheckPurchase")->setValue(is_for_sale); getChild<LLUICtrl>("CheckNextOwnerModify")->setValue(LLSD(BOOL(next_owner_mask & PERM_MODIFY))); @@ -726,6 +781,26 @@ void LLSidepanelItemInfo::stopObjectInventoryObserver() mObjectInventoryObserver = NULL; } +void LLSidepanelItemInfo::setPropertiesFieldsEnabled(bool enabled) +{ + const std::string fields[] = { + "CheckOwnerModify", + "CheckOwnerCopy", + "CheckOwnerTransfer", + "CheckShareWithGroup", + "CheckEveryoneCopy", + "CheckNextOwnerModify", + "CheckNextOwnerCopy", + "CheckNextOwnerTransfer", + "CheckPurchase", + "Edit Cost" + }; + for (size_t t = 0; t<LL_ARRAY_SIZE(fields); ++t) + { + getChildView(fields[t])->setEnabled(false); + } +} + void LLSidepanelItemInfo::onClickCreator() { LLViewerInventoryItem* item = findItem(); @@ -793,10 +868,18 @@ void LLSidepanelItemInfo::onCommitDescription() } } -// static -void LLSidepanelItemInfo::onCommitPermissions() +void LLSidepanelItemInfo::onCommitPermissions(LLUICtrl* ctrl) +{ + if (ctrl) + { + // will be enabled by response from server + ctrl->setEnabled(false); + } + updatePermissions(); +} + +void LLSidepanelItemInfo::updatePermissions() { - //LL_INFOS() << "LLSidepanelItemInfo::onCommitPermissions()" << LL_ENDL; LLViewerInventoryItem* item = findItem(); if(!item) return; @@ -884,19 +967,17 @@ void LLSidepanelItemInfo::onCommitPermissions() } // static -void LLSidepanelItemInfo::onCommitSaleInfo() +void LLSidepanelItemInfo::onCommitSaleInfo(LLUICtrl* ctrl) { + if (ctrl) + { + // will be enabled by response from server + ctrl->setEnabled(false); + } //LL_INFOS() << "LLSidepanelItemInfo::onCommitSaleInfo()" << LL_ENDL; updateSaleInfo(); } -// static -void LLSidepanelItemInfo::onCommitSaleType() -{ - //LL_INFOS() << "LLSidepanelItemInfo::onCommitSaleType()" << LL_ENDL; - updateSaleInfo(); -} - void LLSidepanelItemInfo::updateSaleInfo() { LLViewerInventoryItem* item = findItem(); @@ -977,7 +1058,12 @@ void LLSidepanelItemInfo::onCommitChanges(LLPointer<LLViewerInventoryItem> item) if (mObjectID.isNull()) { // This is in the agent's inventory. - item->updateServer(FALSE); + // Mark update as pending and wait only for most recent one in case user requested for couple + // Once update arrives or any of ids change drop pending id. + mUpdatePendingId++; + LLPointer<LLInventoryCallback> callback = new PropertiesChangedCallback(getHandle(), mItemID, mUpdatePendingId); + update_inventory_item(item.get(), callback); + //item->updateServer(FALSE); gInventory.updateItem(item); gInventory.notifyObservers(); } @@ -1002,6 +1088,7 @@ void LLSidepanelItemInfo::onCommitChanges(LLPointer<LLViewerInventoryItem> item) // prevents flashing in content tab and some duplicated request. object->dirtyInventory(); } + setPropertiesFieldsEnabled(false); } } } @@ -1030,7 +1117,6 @@ void LLSidepanelItemInfo::save() { onCommitName(); onCommitDescription(); - onCommitPermissions(); - onCommitSaleInfo(); - onCommitSaleType(); + updatePermissions(); + updateSaleInfo(); } diff --git a/indra/newview/llsidepaneliteminfo.h b/indra/newview/llsidepaneliteminfo.h index 74cf7afe35..5f29254182 100644 --- a/indra/newview/llsidepaneliteminfo.h +++ b/indra/newview/llsidepaneliteminfo.h @@ -57,6 +57,9 @@ public: const LLUUID& getObjectID() const; const LLUUID& getItemID() const; + // if received update and item id (from callback) matches internal ones, update UI + void onUpdateCallback(const LLUUID& item_id, S32 received_update_id); + protected: /*virtual*/ void refresh(); /*virtual*/ void save(); @@ -71,12 +74,16 @@ private: void startObjectInventoryObserver(); void stopObjectInventoryObserver(); + void setPropertiesFieldsEnabled(bool enabled); LLUUID mItemID; // inventory UUID for the inventory item. LLUUID mObjectID; // in-world task UUID, or null if in agent inventory. LLItemPropertiesObserver* mPropertiesObserver; // for syncing changes to item LLObjectInventoryObserver* mObjectInventoryObserver; // for syncing changes to items inside an object - + + // We can send multiple properties updates simultaneously, make sure only last response counts and there won't be a race condition. + S32 mUpdatePendingId; + // // UI Elements // @@ -85,9 +92,9 @@ protected: void onClickOwner(); void onCommitName(); void onCommitDescription(); - void onCommitPermissions(); - void onCommitSaleInfo(); - void onCommitSaleType(); + void onCommitPermissions(LLUICtrl* ctrl); + void updatePermissions(); + void onCommitSaleInfo(LLUICtrl* ctrl); void updateSaleInfo(); void onCommitChanges(LLPointer<LLViewerInventoryItem> item); }; diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp index f03c7abc4d..7fa06f51e3 100644 --- a/indra/newview/llsidepaneltaskinfo.cpp +++ b/indra/newview/llsidepaneltaskinfo.cpp @@ -174,9 +174,6 @@ BOOL LLSidepanelTaskInfo::postBuild() void LLSidepanelTaskInfo::disableAll() { - mDAPermModify->setEnabled(FALSE); - mDAPermModify->setValue(LLStringUtil::null); - mDACreatorName->setValue(LLStringUtil::null); mDACreatorName->setEnabled(FALSE); @@ -184,18 +181,42 @@ void LLSidepanelTaskInfo::disableAll() mDAOwnerName->setValue(LLStringUtil::null); mDAOwnerName->setEnabled(FALSE); - mDAButtonSetGroup->setEnabled(FALSE); - mDAObjectName->setValue(LLStringUtil::null); mDAObjectName->setEnabled(FALSE); mDAName->setEnabled(FALSE); mDADescription->setEnabled(FALSE); mDAObjectDescription->setValue(LLStringUtil::null); mDAObjectDescription->setEnabled(FALSE); - + + mDAPathfindingAttributes->setEnabled(FALSE); + mDAPathfindingAttributes->setValue(LLStringUtil::null); + + mDAButtonSetGroup->setEnabled(FALSE); + mDAButtonDeed->setEnabled(FALSE); + + mDAPermModify->setEnabled(FALSE); + mDAPermModify->setValue(LLStringUtil::null); + mDAEditCost->setValue(LLStringUtil::null); + mDAComboSaleType->setValue(LLSaleInfo::FS_COPY); + + disablePermissions(); + + mDAB->setVisible(FALSE); + mDAO->setVisible(FALSE); + mDAG->setVisible(FALSE); + mDAE->setVisible(FALSE); + mDAN->setVisible(FALSE); + mDAF->setVisible(FALSE); + + mOpenBtn->setEnabled(FALSE); + mPayBtn->setEnabled(FALSE); + mBuyBtn->setEnabled(FALSE); +} + +void LLSidepanelTaskInfo::disablePermissions() +{ mDACheckboxShareWithGroup->setValue(FALSE); mDACheckboxShareWithGroup->setEnabled(FALSE); - mDAButtonDeed->setEnabled(FALSE); mDACheckboxAllowEveryoneMove->setValue(FALSE); mDACheckboxAllowEveryoneMove->setEnabled(FALSE); @@ -217,33 +238,17 @@ void LLSidepanelTaskInfo::disableAll() //checkbox include in search mDASearchCheck->setValue(FALSE); mDASearchCheck->setEnabled(FALSE); - - mDAComboSaleType->setValue(LLSaleInfo::FS_COPY); + mDAComboSaleType->setEnabled(FALSE); - - mDAEditCost->setValue(LLStringUtil::null); + mDAEditCost->setEnabled(FALSE); - + mDALabelClickAction->setEnabled(FALSE); if (mDAComboClickAction) { mDAComboClickAction->setEnabled(FALSE); mDAComboClickAction->clear(); } - - mDAPathfindingAttributes->setEnabled(FALSE); - mDAPathfindingAttributes->setValue(LLStringUtil::null); - - mDAB->setVisible(FALSE); - mDAO->setVisible(FALSE); - mDAG->setVisible(FALSE); - mDAE->setVisible(FALSE); - mDAN->setVisible(FALSE); - mDAF->setVisible(FALSE); - - mOpenBtn->setEnabled(FALSE); - mPayBtn->setEnabled(FALSE); - mBuyBtn->setEnabled(FALSE); } void LLSidepanelTaskInfo::refresh() @@ -972,6 +977,12 @@ void LLSidepanelTaskInfo::onCommitPerm(LLUICtrl *ctrl, void *data, U8 field, U32 BOOL new_state = check->get(); LLSelectMgr::getInstance()->selectionSetObjectPermissions(field, new_state, perm); + + LLSidepanelTaskInfo* self = (LLSidepanelTaskInfo*)data; + if (self) + { + self->disablePermissions(); + } } // static diff --git a/indra/newview/llsidepaneltaskinfo.h b/indra/newview/llsidepaneltaskinfo.h index cbfb07874b..dc259cb22d 100644 --- a/indra/newview/llsidepaneltaskinfo.h +++ b/indra/newview/llsidepaneltaskinfo.h @@ -95,6 +95,7 @@ protected: static void doClickAction(U8 click_action); void disableAll(); + void disablePermissions(); private: LLNameBox* mLabelGroupName; // group name diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp index 0fa4c2b114..e02b21f036 100644 --- a/indra/newview/llskinningutil.cpp +++ b/indra/newview/llskinningutil.cpp @@ -34,8 +34,12 @@ #include "llvolume.h" #include "llrigginginfo.h" +#define DEBUG_SKINNING LL_DEBUG +#define MAT_USE_SSE 1 + void dump_avatar_and_skin_state(const std::string& reason, LLVOAvatar *avatar, const LLMeshSkinInfo *skin) { +#if DEBUG_SKINNING static S32 dump_count = 0; const S32 max_dump = 10; @@ -81,16 +85,12 @@ void dump_avatar_and_skin_state(const std::string& reason, LLVOAvatar *avatar, c dump_count++; } +#endif } -void LLSkinningUtil::initClass() -{ -} - -U32 LLSkinningUtil::getMaxJointCount() +S32 LLSkinningUtil::getMaxJointCount() { - U32 result = LL_MAX_JOINTS_PER_MESH_OBJECT; - return result; + return (S32)LL_MAX_JOINTS_PER_MESH_OBJECT; } U32 LLSkinningUtil::getMeshJointCount(const LLMeshSkinInfo *skin) @@ -120,6 +120,8 @@ void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin skin->mInvalidJointsScrubbed = true; } +#define MAT_USE_SSE 1 + void LLSkinningUtil::initSkinningMatrixPalette( LLMatrix4* mat, S32 count, @@ -129,10 +131,15 @@ void LLSkinningUtil::initSkinningMatrixPalette( initJointNums(const_cast<LLMeshSkinInfo*>(skin), avatar); for (U32 j = 0; j < count; ++j) { - LLJoint *joint = avatar->getJoint(skin->mJointNums[j]); + S32 joint_num = skin->mJointNums[j]; + LLJoint *joint = NULL; + if (joint_num >= 0 && joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS) + { + joint = avatar->getJoint(joint_num); + } + llassert(joint); if (joint) { -#define MAT_USE_SSE #ifdef MAT_USE_SSE LLMatrix4a bind, world, res; bind.loadu(skin->mInvBindMatrix[j]); @@ -147,6 +154,7 @@ void LLSkinningUtil::initSkinningMatrixPalette( else { mat[j] = skin->mInvBindMatrix[j]; +#if DEBUG_SKINNING // This shouldn't happen - in mesh upload, skinned // rendering should be disabled unless all joints are // valid. In other cases of skinned rendering, invalid @@ -157,16 +165,15 @@ void LLSkinningUtil::initSkinningMatrixPalette( LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " avatar build state: isBuilt() " << avatar->isBuilt() << " mInitFlags " << avatar->mInitFlags << LL_ENDL; -#if 0 - dump_avatar_and_skin_state("initSkinningMatrixPalette joint not found", avatar, skin); #endif + dump_avatar_and_skin_state("initSkinningMatrixPalette joint not found", avatar, skin); } } } void LLSkinningUtil::checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin) { -#ifdef SHOW_ASSERT // same condition that controls llassert() +#if DEBUG_SKINNING const S32 max_joints = skin->mJointNames.size(); for (U32 j=0; j<num_vertices; j++) { @@ -265,6 +272,7 @@ void LLSkinningUtil::initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar) { for (U32 j = 0; j < skin->mJointNames.size(); ++j) { + #if DEBUG_SKINNING LLJoint *joint = NULL; if (skin->mJointNums[j] == -1) { @@ -282,11 +290,16 @@ void LLSkinningUtil::initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar) { 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->mJointNums[j] = 0; } } + #else + LLJoint *joint = (skin->mJointNums[j] == -1) ? avatar->getJoint(skin->mJointNames[j]) : avatar->getJoint(skin->mJointNums[j]); + skin->mJointNums[j] = joint ? joint->getJointNum() : 0; + #endif + // insure we have *a* valid joint to reference + llassert(skin->mJointNums[j] >= 0); } skin->mJointNumsInitialized = true; } @@ -301,7 +314,8 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a if (vol_face.mJointRiggingInfoTab.needsUpdate()) { S32 num_verts = vol_face.mNumVertices; - if (num_verts>0 && vol_face.mWeights && (skin->mJointNames.size()>0)) + S32 num_joints = skin->mJointNames.size(); + if (num_verts > 0 && vol_face.mWeights && num_joints > 0) { initJointNums(const_cast<LLMeshSkinInfo*>(skin), avatar); if (vol_face.mJointRiggingInfoTab.size()==0) @@ -335,7 +349,7 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a for (U32 k=0; k<4; ++k) { S32 joint_index = idx[k]; - if (wght[k] > 0.0f) + if (wght[k] > 0.0f && num_joints > joint_index) { S32 joint_num = skin->mJointNums[joint_index]; if (joint_num >= 0 && joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS) @@ -344,14 +358,17 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a // FIXME could precompute these matMuls. LLMatrix4a bind_shape; - bind_shape.loadu(skin->mBindShapeMatrix); LLMatrix4a inv_bind; - inv_bind.loadu(skin->mInvBindMatrix[joint_index]); LLMatrix4a mat; - matMul(bind_shape, inv_bind, mat); LLVector4a pos_joint_space; + + bind_shape.loadu(skin->mBindShapeMatrix); + inv_bind.loadu(skin->mInvBindMatrix[joint_index]); + matMul(bind_shape, inv_bind, mat); + mat.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); } @@ -366,6 +383,8 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a vol_face.mJointRiggingInfoTab.setNeedsUpdate(false); } } + +#if DEBUG_SKINNING if (vol_face.mJointRiggingInfoTab.size()!=0) { LL_DEBUGS("RigSpammish") << "we have rigging info for vf " << &vol_face @@ -376,6 +395,7 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a LL_DEBUGS("RigSpammish") << "no rigging info for vf " << &vol_face << " num_verts " << vol_face.mNumVertices << LL_ENDL; } +#endif } } diff --git a/indra/newview/llskinningutil.h b/indra/newview/llskinningutil.h index ccc501adc0..efe7c85997 100644 --- a/indra/newview/llskinningutil.h +++ b/indra/newview/llskinningutil.h @@ -27,21 +27,44 @@ #ifndef LLSKINNINGUTIL_H #define LLSKINNINGUTIL_H +#include "v2math.h" +#include "v4math.h" +#include "llvector4a.h" +#include "llmatrix4a.h" + class LLVOAvatar; class LLMeshSkinInfo; -class LLMatrix4a; class LLVolumeFace; +class LLJointRiggingInfoTab; namespace LLSkinningUtil { - void initClass(); - U32 getMaxJointCount(); + S32 getMaxJointCount(); U32 getMeshJointCount(const LLMeshSkinInfo *skin); void scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin); void initSkinningMatrixPalette(LLMatrix4* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar); void checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); void scrubSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); void getPerVertexSkinMatrix(F32* weights, LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints); + + LL_FORCE_INLINE void getPerVertexSkinMatrixWithIndices( + F32* weights, + U8* idx, + LLMatrix4a* mat, + LLMatrix4a& final_mat, + LLMatrix4a* src) + { + final_mat.clear(); + src[0].setMul(mat[idx[0]], weights[0]); + src[1].setMul(mat[idx[1]], weights[1]); + final_mat.add(src[0]); + final_mat.add(src[1]); + src[2].setMul(mat[idx[2]], weights[2]); + src[3].setMul(mat[idx[3]], weights[3]); + final_mat.add(src[2]); + final_mat.add(src[3]); + } + void initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar); void updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *avatar, LLVolumeFace& vol_face); LLQuaternion getUnscaledQuaternion(const LLMatrix4& mat4); diff --git a/indra/newview/llsky.cpp b/indra/newview/llsky.cpp index 5e2442798b..ac7dbcacaa 100644 --- a/indra/newview/llsky.cpp +++ b/indra/newview/llsky.cpp @@ -51,19 +51,16 @@ #include "llvosky.h" #include "llcubemap.h" #include "llviewercontrol.h" -#include "llenvmanager.h" - +#include "llenvironment.h" +#include "llvoavatarself.h" #include "llvowlsky.h" F32 azimuth_from_vector(const LLVector3 &v); F32 elevation_from_vector(const LLVector3 &v); -LLSky gSky; -// ---------------- LLSky ---------------- - -const F32 LLSky::NIGHTTIME_ELEVATION = -8.0f; // degrees -const F32 LLSky::NIGHTTIME_ELEVATION_COS = (F32)sin(NIGHTTIME_ELEVATION*DEG_TO_RAD); +LLSky gSky; +// ---------------- LLSky ---------------- ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// @@ -77,8 +74,6 @@ LLSky::LLSky() mLightingGeneration = 0; mUpdatedThisFrame = TRUE; - mOverrideSimSunPosition = FALSE; - mSunPhase = 0.f; } @@ -134,211 +129,89 @@ void LLSky::resetVertexBuffers() } } -void LLSky::setOverrideSun(BOOL override) +void LLSky::setSunScale(F32 sun_scale) { - if (!mOverrideSimSunPosition && override) - { - mLastSunDirection = getSunDirection(); - } - else if (mOverrideSimSunPosition && !override) - { - setSunDirection(mLastSunDirection, LLVector3::zero); + if(mVOSkyp.notNull()) + { + mVOSkyp->setSunScale(sun_scale); } - mOverrideSimSunPosition = override; } -void LLSky::setSunDirection(const LLVector3 &sun_direction, const LLVector3 &sun_ang_velocity) +void LLSky::setMoonScale(F32 moon_scale) { - if(mVOSkyp.notNull()) { - mVOSkyp->setSunDirection(sun_direction, sun_ang_velocity); + if(mVOSkyp.notNull()) + { + mVOSkyp->setMoonScale(moon_scale); } } - -void LLSky::setSunTargetDirection(const LLVector3 &sun_direction, const LLVector3 &sun_ang_velocity) -{ - mSunTargDir = sun_direction; -} - - -LLVector3 LLSky::getSunDirection() const +void LLSky::setSunTextures(const LLUUID& sun_texture, const LLUUID& sun_texture_next) { - if (mVOSkyp) - { - return mVOSkyp->getToSun(); - } - else - { - return LLVector3::z_axis; + if(mVOSkyp.notNull()) { + mVOSkyp->setSunTextures(sun_texture, sun_texture_next); } } - -LLVector3 LLSky::getMoonDirection() const +void LLSky::setMoonTextures(const LLUUID& moon_texture, const LLUUID& moon_texture_next) { - if (mVOSkyp) - { - return mVOSkyp->getToMoon(); - } - else - { - return LLVector3::z_axis; + if(mVOSkyp.notNull()) { + mVOSkyp->setMoonTextures(moon_texture, moon_texture_next); } } - -LLColor4 LLSky::getSunDiffuseColor() const +void LLSky::setCloudNoiseTextures(const LLUUID& cloud_noise_texture, const LLUUID& cloud_noise_texture_next) { - if (mVOSkyp) - { - return LLColor4(mVOSkyp->getSunDiffuseColor()); - } - else - { - return LLColor4(1.f, 1.f, 1.f, 1.f); + if(mVOSkyp.notNull()) { + mVOSkyp->setCloudNoiseTextures(cloud_noise_texture, cloud_noise_texture_next); } } -LLColor4 LLSky::getSunAmbientColor() const -{ - if (mVOSkyp) - { - return LLColor4(mVOSkyp->getSunAmbientColor()); - } - else - { - return LLColor4(0.f, 0.f, 0.f, 1.f); - } -} - - -LLColor4 LLSky::getMoonDiffuseColor() const +void LLSky::setBloomTextures(const LLUUID& bloom_texture, const LLUUID& bloom_texture_next) { - if (mVOSkyp) - { - return LLColor4(mVOSkyp->getMoonDiffuseColor()); - } - else - { - return LLColor4(1.f, 1.f, 1.f, 1.f); - } -} - -LLColor4 LLSky::getMoonAmbientColor() const -{ - if (mVOSkyp) - { - return LLColor4(mVOSkyp->getMoonAmbientColor()); - } - else - { - return LLColor4(0.f, 0.f, 0.f, 0.f); + if(mVOSkyp.notNull()) { + mVOSkyp->setBloomTextures(bloom_texture, bloom_texture_next); } } - -LLColor4 LLSky::getTotalAmbientColor() const +void LLSky::setSunAndMoonDirectionsCFR(const LLVector3 &sun_direction, const LLVector3 &moon_direction) { - if (mVOSkyp) - { - return mVOSkyp->getTotalAmbientColor(); - } - else - { - return LLColor4(1.f, 1.f, 1.f, 1.f); + if(mVOSkyp.notNull()) { + mVOSkyp->setSunAndMoonDirectionsCFR(sun_direction, moon_direction); } } - -BOOL LLSky::sunUp() const +void LLSky::setSunDirectionCFR(const LLVector3 &sun_direction) { - if (mVOSkyp) - { - return mVOSkyp->isSunUp(); - } - else - { - return TRUE; + if(mVOSkyp.notNull()) { + mVOSkyp->setSunDirectionCFR(sun_direction); } } - -LLColor4U LLSky::getFadeColor() const +void LLSky::setMoonDirectionCFR(const LLVector3 &moon_direction) { - if (mVOSkyp) - { - return mVOSkyp->getFadeColor(); - } - else - { - return LLColor4(1.f, 1.f, 1.f, 1.f); + if(mVOSkyp.notNull()) { + mVOSkyp->setMoonDirectionCFR(moon_direction); } } - ////////////////////////////////////////////////////////////////////// // Public Methods ////////////////////////////////////////////////////////////////////// -void LLSky::init(const LLVector3 &sun_direction) +void LLSky::init() { - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - mVOWLSkyp = static_cast<LLVOWLSky*>(gObjectList.createObjectViewer(LLViewerObject::LL_VO_WL_SKY, NULL)); - mVOWLSkyp->initSunDirection(sun_direction, LLVector3::zero); + mVOWLSkyp->init(); gPipeline.createObject(mVOWLSkyp.get()); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - mVOSkyp = (LLVOSky *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_SKY, NULL); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - - mVOSkyp->initSunDirection(sun_direction, LLVector3()); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - - gPipeline.createObject((LLViewerObject *)mVOSkyp); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + mVOSkyp->init(); + gPipeline.createObject(mVOSkyp.get()); mVOGroundp = (LLVOGround*)gObjectList.createObjectViewer(LLViewerObject::LL_VO_GROUND, NULL); - LLVOGround *groundp = mVOGroundp; - gPipeline.createObject((LLViewerObject *)groundp); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - - gSky.setFogRatio(gSavedSettings.getF32("RenderFogRatio")); - - //////////////////////////// - // - // Legacy code, ignore - // - // - - // Get the parameters. - mSunDefaultPosition = gSavedSettings.getVector3("SkySunDefaultPosition"); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - - if (gSavedSettings.getBOOL("SkyOverrideSimSunPosition") || mOverrideSimSunPosition) - { - setSunDirection(mSunDefaultPosition, LLVector3(0.f, 0.f, 0.f)); - } - else - { - setSunDirection(sun_direction, LLVector3(0.f, 0.f, 0.f)); - } + gPipeline.createObject(mVOGroundp.get()); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + gSky.setFogRatio(gSavedSettings.getF32("RenderFogRatio")); mUpdatedThisFrame = TRUE; } @@ -361,37 +234,21 @@ void LLSky::setWind(const LLVector3& average_wind) } } +void LLSky::addSunMoonBeacons() +{ + if (!gAgentAvatarp || !mVOSkyp) return; -void LLSky::propagateHeavenlyBodies(F32 dt) -{ - if (!mOverrideSimSunPosition) + static LLUICachedControl<bool> show_sun_beacon("sunbeacon", false); + static LLUICachedControl<bool> show_moon_beacon("moonbeacon", false); + + if (show_sun_beacon) { - LLVector3 curr_dir = getSunDirection(); - LLVector3 diff = mSunTargDir - curr_dir; - const F32 dist = diff.normVec(); - if (dist > 0) - { - const F32 step = llmin (dist, 0.00005f); - //const F32 step = min (dist, 0.0001); - diff *= step; - curr_dir += diff; - curr_dir.normVec(); - if (mVOSkyp) - { - mVOSkyp->setSunDirection(curr_dir, LLVector3()); - } - } + renderSunMoonBeacons(gAgentAvatarp->getPositionAgent(), mVOSkyp->getSun().getDirection(), LLColor4(1.f, 0.5f, 0.f, 0.5f)); + } + if (show_moon_beacon) + { + renderSunMoonBeacons(gAgentAvatarp->getPositionAgent(), mVOSkyp->getMoon().getDirection(), LLColor4(1.f, 0.f, 0.8f, 0.5f)); } -} - -F32 LLSky::getSunPhase() const -{ - return mSunPhase; -} - -void LLSky::setSunPhase(const F32 phase) -{ - mSunPhase = phase; } ////////////////////////////////////////////////////////////////////// @@ -399,11 +256,11 @@ void LLSky::setSunPhase(const F32 phase) ////////////////////////////////////////////////////////////////////// -LLColor4 LLSky::getFogColor() const +LLColor4 LLSky::getSkyFogColor() const { if (mVOSkyp) { - return mVOSkyp->getFogColor(); + return mVOSkyp->getSkyFogColor(); } return LLColor4(1.f, 1.f, 1.f, 1.f); diff --git a/indra/newview/llsky.h b/indra/newview/llsky.h index 7b98c97840..8c0d70c16c 100644 --- a/indra/newview/llsky.h +++ b/indra/newview/llsky.h @@ -48,16 +48,23 @@ public: LLSky(); ~LLSky(); - void init(const LLVector3 &sun_direction); - + void init(); void cleanup(); - void setOverrideSun(BOOL override); - BOOL getOverrideSun() { return mOverrideSimSunPosition; } - void setSunDirection(const LLVector3 &sun_direction, const LLVector3 &sun_ang_velocity); - void setSunTargetDirection(const LLVector3 &sun_direction, const LLVector3 &sun_ang_velocity); + // These directions should be in CFR coord sys (+x at, +z up, +y right) + void setSunAndMoonDirectionsCFR(const LLVector3 &sun_direction, const LLVector3 &moon_direction); + void setSunDirectionCFR(const LLVector3 &sun_direction); + void setMoonDirectionCFR(const LLVector3 &moon_direction); + + void setSunTextures(const LLUUID& sun_texture, const LLUUID& sun_texture_next); + void setMoonTextures(const LLUUID& moon_texture, const LLUUID& moon_texture_next); + void setCloudNoiseTextures(const LLUUID& cloud_noise_texture, const LLUUID& cloud_noise_texture_next); + void setBloomTextures(const LLUUID& bloom_texture, const LLUUID& bloom_texture_next); - LLColor4 getFogColor() const; + void setSunScale(F32 sun_scale); + void setMoonScale(F32 moon_scale); + + LLColor4 getSkyFogColor() const; void setCloudDensityAtAgent(F32 cloud_density); void setWind(const LLVector3& wind); @@ -66,8 +73,6 @@ public: void updateCull(); void updateSky(); - void propagateHeavenlyBodies(F32 dt); // dt = seconds - S32 mLightingGeneration; BOOL mUpdatedThisFrame; @@ -75,44 +80,21 @@ public: F32 getFogRatio() const; LLColor4U getFadeColor() const; - LLVector3 getSunDirection() const; - LLVector3 getMoonDirection() const; - LLColor4 getSunDiffuseColor() const; - LLColor4 getMoonDiffuseColor() const; - LLColor4 getSunAmbientColor() const; - LLColor4 getMoonAmbientColor() const; - LLColor4 getTotalAmbientColor() const; - BOOL sunUp() const; - - F32 getSunPhase() const; - void setSunPhase(const F32 phase); - void destroyGL(); void restoreGL(); void resetVertexBuffers(); + void addSunMoonBeacons(); + void renderSunMoonBeacons(const LLVector3& pos_agent, const LLVector3& direction, LLColor4 color); + public: LLPointer<LLVOSky> mVOSkyp; // Pointer to the LLVOSky object (only one, ever!) LLPointer<LLVOGround> mVOGroundp; - LLPointer<LLVOWLSky> mVOWLSkyp; - LLVector3 mSunTargDir; - - // Legacy stuff - LLVector3 mSunDefaultPosition; - - static const F32 NIGHTTIME_ELEVATION; // degrees - static const F32 NIGHTTIME_ELEVATION_COS; - protected: - BOOL mOverrideSimSunPosition; - - F32 mSunPhase; - LLColor4 mFogColor; // Color to use for fog and haze - - LLVector3 mLastSunDirection; + LLColor4 mFogColor; }; -extern LLSky gSky; +extern LLSky gSky; #endif diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index f5fea9dece..8369def968 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -28,14 +28,12 @@ #include "llviewerprecompiledheaders.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llagentcamera.h" #include "llagentui.h" #include "llcombobox.h" -#include "lleconomy.h" #include "llfloaterperms.h" #include "llfloaterreg.h" -#include "llfloaterflickr.h" -#include "llfloatertwitter.h" #include "llimagefilter.h" #include "llimagefiltersmanager.h" #include "llimagebmp.h" @@ -65,6 +63,7 @@ F32 SHINE_WIDTH = 0.6f; F32 SHINE_OPACITY = 0.3f; F32 FALL_TIME = 0.6f; S32 BORDER_WIDTH = 6; +S32 TOP_PANEL_HEIGHT = 30; const S32 MAX_TEXTURE_SIZE = 512 ; //max upload texture size 512 * 512 @@ -156,7 +155,7 @@ F32 LLSnapshotLivePreview::getImageAspect() void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail, F32 delay) { - LL_DEBUGS() << "updateSnapshot: mSnapshotUpToDate = " << getSnapshotUpToDate() << LL_ENDL; + LL_DEBUGS("Snapshot") << "updateSnapshot: mSnapshotUpToDate = " << getSnapshotUpToDate() << LL_ENDL; // Update snapshot if requested. if (new_snapshot) @@ -295,8 +294,8 @@ void LLSnapshotLivePreview::draw() F32 uv_width = isImageScaled() ? 1.f : llmin((F32)getWidth() / (F32)getCurrentImage()->getWidth(), 1.f); F32 uv_height = isImageScaled() ? 1.f : llmin((F32)getHeight() / (F32)getCurrentImage()->getHeight(), 1.f); gGL.pushMatrix(); - { - gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom, 0.f); + { + gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom + TOP_PANEL_HEIGHT, 0.f); gGL.begin(LLRender::QUADS); { gGL.texCoord2f(uv_width, uv_height); @@ -344,18 +343,19 @@ void LLSnapshotLivePreview::draw() } else if (mShineAnimTimer.getStarted()) { - LL_DEBUGS() << "Drawing shining animation" << LL_ENDL; + LL_DEBUGS("Snapshot") << "Drawing shining animation" << LL_ENDL; F32 shine_interp = llmin(1.f, mShineAnimTimer.getElapsedTimeF32() / SHINE_TIME); // draw "shine" effect - LLLocalClipRect clip(getLocalRect()); + LLRect local_rect(0, getRect().getHeight() + TOP_PANEL_HEIGHT, getRect().getWidth(), 0); + LLLocalClipRect clip(local_rect); { // draw diagonal stripe with gradient that passes over screen 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(); + S32 y2 = gViewerWindow->getWindowHeightScaled() + TOP_PANEL_HEIGHT; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.begin(LLRender::QUADS); @@ -385,43 +385,13 @@ void LLSnapshotLivePreview::draw() } } - // draw framing rectangle - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4f(1.f, 1.f, 1.f, 1.f); - const LLRect& outline_rect = getImageRect(); - gGL.begin(LLRender::QUADS); - { - gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); - 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.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.end(); - } - // draw old image dropping away if (mFallAnimTimer.getStarted()) { S32 old_image_index = (mCurImageIndex + 1) % 2; if (mViewerImage[old_image_index].notNull() && mFallAnimTimer.getElapsedTimeF32() < FALL_TIME) { - LL_DEBUGS() << "Drawing fall animation" << LL_ENDL; + LL_DEBUGS("Snapshot") << "Drawing fall animation" << LL_ENDL; F32 fall_interp = mFallAnimTimer.getElapsedTimeF32() / FALL_TIME; F32 alpha = clamp_rescale(fall_interp, 0.f, 1.f, 0.8f, 0.4f); LLColor4 image_color(1.f, 1.f, 1.f, alpha); @@ -465,7 +435,7 @@ void LLSnapshotLivePreview::reshape(S32 width, S32 height, BOOL called_from_pare LLView::reshape(width, height, called_from_parent); if (old_rect.getWidth() != width || old_rect.getHeight() != height) { - LL_DEBUGS() << "window reshaped, updating thumbnail" << LL_ENDL; + LL_DEBUGS("Window", "Snapshot") << "window reshaped, updating thumbnail" << LL_ENDL; if (mViewContainer && mViewContainer->isInVisibleChain()) { // We usually resize only on window reshape, so give it a chance to redraw, assign delay @@ -588,6 +558,7 @@ void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update) if(!gViewerWindow->thumbnailSnapshot(raw, mThumbnailWidth, mThumbnailHeight, mAllowRenderUI && gSavedSettings.getBOOL("RenderUIInSnapshot"), + gSavedSettings.getBOOL("RenderHUDInSnapshot"), FALSE, mSnapshotBufferType) ) { @@ -609,7 +580,7 @@ void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update) } else { - LL_WARNS() << "Couldn't find a path to the following filter : " << getFilter() << LL_ENDL; + LL_WARNS("Snapshot") << "Couldn't find a path to the following filter : " << getFilter() << LL_ENDL; } } // Scale to a power of 2 so it can be mapped to a texture @@ -657,7 +628,7 @@ LLViewerTexture* LLSnapshotLivePreview::getBigThumbnailImage() } else { - LL_WARNS() << "Couldn't find a path to the following filter : " << getFilter() << LL_ENDL; + LL_WARNS("Snapshot") << "Couldn't find a path to the following filter : " << getFilter() << LL_ENDL; } } // Scale to a power of 2 so it can be mapped to a texture @@ -677,7 +648,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)snapshot_preview; if (previewp->getWidth() == 0 || previewp->getHeight() == 0) { - LL_WARNS() << "Incorrect dimensions: " << previewp->getWidth() << "x" << previewp->getHeight() << LL_ENDL; + LL_WARNS("Snapshot") << "Incorrect dimensions: " << previewp->getWidth() << "x" << previewp->getHeight() << LL_ENDL; return FALSE; } @@ -708,7 +679,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) previewp->mCameraRot = new_camera_rot; // request a new snapshot whenever the camera moves, with a time delay BOOL new_snapshot = gSavedSettings.getBOOL("AutoSnapshot") || previewp->mForceUpdateSnapshot; - LL_DEBUGS() << "camera moved, updating thumbnail" << LL_ENDL; + LL_DEBUGS("Snapshot") << "camera moved, updating thumbnail" << LL_ENDL; previewp->updateSnapshot( new_snapshot, // whether a new snapshot is needed or merely invalidate the existing one FALSE, // or if 1st arg is false, whether to produce a new thumbnail image. @@ -724,7 +695,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) // time to produce a snapshot if(!previewp->getSnapshotUpToDate()) { - LL_DEBUGS() << "producing snapshot" << LL_ENDL; + LL_DEBUGS("Snapshot") << "producing snapshot" << LL_ENDL; if (!previewp->mPreviewImage) { previewp->mPreviewImage = new LLImageRaw; @@ -746,6 +717,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) previewp->mKeepAspectRatio,//gSavedSettings.getBOOL("KeepAspectForSnapshot"), previewp->getSnapshotType() == LLSnapshotModel::SNAPSHOT_TEXTURE, previewp->mAllowRenderUI && gSavedSettings.getBOOL("RenderUIInSnapshot"), + gSavedSettings.getBOOL("RenderHUDInSnapshot"), FALSE, previewp->mSnapshotBufferType, previewp->getMaxImageSize())) @@ -773,7 +745,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) previewp->getWindow()->decBusyCount(); previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame") && previewp->mAllowFullScreenPreview); // only show fullscreen preview when in freeze frame mode previewp->mSnapshotActive = FALSE; - LL_DEBUGS() << "done creating snapshot" << LL_ENDL; + LL_DEBUGS("Snapshot") << "done creating snapshot" << LL_ENDL; } if (!previewp->getThumbnailUpToDate()) @@ -864,7 +836,7 @@ LLPointer<LLImageRaw> LLSnapshotLivePreview::getEncodedImage() if (getSnapshotType() == LLSnapshotModel::SNAPSHOT_TEXTURE) { // We don't store the intermediate formatted image in mFormattedImage in the J2C case - LL_DEBUGS() << "Encoding new image of format J2C" << LL_ENDL; + LL_DEBUGS("Snapshot") << "Encoding new image of format J2C" << LL_ENDL; LLPointer<LLImageJ2C> formatted = new LLImageJ2C; // Copy the preview LLPointer<LLImageRaw> scaled = new LLImageRaw( @@ -949,13 +921,13 @@ LLPointer<LLImageFormatted> LLSnapshotLivePreview::getFormattedImage() } else { - LL_WARNS() << "Couldn't find a path to the following filter : " << getFilter() << LL_ENDL; + LL_WARNS("Snapshot") << "Couldn't find a path to the following filter : " << getFilter() << LL_ENDL; } } // Create the new formatted image of the appropriate format. LLSnapshotModel::ESnapshotFormat format = getSnapshotFormat(); - LL_DEBUGS() << "Encoding new image of format " << format << LL_ENDL; + LL_DEBUGS("Snapshot") << "Encoding new image of format " << format << LL_ENDL; switch (format) { @@ -980,7 +952,7 @@ LLPointer<LLImageFormatted> LLSnapshotLivePreview::getFormattedImage() void LLSnapshotLivePreview::setSize(S32 w, S32 h) { - LL_DEBUGS() << "setSize(" << w << ", " << h << ")" << LL_ENDL; + LL_DEBUGS("Snapshot") << "setSize(" << w << ", " << h << ")" << LL_ENDL; setWidth(w); setHeight(h); } @@ -1002,7 +974,7 @@ void LLSnapshotLivePreview::getSize(S32& w, S32& h) const void LLSnapshotLivePreview::saveTexture(BOOL outfit_snapshot, std::string name) { - LL_DEBUGS() << "saving texture: " << mPreviewImage->getWidth() << "x" << mPreviewImage->getHeight() << LL_ENDL; + LL_DEBUGS("Snapshot") << "saving texture: " << mPreviewImage->getWidth() << "x" << mPreviewImage->getHeight() << LL_ENDL; // gen a new uuid for this asset LLTransactionID tid; tid.generate(); @@ -1025,12 +997,12 @@ void LLSnapshotLivePreview::saveTexture(BOOL outfit_snapshot, std::string name) } else { - LL_WARNS() << "Couldn't find a path to the following filter : " << getFilter() << LL_ENDL; + LL_WARNS("Snapshot") << "Couldn't find a path to the following filter : " << getFilter() << LL_ENDL; } } scaled->biasedScaleToPowerOfTwo(MAX_TEXTURE_SIZE); - LL_DEBUGS() << "scaled texture to " << scaled->getWidth() << "x" << scaled->getHeight() << LL_ENDL; + LL_DEBUGS("Snapshot") << "scaled texture to " << scaled->getWidth() << "x" << scaled->getHeight() << LL_ENDL; if (formatted->encode(scaled, 0.0f)) { @@ -1039,7 +1011,7 @@ void LLSnapshotLivePreview::saveTexture(BOOL outfit_snapshot, std::string name) LLAgentUI::buildLocationString(pos_string, LLAgentUI::LOCATION_FORMAT_FULL); std::string who_took_it; LLAgentUI::buildFullname(who_took_it); - S32 expected_upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload(); + S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); std::string res_name = outfit_snapshot ? name : "Snapshot : " + pos_string; std::string res_desc = outfit_snapshot ? "" : "Taken by " + who_took_it + " at " + pos_string; LLFolderType::EType folder_type = outfit_snapshot ? LLFolderType::FT_NONE : LLFolderType::FT_SNAPSHOT_CATEGORY; @@ -1058,7 +1030,7 @@ void LLSnapshotLivePreview::saveTexture(BOOL outfit_snapshot, std::string name) else { LLNotificationsUtil::add("ErrorEncodingSnapshot"); - LL_WARNS() << "Error encoding snapshot" << LL_ENDL; + LL_WARNS("Snapshot") << "Error encoding snapshot" << LL_ENDL; } add(LLStatViewer::SNAPSHOT, 1); diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 1dc1e65fe5..efa4a7fd66 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -55,8 +55,6 @@ #include "llviewershadermgr.h" #include "llcontrolavatar.h" -//#pragma optimize("", off) - static LLTrace::BlockTimerStatHandle FTM_FRUSTUM_CULL("Frustum Culling"); static LLTrace::BlockTimerStatHandle FTM_CULL_REBOUND("Cull Rebound Partition"); @@ -558,7 +556,9 @@ void LLSpatialGroup::shift(const LLVector4a &offset) if (!getSpatialPartition()->mRenderByGroup && getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_TREE && getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_TERRAIN && - getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_BRIDGE) + getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_BRIDGE && + getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_AVATAR && + getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_CONTROL_AV) { setState(GEOM_DIRTY); gPipeline.markRebuild(this, TRUE); @@ -996,7 +996,7 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible) } LLSpatialGroup* group = drawablep->getSpatialGroup(); - llassert(group != NULL); + //llassert(group != NULL); if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING)) { @@ -1091,6 +1091,11 @@ public: virtual bool earlyFail(LLViewerOctreeGroup* base_group) { + if (LLPipeline::sReflectionRender) + { + return false; + } + LLSpatialGroup* group = (LLSpatialGroup*)base_group; group->checkOcclusion(); @@ -2248,52 +2253,91 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE) } } -void renderNormals(LLDrawable* drawablep) -{ - LLVertexBuffer::unbind(); - - LLVOVolume* vol = drawablep->getVOVolume(); - if (vol) - { - LLVolume* volume = vol->getVolume(); - gGL.pushMatrix(); - gGL.multMatrix((F32*) vol->getRelativeXform().mMatrix); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - LLVector4a scale(gSavedSettings.getF32("RenderDebugNormalScale")); - - for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = volume->getVolumeFace(i); - - for (S32 j = 0; j < face.mNumVertices; ++j) - { - gGL.begin(LLRender::LINES); - LLVector4a n,p; - - n.setMul(face.mNormals[j], scale); - p.setAdd(face.mPositions[j], n); - - gGL.diffuseColor4f(1,1,1,1); - gGL.vertex3fv(face.mPositions[j].getF32ptr()); - gGL.vertex3fv(p.getF32ptr()); - - if (face.mTangents) - { - n.setMul(face.mTangents[j], scale); - p.setAdd(face.mPositions[j], n); - - gGL.diffuseColor4f(0,1,1,1); - gGL.vertex3fv(face.mPositions[j].getF32ptr()); - gGL.vertex3fv(p.getF32ptr()); - } - gGL.end(); - } - } - - gGL.popMatrix(); - } +void renderNormals(LLDrawable *drawablep) +{ + if (!drawablep->isVisible()) + return; + + LLVertexBuffer::unbind(); + + LLVOVolume *vol = drawablep->getVOVolume(); + + if (vol) + { + LLVolume *volume = vol->getVolume(); + + // Drawable's normals & tangents are stored in model space, i.e. before any scaling is applied. + // + // SL-13490, using pos + normal to compute the 2nd vertex of a normal line segment doesn't + // work when there's a non-uniform scale in the mix. Normals require MVP-inverse-transpose + // transform. We get that effect here by pre-applying the inverse scale (twice, because + // one forward scale will be re-applied via the MVP in the vertex shader) + + LLVector3 scale_v3 = vol->getScale(); + float scale_len = scale_v3.length(); + LLVector4a obj_scale(scale_v3.mV[VX], scale_v3.mV[VY], scale_v3.mV[VZ]); + obj_scale.normalize3(); + + // Normals &tangent line segments get scaled along with the object. Divide by scale length + // to keep the as-viewed lengths (relatively) constant with the debug setting length + float draw_length = gSavedSettings.getF32("RenderDebugNormalScale") / scale_len; + + // Create inverse-scale vector for normals + LLVector4a inv_scale(1.0 / scale_v3.mV[VX], 1.0 / scale_v3.mV[VY], 1.0 / scale_v3.mV[VZ]); + inv_scale.mul(inv_scale); // Squared, to apply inverse scale twice + inv_scale.normalize3fast(); + + gGL.pushMatrix(); + gGL.multMatrix((F32 *) vol->getRelativeXform().mMatrix); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) + { + const LLVolumeFace &face = volume->getVolumeFace(i); + + gGL.flush(); + gGL.diffuseColor4f(1, 1, 0, 1); + gGL.begin(LLRender::LINES); + for (S32 j = 0; j < face.mNumVertices; ++j) + { + LLVector4a n, p; + + n.setMul(face.mNormals[j], 1.0); + n.mul(inv_scale); // Pre-scale normal, so it's left with an inverse-transpose xform after MVP + n.normalize3fast(); + n.mul(draw_length); + p.setAdd(face.mPositions[j], n); + + gGL.vertex3fv(face.mPositions[j].getF32ptr()); + gGL.vertex3fv(p.getF32ptr()); + } + gGL.end(); + + // Tangents are simple vectors and do not require reorientation via pre-scaling + if (face.mTangents) + { + gGL.flush(); + gGL.diffuseColor4f(0, 1, 1, 1); + gGL.begin(LLRender::LINES); + for (S32 j = 0; j < face.mNumVertices; ++j) + { + LLVector4a t, p; + + t.setMul(face.mTangents[j], 1.0f); + t.normalize3fast(); + t.mul(draw_length); + p.setAdd(face.mPositions[j], t); + + gGL.vertex3fv(face.mPositions[j].getF32ptr()); + gGL.vertex3fv(p.getF32ptr()); + } + gGL.end(); + } + } + + gGL.popMatrix(); + } } S32 get_physics_detail(const LLVolumeParams& volume_params, const LLVector3& scale) @@ -3120,13 +3164,13 @@ void renderRaycast(LLDrawable* drawablep) LLGLEnable blend(GL_BLEND); gGL.diffuseColor4f(0,1,1,0.5f); - if (drawablep->getVOVolume()) + LLVOVolume* vobj = drawablep->getVOVolume(); + if (vobj && !vobj->isDead()) { //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //pushVerts(drawablep->getFace(gDebugRaycastFaceHit), LLVertexBuffer::MAP_VERTEX); //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - LLVOVolume* vobj = drawablep->getVOVolume(); LLVolume* volume = vobj->getVolume(); bool transform = true; @@ -3355,7 +3399,7 @@ public: for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) { LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); - if(!drawable) + if(!drawable || drawable->isDead()) { continue; } @@ -3445,7 +3489,7 @@ public: U8 index = facep->getTextureIndex(); if (facep->mDrawInfo) { - if (index < 255) + if (index < FACE_DO_NOT_BATCH_TEXTURES) { if (facep->mDrawInfo->mTextureList.size() <= index) { diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 7e65da42f7..919f386d29 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -685,6 +685,18 @@ public: virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { LLVolumeGeometryManager::addGeometryCount(group, vertex_count, index_count); } }; +class LLAvatarBridge : public LLVolumeBridge +{ +public: + LLAvatarBridge(LLDrawable* drawablep, LLViewerRegion* regionp); +}; + +class LLControlAVBridge : public LLVolumeBridge +{ +public: + LLControlAVBridge(LLDrawable* drawablep, LLViewerRegion* regionp); +}; + class LLHUDBridge : public LLVolumeBridge { public: @@ -702,6 +714,18 @@ public: virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { } }; +class LLAvatarPartition : public LLBridgePartition +{ +public: + LLAvatarPartition(LLViewerRegion* regionp); +}; + +class LLControlAVPartition : public LLBridgePartition +{ +public: + LLControlAVPartition(LLViewerRegion* regionp); +}; + class LLHUDPartition : public LLBridgePartition { public: diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 6e0a36be49..1242131534 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -39,8 +39,8 @@ #include "llviewermedia_streamingaudio.h" #include "llaudioengine.h" -#ifdef LL_FMODEX -# include "llaudioengine_fmodex.h" +#ifdef LL_FMODSTUDIO +# include "llaudioengine_fmodstudio.h" #endif #ifdef LL_OPENAL @@ -71,6 +71,7 @@ #include "llnotifications.h" #include "llnotificationsutil.h" #include "llpersistentnotificationstorage.h" +#include "llpresetsmanager.h" #include "llteleporthistory.h" #include "llregionhandle.h" #include "llsd.h" @@ -88,6 +89,7 @@ #include "v3math.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llagentcamera.h" #include "llagentpicksinfo.h" #include "llagentwearables.h" @@ -106,7 +108,6 @@ //#include "llfirstuse.h" #include "llfloaterhud.h" #include "llfloaterland.h" -#include "llfloaterpreference.h" #include "llfloatertopobjects.h" #include "llfloaterworldmap.h" #include "llgesturemgr.h" @@ -127,10 +128,12 @@ #include "llpanelpick.h" #include "llpanelgrouplandmoney.h" #include "llpanelgroupnotices.h" +#include "llparcel.h" #include "llpreview.h" #include "llpreviewscript.h" #include "llproxy.h" #include "llproductinforequest.h" +#include "llqueryflags.h" #include "llselectmgr.h" #include "llsky.h" #include "llstatview.h" @@ -141,6 +144,7 @@ #include "lltoolmgr.h" #include "lltrans.h" #include "llui.h" +#include "lluiusage.h" #include "llurldispatcher.h" #include "llurlentry.h" #include "llslurl.h" @@ -158,6 +162,7 @@ #include "llviewermessage.h" #include "llviewernetwork.h" #include "llviewerobjectlist.h" +#include "llviewerparcelaskplay.h" #include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" @@ -174,6 +179,7 @@ #include "pipeline.h" #include "llappviewer.h" #include "llfasttimerview.h" +#include "lltelemetry.h" #include "llfloatermap.h" #include "llweb.h" #include "llvoiceclient.h" @@ -181,8 +187,6 @@ #include "llnamebox.h" #include "llnameeditor.h" #include "llpostprocess.h" -#include "llwlparammanager.h" -#include "llwaterparammanager.h" #include "llagentlanguage.h" #include "llwearable.h" #include "llinventorybridge.h" @@ -198,6 +202,8 @@ #include "llexperiencelog.h" #include "llcleanup.h" +#include "llenvironment.h" + #include "llstacktrace.h" #if LL_WINDOWS @@ -208,7 +214,6 @@ // exported globals // bool gAgentMovementCompleted = false; -S32 gMaxAgentGroups; const std::string SCREEN_HOME_FILENAME = "screen_home%s.png"; const std::string SCREEN_LAST_FILENAME = "screen_last%s.png"; @@ -227,7 +232,6 @@ extern S32 gStartImageHeight; static bool gGotUseCircuitCodeAck = false; static std::string sInitialOutfit; static std::string sInitialOutfitGender; // "male" or "female" -static boost::signals2::connection sWearablesLoadedCon; static bool gUseCircuitCallbackCalled = false; @@ -236,7 +240,8 @@ LLSLURL LLStartUp::sStartSLURL; static LLPointer<LLCredential> gUserCredential; static std::string gDisplayName; -static BOOL gRememberPassword = TRUE; +static bool gRememberPassword = true; +static bool gRememberUser = true; static U64 gFirstSimHandle = 0; static LLHost gFirstSim; @@ -244,9 +249,8 @@ static std::string gFirstSimSeedCap; static LLVector3 gAgentStartLookAt(1.0f, 0.f, 0.f); static std::string gAgentStartLocation = "safe"; static bool mLoginStatePastUI = false; +static bool mBenefitsSuccessfullyInit = false; -const S32 DEFAULT_MAX_AGENT_GROUPS = 42; -const S32 ALLOWED_MAX_AGENT_GROUPS = 500; const F32 STATE_AGENT_WAIT_TIMEOUT = 240; //seconds boost::scoped_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState")); @@ -277,6 +281,7 @@ void general_cert_done(const LLSD& notification, const LLSD& response); void trust_cert_done(const LLSD& notification, const LLSD& response); void apply_udp_blacklist(const std::string& csv); bool process_login_success_response(); +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) @@ -334,7 +339,6 @@ bool idle_startup() static std::string auth_desc; static std::string auth_message; - 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 // last location by default @@ -350,13 +354,6 @@ bool idle_startup() gIdleCallbacks.callFunctions(); gViewerWindow->updateUI(); - // There is a crash on updateClass, this is an attempt to get more information - if (LLMortician::graveyardCount()) - { - std::stringstream log_stream; - LLMortician::logClass(log_stream); - LL_INFOS() << log_stream.str() << LL_ENDL; - } LLMortician::updateClass(); const std::string delims (" "); @@ -517,9 +514,9 @@ bool idle_startup() if(!start_messaging_system( message_template_path, port, - LLVersionInfo::getMajor(), - LLVersionInfo::getMinor(), - LLVersionInfo::getPatch(), + LLVersionInfo::instance().getMajor(), + LLVersionInfo::instance().getMinor(), + LLVersionInfo::instance().getPatch(), FALSE, std::string(), responder, @@ -533,6 +530,8 @@ bool idle_startup() } #if LL_WINDOWS + LLPROFILE_STARTUP(); + // On the windows dev builds, unpackaged, the message.xml file will // be located in indra/build-vc**/newview/<config>/app_settings. std::string message_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message.xml"); @@ -628,13 +627,13 @@ bool idle_startup() delete gAudiop; gAudiop = NULL; -#ifdef LL_FMODEX +#ifdef LL_FMODSTUDIO #if !LL_WINDOWS - if (NULL == getenv("LL_BAD_FMODEX_DRIVER")) + if (NULL == getenv("LL_BAD_FMODSTUDIO_DRIVER")) #endif // !LL_WINDOWS - { - gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODEX(gSavedSettings.getBOOL("FMODExProfilerEnable")); - } + { + gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODSTUDIO(gSavedSettings.getBOOL("FMODExProfilerEnable")); + } #endif #ifdef LL_OPENAL @@ -655,7 +654,7 @@ bool idle_startup() #else void* window_handle = NULL; #endif - bool init = gAudiop->init(kAUDIO_NUM_SOURCES, window_handle); + bool init = gAudiop->init(kAUDIO_NUM_SOURCES, window_handle, LLAppViewer::instance()->getSecondLifeTitle()); if(init) { gAudiop->setMuted(TRUE); @@ -701,19 +700,23 @@ bool idle_startup() else if (gSavedSettings.getBOOL("AutoLogin")) { // Log into last account - gRememberPassword = TRUE; - gSavedSettings.setBOOL("RememberPassword", TRUE); + gRememberPassword = true; + gRememberUser = true; + gSavedSettings.setBOOL("RememberPassword", TRUE); + gSavedSettings.setBOOL("RememberUser", TRUE); show_connect_box = false; } else if (gSavedSettings.getLLSD("UserLoginInfo").size() == 3) { // Console provided login&password gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); + gRememberUser = gSavedSettings.getBOOL("RememberUser"); show_connect_box = false; } else { gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); + gRememberUser = gSavedSettings.getBOOL("RememberUser"); show_connect_box = TRUE; } @@ -781,10 +784,7 @@ bool idle_startup() // Show the login dialog login_show(); // connect dialog is already shown, so fill in the names - if (gUserCredential.notNull() && !LLPanelLogin::isCredentialSet()) - { - LLPanelLogin::setFields( gUserCredential, gRememberPassword); - } + LLPanelLogin::populateFields( gUserCredential, gRememberUser, gRememberPassword); LLPanelLogin::giveFocus(); // MAINT-3231 Show first run dialog only for Desura viewer @@ -816,6 +816,7 @@ bool idle_startup() show_debug_menus(); // Hide the splash screen + LL_DEBUGS("AppInit") << "Hide the splash screen and show window" << LL_ENDL; LLSplashScreen::hide(); // Push our window frontmost gViewerWindow->getWindow()->show(); @@ -823,9 +824,12 @@ bool idle_startup() // DEV-16927. The following code removes errant keystrokes that happen while the window is being // first made visible. #ifdef _WIN32 + LL_DEBUGS("AppInit") << "Processing PeekMessage" << LL_ENDL; MSG msg; while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) ) - { } + { + } + LL_DEBUGS("AppInit") << "PeekMessage processed" << LL_ENDL; #endif display_startup(); timeout.reset(); @@ -873,7 +877,7 @@ bool idle_startup() { // TODO if not use viewer auth // Load all the name information out of the login view - LLPanelLogin::getFields(gUserCredential, gRememberPassword); + LLPanelLogin::getFields(gUserCredential, gRememberUser, gRememberPassword); // end TODO // HACK: Try to make not jump on login @@ -885,14 +889,21 @@ bool idle_startup() // STATE_LOGIN_SHOW state if we've gone backwards mLoginStatePastUI = true; - // save the credentials - std::string userid = "unknown"; - if(gUserCredential.notNull()) - { - userid = gUserCredential->userID(); - gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); - } - gSavedSettings.setBOOL("RememberPassword", gRememberPassword); + // save the credentials + std::string userid = "unknown"; + if (gUserCredential.notNull()) + { + userid = gUserCredential->userID(); + if (gRememberUser) + { + gSecAPIHandler->addToCredentialMap("login_list", gUserCredential, gRememberPassword); + // Legacy viewers use this method to store user credentials, newer viewers + // reuse it to be compatible and to remember last session + gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); + } + } + gSavedSettings.setBOOL("RememberPassword", gRememberPassword); + gSavedSettings.setBOOL("RememberUser", gRememberUser); LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL; gDebugInfo["LoginName"] = userid; @@ -902,13 +913,18 @@ bool idle_startup() LLFile::mkdir(gDirUtilp->getLindenUserDir()); // As soon as directories are ready initialize notification storages - LLPersistentNotificationStorage::getInstance()->initialize(); - LLDoNotDisturbNotificationStorage::getInstance()->initialize(); + if (!LLPersistentNotificationStorage::instanceExists()) + { + // check existance since this part of code can be reached + // twice due to login failures + LLPersistentNotificationStorage::initParamSingleton(); + LLDoNotDisturbNotificationStorage::initParamSingleton(); + } // Set PerAccountSettingsFile to the default value. - gSavedSettings.setString("PerAccountSettingsFile", - gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, - LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount"))); + std::string settings_per_account = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount")); + gSavedSettings.setString("PerAccountSettingsFile", settings_per_account); + gDebugInfo["PerAccountSettingsFilename"] = settings_per_account; // Note: can't store warnings files per account because some come up before login @@ -946,21 +962,6 @@ bool idle_startup() LLFile::mkdir(gDirUtilp->getChatLogsDir()); LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir()); - - //good a place as any to create user windlight directories - std::string user_windlight_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight", "")); - LLFile::mkdir(user_windlight_path_name.c_str()); - - std::string user_windlight_skies_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", "")); - LLFile::mkdir(user_windlight_skies_path_name.c_str()); - - std::string user_windlight_water_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", "")); - LLFile::mkdir(user_windlight_water_path_name.c_str()); - - std::string user_windlight_days_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/days", "")); - LLFile::mkdir(user_windlight_days_path_name.c_str()); - - if (show_connect_box) { LLSLURL slurl; @@ -1001,9 +1002,8 @@ bool idle_startup() gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); - init_start_screen(agent_location_id); - // Display the startup progress bar. + gViewerWindow->initTextures(agent_location_id); gViewerWindow->setShowProgress(TRUE); gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Quit")); @@ -1110,6 +1110,8 @@ bool idle_startup() // Its either downloading or declined. // If optional was skipped this case shouldn't // be reached. + + LL_INFOS("LLStartup") << "Forcing a quit due to update." << LL_ENDL; LLLoginInstance::getInstance()->disconnect(); LLAppViewer::instance()->forceQuit(); } @@ -1130,7 +1132,24 @@ bool idle_startup() { // This was a certificate error, so grab the certificate // and throw up the appropriate dialog. - LLPointer<LLCertificate> certificate = gSecAPIHandler->getCertificate(response["certificate"]); + LLPointer<LLCertificate> certificate; + try + { + certificate = gSecAPIHandler->getCertificate(response["certificate"]); + } + catch (LLCertException &cert_exception) + { + LL_WARNS("LLStartup", "SECAPI") << "Caught " << cert_exception.what() << " certificate expception on getCertificate("<< response["certificate"] << ")" << LL_ENDL; + LLSD args; + args["REASON"] = LLTrans::getString(cert_exception.what()); + + LLNotificationsUtil::add("GeneralCertificateErrorShort", args, response, + general_cert_done); + + reset_login(); + gSavedSettings.setBOOL("AutoLogin", FALSE); + show_connect_box = true; + } if(certificate) { LLSD args = transform_cert_args(certificate); @@ -1216,7 +1235,6 @@ bool idle_startup() display_startup(); gAgentCamera.init(); display_startup(); - set_underclothes_menu_options(); display_startup(); // Since we connected, save off the settings so the user doesn't have to @@ -1236,8 +1254,6 @@ bool idle_startup() LLSurface::initClasses(); display_startup(); - - LLFace::initClass(); display_startup(); LLDrawable::initClass(); @@ -1299,9 +1315,13 @@ bool idle_startup() LLStartUp::initExperiences(); display_startup(); + + // If logging should be enebled, turns it on and loads history from disk + // Note: does not happen on init of singleton because preferences can use + // this instance without logging in + LLConversationLog::getInstance()->initLoggingState(); + LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT ); - - LLConversationLog::getInstance(); return FALSE; } @@ -1410,12 +1430,19 @@ bool idle_startup() // update the voice settings *after* gCacheName initialization // so that we can construct voice UI that relies on the name cache - LLVoiceClient::getInstance()->updateSettings(); + if (LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->updateSettings(); + } display_startup(); // create a container's instance for start a controlling conversation windows // by the voice's events LLFloaterIMContainer::getInstance(); + if (gSavedSettings.getS32("ParcelMediaAutoPlayEnable") == 2) + { + LLViewerParcelAskPlay::getInstance()->loadSettings(); + } // *Note: this is where gWorldMap used to be initialized. @@ -1471,8 +1498,7 @@ bool idle_startup() LLGLState::checkStates(); LLGLState::checkTextureChannels(); - LLEnvManagerNew::getInstance()->usePrefs(); // Load all presets and settings - gSky.init(initial_sun_direction); + gSky.init(); LLGLState::checkStates(); LLGLState::checkTextureChannels(); @@ -1537,12 +1563,14 @@ bool idle_startup() { LLStartUp::setStartupState( STATE_AGENT_SEND ); } - LLMessageSystem* msg = gMessageSystem; - while (msg->checkAllMessages(gFrameCount, gServicePump)) { - display_startup(); + LockMessageChecker lmc(gMessageSystem); + while (lmc.checkAllMessages(gFrameCount, gServicePump)) + { + display_startup(); + } + lmc.processAcks(); } - msg->processAcks(); display_startup(); return FALSE; } @@ -1567,8 +1595,6 @@ bool idle_startup() send_complete_agent_movement(regionp->getHost()); gAssetStorage->setUpstream(regionp->getHost()); gCacheName->setUpstream(regionp->getHost()); - msg->newMessageFast(_PREHASH_EconomyDataRequest); - gAgent.sendReliableMessage(); } display_startup(); @@ -1594,25 +1620,27 @@ bool idle_startup() //--------------------------------------------------------------------- if (STATE_AGENT_WAIT == LLStartUp::getStartupState()) { - LLMessageSystem* msg = gMessageSystem; - while (msg->checkAllMessages(gFrameCount, gServicePump)) { - if (gAgentMovementCompleted) + LockMessageChecker lmc(gMessageSystem); + while (lmc.checkAllMessages(gFrameCount, gServicePump)) { - // Sometimes we have more than one message in the - // queue. break out of this loop and continue - // processing. If we don't, then this could skip one - // or more login steps. - break; - } - else - { - LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got " - << msg->getMessageName() << LL_ENDL; + if (gAgentMovementCompleted) + { + // Sometimes we have more than one message in the + // queue. break out of this loop and continue + // processing. If we don't, then this could skip one + // or more login steps. + break; + } + else + { + LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got " + << gMessageSystem->getMessageName() << LL_ENDL; + } + display_startup(); } - display_startup(); + lmc.processAcks(); } - msg->processAcks(); display_startup(); @@ -1625,7 +1653,14 @@ bool idle_startup() if (!gAgentMovementCompleted && timeout.getElapsedTimeF32() > STATE_AGENT_WAIT_TIMEOUT) { LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; - LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } reset_login(); } return FALSE; @@ -1637,8 +1672,20 @@ bool idle_startup() if (STATE_INVENTORY_SEND == LLStartUp::getStartupState()) { display_startup(); + + // request mute list + LL_INFOS() << "Requesting Mute List" << LL_ENDL; + LLMuteList::getInstance()->requestFromServer(gAgent.getID()); + + // Get L$ and ownership credit information + LL_INFOS() << "Requesting Money Balance" << LL_ENDL; + LLStatusBar::sendMoneyBalanceRequest(); + + display_startup(); + // Inform simulator of our language preference LLAgentLanguage::update(); + display_startup(); // unpack thin inventory LLSD response = LLLoginInstance::getInstance()->getResponse(); @@ -1791,9 +1838,6 @@ bool idle_startup() display_startup(); - //all categories loaded. lets create "My Favorites" category - gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true); - // set up callbacks LL_INFOS() << "Registering Callbacks" << LL_ENDL; LLMessageSystem* msg = gMessageSystem; @@ -1805,14 +1849,6 @@ bool idle_startup() LLLandmark::registerCallbacks(msg); display_startup(); - // request mute list - LL_INFOS() << "Requesting Mute List" << LL_ENDL; - LLMuteList::getInstance()->requestFromServer(gAgent.getID()); - display_startup(); - // Get L$ and ownership credit information - LL_INFOS() << "Requesting Money Balance" << LL_ENDL; - LLStatusBar::sendMoneyBalanceRequest(); - display_startup(); // request all group information LL_INFOS() << "Requesting Agent Data" << LL_ENDL; gAgent.sendAgentDataUpdateRequest(); @@ -1869,14 +1905,13 @@ bool idle_startup() // Set the show start location to true, now that the user has logged // on with this install. gSavedSettings.setBOOL("ShowStartLocation", TRUE); - - // Open Conversation floater on first login. - LLFloaterReg::toggleInstanceOrBringToFront("im_container"); - } display_startup(); - + + // Load stored local environment if needed. + LLEnvironment::instance().loadFromSettings(); + // *TODO : Uncomment that line once the whole grid migrated to SLM and suppress it from LLAgent::handleTeleportFinished() (llagent.cpp) //check_merchant_status(); @@ -1960,6 +1995,8 @@ bool idle_startup() // JC - 7/20/2002 gViewerWindow->sendShapeToSim(); + LLPresetsManager::getInstance()->createMissingDefault(PRESETS_CAMERA); + // The reason we show the alert is because we want to // reduce confusion for when you log in and your provided // location is not your expected location. So, if this is @@ -2147,6 +2184,11 @@ bool idle_startup() set_startup_status(1.0, "", ""); display_startup(); + if (!mBenefitsSuccessfullyInit) + { + LLNotificationsUtil::add("FailedToGetBenefits", LLSD(), LLSD(), boost::bind(on_benefits_failed_callback, _1, _2)); + } + // Let the map know about the inventory. LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance(); if(floater_world_map) @@ -2220,6 +2262,16 @@ bool idle_startup() gAgentAvatarp->sendHoverHeight(); + // look for parcels we own + send_places_query(LLUUID::null, + LLUUID::null, + "", + DFQ_AGENT_OWNED, + LLParcel::C_ANY, + ""); + + LLUIUsage::instance().clear(); + return TRUE; } @@ -2285,8 +2337,8 @@ void login_callback(S32 option, void *userdata) void show_release_notes_if_required() { static bool release_notes_shown = false; - if (!release_notes_shown && (LLVersionInfo::getChannelAndVersion() != gLastRunVersion) - && LLVersionInfo::getViewerMaturity() != LLVersionInfo::TEST_VIEWER // don't show Release Notes for the test builds + if (!release_notes_shown && (LLVersionInfo::instance().getChannelAndVersion() != gLastRunVersion) + && LLVersionInfo::instance().getViewerMaturity() != LLVersionInfo::TEST_VIEWER // don't show Release Notes for the test builds && gSavedSettings.getBOOL("UpdaterShowReleaseNotes") && !gSavedSettings.getBOOL("FirstLoginThisInstall")) { @@ -2360,7 +2412,14 @@ void use_circuit_callback(void**, S32 result) { // Make sure user knows something bad happened. JC LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; - LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } reset_login(); } else @@ -2539,7 +2598,8 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFunc("InitiateDownload", process_initiate_download); msg->setHandlerFunc("LandStatReply", LLFloaterTopObjects::handle_land_reply); - msg->setHandlerFunc("GenericMessage", process_generic_message); + msg->setHandlerFunc("GenericMessage", process_generic_message); + msg->setHandlerFunc("LargeGenericMessage", process_large_generic_message); msg->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message); } @@ -2647,11 +2707,6 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, } 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); @@ -2665,101 +2720,18 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, gAgentWearables.sendDummyAgentWearablesUpdate(); } -//static -void LLStartUp::saveInitialOutfit() -{ - if (sInitialOutfit.empty()) { - LL_DEBUGS() << "sInitialOutfit is empty" << LL_ENDL; - return; - } - - if (sWearablesLoadedCon.connected()) - { - LL_DEBUGS("Avatar") << "sWearablesLoadedCon is connected, disconnecting" << LL_ENDL; - sWearablesLoadedCon.disconnect(); - } - LL_DEBUGS("Avatar") << "calling makeNewOutfitLinks( \"" << sInitialOutfit << "\" )" << LL_ENDL; - LLAppearanceMgr::getInstance()->makeNewOutfitLinks(sInitialOutfit,false); -} - std::string& LLStartUp::getInitialOutfitName() { return sInitialOutfit; } -// Loads a bitmap to display during load -void init_start_screen(S32 location_id) +std::string LLStartUp::getUserId() { - if (gStartTexture.notNull()) - { - gStartTexture = NULL; - LL_INFOS("AppInit") << "re-initializing start screen" << LL_ENDL; - } - - LL_DEBUGS("AppInit") << "Loading startup bitmap..." << LL_ENDL; - - U8 image_codec = IMG_CODEC_PNG; - std::string temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter(); - - if ((S32)START_LOCATION_ID_LAST == location_id) - { - temp_str += LLStartUp::getScreenLastFilename(); - } - else - { - std::string path = temp_str + LLStartUp::getScreenHomeFilename(); - - if (!gDirUtilp->fileExists(path) && LLGridManager::getInstance()->isInProductionGrid()) - { - // Fallback to old file, can be removed later - // Home image only sets when user changes home, so it will take time for users to switch to pngs - temp_str += "screen_home.bmp"; - image_codec = IMG_CODEC_BMP; - } - else - { - temp_str = path; - } - } - - LLPointer<LLImageFormatted> start_image_frmted = LLImageFormatted::createFromType(image_codec); - - // Turn off start screen to get around the occasional readback - // driver bug - if(!gSavedSettings.getBOOL("UseStartScreen")) - { - LL_INFOS("AppInit") << "Bitmap load disabled" << LL_ENDL; - return; - } - else if(!start_image_frmted->load(temp_str) ) - { - LL_WARNS("AppInit") << "Bitmap load failed" << LL_ENDL; - gStartTexture = NULL; - } - else - { - gStartImageWidth = start_image_frmted->getWidth(); - gStartImageHeight = start_image_frmted->getHeight(); - - LLPointer<LLImageRaw> raw = new LLImageRaw; - if (!start_image_frmted->decode(raw, 0.0f)) - { - LL_WARNS("AppInit") << "Bitmap decode failed" << LL_ENDL; - gStartTexture = NULL; - } - else - { - raw->expandToPowerOfTwo(); - gStartTexture = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE) ; - } - } - - if(gStartTexture.isNull()) - { - gStartTexture = LLViewerTexture::sBlackImagep ; - gStartImageWidth = gStartTexture->getWidth() ; - gStartImageHeight = gStartTexture->getHeight() ; - } + if (gUserCredential.isNull()) + { + return ""; + } + return gUserCredential->userID(); } @@ -2857,9 +2829,6 @@ void LLStartUp::multimediaInit() std::string msg = LLTrans::getString("LoginInitializingMultimedia"); set_startup_status(0.42f, msg.c_str(), gAgent.mMOTD.c_str()); display_startup(); - - // LLViewerMedia::initClass(); - LLViewerParcelMedia::initClass(); } void LLStartUp::fontInit() @@ -2887,9 +2856,10 @@ void LLStartUp::initNameCache() // Start cache in not-running state until we figure out if we have // capabilities for display name lookup - LLAvatarNameCache::initClass(false,gSavedSettings.getBOOL("UsePeopleAPI")); - LLAvatarNameCache::setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames")); - LLAvatarNameCache::setUseUsernames(gSavedSettings.getBOOL("NameTagShowUsernames")); + LLAvatarNameCache* cache_inst = LLAvatarNameCache::getInstance(); + cache_inst->setUsePeopleAPI(gSavedSettings.getBOOL("UsePeopleAPI")); + cache_inst->setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames")); + cache_inst->setUseUsernames(gSavedSettings.getBOOL("NameTagShowUsernames")); } @@ -2904,8 +2874,6 @@ void LLStartUp::initExperiences() void LLStartUp::cleanupNameCache() { - SUBSYSTEM_CLEANUP(LLAvatarNameCache); - delete gCacheName; gCacheName = NULL; } @@ -3251,10 +3219,70 @@ void apply_udp_blacklist(const std::string& csv) } +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() { LLSD response = LLLoginInstance::getInstance()->getResponse(); + mBenefitsSuccessfullyInit = init_benefits(response); + std::string text(response["udp_blacklist"]); if(!text.empty()) { @@ -3502,11 +3530,6 @@ bool process_login_success_response() } // Request the map server url - // Non-agni grids have a different default location. - if (!LLGridManager::getInstance()->isInProductionGrid()) - { - gSavedSettings.setString("MapServerURL", "http://test.map.secondlife.com.s3.amazonaws.com/"); - } std::string map_server_url = response["map-server-url"]; if(!map_server_url.empty()) { @@ -3554,26 +3577,6 @@ bool process_login_success_response() } } - LLSD global_textures = response["global-textures"][0]; - if(global_textures.size()) - { - // Extract sun and moon texture IDs. These are used - // in the LLVOSky constructor, but I can't figure out - // how to pass them in. JC - LLUUID id = global_textures["sun_texture_id"]; - if(id.notNull()) - { - gSunTextureID = id; - } - - id = global_textures["moon_texture_id"]; - if(id.notNull()) - { - gMoonTextureID = id; - } - - } - // 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"]; @@ -3594,30 +3597,9 @@ bool process_login_success_response() if(!openid_url.empty()) { std::string openid_token = response["openid_token"]; - LLViewerMedia::openIDSetup(openid_url, openid_token); + LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token); } - gMaxAgentGroups = DEFAULT_MAX_AGENT_GROUPS; - if(response.has("max-agent-groups")) - { - S32 agent_groups = atoi(std::string(response["max-agent-groups"]).c_str()); - if (agent_groups > 0 && agent_groups <= ALLOWED_MAX_AGENT_GROUPS) - { - gMaxAgentGroups = agent_groups; - LL_INFOS("LLStartup") << "gMaxAgentGroups read from login.cgi: " - << gMaxAgentGroups << LL_ENDL; - } - else - { - LL_INFOS("LLStartup") << "Invalid value received, using defaults for gMaxAgentGroups: " - << gMaxAgentGroups << LL_ENDL; - } - } - else { - LL_INFOS("LLStartup") << "Missing max-agent-groups, using default value for gMaxAgentGroups: " - << gMaxAgentGroups << LL_ENDL; - } - bool success = false; // JC: gesture loading done below, when we have an asset system // in place. Don't delete/clear gUserCredentials until then. diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index db37207022..116aeb36a7 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -80,7 +80,6 @@ typedef enum { // exported symbols extern bool gAgentMovementCompleted; -extern S32 gMaxAgentGroups; extern LLPointer<LLViewerTexture> gStartTexture; class LLStartUp @@ -111,10 +110,8 @@ public: static void loadInitialOutfit( const std::string& outfit_folder_name, const std::string& gender_name ); - //save loaded initial outfit into My Outfits category - static void saveInitialOutfit(); - static std::string& getInitialOutfitName(); + static std::string getUserId(); static bool dispatchURL(); // if we have a SLURL or sim string ("Ahern/123/45") that started @@ -128,6 +125,7 @@ public: static LLViewerStats::PhaseMap& getPhases() { return *sPhases; } private: + friend class LLStartupListener; static LLSLURL sStartSLURL; static std::string startupStateToString(EStartupState state); diff --git a/indra/newview/llstartuplistener.cpp b/indra/newview/llstartuplistener.cpp index d9a21f908e..5770b595d0 100644 --- a/indra/newview/llstartuplistener.cpp +++ b/indra/newview/llstartuplistener.cpp @@ -35,7 +35,7 @@ // external library headers // other Linden headers #include "llstartup.h" - +#include "stringize.h" LLStartupListener::LLStartupListener(/* LLStartUp* instance */): LLEventAPI("LLStartUp", "Access e.g. LLStartup::postStartupState()") /* , @@ -43,9 +43,33 @@ LLStartupListener::LLStartupListener(/* LLStartUp* instance */): { add("postStartupState", "Refresh \"StartupState\" listeners with current startup state", &LLStartupListener::postStartupState); + add("getStateTable", "Reply with array of EStartupState string names", + &LLStartupListener::getStateTable); } void LLStartupListener::postStartupState(const LLSD&) const { LLStartUp::postStartupState(); } + +void LLStartupListener::getStateTable(const LLSD& event) const +{ + Response response(LLSD(), event); + + // This relies on our knowledge that STATE_STARTED is the very last + // EStartupState value. If that ever stops being true, we're going to lie + // without realizing it. I can think of no reliable way to test whether + // the enum has been extended *beyond* STATE_STARTED. We could, of course, + // test whether stuff has been inserted before it, by testing its + // numerical value against the constant value as of the last time we + // looked; but that's pointless, as values inserted before STATE_STARTED + // will continue to work fine. The bad case is if new symbols get added + // *after* it. + LLSD table; + // note <= comparison: we want to *include* STATE_STARTED. + for (LLSD::Integer istate{0}; istate <= LLSD::Integer(STATE_STARTED); ++istate) + { + table.append(LLStartUp::startupStateToString(EStartupState(istate))); + } + response["table"] = table; +} diff --git a/indra/newview/llstartuplistener.h b/indra/newview/llstartuplistener.h index a35e11f6eb..0b4380a568 100644 --- a/indra/newview/llstartuplistener.h +++ b/indra/newview/llstartuplistener.h @@ -40,6 +40,7 @@ public: private: void postStartupState(const LLSD&) const; + void getStateTable(const LLSD&) const; //LLStartup* mStartup; }; diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index f3c270a97b..0a87b14e17 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -38,6 +38,7 @@ #include "llfloaterbuycurrency.h" #include "llbuycurrencyhtml.h" #include "llpanelnearbymedia.h" +#include "llpanelpresetscamerapulldown.h" #include "llpanelpresetspulldown.h" #include "llpanelvolumepulldown.h" #include "llfloaterregioninfo.h" @@ -172,8 +173,11 @@ BOOL LLStatusBar::postBuild() mBoxBalance = getChild<LLTextBox>("balance"); mBoxBalance->setClickedCallback( &LLStatusBar::onClickBalance, this ); - mIconPresets = getChild<LLIconCtrl>( "presets_icon" ); - mIconPresets->setMouseEnterCallback(boost::bind(&LLStatusBar::onMouseEnterPresets, this)); + mIconPresetsCamera = getChild<LLIconCtrl>( "presets_icon_camera" ); + mIconPresetsCamera->setMouseEnterCallback(boost::bind(&LLStatusBar::onMouseEnterPresetsCamera, this)); + + mIconPresetsGraphic = getChild<LLIconCtrl>( "presets_icon_graphic" ); + mIconPresetsGraphic->setMouseEnterCallback(boost::bind(&LLStatusBar::onMouseEnterPresets, this)); mBtnVolume = getChild<LLButton>( "volume_btn" ); mBtnVolume->setClickedCallback( onClickVolume, this ); @@ -183,7 +187,7 @@ BOOL LLStatusBar::postBuild() mMediaToggle->setClickedCallback( &LLStatusBar::onClickMediaToggle, this ); mMediaToggle->setMouseEnterCallback(boost::bind(&LLStatusBar::onMouseEnterNearbyMedia, this)); - LLHints::registerHintTarget("linden_balance", getChild<LLView>("balance_bg")->getHandle()); + LLHints::getInstance()->registerHintTarget("linden_balance", getChild<LLView>("balance_bg")->getHandle()); gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&LLStatusBar::onVolumeChanged, this, _2)); @@ -228,6 +232,11 @@ BOOL LLStatusBar::postBuild() mSGPacketLoss = LLUICtrlFactory::create<LLStatGraph>(pgp); addChild(mSGPacketLoss); + mPanelPresetsCameraPulldown = new LLPanelPresetsCameraPulldown(); + addChild(mPanelPresetsCameraPulldown); + mPanelPresetsCameraPulldown->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT); + mPanelPresetsCameraPulldown->setVisible(FALSE); + mPanelPresetsPulldown = new LLPanelPresetsPulldown(); addChild(mPanelPresetsPulldown); mPanelPresetsPulldown->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT); @@ -243,16 +252,24 @@ BOOL LLStatusBar::postBuild() mPanelNearByMedia->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT); mPanelNearByMedia->setVisible(FALSE); + updateBalancePanelPosition(); + // Hook up and init for filtering mFilterEdit = getChild<LLSearchEditor>( "search_menu_edit" ); mSearchPanel = getChild<LLPanel>( "menu_search_panel" ); - mSearchPanel->setVisible(gSavedSettings.getBOOL("MenuSearch")); + BOOL search_panel_visible = gSavedSettings.getBOOL("MenuSearch"); + mSearchPanel->setVisible(search_panel_visible); mFilterEdit->setKeystrokeCallback(boost::bind(&LLStatusBar::onUpdateFilterTerm, this)); mFilterEdit->setCommitCallback(boost::bind(&LLStatusBar::onUpdateFilterTerm, this)); collectSearchableItems(); gSavedSettings.getControl("MenuSearch")->getCommitSignal()->connect(boost::bind(&LLStatusBar::updateMenuSearchVisibility, this, _2)); + if (search_panel_visible) + { + updateMenuSearchPosition(); + } + return TRUE; } @@ -310,16 +327,18 @@ void LLStatusBar::refresh() // update the master volume button state bool mute_audio = LLAppViewer::instance()->getMasterSystemAudioMute(); mBtnVolume->setToggleState(mute_audio); - + + LLViewerMedia* media_inst = LLViewerMedia::getInstance(); + // Disable media toggle if there's no media, parcel media, and no parcel audio // (or if media is disabled) bool button_enabled = (gSavedSettings.getBOOL("AudioStreamingMusic")||gSavedSettings.getBOOL("AudioStreamingMedia")) && - (LLViewerMedia::hasInWorldMedia() || LLViewerMedia::hasParcelMedia() || LLViewerMedia::hasParcelAudio()); + (media_inst->hasInWorldMedia() || media_inst->hasParcelMedia() || media_inst->hasParcelAudio()); mMediaToggle->setEnabled(button_enabled); // Note the "sense" of the toggle is opposite whether media is playing or not - bool any_media_playing = (LLViewerMedia::isAnyMediaPlaying() || - LLViewerMedia::isParcelMediaPlaying() || - LLViewerMedia::isParcelAudioPlaying()); + bool any_media_playing = (media_inst->isAnyMediaPlaying() || + media_inst->isParcelMediaPlaying() || + media_inst->isParcelAudioPlaying()); mMediaToggle->setValue(!any_media_playing); } @@ -334,7 +353,8 @@ void LLStatusBar::setVisibleForMouselook(bool visible) mSGPacketLoss->setVisible(visible); mSearchPanel->setVisible(visible && gSavedSettings.getBOOL("MenuSearch")); setBackgroundVisible(visible); - mIconPresets->setVisible(visible); + mIconPresetsCamera->setVisible(visible); + mIconPresetsGraphic->setVisible(visible); } void LLStatusBar::debitBalance(S32 debit) @@ -361,17 +381,7 @@ void LLStatusBar::setBalance(S32 balance) std::string label_str = getString("buycurrencylabel", string_args); mBoxBalance->setValue(label_str); - // Resize the L$ balance background to be wide enough for your balance plus the buy button - { - const S32 HPAD = 24; - LLRect balance_rect = mBoxBalance->getTextBoundingRect(); - LLRect buy_rect = getChildView("buyL")->getRect(); - LLRect shop_rect = getChildView("goShop")->getRect(); - LLView* balance_bg_view = getChildView("balance_bg"); - LLRect balance_bg_rect = balance_bg_view->getRect(); - balance_bg_rect.mLeft = balance_bg_rect.mRight - (buy_rect.getWidth() + shop_rect.getWidth() + balance_rect.getWidth() + HPAD); - balance_bg_view->setShape(balance_bg_rect); - } + updateBalancePanelPosition(); // If the search panel is shown, move this according to the new balance width. Parcel text will reshape itself in setParcelInfoText if (mSearchPanel && mSearchPanel->getVisible()) @@ -406,7 +416,20 @@ void LLStatusBar::sendMoneyBalanceRequest() msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_MoneyData); msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null ); - gAgent.sendReliableMessage(); + + if (gDisconnected) + { + LL_DEBUGS() << "Trying to send message when disconnected, skipping balance request!" << LL_ENDL; + return; + } + if (!gAgent.getRegion()) + { + LL_DEBUGS() << "LLAgent::sendReliableMessage No region for agent yet, skipping balance request!" << LL_ENDL; + return; + } + // Double amount of retries due to this request initially happening during busy stage + // Ideally this should be turned into a capability + gMessageSystem->sendReliable(gAgent.getRegionHost(), LL_DEFAULT_RELIABLE_RETRIES * 2, TRUE, LL_PING_BASED_TIMEOUT_DUMMY, NULL, NULL); } @@ -485,10 +508,34 @@ void LLStatusBar::onClickBuyCurrency() LLFirstUse::receiveLindens(false); } +void LLStatusBar::onMouseEnterPresetsCamera() +{ + LLView* popup_holder = gViewerWindow->getRootView()->getChildView("popup_holder"); + LLIconCtrl* icon = getChild<LLIconCtrl>( "presets_icon_camera" ); + LLRect icon_rect = icon->getRect(); + LLRect pulldown_rect = mPanelPresetsCameraPulldown->getRect(); + pulldown_rect.setLeftTopAndSize(icon_rect.mLeft - + (pulldown_rect.getWidth() - icon_rect.getWidth()), + icon_rect.mBottom, + pulldown_rect.getWidth(), + pulldown_rect.getHeight()); + + pulldown_rect.translate(popup_holder->getRect().getWidth() - pulldown_rect.mRight, 0); + mPanelPresetsCameraPulldown->setShape(pulldown_rect); + + // show the master presets pull-down + LLUI::getInstance()->clearPopups(); + LLUI::getInstance()->addPopup(mPanelPresetsCameraPulldown); + mPanelNearByMedia->setVisible(FALSE); + mPanelVolumePulldown->setVisible(FALSE); + mPanelPresetsPulldown->setVisible(FALSE); + mPanelPresetsCameraPulldown->setVisible(TRUE); +} + void LLStatusBar::onMouseEnterPresets() { LLView* popup_holder = gViewerWindow->getRootView()->getChildView("popup_holder"); - LLIconCtrl* icon = getChild<LLIconCtrl>( "presets_icon" ); + LLIconCtrl* icon = getChild<LLIconCtrl>( "presets_icon_graphic" ); LLRect icon_rect = icon->getRect(); LLRect pulldown_rect = mPanelPresetsPulldown->getRect(); pulldown_rect.setLeftTopAndSize(icon_rect.mLeft - @@ -501,8 +548,8 @@ void LLStatusBar::onMouseEnterPresets() mPanelPresetsPulldown->setShape(pulldown_rect); // show the master presets pull-down - LLUI::clearPopups(); - LLUI::addPopup(mPanelPresetsPulldown); + LLUI::getInstance()->clearPopups(); + LLUI::getInstance()->addPopup(mPanelPresetsPulldown); mPanelNearByMedia->setVisible(FALSE); mPanelVolumePulldown->setVisible(FALSE); mPanelPresetsPulldown->setVisible(TRUE); @@ -525,8 +572,9 @@ void LLStatusBar::onMouseEnterVolume() // show the master volume pull-down - LLUI::clearPopups(); - LLUI::addPopup(mPanelVolumePulldown); + LLUI::getInstance()->clearPopups(); + LLUI::getInstance()->addPopup(mPanelVolumePulldown); + mPanelPresetsCameraPulldown->setVisible(FALSE); mPanelPresetsPulldown->setVisible(FALSE); mPanelNearByMedia->setVisible(FALSE); mPanelVolumePulldown->setVisible(TRUE); @@ -548,9 +596,10 @@ void LLStatusBar::onMouseEnterNearbyMedia() // show the master volume pull-down mPanelNearByMedia->setShape(nearby_media_rect); - LLUI::clearPopups(); - LLUI::addPopup(mPanelNearByMedia); + LLUI::getInstance()->clearPopups(); + LLUI::getInstance()->addPopup(mPanelNearByMedia); + mPanelPresetsCameraPulldown->setVisible(FALSE); mPanelPresetsPulldown->setVisible(FALSE); mPanelVolumePulldown->setVisible(FALSE); mPanelNearByMedia->setVisible(TRUE); @@ -578,7 +627,7 @@ void LLStatusBar::onClickMediaToggle(void* data) LLStatusBar *status_bar = (LLStatusBar*)data; // "Selected" means it was showing the "play" icon (so media was playing), and now it shows "pause", so turn off media bool pause = status_bar->mMediaToggle->getValue(); - LLViewerMedia::setAllMediaPaused(pause); + LLViewerMedia::getInstance()->setAllMediaPaused(pause); } BOOL can_afford_transaction(S32 cost) @@ -659,6 +708,19 @@ void LLStatusBar::updateMenuSearchPosition() mSearchPanel->setShape( searchRect ); } +void LLStatusBar::updateBalancePanelPosition() +{ + // Resize the L$ balance background to be wide enough for your balance plus the buy button + const S32 HPAD = 24; + LLRect balance_rect = mBoxBalance->getTextBoundingRect(); + LLRect buy_rect = getChildView("buyL")->getRect(); + LLRect shop_rect = getChildView("goShop")->getRect(); + LLView* balance_bg_view = getChildView("balance_bg"); + LLRect balance_bg_rect = balance_bg_view->getRect(); + balance_bg_rect.mLeft = balance_bg_rect.mRight - (buy_rect.getWidth() + shop_rect.getWidth() + balance_rect.getWidth() + HPAD); + balance_bg_view->setShape(balance_bg_rect); +} + // Implements secondlife:///app/balance/request to request a L$ balance // update via UDP message system. JC diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index 403d590aca..3002b91c10 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -41,6 +41,7 @@ class LLUICtrl; class LLUUID; class LLFrameTimer; class LLStatGraph; +class LLPanelPresetsCameraPulldown; class LLPanelPresetsPulldown; class LLPanelVolumePulldown; class LLPanelNearByMedia; @@ -99,6 +100,7 @@ private: void onClickBuyCurrency(); void onVolumeChanged(const LLSD& newvalue); + void onMouseEnterPresetsCamera(); void onMouseEnterPresets(); void onMouseEnterVolume(); void onMouseEnterNearbyMedia(); @@ -114,7 +116,8 @@ private: std::unique_ptr< ll::statusbar::SearchData > mSearchData; void collectSearchableItems(); void updateMenuSearchVisibility( const LLSD& data ); - void updateMenuSearchPosition(); + void updateMenuSearchPosition(); // depends onto balance position + void updateBalancePanelPosition(); private: LLTextBox *mTextTime; @@ -122,7 +125,8 @@ private: LLStatGraph *mSGBandwidth; LLStatGraph *mSGPacketLoss; - LLIconCtrl *mIconPresets; + LLIconCtrl *mIconPresetsCamera; + LLIconCtrl *mIconPresetsGraphic; LLButton *mBtnVolume; LLTextBox *mBoxBalance; LLButton *mMediaToggle; @@ -134,6 +138,7 @@ private: S32 mSquareMetersCommitted; LLFrameTimer* mBalanceTimer; LLFrameTimer* mHealthTimer; + LLPanelPresetsCameraPulldown* mPanelPresetsCameraPulldown; LLPanelPresetsPulldown* mPanelPresetsPulldown; LLPanelVolumePulldown* mPanelVolumePulldown; LLPanelNearByMedia* mPanelNearByMedia; diff --git a/indra/newview/lltelemetry.cpp b/indra/newview/lltelemetry.cpp new file mode 100644 index 0000000000..0c63e2fede --- /dev/null +++ b/indra/newview/lltelemetry.cpp @@ -0,0 +1,145 @@ + /** + * @file lltelemetry.cpp + * @brief Wrapper for Rad Game Tools Telemetry + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2020, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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 "lltelemetry.h" + +#if LLPROFILE_USE_RAD_TELEMETRY_PROFILER + #if LL_WINDOWS + #include "llwin32headers.h" + + // build-vc120-64\packages\lib\release + // build-vc150-64\packages\lib\release + #ifdef _MSC_VER + #pragma comment(lib,"rad_tm_win64.lib") + #else + #pragma message "NOTE: Rad GameTools Telemetry requested but non-MSVC compiler not yet supported on Windows" + #endif + #endif // LL_WINDOWS + + #if LL_DARWIN + #pragma message "NOTE: Rad Game Tools Telemetry requested but not yet supported on Darwin" + #endif + + #if LL_LINUX + #pragma message "NOTE: Rad Game Tools Telemetry requested but not yet supported on Linux" + #endif + +// +// local consts +// +static const tm_int32 TELEMETRY_BUFFER_SIZE = 8 * 1024 * 1024; + +// +// local globals +// +static char *gTelemetryBufferPtr = NULL; // Telemetry + +static const char *tm_status[ TMERR_INIT_NETWORKING_FAILED + 1 ] = +{ + "Telemetry pass: connected" // TM_OK + , "Telemetry FAIL: disabled via #define NTELEMETRY" // TMERR_DISABLED + , "Telemetry FAIL: invalid paramater" // TMERR_INVALID_PARAM + , "Telemetry FAIL: DLL not found" // TMERR_NULL_API + , "Telemetry FAIL: out of resources" // TMERR_OUT_OF_RESOURCES + , "Telemetry FAIL: tmInitialize() not called" // TMERR_UNINITIALIZED + , "Telemetry FAIL: bad hostname" // TMERR_BAD_HOSTNAME + , "Telemetry FAIL: couldn't connect to server" // TMERR_COULD_NOT_CONNECT + , "Telemetry FAIL: unknown network error" // TMERR_UNKNOWN_NETWORK + , "Telemetry FAIL: tmShutdown() already called" // TMERR_ALREADY_SHUTDOWN + , "Telemetry FAIL: memory buffer too small" // TMERR_ARENA_TOO_SMALL + , "Telemetry FAIL: server handshake error" // TMERR_BAD_HANDSHAKE + , "Telemetry FAIL: unaligned parameters" // TMERR_UNALIGNED + , "Telemetry FAIL: network not initialized" // TMERR_NETWORK_NOT_INITIALIZED -- WSAStartup not called before tmOpen() + , "Telemetry FAIL: bad version" // TMERR_BAD_VERSION + , "Telemetry FAIL: timer too large" // TMERR_BAD_TIMER + , "Telemetry FAIL: tmOpen() already called" // TMERR_ALREADY_OPENED + , "Telemetry FAIL: tmInitialize() already called" // TMERR_ALREADY_INITIALIZED + , "Telemetry FAIL: could't open file" // TMERR_FILE_OPEN_FAILED + , "Telemetry FAIL: tmOpen() failed networking" // TMERR_INIT_NETWORKING_FAILED +}; + +// +// exported functionality +// + +void telemetry_shutdown() +{ + #if LL_WINDOWS + if (gTelemetryBufferPtr) + { + tmClose(0); + tmShutdown(); + + delete[] gTelemetryBufferPtr; + gTelemetryBufferPtr = NULL; + } + #endif +} + +void telemetry_startup() +{ + #if LL_WINDOWS + tmLoadLibrary(TM_RELEASE); // Loads .dll + + gTelemetryBufferPtr = new char[ TELEMETRY_BUFFER_SIZE ]; + tmInitialize(TELEMETRY_BUFFER_SIZE, gTelemetryBufferPtr); + + tm_error telemetry_status = tmOpen( + 0, // unused + "SecondLife", // app name + __DATE__ " " __TIME__, // build identifier + "localhost", // server name (or filename) + TMCT_TCP, // connection type (or TMCT_FILE) + 4719, // port + TMOF_INIT_NETWORKING, // open flags + 250 ); // timeout ms + + if (telemetry_status == TMERR_UNKNOWN) + { + LL_ERRS() << "Telemetry FAIL: unknown error" << LL_ENDL; + } + else if (telemetry_status && (telemetry_status <= TMERR_INIT_NETWORKING_FAILED)) + { + LL_INFOS() << tm_status[ telemetry_status ] << LL_ENDL; + free(gTelemetryBufferPtr); + gTelemetryBufferPtr = NULL; + } + #endif // LL_WINDOWS +} + +// Called after we render a frame +void telemetry_update() +{ + #if LL_WINDOWS + if (gTelemetryBufferPtr) + { + tmTick(0); + } + #endif +} +#endif // LLPROFILE_USE_RAD_TELEMETRY_PROFILER diff --git a/indra/newview/lltelemetry.h b/indra/newview/lltelemetry.h new file mode 100644 index 0000000000..a73e5fcfa2 --- /dev/null +++ b/indra/newview/lltelemetry.h @@ -0,0 +1,81 @@ +/** + * @file lltelemetry.h + * @brief Wrapper for Rad Game Tools Telemetry + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2020, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +/* +To use: + +1. Uncomment #define LLPROFILE_USE_RAD_TELEMETRY_PROFILER below + +2. Include this header file + #include "lltelemetry.h" + +3. Add zones to the functions you wish to profile + void onFoo() + { + LLPROFILE_ZONE("Foo"); + } +*/ +//#define LLPROFILE_USE_RAD_TELEMETRY_PROFILER 1 + +// Default NO local telemetry profiling +#ifndef LLPROFILE_USE_RAD_TELEMETRY_PROFILER + #define LLPROFILE_USE_RAD_TELEMETRY_PROFILER 0 + #define LLPROFILE_SHUTDOWN( ...) {} + #define LLPROFILE_STARTUP( ...) {} + #define LLPROFILE_UPDATE( ...) {} + + #define LLPROFILE_AUTO_CPU_MARKER_COLOR(r, g, b) + #define LLPROFILE_ENTER(name) + #define LLPROFILE_ENTER_FORMAT(format, ...) + #define LLPROFILE_FUNCTION + #define LLPROFILE_LEAVE() + #define LLPROFILE_THREAD_NAME(name) + #define LLPROFILE_ZONE(name) + #define LLPROFILE_ZONE_FORMAT(format, ...) +#else + #include <rad_tm.h> + + #define LLPROFILE_SHUTDOWN telemetry_shutdown + #define LLPROFILE_STARTUP telemetry_startup + #define LLPROFILE_UPDATE telemetry_update + + #define LLPROFILE_AUTO_CPU_MARKER_COLOR(r, g, b) tmZoneColor(r, g, b) + #define LLPROFILE_ENTER(name) tmEnter(0, 0, name) + #define LLPROFILE_ENTER_FORMAT(format, ...) tmEnter(0, 0, format, __VA_ARGS__) + #define LLPROFILE_FUNCTION tmFunction(0, 0) + #define LLPROFILE_LEAVE() tmLeave(0) + #define LLPROFILE_THREAD_NAME(name) tmThreadName(0, 0, name) + #define LLPROFILE_ZONE(name) tmZone(0, 0, name) + #define LLPROFILE_ZONE_FORMAT(format, ...) tmZone(0, 0, format, __VA_ARGS__) +#endif // LLPROFILE_USE_RAD_TELEMETRY_PROFILER + +// +// exported functionality +// + +extern void telemetry_startup(); +extern void telemetry_shutdown(); +extern void telemetry_update(); // called after every frame update diff --git a/indra/newview/llteleporthistorystorage.cpp b/indra/newview/llteleporthistorystorage.cpp index 8a5704939a..7d4988c0cc 100644 --- a/indra/newview/llteleporthistorystorage.cpp +++ b/indra/newview/llteleporthistorystorage.cpp @@ -33,6 +33,8 @@ #include "lldir.h" #include "llteleporthistory.h" #include "llagent.h" +#include "llfloaterreg.h" +#include "llfloaterworldmap.h" // Max offset for two global positions to consider them as equal const F64 MAX_GLOBAL_POS_OFFSET = 5.0f; @@ -201,6 +203,12 @@ void LLTeleportHistoryStorage::load() std::string line; while (std::getline(file, line)) { + if (line.empty()) + { + LL_WARNS() << "Teleport history contains empty line."<< LL_ENDL; + continue; + } + LLSD s_item; std::istringstream iss(line); if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) @@ -253,3 +261,23 @@ void LLTeleportHistoryStorage::goToItem(S32 idx) gAgent.teleportViaLocation(mItems[idx].mGlobalPos); } +void LLTeleportHistoryStorage::showItemOnMap(S32 idx) +{ + // Validate specified index. + if (idx < 0 || idx >= (S32)mItems.size()) + { + LL_WARNS() << "Invalid teleport history index (" << idx << ") specified" << LL_ENDL; + dump(); + return; + } + + LLVector3d landmark_global_pos = mItems[idx].mGlobalPos; + + LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); + if (!landmark_global_pos.isExactlyZero() && worldmap_instance) + { + worldmap_instance->trackLocation(landmark_global_pos); + LLFloaterReg::showInstance("world_map", "center"); + } +} + diff --git a/indra/newview/llteleporthistorystorage.h b/indra/newview/llteleporthistorystorage.h index 946ac0af1a..3578923fd7 100644 --- a/indra/newview/llteleporthistorystorage.h +++ b/indra/newview/llteleporthistorystorage.h @@ -107,6 +107,13 @@ public: */ void goToItem(S32 idx); + /** + * Show specific item on map. + * + * The item is specified by its index (starting from 0). + */ + void showItemOnMap(S32 idx); + private: void load(); diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index e5af47ab6c..a9f19dc32d 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -52,7 +52,9 @@ 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) const S32 TEXTURE_FAST_CACHE_ENTRY_OVERHEAD = sizeof(S32) * 4; //w, h, c, level -const S32 TEXTURE_FAST_CACHE_ENTRY_SIZE = 16 * 16 * 4 + TEXTURE_FAST_CACHE_ENTRY_OVERHEAD; +const S32 TEXTURE_FAST_CACHE_DATA_SIZE = 16 * 16 * 4; +const S32 TEXTURE_FAST_CACHE_ENTRY_SIZE = TEXTURE_FAST_CACHE_DATA_SIZE + TEXTURE_FAST_CACHE_ENTRY_OVERHEAD; +const F32 TEXTURE_LAZY_PURGE_TIME_LIMIT = .004f; // 4ms. Would be better to autoadjust, but there is a major cache rework in progress. class LLTextureCacheWorker : public LLWorkerClass { @@ -615,6 +617,9 @@ bool LLTextureCacheRemoteWorker::doWrite() if(idx >= 0) { // write to the fast cache. + // mRawImage is not entirely safe here since it is a pointer to one owned by cache worker, + // it could have been retrieved via getRequestFinished() and then modified. + // If writeToFastCache crashes, something is wrong around fetch worker. if(!mCache->writeToFastCache(mID, idx, mRawImage, mRawDiscardLevel)) { LL_WARNS() << "writeToFastCache failed" << LL_ENDL; @@ -837,6 +842,7 @@ LLTextureCache::LLTextureCache(bool threaded) mFastCachePoolp(NULL), mFastCachePadBuffer(NULL) { + mHeaderAPRFilePoolp = new LLVolatileAPRPool(); // is_local = true, because this pool is for headers, headers are under own mutex } LLTextureCache::~LLTextureCache() @@ -845,6 +851,7 @@ LLTextureCache::~LLTextureCache() writeUpdatedEntries() ; delete mFastCachep; delete mFastCachePoolp; + delete mHeaderAPRFilePoolp; ll_aligned_free_16(mFastCachePadBuffer); } @@ -1013,10 +1020,11 @@ void LLTextureCache::purgeCache(ELLPath location, bool remove_dir) if(LLFile::isdir(mTexturesDirName)) { std::string file_name = gDirUtilp->getExpandedFilename(location, entries_filename); - LLAPRFile::remove(file_name, getLocalAPRFilePool()); + // mHeaderAPRFilePoolp because we are under header mutex, and can be in main thread + LLAPRFile::remove(file_name, mHeaderAPRFilePoolp); file_name = gDirUtilp->getExpandedFilename(location, cache_filename); - LLAPRFile::remove(file_name, getLocalAPRFilePool()); + LLAPRFile::remove(file_name, mHeaderAPRFilePoolp); purgeAllTextures(true); } @@ -1093,7 +1101,7 @@ LLAPRFile* LLTextureCache::openHeaderEntriesFile(bool readonly, S32 offset) { llassert_always(mHeaderAPRFile == NULL); apr_int32_t flags = readonly ? APR_READ|APR_BINARY : APR_READ|APR_WRITE|APR_BINARY; - mHeaderAPRFile = new LLAPRFile(mHeaderEntriesFileName, flags, getLocalAPRFilePool()); + mHeaderAPRFile = new LLAPRFile(mHeaderEntriesFileName, flags, mHeaderAPRFilePoolp); if(offset > 0) { mHeaderAPRFile->seek(APR_SET, offset); @@ -1116,10 +1124,10 @@ void LLTextureCache::readEntriesHeader() { // mHeaderEntriesInfo initializes to default values so safe not to read it llassert_always(mHeaderAPRFile == NULL); - if (LLAPRFile::isExist(mHeaderEntriesFileName, getLocalAPRFilePool())) + if (LLAPRFile::isExist(mHeaderEntriesFileName, mHeaderAPRFilePoolp)) { LLAPRFile::readEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo), - getLocalAPRFilePool()); + mHeaderAPRFilePoolp); } else //create an empty entries header. { @@ -1151,7 +1159,7 @@ void LLTextureCache::writeEntriesHeader() if (!mReadOnly) { LLAPRFile::writeEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo), - getLocalAPRFilePool()); + mHeaderAPRFilePoolp); } } @@ -1669,6 +1677,91 @@ void LLTextureCache::purgeAllTextures(bool purge_directories) LL_INFOS() << "The entire texture cache is cleared." << LL_ENDL ; } +void LLTextureCache::purgeTexturesLazy(F32 time_limit_sec) +{ + if (mReadOnly) + { + return; + } + + if (!mThreaded) + { + LLAppViewer::instance()->pauseMainloopTimeout(); + } + + // time_limit doesn't account for lock time + LLMutexLock lock(&mHeaderMutex); + + if (mPurgeEntryList.empty()) + { + // Read the entries list and form list of textures to purge + std::vector<Entry> entries; + U32 num_entries = openAndReadEntries(entries); + if (!num_entries) + { + return; // nothing to purge + } + + // Use mTexturesSizeMap to collect UUIDs of textures with bodies + typedef std::set<std::pair<U32, S32> > time_idx_set_t; + std::set<std::pair<U32, S32> > time_idx_set; + for (size_map_t::iterator iter1 = mTexturesSizeMap.begin(); + iter1 != mTexturesSizeMap.end(); ++iter1) + { + if (iter1->second > 0) + { + id_map_t::iterator iter2 = mHeaderIDMap.find(iter1->first); + if (iter2 != mHeaderIDMap.end()) + { + S32 idx = iter2->second; + time_idx_set.insert(std::make_pair(entries[idx].mTime, idx)); + } + else + { + LL_ERRS("TextureCache") << "mTexturesSizeMap / mHeaderIDMap corrupted." << LL_ENDL; + } + } + } + + S64 cache_size = mTexturesSizeTotal; + S64 purged_cache_size = (sCacheMaxTexturesSize * (S64)((1.f - TEXTURE_CACHE_PURGE_AMOUNT) * 100)) / 100; + for (time_idx_set_t::iterator iter = time_idx_set.begin(); + iter != time_idx_set.end(); ++iter) + { + S32 idx = iter->second; + if (cache_size >= purged_cache_size) + { + cache_size -= entries[idx].mBodySize; + mPurgeEntryList.push_back(std::pair<S32, Entry>(idx, entries[idx])); + } + else + { + break; + } + } + LL_DEBUGS("TextureCache") << "Formed Purge list of " << mPurgeEntryList.size() << " entries" << LL_ENDL; + } + else + { + // Remove collected entried + LLTimer timer; + while (!mPurgeEntryList.empty() && timer.getElapsedTimeF32() < time_limit_sec) + { + S32 idx = mPurgeEntryList.back().first; + Entry entry = mPurgeEntryList.back().second; + mPurgeEntryList.pop_back(); + // make sure record is still valid + id_map_t::iterator iter_header = mHeaderIDMap.find(entry.mID); + if (iter_header != mHeaderIDMap.end() && iter_header->second == idx) + { + std::string tex_filename = getTextureFileName(entry.mID); + removeEntry(idx, entry, tex_filename); + writeEntryToHeaderImmediately(idx, entry); + } + } + } +} + void LLTextureCache::purgeTextures(bool validate) { if (mReadOnly) @@ -1733,28 +1826,28 @@ void LLTextureCache::purgeTextures(bool validate) iter != time_idx_set.end(); ++iter) { S32 idx = iter->second; - bool purge_entry = false; - std::string filename = getTextureFileName(entries[idx].mID); - if (cache_size >= purged_cache_size) - { - purge_entry = true; - } - else if (validate) + bool purge_entry = false; + if (validate) { // make sure file exists and is the correct size U32 uuididx = entries[idx].mID.mData[0]; if (uuididx == validate_idx) { + std::string filename = getTextureFileName(entries[idx].mID); LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mBodySize << LL_ENDL; - S32 bodysize = LLAPRFile::size(filename, getLocalAPRFilePool()); + // mHeaderAPRFilePoolp because this is under header mutex in main thread + S32 bodysize = LLAPRFile::size(filename, mHeaderAPRFilePoolp); if (bodysize != entries[idx].mBodySize) { - LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mBodySize - << filename << LL_ENDL; + LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mBodySize << filename << LL_ENDL; purge_entry = true; } } } + else if (cache_size >= purged_cache_size) + { + purge_entry = true; + } else { break; @@ -1763,6 +1856,7 @@ void LLTextureCache::purgeTextures(bool validate) if (purge_entry) { purge_count++; + std::string filename = getTextureFileName(entries[idx].mID); LL_DEBUGS("TextureCache") << "PURGING: " << filename << LL_ENDL; cache_size -= entries[idx].mBodySize; removeEntry(idx, entries[idx], filename) ; @@ -1928,11 +2022,10 @@ LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 prio } if (mDoPurge) { - // NOTE: This may cause an occasional hiccup, - // but it really needs to be done on the control thread - // (i.e. here) - purgeTextures(false); - mDoPurge = FALSE; + // NOTE: Needs to be done on the control thread + // (i.e. here) + purgeTexturesLazy(TEXTURE_LAZY_PURGE_TIME_LIMIT); + mDoPurge = !mPurgeEntryList.empty(); } LLMutexLock lock(&mWorkersMutex); LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id, @@ -1976,7 +2069,9 @@ LLPointer<LLImageRaw> LLTextureCache::readFromFastCache(const LLUUID& id, S32& d } S32 image_size = head[0] * head[1] * head[2]; - if(!image_size) //invalid + if(image_size <= 0 + || image_size > TEXTURE_FAST_CACHE_DATA_SIZE + || head[3] < 0) //invalid { closeFastCache(); return NULL; @@ -1998,46 +2093,6 @@ LLPointer<LLImageRaw> LLTextureCache::readFromFastCache(const LLUUID& id, S32& d return raw; } -#if LL_WINDOWS - -static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific - -U32 exception_dupe_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) -{ - if (code == STATUS_MSC_EXCEPTION) - { - // C++ exception, go on - return EXCEPTION_CONTINUE_SEARCH; - } - else - { - // handle it - return EXCEPTION_EXECUTE_HANDLER; - } -} - -//due to unwinding -void dupe(LLPointer<LLImageRaw> &raw) -{ - raw = raw->duplicate(); -} - -void logExceptionDupplicate(LLPointer<LLImageRaw> &raw) -{ - __try - { - dupe(raw); - } - __except (exception_dupe_filter(GetExceptionCode(), GetExceptionInformation())) - { - // convert to C++ styled exception - char integer_string[32]; - sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); - throw std::exception(integer_string); - } -} -#endif - //return the fast cache location bool LLTextureCache::writeToFastCache(LLUUID image_id, S32 id, LLPointer<LLImageRaw> raw, S32 discardlevel) { @@ -2054,8 +2109,9 @@ bool LLTextureCache::writeToFastCache(LLUUID image_id, S32 id, LLPointer<LLImage c = raw->getComponents(); S32 i = 0 ; - - while(((w >> i) * (h >> i) * c) > TEXTURE_FAST_CACHE_ENTRY_SIZE - TEXTURE_FAST_CACHE_ENTRY_OVERHEAD) + + // Search for a discard level that will fit into fast cache + while(((w >> i) * (h >> i) * c) > TEXTURE_FAST_CACHE_DATA_SIZE) { ++i ; } @@ -2066,31 +2122,8 @@ bool LLTextureCache::writeToFastCache(LLUUID image_id, S32 id, LLPointer<LLImage h >>= i; if(w * h *c > 0) //valid { - //make a duplicate to keep the original raw image untouched. - - try - { -#if LL_WINDOWS - // Temporary diagnostics for scale/duplicate crash - logExceptionDupplicate(raw); -#else - raw = raw->duplicate(); -#endif - } - catch (...) - { - removeFromCache(image_id); - LL_ERRS() << "Failed to cache image: " << image_id - << " local id: " << id - << " Exception: " << boost::current_exception_diagnostic_information() - << " Image new width: " << w - << " Image new height: " << h - << " Image new components: " << c - << " Image discard difference: " << i - << LL_ENDL; - - return false; - } + // Make a duplicate to keep the original raw image untouched. + raw = raw->duplicate(); if (raw->isBufferInvalid()) { @@ -2146,7 +2179,7 @@ void LLTextureCache::openFastCache(bool first_time) { mFastCachePadBuffer = (U8*)ll_aligned_malloc_16(TEXTURE_FAST_CACHE_ENTRY_SIZE); } - mFastCachePoolp = new LLVolatileAPRPool(); + mFastCachePoolp = new LLVolatileAPRPool(); // is_local= true by default, so not thread safe by default if (LLAPRFile::isExist(mFastCacheFileName, mFastCachePoolp)) { mFastCachep = new LLAPRFile(mFastCacheFileName, APR_READ|APR_WRITE|APR_BINARY, mFastCachePoolp) ; @@ -2230,7 +2263,9 @@ void LLTextureCache::removeCachedTexture(const LLUUID& id) mTexturesSizeMap.erase(id); } mHeaderIDMap.erase(id); - LLAPRFile::remove(getTextureFileName(id), getLocalAPRFilePool()); + // We are inside header's mutex so mHeaderAPRFilePoolp is safe to use, + // but getLocalAPRFilePool() is not safe, it might be in use by worker + LLAPRFile::remove(getTextureFileName(id), mHeaderAPRFilePoolp); } //called after mHeaderMutex is locked. @@ -2242,7 +2277,10 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename) { if (entry.mBodySize == 0) // Always attempt to remove when mBodySize > 0. { - if (LLAPRFile::isExist(filename, getLocalAPRFilePool())) // Sanity check. Shouldn't exist when body size is 0. + // Sanity check. Shouldn't exist when body size is 0. + // We are inside header's mutex so mHeaderAPRFilePoolp is safe to use, + // but getLocalAPRFilePool() is not safe, it might be in use by worker + if (LLAPRFile::isExist(filename, mHeaderAPRFilePoolp)) { LL_WARNS("TextureCache") << "Entry has body size of zero but file " << filename << " exists. Deleting this file, too." << LL_ENDL; } @@ -2262,7 +2300,7 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename) if (file_maybe_exists) { - LLAPRFile::remove(filename, getLocalAPRFilePool()); + LLAPRFile::remove(filename, mHeaderAPRFilePoolp); } } diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h index 81ea7aeee2..e1c752b58e 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -45,6 +45,11 @@ class LLTextureCache : public LLWorkerThread friend class LLTextureCacheLocalFileWorker; private: + +#if LL_WINDOWS +#pragma pack(push,1) +#endif + // Entries static const U32 sHeaderEncoderStringSize = 32; struct EntriesInfo @@ -73,7 +78,10 @@ private: U32 mTime; // seconds since 1/1/1970 }; - +#if LL_WINDOWS +#pragma pack(pop) +#endif + public: class Responder : public LLResponder @@ -139,7 +147,7 @@ public: U32 getEntries() { return mHeaderEntriesInfo.mEntries; } U32 getMaxEntries() { return sCacheMaxEntries; }; BOOL isInCache(const LLUUID& id) ; - BOOL isInLocal(const LLUUID& id) ; + BOOL isInLocal(const LLUUID& id) ; //not thread safe at the moment protected: // Accessed by LLTextureCacheWorker @@ -155,6 +163,7 @@ private: void readHeaderCache(); void clearCorruptedCache(); void purgeAllTextures(bool purge_directories); + void purgeTexturesLazy(F32 time_limit_sec); void purgeTextures(bool validate); LLAPRFile* openHeaderEntriesFile(bool readonly, S32 offset); void closeHeaderEntriesFile(); @@ -189,6 +198,11 @@ private: LLMutex mFastCacheMutex; LLAPRFile* mHeaderAPRFile; LLVolatileAPRPool* mFastCachePoolp; + + // mLocalAPRFilePoolp is not thread safe and is meant only for workers + // howhever mHeaderEntriesFileName is accessed not from workers' threads + // so it needs own pool (not thread safe by itself, relies onto header's mutex) + LLVolatileAPRPool* mHeaderAPRFilePoolp; typedef std::map<handle_t, LLTextureCacheWorker*> handle_map_t; handle_map_t mReaders; @@ -225,6 +239,8 @@ private: typedef std::map<S32, Entry> idx_entry_map_t; idx_entry_map_t mUpdatedEntryMap; + typedef std::vector<std::pair<S32, Entry> > idx_entry_vector_t; + idx_entry_vector_t mPurgeEntryList; // Statics static F32 sHeaderCacheVersion; diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 8a2fc881a9..1c4a56b549 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -73,9 +73,6 @@ #include "llavatarappearancedefines.h" -static const F32 CONTEXT_CONE_IN_ALPHA = 0.0f; -static const F32 CONTEXT_CONE_OUT_ALPHA = 1.f; -static const F32 CONTEXT_FADE_TIME = 0.08f; static const S32 LOCAL_TRACKING_ID_COLUMN = 1; @@ -143,17 +140,17 @@ void LLFloaterTexturePicker::setImageID(const LLUUID& image_id, bool set_selecti if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(mImageAssetID)) { - if ( mBakeTextureEnabled && mModeSelector->getSelectedIndex() != 2) + if ( mBakeTextureEnabled && mModeSelector->getValue().asInteger() != 2) { - mModeSelector->setSelectedIndex(2, 0); + mModeSelector->selectByValue(2); onModeSelect(0,this); } } else { - if (mModeSelector->getSelectedIndex() == 2) + if (mModeSelector->getValue().asInteger() == 2) { - mModeSelector->setSelectedIndex(0, 0); + mModeSelector->selectByValue(0); onModeSelect(0,this); } @@ -350,7 +347,7 @@ BOOL LLFloaterTexturePicker::postBuild() } mTentativeLabel = getChild<LLTextBox>("Multiple"); - mResolutionLabel = getChild<LLTextBox>("unknown"); + mResolutionLabel = getChild<LLTextBox>("size_lbl"); childSetAction("Default",LLFloaterTexturePicker::onBtnSetToDefault,this); @@ -366,9 +363,9 @@ BOOL LLFloaterTexturePicker::postBuild() mInventoryPanel = getChild<LLInventoryPanel>("inventory panel"); - mModeSelector = getChild<LLRadioGroup>("mode_selection"); + mModeSelector = getChild<LLComboBox>("mode_selection"); mModeSelector->setCommitCallback(onModeSelect, this); - mModeSelector->setSelectedIndex(0, 0); + mModeSelector->selectByValue(0); if(mInventoryPanel) { @@ -398,7 +395,7 @@ BOOL LLFloaterTexturePicker::postBuild() - if (!mImageAssetID.isNull()) + if(!mImageAssetID.isNull()) { mInventoryPanel->setSelection(findItemID(mImageAssetID, FALSE), TAKE_FOCUS_NO); } @@ -410,7 +407,7 @@ BOOL LLFloaterTexturePicker::postBuild() mLocalScrollCtrl = getChild<LLScrollListCtrl>("l_name_list"); mLocalScrollCtrl->setCommitCallback(onLocalScrollCommit, this); - LLLocalBitmapMgr::feedScrollList(mLocalScrollCtrl); + LLLocalBitmapMgr::getInstance()->feedScrollList(mLocalScrollCtrl); mNoCopyTextureSelected = FALSE; @@ -435,66 +432,15 @@ BOOL LLFloaterTexturePicker::postBuild() getChild<LLComboBox>("l_bake_use_texture_combo_box")->setCommitCallback(onBakeTextureSelect, this); getChild<LLCheckBoxCtrl>("hide_base_mesh_region")->setCommitCallback(onHideBaseMeshRegionCheck, this); - setBakeTextureEnabled(FALSE); + setBakeTextureEnabled(TRUE); return TRUE; } // virtual void LLFloaterTexturePicker::draw() { - if (mOwner) - { - // draw cone of context pointing back to texture swatch - LLRect owner_rect; - mOwner->localRectToOtherView(mOwner->getLocalRect(), &owner_rect, this); - LLRect local_rect = getLocalRect(); - if (gFocusMgr.childHasKeyboardFocus(this) && mOwner->isInVisibleChain() && mContextConeOpacity > 0.001f) - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLEnable(GL_CULL_FACE); - gGL.begin(LLRender::QUADS); - { - 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.vertex2i(owner_rect.mLeft, owner_rect.mBottom); - } - gGL.end(); - } - } - - if (gFocusMgr.childHasMouseCapture(getDragHandle())) - { - mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLSmoothInterpolation::getInterpolant(CONTEXT_FADE_TIME)); - } - else - { - mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(CONTEXT_FADE_TIME)); - } + static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f); + drawConeToOwner(mContextConeOpacity, max_opacity, mOwner); updateImageStats(); @@ -743,7 +689,7 @@ void LLFloaterTexturePicker::onBtnSelect(void* userdata) if (self->mLocalScrollCtrl->getVisible() && !self->mLocalScrollCtrl->getAllSelected().empty()) { LLUUID temp_id = self->mLocalScrollCtrl->getFirstSelected()->getColumn(LOCAL_TRACKING_ID_COLUMN)->getValue().asUUID(); - local_id = LLLocalBitmapMgr::getWorldID(temp_id); + local_id = LLLocalBitmapMgr::getInstance()->getWorldID(temp_id); } } @@ -810,27 +756,27 @@ void LLFloaterTexturePicker::onSelectionChange(const std::deque<LLFolderViewItem void LLFloaterTexturePicker::onModeSelect(LLUICtrl* ctrl, void *userdata) { LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; - int mode = self->mModeSelector->getSelectedIndex(); + int index = self->mModeSelector->getValue().asInteger(); - self->getChild<LLButton>("Default")->setVisible(mode == 0); - self->getChild<LLButton>("Blank")->setVisible(mode == 0); - self->getChild<LLButton>("None")->setVisible(mode == 0); - self->getChild<LLButton>("Pipette")->setVisible(mode == 0); - self->getChild<LLFilterEditor>("inventory search editor")->setVisible(mode == 0); - self->getChild<LLInventoryPanel>("inventory panel")->setVisible(mode == 0); + self->getChild<LLButton>("Default")->setVisible(index == 0 ? TRUE : FALSE); + self->getChild<LLButton>("Blank")->setVisible(index == 0 ? TRUE : FALSE); + self->getChild<LLButton>("None")->setVisible(index == 0 ? TRUE : FALSE); + self->getChild<LLButton>("Pipette")->setVisible(index == 0 ? TRUE : FALSE); + self->getChild<LLFilterEditor>("inventory search editor")->setVisible(index == 0 ? TRUE : FALSE); + self->getChild<LLInventoryPanel>("inventory panel")->setVisible(index == 0 ? TRUE : FALSE); /*self->getChild<LLCheckBox>("show_folders_check")->setVisible(mode); no idea under which conditions the above is even shown, needs testing. */ - self->getChild<LLButton>("l_add_btn")->setVisible(mode == 1); - self->getChild<LLButton>("l_rem_btn")->setVisible(mode == 1); - self->getChild<LLButton>("l_upl_btn")->setVisible(mode == 1); - self->getChild<LLScrollListCtrl>("l_name_list")->setVisible(mode == 1); + self->getChild<LLButton>("l_add_btn")->setVisible(index == 1 ? TRUE : FALSE); + self->getChild<LLButton>("l_rem_btn")->setVisible(index == 1 ? TRUE : FALSE); + self->getChild<LLButton>("l_upl_btn")->setVisible(index == 1 ? TRUE : FALSE); + self->getChild<LLScrollListCtrl>("l_name_list")->setVisible(index == 1 ? TRUE : FALSE); - self->getChild<LLComboBox>("l_bake_use_texture_combo_box")->setVisible(mode == 2); - self->getChild<LLCheckBoxCtrl>("hide_base_mesh_region")->setVisible(false);// mode == 2); + self->getChild<LLComboBox>("l_bake_use_texture_combo_box")->setVisible(index == 2 ? TRUE : FALSE); + self->getChild<LLCheckBoxCtrl>("hide_base_mesh_region")->setVisible(FALSE);// index == 2 ? TRUE : FALSE); - if (mode == 2) + if (index == 2) { self->stopUsingPipette(); @@ -890,10 +836,10 @@ void LLFloaterTexturePicker::onModeSelect(LLUICtrl* ctrl, void *userdata) // static void LLFloaterTexturePicker::onBtnAdd(void* userdata) { - if (LLLocalBitmapMgr::addUnit() == true) + if (LLLocalBitmapMgr::getInstance()->addUnit() == true) { LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; - LLLocalBitmapMgr::feedScrollList(self->mLocalScrollCtrl); + LLLocalBitmapMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl); } } @@ -912,13 +858,13 @@ void LLFloaterTexturePicker::onBtnRemove(void* userdata) if (list_item) { LLUUID tracking_id = list_item->getColumn(LOCAL_TRACKING_ID_COLUMN)->getValue().asUUID(); - LLLocalBitmapMgr::delUnit(tracking_id); + LLLocalBitmapMgr::getInstance()->delUnit(tracking_id); } } self->getChild<LLButton>("l_rem_btn")->setEnabled(false); self->getChild<LLButton>("l_upl_btn")->setEnabled(false); - LLLocalBitmapMgr::feedScrollList(self->mLocalScrollCtrl); + LLLocalBitmapMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl); } } @@ -938,7 +884,7 @@ void LLFloaterTexturePicker::onBtnUpload(void* userdata) in the future, it might be a good idea to check the vector size and if more than one units is selected - opt for multi-image upload. */ LLUUID tracking_id = (LLUUID)self->mLocalScrollCtrl->getSelectedItemLabel(LOCAL_TRACKING_ID_COLUMN); - std::string filename = LLLocalBitmapMgr::getFilename(tracking_id); + std::string filename = LLLocalBitmapMgr::getInstance()->getFilename(tracking_id); if (!filename.empty()) { @@ -961,7 +907,7 @@ void LLFloaterTexturePicker::onLocalScrollCommit(LLUICtrl* ctrl, void* userdata) if (has_selection) { LLUUID tracking_id = (LLUUID)self->mLocalScrollCtrl->getSelectedItemLabel(LOCAL_TRACKING_ID_COLUMN); - LLUUID inworld_id = LLLocalBitmapMgr::getWorldID(tracking_id); + LLUUID inworld_id = LLLocalBitmapMgr::getInstance()->getWorldID(tracking_id); if (self->mSetImageAssetIDCallback) { self->mSetImageAssetIDCallback(inworld_id); @@ -1137,7 +1083,7 @@ void LLFloaterTexturePicker::onFilterEdit(const std::string& search_string ) void LLFloaterTexturePicker::setLocalTextureEnabled(BOOL enabled) { - mModeSelector->setIndexEnabled(1,enabled); + mModeSelector->setEnabledByValue(1, enabled); } void LLFloaterTexturePicker::setBakeTextureEnabled(BOOL enabled) @@ -1145,18 +1091,18 @@ void LLFloaterTexturePicker::setBakeTextureEnabled(BOOL enabled) BOOL changed = (enabled != mBakeTextureEnabled); mBakeTextureEnabled = enabled; - mModeSelector->setIndexEnabled(2, enabled); + mModeSelector->setEnabledByValue(2, enabled); - if (!mBakeTextureEnabled && (mModeSelector->getSelectedIndex() == 2)) + if (!mBakeTextureEnabled && (mModeSelector->getValue().asInteger() == 2)) { - mModeSelector->setSelectedIndex(0, 0); + mModeSelector->selectByValue(0); } if (changed && mBakeTextureEnabled && LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(mImageAssetID)) { - if (mModeSelector->getSelectedIndex() != 2) + if (mModeSelector->getValue().asInteger() != 2) { - mModeSelector->setSelectedIndex(2, 0); + mModeSelector->selectByValue(2); } } onModeSelect(0, this); @@ -1211,8 +1157,7 @@ LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p) mImageAssetID(p.image_id), mDefaultImageAssetID(p.default_image_id), mDefaultImageName(p.default_image_name), - mFallbackImage(p.fallback_image), - mBakeTextureEnabled(FALSE) + mFallbackImage(p.fallback_image) { // Default of defaults is white image for diff tex @@ -1405,7 +1350,7 @@ void LLTextureCtrl::showPicker(BOOL take_focus) } if (texture_floaterp) { - texture_floaterp->setBakeTextureEnabled(mBakeTextureEnabled); + texture_floaterp->setBakeTextureEnabled(TRUE); } LLFloater* root_floater = gFloaterView->getParentFloater(this); @@ -1584,7 +1529,6 @@ void LLTextureCtrl::setImageAssetID( const LLUUID& asset_id ) void LLTextureCtrl::setBakeTextureEnabled(BOOL enabled) { - mBakeTextureEnabled = enabled; LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get(); if (floaterp) { diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index b2a34a37c4..92f6f89af6 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -36,7 +36,6 @@ #include "llstring.h" #include "lluictrl.h" #include "llpermissionsflags.h" -#include "llradiogroup.h" #include "lltextbox.h" // for params #include "llviewerinventory.h" #include "llviewborder.h" // for params @@ -44,7 +43,7 @@ #include "llviewertexture.h" #include "llwindow.h" -class LLButton; +class LLComboBox; class LLFloaterTexturePicker; class LLInventoryItem; class LLViewerFetchedTexture; @@ -239,7 +238,6 @@ private: BOOL mShowLoadingPlaceholder; std::string mLoadingPlaceholderString; S32 mLabelWidth; - BOOL mBakeTextureEnabled; }; ////////////////////////////////////////////////////////////////////////////////////////// @@ -367,7 +365,7 @@ protected: LLSaveFolderState mSavedFolderState; BOOL mSelectedItemPinned; - LLRadioGroup* mModeSelector; + LLComboBox* mModeSelector; LLScrollListCtrl* mLocalScrollCtrl; private: diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index fe058024f6..f64db7beb5 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -1977,6 +1977,11 @@ bool LLTextureFetchWorker::doWork(S32 param) setState(WAIT_ON_WRITE); ++mCacheWriteCount; CacheWriteResponder* responder = new CacheWriteResponder(mFetcher, mID); + // This call might be under work mutex, but mRawImage is not nessesary safe here. + // If something retrieves it via getRequestFinished() and modifies, image won't + // be protected by work mutex and won't be safe to use here nor in cache worker. + // So make sure users of getRequestFinished() does not attempt to modify image while + // fetcher is working mCacheWriteHandle = mFetcher->mTextureCache->writeToCache(mID, cache_priority, mFormattedImage->getData(), datasize, mFileSize, mRawImage, mDecodedDiscard, responder); diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index cdf8868597..2aa194e141 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -92,6 +92,7 @@ public: void deleteAllRequests(); // Threads: T* + // keep in mind that if fetcher isn't done, it still might need original raw image bool getRequestFinished(const LLUUID& id, S32& discard_level, LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux, LLCore::HttpStatus& last_http_get_status); diff --git a/indra/newview/lltexturestats.cpp b/indra/newview/lltexturestats.cpp index b55b4d9ca4..8f4b7d000c 100644 --- a/indra/newview/lltexturestats.cpp +++ b/indra/newview/lltexturestats.cpp @@ -46,8 +46,8 @@ void send_texture_stats_to_sim(const LLSD &texture_stats) LLUUID agent_id = gAgent.getID(); texture_stats_report["agent_id"] = agent_id; texture_stats_report["region_id"] = gAgent.getRegion()->getRegionID(); - texture_stats_report["viewer_channel"] = LLVersionInfo::getChannel(); - texture_stats_report["viewer_version"] = LLVersionInfo::getVersion(); + texture_stats_report["viewer_channel"] = LLVersionInfo::instance().getChannel(); + texture_stats_report["viewer_version"] = LLVersionInfo::instance().getVersion(); texture_stats_report["stats_data"] = texture_stats; std::string texture_cap_url = gAgent.getRegion()->getCapability("TextureStats"); diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index 9ec6b99416..29221c0bc5 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -423,8 +423,8 @@ void LLAvatarTexBar::draw() LLColor4 color; U32 line_num = 1; - for (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin(); - baked_iter != LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); + for (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = LLAvatarAppearance::getDictionary()->getBakedTextures().begin(); + baked_iter != LLAvatarAppearance::getDictionary()->getBakedTextures().end(); ++baked_iter) { const LLAvatarAppearanceDefines::EBakedTextureIndex baked_index = baked_iter->first; @@ -549,7 +549,7 @@ void LLGLTexMemBar::draw() U32 texFetchLatMed = U32(recording.getMean(LLTextureFetch::sTexFetchLatency).value() * 1000.0f); U32 texFetchLatMax = U32(recording.getMax(LLTextureFetch::sTexFetchLatency).value() * 1000.0f); - text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB FBO: %d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB", + text = llformat("GL Tot: %d/%d MB Bound: %4d/%4d MB FBO: %d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB", total_mem.value(), max_total_mem.value(), bound_mem.value(), diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index b9b05966bc..bf56a10d4d 100644 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -430,7 +430,7 @@ void LLToast::setVisible(BOOL show) void LLToast::updateHoveredState() { S32 x, y; - LLUI::getMousePositionScreen(&x, &y); + LLUI::getInstance()->getMousePositionScreen(&x, &y); LLRect panel_rc = mWrapperPanel->calcScreenRect(); LLRect button_rc; @@ -612,11 +612,8 @@ S32 LLToast::notifyParent(const LLSD& info) //static void LLToast::updateClass() { - for (LLInstanceTracker<LLToast>::instance_iter iter = LLInstanceTracker<LLToast>::beginInstances(); - iter != LLInstanceTracker<LLToast>::endInstances(); ) + for (auto& toast : LLInstanceTracker<LLToast>::instance_snapshot()) { - LLToast& toast = *iter++; - toast.updateHoveredState(); } } @@ -624,22 +621,6 @@ void LLToast::updateClass() // static void LLToast::cleanupToasts() { - LLToast * toastp = NULL; - - while (LLInstanceTracker<LLToast>::instanceCount() > 0) - { - { // Need to scope iter to allow deletion - LLInstanceTracker<LLToast>::instance_iter iter = LLInstanceTracker<LLToast>::beginInstances(); - toastp = &(*iter); - } - - //LL_INFOS() << "Cleaning up toast id " << toastp->getNotificationID() << LL_ENDL; - - // LLToast destructor will remove it from the LLInstanceTracker. - if (!toastp) - break; // Don't get stuck in the loop if a null pointer somehow got on the list - - delete toastp; - } + LLInstanceTracker<LLToast>::instance_snapshot().deleteAll(); } diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp index 495c9c1f44..8baad30e8f 100644 --- a/indra/newview/lltoastalertpanel.cpp +++ b/indra/newview/lltoastalertpanel.cpp @@ -34,7 +34,6 @@ #include "llfontgl.h" #include "lltextbox.h" #include "llbutton.h" -#include "llcheckboxctrl.h" #include "llkeyboard.h" #include "llfocusmgr.h" #include "lliconctrl.h" @@ -45,6 +44,7 @@ #include "llrootview.h" #include "lltransientfloatermgr.h" #include "llviewercontrol.h" // for gSavedSettings +#include "llweb.h" #include <boost/algorithm/string.hpp> @@ -52,7 +52,6 @@ const S32 MAX_ALLOWED_MSG_WIDTH = 400; const F32 DEFAULT_BUTTON_DELAY = 0.5f; /*static*/ LLControlGroup* LLToastAlertPanel::sSettings = NULL; -/*static*/ LLToastAlertPanel::URLLoader* LLToastAlertPanel::sURLLoader; //----------------------------------------------------------------------------- // Private methods @@ -62,9 +61,8 @@ static const S32 HPAD = 25; static const S32 BTN_HPAD = 8; LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal) - : LLToastPanel(notification), + : LLCheckBoxToastPanel(notification), mDefaultOption( 0 ), - mCheck(NULL), mCaution(notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH), mLabel(notification->getName()), mLineEditor(NULL) @@ -123,6 +121,11 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal data.mURLExternal = mNotification->getURLOpenExternally(); } + if((*it).has("width")) + { + data.mWidth = (*it)["width"].asInteger(); + } + mButtonData.push_back(data); option_index++; } @@ -161,15 +164,29 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal // Calc total width of buttons S32 button_width = 0; S32 sp = font->getWidth(std::string("OO")); + S32 btn_total_width = 0; + S32 default_size_btns = 0; for( S32 i = 0; i < num_options; i++ ) - { + { S32 w = S32(font->getWidth( options[i].second ) + 0.99f) + sp + 2 * LLBUTTON_H_PAD; - button_width = llmax( w, button_width ); + if (mButtonData[i].mWidth > w) + { + btn_total_width += mButtonData[i].mWidth; + } + else + { + button_width = llmax(w, button_width); + default_size_btns++; + } } - S32 btn_total_width = button_width; + if( num_options > 1 ) { - btn_total_width = (num_options * button_width) + ((num_options - 1) * BTN_HPAD); + btn_total_width = btn_total_width + (button_width * default_size_btns) + ((num_options - 1) * BTN_HPAD); + } + else + { + btn_total_width = llmax(btn_total_width, button_width); } // Message: create text box using raw string, as text has been structure deliberately @@ -194,6 +211,11 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal - 3*VPAD - BTN_HEIGHT; // reshape to calculate real text width and height msg_box->reshape( MAX_ALLOWED_MSG_WIDTH, max_allowed_msg_height ); + + if ("GroupLimitInfo" == mNotification->getName() || "GroupLimitInfoPlus" == mNotification->getName()) + { + msg_box->setSkipLinkUnderline(true); + } msg_box->setValue(msg); S32 pixel_width = msg_box->getTextPixelWidth(); @@ -268,14 +290,15 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal mLineEditor->setMaxTextChars(edit_text_max_chars); mLineEditor->setText(edit_text_contents); - if("SaveOutfitAs" == mNotification->getName()) + std::string notif_name = mNotification->getName(); + if (("SaveOutfitAs" == notif_name) || ("SaveSettingAs" == notif_name) || ("CreateLandmarkFolder" == notif_name)) { mLineEditor->setPrevalidate(&LLTextValidate::validateASCII); } // decrease limit of line editor of teleport offer dialog to avoid truncation of // location URL in invitation message, see EXT-6891 - if ("OfferTeleport" == mNotification->getName()) + if ("OfferTeleport" == notif_name) { mLineEditor->setMaxTextLength(gSavedSettings.getS32( "teleport_offer_invitation_max_length")); @@ -329,7 +352,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal if(btn) { btn->setName(options[i].first); - btn->setRect(button_rect.setOriginAndSize( button_left, VPAD, button_width, BTN_HEIGHT )); + btn->setRect(button_rect.setOriginAndSize( button_left, VPAD, (mButtonData[i].mWidth == 0) ? button_width : mButtonData[i].mWidth, BTN_HEIGHT )); btn->setLabel(options[i].second); btn->setFont(font); @@ -344,23 +367,10 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal btn->setFocus(TRUE); } } - button_left += button_width + BTN_HPAD; + button_left += ((mButtonData[i].mWidth == 0) ? button_width : mButtonData[i].mWidth) + BTN_HPAD; } - std::string ignore_label; - - if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE) - { - setCheckBox(LLNotifications::instance().getGlobalString("skipnexttime"), ignore_label); - } - if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY) - { - setCheckBox(LLNotifications::instance().getGlobalString("skipnexttimesessiononly"), ignore_label); - } - else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) - { - setCheckBox(LLNotifications::instance().getGlobalString("alwayschoose"), ignore_label); - } + setCheckBoxes(HPAD, VPAD); // *TODO: check necessity of this code //gFloaterView->adjustToFitScreen(this, FALSE); @@ -380,46 +390,6 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal LLTransientFloaterMgr::GLOBAL, this); } -bool LLToastAlertPanel::setCheckBox( const std::string& check_title, const std::string& check_control ) -{ - mCheck = LLUICtrlFactory::getInstance()->createFromFile<LLCheckBoxCtrl>("alert_check_box.xml", this, LLPanel::child_registry_t::instance()); - - if(!mCheck) - { - return false; - } - - const LLFontGL* font = mCheck->getFont(); - const S32 LINE_HEIGHT = font->getLineHeight(); - - std::vector<std::string> lines; - boost::split(lines, check_title, boost::is_any_of("\n")); - - // Extend dialog for "check next time" - S32 max_msg_width = LLToastPanel::getRect().getWidth() - 2 * HPAD; - S32 check_width = S32(font->getWidth(lines[0]) + 0.99f) + 16; // use width of the first line - max_msg_width = llmax(max_msg_width, check_width); - S32 dialog_width = max_msg_width + 2 * HPAD; - - S32 dialog_height = LLToastPanel::getRect().getHeight(); - dialog_height += LINE_HEIGHT * lines.size(); - dialog_height += LINE_HEIGHT / 2; - - LLToastPanel::reshape( dialog_width, dialog_height, FALSE ); - - S32 msg_x = (LLToastPanel::getRect().getWidth() - max_msg_width) / 2; - - // set check_box's attributes - LLRect check_rect; - mCheck->setRect(check_rect.setOriginAndSize(msg_x, VPAD+BTN_HEIGHT+LINE_HEIGHT/2, max_msg_width, LINE_HEIGHT*lines.size())); - mCheck->setLabel(check_title); - mCheck->setCommitCallback(boost::bind(&LLToastAlertPanel::onClickIgnore, this, _1)); - - LLToastPanel::addChild(mCheck); - - return true; -} - void LLToastAlertPanel::setVisible( BOOL visible ) { // only make the "ding" sound if it's newly visible @@ -555,23 +525,17 @@ void LLToastAlertPanel::onButtonPressed( const LLSD& data, S32 button ) response[button_data->mButton->getName()] = true; // If we declared a URL and chose the URL option, go to the url - if (!button_data->mURL.empty() && sURLLoader != NULL) + if (!button_data->mURL.empty()) { - sURLLoader->load(button_data->mURL, button_data->mURLExternal); + if (button_data->mURLExternal) + { + LLWeb::loadURLExternal(button_data->mURL); + } + else + { + LLWeb::loadURL(button_data->mURL); + } } mNotification->respond(response); // new notification reponse } - -void LLToastAlertPanel::onClickIgnore(LLUICtrl* ctrl) -{ - // checkbox sometimes means "hide and do the default" and - // other times means "warn me again". Yuck. JC - BOOL check = ctrl->getValue().asBoolean(); - if (mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) - { - // question was "show again" so invert value to get "ignore" - check = !check; - } - mNotification->setIgnored(check); -} diff --git a/indra/newview/lltoastalertpanel.h b/indra/newview/lltoastalertpanel.h index d1be5e018e..bd34e40642 100644 --- a/indra/newview/lltoastalertpanel.h +++ b/indra/newview/lltoastalertpanel.h @@ -46,26 +46,12 @@ class LLLineEditor; */ class LLToastAlertPanel - : public LLToastPanel + : public LLCheckBoxToastPanel { LOG_CLASS(LLToastAlertPanel); public: typedef bool (*display_callback_t)(S32 modal); - class URLLoader - { - public: - virtual void load(const std::string& url, bool force_open_externally = 0) = 0; - virtual ~URLLoader() - { - } - }; - - static void setURLLoader(URLLoader* loader) - { - sURLLoader = loader; - } - public: // User's responsibility to call show() after creating these. LLToastAlertPanel( LLNotificationPtr notep, bool is_modal ); @@ -75,13 +61,11 @@ public: virtual void draw(); virtual void setVisible( BOOL visible ); - bool setCheckBox( const std::string&, const std::string& ); void setCaution(BOOL val = TRUE) { mCaution = val; } // If mUnique==TRUE only one copy of this message should exist void setUnique(BOOL val = TRUE) { mUnique = val; } void setEditTextArgs(const LLSD& edit_args); - void onClickIgnore(LLUICtrl* ctrl); void onButtonPressed(const LLSD& data, S32 button); private: @@ -94,19 +78,22 @@ private: BOOL hasTitleBar() const; private: - static URLLoader* sURLLoader; static LLControlGroup* sSettings; struct ButtonData { + ButtonData() + : mWidth(0) + {} + LLButton* mButton; std::string mURL; U32 mURLExternal; + S32 mWidth; }; std::vector<ButtonData> mButtonData; S32 mDefaultOption; - LLCheckBoxCtrl* mCheck; BOOL mCaution; BOOL mUnique; LLUIString mLabel; diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp index a2116817a2..024f25bc98 100644 --- a/indra/newview/lltoastnotifypanel.cpp +++ b/indra/newview/lltoastnotifypanel.cpp @@ -33,6 +33,7 @@ // library includes #include "lldbstrings.h" +#include "llcheckboxctrl.h" #include "lllslconstants.h" #include "llnotifications.h" #include "lluiconstants.h" @@ -55,7 +56,7 @@ const LLFontGL* LLToastNotifyPanel::sFontSmall = NULL; LLToastNotifyPanel::button_click_signal_t LLToastNotifyPanel::sButtonClickSignal; LLToastNotifyPanel::LLToastNotifyPanel(const LLNotificationPtr& notification, const LLRect& rect, bool show_images) -: LLToastPanel(notification), +: LLCheckBoxToastPanel(notification), LLInstanceTracker<LLToastNotifyPanel, LLUUID, LLInstanceTrackerReplaceOnCollision>(notification->getID()) { init(rect, show_images); @@ -162,6 +163,11 @@ void LLToastNotifyPanel::updateButtonsLayout(const std::vector<index_button_pair { left = (max_width - btn_rect.getWidth()) / 2; } + else if (left == 0 && buttons.size() == 2) + { + // Note: this and "size() == 1" shouldn't be inside the cycle, might be good idea to refactor whole placing process + left = (max_width - (btn_rect.getWidth() * 2) - h_pad) / 2; + } else if (left + btn_rect.getWidth() > max_width)// whether there is still some place for button+h_pad in the mControlPanel { // looks like we need to add button to the next row @@ -381,9 +387,9 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images ) if (mIsScriptDialog) { // we are using default width for script buttons so we can determinate button_rows - //to get a number of rows we divide the required width of the buttons to button_panel_width - S32 button_rows = llceil(F32(buttons.size() - 1) * (BUTTON_WIDTH + h_pad) / button_panel_width); - //S32 button_rows = (buttons.size() - 1) * (BUTTON_WIDTH + h_pad) / button_panel_width; + // to get a number of rows we divide the required width of the buttons to button_panel_width + // buttons.size() is reduced by -2 due to presence of ignore button which is calculated independently a bit lower + S32 button_rows = llceil(F32(buttons.size() - 2) * (BUTTON_WIDTH + h_pad) / (button_panel_width + h_pad)); //reserve one row for the ignore_btn button_rows++; //calculate required panel height for scripdialog notification. @@ -409,7 +415,20 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images ) //.xml file intially makes info panel only follow left/right/top. This is so that when control buttons are added the info panel //can shift upward making room for the buttons inside mControlPanel. After the buttons are added, the info panel can then be set to follow 'all'. mInfoPanel->setFollowsAll(); - snapToMessageHeight(mTextBox, LLToastPanel::MAX_TEXT_LENGTH); + + // Add checkbox (one of couple types) if nessesary. + setCheckBoxes(HPAD * 2, 0, mInfoPanel); + if (mCheck) + { + mCheck->setFollows(FOLLOWS_BOTTOM | FOLLOWS_LEFT); + } + // Snap to message, then to checkbox if present + snapToMessageHeight(mTextBox, LLToastPanel::MAX_TEXT_LENGTH); + if (mCheck) + { + S32 new_panel_height = mCheck->getRect().getHeight() + getRect().getHeight() + VPAD; + reshape(getRect().getWidth(), new_panel_height); + } // reshape the panel to its previous size if (current_rect.notEmpty()) diff --git a/indra/newview/lltoastnotifypanel.h b/indra/newview/lltoastnotifypanel.h index e4a75acfda..a5a637c6fa 100644 --- a/indra/newview/lltoastnotifypanel.h +++ b/indra/newview/lltoastnotifypanel.h @@ -47,7 +47,7 @@ class LLNotificationForm; * @deprecated this class will be removed after all toast panel types are * implemented in separate classes. */ -class LLToastNotifyPanel: public LLToastPanel, public LLInstanceTracker<LLToastNotifyPanel, LLUUID, LLInstanceTrackerReplaceOnCollision> +class LLToastNotifyPanel: public LLCheckBoxToastPanel, public LLInstanceTracker<LLToastNotifyPanel, LLUUID, LLInstanceTrackerReplaceOnCollision> { public: /** diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp index 7c624d5b50..100d5ee713 100644 --- a/indra/newview/lltoastpanel.cpp +++ b/indra/newview/lltoastpanel.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "lldbstrings.h" +#include "llcheckboxctrl.h" #include "llpanelgenerictip.h" #include "llpanelonlinestatus.h" #include "llnotifications.h" @@ -34,6 +35,8 @@ #include "lltoastpanel.h" #include "lltoastscriptquestion.h" +#include <boost/algorithm/string.hpp> + //static const S32 LLToastPanel::MIN_PANEL_HEIGHT = 40; // VPAD(4)*2 + ICON_HEIGHT(32) // 'magic numbers', consider initializing (512+20) part from xml/notifications @@ -145,3 +148,108 @@ LLToastPanel* LLToastPanel::buidPanelFromNotification( return res; } + +LLCheckBoxToastPanel::LLCheckBoxToastPanel(const LLNotificationPtr& p_ntf) +: LLToastPanel(p_ntf), +mCheck(NULL) +{ + +} + +void LLCheckBoxToastPanel::setCheckBoxes(const S32 &h_pad, const S32 &v_pad, LLView *parent_view) +{ + std::string ignore_label; + LLNotificationFormPtr form = mNotification->getForm(); + + if (form->getIgnoreType() == LLNotificationForm::IGNORE_CHECKBOX_ONLY) + { + // Normally text is only used to describe notification in preferences, + // but this one is not displayed in preferences and works on case by case + // basis. + // Display text if present, display 'always chose' if not. + std::string ignore_message = form->getIgnoreMessage(); + if (ignore_message.empty()) + { + ignore_message = LLNotifications::instance().getGlobalString("alwayschoose"); + } + setCheckBox(ignore_message, ignore_label, boost::bind(&LLCheckBoxToastPanel::onCommitCheckbox, this, _1), h_pad, v_pad, parent_view); + } + else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE) + { + setCheckBox(LLNotifications::instance().getGlobalString("skipnexttime"), ignore_label, boost::bind(&LLCheckBoxToastPanel::onCommitCheckbox, this, _1), h_pad, v_pad, parent_view); + } + if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY) + { + setCheckBox(LLNotifications::instance().getGlobalString("skipnexttimesessiononly"), ignore_label, boost::bind(&LLCheckBoxToastPanel::onCommitCheckbox, this, _1), h_pad, v_pad, parent_view); + } + else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) + { + setCheckBox(LLNotifications::instance().getGlobalString("alwayschoose"), ignore_label, boost::bind(&LLCheckBoxToastPanel::onCommitCheckbox, this, _1), h_pad, v_pad, parent_view); + } +} + +bool LLCheckBoxToastPanel::setCheckBox(const std::string& check_title, + const std::string& check_control, + const commit_signal_t::slot_type& cb, + const S32 &h_pad, + const S32 &v_pad, + LLView *parent_view) +{ + mCheck = LLUICtrlFactory::getInstance()->createFromFile<LLCheckBoxCtrl>("alert_check_box.xml", this, LLPanel::child_registry_t::instance()); + + if (!mCheck) + { + return false; + } + + const LLFontGL* font = mCheck->getFont(); + const S32 LINE_HEIGHT = font->getLineHeight(); + + std::vector<std::string> lines; + boost::split(lines, check_title, boost::is_any_of("\n")); + + // Extend dialog for "check next time" + S32 max_msg_width = LLToastPanel::getRect().getWidth() - 2 * h_pad; + S32 check_width = S32(font->getWidth(lines[0]) + 0.99f) + 16; // use width of the first line + max_msg_width = llmax(max_msg_width, check_width); + S32 dialog_width = max_msg_width + 2 * h_pad; + + S32 dialog_height = LLToastPanel::getRect().getHeight(); + dialog_height += LINE_HEIGHT * lines.size(); + dialog_height += LINE_HEIGHT / 2; + + LLToastPanel::reshape(dialog_width, dialog_height, FALSE); + + S32 msg_x = (LLToastPanel::getRect().getWidth() - max_msg_width) / 2; + + // set check_box's attributes + LLRect check_rect; + // if we are part of the toast, we need to leave space for buttons + S32 msg_y = v_pad + (parent_view ? 0 : (BTN_HEIGHT + LINE_HEIGHT / 2)); + mCheck->setRect(check_rect.setOriginAndSize(msg_x, msg_y, max_msg_width, LINE_HEIGHT*lines.size())); + mCheck->setLabel(check_title); + mCheck->setCommitCallback(cb); + + if (parent_view) + { + // assume that width and height autoadjusts to toast + parent_view->addChild(mCheck); + } + else + { + LLToastPanel::addChild(mCheck); + } + + return true; +} + +void LLCheckBoxToastPanel::onCommitCheckbox(LLUICtrl* ctrl) +{ + BOOL check = ctrl->getValue().asBoolean(); + if (mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) + { + // question was "show again" so invert value to get "ignore" + check = !check; + } + mNotification->setIgnored(check); +} diff --git a/indra/newview/lltoastpanel.h b/indra/newview/lltoastpanel.h index 6a9b72a5ae..f4c758ade9 100644 --- a/indra/newview/lltoastpanel.h +++ b/indra/newview/lltoastpanel.h @@ -64,4 +64,23 @@ protected: S32 computeSnappedToMessageHeight(LLTextBase* message, S32 maxLineCount); }; +class LLCheckBoxCtrl; + +// Wrapper with support for 'don't ask again' checkbox +class LLCheckBoxToastPanel : public LLToastPanel +{ +public: + LLCheckBoxToastPanel(const LLNotificationPtr& p_ntf); + virtual ~LLCheckBoxToastPanel() {}; + + // set checkboxes acording to defaults from form + void setCheckBoxes(const S32 &h_pad, const S32 &v_pad, LLView *parent_view = NULL); + // set single checkbox + bool setCheckBox(const std::string&, const std::string&, const commit_signal_t::slot_type& cb, const S32 &h_pad, const S32 &v_pad, LLView *parent_view = NULL); +protected: + void onCommitCheckbox(LLUICtrl* ctrl); + + LLCheckBoxCtrl* mCheck; +}; + #endif /* LL_TOASTPANEL_H */ diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp index b5d78f3654..5235914c34 100644 --- a/indra/newview/lltool.cpp +++ b/indra/newview/lltool.cpp @@ -60,7 +60,7 @@ LLTool::~LLTool() } } -BOOL LLTool::handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down) +BOOL LLTool::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); @@ -83,9 +83,9 @@ BOOL LLTool::handleMouseDown(S32 x, S32 y, MASK mask) LL_INFOS() << "LLTool left mouse down" << LL_ENDL; } // by default, didn't handle it + // AGENT_CONTROL_LBUTTON_DOWN is handled by scanMouse() and scanKey() // LL_INFOS() << "LLTool::handleMouseDown" << LL_ENDL; - gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN); - return TRUE; + return FALSE; } BOOL LLTool::handleMouseUp(S32 x, S32 y, MASK mask) @@ -95,8 +95,8 @@ BOOL LLTool::handleMouseUp(S32 x, S32 y, MASK mask) LL_INFOS() << "LLTool left mouse up" << LL_ENDL; } // by default, didn't handle it + // AGENT_CONTROL_LBUTTON_UP is handled by scanMouse() and scanKey() // LL_INFOS() << "LLTool::handleMouseUp" << LL_ENDL; - gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP); return TRUE; } @@ -115,6 +115,12 @@ BOOL LLTool::handleScrollWheel(S32 x, S32 y, S32 clicks) return FALSE; } +BOOL LLTool::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + // by default, didn't handle it + return FALSE; +} + BOOL LLTool::handleDoubleClick(S32 x,S32 y,MASK mask) { // LL_INFOS() << "LLTool::handleDoubleClick" << LL_ENDL; diff --git a/indra/newview/lltool.h b/indra/newview/lltool.h index c5bad9d532..41a38804ce 100644 --- a/indra/newview/lltool.h +++ b/indra/newview/lltool.h @@ -49,7 +49,7 @@ public: virtual BOOL isView() const { return FALSE; } // Virtual functions inherited from LLMouseHandler - virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down); + virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); @@ -57,6 +57,7 @@ public: virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + virtual BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index f66211ef34..50868d0fa5 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -270,7 +270,8 @@ LLToolDragAndDrop::LLDragAndDropDictionary::LLDragAndDropDictionary() addEntry(DAD_GESTURE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dActivateGesture, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_LINK, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_MESH, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dMeshObject, &LLToolDragAndDrop::dad3dNULL)); - // TODO: animation on self could play it? edit it? + addEntry(DAD_SETTINGS, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); + // TODO: animation on self could play it? edit it? // TODO: gesture on self could play it? edit it? }; @@ -1626,6 +1627,7 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_ case DAD_CALLINGCARD: case DAD_MESH: case DAD_CATEGORY: + case DAD_SETTINGS: { LLInventoryObject* inv_obj = (LLInventoryObject*)cargo_data; if(gInventory.getCategory(inv_obj->getUUID()) || (gInventory.getItem(inv_obj->getUUID()) @@ -1728,6 +1730,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); if(gInventory.isObjectDescendentOf(item->getUUID(), outbox_id)) { + // Legacy return ACCEPT_NO; } @@ -2154,6 +2157,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory( const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); if(gInventory.isObjectDescendentOf(category->getUUID(), outbox_id)) { + // Legacy return ACCEPT_NO; } diff --git a/indra/newview/lltoolfocus.cpp b/indra/newview/lltoolfocus.cpp index 596951fdfb..07f46c5fbe 100644 --- a/indra/newview/lltoolfocus.cpp +++ b/indra/newview/lltoolfocus.cpp @@ -293,12 +293,12 @@ BOOL LLToolCamera::handleMouseUp(S32 x, S32 y, MASK mask) BOOL success = LLViewerCamera::getInstance()->projectPosAgentToScreen(focus_pos, mouse_pos); if (success) { - LLUI::setMousePositionScreen(mouse_pos.mX, mouse_pos.mY); + LLUI::getInstance()->setMousePositionScreen(mouse_pos.mX, mouse_pos.mY); } } else if (mMouseSteering) { - LLUI::setMousePositionScreen(mMouseDownX, mMouseDownY); + LLUI::getInstance()->setMousePositionScreen(mMouseDownX, mMouseDownY); } else { @@ -308,7 +308,7 @@ BOOL LLToolCamera::handleMouseUp(S32 x, S32 y, MASK mask) else { // not a valid zoomable object - LLUI::setMousePositionScreen(mMouseDownX, mMouseDownY); + LLUI::getInstance()->setMousePositionScreen(mMouseDownX, mMouseDownY); } // calls releaseMouse() internally diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp index f3e661e71a..f01b374db1 100644 --- a/indra/newview/lltoolgrab.cpp +++ b/indra/newview/lltoolgrab.cpp @@ -142,8 +142,9 @@ BOOL LLToolGrabBase::handleMouseDown(S32 x, S32 y, MASK mask) // call the base class to propogate info to sim LLTool::handleMouseDown(x, y, mask); - - if (!gAgent.leftButtonGrabbed()) + + // leftButtonGrabbed() checks if controls are reserved by scripts, but does not take masks into account + if (!gAgent.leftButtonGrabbed() || ((mask & DEFAULT_GRAB_MASK) != 0 && !gAgentCamera.cameraMouselook())) { // can grab transparent objects (how touch event propagates, scripters rely on this) gViewerWindow->pickAsync(x, y, mask, pickCallback, /*BOOL pick_transparent*/ TRUE); @@ -721,9 +722,14 @@ void LLToolGrabBase::handleHoverActive(S32 x, S32 y, MASK mask) !objectp->isHUDAttachment() && objectp->getRoot() == gAgentAvatarp->getRoot()) { - // force focus to point in space where we were looking previously - gAgentCamera.setFocusGlobal(gAgentCamera.calcFocusPositionTargetGlobal(), LLUUID::null); - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + // we are essentially editing object position + if (!gSavedSettings.getBOOL("EditCameraMovement")) + { + // force focus to point in space where we were looking previously + // Example of use: follow cam scripts shouldn't affect you when movng objects arouns + gAgentCamera.setFocusGlobal(gAgentCamera.calcFocusPositionTargetGlobal(), LLUUID::null); + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + } } else { @@ -1001,7 +1007,7 @@ void LLToolGrabBase::onMouseCaptureLost() // ...move cursor "naturally", as if it had moved when hidden S32 x = mGrabPick.mMousePt.mX + mAccumDeltaX; S32 y = mGrabPick.mMousePt.mY + mAccumDeltaY; - LLUI::setMousePositionScreen(x, y); + LLUI::getInstance()->setMousePositionScreen(x, y); } else if (mHasMoved) { @@ -1011,13 +1017,13 @@ void LLToolGrabBase::onMouseCaptureLost() LLCoordGL gl_point; if (LLViewerCamera::getInstance()->projectPosAgentToScreen(grab_point_agent, gl_point)) { - LLUI::setMousePositionScreen(gl_point.mX, gl_point.mY); + LLUI::getInstance()->setMousePositionScreen(gl_point.mX, gl_point.mY); } } else { // ...move cursor back to click position - LLUI::setMousePositionScreen(mGrabPick.mMousePt.mX, mGrabPick.mMousePt.mY); + LLUI::getInstance()->setMousePositionScreen(mGrabPick.mMousePt.mX, mGrabPick.mMousePt.mY); } gViewerWindow->showCursor(); diff --git a/indra/newview/lltoolgrab.h b/indra/newview/lltoolgrab.h index 02ed5c26d7..ce0de0f946 100644 --- a/indra/newview/lltoolgrab.h +++ b/indra/newview/lltoolgrab.h @@ -44,6 +44,7 @@ class LLPickInfo; void send_ObjectGrab_message(LLViewerObject* object, const LLPickInfo & pick, const LLVector3 &grab_offset); void send_ObjectDeGrab_message(LLViewerObject* object, const LLPickInfo & pick); +const MASK DEFAULT_GRAB_MASK = MASK_CONTROL; /** * LLToolGrabBase contains most of the semantics of LLToolGrab. It's just that diff --git a/indra/newview/lltoolgun.cpp b/indra/newview/lltoolgun.cpp index 6c9155be85..9539081f30 100644 --- a/indra/newview/lltoolgun.cpp +++ b/indra/newview/lltoolgun.cpp @@ -107,11 +107,18 @@ BOOL LLToolGun::handleHover(S32 x, S32 y, MASK mask) if (gSavedSettings.getBOOL("MouseSun")) { - gSky.setSunDirection(LLViewerCamera::getInstance()->getAtAxis(), LLVector3(0.f, 0.f, 0.f)); - gSky.setOverrideSun(TRUE); + LLVector3 sunpos = LLViewerCamera::getInstance()->getAtAxis(); + gSky.setSunDirectionCFR(sunpos); gSavedSettings.setVector3("SkySunDefaultPosition", LLViewerCamera::getInstance()->getAtAxis()); } + if (gSavedSettings.getBOOL("MouseMoon")) + { + LLVector3 moonpos = LLViewerCamera::getInstance()->getAtAxis(); + gSky.setMoonDirectionCFR(moonpos); + gSavedSettings.setVector3("SkyMoonDefaultPosition", LLViewerCamera::getInstance()->getAtAxis()); + } + gViewerWindow->moveCursorToCenter(); gViewerWindow->hideCursor(); } diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp index f6eb290bc3..fa2dd60ee0 100644 --- a/indra/newview/lltoolmgr.cpp +++ b/indra/newview/lltoolmgr.cpp @@ -355,7 +355,7 @@ bool LLToolMgr::inBuildMode() bool LLToolMgr::canAccessMarketplace() { - return (LLMarketplaceData::instance().getSLMStatus() != MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT) || gSavedSettings.getBOOL("InventoryOutboxDisplayBoth"); + return (LLMarketplaceData::instance().getSLMStatus() != MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT); } void LLToolMgr::toggleMarketplace(const LLSD& sdname) @@ -405,7 +405,7 @@ void LLToolMgr::clearTransientTool() void LLToolMgr::onAppFocusLost() { - if (LLApp::isQuitting()) + if (LLApp::isExiting()) return; if (mSelectedTool) diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 2a87bce134..75a5fabdc2 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -63,6 +63,7 @@ #include "llviewerobject.h" #include "llviewerparcelmgr.h" #include "llviewerwindow.h" +#include "llviewerinput.h" #include "llviewermedia.h" #include "llvoavatarself.h" #include "llviewermediafocus.h" @@ -83,7 +84,6 @@ LLToolPie::LLToolPie() mMouseOutsideSlop( false ), mMouseSteerX(-1), mMouseSteerY(-1), - mBlockClickToWalk(false), mClickAction(0), mClickActionBuyEnabled( gSavedSettings.getBOOL("ClickActionBuyEnabled") ), mClickActionPayEnabled( gSavedSettings.getBOOL("ClickActionPayEnabled") ), @@ -91,7 +91,7 @@ LLToolPie::LLToolPie() { } -BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down) +BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); @@ -172,10 +172,8 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask) mPick.mKeyMask = mask; mMouseButtonDown = true; - - handleLeftClickPick(); - return TRUE; + return handleLeftClickPick(); } // Spawn context menus on right mouse down so you can drag over and select @@ -203,9 +201,31 @@ BOOL LLToolPie::handleRightMouseUp(S32 x, S32 y, MASK mask) return LLTool::handleRightMouseUp(x, y, mask); } +BOOL LLToolPie::handleScrollWheelAny(S32 x, S32 y, S32 clicks_x, S32 clicks_y) +{ + BOOL res = FALSE; + // mHoverPick should have updated on its own and we should have a face + // in LLViewerMediaFocus in case of media, so just reuse mHoverPick + if (mHoverPick.mUVCoords.mV[VX] >= 0.f && mHoverPick.mUVCoords.mV[VY] >= 0.f) + { + res = LLViewerMediaFocus::getInstance()->handleScrollWheel(mHoverPick.mUVCoords, clicks_x, clicks_y); + } + else + { + // this won't provide correct coordinates in case of object selection + res = LLViewerMediaFocus::getInstance()->handleScrollWheel(x, y, clicks_x, clicks_y); + } + return res; +} + BOOL LLToolPie::handleScrollWheel(S32 x, S32 y, S32 clicks) { - return LLViewerMediaFocus::getInstance()->handleScrollWheel(x, y, clicks); + return handleScrollWheelAny(x, y, 0, clicks); +} + +BOOL LLToolPie::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + return handleScrollWheelAny(x, y, clicks, 0); } // True if you selected an object. @@ -369,8 +389,6 @@ BOOL LLToolPie::handleLeftClickPick() // put focus back "in world" if (gFocusMgr.getKeyboardFocus()) { - // don't click to walk on attempt to give focus to world - mBlockClickToWalk = true; gFocusMgr.setKeyboardFocus(NULL); } @@ -414,7 +432,7 @@ BOOL LLToolPie::handleLeftClickPick() } object = (LLViewerObject*)object->getParent(); } - if (object && object == gAgentAvatarp && !gSavedSettings.getBOOL("ClickToWalk")) + if (object && object == gAgentAvatarp) { // we left clicked on avatar, switch to focus mode mMouseButtonDown = false; @@ -431,7 +449,6 @@ BOOL LLToolPie::handleLeftClickPick() // LLFirstUse::useLeftClickNoHit(); ///////// - // Eat the event return LLTool::handleMouseDown(x, y, mask); } @@ -538,17 +555,120 @@ void LLToolPie::resetSelection() mClickAction = 0; } -void LLToolPie::walkToClickedLocation() +bool LLToolPie::walkToClickedLocation() +{ + if (gAgent.getFlying() // don't auto-navigate while flying until that works + || !gAgentAvatarp + || gAgentAvatarp->isSitting()) + { + return false; + } + + LLPickInfo saved_pick = mPick; + if (gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK) + { + mPick = gViewerWindow->pickImmediate(mHoverPick.mMousePt.mX, mHoverPick.mMousePt.mY, + FALSE /* ignore transparent */, + FALSE /* ignore rigged */, + FALSE /* ignore particles */); + } + else + { + // We do not handle hover in mouselook as we do in other modes, so + // use croshair's position to do a pick + mPick = gViewerWindow->pickImmediate(gViewerWindow->getWorldViewRectScaled().getWidth() / 2, + gViewerWindow->getWorldViewRectScaled().getHeight() / 2, + FALSE /* ignore transparent */, + FALSE /* ignore rigged */, + FALSE /* ignore particles */); + } + + if (mPick.mPickType == LLPickInfo::PICK_OBJECT) + { + if (mPick.getObject() && mPick.getObject()->isHUDAttachment()) + { + mPick = saved_pick; + return false; + } + } + + LLViewerObject* avatar_object = mPick.getObject(); + + // get pointer to avatar + while (avatar_object && !avatar_object->isAvatar()) + { + avatar_object = (LLViewerObject*)avatar_object->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; + } + + if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || + (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())) + { + gAgentCamera.setFocusOnAvatar(TRUE, TRUE); + + if (mAutoPilotDestination) { mAutoPilotDestination->markDead(); } + mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE); + mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal); + mAutoPilotDestination->setPixelSize(5); + mAutoPilotDestination->setColor(LLColor4U(170, 210, 190)); + mAutoPilotDestination->setDuration(3.f); + + LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal; + gAgent.startAutoPilotGlobal(pos, std::string(), NULL, NULL, NULL, 0.f, 0.03f, FALSE); + LLFirstUse::notMoving(false); + showVisualContextMenuEffect(); + return true; + } + else + { + LL_DEBUGS() << "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; + mPick = saved_pick; + return false; + } + return true; +} + +bool LLToolPie::teleportToClickedLocation() { - if(mAutoPilotDestination) { mAutoPilotDestination->markDead(); } - mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE); - mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal); - mAutoPilotDestination->setPixelSize(5); - mAutoPilotDestination->setColor(LLColor4U(170, 210, 190)); - mAutoPilotDestination->setDuration(3.f); - - LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal; - gAgent.startAutoPilotGlobal(pos, std::string(), NULL, NULL, NULL, 0.f, 0.03f, FALSE); + if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK) + { + // We do not handle hover in mouselook as we do in other modes, so + // use croshair's position to do a pick + BOOL pick_rigged = false; + mHoverPick = gViewerWindow->pickImmediate(gViewerWindow->getWorldViewRectScaled().getWidth() / 2, + gViewerWindow->getWorldViewRectScaled().getHeight() / 2, + FALSE, + pick_rigged); + } + LLViewerObject* objp = mHoverPick.getObject(); + LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL; + + bool is_in_world = mHoverPick.mObjectID.notNull() && objp && !objp->isHUDAttachment(); + bool is_land = mHoverPick.mPickType == LLPickInfo::PICK_LAND; + bool pos_non_zero = !mHoverPick.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))) + { + LLVector3d pos = mHoverPick.mPosGlobal; + pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot(); + gAgent.teleportViaLocationLookAt(pos); + mPick = mHoverPick; + showVisualContextMenuEffect(); + return true; + } + return false; } // When we get object properties after left-clicking on an object @@ -624,8 +744,9 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL; } else if (!mMouseOutsideSlop - && mMouseButtonDown - && gSavedSettings.getBOOL("ClickToWalk")) + && mMouseButtonDown + // disable camera steering if click on land is not used for moving + && gViewerInput.isMouseBindUsed(CLICK_LEFT)) { S32 delta_x = x - mMouseDownX; S32 delta_y = y - mMouseDownY; @@ -649,7 +770,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, pick_rigged); + LLPickInfo click_action_pick = gViewerWindow->pickImmediate(x, y, FALSE, pick_rigged); LLViewerObject* click_action_object = click_action_pick.getObject(); @@ -710,70 +831,10 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) mDoubleClickTimer.reset(); } LLViewerObject* obj = mPick.getObject(); - U8 click_action = final_click_action(obj); - // let media have first pass at click - if (handleMediaMouseUp() || LLViewerMediaFocus::getInstance()->getFocus()) - { - mBlockClickToWalk = true; - } stopCameraSteering(); mMouseButtonDown = false; - if (click_action == CLICK_ACTION_NONE // not doing 1-click action - && gSavedSettings.getBOOL("ClickToWalk") // click to walk enabled - && !gAgent.getFlying() // don't auto-navigate while flying until that works - && gAgentAvatarp - && !gAgentAvatarp->isSitting() - && !mBlockClickToWalk // another behavior hasn't cancelled click to walk - ) - { - // 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 */); - - if (!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(); - } - - 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(); - LLFirstUse::notMoving(false); - - 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()) { @@ -783,7 +844,6 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) LLToolMgr::getInstance()->clearTransientTool(); gAgentCamera.setLookAt(LOOKAT_TARGET_CONVERSATION, obj); // maybe look at object/person clicked on - mBlockClickToWalk = false; return LLTool::handleMouseUp(x, y, mask); } @@ -809,102 +869,21 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask) return TRUE; } - if (!mDoubleClickTimer.getStarted() || (mDoubleClickTimer.getElapsedTimeF32() > 0.3f)) + if (!mDoubleClickTimer.getStarted() || (mDoubleClickTimer.getElapsedTimeF32() > 0.3f)) { mDoubleClickTimer.stop(); return FALSE; } mDoubleClickTimer.stop(); - if (gSavedSettings.getBOOL("DoubleClickAutoPilot")) - { - // We may be doing double 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 */); - - if(mPick.mPickType == LLPickInfo::PICK_OBJECT) - { - if (mPick.getObject() && mPick.getObject()->isHUDAttachment()) - { - mPick = savedPick; - return FALSE; - } - } - - if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || - (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())) - { - walkToClickedLocation(); - return TRUE; - } - else - { - // restore the original pick for any other purpose - mPick = savedPick; - } - } - else if (gSavedSettings.getBOOL("DoubleClickTeleport")) - { - LLViewerObject* objp = mPick.getObject(); - LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL; - - bool is_in_world = mPick.mObjectID.notNull() && objp && !objp->isHUDAttachment(); - 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))) - { - LLVector3d pos = mPick.mPosGlobal; - pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot(); - gAgent.teleportViaLocationLookAt(pos); - return TRUE; - } - } - return FALSE; } static bool needs_tooltip(LLSelectNode* nodep) { - if (!nodep) + if (!nodep || !nodep->mValid) return false; - - LLViewerObject* object = nodep->getObject(); - LLViewerObject *parent = (LLViewerObject *)object->getParent(); - if (object->flagHandleTouch() - || (parent && parent->flagHandleTouch()) - || object->flagTakesMoney() - || (parent && parent->flagTakesMoney()) - || object->flagAllowInventoryAdd() - ) - { - return true; - } - - U8 click_action = final_click_action(object); - if (click_action != 0) - { - return true; - } - - if (nodep->mValid) - { - bool anyone_copy = anyone_copy_selection(nodep); - bool for_sale = for_sale_selection(nodep); - if (anyone_copy || for_sale) - { - return true; - } - } - return false; + return true; } @@ -1185,7 +1164,7 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l const LLMediaEntry* mep = has_media ? tep->getMediaData() : NULL; if (mep) { - viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()); + viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID()); LLPluginClassMedia* media_plugin = NULL; if (media_impl.notNull() && (media_impl->hasMedia())) @@ -1255,7 +1234,8 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l BOOL LLToolPie::handleToolTip(S32 local_x, S32 local_y, MASK mask) { - if (!LLUI::sSettingGroups["config"]->getBOOL("ShowHoverTips")) return TRUE; + static LLCachedControl<bool> show_hover_tips(*LLUI::getInstance()->mSettingGroups["config"], "ShowHoverTips", true); + if (!show_hover_tips) return TRUE; if (!mHoverPick.isValid()) return TRUE; LLViewerObject* hover_object = mHoverPick.getObject(); @@ -1360,7 +1340,7 @@ void LLToolPie::playCurrentMedia(const LLPickInfo& info) LLPluginClassMedia* media_plugin = NULL; - viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()); + viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID()); if(media_impl.notNull() && media_impl->hasMedia()) { @@ -1412,7 +1392,7 @@ void LLToolPie::VisitHomePage(const LLPickInfo& info) LLPluginClassMedia* media_plugin = NULL; - viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()); + viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID()); if(media_impl.notNull() && media_impl->hasMedia()) { @@ -1428,7 +1408,6 @@ void LLToolPie::VisitHomePage(const LLPickInfo& info) void LLToolPie::handleSelect() { // tool is reselected when app gets focus, etc. - mBlockClickToWalk = true; } void LLToolPie::handleDeselect() @@ -1455,7 +1434,7 @@ LLTool* LLToolPie::getOverrideTool(MASK mask) { if (gSavedSettings.getBOOL("EnableGrab")) { - if (mask == MASK_CONTROL) + if (mask == DEFAULT_GRAB_MASK) { return LLToolGrab::getInstance(); } @@ -1489,7 +1468,7 @@ void LLToolPie::stopCameraSteering() bool LLToolPie::inCameraSteerMode() { - return mMouseButtonDown && mMouseOutsideSlop && gSavedSettings.getBOOL("ClickToWalk"); + return mMouseButtonDown && mMouseOutsideSlop; } // true if x,y outside small box around start_x,start_y @@ -1512,19 +1491,19 @@ static void handle_click_action_play() LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if (!parcel) return; - LLViewerMediaImpl::EMediaStatus status = LLViewerParcelMedia::getStatus(); + LLViewerMediaImpl::EMediaStatus status = LLViewerParcelMedia::getInstance()->getStatus(); switch(status) { case LLViewerMediaImpl::MEDIA_PLAYING: - LLViewerParcelMedia::pause(); + LLViewerParcelMedia::getInstance()->pause(); break; case LLViewerMediaImpl::MEDIA_PAUSED: - LLViewerParcelMedia::start(); + LLViewerParcelMedia::getInstance()->start(); break; default: - LLViewerParcelMedia::play(parcel); + LLViewerParcelMedia::getInstance()->play(parcel); break; } } @@ -1555,7 +1534,7 @@ bool LLToolPie::handleMediaClick(const LLPickInfo& pick) if (!mep) return false; - viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()); + viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID()); if (gSavedSettings.getBOOL("MediaOnAPrimUI")) { @@ -1609,7 +1588,7 @@ bool LLToolPie::handleMediaDblClick(const LLPickInfo& pick) if (!mep) return false; - viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()); + viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID()); if (gSavedSettings.getBOOL("MediaOnAPrimUI")) { @@ -1664,7 +1643,7 @@ bool LLToolPie::handleMediaHover(const LLPickInfo& pick) if (mep && gSavedSettings.getBOOL("MediaOnAPrimUI")) { - viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()); + viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID()); if(media_impl.notNull()) { @@ -1702,7 +1681,7 @@ bool LLToolPie::handleMediaMouseUp() if(mMediaMouseCaptureID.notNull()) { // Face media needs to know the mouse went up. - viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mMediaMouseCaptureID); + viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mMediaMouseCaptureID); if(media_impl) { // This will send a mouseUp event to the plugin using the last known mouse coordinate (from a mouseDown or mouseMove), which is what we want. @@ -1731,7 +1710,7 @@ static void handle_click_action_open_media(LLPointer<LLViewerObject> objectp) if( face < 0 || face >= objectp->getNumTEs() ) return; // is media playing on this face? - if (LLViewerMedia::getMediaImplFromTextureID(objectp->getTE(face)->getID()) != NULL) + if (LLViewerMedia::getInstance()->getMediaImplFromTextureID(objectp->getTE(face)->getID()) != NULL) { handle_click_action_play(); return; @@ -1761,7 +1740,7 @@ static ECursorType cursor_from_parcel_media(U8 click_action) open_cursor = UI_CURSOR_TOOLMEDIAOPEN; - LLViewerMediaImpl::EMediaStatus status = LLViewerParcelMedia::getStatus(); + LLViewerMediaImpl::EMediaStatus status = LLViewerParcelMedia::getInstance()->getStatus(); switch(status) { case LLViewerMediaImpl::MEDIA_PLAYING: @@ -1940,7 +1919,6 @@ void LLToolPie::startCameraSteering() { LLFirstUse::notMoving(false); mMouseOutsideSlop = true; - mBlockClickToWalk = true; if (gAgentCamera.getFocusOnAvatar()) { diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index 95d155a474..8f6100e4b4 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -42,14 +42,16 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie> public: // Virtual functions inherited from LLMouseHandler - virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down); + virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); virtual BOOL handleMouseDown(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 handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + BOOL handleScrollWheelAny(S32 x, S32 y, S32 clicks_x, S32 clicks_y); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + virtual BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); virtual void render(); @@ -66,8 +68,8 @@ public: LLViewerObject* getClickActionObject() { return mClickActionObject; } LLObjectSelection* getLeftClickSelection() { return (LLObjectSelection*)mLeftClickSelection; } void resetSelection(); - void walkToClickedLocation(); - void blockClickToWalk() { mBlockClickToWalk = true; } + bool walkToClickedLocation(); + bool teleportToClickedLocation(); void stopClickToWalk(); static void selectionPropertiesReceived(); @@ -109,7 +111,6 @@ private: LLPointer<LLHUDEffectBlob> mAutoPilotDestination; LLPointer<LLHUDEffectBlob> mMouseSteerGrabPoint; bool mClockwise; - bool mBlockClickToWalk; LLUUID mMediaMouseCaptureID; LLPickInfo mPick; LLPickInfo mHoverPick; diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp index 2ec5c41b88..728d0c9417 100644 --- a/indra/newview/lltracker.cpp +++ b/indra/newview/lltracker.cpp @@ -570,8 +570,8 @@ void LLTracker::renderBeacon(LLVector3d pos_global, color_frac = 1.f - 0.6f*(dist/LLViewerCamera::getInstance()->getFar()); } - LLColor4 fogged_color = color_frac * color + (1 - color_frac)*gSky.getFogColor(); - LLColor4 fogged_color_under = color_frac * color_under + (1 - color_frac) * gSky.getFogColor(); + LLColor4 fogged_color = color_frac * color + (1 - color_frac)*gSky.getSkyFogColor(); + LLColor4 fogged_color_under = color_frac * color_under + (1 - color_frac) * gSky.getSkyFogColor(); F32 FADE_DIST = 3.f; fogged_color.mV[3] = llmax(0.2f, llmin(0.5f,(dist-FADE_DIST)/FADE_DIST)); diff --git a/indra/newview/lltrackpicker.cpp b/indra/newview/lltrackpicker.cpp new file mode 100644 index 0000000000..fe6256a8a9 --- /dev/null +++ b/indra/newview/lltrackpicker.cpp @@ -0,0 +1,134 @@ +/** +* @author AndreyK Productengine +* @brief LLTrackPicker class header file including related functions +* +* $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 "llviewerprecompiledheaders.h" + +#include "lltrackpicker.h" + +#include "llradiogroup.h" +#include "llviewercontrol.h" + + +//========================================================================= +namespace +{ + const std::string FLOATER_DEFINITION_XML("floater_pick_track.xml"); + + const std::string BTN_SELECT("btn_select"); + const std::string BTN_CANCEL("btn_cancel"); + const std::string RDO_TRACK_SELECTION("track_selection"); + const std::string RDO_TRACK_PREFIX("radio_sky"); +} +//========================================================================= + +LLFloaterTrackPicker::LLFloaterTrackPicker(LLView * owner, const LLSD ¶ms) : + LLFloater(params), + mContextConeOpacity(0.0f), + mOwnerHandle() +{ + mOwnerHandle = owner->getHandle(); + buildFromFile(FLOATER_DEFINITION_XML); +} + +LLFloaterTrackPicker::~LLFloaterTrackPicker() +{ +} + +BOOL LLFloaterTrackPicker::postBuild() +{ + childSetAction(BTN_CANCEL, [this](LLUICtrl*, const LLSD& param){ onButtonCancel(); }); + childSetAction(BTN_SELECT, [this](LLUICtrl*, const LLSD& param){ onButtonSelect(); }); + return TRUE; +} + +void LLFloaterTrackPicker::onClose(bool app_quitting) +{ + if (app_quitting) + return; + + LLView *owner = mOwnerHandle.get(); + if (owner) + { + owner->setFocus(TRUE); + } +} + +void LLFloaterTrackPicker::showPicker(const LLSD &args) +{ + LLSD::array_const_iterator iter; + LLSD::array_const_iterator end = args.endArray(); + + bool select_item = true; + for (iter = args.beginArray(); iter != end; ++iter) + { + S32 track_id = (*iter)["id"].asInteger(); + bool can_enable = (*iter)["enabled"].asBoolean(); + LLCheckBoxCtrl *view = getChild<LLCheckBoxCtrl>(RDO_TRACK_PREFIX + llformat("%d", track_id), true); + view->setEnabled(can_enable); + view->setLabelArg("[ALT]", (*iter).has("altitude") ? ((*iter)["altitude"].asString() + "m") : " "); + + // Mark first avaliable item as selected + if (can_enable && select_item) + { + select_item = false; + getChild<LLRadioGroup>(RDO_TRACK_SELECTION, true)->setSelectedByValue(LLSD(track_id), TRUE); + } + } + + openFloater(getKey()); + setFocus(TRUE); +} + +void LLFloaterTrackPicker::draw() +{ + LLView *owner = mOwnerHandle.get(); + static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f); + drawConeToOwner(mContextConeOpacity, max_opacity, owner); + + LLFloater::draw(); +} + +void LLFloaterTrackPicker::onButtonCancel() +{ + closeFloater(); +} + +void LLFloaterTrackPicker::onButtonSelect() +{ + if (mCommitSignal) + { + (*mCommitSignal)(this, getChild<LLRadioGroup>(RDO_TRACK_SELECTION, true)->getSelectedValue()); + } + closeFloater(); +} + +void LLFloaterTrackPicker::onFocusLost() +{ + if (isInVisibleChain()) + { + closeFloater(); + } +} diff --git a/indra/newview/lltrackpicker.h b/indra/newview/lltrackpicker.h new file mode 100644 index 0000000000..dab3b72915 --- /dev/null +++ b/indra/newview/lltrackpicker.h @@ -0,0 +1,58 @@ +/** + * @file lltrackpicker.h + * @author AndreyK Productengine + * @brief LLTrackPicker class header file including related functions + * + * $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$ + */ + +#ifndef LL_TRACKPICKER_H +#define LL_TRACKPICKER_H + +#include "llfloater.h" + + +//========================================================================= + +class LLFloaterTrackPicker : public LLFloater +{ +public: + LLFloaterTrackPicker(LLView * owner, const LLSD ¶ms = LLSD()); + virtual ~LLFloaterTrackPicker() override; + + virtual BOOL postBuild() override; + virtual void onClose(bool app_quitting) override; + void showPicker(const LLSD &args); + + virtual void draw() override; + + void onButtonCancel(); + void onButtonSelect(); + +private: + void onFocusLost() override; + + F32 mContextConeOpacity; + LLHandle<LLView> mOwnerHandle; +}; + +#endif // LL_TRACKPICKER_H diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index e424983cf8..553a3cd086 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -134,16 +134,17 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std:: std::string user_agent = llformat("%s %d.%d.%d (%d)", - LLVersionInfo::getChannel().c_str(), - LLVersionInfo::getMajor(), - LLVersionInfo::getMinor(), - LLVersionInfo::getPatch(), - LLVersionInfo::getBuild()); + LLVersionInfo::instance().getChannel().c_str(), + LLVersionInfo::instance().getMajor(), + LLVersionInfo::instance().getMinor(), + LLVersionInfo::instance().getPatch(), + LLVersionInfo::instance().getBuild()); httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); httpOpts->setFollowRedirects(true); + httpOpts->setSSLVerifyPeer(false); std::string url = this->getKeyVerificationURL(key); if (url.empty()) @@ -177,14 +178,15 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s std::string user_agent = llformat("%s %d.%d.%d (%d)", - LLVersionInfo::getChannel().c_str(), - LLVersionInfo::getMajor(), - LLVersionInfo::getMinor(), - LLVersionInfo::getPatch(), - LLVersionInfo::getBuild()); + LLVersionInfo::instance().getChannel().c_str(), + LLVersionInfo::instance().getMajor(), + LLVersionInfo::instance().getMinor(), + LLVersionInfo::instance().getPatch(), + LLVersionInfo::instance().getBuild()); httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); + httpOpts->setSSLVerifyPeer(false); std::string url = this->getTranslateURL(fromTo.first, fromTo.second, msg); if (url.empty()) diff --git a/indra/newview/lltwitterconnect.cpp b/indra/newview/lltwitterconnect.cpp deleted file mode 100644 index b2d2fa9d77..0000000000 --- a/indra/newview/lltwitterconnect.cpp +++ /dev/null @@ -1,576 +0,0 @@ -/** - * @file lltwitterconnect.h - * @author Merov, Cho - * @brief Connection to Twitter 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 "lltwitterconnect.h" -#include "llflickrconnect.h" - -#include "llagent.h" -#include "llcallingcard.h" // for LLAvatarTracker -#include "llcommandhandler.h" -#include "llnotificationsutil.h" -#include "llurlaction.h" -#include "llimagepng.h" -#include "llimagejpeg.h" -#include "lltrans.h" -#include "llevents.h" -#include "llviewerregion.h" - -#include "llfloaterwebcontent.h" -#include "llfloaterreg.h" -#include "llcorehttputil.h" - -boost::scoped_ptr<LLEventPump> LLTwitterConnect::sStateWatcher(new LLEventStream("TwitterConnectState")); -boost::scoped_ptr<LLEventPump> LLTwitterConnect::sInfoWatcher(new LLEventStream("TwitterConnectInfo")); -boost::scoped_ptr<LLEventPump> LLTwitterConnect::sContentWatcher(new LLEventStream("TwitterConnectContent")); - -// Local functions -void log_twitter_connect_error(const std::string& request, U32 status, const std::string& reason, const std::string& code, const std::string& description) -{ - // Note: 302 (redirect) is *not* an error that warrants logging - if (status != 302) - { - LL_WARNS("TwitterConnect") << request << " request failed with a " << status << " " << reason << ". Reason: " << code << " (" << description << ")" << LL_ENDL; - } -} - -void toast_user_for_twitter_success() -{ - LLSD args; - args["MESSAGE"] = LLTrans::getString("twitter_post_success"); - LLNotificationsUtil::add("TwitterConnect", args); -} - -class LLTwitterConnectHandler : public LLCommandHandler -{ -public: - LLTwitterConnectHandler() : LLCommandHandler("fbc", UNTRUSTED_THROTTLE) {} - - bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web) - { - if (tokens.size() >= 1) - { - if (tokens[0].asString() == "connect") - { - if (tokens.size() >= 2 && tokens[1].asString() == "twitter") - { - // this command probably came from the twitter_web browser, so close it - LLFloaterReg::hideInstance("twitter_web"); - - // connect to twitter - if (query_map.has("oauth_token")) - { - LLTwitterConnect::instance().connectToTwitter(query_map["oauth_token"], query_map.get("oauth_verifier")); - } - return true; - } - else if (tokens.size() >= 2 && tokens[1].asString() == "flickr") - { - // this command probably came from the flickr_web browser, so close it - LLFloaterReg::hideInstance("flickr_web"); - - // connect to flickr - if (query_map.has("oauth_token")) - { - LLFlickrConnect::instance().connectToFlickr(query_map["oauth_token"], query_map.get("oauth_verifier")); - } - return true; - } - } - } - return false; - } -}; -LLTwitterConnectHandler gTwitterConnectHandler; - - -/////////////////////////////////////////////////////////////////////////////// -// -void LLTwitterConnect::twitterConnectCoro(std::string requestToken, std::string oauthVerifier) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - - httpOpts->setWantHeaders(true); - httpOpts->setFollowRedirects(false); - - LLSD body; - if (!requestToken.empty()) - body["request_token"] = requestToken; - if (!oauthVerifier.empty()) - body["oauth_verifier"] = oauthVerifier; - - LLSD result = httpAdapter->putAndSuspend(httpRequest, getTwitterConnectURL("/connection"), body, httpOpts); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (!status) - { - if ( status == LLCore::HttpStatus(HTTP_FOUND) ) - { - std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; - if (location.empty()) - { - LL_WARNS("FlickrConnect") << "Missing Location header " << LL_ENDL; - } - else - { - openTwitterWeb(location); - } - } - else - { - LL_WARNS("TwitterConnect") << "Connection failed " << status.toString() << LL_ENDL; - setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED); - log_twitter_connect_error("Connect", status.getStatus(), status.toString(), - result.get("error_code"), result.get("error_description")); - } - } - else - { - LL_DEBUGS("TwitterConnect") << "Connect successful. " << LL_ENDL; - setConnectionState(LLTwitterConnect::TWITTER_CONNECTED); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// -bool LLTwitterConnect::testShareStatus(LLSD &result) -{ - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (status) - return true; - - if (status == LLCore::HttpStatus(HTTP_FOUND)) - { - std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; - if (location.empty()) - { - LL_WARNS("TwitterConnect") << "Missing Location header " << LL_ENDL; - } - else - { - openTwitterWeb(location); - } - } - if (status == LLCore::HttpStatus(HTTP_NOT_FOUND)) - { - LL_DEBUGS("TwitterConnect") << "Not connected. " << LL_ENDL; - connectToTwitter(); - } - else - { - LL_WARNS("TwitterConnect") << "HTTP Status error " << status.toString() << LL_ENDL; - setConnectionState(LLTwitterConnect::TWITTER_POST_FAILED); - log_twitter_connect_error("Share", status.getStatus(), status.toString(), - result.get("error_code"), result.get("error_description")); - } - return false; -} - -void LLTwitterConnect::twitterShareCoro(std::string route, LLSD share) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - - httpOpts->setWantHeaders(true); - httpOpts->setFollowRedirects(false); - - LLSD result = httpAdapter->postAndSuspend(httpRequest, getTwitterConnectURL(route, true), share, httpOpts); - - if (testShareStatus(result)) - { - toast_user_for_twitter_success(); - LL_DEBUGS("TwitterConnect") << "Post successful. " << LL_ENDL; - setConnectionState(LLTwitterConnect::TWITTER_POSTED); - } -} - -void LLTwitterConnect::twitterShareImageCoro(LLPointer<LLImageFormatted> image, std::string status) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); - LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - - httpOpts->setWantHeaders(true); - httpOpts->setFollowRedirects(false); - - std::string imageFormat; - if (dynamic_cast<LLImagePNG*>(image.get())) - { - imageFormat = "png"; - } - else if (dynamic_cast<LLImageJPEG*>(image.get())) - { - imageFormat = "jpg"; - } - else - { - LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL; - return; - } - - // All this code is mostly copied from LLWebProfile::post() - const std::string boundary = "----------------------------0123abcdefab"; - - std::string contentType = "multipart/form-data; boundary=" + boundary; - httpHeaders->append("Content-Type", contentType.c_str()); - - LLCore::BufferArray::ptr_t raw = LLCore::BufferArray::ptr_t(new LLCore::BufferArray()); // - LLCore::BufferArrayStream body(raw.get()); - - // *NOTE: The order seems to matter. - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"status\"\r\n\r\n" - << status << "\r\n"; - - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n" - << "Content-Type: image/" << imageFormat << "\r\n\r\n"; - - // Insert the image data. - // *FIX: Treating this as a string will probably screw it up ... - U8* image_data = image->getData(); - for (S32 i = 0; i < image->getDataSize(); ++i) - { - body << image_data[i]; - } - - body << "\r\n--" << boundary << "--\r\n"; - - LLSD result = httpAdapter->postAndSuspend(httpRequest, getTwitterConnectURL("/share/photo", true), raw, httpOpts, httpHeaders); - - if (testShareStatus(result)) - { - toast_user_for_twitter_success(); - LL_DEBUGS("TwitterConnect") << "Post successful. " << LL_ENDL; - setConnectionState(LLTwitterConnect::TWITTER_POSTED); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// -void LLTwitterConnect::twitterDisconnectCoro() -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - - httpOpts->setFollowRedirects(false); - - LLSD result = httpAdapter->deleteAndSuspend(httpRequest, getTwitterConnectURL("/connection"), httpOpts); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (!status && (status != LLCore::HttpStatus(HTTP_NOT_FOUND))) - { - LL_WARNS("TwitterConnect") << "Disconnect failed!" << LL_ENDL; - setConnectionState(LLTwitterConnect::TWITTER_DISCONNECT_FAILED); - - log_twitter_connect_error("Disconnect", status.getStatus(), status.toString(), - result.get("error_code"), result.get("error_description")); - } - else - { - LL_DEBUGS("TwitterConnect") << "Disconnect successful. " << LL_ENDL; - clearInfo(); - setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// -void LLTwitterConnect::twitterConnectedCoro(bool autoConnect) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - - httpOpts->setFollowRedirects(false); - setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS); - - LLSD result = httpAdapter->getAndSuspend(httpRequest, getTwitterConnectURL("/connection", true), httpOpts); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (!status) - { - if (status == LLCore::HttpStatus(HTTP_NOT_FOUND)) - { - LL_DEBUGS("TwitterConnect") << "Not connected. " << LL_ENDL; - if (autoConnect) - { - connectToTwitter(); - } - else - { - setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED); - } - } - else - { - LL_WARNS("TwitterConnect") << "Failed to test connection:" << status.toTerseString() << LL_ENDL; - - setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED); - log_twitter_connect_error("Connected", status.getStatus(), status.toString(), - result.get("error_code"), result.get("error_description")); - } - } - else - { - LL_DEBUGS("TwitterConnect") << "Connect successful. " << LL_ENDL; - setConnectionState(LLTwitterConnect::TWITTER_CONNECTED); - } - -} - -/////////////////////////////////////////////////////////////////////////////// -// -void LLTwitterConnect::twitterInfoCoro() -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - - httpOpts->setWantHeaders(true); - httpOpts->setFollowRedirects(false); - - LLSD result = httpAdapter->getAndSuspend(httpRequest, getTwitterConnectURL("/info", true), httpOpts); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (status == LLCore::HttpStatus(HTTP_FOUND)) - { - std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; - if (location.empty()) - { - LL_WARNS("TwitterConnect") << "Missing Location header " << LL_ENDL; - } - else - { - openTwitterWeb(location); - } - } - else if (!status) - { - LL_WARNS("TwitterConnect") << "Twitter Info failed: " << status.toString() << LL_ENDL; - log_twitter_connect_error("Info", status.getStatus(), status.toString(), - result.get("error_code"), result.get("error_description")); - } - else - { - LL_INFOS("TwitterConnect") << "Twitter: Info received" << LL_ENDL; - result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); - storeInfo(result); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// -LLTwitterConnect::LLTwitterConnect() -: mConnectionState(TWITTER_NOT_CONNECTED), - mConnected(false), - mInfo(), - mRefreshInfo(false), - mReadFromMaster(false) -{ -} - -void LLTwitterConnect::openTwitterWeb(std::string url) -{ - LLFloaterWebContent::Params p; - p.url(url); - p.show_chrome(true); - p.allow_back_forward_navigation(false); - p.clean_browser(true); - LLFloater *floater = LLFloaterReg::showInstance("twitter_web", p); - //the internal web browser has a bug that prevents it from gaining focus unless a mouse event occurs first (it seems). - //So when showing the internal web browser, set focus to it's containing floater "twitter_web". When a mouse event - //occurs on the "webbrowser" panel part of the floater, a mouse cursor will properly show and the "webbrowser" will gain focus. - //twitter_web floater contains the "webbrowser" panel. JIRA: ACME-744 - gFocusMgr.setKeyboardFocus( floater ); - - //LLUrlAction::openURLExternal(url); -} - -std::string LLTwitterConnect::getTwitterConnectURL(const std::string& route, bool include_read_from_master) -{ - std::string url(""); - LLViewerRegion *regionp = gAgent.getRegion(); - if (regionp) - { - //url = "http://pdp15.lindenlab.com/twitter/agent/" + gAgentID.asString(); // TEMPORARY FOR TESTING - CHO - url = regionp->getCapability("TwitterConnect"); - url += route; - - if (include_read_from_master && mReadFromMaster) - { - url += "?read_from_master=true"; - } - } - return url; -} - -void LLTwitterConnect::connectToTwitter(const std::string& request_token, const std::string& oauth_verifier) -{ - setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS); - - LLCoros::instance().launch("LLTwitterConnect::twitterConnectCoro", - boost::bind(&LLTwitterConnect::twitterConnectCoro, this, request_token, oauth_verifier)); -} - -void LLTwitterConnect::disconnectFromTwitter() -{ - setConnectionState(LLTwitterConnect::TWITTER_DISCONNECTING); - - LLCoros::instance().launch("LLTwitterConnect::twitterDisconnectCoro", - boost::bind(&LLTwitterConnect::twitterDisconnectCoro, this)); -} - -void LLTwitterConnect::checkConnectionToTwitter(bool auto_connect) -{ - LLCoros::instance().launch("LLTwitterConnect::twitterConnectedCoro", - boost::bind(&LLTwitterConnect::twitterConnectedCoro, this, auto_connect)); -} - -void LLTwitterConnect::loadTwitterInfo() -{ - if(mRefreshInfo) - { - LLCoros::instance().launch("LLTwitterConnect::twitterInfoCoro", - boost::bind(&LLTwitterConnect::twitterInfoCoro, this)); - } -} - -void LLTwitterConnect::uploadPhoto(const std::string& image_url, const std::string& status) -{ - LLSD body; - body["image"] = image_url; - body["status"] = status; - - setConnectionState(LLTwitterConnect::TWITTER_POSTING); - - LLCoros::instance().launch("LLTwitterConnect::twitterShareCoro", - boost::bind(&LLTwitterConnect::twitterShareCoro, this, "/share/photo", body)); -} - -void LLTwitterConnect::uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& status) -{ - setConnectionState(LLTwitterConnect::TWITTER_POSTING); - - LLCoros::instance().launch("LLTwitterConnect::twitterShareImageCoro", - boost::bind(&LLTwitterConnect::twitterShareImageCoro, this, image, status)); -} - -void LLTwitterConnect::updateStatus(const std::string& status) -{ - LLSD body; - body["status"] = status; - - setConnectionState(LLTwitterConnect::TWITTER_POSTING); - - LLCoros::instance().launch("LLTwitterConnect::twitterShareCoro", - boost::bind(&LLTwitterConnect::twitterShareCoro, this, "/share/status", body)); -} - -void LLTwitterConnect::storeInfo(const LLSD& info) -{ - mInfo = info; - mRefreshInfo = false; - - sInfoWatcher->post(info); -} - -const LLSD& LLTwitterConnect::getInfo() const -{ - return mInfo; -} - -void LLTwitterConnect::clearInfo() -{ - mInfo = LLSD(); -} - -void LLTwitterConnect::setDataDirty() -{ - mRefreshInfo = true; -} - -void LLTwitterConnect::setConnectionState(LLTwitterConnect::EConnectionState connection_state) -{ - if(connection_state == TWITTER_CONNECTED) - { - mReadFromMaster = true; - setConnected(true); - setDataDirty(); - } - else if(connection_state == TWITTER_NOT_CONNECTED) - { - setConnected(false); - } - else if(connection_state == TWITTER_POSTED) - { - mReadFromMaster = false; - } - - if (mConnectionState != connection_state) - { - // set the connection state before notifying watchers - mConnectionState = connection_state; - - LLSD state_info; - state_info["enum"] = connection_state; - sStateWatcher->post(state_info); - } -} - -void LLTwitterConnect::setConnected(bool connected) -{ - mConnected = connected; -} diff --git a/indra/newview/lltwitterconnect.h b/indra/newview/lltwitterconnect.h deleted file mode 100644 index e77048cc35..0000000000 --- a/indra/newview/lltwitterconnect.h +++ /dev/null @@ -1,107 +0,0 @@ -/** - * @file lltwitterconnect.h - * @author Merov, Cho - * @brief Connection to Twitter 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_LLTWITTERCONNECT_H -#define LL_LLTWITTERCONNECT_H - -#include "llsingleton.h" -#include "llimage.h" -#include "llcoros.h" -#include "lleventcoro.h" - -class LLEventPump; - -/** - * @class LLTwitterConnect - * - * Manages authentication to, and interaction with, a web service allowing the - * the viewer to post status updates and upload photos to Twitter. - */ -class LLTwitterConnect : public LLSingleton<LLTwitterConnect> -{ - LLSINGLETON(LLTwitterConnect); - LOG_CLASS(LLTwitterConnect); -public: - enum EConnectionState - { - TWITTER_NOT_CONNECTED = 0, - TWITTER_CONNECTION_IN_PROGRESS = 1, - TWITTER_CONNECTED = 2, - TWITTER_CONNECTION_FAILED = 3, - TWITTER_POSTING = 4, - TWITTER_POSTED = 5, - TWITTER_POST_FAILED = 6, - TWITTER_DISCONNECTING = 7, - TWITTER_DISCONNECT_FAILED = 8 - }; - - void connectToTwitter(const std::string& request_token = "", const std::string& oauth_verifier = ""); // Initiate the complete Twitter connection. Please use checkConnectionToTwitter() in normal use. - void disconnectFromTwitter(); // Disconnect from the Twitter service. - void checkConnectionToTwitter(bool auto_connect = false); // Check if an access token is available on the Twitter service. If not, call connectToTwitter(). - - void loadTwitterInfo(); - void uploadPhoto(const std::string& image_url, const std::string& status); - void uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& status); - void updateStatus(const std::string& status); - - void storeInfo(const LLSD& info); - const LLSD& getInfo() const; - void clearInfo(); - void setDataDirty(); - - void setConnectionState(EConnectionState connection_state); - void setConnected(bool connected); - bool isConnected() { return mConnected; } - bool isTransactionOngoing() { return ((mConnectionState == TWITTER_CONNECTION_IN_PROGRESS) || (mConnectionState == TWITTER_POSTING) || (mConnectionState == TWITTER_DISCONNECTING)); } - EConnectionState getConnectionState() { return mConnectionState; } - - void openTwitterWeb(std::string url); - -private: - - std::string getTwitterConnectURL(const std::string& route = "", bool include_read_from_master = false); - - EConnectionState mConnectionState; - BOOL mConnected; - LLSD mInfo; - bool mRefreshInfo; - bool mReadFromMaster; - - static boost::scoped_ptr<LLEventPump> sStateWatcher; - static boost::scoped_ptr<LLEventPump> sInfoWatcher; - static boost::scoped_ptr<LLEventPump> sContentWatcher; - - bool testShareStatus(LLSD &result); - void twitterConnectCoro(std::string requestToken, std::string oauthVerifier); - void twitterDisconnectCoro(); - void twitterConnectedCoro(bool autoConnect); - void twitterInfoCoro(); - void twitterShareCoro(std::string route, LLSD share); - void twitterShareImageCoro(LLPointer<LLImageFormatted> image, std::string status); -}; - -#endif // LL_LLTWITTERCONNECT_H diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index 6b2cd71d40..956f5cf187 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -84,8 +84,8 @@ void LLUIListener::getValue(const LLSD&event) const { LLSD reply = LLSD::emptyMap(); - const LLView* root = LLUI::getRootView(); - const LLView* view = LLUI::resolvePath(root, event["path"].asString()); + const LLView* root = LLUI::getInstance()->getRootView(); + const LLView* view = LLUI::getInstance()->resolvePath(root, event["path"].asString()); const LLUICtrl* ctrl(dynamic_cast<const LLUICtrl*>(view)); if (ctrl) diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h index 15c3dad38e..77e950a1c9 100644 --- a/indra/newview/lluploadfloaterobservers.h +++ b/indra/newview/lluploadfloaterobservers.h @@ -53,7 +53,7 @@ public: virtual ~LLWholeModelFeeObserver() {} virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0; - virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) = 0; + virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason, const LLSD& result) = 0; LLHandle<LLWholeModelFeeObserver> getWholeModelFeeObserverHandle() const { return mWholeModelFeeObserverHandle; } diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp index da31e4f542..a1670351f4 100644 --- a/indra/newview/llurldispatcher.cpp +++ b/indra/newview/llurldispatcher.cpp @@ -188,7 +188,7 @@ bool LLURLDispatcherImpl::dispatchRegion(const LLSLURL& slurl, const std::string LLWorldMapMessage::getInstance()->sendNamedRegionRequest(slurl.getRegion(), LLURLDispatcherImpl::regionNameCallback, slurl.getSLURLString(), - LLUI::sSettingGroups["config"]->getBOOL("SLURLTeleportDirectly")); // don't teleport + LLUI::getInstance()->mSettingGroups["config"]->getBOOL("SLURLTeleportDirectly")); // don't teleport return true; } diff --git a/indra/newview/llurlfloaterdispatchhandler.cpp b/indra/newview/llurlfloaterdispatchhandler.cpp new file mode 100644 index 0000000000..6b1a373beb --- /dev/null +++ b/indra/newview/llurlfloaterdispatchhandler.cpp @@ -0,0 +1,214 @@ +/** + * @file llurlfloaterdispatchhandler.cpp + * @brief Handles URLFloater generic message from server + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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 "llurlfloaterdispatchhandler.h" + +#include "llfloaterreg.h" +#include "llfloaterhowto.h" +#include "llfloaterwebcontent.h" +#include "llsdserialize.h" +#include "llviewercontrol.h" +#include "llviewergenericmessage.h" +#include "llweb.h" + +// Example: +// llOpenFloater("guidebook", "http://page.com", []); + +// values specified by server side's dispatcher +// for llopenfloater +const std::string MESSAGE_URL_FLOATER("URLFloater"); +const std::string KEY_ACTION("action"); // "action" will be the string constant "OpenURL" +const std::string VALUE_OPEN_URL("OpenURL"); +const std::string KEY_DATA("action_data"); +const std::string KEY_FLOATER("floater_title"); // name of the floater, not title +const std::string KEY_URL("floater_url"); +const std::string KEY_PARAMS("floater_params"); + +// Supported floaters +const std::string FLOATER_GUIDEBOOK("guidebook"); +const std::string FLOATER_HOW_TO("how_to"); // alias for guidebook +const std::string FLOATER_WEB_CONTENT("web_content"); + +// All arguments are palceholders! Server side will need to add validation first. +// Web content universal argument +const std::string KEY_TRUSTED_CONTENT("trusted_content"); + +// Guidebook specific arguments +const std::string KEY_WIDTH("width"); +const std::string KEY_HEGHT("height"); +const std::string KEY_CAN_CLOSE("can_close"); +const std::string KEY_TITLE("title"); + +// web_content specific arguments +const std::string KEY_SHOW_PAGE_TITLE("show_page_title"); +const std::string KEY_ALLOW_ADRESS_ENTRY("allow_address_entry"); // It is not recomended to set this to true if trusted content is allowed + + +LLUrlFloaterDispatchHandler LLUrlFloaterDispatchHandler::sUrlDispatchhandler; + +LLUrlFloaterDispatchHandler::LLUrlFloaterDispatchHandler() +{ +} + +LLUrlFloaterDispatchHandler::~LLUrlFloaterDispatchHandler() +{ +} + +void LLUrlFloaterDispatchHandler::registerInDispatcher() +{ + if (!gGenericDispatcher.isHandlerPresent(MESSAGE_URL_FLOATER)) + { + gGenericDispatcher.addHandler(MESSAGE_URL_FLOATER, &sUrlDispatchhandler); + } +} + +//virtual +bool LLUrlFloaterDispatchHandler::operator()(const LLDispatcher *, const std::string& key, const LLUUID& invoice, const sparam_t& strings) +{ + // invoice - transaction id + + 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("URLFloater") << "Attempted to read parameter data into LLSD but failed:" << llsdRaw << LL_ENDL; + return false; + } + } + + // At the moment command_params is a placeholder and code treats it as map + // Once server side adds argument validation this will be either a map or an array + std::string floater; + LLSD command_params; + std::string url; + + if (message.has(KEY_ACTION) && message[KEY_ACTION].asString() == VALUE_OPEN_URL) + { + LLSD &action_data = message[KEY_DATA]; + if (action_data.isMap()) + { + floater = action_data[KEY_FLOATER].asString(); + command_params = action_data[KEY_PARAMS]; + url = action_data[KEY_URL].asString(); + } + } + else if (message.has(KEY_FLOATER)) + { + floater = message[KEY_FLOATER].asString(); + command_params = message[KEY_PARAMS]; + url = message[KEY_URL].asString(); + } + else + { + LL_WARNS("URLFloater") << "Received " << MESSAGE_URL_FLOATER << " with unexpected data format: " << message << LL_ENDL; + return false; + } + + if (url.find("://") == std::string::npos) + { + // try unescaping + url = LLURI::unescape(url); + } + + LLFloaterWebContent::Params params; + params.url = url; + + if (floater == FLOATER_GUIDEBOOK || floater == FLOATER_HOW_TO) + { + LL_DEBUGS("URLFloater") << "Opening how_to floater with parameters: " << message << LL_ENDL; + if (command_params.isMap()) // by default is undefines + { + params.trusted_content = command_params.has(KEY_TRUSTED_CONTENT) ? command_params[KEY_TRUSTED_CONTENT].asBoolean() : false; + + // Script's side argument list can't include other lists, neither + // there is a LLRect type, so expect just width and height + if (command_params.has(KEY_WIDTH) && command_params.has(KEY_HEGHT)) + { + LLRect rect(0, command_params[KEY_HEGHT].asInteger(), command_params[KEY_WIDTH].asInteger(), 0); + params.preferred_media_size.setValue(rect); + } + } + + // Some locations will have customized guidebook, which this function easists for + // only one instance of guidebook can exist at a time, so if this command arrives, + // we need to close previous guidebook then reopen it. + + LLFloater* instance = LLFloaterReg::findInstance("guidebook"); + if (instance) + { + instance->closeHostedFloater(); + } + + LLFloaterReg::toggleInstanceOrBringToFront("guidebook", params); + + if (command_params.isMap()) + { + LLFloater* instance = LLFloaterReg::findInstance("guidebook"); + if (command_params.has(KEY_CAN_CLOSE)) + { + instance->setCanClose(command_params[KEY_CAN_CLOSE].asBoolean()); + } + if (command_params.has(KEY_TITLE)) + { + instance->setTitle(command_params[KEY_TITLE].asString()); + } + } + } + else if (floater == FLOATER_WEB_CONTENT) + { + LL_DEBUGS("URLFloater") << "Opening web_content floater with parameters: " << message << LL_ENDL; + if (command_params.isMap()) // by default is undefines, might be better idea to init params from command_params + { + params.trusted_content = command_params.has(KEY_TRUSTED_CONTENT) ? command_params[KEY_TRUSTED_CONTENT].asBoolean() : false; + params.show_page_title = command_params.has(KEY_SHOW_PAGE_TITLE) ? command_params[KEY_SHOW_PAGE_TITLE].asBoolean() : true; + params.allow_address_entry = command_params.has(KEY_ALLOW_ADRESS_ENTRY) ? command_params[KEY_ALLOW_ADRESS_ENTRY].asBoolean() : true; + } + LLFloaterReg::showInstance("web_content", params); + } + else + { + LL_DEBUGS("URLFloater") << "Unknow floater with parameters: " << message << LL_ENDL; + if (LLFloaterReg::isRegistered(floater)) + { + // A valid floater + LL_INFOS("URLFloater") << "Floater " << floater << " is not supported by llopenfloater or URLFloater" << LL_ENDL; + } + else + { + // A valid message, but no such flaoter + LL_WARNS("URLFloater") << "Recieved a command to open unknown floater: " << floater << LL_ENDL; + } + } + + return true; +} diff --git a/indra/newview/llurlfloaterdispatchhandler.h b/indra/newview/llurlfloaterdispatchhandler.h new file mode 100644 index 0000000000..1dff52c66f --- /dev/null +++ b/indra/newview/llurlfloaterdispatchhandler.h @@ -0,0 +1,49 @@ +/** + * @file llurlfloaterdispatchhandler.h + * @brief Handles URLFloater generic message from server + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * 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_LLURLFLOATERDISPATCHHANDLER_H +#define LL_LLURLFLOATERDISPATCHHANDLER_H + +#include "lldispatcher.h" + +class LLUrlFloaterDispatchHandler : public LLDispatchHandler +{ +public: + LOG_CLASS(LLUrlFloaterDispatchHandler); + + LLUrlFloaterDispatchHandler(); + virtual ~LLUrlFloaterDispatchHandler(); + + virtual bool operator()(const LLDispatcher *, const std::string& key, const LLUUID& invoice, const sparam_t& strings) override; + + static void registerInDispatcher(); + +private: + static LLUrlFloaterDispatchHandler sUrlDispatchhandler; +}; + +#endif // LL_LLURLFLOATERDISPATCHHANDLER_H + diff --git a/indra/newview/llurllineeditorctrl.cpp b/indra/newview/llurllineeditorctrl.cpp index 8a61114852..2b7e598a59 100644 --- a/indra/newview/llurllineeditorctrl.cpp +++ b/indra/newview/llurllineeditorctrl.cpp @@ -66,7 +66,7 @@ void LLURLLineEditor::cut() if( need_to_rollback ) { rollback.doRollback( this ); - LLUI::reportBadKeystroke(); + LLUI::getInstance()->reportBadKeystroke(); } else if( mKeystrokeCallback ) diff --git a/indra/newview/llurlwhitelist.cpp b/indra/newview/llurlwhitelist.cpp index 3a7285974e..b4d38f5d1e 100644 --- a/indra/newview/llurlwhitelist.cpp +++ b/indra/newview/llurlwhitelist.cpp @@ -31,8 +31,6 @@ #include <iostream> #include <fstream> -LLUrlWhiteList* LLUrlWhiteList::sInstance = 0; - /////////////////////////////////////////////////////////////////////////////// // LLUrlWhiteList::LLUrlWhiteList () : @@ -50,29 +48,6 @@ LLUrlWhiteList::~LLUrlWhiteList () } /////////////////////////////////////////////////////////////////////////////// - -//static -void LLUrlWhiteList::initClass () -{ - if ( ! sInstance ) - { - sInstance = new LLUrlWhiteList (); - } -} - -//static -void LLUrlWhiteList::cleanupClass () -{ - delete sInstance; - sInstance = NULL; -} - -LLUrlWhiteList* LLUrlWhiteList::getInstance () -{ - return sInstance; -} - -/////////////////////////////////////////////////////////////////////////////// // bool LLUrlWhiteList::load () { diff --git a/indra/newview/llurlwhitelist.h b/indra/newview/llurlwhitelist.h index b0969051a7..c2511b08fd 100644 --- a/indra/newview/llurlwhitelist.h +++ b/indra/newview/llurlwhitelist.h @@ -30,15 +30,11 @@ #include <list> -class LLUrlWhiteList +class LLUrlWhiteList : public LLSingleton<LLUrlWhiteList> { + LLSINGLETON(LLUrlWhiteList); + ~LLUrlWhiteList(); public: - virtual ~LLUrlWhiteList (); - - static void initClass(); - static void cleanupClass(); - static LLUrlWhiteList* getInstance (); - bool load (); bool save (); @@ -51,9 +47,6 @@ class LLUrlWhiteList bool getNext ( std::string& valueOut ); private: - LLUrlWhiteList (); - static LLUrlWhiteList* sInstance; - typedef std::vector < std::string > string_list_t ; bool mLoaded; diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp index 4e07223784..4720a989b0 100644 --- a/indra/newview/llversioninfo.cpp +++ b/indra/newview/llversioninfo.cpp @@ -26,9 +26,10 @@ */ #include "llviewerprecompiledheaders.h" -#include <iostream> -#include <sstream> +#include "llevents.h" +#include "lleventfilter.h" #include "llversioninfo.h" +#include "stringize.h" #include <boost/regex.hpp> #if ! defined(LL_VIEWER_CHANNEL) \ @@ -43,100 +44,90 @@ // Set the version numbers in indra/VIEWER_VERSION // -//static +LLVersionInfo::LLVersionInfo(): + short_version(STRINGIZE(LL_VIEWER_VERSION_MAJOR << "." + << LL_VIEWER_VERSION_MINOR << "." + << LL_VIEWER_VERSION_PATCH)), + // LL_VIEWER_CHANNEL is a macro defined on the compiler command line. The + // macro expands to the string name of the channel, but without quotes. We + // need to turn it into a quoted string. LL_TO_STRING() does that. + mWorkingChannelName(LL_TO_STRING(LL_VIEWER_CHANNEL)), + build_configuration(LLBUILD_CONFIG), // set in indra/cmake/BuildVersion.cmake + // instantiate an LLEventMailDrop with canonical name to listen for news + // from SLVersionChecker + mPump{new LLEventMailDrop("relnotes")}, + // immediately listen on mPump, store arriving URL into mReleaseNotes + mStore{new LLStoreListener<std::string>(*mPump, mReleaseNotes)} +{ +} + +void LLVersionInfo::initSingleton() +{ + // We override initSingleton() not because we have dependencies on other + // LLSingletons, but because certain initializations call other member + // functions. We should refrain from calling methods until this object is + // fully constructed; such calls don't really belong in the constructor. + + // cache the version string + version = STRINGIZE(getShortVersion() << "." << getBuild()); +} + +LLVersionInfo::~LLVersionInfo() +{ +} + 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() +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() +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 -{ - // LL_VIEWER_CHANNEL is a macro defined on the compiler command line. The - // macro expands to the string name of the channel, but without quotes. We - // need to turn it into a quoted string. LL_TO_STRING() does that. - /// 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_TO_STRING(LL_VIEWER_CHANNEL)); - - // Storage for the "version and channel" string. - // This will get reset too. - std::string sVersionChannel(""); -} - -//static -const std::string &LLVersionInfo::getChannelAndVersion() +std::string LLVersionInfo::getChannelAndVersion() { - if (sVersionChannel.empty()) + if (mVersionChannel.empty()) { // cache the version string - sVersionChannel = LLVersionInfo::getChannel() + " " + LLVersionInfo::getVersion(); + mVersionChannel = getChannel() + " " + getVersion(); } - return sVersionChannel; + return mVersionChannel; } -//static -const std::string &LLVersionInfo::getChannel() +std::string LLVersionInfo::getChannel() { - return sWorkingChannelName; + return mWorkingChannelName; } void LLVersionInfo::resetChannel(const std::string& channel) { - sWorkingChannelName = channel; - sVersionChannel.clear(); // Reset version and channel string til next use. + mWorkingChannelName = channel; + mVersionChannel.clear(); // Reset version and channel string til next use. } -//static LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity() { ViewerMaturity maturity; @@ -175,8 +166,12 @@ LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity() } -const std::string &LLVersionInfo::getBuildConfig() +std::string LLVersionInfo::getBuildConfig() { - static const std::string build_configuration(LLBUILD_CONFIG); // set in indra/cmake/BuildVersion.cmake return build_configuration; } + +std::string LLVersionInfo::getReleaseNotes() +{ + return mReleaseNotes; +} diff --git a/indra/newview/llversioninfo.h b/indra/newview/llversioninfo.h index b8b4341385..02ff0c094a 100644 --- a/indra/newview/llversioninfo.h +++ b/indra/newview/llversioninfo.h @@ -28,8 +28,14 @@ #ifndef LL_LLVERSIONINFO_H #define LL_LLVERSIONINFO_H -#include <string> #include "stdtypes.h" +#include "llsingleton.h" +#include <string> +#include <memory> + +class LLEventMailDrop; +template <typename T> +class LLStoreListener; /// /// This API provides version information for the viewer. This @@ -38,42 +44,46 @@ /// viewer code that wants to query the current version should /// use this API. /// -class LLVersionInfo +class LLVersionInfo: public LLSingleton<LLVersionInfo> { + LLSINGLETON(LLVersionInfo); + void initSingleton(); public: - /// return the major verion number as an integer - static S32 getMajor(); + ~LLVersionInfo(); - /// return the minor verion number as an integer - static S32 getMinor(); + /// return the major version number as an integer + S32 getMajor(); - /// return the patch verion number as an integer - static S32 getPatch(); + /// return the minor version number as an integer + S32 getMinor(); + + /// return the patch version number as an integer + S32 getPatch(); /// return the build number as an integer - static S32 getBuild(); + S32 getBuild(); /// return the full viewer version as a string like "2.0.0.200030" - static const std::string &getVersion(); + std::string getVersion(); /// return the viewer version as a string like "2.0.0" - static const std::string &getShortVersion(); + 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(); + std::string getChannelAndVersion(); /// return the channel name, e.g. "Second Life" - static const std::string &getChannel(); + std::string getChannel(); /// return the CMake build type - static const std::string &getBuildConfig(); + std::string getBuildConfig(); /// reset the channel name used by the viewer. - static void resetChannel(const std::string& channel); + void resetChannel(const std::string& channel); /// return the bit width of an address - static const S32 getAddressSize() { return ADDRESS_SIZE; } + S32 getAddressSize() { return ADDRESS_SIZE; } typedef enum { @@ -82,7 +92,31 @@ public: BETA_VIEWER, RELEASE_VIEWER } ViewerMaturity; - static ViewerMaturity getViewerMaturity(); + ViewerMaturity getViewerMaturity(); + + /// get the release-notes URL, once it becomes available -- until then, + /// return empty string + std::string getReleaseNotes(); + +private: + std::string version; + std::string short_version; + /// Storage of the channel name the viewer is using. + // The channel name is set by hardcoded constant, + // or by calling resetChannel() + std::string mWorkingChannelName; + // Storage for the "version and channel" string. + // This will get reset too. + std::string mVersionChannel; + std::string build_configuration; + std::string mReleaseNotes; + // Store unique_ptrs to the next couple things so we don't have to explain + // to every consumer of this header file all the details of each. + // mPump is the LLEventMailDrop on which we listen for SLVersionChecker to + // post the release-notes URL from the Viewer Version Manager. + std::unique_ptr<LLEventMailDrop> mPump; + // mStore is an adapter that stores the release-notes URL in mReleaseNotes. + std::unique_ptr<LLStoreListener<std::string>> mStore; }; #endif diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index e0b64403ef..c1b129750a 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -49,6 +49,9 @@ /// LLViewerAssetRequest ///---------------------------------------------------------------------------- + // There is also PoolSizeAssetStorage value in setting that should mirror this name +static const std::string VIEWER_ASSET_STORAGE_CORO_POOL = "AssetStorage"; + /** * @brief Local class to encapsulate asset fetch requests with a timestamp. * @@ -112,6 +115,7 @@ LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager * mCountSucceeded(0), mTotalBytesFetched(0) { + LLCoprocedureManager::instance().initializePool(VIEWER_ASSET_STORAGE_CORO_POOL); } @@ -125,6 +129,24 @@ LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager * mCountSucceeded(0), mTotalBytesFetched(0) { + LLCoprocedureManager::instance().initializePool(VIEWER_ASSET_STORAGE_CORO_POOL); +} + +LLViewerAssetStorage::~LLViewerAssetStorage() +{ + if (!LLCoprocedureManager::wasDeleted()) + { + // This class has dedicated coroutine pool, clean it up, otherwise coroutines will crash later. + LLCoprocedureManager::instance().close(VIEWER_ASSET_STORAGE_CORO_POOL); + } + + while (mCoroWaitList.size() > 0) + { + CoroWaitList &request = mCoroWaitList.front(); + // Clean up pending downloads, delete request and trigger callbacks + removeAndCallbackPendingDownloads(request.mId, request.mType, request.mId, request.mType, LL_ERR_NOERR, LLExtStat::NONE); + mCoroWaitList.pop_front(); + } } // virtual @@ -168,7 +190,7 @@ void LLViewerAssetStorage::storeAssetData( delete req; if (callback) { - callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_VFS_CORRUPT); + callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_FAILED, LLExtStat::VFS_CORRUPT); } return; } @@ -209,7 +231,7 @@ void LLViewerAssetStorage::storeAssetData( if (callback) { - callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_VFS_CORRUPT); + callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LLExtStat::VFS_CORRUPT); } return; } @@ -236,7 +258,7 @@ void LLViewerAssetStorage::storeAssetData( 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) { - callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_NONEXISTENT_FILE); + callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LLExtStat::NONEXISTENT_FILE); } } } @@ -247,7 +269,7 @@ void LLViewerAssetStorage::storeAssetData( reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_NO_UPSTREAM, __FILE__, __LINE__, "No upstream provider" ); if (callback) { - callback(asset_id, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); + callback(asset_id, user_data, LL_ERR_CIRCUIT_GONE, LLExtStat::NO_UPSTREAM); } } } @@ -333,11 +355,32 @@ void LLViewerAssetStorage::storeAssetData( } if (callback) { - callback(asset_id, user_data, LL_ERR_CANNOT_OPEN_FILE, LL_EXSTAT_BLOCKED_FILE); + callback(asset_id, user_data, LL_ERR_CANNOT_OPEN_FILE, LLExtStat::BLOCKED_FILE); } } } +void LLViewerAssetStorage::checkForTimeouts() +{ + LLAssetStorage::checkForTimeouts(); + + // Restore requests + LLCoprocedureManager* manager = LLCoprocedureManager::getInstance(); + while (mCoroWaitList.size() > 0 + && manager->count(VIEWER_ASSET_STORAGE_CORO_POOL) < LLCoprocedureManager::DEFAULT_QUEUE_SIZE) + { + CoroWaitList &request = mCoroWaitList.front(); + + bool with_http = true; + bool is_temp = false; + LLViewerAssetStatsFF::record_enqueue(request.mType, with_http, is_temp); + + manager->enqueueCoprocedure(VIEWER_ASSET_STORAGE_CORO_POOL, "LLViewerAssetStorage::assetRequestCoro", + boost::bind(&LLViewerAssetStorage::assetRequestCoro, this, request.mRequest, request.mId, request.mType, request.mCallback, request.mUserData)); + + mCoroWaitList.pop_front(); + } +} /** * @brief Allocate and queue an asset fetch request for the viewer @@ -395,12 +438,20 @@ void LLViewerAssetStorage::queueRequestHttp( // This is the same as the current UDP logic - don't re-request a duplicate. if (!duplicate) { - bool with_http = true; - bool is_temp = false; - LLViewerAssetStatsFF::record_enqueue(atype, with_http, is_temp); + // Coroutine buffer has fixed size (synchronization buffer, so we have no alternatives), so buffer any request above limit + if (LLCoprocedureManager::instance().count(VIEWER_ASSET_STORAGE_CORO_POOL) < LLCoprocedureManager::DEFAULT_QUEUE_SIZE) + { + bool with_http = true; + bool is_temp = false; + LLViewerAssetStatsFF::record_enqueue(atype, with_http, is_temp); - LLCoprocedureManager::instance().enqueueCoprocedure("AssetStorage","LLViewerAssetStorage::assetRequestCoro", - boost::bind(&LLViewerAssetStorage::assetRequestCoro, this, req, uuid, atype, callback, user_data)); + LLCoprocedureManager::instance().enqueueCoprocedure(VIEWER_ASSET_STORAGE_CORO_POOL, "LLViewerAssetStorage::assetRequestCoro", + boost::bind(&LLViewerAssetStorage::assetRequestCoro, this, req, uuid, atype, callback, user_data)); + } + else + { + mCoroWaitList.emplace_back(req, uuid, atype, callback, user_data); + } } } @@ -444,13 +495,18 @@ void LLViewerAssetStorage::assetRequestCoro( mCountStarted++; S32 result_code = LL_ERR_NOERR; - LLExtStat ext_status = LL_EXSTAT_NONE; + LLExtStat ext_status = LLExtStat::NONE; + if (!gAssetStorage) + { + LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: asset storage no longer exists" << LL_ENDL; + return; + } if (!gAgent.getRegion()) { LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: no region set" << LL_ENDL; result_code = LL_ERR_ASSET_REQUEST_FAILED; - ext_status = LL_EXSTAT_NONE; + ext_status = LLExtStat::NONE; removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status); return; } @@ -475,7 +531,7 @@ void LLViewerAssetStorage::assetRequestCoro( { LL_WARNS_ONCE("ViewerAsset") << "asset request fails: caps received but no viewer asset cap found" << LL_ENDL; result_code = LL_ERR_ASSET_REQUEST_FAILED; - ext_status = LL_EXSTAT_NONE; + ext_status = LLExtStat::NONE; removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status); return; } @@ -490,7 +546,7 @@ void LLViewerAssetStorage::assetRequestCoro( LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts); - if (LLApp::isQuitting()) + if (LLApp::isExiting() || !gAssetStorage) { // Bail out if result arrives after shutdown has been started. return; @@ -504,7 +560,7 @@ void LLViewerAssetStorage::assetRequestCoro( { LL_DEBUGS("ViewerAsset") << "request failed, status " << status.toTerseString() << LL_ENDL; result_code = LL_ERR_ASSET_REQUEST_FAILED; - ext_status = LL_EXSTAT_NONE; + ext_status = LLExtStat::NONE; } else { @@ -530,13 +586,13 @@ void LLViewerAssetStorage::assetRequestCoro( // 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; + ext_status = LLExtStat::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; + ext_status = LLExtStat::VFS_CORRUPT; } else { @@ -548,7 +604,7 @@ void LLViewerAssetStorage::assetRequestCoro( // 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; + ext_status = LLExtStat::NONE; } } diff --git a/indra/newview/llviewerassetstorage.h b/indra/newview/llviewerassetstorage.h index 50131682e7..c1a5534b81 100644 --- a/indra/newview/llviewerassetstorage.h +++ b/indra/newview/llviewerassetstorage.h @@ -43,7 +43,9 @@ public: LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS *vfs, LLVFS *static_vfs); - virtual void storeAssetData( + ~LLViewerAssetStorage(); + + void storeAssetData( const LLTransactionID& tid, LLAssetType::EType atype, LLStoreAssetCallback callback, @@ -52,9 +54,9 @@ public: bool is_priority = false, bool store_local = false, bool user_waiting=FALSE, - F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT); - - virtual void storeAssetData( + F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT) override; + + void storeAssetData( const std::string& filename, const LLTransactionID& tid, LLAssetType::EType type, @@ -63,20 +65,21 @@ public: bool temp_file = false, bool is_priority = false, bool user_waiting=FALSE, - F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT); + F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT) override; + + void checkForTimeouts() override; protected: - // 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); + BOOL is_priority) override; void queueRequestHttp(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); @@ -86,13 +89,40 @@ protected: void assetRequestCoro(LLViewerAssetRequest *req, const LLUUID uuid, LLAssetType::EType atype, - void (*callback) (LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat), + LLGetAssetCallback callback, void *user_data); std::string getAssetURL(const std::string& cap_url, const LLUUID& uuid, LLAssetType::EType atype); - void logAssetStorageInfo(); - + void logAssetStorageInfo() override; + + // Asset storage works through coroutines and coroutines have limited queue capacity + // This class is meant to temporary store requests when fiber's queue is full + class CoroWaitList + { + public: + CoroWaitList(LLViewerAssetRequest *req, + const LLUUID& uuid, + LLAssetType::EType atype, + LLGetAssetCallback &callback, + void *user_data) + : mRequest(req), + mId(uuid), + mType(atype), + mCallback(callback), + mUserData(user_data) + { + } + + LLViewerAssetRequest* mRequest; + LLUUID mId; + LLAssetType::EType mType; + LLGetAssetCallback mCallback; + void *mUserData; + }; + typedef std::list<CoroWaitList> wait_list_t; + wait_list_t mCoroWaitList; + std::string mViewerAssetUrl; S32 mAssetCoroCount; S32 mCountRequests; diff --git a/indra/newview/llviewerassettype.cpp b/indra/newview/llviewerassettype.cpp index f07c14d01f..4804ef6ddc 100644 --- a/indra/newview/llviewerassettype.cpp +++ b/indra/newview/llviewerassettype.cpp @@ -87,6 +87,7 @@ LLViewerAssetDictionary::LLViewerAssetDictionary() addEntry(LLViewerAssetType::AT_UNKNOWN, new ViewerAssetEntry(DAD_NONE)); addEntry(LLViewerAssetType::AT_NONE, new ViewerAssetEntry(DAD_NONE)); + addEntry(LLViewerAssetType::AT_SETTINGS, new ViewerAssetEntry(DAD_SETTINGS)); }; EDragAndDropType LLViewerAssetType::lookupDragAndDropType(EType asset_type) diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index 97fbb8c601..bc07821ccd 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -36,7 +36,6 @@ #include "lluploaddialog.h" #include "llpreviewscript.h" #include "llnotificationsutil.h" -#include "lleconomy.h" #include "llagent.h" #include "llfloaterreg.h" #include "llfloatersnapshot.h" @@ -171,22 +170,6 @@ void LLResourceUploadInfo::logPreparedUpload() "Asset Type: " << LLAssetType::lookup(mAssetType) << LL_ENDL; } -S32 LLResourceUploadInfo::getEconomyUploadCost() -{ - // Update L$ and ownership credit information - // since it probably changed on the server - if (getAssetType() == LLAssetType::AT_TEXTURE || - getAssetType() == LLAssetType::AT_SOUND || - getAssetType() == LLAssetType::AT_ANIMATION || - getAssetType() == LLAssetType::AT_MESH) - { - return LLGlobalEconomy::instance().getPriceUpload(); - } - - return 0; -} - - LLUUID LLResourceUploadInfo::finishUpload(LLSD &result) { if (getFolderId().isNull()) @@ -323,6 +306,43 @@ std::string LLResourceUploadInfo::getDisplayName() const return (mName.empty()) ? mAssetId.asString() : mName; }; +bool LLResourceUploadInfo::findAssetTypeOfExtension(const std::string& exten, LLAssetType::EType& asset_type) +{ + U32 codec; + return findAssetTypeAndCodecOfExtension(exten, asset_type, codec, false); +} + +// static +bool LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(const std::string& exten, LLAssetType::EType& asset_type, U32& codec, bool bulk_upload) +{ + bool succ = false; + std::string exten_lc(exten); + LLStringUtil::toLower(exten_lc); + codec = LLImageBase::getCodecFromExtension(exten_lc); + if (codec != IMG_CODEC_INVALID) + { + asset_type = LLAssetType::AT_TEXTURE; + succ = true; + } + else if (exten_lc == "wav") + { + asset_type = LLAssetType::AT_SOUND; + succ = true; + } + else if (exten_lc == "anim") + { + asset_type = LLAssetType::AT_ANIMATION; + succ = true; + } + else if (!bulk_upload && (exten_lc == "bvh")) + { + asset_type = LLAssetType::AT_ANIMATION; + succ = true; + } + + return succ; +} + //========================================================================= LLNewFileResourceUploadInfo::LLNewFileResourceUploadInfo( std::string fileName, @@ -360,9 +380,11 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() std::string filename = gDirUtilp->getTempFilename(); std::string exten = gDirUtilp->getExtension(getFileName()); - U32 codec = LLImageBase::getCodecFromExtension(exten); LLAssetType::EType assetType = LLAssetType::AT_NONE; + U32 codec = IMG_CODEC_INVALID; + bool found_type = findAssetTypeAndCodecOfExtension(exten, assetType, codec); + std::string errorMessage; std::string errorLabel; @@ -379,10 +401,16 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() errorLabel = "NoFileExtension"; error = true; } - else if (codec != IMG_CODEC_INVALID) + else if (!found_type) + { + // Unknown extension + errorMessage = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str()); + errorLabel = "ErrorMessage"; + error = TRUE;; + } + else if (assetType == LLAssetType::AT_TEXTURE) { // It's an image file, the upload procedure is the same for all - assetType = LLAssetType::AT_TEXTURE; if (!LLViewerTextureList::createUploadFile(getFileName(), filename, codec)) { errorMessage = llformat("Problem with file %s:\n\n%s\n", @@ -391,9 +419,8 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() error = true; } } - else if (exten == "wav") + else if (assetType == LLAssetType::AT_SOUND) { - assetType = LLAssetType::AT_SOUND; // tag it as audio S32 encodeResult = 0; LL_INFOS() << "Attempting to encode wav as an ogg file" << LL_ENDL; @@ -423,18 +450,10 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() errorLabel = "DoNotSupportBulkAnimationUpload"; error = true; } - else if (exten == "anim") + else if (assetType == LLAssetType::AT_ANIMATION) { - assetType = LLAssetType::AT_ANIMATION; filename = getFileName(); } - else - { - // Unknown extension - errorMessage = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str()); - errorLabel = "ErrorMessage"; - error = TRUE;; - } if (error) { @@ -487,7 +506,7 @@ LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID itemId, LLAssetType: mTaskId(LLUUID::null), mContents(buffer), mInvnFinishFn(finish), - mTaskFinishFn(NULL), + mTaskFinishFn(nullptr), mStoredToVFS(false) { setItemId(itemId); @@ -501,7 +520,7 @@ LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID itemId, LLPointer<LL mTaskId(LLUUID::null), mContents(), mInvnFinishFn(finish), - mTaskFinishFn(NULL), + mTaskFinishFn(nullptr), mStoredToVFS(false) { setItemId(itemId); @@ -534,7 +553,7 @@ LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID taskId, LLUUID itemI mTaskUpload(true), mTaskId(taskId), mContents(buffer), - mInvnFinishFn(NULL), + mInvnFinishFn(nullptr), mTaskFinishFn(finish), mStoredToVFS(false) { @@ -739,8 +758,12 @@ void LLViewerAssetUpload::AssetInventoryUploadCoproc(LLCoreHttpUtil::HttpCorouti LLUploadDialog::modalUploadFinished(); return; } + if (!result.has("success")) + { + result["success"] = LLSD::Boolean((ulstate == "complete") && status); + } - S32 uploadPrice = result["upload_price"].asInteger();//uploadInfo->getEconomyUploadCost(); + S32 uploadPrice = result["upload_price"].asInteger(); if (uploadPrice > 0) { diff --git a/indra/newview/llviewerassetupload.h b/indra/newview/llviewerassetupload.h index ee1806b782..d9eacf3167 100644 --- a/indra/newview/llviewerassetupload.h +++ b/indra/newview/llviewerassetupload.h @@ -40,7 +40,7 @@ class LLResourceUploadInfo { public: - typedef boost::shared_ptr<LLResourceUploadInfo> ptr_t; + typedef std::shared_ptr<LLResourceUploadInfo> ptr_t; LLResourceUploadInfo( LLTransactionID transactId, @@ -62,7 +62,6 @@ public: virtual LLSD prepareUpload(); virtual LLSD generatePostBody(); virtual void logPreparedUpload(); - virtual S32 getEconomyUploadCost(); virtual LLUUID finishUpload(LLSD &result); LLTransactionID getTransactionId() const { return mTransactionId; } @@ -88,6 +87,9 @@ public: LLUUID getItemId() const { return mItemId; } LLAssetID getAssetId() const { return mAssetId; } + static bool findAssetTypeOfExtension(const std::string& exten, LLAssetType::EType& asset_type); + static bool findAssetTypeAndCodecOfExtension(const std::string& exten, LLAssetType::EType& asset_type, U32& codec, bool bulk_upload = true); + protected: LLResourceUploadInfo( std::string name, @@ -169,8 +171,8 @@ private: class LLBufferedAssetUploadInfo : public LLResourceUploadInfo { public: - typedef boost::function<void(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD response)> invnUploadFinish_f; - typedef boost::function<void(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response)> taskUploadFinish_f; + typedef std::function<void(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD response)> invnUploadFinish_f; + typedef std::function<void(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response)> taskUploadFinish_f; LLBufferedAssetUploadInfo(LLUUID itemId, LLAssetType::EType assetType, std::string buffer, invnUploadFinish_f finish); LLBufferedAssetUploadInfo(LLUUID itemId, LLPointer<LLImageFormatted> image, invnUploadFinish_f finish); diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index 7ce9d858dd..cb20801756 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -463,24 +463,25 @@ void audio_update_volume(bool force_update) F32 media_volume = gSavedSettings.getF32("AudioLevelMedia"); BOOL media_muted = gSavedSettings.getBOOL("MuteMedia"); media_volume = mute_volume * master_volume * media_volume; - LLViewerMedia::setVolume( media_muted ? 0.0f : media_volume ); + LLViewerMedia::getInstance()->setVolume( media_muted ? 0.0f : media_volume ); - // Voice - if (LLVoiceClient::getInstance()) + // Voice, this is parametric singleton, it gets initialized when ready + if (LLVoiceClient::instanceExists()) { F32 voice_volume = gSavedSettings.getF32("AudioLevelVoice"); voice_volume = mute_volume * master_volume * voice_volume; BOOL voice_mute = gSavedSettings.getBOOL("MuteVoice"); - LLVoiceClient::getInstance()->setVoiceVolume(voice_mute ? 0.f : voice_volume); - LLVoiceClient::getInstance()->setMicGain(voice_mute ? 0.f : gSavedSettings.getF32("AudioLevelMic")); + LLVoiceClient *voice_inst = LLVoiceClient::getInstance(); + voice_inst->setVoiceVolume(voice_mute ? 0.f : voice_volume); + voice_inst->setMicGain(voice_mute ? 0.f : gSavedSettings.getF32("AudioLevelMic")); if (!gViewerWindow->getActive() && (gSavedSettings.getBOOL("MuteWhenMinimized"))) { - LLVoiceClient::getInstance()->setMuteMic(true); + voice_inst->setMuteMic(true); } else { - LLVoiceClient::getInstance()->setMuteMic(false); + voice_inst->setMuteMic(false); } } } diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index 778e275727..27a87ee1a0 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -81,31 +81,6 @@ glh::matrix4f gl_pick_matrix(GLfloat x, GLfloat y, GLfloat width, GLfloat height 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); - -} - // Build time optimization, generate this once in .cpp file template class LLViewerCamera* LLSingleton<class LLViewerCamera>::getInstance(); diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h index 5901de289f..fb07a3fb2d 100644 --- a/indra/newview/llviewercamera.h +++ b/indra/newview/llviewercamera.h @@ -35,14 +35,6 @@ #include "lltrace.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 }; - const BOOL FOR_SELECTION = TRUE; const BOOL NOT_FOR_SELECTION = FALSE; diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index a699491e1b..76dc9a6790 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -94,6 +94,7 @@ LLControlGroup gWarningSettings("Warnings"); // persists ignored dialogs/warning std::string gLastRunVersion; extern BOOL gResizeScreenTexture; +extern BOOL gResizeShadowTexture; extern BOOL gDebugGL; //////////////////////////////////////////////////////////////////////////// // Listeners @@ -186,10 +187,33 @@ static bool handleRenderPerfTestChanged(const LLSD& newvalue) bool handleRenderTransparentWaterChanged(const LLSD& newvalue) { + LLRenderTarget::sUseFBO = newvalue.asBoolean(); + if (gPipeline.isInit()) + { + gPipeline.updateRenderTransparentWater(); + gPipeline.updateRenderDeferred(); + gPipeline.releaseGLBuffers(); + gPipeline.createGLBuffers(); + gPipeline.resetVertexBuffers(); + LLViewerShaderMgr::instance()->setShaders(); + } LLWorld::getInstance()->updateWaterObjects(); return true; } + +static bool handleShadowsResized(const LLSD& newvalue) +{ + gPipeline.requestResizeShadowTexture(); + return true; +} + +static bool handleWindowResized(const LLSD& newvalue) +{ + gPipeline.requestResizeScreenTexture(); + return true; +} + static bool handleReleaseGLBufferChanged(const LLSD& newvalue) { if (gPipeline.isInit()) @@ -486,7 +510,10 @@ bool handleHighResSnapshotChanged(const LLSD& newvalue) bool handleVoiceClientPrefsChanged(const LLSD& newvalue) { - LLVoiceClient::getInstance()->updateSettings(); + if (LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->updateSettings(); + } return true; } @@ -608,15 +635,14 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderMaxTextureIndex")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderUseTriStrips")->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("RenderUIBuffer")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); + gSavedSettings.getControl("RenderUIBuffer")->getSignal()->connect(boost::bind(&handleWindowResized, _2)); gSavedSettings.getControl("RenderDepthOfField")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); gSavedSettings.getControl("RenderFSAASamples")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); gSavedSettings.getControl("RenderSpecularResX")->getSignal()->connect(boost::bind(&handleLUTBufferChanged, _2)); gSavedSettings.getControl("RenderSpecularResY")->getSignal()->connect(boost::bind(&handleLUTBufferChanged, _2)); gSavedSettings.getControl("RenderSpecularExponent")->getSignal()->connect(boost::bind(&handleLUTBufferChanged, _2)); gSavedSettings.getControl("RenderAnisotropic")->getSignal()->connect(boost::bind(&handleAnisotropicChanged, _2)); - gSavedSettings.getControl("RenderShadowResolutionScale")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); + gSavedSettings.getControl("RenderShadowResolutionScale")->getSignal()->connect(boost::bind(&handleShadowsResized, _2)); gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderGlowResolutionPow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); diff --git a/indra/newview/llviewercontrollistener.cpp b/indra/newview/llviewercontrollistener.cpp index d2484b2b23..3443bb644a 100644 --- a/indra/newview/llviewercontrollistener.cpp +++ b/indra/newview/llviewercontrollistener.cpp @@ -50,11 +50,9 @@ LLViewerControlListener::LLViewerControlListener() std::ostringstream groupnames; groupnames << "[\"group\"] is one of "; const char* delim = ""; - for (LLControlGroup::key_iter cgki(LLControlGroup::beginKeys()), - cgkend(LLControlGroup::endKeys()); - cgki != cgkend; ++cgki) + for (const auto& key : LLControlGroup::key_snapshot()) { - groupnames << delim << '"' << *cgki << '"'; + groupnames << delim << '"' << key << '"'; delim = ", "; } groupnames << '\n'; @@ -181,11 +179,9 @@ void LLViewerControlListener::groups(LLSD const & request) { // No Info, we're not looking up either a group or a control name. Response response(LLSD(), request); - for (LLControlGroup::key_iter cgki(LLControlGroup::beginKeys()), - cgkend(LLControlGroup::endKeys()); - cgki != cgkend; ++cgki) + for (const auto& key : LLControlGroup::key_snapshot()) { - response["groups"].append(*cgki); + response["groups"].append(key); } } diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 5924dbc260..109dc93261 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -74,11 +74,11 @@ #include "llviewerregion.h" #include "lldrawpoolwater.h" #include "lldrawpoolbump.h" -#include "llwlparammanager.h" -#include "llwaterparammanager.h" #include "llpostprocess.h" #include "llscenemonitor.h" +#include "llenvironment.h" + extern LLPointer<LLViewerTexture> gStartTexture; extern bool gShiftFrame; @@ -94,6 +94,7 @@ BOOL gForceRenderLandFence = FALSE; BOOL gDisplaySwapBuffers = FALSE; BOOL gDepthDirty = FALSE; BOOL gResizeScreenTexture = FALSE; +BOOL gResizeShadowTexture = FALSE; BOOL gWindowResized = FALSE; BOOL gSnapshot = FALSE; BOOL gShaderProfileFrame = FALSE; @@ -130,9 +131,6 @@ void display_startup() gPipeline.updateGL(); - // Update images? - //gImageList.updateImages(0.01f); - // Written as branch to appease GCC which doesn't like different // pointer types across ternary ops // @@ -153,6 +151,10 @@ void display_startup() { LLViewerDynamicTexture::updateAllInstances(); } + else + { + LL_DEBUGS("Window") << "First display_startup frame" << LL_ENDL; + } LLGLState::checkStates(); LLGLState::checkTextureChannels(); @@ -199,10 +201,6 @@ void display_update_camera() LLViewerCamera::getInstance()->setFar(final_far); gViewerWindow->setup3DRender(); - // update all the sky/atmospheric/water settings - LLWLParamManager::getInstance()->update(LLViewerCamera::getInstance()); - LLWaterParamManager::getInstance()->update(LLViewerCamera::getInstance()); - // Update land visibility too LLWorld::getInstance()->setLandFarClip(final_far); } @@ -250,6 +248,7 @@ static LLTrace::BlockTimerStatHandle FTM_HUD_UPDATE("HUD Update"); static LLTrace::BlockTimerStatHandle FTM_DISPLAY_UPDATE_GEOM("Update Geom"); static LLTrace::BlockTimerStatHandle FTM_TEXTURE_UNBIND("Texture Unbind"); static LLTrace::BlockTimerStatHandle FTM_TELEPORT_DISPLAY("Teleport Display"); +static LLTrace::BlockTimerStatHandle FTM_EEP_UPDATE("Env Update"); // Paint the display! void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) @@ -258,6 +257,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if (gWindowResized) { //skip render on frames where window has been resized + LL_DEBUGS("Window") << "Resizing window" << LL_ENDL; LL_RECORD_BLOCK_TIME(FTM_RESIZE_WINDOW); gGL.flush(); glClear(GL_COLOR_BUFFER_BIT); @@ -269,6 +269,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) return; } + if (gResizeShadowTexture) + { //skip render on frames where window has been resized + gPipeline.resizeShadowTexture(); + gResizeShadowTexture = FALSE; + } + if (LLPipeline::sRenderDeferred) { //hack to make sky show up in deferred snapshots for_snapshot = FALSE; @@ -417,6 +423,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if( (gAgent.getTeleportState() != LLAgent::TELEPORT_START) && (teleport_percent > 100.f) ) { // Give up. Don't keep the UI locked forever. + LL_WARNS("Teleport") << "Giving up on teleport. elapsed time " << teleport_elapsed << " exceeds max time " << teleport_save_time << LL_ENDL; gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); gAgent.setTeleportMessage(std::string()); } @@ -438,6 +445,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) gTeleportDisplayTimer.reset(); gViewerWindow->setShowProgress(TRUE); gViewerWindow->setProgressPercent(llmin(teleport_percent, 0.0f)); + LL_INFOS("Teleport") << "A teleport request has been sent, setting state to TELEPORT_REQUESTED" << LL_ENDL; gAgent.setTeleportState( LLAgent::TELEPORT_REQUESTED ); gAgent.setTeleportMessage( LLAgent::sTeleportProgressMessages["requesting"]); @@ -462,9 +470,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) gTeleportArrivalTimer.reset(); gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel")); gViewerWindow->setProgressPercent(75.f); + LL_INFOS("Teleport") << "Changing state to TELEPORT_ARRIVING" << LL_ENDL; gAgent.setTeleportState( LLAgent::TELEPORT_ARRIVING ); gAgent.setTeleportMessage( LLAgent::sTeleportProgressMessages["arriving"]); + gAgent.sheduleTeleportIM(); gTextureList.mForceResetTextureStats = TRUE; gAgentCamera.resetView(TRUE, TRUE); @@ -478,6 +488,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) { arrival_fraction = 1.f; //LLFirstUse::useTeleport(); + LL_INFOS("Teleport") << "arrival_fraction is " << arrival_fraction << " changing state to TELEPORT_NONE" << LL_ENDL; gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); } gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel")); @@ -493,6 +504,10 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if( gTeleportDisplayTimer.getElapsedTimeF32() > teleport_local_delay() ) { //LLFirstUse::useTeleport(); + LL_INFOS("Teleport") << "State is local and gTeleportDisplayTimer " << gTeleportDisplayTimer.getElapsedTimeF32() + << " exceeds teleport_local_delete " << teleport_local_delay + << "; setting state to TELEPORT_NONE" + << LL_ENDL; gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); } } @@ -569,7 +584,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if (gDisconnected) { LLAppViewer::instance()->pingMainloopTimeout("Display:Disconnected"); - LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); render_ui(); swap(); } @@ -634,6 +648,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) display_update_camera(); stop_glerror(); + { + LL_RECORD_BLOCK_TIME(FTM_EEP_UPDATE); + // update all the sky/atmospheric/water settings + LLEnvironment::instance().update(LLViewerCamera::getInstance()); + } + // *TODO: merge these two methods { LL_RECORD_BLOCK_TIME(FTM_HUD_UPDATE); @@ -656,7 +676,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) stop_glerror(); S32 water_clip = 0; - if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) && + if ((LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) && (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER) || gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER))) { @@ -699,9 +719,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLGLState::checkTextureChannels(); LLGLState::checkClientArrays(); - BOOL to_texture = gPipeline.canUseVertexShaders() && - LLPipeline::sRenderGlow; - LLAppViewer::instance()->pingMainloopTimeout("Display:Swap"); { @@ -732,18 +749,15 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLGLState::checkTextureChannels(); LLGLState::checkClientArrays(); - glh::matrix4f proj = glh_get_current_projection(); - glh::matrix4f mod = glh_get_current_modelview(); + glh::matrix4f proj = get_current_projection(); + glh::matrix4f mod = get_current_modelview(); glViewport(0,0,512,512); LLVOAvatar::updateFreezeCounter() ; - if(!LLPipeline::sMemAllocationThrottled) - { - LLVOAvatar::updateImpostors(); - } + LLVOAvatar::updateImpostors(); - glh_set_current_projection(proj); - glh_set_current_modelview(mod); + set_current_projection(proj); + set_current_modelview(mod); gGL.matrixMode(LLRender::MM_PROJECTION); gGL.loadMatrix(proj.m); gGL.matrixMode(LLRender::MM_MODELVIEW); @@ -901,38 +915,35 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) // gGL.popMatrix(); //} - LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater(); + LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE; LLGLState::checkStates(); LLGLState::checkClientArrays(); stop_glerror(); - if (to_texture) - { - gGL.setColorMask(true, true); - - if (LLPipeline::sRenderDeferred) - { - gPipeline.mDeferredScreen.bindTarget(); - glClearColor(1,0,1,1); - gPipeline.mDeferredScreen.clear(); - } - else - { - gPipeline.mScreen.bindTarget(); - if (LLPipeline::sUnderWaterRender && !gPipeline.canUseWindLightShaders()) - { - const LLColor4 &col = LLDrawPoolWater::sWaterFogColor; - glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f); - } - gPipeline.mScreen.clear(); - } - - gGL.setColorMask(true, false); - } - - LLAppViewer::instance()->pingMainloopTimeout("Display:RenderGeom"); + gGL.setColorMask(true, true); + + if (LLPipeline::sRenderDeferred) + { + gPipeline.mDeferredScreen.bindTarget(); + glClearColor(1, 0, 1, 1); + gPipeline.mDeferredScreen.clear(); + } + else + { + gPipeline.mScreen.bindTarget(); + if (LLPipeline::sUnderWaterRender && !gPipeline.canUseWindLightShaders()) + { + const LLColor4 &col = LLEnvironment::instance().getCurrentWater()->getWaterFogColor(); + glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f); + } + gPipeline.mScreen.clear(); + } + + gGL.setColorMask(true, false); + + LLAppViewer::instance()->pingMainloopTimeout("Display:RenderGeom"); if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot()) && !gRestoreGL) @@ -994,39 +1005,21 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) } } - LLAppViewer::instance()->pingMainloopTimeout("Display:RenderFlush"); - - if (to_texture) - { - if (LLPipeline::sRenderDeferred) - { - gPipeline.mDeferredScreen.flush(); - if(LLRenderTarget::sUseFBO) - { - LLRenderTarget::copyContentsToFramebuffer(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), - gPipeline.mDeferredScreen.getHeight(), 0, 0, - gPipeline.mDeferredScreen.getWidth(), - gPipeline.mDeferredScreen.getHeight(), - GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); - } - } - else - { - gPipeline.mScreen.flush(); - if(LLRenderTarget::sUseFBO) - { - LLRenderTarget::copyContentsToFramebuffer(gPipeline.mScreen, 0, 0, gPipeline.mScreen.getWidth(), - gPipeline.mScreen.getHeight(), 0, 0, - gPipeline.mScreen.getWidth(), - gPipeline.mScreen.getHeight(), - GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); - } - } - } + LLAppViewer::instance()->pingMainloopTimeout("Display:RenderFlush"); - if (LLPipeline::sRenderDeferred) - { - gPipeline.renderDeferredLighting(); + LLRenderTarget &rt = (gPipeline.sRenderDeferred ? gPipeline.mDeferredScreen : gPipeline.mScreen); + rt.flush(); + + if (rt.sUseFBO) + { + LLRenderTarget::copyContentsToFramebuffer(rt, 0, 0, rt.getWidth(), rt.getHeight(), 0, 0, rt.getWidth(), + rt.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, + GL_NEAREST); + } + + if (LLPipeline::sRenderDeferred) + { + gPipeline.renderDeferredLighting(&gPipeline.mScreen); } LLPipeline::sUnderWaterRender = FALSE; @@ -1039,7 +1032,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLAppViewer::instance()->pingMainloopTimeout("Display:RenderUI"); if (!for_snapshot) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); render_ui(); swap(); } @@ -1081,13 +1073,13 @@ 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(); + glh::matrix4f current_proj = get_current_projection(); + glh::matrix4f current_mod = get_current_modelview(); // clamp target zoom level to reasonable values gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f); // smoothly interpolate current zoom level - gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.mHUDTargetZoom, LLSmoothInterpolation::getInterpolant(0.03f)); + gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.getAgentHUDTargetZoom(), LLSmoothInterpolation::getInterpolant(0.03f)); if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices()) { @@ -1174,8 +1166,8 @@ void render_hud_attachments() gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.popMatrix(); - glh_set_current_projection(current_proj); - glh_set_current_modelview(current_mod); + set_current_projection(current_proj); + set_current_modelview(current_mod); } LLRect get_whole_screen_region() @@ -1257,29 +1249,32 @@ bool setup_hud_matrices(const LLRect& screen_region) // set up transform to keep HUD objects in front of camera gGL.matrixMode(LLRender::MM_PROJECTION); gGL.loadMatrix(proj.m); - glh_set_current_projection(proj); + set_current_projection(proj); gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.loadMatrix(model.m); - glh_set_current_modelview(model); + set_current_modelview(model); return TRUE; } void render_ui(F32 zoom_factor, int subfield) { + LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); + LLGLState::checkStates(); - glh::matrix4f saved_view = glh_get_current_modelview(); + glh::matrix4f saved_view = get_current_modelview(); if (!gSnapshot) { gGL.pushMatrix(); gGL.loadMatrix(gGLLastModelView); - glh_set_current_modelview(glh_copy_matrix(gGLLastModelView)); + set_current_modelview(copy_matrix(gGLLastModelView)); } if(LLSceneMonitor::getInstance()->needsUpdate()) { + LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_SCENE_MON); gGL.pushMatrix(); gViewerWindow->setup2DRender(); LLSceneMonitor::getInstance()->compare(); @@ -1287,19 +1282,12 @@ void render_ui(F32 zoom_factor, int subfield) gGL.popMatrix(); } - { - BOOL to_texture = gPipeline.canUseVertexShaders() && - LLPipeline::sRenderGlow; + // Finalize scene + gPipeline.renderFinalize(); - if (to_texture) - { - gPipeline.renderBloom(gSnapshot, zoom_factor, subfield); - } - - LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD); - render_hud_elements(); - render_hud_attachments(); - } + LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD); + render_hud_elements(); + render_hud_attachments(); LLGLSDefault gls_default; LLGLSUIDefault gls_ui; @@ -1313,6 +1301,7 @@ void render_ui(F32 zoom_factor, int subfield) { if (!gDisconnected) { + LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_3D); render_ui_3d(); LLGLState::checkStates(); } @@ -1321,12 +1310,14 @@ void render_ui(F32 zoom_factor, int subfield) render_disconnected_background(); } + LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_2D); render_ui_2d(); LLGLState::checkStates(); } gGL.flush(); { + LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_DEBUG_TEXT); gViewerWindow->setup2DRender(); gViewerWindow->updateDebugText(); gViewerWindow->drawDebugText(); @@ -1337,7 +1328,7 @@ void render_ui(F32 zoom_factor, int subfield) if (!gSnapshot) { - glh_set_current_modelview(saved_view); + set_current_modelview(saved_view); gGL.popMatrix(); } } @@ -1508,9 +1499,9 @@ void render_ui_2d() if (gSavedSettings.getBOOL("RenderUIBuffer")) { - if (LLUI::sDirty) + if (LLView::sIsRectDirty) { - LLUI::sDirty = FALSE; + LLView::sIsRectDirty = false; LLRect t_rect; gPipeline.mUIScreen.bindTarget(); @@ -1518,21 +1509,21 @@ void render_ui_2d() { static const S32 pad = 8; - LLUI::sDirtyRect.mLeft -= pad; - LLUI::sDirtyRect.mRight += pad; - LLUI::sDirtyRect.mBottom -= pad; - LLUI::sDirtyRect.mTop += pad; + LLView::sDirtyRect.mLeft -= pad; + LLView::sDirtyRect.mRight += pad; + LLView::sDirtyRect.mBottom -= pad; + LLView::sDirtyRect.mTop += pad; LLGLEnable scissor(GL_SCISSOR_TEST); - static LLRect last_rect = LLUI::sDirtyRect; + static LLRect last_rect = LLView::sDirtyRect; //union with last rect to avoid mouse poop - last_rect.unionWith(LLUI::sDirtyRect); + last_rect.unionWith(LLView::sDirtyRect); - t_rect = LLUI::sDirtyRect; - LLUI::sDirtyRect = last_rect; + t_rect = LLView::sDirtyRect; + LLView::sDirtyRect = last_rect; last_rect = t_rect; - + last_rect.mLeft = LLRect::tCoordType(last_rect.mLeft / LLUI::getScaleFactor().mV[0]); last_rect.mRight = LLRect::tCoordType(last_rect.mRight / LLUI::getScaleFactor().mV[0]); last_rect.mTop = LLRect::tCoordType(last_rect.mTop / LLUI::getScaleFactor().mV[1]); @@ -1548,7 +1539,7 @@ void render_ui_2d() gPipeline.mUIScreen.flush(); gGL.setColorMask(true, false); - LLUI::sDirtyRect = t_rect; + LLView::sDirtyRect = t_rect; } LLGLDisable cull(GL_CULL_FACE); diff --git a/indra/newview/llviewerdisplay.h b/indra/newview/llviewerdisplay.h index f6467d7f93..e8072193ea 100644 --- a/indra/newview/llviewerdisplay.h +++ b/indra/newview/llviewerdisplay.h @@ -40,6 +40,7 @@ extern BOOL gTeleportDisplay; extern LLFrameTimer gTeleportDisplayTimer; extern BOOL gForceRenderLandFence; extern BOOL gResizeScreenTexture; +extern BOOL gResizeShadowTexture; extern BOOL gWindowResized; #endif // LL_LLVIEWERDISPLAY_H diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index f475ab7d66..5a05f89758 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -34,6 +34,7 @@ #include "llcompilequeue.h" #include "llfasttimerview.h" #include "llfloaterabout.h" +#include "llfloateraddpaymentmethod.h" #include "llfloaterauction.h" #include "llfloaterautoreplacesettings.h" #include "llfloateravatar.h" @@ -53,28 +54,29 @@ #include "llfloaterbuyland.h" #include "llfloaterbvhpreview.h" #include "llfloatercamera.h" +#include "llfloatercamerapresets.h" #include "llfloaterchatvoicevolume.h" #include "llfloaterconversationlog.h" #include "llfloaterconversationpreview.h" -#include "llfloaterdeleteenvpreset.h" +#include "llfloatercreatelandmark.h" #include "llfloaterdeleteprefpreset.h" #include "llfloaterdestinations.h" -#include "llfloatereditdaycycle.h" -#include "llfloatereditsky.h" -#include "llfloatereditwater.h" -#include "llfloaterenvironmentsettings.h" +#include "llfloatereditextdaycycle.h" +#include "llfloaterenvironmentadjust.h" #include "llfloaterexperienceprofile.h" #include "llfloaterexperiences.h" #include "llfloaterexperiencepicker.h" #include "llfloaterevent.h" -#include "llfloaterflickr.h" +#include "llfloaterfixedenvironment.h" #include "llfloaterfonttest.h" +#include "llfloaterforgetuser.h" #include "llfloatergesture.h" #include "llfloatergodtools.h" #include "llfloatergridstatus.h" #include "llfloatergroups.h" #include "llfloaterhelpbrowser.h" #include "llfloaterhoverheight.h" +#include "llfloaterhowto.h" #include "llfloaterhud.h" #include "llfloaterimagepreview.h" #include "llfloaterimsession.h" @@ -91,6 +93,7 @@ #include "llfloatermemleak.h" #include "llfloatermodelpreview.h" #include "llfloatermyscripts.h" +#include "llfloatermyenvironment.h" #include "llfloaternamedesc.h" #include "llfloaternotificationsconsole.h" #include "llfloaternotificationstabbed.h" @@ -105,12 +108,14 @@ #include "llfloaterperms.h" #include "llfloaterpostprocess.h" #include "llfloaterpreference.h" +#include "llfloaterpreferenceviewadvanced.h" #include "llfloaterpreviewtrash.h" #include "llfloaterproperties.h" #include "llfloaterregiondebugconsole.h" #include "llfloaterregioninfo.h" #include "llfloaterregionrestarting.h" #include "llfloaterreporter.h" +#include "llfloatersavecamerapreset.h" #include "llfloatersaveprefpreset.h" #include "llfloatersceneloadstats.h" #include "llfloaterscriptdebug.h" @@ -132,7 +137,6 @@ #include "llfloatertos.h" #include "llfloatertoybox.h" #include "llfloatertranslationsettings.h" -#include "llfloatertwitter.h" #include "llfloateruipreview.h" #include "llfloatervoiceeffect.h" #include "llfloaterwebcontent.h" @@ -193,6 +197,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterAboutUtil::registerFloater(); LLFloaterReg::add("block_timers", "floater_fast_timers.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFastTimerView>); LLFloaterReg::add("about_land", "floater_about_land.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLand>); + LLFloaterReg::add("add_payment_method", "floater_add_payment_method.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAddPaymentMethod>); LLFloaterReg::add("appearance", "floater_my_appearance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); LLFloaterReg::add("associate_listing", "floater_associate_listing.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAssociateListing>); LLFloaterReg::add("auction", "floater_auction.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAuction>); @@ -214,20 +219,25 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("bumps", "floater_bumps.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBump>); LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCamera>); + LLFloaterReg::add("camera_presets", "floater_camera_presets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCameraPresets>); LLFloaterReg::add("chat_voice", "floater_voice_chat_volume.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatVoiceVolume>); LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterIMNearbyChat::buildFloater); LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>); LLFloaterReg::add("conversation", "floater_conversation_log.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationLog>); + LLFloaterReg::add("add_landmark", "floater_create_landmark.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCreateLandmark>); LLFloaterReg::add("delete_pref_preset", "floater_delete_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDeletePrefPreset>); LLFloaterReg::add("destinations", "floater_destinations.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDestinations>); LLFloaterReg::add("env_post_process", "floater_post_process.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPostProcess>); - LLFloaterReg::add("env_settings", "floater_environment_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEnvironmentSettings>); - LLFloaterReg::add("env_delete_preset", "floater_delete_env_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDeleteEnvPreset>); - LLFloaterReg::add("env_edit_sky", "floater_edit_sky_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEditSky>); - LLFloaterReg::add("env_edit_water", "floater_edit_water_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEditWater>); - LLFloaterReg::add("env_edit_day_cycle", "floater_edit_day_cycle.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEditDayCycle>); + + LLFloaterReg::add("env_fixed_environmentent_water", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentWater>); + LLFloaterReg::add("env_fixed_environmentent_sky", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentSky>); + + LLFloaterReg::add("env_adjust_snapshot", "floater_adjust_environment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEnvironmentAdjust>); + + LLFloaterReg::add("env_edit_extdaycycle", "floater_edit_ext_day_cycle.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEditExtDayCycle>); + LLFloaterReg::add("my_environments", "floater_my_environments.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMyEnvironment>); LLFloaterReg::add("event", "floater_event.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEvent>); LLFloaterReg::add("experiences", "floater_experiences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiences>); @@ -235,6 +245,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("experience_search", "floater_experience_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiencePicker>); LLFloaterReg::add("font_test", "floater_font_test.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFontTest>); + LLFloaterReg::add("forget_username", "floater_forget_user.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterForgetUser>); LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGesture>); LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGodTools>); @@ -297,6 +308,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("places", "floater_places.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>); LLFloaterReg::add("prefs_graphics_advanced", "floater_preferences_graphics_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceGraphicsAdvanced>); + LLFloaterReg::add("prefs_view_advanced", "floater_preferences_view_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceViewAdvanced>); LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceProxy>); LLFloaterReg::add("prefs_spellchecker_import", "floater_spellcheck_import.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerImport>); LLFloaterReg::add("prefs_translation", "floater_translation_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTranslationSettings>); @@ -316,6 +328,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("properties", "floater_inventory_item_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterProperties>); LLFloaterReg::add("publish_classified", "floater_publish_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPublishClassifiedFloater>); LLFloaterReg::add("save_pref_preset", "floater_save_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSavePrefPreset>); + LLFloaterReg::add("save_camera_preset", "floater_save_camera_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSaveCameraPreset>); LLFloaterReg::add("script_colors", "floater_script_ed_prefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptEdPrefs>); LLFloaterReg::add("telehubs", "floater_telehub.xml",&LLFloaterReg::build<LLFloaterTelehub>); @@ -350,13 +363,8 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("search", "floater_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSearch>); LLFloaterReg::add("my_profile", "floater_my_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create); LLFloaterReg::add("profile", "floater_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create); - LLFloaterReg::add("how_to", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create); + LLFloaterReg::add("guidebook", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHowTo>); - LLFloaterReg::add("flickr_web", "floater_fbc_web.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create); - LLFloaterReg::add("twitter_web", "floater_fbc_web.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create); - - LLFloaterReg::add("flickr", "floater_flickr.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFlickr>); - LLFloaterReg::add("twitter", "floater_twitter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTwitter>); LLFloaterReg::add("big_preview", "floater_big_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBigPreview>); LLFloaterUIPreviewUtil::registerFloater(); diff --git a/indra/newview/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp index 9cb2e0336a..f770db31dd 100644 --- a/indra/newview/llviewerfoldertype.cpp +++ b/indra/newview/llviewerfoldertype.cpp @@ -130,10 +130,11 @@ LLViewerFolderDictionary::LLViewerFolderDictionary() addEntry(LLFolderType::FT_FAVORITE, new ViewerFolderEntry("Favorites", "Inv_SysOpen", "Inv_SysClosed", FALSE, true)); addEntry(LLFolderType::FT_CURRENT_OUTFIT, new ViewerFolderEntry("Current Outfit", "Inv_SysOpen", "Inv_SysClosed", TRUE, false)); - addEntry(LLFolderType::FT_OUTFIT, new ViewerFolderEntry("New Outfit", "Inv_LookFolderOpen", "Inv_LookFolderClosed", TRUE, true)); + addEntry(LLFolderType::FT_OUTFIT, new ViewerFolderEntry("New Outfit", "Inv_LookFolderOpen", "Inv_LookFolderClosed", TRUE, false)); addEntry(LLFolderType::FT_MY_OUTFITS, new ViewerFolderEntry("My Outfits", "Inv_SysOpen", "Inv_SysClosed", TRUE, true)); addEntry(LLFolderType::FT_MESH, new ViewerFolderEntry("Meshes", "Inv_SysOpen", "Inv_SysClosed", FALSE, true)); - + addEntry(LLFolderType::FT_SETTINGS, new ViewerFolderEntry("Settings", "Inv_SysOpen", "Inv_SysClosed", FALSE, true)); + bool boxes_invisible = !gSavedSettings.getBOOL("InventoryOutboxMakeVisible"); addEntry(LLFolderType::FT_INBOX, new ViewerFolderEntry("Received Items", "Inv_SysOpen", "Inv_SysClosed", FALSE, boxes_invisible)); addEntry(LLFolderType::FT_OUTBOX, new ViewerFolderEntry("Merchant Outbox", "Inv_SysOpen", "Inv_SysClosed", FALSE, true)); diff --git a/indra/newview/llviewergenericmessage.cpp b/indra/newview/llviewergenericmessage.cpp index 3df53a4a30..d3de9d72bf 100644 --- a/indra/newview/llviewergenericmessage.cpp +++ b/indra/newview/llviewergenericmessage.cpp @@ -70,8 +70,6 @@ void send_generic_message(const std::string& method, gAgent.sendReliableMessage(); } - - void process_generic_message(LLMessageSystem* msg, void**) { LLUUID agent_id; @@ -93,3 +91,25 @@ void process_generic_message(LLMessageSystem* msg, void**) << LL_ENDL; } } + +void process_large_generic_message(LLMessageSystem* msg, void**) +{ + LLUUID agent_id; + msg->getUUID("AgentData", "AgentID", agent_id); + if (agent_id != gAgent.getID()) + { + LL_WARNS() << "GenericMessage for wrong agent" << LL_ENDL; + return; + } + + std::string request; + LLUUID invoice; + LLDispatcher::sparam_t strings; + LLDispatcher::unpackLargeMessage(msg, request, invoice, strings); + + if (!gGenericDispatcher.dispatch(request, invoice, strings)) + { + LL_WARNS() << "GenericMessage " << request << " failed to dispatch" + << LL_ENDL; + } +} diff --git a/indra/newview/llviewergenericmessage.h b/indra/newview/llviewergenericmessage.h index 9d451ec0bc..170f38a485 100644 --- a/indra/newview/llviewergenericmessage.h +++ b/indra/newview/llviewergenericmessage.h @@ -38,6 +38,7 @@ void send_generic_message(const std::string& method, const LLUUID& invoice = LLUUID::null); void process_generic_message(LLMessageSystem* msg, void**); +void process_large_generic_message(LLMessageSystem* msg, void**); extern LLDispatcher gGenericDispatcher; diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp new file mode 100644 index 0000000000..c0eaa88f54 --- /dev/null +++ b/indra/newview/llviewerinput.cpp @@ -0,0 +1,1540 @@ +/** + * @file llviewerinput.cpp + * @brief LLViewerInput class implementation + * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llviewerinput.h" + +#include "llappviewer.h" +#include "llfloaterreg.h" +#include "llmath.h" +#include "llagent.h" +#include "llagentcamera.h" +#include "llfloaterimnearbychat.h" +#include "llfocusmgr.h" +#include "llkeybind.h" // LLKeyData +#include "llmorphview.h" +#include "llmoveview.h" +#include "lltoolfocus.h" +#include "lltoolpie.h" +#include "llviewercontrol.h" +#include "llviewerwindow.h" +#include "llvoavatarself.h" +#include "llfloatercamera.h" +#include "llinitparam.h" +#include "llselectmgr.h" + +// +// Constants +// + +const F32 FLY_TIME = 0.5f; +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 LLKeyData agent_control_lbutton(CLICK_LEFT, KEY_NONE, MASK_NONE, true); + +struct LLKeyboardActionRegistry +: public LLRegistrySingleton<std::string, boost::function<bool (EKeystate keystate)>, LLKeyboardActionRegistry> +{ + LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry); +}; + +LLViewerInput gViewerInput; + +bool agent_jump( EKeystate s ) +{ + static BOOL first_fly_attempt(TRUE); + if (KEYSTATE_UP == s) + { + first_fly_attempt = TRUE; + return true; + } + F32 time = gKeyboard->getCurKeyElapsedTime(); + S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount()); + + if( time < FLY_TIME + || frame_count <= FLY_FRAMES + || gAgent.upGrabbed() + || !gSavedSettings.getBOOL("AutomaticFly")) + { + gAgent.moveUp(1); + } + else + { + gAgent.setFlying(TRUE, first_fly_attempt); + first_fly_attempt = FALSE; + gAgent.moveUp(1); + } + return true; +} + +bool agent_push_down( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgent.moveUp(-1); + return true; +} + +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()); + } +} + +static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode mode) +{ + if (KEYSTATE_UP == s) + { + // 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 && + !gAgent.getRunning()) + { + if (gAgent.mDoubleTapRunMode == mode && + gAgent.mDoubleTapRunTimer.getElapsedTimeF32() < NUDGE_TIME) + { + // Same walk-key was pushed again quickly; this is a + // double-tap so engage temporary running. + gAgent.setRunning(); + gAgent.sendWalkRun(gAgent.getRunning()); + } + + // Pressing any walk-key resets the double-tap timer + gAgent.mDoubleTapRunTimer.reset(); + gAgent.mDoubleTapRunMode = mode; + } +} + +static void agent_push_forwardbackward( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode ) +{ + agent_handle_doubletap_run(s, mode); + if (KEYSTATE_UP == s) return; + + F32 time = gKeyboard->getCurKeyElapsedTime(); + S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount()); + + if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES) + { + gAgent.moveAtNudge(direction); + } + else + { + gAgent.moveAt(direction); + } +} + +bool camera_move_forward( EKeystate s ); + +bool agent_push_forward( EKeystate s ) +{ + if(gAgent.isMovementLocked()) return true; + + //in free camera control mode we need to intercept keyboard events for avatar movements + if (LLFloaterCamera::inFreeCameraMode()) + { + camera_move_forward(s); + } + else + { + agent_push_forwardbackward(s, 1, LLAgent::DOUBLETAP_FORWARD); + } + return true; +} + +bool camera_move_backward( EKeystate s ); + +bool agent_push_backward( EKeystate s ) +{ + if(gAgent.isMovementLocked()) return true; + + //in free camera control mode we need to intercept keyboard events for avatar movements + if (LLFloaterCamera::inFreeCameraMode()) + { + camera_move_backward(s); + } + else if (!gAgent.backwardGrabbed() && gAgentAvatarp->isSitting() && gSavedSettings.getBOOL("LeaveMouselook")) + { + gAgentCamera.changeCameraToThirdPerson(); + } + else + { + agent_push_forwardbackward(s, -1, LLAgent::DOUBLETAP_BACKWARD); + } + return true; +} + +static void agent_slide_leftright( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode ) +{ + agent_handle_doubletap_run(s, mode); + if( KEYSTATE_UP == s ) return; + F32 time = gKeyboard->getCurKeyElapsedTime(); + S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount()); + + if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES) + { + gAgent.moveLeftNudge(direction); + } + else + { + gAgent.moveLeft(direction); + } +} + + +bool agent_slide_left( EKeystate s ) +{ + if(gAgent.isMovementLocked()) return true; + agent_slide_leftright(s, 1, LLAgent::DOUBLETAP_SLIDELEFT); + return true; +} + + +bool agent_slide_right( EKeystate s ) +{ + if(gAgent.isMovementLocked()) return true; + agent_slide_leftright(s, -1, LLAgent::DOUBLETAP_SLIDERIGHT); + return true; +} + +bool camera_spin_around_cw( EKeystate s ); + +bool agent_turn_left(EKeystate s) +{ + //in free camera control mode we need to intercept keyboard events for avatar movements + if (LLFloaterCamera::inFreeCameraMode()) + { + camera_spin_around_cw(s); + return true; + } + + if(gAgent.isMovementLocked()) return false; + + if (LLToolCamera::getInstance()->mouseSteerMode()) + { + agent_slide_left(s); + } + else + { + if (KEYSTATE_UP == s) + { + // Check temporary running. In case user released 'left' key with shift already released. + agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDELEFT); + return true; + } + F32 time = gKeyboard->getCurKeyElapsedTime(); + gAgent.moveYaw( LLFloaterMove::getYawRate( time ) ); + } + return true; +} + +bool camera_spin_around_ccw( EKeystate s ); + +bool agent_turn_right( EKeystate s ) +{ + //in free camera control mode we need to intercept keyboard events for avatar movements + if (LLFloaterCamera::inFreeCameraMode()) + { + camera_spin_around_ccw(s); + return true; + } + + if(gAgent.isMovementLocked()) return false; + + if (LLToolCamera::getInstance()->mouseSteerMode()) + { + agent_slide_right(s); + } + else + { + if (KEYSTATE_UP == s) + { + // Check temporary running. In case user released 'right' key with shift already released. + agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDERIGHT); + return true; + } + F32 time = gKeyboard->getCurKeyElapsedTime(); + gAgent.moveYaw( -LLFloaterMove::getYawRate( time ) ); + } + return true; +} + +bool agent_look_up( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgent.movePitch(-1); + //gAgent.rotate(-2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() ); + return true; +} + + +bool agent_look_down( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgent.movePitch(1); + //gAgent.rotate(2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() ); + return true; +} + +bool agent_toggle_fly( EKeystate s ) +{ + // Only catch the edge + if (KEYSTATE_DOWN == s ) + { + LLAgent::toggleFlying(); + } + return true; +} + +F32 get_orbit_rate() +{ + F32 time = gKeyboard->getCurKeyElapsedTime(); + if( time < NUDGE_TIME ) + { + F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME; + //LL_INFOS() << rate << LL_ENDL; + return rate; + } + else + { + return 1; + } +} + +bool camera_spin_around_ccw( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setOrbitLeftKey( get_orbit_rate() ); + return true; +} + + +bool camera_spin_around_cw( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setOrbitRightKey( get_orbit_rate() ); + return true; +} + +bool camera_spin_around_ccw_sitting( EKeystate s ) +{ + if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT ) return true; + if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning()) + { + //send keystrokes, but do not change camera + agent_turn_right(s); + } + else + { + //change camera but do not send keystrokes + gAgentCamera.unlockView(); + gAgentCamera.setOrbitLeftKey( get_orbit_rate() ); + } + return true; +} + + +bool camera_spin_around_cw_sitting( EKeystate s ) +{ + if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT ) return true; + if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning()) + { + //send keystrokes, but do not change camera + agent_turn_left(s); + } + else + { + //change camera but do not send keystrokes + gAgentCamera.unlockView(); + gAgentCamera.setOrbitRightKey( get_orbit_rate() ); + } + return true; +} + + +bool camera_spin_over( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setOrbitUpKey( get_orbit_rate() ); + return true; +} + + +bool camera_spin_under( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setOrbitDownKey( get_orbit_rate() ); + return true; +} + +bool camera_spin_over_sitting( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + if (gAgent.upGrabbed() || gAgentCamera.sitCameraEnabled()) + { + //send keystrokes, but do not change camera + agent_jump(s); + } + else + { + //change camera but do not send keystrokes + gAgentCamera.setOrbitUpKey( get_orbit_rate() ); + } + return true; +} + + +bool camera_spin_under_sitting( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + if (gAgent.downGrabbed() || gAgentCamera.sitCameraEnabled()) + { + //send keystrokes, but do not change camera + agent_push_down(s); + } + else + { + //change camera but do not send keystrokes + gAgentCamera.setOrbitDownKey( get_orbit_rate() ); + } + return true; +} + +bool camera_move_forward( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setOrbitInKey( get_orbit_rate() ); + return true; +} + + +bool camera_move_backward( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setOrbitOutKey( get_orbit_rate() ); + return true; +} + +bool camera_move_forward_sitting( EKeystate s ) +{ + if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD ) return true; + if (gAgent.forwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun())) + { + agent_push_forward(s); + } + else + { + gAgentCamera.setOrbitInKey( get_orbit_rate() ); + } + return true; +} + +bool camera_move_backward_sitting( EKeystate s ) +{ + if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD ) return true; + + if (gAgent.backwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun())) + { + agent_push_backward(s); + } + else + { + gAgentCamera.setOrbitOutKey( get_orbit_rate() ); + } + return true; +} + +bool camera_pan_up( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setPanUpKey( get_orbit_rate() ); + return true; +} + +bool camera_pan_down( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setPanDownKey( get_orbit_rate() ); + return true; +} + +bool camera_pan_left( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setPanLeftKey( get_orbit_rate() ); + return true; +} + +bool camera_pan_right( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setPanRightKey( get_orbit_rate() ); + return true; +} + +bool camera_pan_in( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setPanInKey( get_orbit_rate() ); + return true; +} + +bool camera_pan_out( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setPanOutKey( get_orbit_rate() ); + return true; +} + +bool camera_move_forward_fast( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setOrbitInKey(2.5f); + return true; +} + +bool camera_move_backward_fast( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setOrbitOutKey(2.5f); + return true; +} + + +bool edit_avatar_spin_ccw( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gMorphView->setCameraDrivenByKeys( TRUE ); + gAgentCamera.setOrbitLeftKey( get_orbit_rate() ); + //gMorphView->orbitLeft( get_orbit_rate() ); + return true; +} + + +bool edit_avatar_spin_cw( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gMorphView->setCameraDrivenByKeys( TRUE ); + gAgentCamera.setOrbitRightKey( get_orbit_rate() ); + //gMorphView->orbitRight( get_orbit_rate() ); + return true; +} + +bool edit_avatar_spin_over( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gMorphView->setCameraDrivenByKeys( TRUE ); + gAgentCamera.setOrbitUpKey( get_orbit_rate() ); + //gMorphView->orbitUp( get_orbit_rate() ); + return true; +} + + +bool edit_avatar_spin_under( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gMorphView->setCameraDrivenByKeys( TRUE ); + gAgentCamera.setOrbitDownKey( get_orbit_rate() ); + //gMorphView->orbitDown( get_orbit_rate() ); + return true; +} + +bool edit_avatar_move_forward( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gMorphView->setCameraDrivenByKeys( TRUE ); + gAgentCamera.setOrbitInKey( get_orbit_rate() ); + //gMorphView->orbitIn(); + return true; +} + + +bool edit_avatar_move_backward( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gMorphView->setCameraDrivenByKeys( TRUE ); + gAgentCamera.setOrbitOutKey( get_orbit_rate() ); + //gMorphView->orbitOut(); + return true; +} + +bool stop_moving( EKeystate s ) +{ + //it's supposed that 'stop moving' key will be held down for some time + if( KEYSTATE_UP == s ) return true; + // stop agent + gAgent.setControlFlags(AGENT_CONTROL_STOP); + + // cancel autopilot + gAgent.stopAutoPilot(); + return true; +} + +bool start_chat( EKeystate s ) +{ + if (LLAppViewer::instance()->quitRequested()) + { + return true; // can't talk, gotta go, kthxbye! + } + if (KEYSTATE_DOWN != s) return true; + + // start chat + LLFloaterIMNearbyChat::startChat(NULL); + return true; +} + +bool start_gesture( EKeystate s ) +{ + LLUICtrl* focus_ctrlp = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); + if (KEYSTATE_UP == s && + ! (focus_ctrlp && focus_ctrlp->acceptsTextInput())) + { + if ((LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"))->getCurrentChat().empty()) + { + // No existing chat in chat editor, insert '/' + LLFloaterIMNearbyChat::startChat("/"); + } + else + { + // Don't overwrite existing text in chat editor + LLFloaterIMNearbyChat::startChat(NULL); + } + } + return true; +} + +bool run_forward(EKeystate s) +{ + if (KEYSTATE_UP != s) + { + if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD) + { + gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_FORWARD; + } + if (!gAgent.getRunning()) + { + gAgent.setRunning(); + gAgent.sendWalkRun(true); + } + } + else if(KEYSTATE_UP == s) + { + if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_FORWARD) + gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE; + gAgent.clearRunning(); + gAgent.sendWalkRun(false); + } + agent_push_forward(s); + return true; +} + +bool run_backward(EKeystate s) +{ + if (KEYSTATE_UP != s) + { + if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD) + { + gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_BACKWARD; + } + if (!gAgent.getRunning()) + { + gAgent.setRunning(); + gAgent.sendWalkRun(true); + } + } + else if (KEYSTATE_UP == s) + { + if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_BACKWARD) + gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE; + gAgent.clearRunning(); + gAgent.sendWalkRun(false); + } + agent_push_backward(s); + return true; +} + +bool run_left(EKeystate s) +{ + if (KEYSTATE_UP != s) + { + if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT) + { + gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_SLIDELEFT; + } + if (!gAgent.getRunning()) + { + gAgent.setRunning(); + gAgent.sendWalkRun(true); + } + } + else if (KEYSTATE_UP == s) + { + if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_SLIDELEFT) + gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE; + gAgent.clearRunning(); + gAgent.sendWalkRun(false); + } + agent_slide_left(s); + return true; +} + +bool run_right(EKeystate s) +{ + if (KEYSTATE_UP != s) + { + if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT) + { + gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_SLIDERIGHT; + } + if (!gAgent.getRunning()) + { + gAgent.setRunning(); + gAgent.sendWalkRun(true); + } + } + else if (KEYSTATE_UP == s) + { + if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_SLIDERIGHT) + gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE; + gAgent.clearRunning(); + gAgent.sendWalkRun(false); + } + agent_slide_right(s); + return true; +} + +bool toggle_run(EKeystate s) +{ + if (KEYSTATE_DOWN != s) return true; + bool run = gAgent.getAlwaysRun(); + if (run) + { + gAgent.clearAlwaysRun(); + gAgent.clearRunning(); + } + else + { + gAgent.setAlwaysRun(); + gAgent.setRunning(); + } + gAgent.sendWalkRun(!run); + return true; +} + +bool toggle_sit(EKeystate s) +{ + if (KEYSTATE_DOWN != s) return true; + if (gAgent.isSitting()) + { + gAgent.standUp(); + } + else + { + gAgent.sitDown(); + } + return true; +} + +bool toggle_pause_media(EKeystate s) // analogue of play/pause button in top bar +{ + if (KEYSTATE_DOWN != s) return true; + bool pause = LLViewerMedia::getInstance()->isAnyMediaPlaying(); + LLViewerMedia::getInstance()->setAllMediaPaused(pause); + return true; +} + +bool toggle_enable_media(EKeystate s) +{ + if (KEYSTATE_DOWN != s) return true; + bool pause = LLViewerMedia::getInstance()->isAnyMediaPlaying() || LLViewerMedia::getInstance()->isAnyMediaShowing(); + LLViewerMedia::getInstance()->setAllMediaEnabled(!pause); + return true; +} + +bool walk_to(EKeystate s) +{ + if (KEYSTATE_DOWN != s) return true; + return LLToolPie::getInstance()->walkToClickedLocation(); +} + +bool teleport_to(EKeystate s) +{ + if (KEYSTATE_DOWN != s) return true; + return LLToolPie::getInstance()->teleportToClickedLocation(); +} + +bool toggle_voice(EKeystate s) +{ + if (KEYSTATE_DOWN != s) return true; + if (!LLAgent::isActionAllowed("speak")) return false; + LLVoiceClient::getInstance()->toggleUserPTTState(); + return true; +} + +bool voice_follow_key(EKeystate s) +{ + if (KEYSTATE_DOWN == s) + { + if (!LLAgent::isActionAllowed("speak")) return false; + LLVoiceClient::getInstance()->setUserPTTState(true); + return true; + } + else if (KEYSTATE_UP == s && LLVoiceClient::getInstance()->getUserPTTState()) + { + LLVoiceClient::getInstance()->setUserPTTState(false); + return true; + } + return false; +} + +bool agen_control_lbutton_handle(EKeystate s) +{ + switch (s) + { + case KEYSTATE_DOWN: + gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN); + break; + case KEYSTATE_UP: + gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP); + break; + default: + break; + } + return true; +} + +#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("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("run_forward", run_forward); +REGISTER_KEYBOARD_ACTION("run_backward", run_backward); +REGISTER_KEYBOARD_ACTION("run_left", run_left); +REGISTER_KEYBOARD_ACTION("run_right", run_right); +REGISTER_KEYBOARD_ACTION("toggle_run", toggle_run); +REGISTER_KEYBOARD_ACTION("toggle_sit", toggle_sit); +REGISTER_KEYBOARD_ACTION("toggle_pause_media", toggle_pause_media); +REGISTER_KEYBOARD_ACTION("toggle_enable_media", toggle_enable_media); +REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to); +REGISTER_KEYBOARD_ACTION("walk_to", walk_to); +REGISTER_KEYBOARD_ACTION("toggle_voice", toggle_voice); +REGISTER_KEYBOARD_ACTION("voice_follow_key", voice_follow_key); +#undef REGISTER_KEYBOARD_ACTION + +LLViewerInput::LLViewerInput() +{ + resetBindings(); + + for (S32 i = 0; i < KEY_COUNT; i++) + { + mKeyHandledByUI[i] = FALSE; + } + for (S32 i = 0; i < CLICK_COUNT; i++) + { + mMouseLevel[i] = MOUSE_STATE_SILENT; + } + // we want the UI to never see these keys so that they can always control the avatar/camera + for(KEY k = KEY_PAD_UP; k <= KEY_PAD_DIVIDE; k++) + { + mKeysSkippedByUI.insert(k); + } +} + +// static +BOOL LLViewerInput::modeFromString(const std::string& string, S32 *mode) +{ + if (string == "FIRST_PERSON") + { + *mode = MODE_FIRST_PERSON; + return TRUE; + } + else if (string == "THIRD_PERSON") + { + *mode = MODE_THIRD_PERSON; + return TRUE; + } + else if (string == "EDIT_AVATAR") + { + *mode = MODE_EDIT_AVATAR; + return TRUE; + } + else if (string == "SITTING") + { + *mode = MODE_SITTING; + return TRUE; + } + else + { + *mode = MODE_THIRD_PERSON; + return FALSE; + } +} + +// static +BOOL LLViewerInput::mouseFromString(const std::string& string, EMouseClickType *mode) +{ + if (string == "LMB") + { + *mode = CLICK_LEFT; + return TRUE; + } + else if (string == "Double LMB") + { + *mode = CLICK_DOUBLELEFT; + return TRUE; + } + else if (string == "MMB") + { + *mode = CLICK_MIDDLE; + return TRUE; + } + else if (string == "MB4") + { + *mode = CLICK_BUTTON4; + return TRUE; + } + else if (string == "MB5") + { + *mode = CLICK_BUTTON5; + return TRUE; + } + else + { + *mode = CLICK_NONE; + return FALSE; + } +} + +BOOL LLViewerInput::handleKey(KEY translated_key, MASK translated_mask, BOOL repeated) +{ + // check for re-map + EKeyboardMode mode = gViewerInput.getMode(); + U32 keyidx = (translated_mask<<16) | translated_key; + key_remap_t::iterator iter = mRemapKeys[mode].find(keyidx); + if (iter != mRemapKeys[mode].end()) + { + translated_key = (iter->second) & 0xff; + translated_mask = (iter->second)>>16; + } + + // No repeats of F-keys + BOOL repeatable_key = (translated_key < KEY_F1 || translated_key > KEY_F12); + if (!repeatable_key && repeated) + { + return FALSE; + } + + LL_DEBUGS("UserInput") << "keydown -" << translated_key << "-" << LL_ENDL; + // skip skipped keys + if(mKeysSkippedByUI.find(translated_key) != mKeysSkippedByUI.end()) + { + mKeyHandledByUI[translated_key] = FALSE; + LL_INFOS("KeyboardHandling") << "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 LLViewerInput::handleKeyUp(KEY translated_key, MASK translated_mask) +{ + return gViewerWindow->handleKeyUp(translated_key, translated_mask); +} + +BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name) +{ + S32 index; + typedef boost::function<bool(EKeystate)> function_t; + function_t function = NULL; + std::string name; + + // Allow remapping of F2-F12 + if (function_name[0] == 'F') + { + int c1 = function_name[1] - '0'; + int c2 = function_name[2] ? function_name[2] - '0' : -1; + if (c1 >= 0 && c1 <= 9 && c2 >= -1 && c2 <= 9) + { + int idx = c1; + if (c2 >= 0) + idx = idx*10 + c2; + if (idx >=2 && idx <= 12) + { + U32 keyidx = ((mask<<16)|key); + (mRemapKeys[mode])[keyidx] = ((0<<16)|(KEY_F1+(idx-1))); + return TRUE; + } + } + } + + // Not remapped, look for a function + + function_t* result = LLKeyboardActionRegistry::getValue(function_name); + if (result) + { + function = *result; + } + + if (!function) + { + LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; + return FALSE; + } + + // check for duplicate first and overwrite + S32 size = mKeyBindings[mode].size(); + for (index = 0; index < size; index++) + { + if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask) + break; + } + + if (mode >= MODE_COUNT) + { + LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL; + return FALSE; + } + + LLKeyboardBinding bind; + bind.mKey = key; + bind.mMask = mask; + bind.mFunction = function; + + mKeyBindings[mode].push_back(bind); + + return TRUE; +} + +BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const std::string& function_name) +{ + S32 index; + typedef boost::function<bool(EKeystate)> function_t; + function_t function = NULL; + + function_t* result = LLKeyboardActionRegistry::getValue(function_name); + if (result) + { + function = *result; + } + + if (!function) + { + LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; + return FALSE; + } + + // check for duplicate first and overwrite + S32 size = mMouseBindings[mode].size(); + for (index = 0; index < size; index++) + { + if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask) + break; + } + + if (mode >= MODE_COUNT) + { + LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL; + return FALSE; + } + + LLMouseBinding bind; + bind.mMouse = mouse; + bind.mMask = mask; + bind.mFunction = function; + + mMouseBindings[mode].push_back(bind); + + return TRUE; +} + +LLViewerInput::KeyBinding::KeyBinding() +: key("key"), + mouse("mouse"), + mask("mask"), + command("command") +{} + +LLViewerInput::KeyMode::KeyMode() +: bindings("binding") +{} + +LLViewerInput::Keys::Keys() +: first_person("first_person"), + third_person("third_person"), + sitting("sitting"), + edit_avatar("edit_avatar") +{} + +void LLViewerInput::resetBindings() +{ + for (S32 i = 0; i < MODE_COUNT; i++) + { + mKeyBindings[i].clear(); + mMouseBindings[i].clear(); + } +} + +S32 LLViewerInput::loadBindingsXML(const std::string& filename) +{ + resetBindings(); + + S32 binding_count = 0; + Keys keys; + LLSimpleXUIParser parser; + + if (parser.readXUI(filename, keys) + && keys.validateBlock()) + { + binding_count += loadBindingMode(keys.first_person, MODE_FIRST_PERSON); + binding_count += loadBindingMode(keys.third_person, MODE_THIRD_PERSON); + binding_count += loadBindingMode(keys.sitting, MODE_SITTING); + binding_count += loadBindingMode(keys.edit_avatar, MODE_EDIT_AVATAR); + } + return binding_count; +} + +S32 count_masks(const MASK &mask) +{ + S32 res = 0; + if (mask & MASK_CONTROL) + { + res++; + } + if (mask & MASK_SHIFT) + { + res++; + } + if (mask & MASK_ALT) + { + res++; + } + return res; +} + +bool compare_key_by_mask(LLKeyboardBinding i1, LLKeyboardBinding i2) +{ + return (count_masks(i1.mMask) > count_masks(i2.mMask)); +} + +bool compare_mouse_by_mask(LLMouseBinding i1, LLMouseBinding i2) +{ + return (count_masks(i1.mMask) > count_masks(i2.mMask)); +} + +S32 LLViewerInput::loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mode) +{ + S32 binding_count = 0; + for (LLInitParam::ParamIterator<KeyBinding>::const_iterator it = keymode.bindings.begin(), + end_it = keymode.bindings.end(); + it != end_it; + ++it) + { + bool processed = false; + std::string key_str = it->key.getValue(); + if (!key_str.empty() && key_str != "NONE") + { + KEY key; + LLKeyboard::keyFromString(key_str, &key); + if (key != KEY_NONE) + { + MASK mask; + LLKeyboard::maskFromString(it->mask, &mask); + bindKey(mode, key, mask, it->command); + processed = true; + } + else + { + LL_WARNS_ONCE() << "There might be issues in keybindings' file" << LL_ENDL; + } + } + if (!processed && it->mouse.isProvided() && !it->mouse.getValue().empty()) + { + EMouseClickType mouse; + mouseFromString(it->mouse.getValue(), &mouse); + if (mouse != CLICK_NONE) + { + MASK mask; + LLKeyboard::maskFromString(it->mask, &mask); + bindMouse(mode, mouse, mask, it->command); + processed = true; + } + else + { + LL_WARNS_ONCE() << "There might be issues in keybindings' file" << LL_ENDL; + } + } + if (processed) + { + // total + binding_count++; + } + } + + // sort lists by mask (so that Shift+W is executed before W, if both are assigned, but if Shift+W is not assigned W should be executed) + std::sort(mKeyBindings[mode].begin(), mKeyBindings[mode].end(), compare_key_by_mask); + std::sort(mMouseBindings[mode].begin(), mMouseBindings[mode].end(), compare_mouse_by_mask); + + return binding_count; +} + +EKeyboardMode LLViewerInput::getMode() const +{ + if ( gAgentCamera.cameraMouselook() ) + { + return MODE_FIRST_PERSON; + } + else if ( gMorphView && gMorphView->getVisible()) + { + return MODE_EDIT_AVATAR; + } + else if (isAgentAvatarValid() && gAgentAvatarp->isSitting()) + { + return MODE_SITTING; + } + else + { + return MODE_THIRD_PERSON; + } +} + +bool LLViewerInput::scanKey(const std::vector<LLKeyboardBinding> &binding, + S32 binding_count, + KEY key, + MASK mask, + BOOL key_down, + BOOL key_up, + BOOL key_level, + bool repeat) const +{ + for (S32 i = 0; i < binding_count; i++) + { + if (binding[i].mKey == key) + { + if ((binding[i].mMask & mask) == binding[i].mMask) + { + bool res = false; + if (key_down && !repeat) + { + // ...key went down this frame, call function + res = binding[i].mFunction( KEYSTATE_DOWN ); + return true; + } + else if (key_up) + { + // ...key went down this frame, call function + res = binding[i].mFunction( KEYSTATE_UP ); + } + else if (key_level) + { + // ...key held down from previous frame + // Not windows, just call the function. + res = binding[i].mFunction( KEYSTATE_LEVEL ); + }//if + // Key+Mask combinations are supposed to be unique, so we won't find anything else + return res; + }//if + }//if + }//for + return false; +} + +// Called from scanKeyboard. +bool LLViewerInput::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) const +{ + if (LLApp::isExiting()) + { + return false; + } + + S32 mode = getMode(); + // Consider keyboard scanning as NOT mouse event. JC + MASK mask = gKeyboard->currentMask(FALSE); + + if (mKeyHandledByUI[key]) + { + return false; + } + + // don't process key down on repeated keys + BOOL repeat = gKeyboard->getKeyRepeated(key); + + bool res = scanKey(mKeyBindings[mode], mKeyBindings[mode].size(), key, mask, key_down, key_up, key_level, repeat); + + if (!res && agent_control_lbutton.canHandle(CLICK_NONE, key, mask)) + { + if (key_down && !repeat) + { + res = agen_control_lbutton_handle(KEYSTATE_DOWN); + } + if (key_up) + { + res = agen_control_lbutton_handle(KEYSTATE_UP); + } + } + return res; +} + +BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down) +{ + BOOL handled = gViewerWindow->handleAnyMouseClick(window_impl, pos, mask, clicktype, down); + + if (clicktype != CLICK_NONE) + { + // Special case + // If UI doesn't handle double click, LMB click is issued, so supres LMB 'down' when doubleclick is set + // handle !down as if we are handling doubleclick + + bool double_click_sp = (clicktype == CLICK_LEFT + && (mMouseLevel[CLICK_DOUBLELEFT] != MOUSE_STATE_SILENT) + && mMouseLevel[CLICK_LEFT] == MOUSE_STATE_SILENT); + if (double_click_sp && !down) + { + // Process doubleclick instead + clicktype = CLICK_DOUBLELEFT; + } + + + if (double_click_sp && down) + { + // Consume click. + // Due to handling, double click that is not handled will be immediately followed by LMB click + } + // If UI handled 'down', it should handle 'up' as well + // If we handle 'down' not by UI, then we should handle 'up'/'level' regardless of UI + else if (handled) + { + // UI handled new 'down' so iterupt whatever state we were in. + if (mMouseLevel[clicktype] != MOUSE_STATE_SILENT) + { + if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN) + { + mMouseLevel[clicktype] = MOUSE_STATE_CLICK; + } + else + { + mMouseLevel[clicktype] = MOUSE_STATE_UP; + } + } + } + else if (down) + { + if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN) + { + // this is repeated hit (mouse does not repeat event until release) + // for now treat rapid clicking like mouse being held + mMouseLevel[clicktype] = MOUSE_STATE_LEVEL; + } + else + { + mMouseLevel[clicktype] = MOUSE_STATE_DOWN; + } + } + else if (mMouseLevel[clicktype] != MOUSE_STATE_SILENT) + { + // Released mouse key + if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN) + { + mMouseLevel[clicktype] = MOUSE_STATE_CLICK; + } + else + { + mMouseLevel[clicktype] = MOUSE_STATE_UP; + } + } + } + + return handled; +} + +bool LLViewerInput::scanMouse(const std::vector<LLMouseBinding> &binding, S32 binding_count, EMouseClickType mouse, MASK mask, EMouseState state) const +{ + for (S32 i = 0; i < binding_count; i++) + { + if (binding[i].mMouse == mouse && (binding[i].mMask & mask) == binding[i].mMask) + { + bool res = false; + switch (state) + { + case MOUSE_STATE_DOWN: + res = binding[i].mFunction(KEYSTATE_DOWN); + break; + case MOUSE_STATE_CLICK: + // Button went down and up in scope of single frame + // might not work best with some functions, + // but some function need specific states specifically + res = binding[i].mFunction(KEYSTATE_DOWN); + res |= binding[i].mFunction(KEYSTATE_UP); + break; + case MOUSE_STATE_LEVEL: + res = binding[i].mFunction(KEYSTATE_LEVEL); + break; + case MOUSE_STATE_UP: + res = binding[i].mFunction(KEYSTATE_UP); + break; + default: + break; + } + // Key+Mask combinations are supposed to be unique, no need to continue + return res; + } + } + return false; +} + +// todo: this recods key, scanMouse() triggers functions with EKeystate +bool LLViewerInput::scanMouse(EMouseClickType click, EMouseState state) const +{ + bool res = false; + S32 mode = getMode(); + MASK mask = gKeyboard->currentMask(TRUE); + res = scanMouse(mMouseBindings[mode], mMouseBindings[mode].size(), click, mask, state); + // no user defined actions found or those actions can't handle the key/button, handle control if nessesary + if (!res && agent_control_lbutton.canHandle(click, KEY_NONE, mask)) + { + switch (state) + { + case MOUSE_STATE_DOWN: + agen_control_lbutton_handle(KEYSTATE_DOWN); + res = true; + break; + case MOUSE_STATE_CLICK: + // might not work best with some functions, + // but some function need specific states too specifically + agen_control_lbutton_handle(KEYSTATE_DOWN); + agen_control_lbutton_handle(KEYSTATE_UP); + res = true; + break; + case MOUSE_STATE_UP: + agen_control_lbutton_handle(KEYSTATE_UP); + res = true; + break; + default: + break; + } + } + return res; +} + +void LLViewerInput::scanMouse() +{ + for (S32 i = 0; i < CLICK_COUNT; i++) + { + if (mMouseLevel[i] != MOUSE_STATE_SILENT) + { + scanMouse((EMouseClickType)i, mMouseLevel[i]); + if (mMouseLevel[i] == MOUSE_STATE_DOWN) + { + // mouse doesn't support 'continued' state, so after handling, switch to LEVEL + mMouseLevel[i] = MOUSE_STATE_LEVEL; + } + else if (mMouseLevel[i] == MOUSE_STATE_UP || mMouseLevel[i] == MOUSE_STATE_CLICK) + { + mMouseLevel[i] = MOUSE_STATE_SILENT; + } + } + } +} + +bool LLViewerInput::isMouseBindUsed(const EMouseClickType mouse, const MASK mask, const S32 mode) +{ + S32 size = mMouseBindings[mode].size(); + for (S32 index = 0; index < size; index++) + { + if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask) + return true; + } + return false; +} diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h new file mode 100644 index 0000000000..281a209896 --- /dev/null +++ b/indra/newview/llviewerinput.h @@ -0,0 +1,179 @@ +/** + * @file llviewerinput.h + * @brief LLViewerInput class header file + * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLVIEWERINPUT_H +#define LL_LLVIEWERINPUT_H + +#include "llkeyboard.h" // For EKeystate +#include "llinitparam.h" + +const S32 MAX_KEY_BINDINGS = 128; // was 60 + +class LLNamedFunction +{ +public: + LLNamedFunction() : mFunction(NULL) { }; + ~LLNamedFunction() { }; + + std::string mName; + LLKeyFunc mFunction; +}; + +class LLKeyboardBinding +{ +public: + KEY mKey; + MASK mMask; + + LLKeyFunc mFunction; +}; + +class LLMouseBinding +{ +public: + EMouseClickType mMouse; + MASK mMask; + + LLKeyFunc mFunction; +}; + + +typedef enum e_keyboard_mode +{ + MODE_FIRST_PERSON, + MODE_THIRD_PERSON, + MODE_EDIT_AVATAR, + MODE_SITTING, + MODE_COUNT +} EKeyboardMode; + +class LLWindow; + +void bind_keyboard_functions(); + +class LLViewerInput +{ +public: + struct KeyBinding : public LLInitParam::Block<KeyBinding> + { + Mandatory<std::string> key, + mask, + command; + Optional<std::string> mouse; // Note, not mandatory for the sake of backward campatibility with keys.xml + + KeyBinding(); + }; + + struct KeyMode : public LLInitParam::Block<KeyMode> + { + Multiple<KeyBinding> bindings; + + KeyMode(); + }; + + struct Keys : public LLInitParam::Block<Keys> + { + Optional<KeyMode> first_person, + third_person, + sitting, + edit_avatar; + + Keys(); + }; + + LLViewerInput(); + + BOOL handleKey(KEY key, MASK mask, BOOL repeated); + BOOL handleKeyUp(KEY key, MASK mask); + + S32 loadBindingsXML(const std::string& filename); // returns number bound, 0 on error + EKeyboardMode getMode() const; + + static BOOL modeFromString(const std::string& string, S32 *mode); // False on failure + static BOOL mouseFromString(const std::string& string, EMouseClickType *mode);// False on failure + + bool scanKey(KEY key, + BOOL key_down, + BOOL key_up, + BOOL key_level) const; + + // handleMouse() records state, scanMouse() goes through states, scanMouse(click) processes individual saved states after UI is done with them + BOOL handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down); + void scanMouse(); + + bool isMouseBindUsed(const EMouseClickType mouse, const MASK mask = MASK_NONE, const S32 mode = MODE_THIRD_PERSON); + +private: + bool scanKey(const std::vector<LLKeyboardBinding> &binding, + S32 binding_count, + KEY key, + MASK mask, + BOOL key_down, + BOOL key_up, + BOOL key_level, + bool repeat) const; + + enum EMouseState + { + MOUSE_STATE_DOWN, // key down this frame + MOUSE_STATE_CLICK, // key went up and down in scope of same frame + MOUSE_STATE_LEVEL, // clicked again fast, or never released + MOUSE_STATE_UP, // went up this frame + MOUSE_STATE_SILENT // notified about 'up', do not notify again + }; + bool scanMouse(EMouseClickType click, EMouseState state) const; + bool scanMouse(const std::vector<LLMouseBinding> &binding, + S32 binding_count, + EMouseClickType mouse, + MASK mask, + EMouseState state) const; + + S32 loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mode); + BOOL bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name); + BOOL bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const std::string& function_name); + void resetBindings(); + + // Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here + + // TODO: at some point it is better to remake this, especially keyaboard part + // would be much better to send to functions actual state of the button than + // to send what we think function wants based on collection of bools (mKeyRepeated, mKeyLevel, mKeyDown) + std::vector<LLKeyboardBinding> mKeyBindings[MODE_COUNT]; + std::vector<LLMouseBinding> mMouseBindings[MODE_COUNT]; + + typedef std::map<U32, U32> key_remap_t; + key_remap_t mRemapKeys[MODE_COUNT]; + std::set<KEY> mKeysSkippedByUI; + BOOL mKeyHandledByUI[KEY_COUNT]; // key processed successfully by UI + + // This is indentical to what llkeyboard does (mKeyRepeated, mKeyLevel, mKeyDown e t c), + // just instead of remembering individually as bools, we record state as enum + EMouseState mMouseLevel[CLICK_COUNT]; // records of key state +}; + +extern LLViewerInput gViewerInput; + +#endif // LL_LLVIEWERINPUT_H diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 61857d6fb1..bbed741a33 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -70,6 +70,7 @@ #include "llfloaterperms.h" #include "llclipboard.h" #include "llhttpretrypolicy.h" +#include "llsettingsvo.h" // do-nothing ops for use in callbacks. void no_op_inventory_func(const LLUUID&) {} @@ -80,6 +81,9 @@ static const char * const LOG_INV("Inventory"); static const char * const LOG_LOCAL("InventoryLocalize"); static const char * const LOG_NOTECARD("copy_inventory_from_notecard"); +static const std::string INV_OWNER_ID("owner_id"); +static const std::string INV_VERSION("version"); + #if 1 // *TODO$: LLInventoryCallback should be deprecated to conform to the new boost::bind/coroutine model. // temp code in transition @@ -238,7 +242,7 @@ public: return false; } - if (!LLUI::sSettingGroups["config"]->getBOOL("EnableInventory")) + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableInventory")) { LLNotificationsUtil::add("NoInventory", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); return true; @@ -518,14 +522,6 @@ void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const } // virtual -BOOL LLViewerInventoryItem::importFile(LLFILE* fp) -{ - BOOL rv = LLInventoryItem::importFile(fp); - mIsComplete = TRUE; - return rv; -} - -// virtual BOOL LLViewerInventoryItem::importLegacyStream(std::istream& input_stream) { BOOL rv = LLInventoryItem::importLegacyStream(input_stream); @@ -533,32 +529,6 @@ BOOL LLViewerInventoryItem::importLegacyStream(std::istream& input_stream) return rv; } -bool LLViewerInventoryItem::importFileLocal(LLFILE* fp) -{ - // TODO: convert all functions that return BOOL to return bool - bool rv = (LLInventoryItem::importFile(fp) ? true : false); - mIsComplete = false; - return rv; -} - -bool LLViewerInventoryItem::exportFileLocal(LLFILE* fp) const -{ - std::string uuid_str; - fprintf(fp, "\tinv_item\t0\n\t{\n"); - mUUID.toString(uuid_str); - fprintf(fp, "\t\titem_id\t%s\n", uuid_str.c_str()); - mParentUUID.toString(uuid_str); - fprintf(fp, "\t\tparent_id\t%s\n", uuid_str.c_str()); - mPermissions.exportFile(fp); - fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType)); - const std::string inv_type_str = LLInventoryType::lookup(mInventoryType); - if(!inv_type_str.empty()) fprintf(fp, "\t\tinv_type\t%s\n", inv_type_str.c_str()); - fprintf(fp, "\t\tname\t%s|\n", mName.c_str()); - fprintf(fp, "\t\tcreation_date\t%d\n", (S32) mCreationDate); - fprintf(fp,"\t}\n"); - return true; -} - void LLViewerInventoryItem::updateParentOnServer(BOOL restamp) const { LLMessageSystem* msg = gMessageSystem; @@ -719,90 +689,26 @@ S32 LLViewerInventoryCategory::getViewerDescendentCount() const return descendents_actual; } -bool LLViewerInventoryCategory::importFileLocal(LLFILE* fp) +LLSD LLViewerInventoryCategory::exportLLSD() const { - // *NOTE: This buffer size is hard coded into scanf() below. - char buffer[MAX_STRING]; /* Flawfinder: ignore */ - char keyword[MAX_STRING]; /* Flawfinder: ignore */ - char valuestr[MAX_STRING]; /* Flawfinder: ignore */ + LLSD cat_data = LLInventoryCategory::exportLLSD(); + cat_data[INV_OWNER_ID] = mOwnerID; + cat_data[INV_VERSION] = mVersion; - keyword[0] = '\0'; - valuestr[0] = '\0'; - while(!feof(fp)) - { - if (fgets(buffer, MAX_STRING, fp) == NULL) - { - buffer[0] = '\0'; - } - - sscanf( /* Flawfinder: ignore */ - buffer, " %254s %254s", keyword, valuestr); - if(0 == strcmp("{",keyword)) - { - continue; - } - if(0 == strcmp("}", keyword)) - { - break; - } - else if(0 == strcmp("cat_id", keyword)) - { - mUUID.set(valuestr); - } - else if(0 == strcmp("parent_id", keyword)) - { - mParentUUID.set(valuestr); - } - else if(0 == strcmp("type", keyword)) - { - mType = LLAssetType::lookup(valuestr); - } - else if(0 == strcmp("pref_type", keyword)) - { - mPreferredType = LLFolderType::lookup(valuestr); - } - else if(0 == strcmp("name", keyword)) - { - //strcpy(valuestr, buffer + strlen(keyword) + 3); - // *NOTE: Not ANSI C, but widely supported. - sscanf( /* Flawfinder: ignore */ - buffer, " %254s %254[^|]", keyword, valuestr); - mName.assign(valuestr); - LLStringUtil::replaceNonstandardASCII(mName, ' '); - LLStringUtil::replaceChar(mName, '|', ' '); - } - else if(0 == strcmp("owner_id", keyword)) - { - mOwnerID.set(valuestr); - } - else if(0 == strcmp("version", keyword)) - { - sscanf(valuestr, "%d", &mVersion); - } - else - { - LL_WARNS(LOG_INV) << "unknown keyword '" << keyword - << "' in inventory import category " << mUUID << LL_ENDL; - } - } - return true; + return cat_data; } -bool LLViewerInventoryCategory::exportFileLocal(LLFILE* fp) const -{ - std::string uuid_str; - fprintf(fp, "\tinv_category\t0\n\t{\n"); - mUUID.toString(uuid_str); - fprintf(fp, "\t\tcat_id\t%s\n", uuid_str.c_str()); - mParentUUID.toString(uuid_str); - fprintf(fp, "\t\tparent_id\t%s\n", uuid_str.c_str()); - fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType)); - fprintf(fp, "\t\tpref_type\t%s\n", LLFolderType::lookup(mPreferredType).c_str()); - fprintf(fp, "\t\tname\t%s|\n", mName.c_str()); - mOwnerID.toString(uuid_str); - fprintf(fp, "\t\towner_id\t%s\n", uuid_str.c_str()); - fprintf(fp, "\t\tversion\t%d\n", mVersion); - fprintf(fp,"\t}\n"); +bool LLViewerInventoryCategory::importLLSD(const LLSD& cat_data) +{ + LLInventoryCategory::importLLSD(cat_data); + if (cat_data.has(INV_OWNER_ID)) + { + mOwnerID = cat_data[INV_OWNER_ID].asUUID(); + } + if (cat_data.has(INV_VERSION)) + { + setVersion(cat_data[INV_VERSION].asInteger()); + } return true; } @@ -1098,7 +1004,7 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, const LLUUID& parent, const LLTransactionID& transaction_id, const std::string& name, const std::string& desc, LLAssetType::EType asset_type, - LLInventoryType::EType inv_type, LLWearableType::EType wtype, + LLInventoryType::EType inv_type, U8 subtype, U32 next_owner_perm, LLPointer<LLInventoryCallback> cb) { @@ -1133,7 +1039,7 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, msg->addU32Fast(_PREHASH_NextOwnerMask, next_owner_perm); msg->addS8Fast(_PREHASH_Type, (S8)asset_type); msg->addS8Fast(_PREHASH_InvType, (S8)inv_type); - msg->addU8Fast(_PREHASH_WearableType, (U8)wtype); + msg->addU8Fast(_PREHASH_WearableType, (U8)subtype); msg->addStringFast(_PREHASH_Name, server_name); msg->addStringFast(_PREHASH_Description, desc); @@ -1147,9 +1053,36 @@ void create_inventory_callingcard(const LLUUID& avatar_id, const LLUUID& parent LLAvatarNameCache::get(avatar_id, &av_name); create_inventory_item(gAgent.getID(), gAgent.getSessionID(), parent, LLTransactionID::tnull, av_name.getUserName(), item_desc, LLAssetType::AT_CALLINGCARD, - LLInventoryType::IT_CALLINGCARD, NOT_WEARABLE, PERM_MOVE | PERM_TRANSFER, cb); + LLInventoryType::IT_CALLINGCARD, NO_INV_SUBTYPE, PERM_MOVE | PERM_TRANSFER, cb); } +void create_inventory_wearable(const LLUUID& agent_id, const LLUUID& session_id, + const LLUUID& parent, const LLTransactionID& transaction_id, + const std::string& name, + const std::string& desc, LLAssetType::EType asset_type, + LLWearableType::EType wtype, + U32 next_owner_perm, + LLPointer<LLInventoryCallback> cb) +{ + create_inventory_item(agent_id, session_id, parent, transaction_id, + name, desc, asset_type, LLInventoryType::IT_WEARABLE, static_cast<U8>(wtype), + next_owner_perm, cb); +} + +void create_inventory_settings(const LLUUID& agent_id, const LLUUID& session_id, + const LLUUID& parent, const LLTransactionID& transaction_id, + const std::string& name, + const std::string& desc, + LLSettingsType::type_e settype, + U32 next_owner_perm, + LLPointer<LLInventoryCallback> cb) +{ + create_inventory_item(agent_id, session_id, parent, transaction_id, + name, desc, LLAssetType::AT_SETTINGS, LLInventoryType::IT_SETTINGS, + static_cast<U8>(settype), next_owner_perm, cb); +} + + void copy_inventory_item( const LLUUID& agent_id, const LLUUID& current_owner, @@ -1701,7 +1634,7 @@ void create_new_item(const std::string& name, desc, asset_type, inv_type, - NOT_WEARABLE, + NO_INV_SUBTYPE, next_owner_perm, cb); } @@ -1745,7 +1678,7 @@ void menu_create_inventory_item(LLInventoryPanel* panel, LLFolderBridge *bridge, { std::string type_name = userdata.asString(); - if (("inbox" == type_name) || ("outbox" == type_name) || ("category" == type_name) || ("current" == type_name) || ("outfit" == type_name) || ("my_otfts" == type_name)) + if (("inbox" == type_name) || ("category" == type_name) || ("current" == type_name) || ("outfit" == type_name) || ("my_otfts" == type_name)) { LLFolderType::EType preferred_type = LLFolderType::lookup(type_name); @@ -1794,6 +1727,32 @@ void menu_create_inventory_item(LLInventoryPanel* panel, LLFolderBridge *bridge, LLInventoryType::IT_GESTURE, PERM_ALL); // overridden in create_new_item } + else if (("sky" == type_name) || ("water" == type_name) || ("daycycle" == type_name)) + { + LLSettingsType::type_e stype(LLSettingsType::ST_NONE); + + if ("sky" == type_name) + { + stype = LLSettingsType::ST_SKY; + } + else if ("water" == type_name) + { + stype = LLSettingsType::ST_WATER; + } + else if ("daycycle" == type_name) + { + stype = LLSettingsType::ST_DAYCYCLE; + } + else + { + LL_ERRS(LOG_INV) << "Unknown settings type: '" << type_name << "'" << LL_ENDL; + return; + } + + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS); + + LLSettingsVOBase::createNewInventoryItem(stype, parent_id); + } else { // Use for all clothing and body parts. Adding new wearable types requires updating LLWearableDictionary. @@ -1974,6 +1933,19 @@ LLWearableType::EType LLViewerInventoryItem::getWearableType() const return LLWearableType::inventoryFlagsToWearableType(getFlags()); } +bool LLViewerInventoryItem::isSettingsType() const +{ + return (getInventoryType() == LLInventoryType::IT_SETTINGS); +} + +LLSettingsType::type_e LLViewerInventoryItem::getSettingsType() const +{ + if (!isSettingsType()) + { + return LLSettingsType::ST_NONE; + } + return LLSettingsType::fromInventoryFlags(getFlags()); +} time_t LLViewerInventoryItem::getCreationDate() const { diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index b3053e365b..24b632632b 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -31,6 +31,7 @@ #include "llframetimer.h" #include "llwearable.h" #include "llinitdestroyclass.h" //for LLDestroyClass +#include "llinventorysettings.h" #include <boost/signals2.hpp> // boost::signals2::trackable @@ -74,6 +75,9 @@ public: virtual LLInventoryType::EType getInventoryType() const; virtual bool isWearableType() const; virtual LLWearableType::EType getWearableType() const; + virtual bool isSettingsType() const; + virtual LLSettingsType::type_e getSettingsType() const; + virtual U32 getFlags() const; virtual time_t getCreationDate() const; virtual U32 getCRC32() const; // really more of a checksum. @@ -127,14 +131,8 @@ public: virtual void packMessage(LLMessageSystem* msg) const; virtual BOOL unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0); virtual BOOL unpackMessage(const LLSD& item); - virtual BOOL importFile(LLFILE* fp); virtual BOOL importLegacyStream(std::istream& input_stream); - // file handling on the viewer. These are not meant for anything - // other than cacheing. - bool exportFileLocal(LLFILE* fp) const; - bool importFileLocal(LLFILE* fp); - // new methods BOOL isFinished() const { return mIsComplete; } void setComplete(BOOL complete) { mIsComplete = complete; } @@ -222,10 +220,9 @@ public: // 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. - bool exportFileLocal(LLFILE* fp) const; - bool importFileLocal(LLFILE* fp); + LLSD exportLLSD() const; + bool importLLSD(const LLSD& cat_data); + void determineFolderType(); void changeType(LLFolderType::EType new_folder_type); virtual void unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0); @@ -295,7 +292,7 @@ public: // virtual void fire(const LLUUID& item_id) -{ + { mFireFunc(item_id); } @@ -336,17 +333,32 @@ public: extern LLInventoryCallbackManager gInventoryCallbacks; -#define NOT_WEARABLE (LLWearableType::EType)0 +const U8 NO_INV_SUBTYPE{ 0 }; // *TODO: Find a home for these void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, const LLUUID& parent, const LLTransactionID& transaction_id, const std::string& name, const std::string& desc, LLAssetType::EType asset_type, - LLInventoryType::EType inv_type, LLWearableType::EType wtype, + LLInventoryType::EType inv_type, U8 subtype, U32 next_owner_perm, LLPointer<LLInventoryCallback> cb); +void create_inventory_wearable(const LLUUID& agent_id, const LLUUID& session_id, + const LLUUID& parent, const LLTransactionID& transaction_id, + const std::string& name, + const std::string& desc, LLAssetType::EType asset_type, + LLWearableType::EType wtype, + U32 next_owner_perm, + LLPointer<LLInventoryCallback> cb); + +void create_inventory_settings(const LLUUID& agent_id, const LLUUID& session_id, + const LLUUID& parent, const LLTransactionID& transaction_id, + const std::string& name, const std::string& desc, + LLSettingsType::type_e settype, + U32 next_owner_perm, LLPointer<LLInventoryCallback> cb); + + void create_inventory_callingcard(const LLUUID& avatar_id, const LLUUID& parent = LLUUID::null, LLPointer<LLInventoryCallback> cb=NULL); /** diff --git a/indra/newview/llviewerjoint.cpp b/indra/newview/llviewerjoint.cpp index b7bd131246..9653e80b53 100644 --- a/indra/newview/llviewerjoint.cpp +++ b/indra/newview/llviewerjoint.cpp @@ -141,10 +141,11 @@ U32 LLViewerJoint::render( F32 pixelArea, BOOL first_pass, BOOL is_dummy ) //---------------------------------------------------------------- // render children //---------------------------------------------------------------- - for (child_list_t::iterator iter = mChildren.begin(); - iter != mChildren.end(); ++iter) + for (LLJoint* j : mChildren) { - LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter); + // LLViewerJoint is derived from LLAvatarJoint, + // all children of LLAvatarJoint are assumed to be LLAvatarJoint + LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(j); F32 jointLOD = joint->getLOD(); if (pixelArea >= jointLOD || sDisableLOD) { diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index cf9243a871..8a597ed7e6 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -225,7 +225,7 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object) iter != mAttachedObjects.end(); ++iter) { - LLViewerObject *attached_object = (*iter); + LLViewerObject *attached_object = iter->get(); if (attached_object == object) { break; @@ -327,7 +327,7 @@ void LLViewerJointAttachment::setAttachmentVisibility(BOOL visible) iter != mAttachedObjects.end(); ++iter) { - LLViewerObject *attached_obj = (*iter); + LLViewerObject *attached_obj = iter->get(); if (!attached_obj || attached_obj->mDrawable.isNull() || !(attached_obj->mDrawable->getSpatialBridge())) continue; @@ -366,7 +366,7 @@ S32 LLViewerJointAttachment::getNumAnimatedObjects() const iter != mAttachedObjects.end(); ++iter) { - const LLViewerObject *attached_object = *iter; + const LLViewerObject *attached_object = iter->get(); if (attached_object->isAnimatedObject()) { count++; @@ -384,7 +384,7 @@ void LLViewerJointAttachment::clampObjectPosition() iter != mAttachedObjects.end(); ++iter) { - if (LLViewerObject *attached_object = (*iter)) + if (LLViewerObject *attached_object = iter->get()) { // *NOTE: object can drift when hitting maximum radius LLVector3 attachmentPos = attached_object->getPosition(); @@ -406,7 +406,7 @@ void LLViewerJointAttachment::calcLOD() iter != mAttachedObjects.end(); ++iter) { - if (LLViewerObject *attached_object = (*iter)) + if (LLViewerObject *attached_object = iter->get()) { maxarea = llmax(maxarea,attached_object->getMaxScale() * attached_object->getMidScale()); LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); @@ -445,7 +445,7 @@ BOOL LLViewerJointAttachment::isObjectAttached(const LLViewerObject *viewer_obje iter != mAttachedObjects.end(); ++iter) { - const LLViewerObject* attached_object = (*iter); + const LLViewerObject* attached_object = iter->get(); if (attached_object == viewer_object) { return TRUE; @@ -460,7 +460,7 @@ const LLViewerObject *LLViewerJointAttachment::getAttachedObject(const LLUUID &o iter != mAttachedObjects.end(); ++iter) { - const LLViewerObject* attached_object = (*iter); + const LLViewerObject* attached_object = iter->get(); if (attached_object->getAttachmentItemID() == object_id) { return attached_object; @@ -475,7 +475,7 @@ LLViewerObject *LLViewerJointAttachment::getAttachedObject(const LLUUID &object_ iter != mAttachedObjects.end(); ++iter) { - LLViewerObject* attached_object = (*iter); + LLViewerObject* attached_object = iter->get(); if (attached_object->getAttachmentItemID() == object_id) { return attached_object; diff --git a/indra/newview/llviewerjointattachment.h b/indra/newview/llviewerjointattachment.h index 9641ab4208..e5edf2c06b 100644 --- a/indra/newview/llviewerjointattachment.h +++ b/indra/newview/llviewerjointattachment.h @@ -95,7 +95,7 @@ public: LLViewerObject *getAttachedObject(const LLUUID &object_id); // list of attachments for this joint - typedef std::vector<LLViewerObject *> attachedobjs_vec_t; + typedef std::vector<LLPointer<LLViewerObject> > attachedobjs_vec_t; attachedobjs_vec_t mAttachedObjects; protected: diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index 43a81ada49..63ad708e59 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -56,7 +56,7 @@ #include "m4math.h" #include "llmatrix4a.h" -#if !LL_DARWIN && !LL_LINUX && !LL_SOLARIS +#if !LL_DARWIN && !LL_LINUX extern PFNGLWEIGHTPOINTERARBPROC glWeightPointerARB; extern PFNGLWEIGHTFVARBPROC glWeightfvARB; extern PFNGLVERTEXBLENDARBPROC glVertexBlendARB; @@ -112,7 +112,7 @@ void LLViewerJointMesh::uploadJointMatrices() S32 joint_num; LLPolyMesh *reference_mesh = mMesh->getReferenceMesh(); LLDrawPool *poolp = mFace ? mFace->getPool() : NULL; - BOOL hardware_skinning = (poolp && poolp->getVertexShaderLevel() > 0) ? TRUE : FALSE; + BOOL hardware_skinning = (poolp && poolp->getShaderLevel() > 0) ? TRUE : FALSE; //calculate joint matrices for (joint_num = 0; joint_num < reference_mesh->mJointRenderData.size(); joint_num++) @@ -246,14 +246,13 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) stop_glerror(); - LLGLSSpecular specular(LLColor4(1.f,1.f,1.f,1.f), (mFace->getPool()->getVertexShaderLevel() > 0 || LLGLSLShader::sNoFixedFunction) ? 0.f : mShiny); + LLGLSSpecular specular(LLColor4(1.f,1.f,1.f,1.f), (mFace->getPool()->getShaderLevel() > 0 || LLGLSLShader::sNoFixedFunction) ? 0.f : mShiny); //---------------------------------------------------------------- // setup current texture //---------------------------------------------------------------- llassert( !(mTexture.notNull() && mLayerSet) ); // mutually exclusive - LLTexUnit::eTextureAddressMode old_mode = LLTexUnit::TAM_WRAP; LLViewerTexLayerSet *layerset = dynamic_cast<LLViewerTexLayerSet*>(mLayerSet); if (mTestImageName) { @@ -280,22 +279,15 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) gGL.getTexUnit(diffuse_channel)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT)); } } - else - if ( !is_dummy && mTexture.notNull() ) + 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; @@ -307,14 +299,14 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) if (mMesh->hasWeights()) { - if ((mFace->getPool()->getVertexShaderLevel() > 0)) + if ((mFace->getPool()->getShaderLevel() > 0)) { if (first_pass) { uploadJointMatrices(); } mask = mask | LLVertexBuffer::MAP_WEIGHT; - if (mFace->getPool()->getVertexShaderLevel() > 1) + if (mFace->getPool()->getShaderLevel() > 1) { mask = mask | LLVertexBuffer::MAP_CLOTHWEIGHT; } @@ -341,12 +333,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; } @@ -390,7 +376,7 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w } LLDrawPool *poolp = mFace->getPool(); - BOOL hardware_skinning = (poolp && poolp->getVertexShaderLevel() > 0) ? TRUE : FALSE; + BOOL hardware_skinning = (poolp && poolp->getShaderLevel() > 0) ? TRUE : FALSE; if (!hardware_skinning && terse_update) { //no need to do terse updates if we're doing software vertex skinning @@ -538,7 +524,7 @@ void LLViewerJointMesh::updateJointGeometry() && mFace && mMesh->hasWeights() && mFace->getVertexBuffer() - && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) == 0)) + && LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) == 0)) { return; } diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp index e44d80b7ce..e35cb26ce1 100644 --- a/indra/newview/llviewerjoystick.cpp +++ b/indra/newview/llviewerjoystick.cpp @@ -36,10 +36,19 @@ #include "lltoolmgr.h" #include "llselectmgr.h" #include "llviewermenu.h" +#include "llviewerwindow.h" +#include "llwindow.h" #include "llagent.h" #include "llagentcamera.h" #include "llfocusmgr.h" +#if LL_WINDOWS && !LL_MESA_HEADLESS +// Require DirectInput version 8 +#define DIRECTINPUT_VERSION 0x0800 + +#include <dinput.h> +#endif + // ---------------------------------------------------------------------------- // Constants @@ -62,6 +71,164 @@ F32 LLViewerJoystick::sDelta[] = {0,0,0,0,0,0,0}; #define MAX_SPACENAVIGATOR_INPUT 3000.0f #define MAX_JOYSTICK_INPUT_VALUE MAX_SPACENAVIGATOR_INPUT + +#if LIB_NDOF +std::ostream& operator<<(std::ostream& out, NDOF_Device* ptr) +{ + if (! ptr) + { + return out << "nullptr"; + } + out << "NDOF_Device{ "; + out << "axes ["; + const char* delim = ""; + for (short axis = 0; axis < ptr->axes_count; ++axis) + { + out << delim << ptr->axes[axis]; + delim = ", "; + } + out << "]"; + out << ", buttons ["; + delim = ""; + for (short button = 0; button < ptr->btn_count; ++button) + { + out << delim << ptr->buttons[button]; + delim = ", "; + } + out << "]"; + out << ", range " << ptr->axes_min << ':' << ptr->axes_max; + // If we don't coerce these to unsigned, they're streamed as characters, + // e.g. ctrl-A or nul. + out << ", absolute " << unsigned(ptr->absolute); + out << ", valid " << unsigned(ptr->valid); + out << ", manufacturer '" << ptr->manufacturer << "'"; + out << ", product '" << ptr->product << "'"; + out << ", private " << ptr->private_data; + out << " }"; + return out; +} +#endif // LIB_NDOF + + +#if LL_WINDOWS && !LL_MESA_HEADLESS +// this should reflect ndof and set axises, see ndofdev_win.cpp from ndof package +BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* inst, VOID* user_data) +{ + if (inst->dwType & DIDFT_AXIS) + { + LPDIRECTINPUTDEVICE8 device = *((LPDIRECTINPUTDEVICE8 *)user_data); + DIPROPRANGE diprg; + diprg.diph.dwSize = sizeof(DIPROPRANGE); + diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); + diprg.diph.dwHow = DIPH_BYID; + diprg.diph.dwObj = inst->dwType; // specify the enumerated axis + + // Set the range for the axis + diprg.lMin = (long)-MAX_JOYSTICK_INPUT_VALUE; + diprg.lMax = (long)+MAX_JOYSTICK_INPUT_VALUE; + HRESULT hr = device->SetProperty(DIPROP_RANGE, &diprg.diph); + + if (FAILED(hr)) + { + return DIENUM_STOP; + } + } + + return DIENUM_CONTINUE; +} + +BOOL CALLBACK di8_devices_callback(LPCDIDEVICEINSTANCE device_instance_ptr, LPVOID pvRef) +{ + // Note: If a single device can function as more than one DirectInput + // device type, it is enumerated as each device type that it supports. + // Capable of detecting devices like Oculus Rift + if (device_instance_ptr) + { + std::string product_name = utf16str_to_utf8str(llutf16string(device_instance_ptr->tszProductName)); + + LLSD guid = LLViewerJoystick::getInstance()->getDeviceUUID(); + + bool init_device = false; + if (guid.isBinary()) + { + std::vector<U8> bin_bucket = guid.asBinary(); + init_device = memcmp(&bin_bucket[0], &device_instance_ptr->guidInstance, sizeof(GUID)) == 0; + } + else + { + // It might be better to init space navigator here, but if system doesn't has one, + // ndof will pick a random device, it is simpler to pick first device now to have an id + init_device = true; + } + + if (init_device) + { + LL_DEBUGS("Joystick") << "Found and attempting to use device: " << product_name << LL_ENDL; + LPDIRECTINPUT8 di8_interface = *((LPDIRECTINPUT8 *)gViewerWindow->getWindow()->getDirectInput8()); + LPDIRECTINPUTDEVICE8 device = NULL; + + HRESULT status = di8_interface->CreateDevice( + device_instance_ptr->guidInstance, // REFGUID rguid, + &device, // LPDIRECTINPUTDEVICE * lplpDirectInputDevice, + NULL // LPUNKNOWN pUnkOuter + ); + + if (status == DI_OK) + { + // prerequisite for aquire() + LL_DEBUGS("Joystick") << "Device created" << LL_ENDL; + status = device->SetDataFormat(&c_dfDIJoystick); // c_dfDIJoystick2 + } + + if (status == DI_OK) + { + // set properties + LL_DEBUGS("Joystick") << "Format set" << LL_ENDL; + status = device->EnumObjects(EnumObjectsCallback, &device, DIDFT_ALL); + } + + if (status == DI_OK) + { + LL_DEBUGS("Joystick") << "Properties updated" << LL_ENDL; + + S32 size = sizeof(GUID); + LLSD::Binary data; //just an std::vector + data.resize(size); + memcpy(&data[0], &device_instance_ptr->guidInstance /*POD _GUID*/, size); + LLViewerJoystick::getInstance()->initDevice(&device, product_name, LLSD(data)); + return DIENUM_STOP; + } + } + else + { + LL_DEBUGS("Joystick") << "Found device: " << product_name << LL_ENDL; + } + } + return DIENUM_CONTINUE; +} + +// Windows guids +// This is GUID2 so teoretically it can be memcpy copied into LLUUID +void guid_from_string(GUID &guid, const std::string &input) +{ + CLSIDFromString(utf8str_to_utf16str(input).c_str(), &guid); +} + +std::string string_from_guid(const GUID &guid) +{ + OLECHAR* guidString; //wchat + StringFromCLSID(guid, &guidString); + + // use guidString... + + std::string res = utf16str_to_utf8str(llutf16string(guidString)); + // ensure memory is freed + ::CoTaskMemFree(guidString); + + return res; +} +#endif + // ----------------------------------------------------------------------------- void LLViewerJoystick::updateEnabled(bool autoenable) { @@ -71,7 +238,8 @@ void LLViewerJoystick::updateEnabled(bool autoenable) } else { - if (isLikeSpaceNavigator() && autoenable) + // autoenable if user specifically chose this device + if (autoenable && (isLikeSpaceNavigator() || isDeviceUUIDSet())) { gSavedSettings.setBOOL("JoystickEnabled", TRUE ); } @@ -107,11 +275,11 @@ NDOF_HotPlugResult LLViewerJoystick::HotPlugAddCallback(NDOF_Device *dev) LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); if (joystick->mDriverState == JDS_UNINITIALIZED) { - LL_INFOS() << "HotPlugAddCallback: will use device:" << LL_ENDL; - ndof_dump(dev); + LL_INFOS("Joystick") << "HotPlugAddCallback: will use device:" << LL_ENDL; + ndof_dump(stderr, dev); joystick->mNdofDev = dev; - joystick->mDriverState = JDS_INITIALIZED; - res = NDOF_KEEP_HOTPLUGGED; + joystick->mDriverState = JDS_INITIALIZED; + res = NDOF_KEEP_HOTPLUGGED; } joystick->updateEnabled(true); return res; @@ -125,9 +293,9 @@ void LLViewerJoystick::HotPlugRemovalCallback(NDOF_Device *dev) LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); if (joystick->mNdofDev == dev) { - LL_INFOS() << "HotPlugRemovalCallback: joystick->mNdofDev=" + LL_INFOS("Joystick") << "HotPlugRemovalCallback: joystick->mNdofDev=" << joystick->mNdofDev << "; removed device:" << LL_ENDL; - ndof_dump(dev); + ndof_dump(stderr, dev); joystick->mDriverState = JDS_UNINITIALIZED; } joystick->updateEnabled(true); @@ -152,6 +320,8 @@ LLViewerJoystick::LLViewerJoystick() // factor in bandwidth? bandwidth = gViewerStats->mKBitStat mPerfScale = 4000.f / gSysCPU.getMHz(); // hmm. why? + + mLastDeviceUUID = LLSD::Integer(1); } // ----------------------------------------------------------------------------- @@ -170,12 +340,14 @@ void LLViewerJoystick::init(bool autoenable) static bool libinit = false; mDriverState = JDS_INITIALIZING; + loadDeviceIdFromSettings(); + if (libinit == false) { // Note: The HotPlug callbacks are not actually getting called on Windows if (ndof_libinit(HotPlugAddCallback, HotPlugRemovalCallback, - NULL)) + gViewerWindow->getWindow()->getDirectInput8())) { mDriverState = JDS_UNINITIALIZED; } @@ -192,35 +364,33 @@ void LLViewerJoystick::init(bool autoenable) if (libinit) { if (mNdofDev) - { - // Different joysticks will return different ranges of raw values. - // Since we want to handle every device in the same uniform way, - // we initialize the mNdofDev struct and we set the range - // of values we would like to receive. - // - // HACK: On Windows, libndofdev passes our range to DI with a - // SetProperty call. This works but with one notable exception, the - // SpaceNavigator, who doesn't seem to care about the SetProperty - // call. In theory, we should handle this case inside libndofdev. - // However, the range we're setting here is arbitrary anyway, - // so let's just use the SpaceNavigator range for our purposes. - mNdofDev->axes_min = (long)-MAX_JOYSTICK_INPUT_VALUE; - mNdofDev->axes_max = (long)+MAX_JOYSTICK_INPUT_VALUE; - - // libndofdev could be used to return deltas. Here we choose to - // just have the absolute values instead. - mNdofDev->absolute = 1; - - // init & use the first suitable NDOF device found on the USB chain - if (ndof_init_first(mNdofDev, NULL)) - { - mDriverState = JDS_UNINITIALIZED; - LL_WARNS() << "ndof_init_first FAILED" << LL_ENDL; - } - else - { - mDriverState = JDS_INITIALIZED; - } + { + // di8_devices_callback callback is immediate and happens in scope of getInputDevices() +#if LL_WINDOWS && !LL_MESA_HEADLESS + // space navigator is marked as DI8DEVCLASS_GAMECTRL in ndof lib + U32 device_type = DI8DEVCLASS_GAMECTRL; + void* callback = &di8_devices_callback; +#else + // MAC doesn't support device search yet + // On MAC there is an ndof_idsearch and it is possible to specify product + // and manufacturer in NDOF_Device for ndof_init_first to pick specific one + U32 device_type = 0; + void* callback = NULL; +#endif + if (!gViewerWindow->getWindow()->getInputDevices(device_type, callback, NULL)) + { + LL_INFOS("Joystick") << "Failed to gather devices from window. Falling back to ndof's init" << LL_ENDL; + // Failed to gather devices from windows, init first suitable one + mLastDeviceUUID = LLSD(); + void *preffered_device = NULL; + initDevice(preffered_device); + } + + if (mDriverState == JDS_INITIALIZING) + { + LL_INFOS("Joystick") << "Found no matching joystick devices." << LL_ENDL; + mDriverState = JDS_UNINITIALIZED; + } } else { @@ -258,20 +428,104 @@ void LLViewerJoystick::init(bool autoenable) { // No device connected, don't change any settings } - - LL_INFOS() << "ndof: mDriverState=" << mDriverState << "; mNdofDev=" + + LL_INFOS("Joystick") << "ndof: mDriverState=" << mDriverState << "; mNdofDev=" << mNdofDev << "; libinit=" << libinit << LL_ENDL; #endif } +void LLViewerJoystick::initDevice(LLSD &guid) +{ +#if LIB_NDOF + mLastDeviceUUID = guid; + +#if LL_WINDOWS && !LL_MESA_HEADLESS + // space navigator is marked as DI8DEVCLASS_GAMECTRL in ndof lib + U32 device_type = DI8DEVCLASS_GAMECTRL; + void* callback = &di8_devices_callback; +#else + // MAC doesn't support device search yet + // On MAC there is an ndof_idsearch and it is possible to specify product + // and manufacturer in NDOF_Device for ndof_init_first to pick specific one + U32 device_type = 0; + void* callback = NULL; +#endif + + mDriverState = JDS_INITIALIZING; + if (!gViewerWindow->getWindow()->getInputDevices(device_type, callback, NULL)) + { + LL_INFOS("Joystick") << "Failed to gather devices from window. Falling back to ndof's init" << LL_ENDL; + // Failed to gather devices from windows, init first suitable one + void *preffered_device = NULL; + mLastDeviceUUID = LLSD(); + initDevice(preffered_device); + } + + if (mDriverState == JDS_INITIALIZING) + { + LL_INFOS("Joystick") << "Found no matching joystick devices." << LL_ENDL; + mDriverState = JDS_UNINITIALIZED; + } +#endif +} + +void LLViewerJoystick::initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/, std::string &name, LLSD &guid) +{ +#if LIB_NDOF + mLastDeviceUUID = guid; + + strncpy(mNdofDev->product, name.c_str(), sizeof(mNdofDev->product)); + mNdofDev->manufacturer[0] = '\0'; + + initDevice(preffered_device); +#endif +} + +void LLViewerJoystick::initDevice(void * preffered_device /* LPDIRECTINPUTDEVICE8* */) +{ +#if LIB_NDOF + // Different joysticks will return different ranges of raw values. + // Since we want to handle every device in the same uniform way, + // we initialize the mNdofDev struct and we set the range + // of values we would like to receive. + // + // HACK: On Windows, libndofdev passes our range to DI with a + // SetProperty call. This works but with one notable exception, the + // SpaceNavigator, who doesn't seem to care about the SetProperty + // call. In theory, we should handle this case inside libndofdev. + // However, the range we're setting here is arbitrary anyway, + // so let's just use the SpaceNavigator range for our purposes. + mNdofDev->axes_min = (long)-MAX_JOYSTICK_INPUT_VALUE; + mNdofDev->axes_max = (long)+MAX_JOYSTICK_INPUT_VALUE; + + // libndofdev could be used to return deltas. Here we choose to + // just have the absolute values instead. + mNdofDev->absolute = 1; + // init & use the first suitable NDOF device found on the USB chain + // On windows preffered_device needs to be a pointer to LPDIRECTINPUTDEVICE8 + if (ndof_init_first(mNdofDev, preffered_device)) + { + mDriverState = JDS_UNINITIALIZED; + LL_WARNS() << "ndof_init_first FAILED" << LL_ENDL; + } + else + { + mDriverState = JDS_INITIALIZED; + } +#endif +} + // ----------------------------------------------------------------------------- void LLViewerJoystick::terminate() { #if LIB_NDOF - - ndof_libcleanup(); - LL_INFOS() << "Terminated connection with NDOF device." << LL_ENDL; - mDriverState = JDS_UNINITIALIZED; + if (mNdofDev != NULL) + { + ndof_libcleanup(); // frees alocated memory in mNdofDev + mDriverState = JDS_UNINITIALIZED; + mNdofDev = NULL; + LL_INFOS("Joystick") << "Terminated connection with NDOF device." << LL_ENDL; + } #endif } @@ -1061,6 +1315,74 @@ void LLViewerJoystick::scanJoystick() } // ----------------------------------------------------------------------------- +bool LLViewerJoystick::isDeviceUUIDSet() +{ +#if LL_WINDOWS && !LL_MESA_HEADLESS + // for ease of comparison and to dial less with platform specific variables, we store id as LLSD binary + return mLastDeviceUUID.isBinary(); +#else + return false; +#endif +} + +LLSD LLViewerJoystick::getDeviceUUID() +{ + return mLastDeviceUUID; +} + +std::string LLViewerJoystick::getDeviceUUIDString() +{ +#if LL_WINDOWS && !LL_MESA_HEADLESS + // Might be simpler to just convert _GUID into string everywhere, store and compare as string + if (mLastDeviceUUID.isBinary()) + { + S32 size = sizeof(GUID); + LLSD::Binary data = mLastDeviceUUID.asBinary(); + GUID guid; + memcpy(&guid, &data[0], size); + return string_from_guid(guid); + } + else + { + return std::string(); + } +#else + return std::string(); + // return mLastDeviceUUID; +#endif +} + +void LLViewerJoystick::loadDeviceIdFromSettings() +{ +#if LL_WINDOWS && !LL_MESA_HEADLESS + // We can't save binary data to gSavedSettings, somebody editing the file will corrupt it, + // so _GUID data gets converted to string (we probably can convert it to LLUUID with memcpy) + // and here we need to convert it back to binary from string + std::string device_string = gSavedSettings.getString("JoystickDeviceUUID"); + if (device_string.empty()) + { + mLastDeviceUUID = LLSD(); + } + else + { + LL_DEBUGS("Joystick") << "Looking for device by id: " << device_string << LL_ENDL; + GUID guid; + guid_from_string(guid, device_string); + S32 size = sizeof(GUID); + LLSD::Binary data; //just an std::vector + data.resize(size); + memcpy(&data[0], &guid /*POD _GUID*/, size); + // We store this data in LLSD since LLSD is versatile and will be able to handle both GUID2 + // and any data MAC will need for device selection + mLastDeviceUUID = LLSD(data); + } +#else + mLastDeviceUUID = LLSD(); + //mLastDeviceUUID = gSavedSettings.getLLSD("JoystickDeviceUUID"); +#endif +} + +// ----------------------------------------------------------------------------- std::string LLViewerJoystick::getDescription() { std::string res; @@ -1075,7 +1397,7 @@ std::string LLViewerJoystick::getDescription() bool LLViewerJoystick::isLikeSpaceNavigator() const { -#if LIB_NDOF +#if LIB_NDOF return (isJoystickInitialized() && (strncmp(mNdofDev->product, "SpaceNavigator", 14) == 0 || strncmp(mNdofDev->product, "SpaceExplorer", 13) == 0 @@ -1099,10 +1421,10 @@ void LLViewerJoystick::setSNDefaults() const float platformScaleAvXZ = 2.f; const bool is_3d_cursor = true; #endif - + //gViewerWindow->alertXml("CacheWillClear"); - LL_INFOS() << "restoring SpaceNavigator defaults..." << LL_ENDL; - + LL_INFOS("Joystick") << "restoring SpaceNavigator defaults..." << LL_ENDL; + gSavedSettings.setS32("JoystickAxis0", 1); // z (at) gSavedSettings.setS32("JoystickAxis1", 0); // x (slide) gSavedSettings.setS32("JoystickAxis2", 2); // y (up) @@ -1110,11 +1432,11 @@ void LLViewerJoystick::setSNDefaults() gSavedSettings.setS32("JoystickAxis4", 3); // roll gSavedSettings.setS32("JoystickAxis5", 5); // yaw gSavedSettings.setS32("JoystickAxis6", -1); - + gSavedSettings.setBOOL("Cursor3D", 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); diff --git a/indra/newview/llviewerjoystick.h b/indra/newview/llviewerjoystick.h index 016b435ee8..782c523d4f 100644 --- a/indra/newview/llviewerjoystick.h +++ b/indra/newview/llviewerjoystick.h @@ -50,6 +50,9 @@ class LLViewerJoystick : public LLSingleton<LLViewerJoystick> public: void init(bool autoenable); + void initDevice(LLSD &guid); + void initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/); + void initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/, std::string &name, LLSD &guid); void terminate(); void updateStatus(); @@ -68,8 +71,11 @@ public: void setOverrideCamera(bool val); bool toggleFlycam(); void setSNDefaults(); + bool isDeviceUUIDSet(); + LLSD getDeviceUUID(); //unconverted, OS dependent value wrapped into LLSD, for comparison/search + std::string getDeviceUUIDString(); // converted readable value for settings std::string getDescription(); - + protected: void updateEnabled(bool autoenable); void handleRun(F32 inc); @@ -80,6 +86,7 @@ protected: void agentYaw(F32 yaw_inc); void agentJump(); void resetDeltas(S32 axis[]); + void loadDeviceIdFromSettings(); #if LIB_NDOF static NDOF_HotPlugResult HotPlugAddCallback(NDOF_Device *dev); static void HotPlugRemovalCallback(NDOF_Device *dev); @@ -95,6 +102,7 @@ private: bool mCameraUpdated; bool mOverrideCamera; U32 mJoystickRun; + LLSD mLastDeviceUUID; // _GUID as U8 binary map, integer 1 for no device/ndof's device static F32 sLastDelta[7]; static F32 sDelta[7]; diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp deleted file mode 100644 index e930eb20d3..0000000000 --- a/indra/newview/llviewerkeyboard.cpp +++ /dev/null @@ -1,1032 +0,0 @@ -/** - * @file llviewerkeyboard.cpp - * @brief LLViewerKeyboard class implementation - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llappviewer.h" -#include "llfloaterreg.h" -#include "llviewerkeyboard.h" -#include "llmath.h" -#include "llagent.h" -#include "llagentcamera.h" -#include "llfloaterimnearbychat.h" -#include "llviewercontrol.h" -#include "llfocusmgr.h" -#include "llmorphview.h" -#include "llmoveview.h" -#include "lltoolfocus.h" -#include "llviewerwindow.h" -#include "llvoavatarself.h" -#include "llfloatercamera.h" -#include "llinitparam.h" - -// -// Constants -// - -const F32 FLY_TIME = 0.5f; -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 - -struct LLKeyboardActionRegistry -: public LLRegistrySingleton<std::string, boost::function<void (EKeystate keystate)>, LLKeyboardActionRegistry> -{ - LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry); -}; - -LLViewerKeyboard gViewerKeyboard; - -void agent_jump( EKeystate s ) -{ - static BOOL first_fly_attempt(TRUE); - if (KEYSTATE_UP == s) - { - first_fly_attempt = TRUE; - return; - } - F32 time = gKeyboard->getCurKeyElapsedTime(); - S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount()); - - if( time < FLY_TIME - || frame_count <= FLY_FRAMES - || gAgent.upGrabbed() - || !gSavedSettings.getBOOL("AutomaticFly")) - { - gAgent.moveUp(1); - } - else - { - gAgent.setFlying(TRUE, first_fly_attempt); - first_fly_attempt = FALSE; - gAgent.moveUp(1); - } -} - -void agent_push_down( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgent.moveUp(-1); -} - -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()); - } -} - -static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode mode) -{ - if (KEYSTATE_UP == s) - { - // 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 && - !gAgent.getRunning()) - { - if (gAgent.mDoubleTapRunMode == mode && - gAgent.mDoubleTapRunTimer.getElapsedTimeF32() < NUDGE_TIME) - { - // Same walk-key was pushed again quickly; this is a - // double-tap so engage temporary running. - gAgent.setRunning(); - gAgent.sendWalkRun(gAgent.getRunning()); - } - - // Pressing any walk-key resets the double-tap timer - gAgent.mDoubleTapRunTimer.reset(); - gAgent.mDoubleTapRunMode = mode; - } -} - -static void agent_push_forwardbackward( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode ) -{ - agent_handle_doubletap_run(s, mode); - if (KEYSTATE_UP == s) return; - - F32 time = gKeyboard->getCurKeyElapsedTime(); - S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount()); - - if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES) - { - gAgent.moveAtNudge(direction); - } - else - { - gAgent.moveAt(direction); - } -} - -void camera_move_forward( EKeystate s ); - -void agent_push_forward( EKeystate s ) -{ - if(gAgent.isMovementLocked()) return; - - //in free camera control mode we need to intercept keyboard events for avatar movements - if (LLFloaterCamera::inFreeCameraMode()) - { - camera_move_forward(s); - } - else - { - agent_push_forwardbackward(s, 1, LLAgent::DOUBLETAP_FORWARD); - } -} - -void camera_move_backward( EKeystate s ); - -void agent_push_backward( EKeystate s ) -{ - if(gAgent.isMovementLocked()) return; - - //in free camera control mode we need to intercept keyboard events for avatar movements - if (LLFloaterCamera::inFreeCameraMode()) - { - camera_move_backward(s); - } - else if (!gAgent.backwardGrabbed() && gAgentAvatarp->isSitting() && gSavedSettings.getBOOL("LeaveMouselook")) - { - gAgentCamera.changeCameraToThirdPerson(); - } - else - { - agent_push_forwardbackward(s, -1, LLAgent::DOUBLETAP_BACKWARD); - } -} - -static void agent_slide_leftright( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode ) -{ - agent_handle_doubletap_run(s, mode); - if( KEYSTATE_UP == s ) return; - F32 time = gKeyboard->getCurKeyElapsedTime(); - S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount()); - - if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES) - { - gAgent.moveLeftNudge(direction); - } - else - { - gAgent.moveLeft(direction); - } -} - - -void agent_slide_left( EKeystate s ) -{ - if(gAgent.isMovementLocked()) return; - agent_slide_leftright(s, 1, LLAgent::DOUBLETAP_SLIDELEFT); -} - - -void agent_slide_right( EKeystate s ) -{ - if(gAgent.isMovementLocked()) return; - agent_slide_leftright(s, -1, LLAgent::DOUBLETAP_SLIDERIGHT); -} - -void camera_spin_around_cw( EKeystate s ); - -void agent_turn_left( EKeystate s ) -{ - //in free camera control mode we need to intercept keyboard events for avatar movements - if (LLFloaterCamera::inFreeCameraMode()) - { - camera_spin_around_cw(s); - return; - } - - if(gAgent.isMovementLocked()) return; - - if (LLToolCamera::getInstance()->mouseSteerMode()) - { - agent_slide_left(s); - } - else - { - if (KEYSTATE_UP == s) - { - // Check temporary running. In case user released 'left' key with shift already released. - agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDELEFT); - return; - } - F32 time = gKeyboard->getCurKeyElapsedTime(); - gAgent.moveYaw( LLFloaterMove::getYawRate( time ) ); - } -} - -void camera_spin_around_ccw( EKeystate s ); - -void agent_turn_right( EKeystate s ) -{ - //in free camera control mode we need to intercept keyboard events for avatar movements - if (LLFloaterCamera::inFreeCameraMode()) - { - camera_spin_around_ccw(s); - return; - } - - if(gAgent.isMovementLocked()) return; - - if (LLToolCamera::getInstance()->mouseSteerMode()) - { - agent_slide_right(s); - } - else - { - if (KEYSTATE_UP == s) - { - // Check temporary running. In case user released 'right' key with shift already released. - agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDERIGHT); - return; - } - F32 time = gKeyboard->getCurKeyElapsedTime(); - gAgent.moveYaw( -LLFloaterMove::getYawRate( time ) ); - } -} - -void agent_look_up( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgent.movePitch(-1); - //gAgent.rotate(-2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() ); -} - - -void agent_look_down( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgent.movePitch(1); - //gAgent.rotate(2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() ); -} - -void agent_toggle_fly( EKeystate s ) -{ - // Only catch the edge - if (KEYSTATE_DOWN == s ) - { - LLAgent::toggleFlying(); - } -} - -F32 get_orbit_rate() -{ - F32 time = gKeyboard->getCurKeyElapsedTime(); - if( time < NUDGE_TIME ) - { - F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME; - //LL_INFOS() << rate << LL_ENDL; - return rate; - } - else - { - return 1; - } -} - -void camera_spin_around_ccw( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setOrbitLeftKey( get_orbit_rate() ); -} - - -void camera_spin_around_cw( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setOrbitRightKey( get_orbit_rate() ); -} - -void camera_spin_around_ccw_sitting( EKeystate s ) -{ - if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT ) return; - if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning()) - { - //send keystrokes, but do not change camera - agent_turn_right(s); - } - else - { - //change camera but do not send keystrokes - gAgentCamera.setOrbitLeftKey( get_orbit_rate() ); - } -} - - -void camera_spin_around_cw_sitting( EKeystate s ) -{ - if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT ) return; - if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning()) - { - //send keystrokes, but do not change camera - agent_turn_left(s); - } - else - { - //change camera but do not send keystrokes - gAgentCamera.setOrbitRightKey( get_orbit_rate() ); - } -} - - -void camera_spin_over( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setOrbitUpKey( get_orbit_rate() ); -} - - -void camera_spin_under( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setOrbitDownKey( get_orbit_rate() ); -} - -void camera_spin_over_sitting( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - if (gAgent.upGrabbed() || gAgentCamera.sitCameraEnabled()) - { - //send keystrokes, but do not change camera - agent_jump(s); - } - else - { - //change camera but do not send keystrokes - gAgentCamera.setOrbitUpKey( get_orbit_rate() ); - } -} - - -void camera_spin_under_sitting( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - if (gAgent.downGrabbed() || gAgentCamera.sitCameraEnabled()) - { - //send keystrokes, but do not change camera - agent_push_down(s); - } - else - { - //change camera but do not send keystrokes - gAgentCamera.setOrbitDownKey( get_orbit_rate() ); - } -} - -void camera_move_forward( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setOrbitInKey( get_orbit_rate() ); -} - - -void camera_move_backward( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setOrbitOutKey( get_orbit_rate() ); -} - -void camera_move_forward_sitting( EKeystate s ) -{ - if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD ) return; - if (gAgent.forwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun())) - { - agent_push_forward(s); - } - else - { - gAgentCamera.setOrbitInKey( get_orbit_rate() ); - } -} - - -void camera_move_backward_sitting( EKeystate s ) -{ - if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD ) return; - - if (gAgent.backwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun())) - { - agent_push_backward(s); - } - else - { - gAgentCamera.setOrbitOutKey( get_orbit_rate() ); - } -} - -void camera_pan_up( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setPanUpKey( get_orbit_rate() ); -} - -void camera_pan_down( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setPanDownKey( get_orbit_rate() ); -} - -void camera_pan_left( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setPanLeftKey( get_orbit_rate() ); -} - -void camera_pan_right( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setPanRightKey( get_orbit_rate() ); -} - -void camera_pan_in( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setPanInKey( get_orbit_rate() ); -} - -void camera_pan_out( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setPanOutKey( get_orbit_rate() ); -} - -void camera_move_forward_fast( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setOrbitInKey(2.5f); -} - -void camera_move_backward_fast( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setOrbitOutKey(2.5f); -} - - -void edit_avatar_spin_ccw( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gMorphView->setCameraDrivenByKeys( TRUE ); - gAgentCamera.setOrbitLeftKey( get_orbit_rate() ); - //gMorphView->orbitLeft( get_orbit_rate() ); -} - - -void edit_avatar_spin_cw( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gMorphView->setCameraDrivenByKeys( TRUE ); - gAgentCamera.setOrbitRightKey( get_orbit_rate() ); - //gMorphView->orbitRight( get_orbit_rate() ); -} - -void edit_avatar_spin_over( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gMorphView->setCameraDrivenByKeys( TRUE ); - gAgentCamera.setOrbitUpKey( get_orbit_rate() ); - //gMorphView->orbitUp( get_orbit_rate() ); -} - - -void edit_avatar_spin_under( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gMorphView->setCameraDrivenByKeys( TRUE ); - gAgentCamera.setOrbitDownKey( get_orbit_rate() ); - //gMorphView->orbitDown( get_orbit_rate() ); -} - -void edit_avatar_move_forward( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gMorphView->setCameraDrivenByKeys( TRUE ); - gAgentCamera.setOrbitInKey( get_orbit_rate() ); - //gMorphView->orbitIn(); -} - - -void edit_avatar_move_backward( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gMorphView->setCameraDrivenByKeys( TRUE ); - gAgentCamera.setOrbitOutKey( get_orbit_rate() ); - //gMorphView->orbitOut(); -} - -void stop_moving( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - // stop agent - gAgent.setControlFlags(AGENT_CONTROL_STOP); - - // cancel autopilot - gAgent.stopAutoPilot(); -} - -void start_chat( EKeystate s ) -{ - if (LLAppViewer::instance()->quitRequested()) - { - return; // can't talk, gotta go, kthxbye! - } - - // start chat - LLFloaterIMNearbyChat::startChat(NULL); -} - -void start_gesture( EKeystate s ) -{ - LLUICtrl* focus_ctrlp = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); - if (KEYSTATE_UP == s && - ! (focus_ctrlp && focus_ctrlp->acceptsTextInput())) - { - if ((LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"))->getCurrentChat().empty()) - { - // No existing chat in chat editor, insert '/' - LLFloaterIMNearbyChat::startChat("/"); - } - else - { - // Don't overwrite existing text in chat editor - LLFloaterIMNearbyChat::startChat(NULL); - } - } -} - -#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("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); -#undef REGISTER_KEYBOARD_ACTION - -LLViewerKeyboard::LLViewerKeyboard() -{ - for (S32 i = 0; i < MODE_COUNT; i++) - { - mBindingCount[i] = 0; - } - - for (S32 i = 0; i < KEY_COUNT; i++) - { - mKeyHandledByUI[i] = FALSE; - } - // we want the UI to never see these keys so that they can always control the avatar/camera - for(KEY k = KEY_PAD_UP; k <= KEY_PAD_DIVIDE; k++) - { - mKeysSkippedByUI.insert(k); - } -} - -BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode) -{ - if (string == "FIRST_PERSON") - { - *mode = MODE_FIRST_PERSON; - return TRUE; - } - else if (string == "THIRD_PERSON") - { - *mode = MODE_THIRD_PERSON; - return TRUE; - } - else if (string == "EDIT") - { - *mode = MODE_EDIT; - return TRUE; - } - else if (string == "EDIT_AVATAR") - { - *mode = MODE_EDIT_AVATAR; - return TRUE; - } - else if (string == "SITTING") - { - *mode = MODE_SITTING; - return TRUE; - } - else - { - *mode = MODE_THIRD_PERSON; - return FALSE; - } -} - -BOOL LLViewerKeyboard::handleKey(KEY translated_key, MASK translated_mask, BOOL repeated) -{ - // check for re-map - EKeyboardMode mode = gViewerKeyboard.getMode(); - U32 keyidx = (translated_mask<<16) | translated_key; - key_remap_t::iterator iter = mRemapKeys[mode].find(keyidx); - if (iter != mRemapKeys[mode].end()) - { - translated_key = (iter->second) & 0xff; - translated_mask = (iter->second)>>16; - } - - // No repeats of F-keys - BOOL repeatable_key = (translated_key < KEY_F1 || translated_key > KEY_F12); - if (!repeatable_key && repeated) - { - return FALSE; - } - - LL_DEBUGS("UserInput") << "keydown -" << translated_key << "-" << LL_ENDL; - // skip skipped keys - if(mKeysSkippedByUI.find(translated_key) != mKeysSkippedByUI.end()) - { - mKeyHandledByUI[translated_key] = FALSE; - LL_INFOS("KeyboardHandling") << "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 index; - typedef boost::function<void(EKeystate)> function_t; - function_t function = NULL; - std::string name; - - // Allow remapping of F2-F12 - if (function_name[0] == 'F') - { - int c1 = function_name[1] - '0'; - int c2 = function_name[2] ? function_name[2] - '0' : -1; - if (c1 >= 0 && c1 <= 9 && c2 >= -1 && c2 <= 9) - { - int idx = c1; - if (c2 >= 0) - idx = idx*10 + c2; - if (idx >=2 && idx <= 12) - { - U32 keyidx = ((mask<<16)|key); - (mRemapKeys[mode])[keyidx] = ((0<<16)|(KEY_F1+(idx-1))); - return TRUE; - } - } - } - - // Not remapped, look for a function - - function_t* result = LLKeyboardActionRegistry::getValue(function_name); - if (result) - { - function = *result; - } - - if (!function) - { - LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; - return FALSE; - } - - // check for duplicate first and overwrite - for (index = 0; index < mBindingCount[mode]; index++) - { - if (key == mBindings[mode][index].mKey && mask == mBindings[mode][index].mMask) - break; - } - - if (index >= MAX_KEY_BINDINGS) - { - LL_ERRS() << "LLKeyboard::bindKey() - too many keys for mode " << mode << LL_ENDL; - return FALSE; - } - - if (mode >= MODE_COUNT) - { - 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].mFunction = function; - - if (index == mBindingCount[mode]) - mBindingCount[mode]++; - - 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<KeyBinding>::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) -{ - LLFILE *fp; - const S32 BUFFER_SIZE = 2048; - char buffer[BUFFER_SIZE]; /* Flawfinder: ignore */ - // *NOTE: This buffer size is hard coded into scanf() below. - char mode_string[MAX_STRING] = ""; /* Flawfinder: ignore */ - char key_string[MAX_STRING] = ""; /* Flawfinder: ignore */ - char mask_string[MAX_STRING] = ""; /* Flawfinder: ignore */ - char function_string[MAX_STRING] = ""; /* Flawfinder: ignore */ - S32 mode = MODE_THIRD_PERSON; - KEY key = 0; - MASK mask = 0; - S32 tokens_read; - S32 binding_count = 0; - S32 line_count = 0; - - if(filename.empty()) - { - LL_ERRS() << " No filename specified" << LL_ENDL; - return 0; - } - - fp = LLFile::fopen(filename, "r"); - - if (!fp) - { - return 0; - } - - - while (!feof(fp)) - { - line_count++; - if (!fgets(buffer, BUFFER_SIZE, fp)) - break; - - // skip over comments, blank lines - if (buffer[0] == '#' || buffer[0] == '\n') continue; - - // grab the binding strings - tokens_read = sscanf( /* Flawfinder: ignore */ - buffer, - "%254s %254s %254s %254s", - mode_string, - key_string, - mask_string, - function_string); - - if (tokens_read == EOF) - { - 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) - { - LL_INFOS() << "Can't read line " << line_count << " of key binding file " << filename << LL_ENDL; - continue; - } - - // convert mode - if (!modeFromString(mode_string, &mode)) - { - 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)) - { - 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)) - { - LL_INFOS() << "Can't interpret mask on line " << line_count << " of key binding file " << filename << LL_ENDL; - continue; - } - - // bind key - if (bindKey(mode, key, mask, function_string)) - { - binding_count++; - } - } - - fclose(fp); - - return binding_count; -} - - -EKeyboardMode LLViewerKeyboard::getMode() -{ - if ( gAgentCamera.cameraMouselook() ) - { - return MODE_FIRST_PERSON; - } - else if ( gMorphView && gMorphView->getVisible()) - { - return MODE_EDIT_AVATAR; - } - else if (isAgentAvatarValid() && gAgentAvatarp->isSitting()) - { - return MODE_SITTING; - } - else - { - return MODE_THIRD_PERSON; - } -} - - -// Called from scanKeyboard. -void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) -{ - S32 mode = getMode(); - // Consider keyboard scanning as NOT mouse event. JC - MASK mask = gKeyboard->currentMask(FALSE); - - LLKeyBinding* binding = mBindings[mode]; - S32 binding_count = mBindingCount[mode]; - - - if (mKeyHandledByUI[key]) - { - return; - } - - // don't process key down on repeated keys - BOOL repeat = gKeyboard->getKeyRepeated(key); - - for (S32 i = 0; i < binding_count; i++) - { - //for (S32 key = 0; key < KEY_COUNT; key++) - if (binding[i].mKey == key) - { - //if (binding[i].mKey == key && binding[i].mMask == mask) - if (binding[i].mMask == mask) - { - if (key_down && !repeat) - { - // ...key went down this frame, call function - binding[i].mFunction( KEYSTATE_DOWN ); - } - else if (key_up) - { - // ...key went down this frame, call function - 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 ); - }//if - }//if - }//for - }//for -} diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h deleted file mode 100644 index 110dc89d28..0000000000 --- a/indra/newview/llviewerkeyboard.h +++ /dev/null @@ -1,118 +0,0 @@ -/** - * @file llviewerkeyboard.h - * @brief LLViewerKeyboard class header file - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLVIEWERKEYBOARD_H -#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 - -class LLNamedFunction -{ -public: - LLNamedFunction() : mFunction(NULL) { }; - ~LLNamedFunction() { }; - - std::string mName; - LLKeyFunc mFunction; -}; - -typedef enum e_keyboard_mode -{ - MODE_FIRST_PERSON, - MODE_THIRD_PERSON, - MODE_EDIT, - MODE_EDIT_AVATAR, - MODE_SITTING, - MODE_COUNT -} EKeyboardMode; - - -void bind_keyboard_functions(); - -class LLViewerKeyboard -{ -public: - struct KeyBinding : public LLInitParam::Block<KeyBinding> - { - Mandatory<std::string> key, - mask, - command; - - KeyBinding(); - }; - - struct KeyMode : public LLInitParam::Block<KeyMode> - { - Multiple<KeyBinding> bindings; - EKeyboardMode mode; - KeyMode(EKeyboardMode mode); - }; - - struct Keys : public LLInitParam::Block<Keys> - { - Optional<KeyMode> first_person, - third_person, - edit, - sitting, - edit_avatar; - - Keys(); - }; - - LLViewerKeyboard(); - - BOOL handleKey(KEY key, MASK mask, BOOL repeated); - 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 - 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); - -private: - S32 loadBindingMode(const LLViewerKeyboard::KeyMode& keymode); - BOOL bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name); - - // Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here - S32 mBindingCount[MODE_COUNT]; - LLKeyBinding mBindings[MODE_COUNT][MAX_KEY_BINDINGS]; - - typedef std::map<U32, U32> key_remap_t; - key_remap_t mRemapKeys[MODE_COUNT]; - std::set<KEY> mKeysSkippedByUI; - BOOL mKeyHandledByUI[KEY_COUNT]; // key processed successfully by UI -}; - -extern LLViewerKeyboard gViewerKeyboard; - -#endif // LL_LLVIEWERKEYBOARD_H diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index a27a083a2a..d35dbda907 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -57,6 +57,7 @@ #include "llviewercontrol.h" #include "llviewermenufile.h" // LLFilePickerThread #include "llviewernetwork.h" +#include "llviewerparcelaskplay.h" #include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" @@ -77,12 +78,6 @@ #include <boost/bind.hpp> // for SkinFolder listener #include <boost/signals2.hpp> -/*static*/ const char* LLViewerMedia::AUTO_PLAY_MEDIA_SETTING = "ParcelMediaAutoPlayEnable"; -/*static*/ const char* LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING = "MediaShowOnOthers"; -/*static*/ const char* LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING = "MediaShowWithinParcel"; -/*static*/ const char* LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING = "MediaShowOutsideParcel"; - - class LLMediaFilePicker : public LLFilePickerThread // deletes itself when done { public: @@ -191,9 +186,6 @@ LLViewerMediaObserver::~LLViewerMediaObserver() } -LLURL LLViewerMedia::sOpenIDURL; -std::string LLViewerMedia::sOpenIDCookie; -LLPluginClassMedia* LLViewerMedia::sSpareBrowserMediaSource = NULL; static LLViewerMedia::impl_list sViewerMediaImplList; static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap; static LLTimer sMediaCreateTimer; @@ -202,9 +194,6 @@ static F32 sGlobalVolume = 1.0f; static bool sForceUpdate = false; static LLUUID sOnlyAudibleTextureID = LLUUID::null; static F64 sLowestLoadableImplInterest = 0.0f; -static bool sAnyMediaShowing = false; -static bool sAnyMediaPlaying = false; -static boost::signals2::connection sTeleportFinishConnection; ////////////////////////////////////////////////////////////////////////////////////////// static void add_media_impl(LLViewerMediaImpl* media) @@ -230,7 +219,7 @@ static void remove_media_impl(LLViewerMediaImpl* media) class LLViewerMediaMuteListObserver : public LLMuteListObserver { - /* virtual */ void onChange() { LLViewerMedia::muteListChanged();} + /* virtual */ void onChange() { LLViewerMedia::getInstance()->muteListChanged();} }; static LLViewerMediaMuteListObserver sViewerMediaMuteListObserver; @@ -239,9 +228,40 @@ static bool sViewerMediaMuteListObserverInitialized = false; ////////////////////////////////////////////////////////////////////////////////////////// // LLViewerMedia - ////////////////////////////////////////////////////////////////////////////////////////// + +/*static*/ const char* LLViewerMedia::AUTO_PLAY_MEDIA_SETTING = "ParcelMediaAutoPlayEnable"; +/*static*/ const char* LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING = "MediaShowOnOthers"; +/*static*/ const char* LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING = "MediaShowWithinParcel"; +/*static*/ const char* LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING = "MediaShowOutsideParcel"; + +LLViewerMedia::LLViewerMedia(): +mAnyMediaShowing(false), +mAnyMediaPlaying(false), +mSpareBrowserMediaSource(NULL) +{ +} + +LLViewerMedia::~LLViewerMedia() +{ + gIdleCallbacks.deleteFunction(LLViewerMedia::onIdle, NULL); + mTeleportFinishConnection.disconnect(); + if (mSpareBrowserMediaSource != NULL) + { + delete mSpareBrowserMediaSource; + mSpareBrowserMediaSource = NULL; + } +} + // static +void LLViewerMedia::initSingleton() +{ + gIdleCallbacks.addFunction(LLViewerMedia::onIdle, NULL); + mTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> + setTeleportFinishedCallback(boost::bind(&LLViewerMedia::onTeleportFinished, this)); +} + +////////////////////////////////////////////////////////////////////////////////////////// viewer_media_t LLViewerMedia::newMediaImpl( const LLUUID& texture_id, S32 media_width, @@ -368,7 +388,6 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s } ////////////////////////////////////////////////////////////////////////////////////////// -// static LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureID(const LLUUID& texture_id) { LLViewerMediaImpl* result = NULL; @@ -384,7 +403,6 @@ LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureID(const LLUUID& textur } ////////////////////////////////////////////////////////////////////////////////////////// -// static std::string LLViewerMedia::getCurrentUserAgent() { // Don't use user-visible string to avoid @@ -393,7 +411,7 @@ std::string LLViewerMedia::getCurrentUserAgent() // Just in case we need to check browser differences in A/B test // builds. - std::string channel = LLVersionInfo::getChannel(); + std::string channel = LLVersionInfo::instance().getChannel(); // append our magic version number string to the browser user agent id // See the HTTP 1.0 and 1.1 specifications for allowed formats: @@ -403,7 +421,7 @@ std::string LLViewerMedia::getCurrentUserAgent() // http://www.mozilla.org/build/revised-user-agent-strings.html std::ostringstream codec; codec << "SecondLife/"; - codec << LLVersionInfo::getVersion(); + codec << LLVersionInfo::instance().getVersion(); codec << " (" << channel << "; " << skin_name << " skin)"; LL_INFOS() << codec.str() << LL_ENDL; @@ -411,7 +429,6 @@ std::string LLViewerMedia::getCurrentUserAgent() } ////////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::updateBrowserUserAgent() { std::string user_agent = getCurrentUserAgent(); @@ -431,7 +448,6 @@ void LLViewerMedia::updateBrowserUserAgent() } ////////////////////////////////////////////////////////////////////////////////////////// -// static bool LLViewerMedia::handleSkinCurrentChanged(const LLSD& /*newvalue*/) { // gSavedSettings is already updated when this function is called. @@ -440,7 +456,6 @@ bool LLViewerMedia::handleSkinCurrentChanged(const LLSD& /*newvalue*/) } ////////////////////////////////////////////////////////////////////////////////////////// -// static bool LLViewerMedia::textureHasMedia(const LLUUID& texture_id) { impl_list::iterator iter = sViewerMediaImplList.begin(); @@ -458,7 +473,6 @@ bool LLViewerMedia::textureHasMedia(const LLUUID& texture_id) } ////////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::setVolume(F32 volume) { if(volume != sGlobalVolume || sForceUpdate) @@ -478,14 +492,12 @@ void LLViewerMedia::setVolume(F32 volume) } ////////////////////////////////////////////////////////////////////////////////////////// -// static F32 LLViewerMedia::getVolume() { return sGlobalVolume; } ////////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::muteListChanged() { // When the mute list changes, we need to check mute status on all impls. @@ -500,7 +512,6 @@ void LLViewerMedia::muteListChanged() } ////////////////////////////////////////////////////////////////////////////////////////// -// static bool LLViewerMedia::isInterestingEnough(const LLVOVolume *object, const F64 &object_interest) { bool result = false; @@ -535,6 +546,7 @@ LLViewerMedia::impl_list &LLViewerMedia::getPriorityList() return sViewerMediaImplList; } +// static // This is the predicate function used to sort sViewerMediaImplList by priority. bool LLViewerMedia::priorityComparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2) { @@ -629,7 +641,12 @@ static LLTrace::BlockTimerStatHandle FTM_MEDIA_MISC("Misc"); ////////////////////////////////////////////////////////////////////////////////////////// -// static +void LLViewerMedia::onIdle(void *dummy_arg) +{ + LLViewerMedia::getInstance()->updateMedia(dummy_arg); +} + +////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMedia::updateMedia(void *dummy_arg) { LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE); @@ -642,8 +659,8 @@ void LLViewerMedia::updateMedia(void *dummy_arg) // removing it for now. //createSpareBrowserMediaSource(); - sAnyMediaShowing = false; - sAnyMediaPlaying = false; + mAnyMediaShowing = false; + mAnyMediaPlaying = false; impl_list::iterator iter = sViewerMediaImplList.begin(); impl_list::iterator end = sViewerMediaImplList.end(); @@ -659,10 +676,10 @@ void LLViewerMedia::updateMedia(void *dummy_arg) } // Let the spare media source actually launch - if(sSpareBrowserMediaSource) + if(mSpareBrowserMediaSource) { LL_RECORD_BLOCK_TIME(FTM_MEDIA_SPARE_IDLE); - sSpareBrowserMediaSource->idle(); + mSpareBrowserMediaSource->idle(); } { @@ -848,13 +865,13 @@ void LLViewerMedia::updateMedia(void *dummy_arg) if (!pimpl->getUsedInUI() && pimpl->hasMedia()) { - sAnyMediaShowing = true; + mAnyMediaShowing = true; } if (!pimpl->getUsedInUI() && pimpl->hasMedia() && (pimpl->isMediaPlaying() || !pimpl->isMediaTimeBased())) { // consider visible non-timebased media as playing - sAnyMediaPlaying = true; + mAnyMediaPlaying = true; } } @@ -899,21 +916,18 @@ void LLViewerMedia::updateMedia(void *dummy_arg) } ////////////////////////////////////////////////////////////////////////////////////////// -// static bool LLViewerMedia::isAnyMediaShowing() { - return sAnyMediaShowing; + return mAnyMediaShowing; } ////////////////////////////////////////////////////////////////////////////////////////// -// static bool LLViewerMedia::isAnyMediaPlaying() { - return sAnyMediaPlaying; + return mAnyMediaPlaying; } ////////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::setAllMediaEnabled(bool val) { // Set "tentative" autoplay first. We need to do this here or else @@ -938,7 +952,7 @@ void LLViewerMedia::setAllMediaEnabled(bool val) { if (!LLViewerMedia::isParcelMediaPlaying() && LLViewerMedia::hasParcelMedia()) { - LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel()); + LLViewerParcelMedia::getInstance()->play(LLViewerParcelMgr::getInstance()->getAgentParcel()); } static LLCachedControl<bool> audio_streaming_music(gSavedSettings, "AudioStreamingMusic", true); @@ -960,7 +974,7 @@ void LLViewerMedia::setAllMediaEnabled(bool val) } else { // This actually unloads the impl, as opposed to "stop"ping the media - LLViewerParcelMedia::stop(); + LLViewerParcelMedia::getInstance()->stop(); if (gAudiop) { LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade(); @@ -969,7 +983,6 @@ void LLViewerMedia::setAllMediaEnabled(bool val) } ////////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::setAllMediaPaused(bool val) { // Set "tentative" autoplay first. We need to do this here or else @@ -1005,12 +1018,14 @@ void LLViewerMedia::setAllMediaPaused(bool val) } } + LLParcel *agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + // Also do Parcel Media and Parcel Audio if (!val) { if (!LLViewerMedia::isParcelMediaPlaying() && LLViewerMedia::hasParcelMedia()) { - LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel()); + LLViewerParcelMedia::getInstance()->play(agent_parcel); } static LLCachedControl<bool> audio_streaming_music(gSavedSettings, "AudioStreamingMusic", true); @@ -1032,28 +1047,40 @@ void LLViewerMedia::setAllMediaPaused(bool val) } else { // This actually unloads the impl, as opposed to "stop"ping the media - LLViewerParcelMedia::stop(); + LLViewerParcelMedia::getInstance()->stop(); if (gAudiop) { LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade(); } } + + // remove play choice for current parcel + if (agent_parcel && gAgent.getRegion()) + { + LLViewerParcelAskPlay::getInstance()->resetSetting(gAgent.getRegion()->getRegionID(), agent_parcel->getLocalID()); + } } ////////////////////////////////////////////////////////////////////////////////////////// -// static bool LLViewerMedia::isParcelMediaPlaying() { - return (LLViewerMedia::hasParcelMedia() && LLViewerParcelMedia::getParcelMedia() && LLViewerParcelMedia::getParcelMedia()->hasMedia()); + viewer_media_t media = LLViewerParcelMedia::getInstance()->getParcelMedia(); + return (LLViewerMedia::hasParcelMedia() && media && media->hasMedia()); } ///////////////////////////////////////////////////////////////////////////////////////// -// static bool LLViewerMedia::isParcelAudioPlaying() { return (LLViewerMedia::hasParcelAudio() && gAudiop && LLAudioEngine::AUDIO_PLAYING == gAudiop->isInternetStreamPlaying()); } +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::authSubmitCallback(const LLSD& notification, const LLSD& response) +{ + LLViewerMedia::getInstance()->onAuthSubmit(notification, response); +} + void LLViewerMedia::onAuthSubmit(const LLSD& notification, const LLSD& response) { LLViewerMediaImpl *impl = LLViewerMedia::getMediaImplFromTextureID(notification["payload"]["media_id"]); @@ -1075,7 +1102,6 @@ void LLViewerMedia::onAuthSubmit(const LLSD& notification, const LLSD& response) } ///////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::clearAllCookies() { // Clear all cookies for all plugins @@ -1092,7 +1118,6 @@ void LLViewerMedia::clearAllCookies() } ///////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::clearAllCaches() { // Clear all plugins' caches @@ -1106,7 +1131,6 @@ void LLViewerMedia::clearAllCaches() } ///////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::setCookiesEnabled(bool enabled) { // Set the "cookies enabled" flag for all loaded plugins @@ -1123,7 +1147,6 @@ void LLViewerMedia::setCookiesEnabled(bool enabled) } ///////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int port) { // Set the proxy config for all loaded plugins @@ -1140,10 +1163,6 @@ void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int por } ///////////////////////////////////////////////////////////////////////////////////////// -// static -///////////////////////////////////////////////////////////////////////////////////////// -//// static - LLSD LLViewerMedia::getHeaders() { LLSD headers = LLSD::emptyMap(); @@ -1151,14 +1170,13 @@ LLSD LLViewerMedia::getHeaders() // *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[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_XML; - headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie; + headers[HTTP_OUT_HEADER_COOKIE] = mOpenIDCookie; headers[HTTP_OUT_HEADER_USER_AGENT] = getCurrentUserAgent(); return headers; } ///////////////////////////////////////////////////////////////////////////////////////// - // static bool LLViewerMedia::parseRawCookie(const std::string raw_cookie, std::string& name, std::string& value, std::string& path, bool& httponly, bool& secure) { std::size_t name_pos = raw_cookie.find_first_of("="); @@ -1181,13 +1199,14 @@ bool LLViewerMedia::parseRawCookie(const std::string raw_cookie, std::string& na return false; } +///////////////////////////////////////////////////////////////////////////////////////// LLCore::HttpHeaders::ptr_t LLViewerMedia::getHttpHeaders() { LLCore::HttpHeaders::ptr_t headers(new LLCore::HttpHeaders); headers->append(HTTP_OUT_HEADER_ACCEPT, "*/*"); headers->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_XML); - headers->append(HTTP_OUT_HEADER_COOKIE, sOpenIDCookie); + headers->append(HTTP_OUT_HEADER_COOKIE, mOpenIDCookie); headers->append(HTTP_OUT_HEADER_USER_AGENT, getCurrentUserAgent()); return headers; @@ -1195,10 +1214,9 @@ LLCore::HttpHeaders::ptr_t LLViewerMedia::getHttpHeaders() ///////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::setOpenIDCookie(const std::string& url) { - if(!sOpenIDCookie.empty()) + if(!mOpenIDCookie.empty()) { std::string profileUrl = getProfileURL(""); @@ -1207,7 +1225,7 @@ void LLViewerMedia::setOpenIDCookie(const std::string& url) } } -/*static*/ +//static void LLViewerMedia::getOpenIDCookieCoro(std::string url) { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); @@ -1219,6 +1237,7 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url) httpOpts->setFollowRedirects(true); httpOpts->setWantHeaders(true); + httpOpts->setSSLVerifyPeer(false); // viewer's cert bundle doesn't appear to agree with web certs from "https://my.secondlife.com/" LLURL hostUrl(url.c_str()); std::string hostAuth = hostUrl.getAuthority(); @@ -1229,7 +1248,7 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url) // 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 authority = getInstance()->mOpenIDURL.mAuthority; std::string::size_type hostStart = authority.find('@'); if (hostStart == std::string::npos) { // no username/password @@ -1246,7 +1265,8 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url) { // no port hostEnd = authority.size(); } - + + LLViewerMedia* inst = getInstance(); if (url.length()) { LLMediaCtrl* media_instance = LLFloaterReg::getInstance("destinations")->getChild<LLMediaCtrl>("destination_guide_contents"); @@ -1258,8 +1278,8 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url) std::string cookie_path = ""; bool httponly = true; bool secure = true; - if (parseRawCookie(sOpenIDCookie, cookie_name, cookie_value, cookie_path, httponly, secure) && - media_instance->getMediaPlugin()) + if (inst->parseRawCookie(inst->mOpenIDCookie, 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. @@ -1268,7 +1288,7 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url) // (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)); + std::string cefUrl(std::string(inst->mOpenIDURL.mURI) + "://" + std::string(inst->mOpenIDURL.mAuthority)); media_instance->getMediaPlugin()->setCookie(cefUrl, cookie_name, cookie_value, cookie_host, cookie_path, httponly, secure); } @@ -1281,11 +1301,11 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url) // Do a web profile get so we can store the cookie httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*"); - httpHeaders->append(HTTP_OUT_HEADER_COOKIE, sOpenIDCookie); - httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, getCurrentUserAgent()); + httpHeaders->append(HTTP_OUT_HEADER_COOKIE, inst->mOpenIDCookie); + httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, inst->getCurrentUserAgent()); LL_DEBUGS("MediaAuth") << "Requesting " << url << LL_ENDL; - LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << LL_ENDL; + LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << inst->mOpenIDCookie << "]" << LL_ENDL; LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts, httpHeaders); @@ -1314,7 +1334,6 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url) } ///////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::openIDSetup(const std::string &openidUrl, const std::string &openidToken) { LL_DEBUGS("MediaAuth") << "url = \"" << openidUrl << "\", token = \"" << openidToken << "\"" << LL_ENDL; @@ -1323,7 +1342,6 @@ void LLViewerMedia::openIDSetup(const std::string &openidUrl, const std::string boost::bind(&LLViewerMedia::openIDSetupCoro, openidUrl, openidToken)); } -/*static*/ void LLViewerMedia::openIDSetupCoro(std::string openidUrl, std::string openidToken) { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); @@ -1338,10 +1356,10 @@ void LLViewerMedia::openIDSetupCoro(std::string openidUrl, std::string openidTok // 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(openidUrl.c_str()); + getInstance()->mOpenIDURL.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(); + getInstance()->mOpenIDCookie.clear(); httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*"); httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/x-www-form-urlencoded"); @@ -1373,24 +1391,22 @@ void LLViewerMedia::openIDSetupCoro(std::string openidUrl, std::string openidTok const std::string& cookie = resultHeaders[HTTP_IN_HEADER_SET_COOKIE].asString(); // *TODO: What about bad status codes? Does this destroy previous cookies? - LLViewerMedia::openIDCookieResponse(openidUrl, cookie); + LLViewerMedia::getInstance()->openIDCookieResponse(openidUrl, cookie); LL_DEBUGS("MediaAuth") << "OpenID cookie set." << LL_ENDL; } ///////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::openIDCookieResponse(const std::string& url, const std::string &cookie) { LL_DEBUGS("MediaAuth") << "Cookie received: \"" << cookie << "\"" << LL_ENDL; - sOpenIDCookie += cookie; + mOpenIDCookie += cookie; setOpenIDCookie(url); } ///////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::proxyWindowOpened(const std::string &target, const std::string &uuid) { if(uuid.empty()) @@ -1406,7 +1422,6 @@ void LLViewerMedia::proxyWindowOpened(const std::string &target, const std::stri } ///////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::proxyWindowClosed(const std::string &uuid) { if(uuid.empty()) @@ -1422,28 +1437,26 @@ void LLViewerMedia::proxyWindowClosed(const std::string &uuid) } ///////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::createSpareBrowserMediaSource() { // 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 // popping up at the moment we start a media plugin. - if (!sSpareBrowserMediaSource && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) + if (!mSpareBrowserMediaSource && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) { // 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(HTTP_CONTENT_TEXT_HTML, NULL, 0, 0, 1.0); + mSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType(HTTP_CONTENT_TEXT_HTML, NULL, 0, 0, 1.0); } } ///////////////////////////////////////////////////////////////////////////////////////// -// static LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource() { - LLPluginClassMedia* result = sSpareBrowserMediaSource; - sSpareBrowserMediaSource = NULL; + LLPluginClassMedia* result = mSpareBrowserMediaSource; + mSpareBrowserMediaSource = NULL; return result; }; @@ -1465,50 +1478,24 @@ bool LLViewerMedia::hasInWorldMedia() } ////////////////////////////////////////////////////////////////////////////////////////// -// static bool LLViewerMedia::hasParcelMedia() { - return !LLViewerParcelMedia::getURL().empty(); + return !LLViewerParcelMedia::getInstance()->getURL().empty(); } ////////////////////////////////////////////////////////////////////////////////////////// -// static bool LLViewerMedia::hasParcelAudio() { return !LLViewerMedia::getParcelAudioURL().empty(); } ////////////////////////////////////////////////////////////////////////////////////////// -// static std::string LLViewerMedia::getParcelAudioURL() { return LLViewerParcelMgr::getInstance()->getAgentParcel()->getMusicURL(); } ////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::initClass() -{ - gIdleCallbacks.addFunction(LLViewerMedia::updateMedia, NULL); - sTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> - setTeleportFinishedCallback(boost::bind(&LLViewerMedia::onTeleportFinished)); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::cleanupClass() -{ - gIdleCallbacks.deleteFunction(LLViewerMedia::updateMedia, NULL); - sTeleportFinishConnection.disconnect(); - if (sSpareBrowserMediaSource != NULL) - { - delete sSpareBrowserMediaSource; - sSpareBrowserMediaSource = NULL; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::onTeleportFinished() { // On teleport, clear this setting (i.e. set it to true) @@ -1517,9 +1504,7 @@ void LLViewerMedia::onTeleportFinished() LLViewerMediaImpl::sMimeTypesFailed.clear(); } - ////////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerMedia::setOnlyAudibleMediaTextureID(const LLUUID& texture_id) { sOnlyAudibleTextureID = texture_id; @@ -1711,7 +1696,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ if ((plugin_basename == "media_plugin_cef") && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins") && !clean_browser) { - media_source = LLViewerMedia::getSpareBrowserMediaSource(); + media_source = LLViewerMedia::getInstance()->getSpareBrowserMediaSource(); if(media_source) { media_source->setOwner(owner); @@ -1734,23 +1719,8 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ 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(); - if ( ! linden_user_dir.empty() ) - { - user_data_path_cookies = linden_user_dir; - user_data_path_cookies += gDirUtilp->getDirDelimiter(); - }; - // See if the plugin executable exists llstat s; if(LLFile::stat(launcher_name, &s)) @@ -1767,7 +1737,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ { media_source = new LLPluginClassMedia(owner); media_source->setSize(default_width, default_height); - media_source->setUserDataPath(user_data_path_cache, user_data_path_cookies, user_data_path_cef_log); + media_source->setUserDataPath(user_data_path_cache, gDirUtilp->getUserName(), user_data_path_cef_log); media_source->setLanguageCode(LLUI::getLanguage()); media_source->setZoomFactor(zoom_factor); @@ -1775,19 +1745,19 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ bool cookies_enabled = gSavedSettings.getBOOL( "CookiesEnabled" ); 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 || clean_browser); - // collect 'javascript enabled' setting from prefs and send to embedded browser bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" ); media_source->setJavascriptEnabled( javascript_enabled || clean_browser); + // As of SL-15559 PDF files do not load in CEF v91 we enable plugins + // but explicitly disable Flash (PDF support in CEF is now treated as a plugin) + media_source->setPluginsEnabled(true); + bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging"); 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->setBrowserUserAgent(LLViewerMedia::getInstance()->getCurrentUserAgent()); media_source->setTarget(target); @@ -1858,7 +1828,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) media_source->setDisableTimeout(gSavedSettings.getBOOL("DebugPluginDisableTimeout")); media_source->setLoop(mMediaLoop); media_source->setAutoScale(mMediaAutoScale); - media_source->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent()); + media_source->setBrowserUserAgent(LLViewerMedia::getInstance()->getCurrentUserAgent()); media_source->focus(mHasFocus); media_source->setBackgroundColor(mBackgroundColor); @@ -2091,7 +2061,7 @@ void LLViewerMediaImpl::updateVolume() if(mMediaSource) { // always scale the volume by the global media volume - F32 volume = mRequestedVolume * LLViewerMedia::getVolume(); + F32 volume = mRequestedVolume * LLViewerMedia::getInstance()->getVolume(); if (mProximityCamera > 0) { @@ -2309,14 +2279,26 @@ void LLViewerMediaImpl::mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button) } ////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, MASK mask) +void LLViewerMediaImpl::scrollWheel(const LLVector2& texture_coords, S32 scroll_x, S32 scroll_y, MASK mask) +{ + if (mMediaSource) + { + S32 x, y; + scaleTextureCoords(texture_coords, &x, &y); + + scrollWheel(x, y, scroll_x, scroll_y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, S32 scroll_x, S32 scroll_y, MASK mask) { scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; if (mMediaSource) { - mMediaSource->scrollEvent(x, y, mask); + mMediaSource->scrollEvent(x, y, scroll_x, scroll_y, mask); } } @@ -3365,7 +3347,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla auth_request_params.substitutions = args; auth_request_params.payload = LLSD().with("media_id", mTextureId); - auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2); + auth_request_params.functor.function = boost::bind(&LLViewerMedia::authSubmitCallback, _1, _2); LLNotifications::instance().add(auth_request_params); }; break; @@ -3778,7 +3760,7 @@ void LLViewerMediaImpl::setTextureID(LLUUID id) bool LLViewerMediaImpl::isAutoPlayable() const { return (mMediaAutoPlay && - gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && + gSavedSettings.getS32("ParcelMediaAutoPlayEnable") != 0 && gSavedSettings.getBOOL("MediaTentativeAutoPlay")); } diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index e2e758befb..8bf1ad2441 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -70,11 +70,14 @@ private: class LLViewerMediaImpl; -class LLViewerMedia +class LLViewerMedia: public LLSingleton<LLViewerMedia> { + LLSINGLETON(LLViewerMedia); + ~LLViewerMedia(); + void initSingleton(); LOG_CLASS(LLViewerMedia); + public: - // String to get/set media autoplay in gSavedSettings static const char* AUTO_PLAY_MEDIA_SETTING; static const char* SHOW_MEDIA_ON_OTHERS_SETTING; @@ -88,91 +91,93 @@ public: // Special case early init for just web browser component // so we can show login screen. See .cpp file for details. JC - static viewer_media_t newMediaImpl(const LLUUID& texture_id, + viewer_media_t newMediaImpl(const LLUUID& texture_id, S32 media_width = 0, S32 media_height = 0, U8 media_auto_scale = false, U8 media_loop = false); - static viewer_media_t updateMediaImpl(LLMediaEntry* media_entry, const std::string& previous_url, bool update_from_self); - static LLViewerMediaImpl* getMediaImplFromTextureID(const LLUUID& texture_id); - static std::string getCurrentUserAgent(); - static void updateBrowserUserAgent(); - static bool handleSkinCurrentChanged(const LLSD& /*newvalue*/); - static bool textureHasMedia(const LLUUID& texture_id); - static void setVolume(F32 volume); + viewer_media_t updateMediaImpl(LLMediaEntry* media_entry, const std::string& previous_url, bool update_from_self); + LLViewerMediaImpl* getMediaImplFromTextureID(const LLUUID& texture_id); + std::string getCurrentUserAgent(); + void updateBrowserUserAgent(); + bool handleSkinCurrentChanged(const LLSD& /*newvalue*/); + bool textureHasMedia(const LLUUID& texture_id); + void setVolume(F32 volume); // Is any media currently "showing"? Includes Parcel Media. Does not include media in the UI. - static bool isAnyMediaShowing(); + 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(); + bool isAnyMediaPlaying(); // Set all media enabled or disabled, depending on val. Does not include media in the UI. - static void setAllMediaEnabled(bool val); + 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); + void setAllMediaPaused(bool val); - static void updateMedia(void* dummy_arg = NULL); - - static void initClass(); - static void cleanupClass(); - - static F32 getVolume(); - static void muteListChanged(); - static bool isInterestingEnough(const LLVOVolume* object, const F64 &object_interest); + static void onIdle(void* dummy_arg = NULL); // updateMedia wrapper + void updateMedia(void* dummy_arg = NULL); + + F32 getVolume(); + void muteListChanged(); + bool isInterestingEnough(const LLVOVolume* object, const F64 &object_interest); // Returns the priority-sorted list of all media impls. - static impl_list &getPriorityList(); + impl_list &getPriorityList(); // This is the comparitor used to sort the list. static bool priorityComparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2); // These are just helper functions for the convenience of others working with media - static bool hasInWorldMedia(); - static std::string getParcelAudioURL(); - static bool hasParcelMedia(); - static bool hasParcelAudio(); - static bool isParcelMediaPlaying(); - static bool isParcelAudioPlaying(); - - static void onAuthSubmit(const LLSD& notification, const LLSD& response); + bool hasInWorldMedia(); + std::string getParcelAudioURL(); + bool hasParcelMedia(); + bool hasParcelAudio(); + bool isParcelMediaPlaying(); + bool isParcelAudioPlaying(); + + static void authSubmitCallback(const LLSD& notification, const LLSD& response); // Clear all cookies for all plugins - static void clearAllCookies(); + void clearAllCookies(); // Clear all plugins' caches - static void clearAllCaches(); + void clearAllCaches(); // Set the "cookies enabled" flag for all loaded plugins - static void setCookiesEnabled(bool enabled); + void setCookiesEnabled(bool enabled); // Set the proxy config for all loaded plugins - static void setProxyConfig(bool enable, const std::string &host, int port); + void setProxyConfig(bool enable, const std::string &host, int port); - static void openIDSetup(const std::string &openid_url, const std::string &openid_token); - static void openIDCookieResponse(const std::string& url, const std::string &cookie); + void openIDSetup(const std::string &openid_url, const std::string &openid_token); + void openIDCookieResponse(const std::string& url, const std::string &cookie); - static void proxyWindowOpened(const std::string &target, const std::string &uuid); - static void proxyWindowClosed(const std::string &uuid); + void proxyWindowOpened(const std::string &target, const std::string &uuid); + void proxyWindowClosed(const std::string &uuid); - static void createSpareBrowserMediaSource(); - static LLPluginClassMedia* getSpareBrowserMediaSource(); + void createSpareBrowserMediaSource(); + LLPluginClassMedia* getSpareBrowserMediaSource(); - static void setOnlyAudibleMediaTextureID(const LLUUID& texture_id); + void setOnlyAudibleMediaTextureID(const LLUUID& texture_id); - static LLSD getHeaders(); - static LLCore::HttpHeaders::ptr_t getHttpHeaders(); + LLSD getHeaders(); + LLCore::HttpHeaders::ptr_t getHttpHeaders(); 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(const std::string& url); - static void onTeleportFinished(); - - static void openIDSetupCoro(std::string openidUrl, std::string openidToken); - static void getOpenIDCookieCoro(std::string url); - - static LLURL sOpenIDURL; - static std::string sOpenIDCookie; - static LLPluginClassMedia* sSpareBrowserMediaSource; + void onAuthSubmit(const LLSD& notification, const LLSD& response); + bool parseRawCookie(const std::string raw_cookie, std::string& name, std::string& value, std::string& path, bool& httponly, bool& secure); + void setOpenIDCookie(const std::string& url); + void onTeleportFinished(); + + static void openIDSetupCoro(std::string openidUrl, std::string openidToken); + static void getOpenIDCookieCoro(std::string url); + + bool mAnyMediaShowing; + bool mAnyMediaPlaying; + LLURL mOpenIDURL; + std::string mOpenIDCookie; + LLPluginClassMedia* mSpareBrowserMediaSource; + boost::signals2::connection mTeleportFinishConnection; }; // Implementation functions not exported into header file @@ -230,7 +235,8 @@ public: void mouseMove(const LLVector2& texture_coords, 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, MASK mask); + void scrollWheel(const LLVector2& texture_coords, S32 scroll_x, S32 scroll_y, MASK mask); + void scrollWheel(S32 x, S32 y, S32 scroll_x, S32 scroll_y, MASK mask); void mouseCapture(); void navigateBack(); @@ -315,6 +321,7 @@ public: /*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 handleScrollHWheel(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; }; diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp index 59165c1d71..ba80eeb6b6 100644 --- a/indra/newview/llviewermediafocus.cpp +++ b/indra/newview/llviewermediafocus.cpp @@ -205,8 +205,9 @@ bool LLViewerMediaFocus::getFocus() } // This function selects an ideal viewing distance based on the focused object, pick normal, and padding value -void LLViewerMediaFocus::setCameraZoom(LLViewerObject* object, LLVector3 normal, F32 padding_factor, bool zoom_in_only) +LLVector3d LLViewerMediaFocus::setCameraZoom(LLViewerObject* object, LLVector3 normal, F32 padding_factor, bool zoom_in_only) { + LLVector3d camera_pos; if (object) { gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); @@ -254,7 +255,7 @@ void LLViewerMediaFocus::setCameraZoom(LLViewerObject* object, LLVector3 normal, distance += depth * 0.5; // Finally animate the camera to this new position and focal point - LLVector3d camera_pos, target_pos; + LLVector3d target_pos; // The target lookat position is the center of the selection (in global coords) target_pos = center; // Target look-from (camera) position is "distance" away from the target along the normal @@ -287,7 +288,7 @@ void LLViewerMediaFocus::setCameraZoom(LLViewerObject* object, LLVector3 normal, if (zoom_in_only && (dist_vec_squared(gAgentCamera.getCameraPositionGlobal(), target_pos) < dist_vec_squared(camera_pos, target_pos))) { - return; + return camera_pos; } gAgentCamera.setCameraPosAndFocusGlobal(camera_pos, target_pos, object->getID() ); @@ -298,6 +299,7 @@ void LLViewerMediaFocus::setCameraZoom(LLViewerObject* object, LLVector3 normal, // If we have no object, focus back on the avatar. gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE); } + return camera_pos; } void LLViewerMediaFocus::onFocusReceived() { @@ -338,15 +340,6 @@ BOOL LLViewerMediaFocus::handleKey(KEY key, MASK mask, BOOL called_from_parent) clearFocus(); } - - if ( KEY_F1 == key && LLUI::sHelpImpl && mMediaControls.get()) - { - std::string help_topic; - if (mMediaControls.get()->findHelpTopic(help_topic)) - { - LLUI::sHelpImpl->showTopic(help_topic); - } - } } return true; @@ -371,18 +364,26 @@ BOOL LLViewerMediaFocus::handleUnicodeChar(llwchar uni_char, BOOL called_from_pa media_impl->handleUnicodeCharHere(uni_char); return true; } -BOOL LLViewerMediaFocus::handleScrollWheel(S32 x, S32 y, S32 clicks) + +BOOL LLViewerMediaFocus::handleScrollWheel(const LLVector2& texture_coords, S32 clicks_x, S32 clicks_y) +{ + BOOL retval = FALSE; + LLViewerMediaImpl* media_impl = getFocusedMediaImpl(); + if (media_impl && media_impl->hasMedia()) + { + media_impl->scrollWheel(texture_coords, clicks_x, clicks_y, gKeyboard->currentMask(TRUE)); + retval = TRUE; + } + return retval; +} + +BOOL LLViewerMediaFocus::handleScrollWheel(S32 x, S32 y, S32 clicks_x, S32 clicks_y) { BOOL retval = FALSE; 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, clicks_x, clicks_y, gKeyboard->currentMask(TRUE)); retval = TRUE; } return retval; @@ -537,7 +538,7 @@ bool LLViewerMediaFocus::isHoveringOverFace(LLPointer<LLViewerObject> objectp, S LLViewerMediaImpl* LLViewerMediaFocus::getFocusedMediaImpl() { - return LLViewerMedia::getMediaImplFromTextureID(mFocusedImplID); + return LLViewerMedia::getInstance()->getMediaImplFromTextureID(mFocusedImplID); } LLViewerObject* LLViewerMediaFocus::getFocusedObject() @@ -547,7 +548,7 @@ LLViewerObject* LLViewerMediaFocus::getFocusedObject() LLViewerMediaImpl* LLViewerMediaFocus::getHoverMediaImpl() { - return LLViewerMedia::getMediaImplFromTextureID(mHoverImplID); + return LLViewerMedia::getInstance()->getMediaImplFromTextureID(mHoverImplID); } LLViewerObject* LLViewerMediaFocus::getHoverObject() @@ -557,7 +558,7 @@ LLViewerObject* LLViewerMediaFocus::getHoverObject() void LLViewerMediaFocus::focusZoomOnMedia(LLUUID media_id) { - LLViewerMediaImpl* impl = LLViewerMedia::getMediaImplFromTextureID(media_id); + LLViewerMediaImpl* impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(media_id); if(impl) { diff --git a/indra/newview/llviewermediafocus.h b/indra/newview/llviewermediafocus.h index 763a6c1688..effd08a559 100644 --- a/indra/newview/llviewermediafocus.h +++ b/indra/newview/llviewermediafocus.h @@ -58,16 +58,18 @@ public: /*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); + BOOL handleScrollWheel(const LLVector2& texture_coords, S32 clicks_x, S32 clicks_y); + BOOL handleScrollWheel(S32 x, S32 y, S32 clicks_x, S32 clicks_y); void update(); - static void setCameraZoom(LLViewerObject* object, LLVector3 normal, F32 padding_factor, bool zoom_in_only = false); + static LLVector3d setCameraZoom(LLViewerObject* object, LLVector3 normal, F32 padding_factor, bool zoom_in_only = false); static F32 getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& normal, F32* height, F32* width, F32* depth); bool isFocusedOnFace(LLPointer<LLViewerObject> objectp, S32 face); bool isHoveringOverFace(LLPointer<LLViewerObject> objectp, S32 face); - + bool isHoveringOverFocused() { return mFocusedObjectID == mHoverObjectID && mFocusedObjectFace == mHoverObjectFace; }; + // These look up (by uuid) and return the values that were set with setFocusFace. They will return null if the objects have been destroyed. LLViewerMediaImpl* getFocusedMediaImpl(); LLViewerObject* getFocusedObject(); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index f99cbedcbe..387bd4cf49 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -45,15 +45,15 @@ // newview includes #include "llagent.h" #include "llagentaccess.h" +#include "llagentbenefits.h" #include "llagentcamera.h" #include "llagentui.h" #include "llagentwearables.h" #include "llagentpilot.h" #include "llcompilequeue.h" #include "llconsole.h" -#include "lldaycyclemanager.h" #include "lldebugview.h" -#include "llenvmanager.h" +#include "llenvironment.h" #include "llfilepicker.h" #include "llfirstuse.h" #include "llfloaterabout.h" @@ -64,6 +64,7 @@ #include "llfloaterimcontainer.h" #include "llfloaterland.h" #include "llfloaterimnearbychat.h" +#include "llfloaterlandholdings.h" #include "llfloaterpathfindingcharacters.h" #include "llfloaterpathfindinglinksets.h" #include "llfloaterpay.h" @@ -120,21 +121,19 @@ #include "llworldmap.h" #include "pipeline.h" #include "llviewerjoystick.h" -#include "llwaterparammanager.h" -#include "llwlanimator.h" -#include "llwlparammanager.h" #include "llfloatercamera.h" #include "lluilistener.h" #include "llappearancemgr.h" #include "lltrans.h" -#include "lleconomy.h" #include "lltoolgrab.h" #include "llwindow.h" #include "llpathfindingmanager.h" #include "llstartup.h" #include "boost/unordered_map.hpp" #include <boost/regex.hpp> +#include <boost/algorithm/string.hpp> #include "llcleanup.h" +#include "llviewershadermgr.h" using namespace LLAvatarAppearanceDefines; @@ -187,11 +186,15 @@ const std::string SAVE_INTO_TASK_INVENTORY("Save Object Back to Object Contents" LLMenuGL* gAttachSubMenu = NULL; LLMenuGL* gDetachSubMenu = NULL; LLMenuGL* gTakeOffClothes = NULL; +LLMenuGL* gDetachAvatarMenu = NULL; +LLMenuGL* gDetachHUDAvatarMenu = NULL; LLContextMenu* gAttachScreenPieMenu = NULL; LLContextMenu* gAttachPieMenu = NULL; LLContextMenu* gAttachBodyPartPieMenus[9]; LLContextMenu* gDetachPieMenu = NULL; LLContextMenu* gDetachScreenPieMenu = NULL; +LLContextMenu* gDetachAttSelfMenu = NULL; +LLContextMenu* gDetachHUDAttSelfMenu = NULL; LLContextMenu* gDetachBodyPartPieMenus[9]; // @@ -288,6 +291,8 @@ void force_error_bad_memory_access(void *); void force_error_infinite_loop(void *); void force_error_software_exception(void *); void force_error_driver_crash(void *); +void force_error_coroutine_crash(void *); +void force_error_thread_crash(void *); void handle_force_delete(void*); void print_object_info(void*); @@ -377,20 +382,6 @@ void initialize_menus(); // Break up groups of more than 6 items with separators //----------------------------------------------------------------------------- -void set_underclothes_menu_options() -{ - if (gMenuHolder && gAgent.isTeen()) - { - gMenuHolder->getChild<LLView>("Self Underpants")->setVisible(FALSE); - gMenuHolder->getChild<LLView>("Self Undershirt")->setVisible(FALSE); - } - if (gMenuBarView && gAgent.isTeen()) - { - gMenuBarView->getChild<LLView>("Menu Underpants")->setVisible(FALSE); - gMenuBarView->getChild<LLView>("Menu Undershirt")->setVisible(FALSE); - } -} - void set_merchant_SLM_menu() { // All other cases (new merchant, not merchant, migrated merchant): show the new Marketplace Listings menu and enable the tool @@ -401,23 +392,20 @@ void set_merchant_SLM_menu() void check_merchant_status(bool force) { - if (!gSavedSettings.getBOOL("InventoryOutboxDisplayBoth")) + if (force) { - 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<LLView>("MarketplaceListings")->setVisible(FALSE); - - // Also disable the toolbar button for Marketplace Listings - LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings"); - gToolBarView->enableCommand(command->id(), false); - - // Launch an SLM test connection to get the merchant status - LLMarketplaceData::instance().initializeSLM(boost::bind(&set_merchant_SLM_menu)); + // 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<LLView>("MarketplaceListings")->setVisible(FALSE); + + // Also disable the toolbar button for Marketplace Listings + LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings"); + gToolBarView->enableCommand(command->id(), false); + + // Launch an SLM test connection to get the merchant status + LLMarketplaceData::instance().initializeSLM(boost::bind(&set_merchant_SLM_menu)); } void init_menus() @@ -463,6 +451,9 @@ void init_menus() gMenuAttachmentOther = LLUICtrlFactory::createFromFile<LLContextMenu>( "menu_attachment_other.xml", gMenuHolder, registry); + gDetachHUDAttSelfMenu = gMenuHolder->getChild<LLContextMenu>("Detach Self HUD", true); + gDetachAttSelfMenu = gMenuHolder->getChild<LLContextMenu>("Detach Self", true); + gMenuLand = LLUICtrlFactory::createFromFile<LLContextMenu>( "menu_land.xml", gMenuHolder, registry); @@ -508,17 +499,20 @@ void init_menus() gViewerWindow->setMenuBackgroundColor(false, LLGridManager::getInstance()->isInProductionGrid()); - // Assume L$10 for now, the server will tell us the real cost at login // *TODO:Also fix cost in llfolderview.cpp for Inventory menus - const std::string upload_cost("10"); - gMenuHolder->childSetLabelArg("Upload Image", "[COST]", upload_cost); - gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", upload_cost); - gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", upload_cost); - gMenuHolder->childSetLabelArg("Bulk Upload", "[COST]", upload_cost); + const std::string texture_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()); + const std::string sound_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getSoundUploadCost()); + const std::string animation_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getAnimationUploadCost()); + gMenuHolder->childSetLabelArg("Upload Image", "[COST]", texture_upload_cost_str); + gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", sound_upload_cost_str); + gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", animation_upload_cost_str); gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", TRUE); gDetachSubMenu = gMenuBarView->findChildMenuByName("Detach Object", TRUE); + gDetachAvatarMenu = gMenuHolder->getChild<LLMenuGL>("Avatar Detach", true); + gDetachHUDAvatarMenu = gMenuHolder->getChild<LLMenuGL>("Avatar Detach HUD", true); + // Don't display the Memory console menu if the feature is turned off LLMenuItemCheckGL *memoryMenu = gMenuBarView->getChild<LLMenuItemCheckGL>("Memory", TRUE); if (memoryMenu) @@ -695,19 +689,6 @@ class LLAdvancedCheckHUDInfo : public view_listener_t }; -////////////// -// FLYING // -////////////// - -class LLAdvancedAgentFlyingInfo : public view_listener_t -{ - bool handleEvent(const LLSD&) - { - return gAgent.getFlying(); - } -}; - - /////////////////////// // CLEAR GROUP CACHE // /////////////////////// @@ -745,6 +726,10 @@ U32 render_type_from_string(std::string render_type) { return LLPipeline::RENDER_TYPE_AVATAR; } + else if ("controlAV" == render_type) // Animesh + { + return LLPipeline::RENDER_TYPE_CONTROL_AV; + } else if ("surfacePatch" == render_type) { return LLPipeline::RENDER_TYPE_TERRAIN; @@ -2276,8 +2261,8 @@ class LLAdvancedEnableRenderDeferred: public view_listener_t { bool handleEvent(const LLSD& userdata) { - bool new_value = gGLManager.mHasFramebufferObject && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1 && - LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0; + bool new_value = gGLManager.mHasFramebufferObject && LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1 && + LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0; return new_value; } }; @@ -2289,8 +2274,8 @@ class LLAdvancedEnableRenderDeferredOptions: public view_listener_t { bool handleEvent(const LLSD& userdata) { - bool new_value = gGLManager.mHasFramebufferObject && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1 && - LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0 && gSavedSettings.getBOOL("RenderDeferred"); + bool new_value = gGLManager.mHasFramebufferObject && LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1 && + LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0 && gSavedSettings.getBOOL("RenderDeferred"); return new_value; } }; @@ -2378,6 +2363,24 @@ class LLAdvancedForceErrorDriverCrash : public view_listener_t } }; +class LLAdvancedForceErrorCoroutineCrash : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + force_error_coroutine_crash(NULL); + return true; + } +}; + +class LLAdvancedForceErrorThreadCrash : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + force_error_thread_crash(NULL); + return true; + } +}; + class LLAdvancedForceErrorDisconnectViewer : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -2782,7 +2785,6 @@ class LLObjectBuild : public view_listener_t } }; - void handle_object_edit() { LLViewerParcelMgr::getInstance()->deselectLand(); @@ -2827,6 +2829,57 @@ void handle_object_edit() return; } +void handle_attachment_edit(const LLUUID& inv_item_id) +{ + if (isAgentAvatarValid()) + { + if (LLViewerObject* attached_obj = gAgentAvatarp->getWornAttachment(inv_item_id)) + { + LLSelectMgr::getInstance()->deselectAll(); + LLSelectMgr::getInstance()->selectObjectAndFamily(attached_obj); + + handle_object_edit(); + } + } +} + +void handle_attachment_touch(const LLUUID& inv_item_id) +{ + if ( (isAgentAvatarValid()) && (enable_attachment_touch(inv_item_id)) ) + { + if (LLViewerObject* attach_obj = gAgentAvatarp->getWornAttachment(gInventory.getLinkedItemID(inv_item_id))) + { + LLSelectMgr::getInstance()->deselectAll(); + + LLObjectSelectionHandle sel = LLSelectMgr::getInstance()->selectObjectAndFamily(attach_obj); + if (!LLToolMgr::getInstance()->inBuildMode()) + { + struct SetTransient : public LLSelectedNodeFunctor + { + bool apply(LLSelectNode* node) + { + node->setTransient(TRUE); + return true; + } + } f; + sel->applyToNodes(&f); + } + + handle_object_touch(); + } + } +} + +bool enable_attachment_touch(const LLUUID& inv_item_id) +{ + if (isAgentAvatarValid()) + { + const LLViewerObject* attach_obj = gAgentAvatarp->getWornAttachment(gInventory.getLinkedItemID(inv_item_id)); + return (attach_obj) && (attach_obj->flagHandleTouch()); + } + return false; +} + void handle_object_inspect() { LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); @@ -3149,6 +3202,7 @@ class LLObjectMute : public view_listener_t if (avatar) { avatar->mNeedsImpostorUpdate = TRUE; + avatar->mLastImpostorUpdateReason = 9; id = avatar->getID(); @@ -3707,6 +3761,35 @@ bool enable_sitdown_self() return show_sitdown_self() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying(); } +class LLSelfToggleSitStand : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + if (isAgentAvatarValid()) + { + if (gAgentAvatarp->isSitting()) + { + gAgent.standUp(); + } + else + { + gAgent.sitDown(); + } + } + return true; + } +}; + +bool enable_sit_stand() +{ + return enable_sitdown_self() || enable_standup_self(); +} + +bool enable_fly_land() +{ + return gAgent.getFlying() || LLAgent::enableFlying(); +} + class LLCheckPanelPeopleTab : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -4072,25 +4155,31 @@ void near_sit_down_point(BOOL success, void *) class LLLandSit : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgent.standUp(); - LLViewerParcelMgr::getInstance()->deselectLand(); + bool handleEvent(const LLSD& userdata) + { + LLVector3d posGlobal = LLToolPie::getInstance()->getPick().mPosGlobal; - LLVector3d posGlobal = LLToolPie::getInstance()->getPick().mPosGlobal; - - LLQuaternion target_rot; - if (isAgentAvatarValid()) - { - target_rot = gAgentAvatarp->getRotation(); - } - else - { - target_rot = gAgent.getFrameAgent().getQuaternion(); - } - gAgent.startAutoPilotGlobal(posGlobal, "Sit", &target_rot, near_sit_down_point, NULL, 0.7f); - return true; - } + LLQuaternion target_rot; + if (isAgentAvatarValid()) + { + target_rot = gAgentAvatarp->getRotation(); + } + else + { + target_rot = gAgent.getFrameAgent().getQuaternion(); + } + gAgent.startAutoPilotGlobal(posGlobal, "Sit", &target_rot, near_sit_down_point, NULL, 0.7f); + return true; + } +}; + +class LLLandCanSit : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLVector3d posGlobal = LLToolPie::getInstance()->getPick().mPosGlobal; + return !posGlobal.isExactlyZero(); // valid position, not beyond draw distance + } }; //------------------------------------------------------------------- @@ -4109,8 +4198,7 @@ void handle_reset_view() // switching to outfit selector should automagically save any currently edited wearable LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "my_outfits")); } - - gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW); + gAgentCamera.setFocusOnAvatar(TRUE, FALSE, FALSE); reset_view_final( TRUE ); LLFloaterCamera::resetCameraMode(); } @@ -4601,6 +4689,18 @@ void handle_take_copy() derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id); } +void handle_link_objects() +{ + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + LLFloaterReg::toggleInstanceOrBringToFront("places"); + } + else + { + LLSelectMgr::getInstance()->linkObjects(); + } +} + // You can return an object to its owner if it is on your land. class LLObjectReturn : public view_listener_t { @@ -4897,7 +4997,7 @@ void handle_buy_or_take() { LLStringUtil::format_map_t args; args["AMOUNT"] = llformat("%d", total_price); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString( "BuyingCosts", args ), total_price ); + LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString( "this_object_costs", args ), total_price ); } } else @@ -4926,13 +5026,6 @@ bool tools_visible_take_object() return !is_selection_buy_not_take(); } -bool enable_how_to_visible(const LLSD& param) -{ - LLFloaterWebContent::Params p; - p.target = "__help_how_to"; - return LLFloaterReg::instanceVisible("how_to", p); -} - class LLToolsEnableBuyOrTake : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -5359,7 +5452,7 @@ class LLToolsSelectNextPartFace : public view_listener_t new_te = to_select->getNumTEs() - 1; } } - LLSelectMgr::getInstance()->addAsIndividual(to_select, new_te, FALSE); + LLSelectMgr::getInstance()->selectObjectOnly(to_select, new_te); } else { @@ -5888,6 +5981,16 @@ class LLWorldSetHomeLocation : public view_listener_t } }; +class LLWorldLindenHome : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + std::string url = LLFloaterLandHoldings::sHasLindenHome ? LLTrans::getString("lindenhomes_my_home_url") : LLTrans::getString("lindenhomes_get_home_url"); + LLWeb::loadURL(url); + return true; + } +}; + class LLWorldTeleportHome : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -5970,7 +6073,7 @@ class LLWorldCreateLandmark : public view_listener_t { bool handleEvent(const LLSD& userdata) { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); + LLFloaterReg::showInstance("add_landmark"); return true; } @@ -6278,7 +6381,7 @@ void dump_inventory(void*) void handle_dump_followcam(void*) { - LLFollowCamMgr::dump(); + LLFollowCamMgr::getInstance()->dump(); } void handle_viewer_enable_message_log(void*) @@ -6301,6 +6404,11 @@ void handle_edit_outfit() LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); } +void handle_now_wearing() +{ + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "now_wearing")); +} + void handle_edit_shape() { LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_shape")); @@ -6672,10 +6780,10 @@ private: static void onNearAttachObject(BOOL success, void *user_data); void confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point); - - struct CallbackData + class CallbackData : public LLSelectionCallbackData { - CallbackData(LLViewerJointAttachment* point, bool replace) : mAttachmentPoint(point), mReplace(replace) {} + public: + CallbackData(LLViewerJointAttachment* point, bool replace) : LLSelectionCallbackData(), mAttachmentPoint(point), mReplace(replace) {} LLViewerJointAttachment* mAttachmentPoint; bool mReplace; @@ -6716,8 +6824,8 @@ void LLObjectAttachToAvatar::onNearAttachObject(BOOL success, void *user_data) // interpret 0 as "default location" attachment_id = 0; } - LLSelectMgr::getInstance()->sendAttach(attachment_id, cb_data->mReplace); - } + LLSelectMgr::getInstance()->sendAttach(cb_data->getSelection(), attachment_id, cb_data->mReplace); + } LLObjectAttachToAvatar::setObjectSelection(NULL); delete cb_data; @@ -6840,7 +6948,7 @@ class LLAttachmentDetachFromPoint : public view_listener_t iter != attachment->mAttachedObjects.end(); iter++) { - LLViewerObject *attached_object = (*iter); + LLViewerObject *attached_object = iter->get(); ids_to_remove.push_back(attached_object->getAttachmentItemID()); } } @@ -6866,7 +6974,7 @@ static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data) attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - const LLViewerObject* attached_object = (*attachment_iter); + const LLViewerObject* attached_object = attachment_iter->get(); if (attached_object) { LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID()); @@ -6979,7 +7087,7 @@ class LLAttachmentEnableDrop : public view_listener_t { // make sure item is in your inventory (it could be a delayed attach message being sent from the sim) // so check to see if the item is in the inventory already - item = gInventory.getItem((*attachment_iter)->getAttachmentItemID()); + item = gInventory.getItem(attachment_iter->get()->getAttachmentItemID()); if (!item) { // Item does not exist, make an observer to enable the pie menu @@ -7083,7 +7191,21 @@ BOOL object_is_wearable() { return FALSE; } - return gAgentAvatarp->canAttachMoreObjects(); + if (!gAgentAvatarp->canAttachMoreObjects()) + { + return FALSE; + } + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) + { + LLSelectNode* node = *iter; + if (node->mPermissions->getOwner() == gAgent.getID()) + { + return TRUE; + } + } + return FALSE; } @@ -7361,7 +7483,7 @@ void handle_dump_attachments(void*) attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - LLViewerObject *attached_object = (*attachment_iter); + LLViewerObject *attached_object = attachment_iter->get(); BOOL visible = (attached_object != NULL && attached_object->mDrawable.notNull() && !attached_object->mDrawable->isRenderType(0)); @@ -7381,6 +7503,8 @@ void handle_dump_attachments(void*) // these are used in the gl menus to set control values, generically. class LLToggleControl : public view_listener_t { +protected: + bool handleEvent(const LLSD& userdata) { std::string control_name = userdata.asString(); @@ -7457,6 +7581,24 @@ class LLAdvancedClickRenderBenchmark: public view_listener_t } }; +// these are used in the gl menus to set control values that require shader recompilation +class LLToggleShaderControl : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + std::string control_name = userdata.asString(); + BOOL checked = gSavedSettings.getBOOL( control_name ); + gSavedSettings.setBOOL( control_name, !checked ); + LLPipeline::refreshCachedSettings(); + //gPipeline.updateRenderDeferred(); + //gPipeline.releaseGLBuffers(); + //gPipeline.createGLBuffers(); + //gPipeline.resetVertexBuffers(); + LLViewerShaderMgr::instance()->setShaders(); + return !checked; + } +}; + void menu_toggle_attached_lights(void* user_data) { LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); @@ -7623,15 +7765,7 @@ class LLToggleHowTo : public view_listener_t { bool handleEvent(const LLSD& userdata) { - LLFloaterWebContent::Params p; - std::string url = gSavedSettings.getString("HowToHelpURL"); - p.url = LLWeb::expandURLSubstitutions(url, LLSD()); - p.show_chrome = false; - p.target = "__help_how_to"; - p.show_page_title = false; - p.preferred_media_size = LLRect(0, 460, 335, 0); - - LLFloaterReg::toggleInstanceOrBringToFront("how_to", p); + LLFloaterReg::toggleInstanceOrBringToFront("guidebook"); return true; } }; @@ -7830,7 +7964,7 @@ void handle_grab_baked_texture(void* data) if(folder_id.notNull()) { std::string name; - name = "Baked " + LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(baked_tex_index)->mNameCapitalized + " Texture"; + name = "Baked " + LLAvatarAppearance::getDictionary()->getBakedTexture(baked_tex_index)->mNameCapitalized + " Texture"; LLUUID item_id; item_id.generate(); @@ -7960,6 +8094,16 @@ void force_error_driver_crash(void *) LLAppViewer::instance()->forceErrorDriverCrash(); } +void force_error_coroutine_crash(void *) +{ + LLAppViewer::instance()->forceErrorCoroutineCrash(); +} + +void force_error_thread_crash(void *) +{ + LLAppViewer::instance()->forceErrorThreadCrash(); +} + class LLToolsUseSelectionForGrid : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -8003,7 +8147,6 @@ BOOL LLViewerMenuHolderGL::hideMenus() if (LLMenuHolderGL::hideMenus()) { - LLToolPie::instance().blockClickToWalk(); handled = TRUE; } @@ -8258,6 +8401,14 @@ class LLViewToggleBeacon : public view_listener_t gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons() ); } } + else if (beacon == "sunbeacon") + { + gSavedSettings.setBOOL("sunbeacon", !gSavedSettings.getBOOL("sunbeacon")); + } + else if (beacon == "moonbeacon") + { + gSavedSettings.setBOOL("moonbeacon", !gSavedSettings.getBOOL("moonbeacon")); + } else if (beacon == "renderbeacons") { LLPipeline::toggleRenderBeacons(); @@ -8474,42 +8625,68 @@ class LLToolsSelectTool : public view_listener_t /// WINDLIGHT callbacks class LLWorldEnvSettings : public view_listener_t { + void defocusEnvFloaters() + { + //currently there is only one instance of each floater + std::vector<std::string> env_floaters_names = { "env_edit_extdaycycle", "env_fixed_environmentent_water", "env_fixed_environmentent_sky" }; + for (std::vector<std::string>::const_iterator it = env_floaters_names.begin(); it != env_floaters_names.end(); ++it) + { + LLFloater* env_floater = LLFloaterReg::findTypedInstance<LLFloater>(*it); + if (env_floater) + { + env_floater->setFocus(FALSE); + } + } + } + bool handleEvent(const LLSD& userdata) { - std::string tod = userdata.asString(); + std::string event_name = userdata.asString(); - if (tod == "editor") + if (event_name == "sunrise") { - LLFloaterReg::toggleInstance("env_settings"); - return true; + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_SUNRISE, LLEnvironment::TRANSITION_INSTANT); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); + defocusEnvFloaters(); } - - if (tod == "sunrise") + else if (event_name == "noon") { - LLEnvManagerNew::instance().setUseSkyPreset("Sunrise"); + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_MIDDAY, LLEnvironment::TRANSITION_INSTANT); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); + defocusEnvFloaters(); } - else if (tod == "noon") + else if (event_name == "sunset") { - LLEnvManagerNew::instance().setUseSkyPreset("Midday"); + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_SUNSET, LLEnvironment::TRANSITION_INSTANT); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); + defocusEnvFloaters(); } - else if (tod == "sunset") + else if (event_name == "midnight") { - LLEnvManagerNew::instance().setUseSkyPreset("Sunset"); + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_MIDNIGHT, LLEnvironment::TRANSITION_INSTANT); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); + defocusEnvFloaters(); } - else if (tod == "midnight") + else if (event_name == "region") { - LLEnvManagerNew::instance().setUseSkyPreset("Midnight"); + LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_LOCAL); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); + defocusEnvFloaters(); } + else if (event_name == "pause_clouds") + { + if (LLEnvironment::instance().isCloudScrollPaused()) + LLEnvironment::instance().resumeCloudScroll(); else + LLEnvironment::instance().pauseCloudScroll(); + } + else if (event_name == "adjust_tool") { - LLEnvManagerNew &envmgr = LLEnvManagerNew::instance(); - // reset all environmental settings to track the region defaults, make this reset 'sticky' like the other sun settings. - bool use_fixed_sky = false; - bool use_region_settings = true; - envmgr.setUserPrefs(envmgr.getWaterPresetName(), - envmgr.getSkyPresetName(), - envmgr.getDayCycleName(), - use_fixed_sky, use_region_settings); + LLFloaterReg::showInstance("env_adjust_snapshot"); + } + else if (event_name == "my_environs") + { + LLFloaterReg::showInstance("my_environments"); } return true; @@ -8521,39 +8698,46 @@ class LLWorldEnableEnvSettings : public view_listener_t bool handleEvent(const LLSD& userdata) { bool result = false; - std::string tod = userdata.asString(); + std::string event_name = userdata.asString(); - if (LLEnvManagerNew::instance().getUseRegionSettings()) + if (event_name == "pause_clouds") { - return (tod == "region"); + return LLEnvironment::instance().isCloudScrollPaused(); } - if (LLEnvManagerNew::instance().getUseFixedSky()) + LLSettingsSky::ptr_t sky = LLEnvironment::instance().getEnvironmentFixedSky(LLEnvironment::ENV_LOCAL); + + if (!sky) { - if (tod == "sunrise") + return (event_name == "region"); + } + + std::string skyname = (sky) ? sky->getName() : ""; + LLUUID skyid = (sky) ? sky->getAssetId() : LLUUID::null; + + if (event_name == "sunrise") { - result = (LLEnvManagerNew::instance().getSkyPresetName() == "Sunrise"); + result = (skyid == LLEnvironment::KNOWN_SKY_SUNRISE); } - else if (tod == "noon") + else if (event_name == "noon") { - result = (LLEnvManagerNew::instance().getSkyPresetName() == "Midday"); + result = (skyid == LLEnvironment::KNOWN_SKY_MIDDAY); } - else if (tod == "sunset") + else if (event_name == "sunset") { - result = (LLEnvManagerNew::instance().getSkyPresetName() == "Sunset"); + result = (skyid == LLEnvironment::KNOWN_SKY_SUNSET); } - else if (tod == "midnight") + else if (event_name == "midnight") { - result = (LLEnvManagerNew::instance().getSkyPresetName() == "Midnight"); + result = (skyid == LLEnvironment::KNOWN_SKY_MIDNIGHT); } - else if (tod == "region") + else if (event_name == "region") { return false; } else { - LL_WARNS() << "Unknown time-of-day item: " << tod << LL_ENDL; - } + LL_WARNS() << "Unknown time-of-day item: " << event_name << LL_ENDL; } return result; } @@ -8567,39 +8751,27 @@ class LLWorldEnvPreset : public view_listener_t if (item == "new_water") { - LLFloaterReg::showInstance("env_edit_water", "new"); + LLFloaterReg::showInstance("env_fixed_environmentent_water", "new"); } else if (item == "edit_water") { - LLFloaterReg::showInstance("env_edit_water", "edit"); - } - else if (item == "delete_water") - { - LLFloaterReg::showInstance("env_delete_preset", "water"); + LLFloaterReg::showInstance("env_fixed_environmentent_water", "edit"); } else if (item == "new_sky") { - LLFloaterReg::showInstance("env_edit_sky", "new"); + LLFloaterReg::showInstance("env_fixed_environmentent_sky", "new"); } else if (item == "edit_sky") { - LLFloaterReg::showInstance("env_edit_sky", "edit"); - } - else if (item == "delete_sky") - { - LLFloaterReg::showInstance("env_delete_preset", "sky"); + LLFloaterReg::showInstance("env_fixed_environmentent_sky", "edit"); } else if (item == "new_day_cycle") { - LLFloaterReg::showInstance("env_edit_day_cycle", "new"); + LLFloaterReg::showInstance("env_edit_extdaycycle", LLSDMap("edit_context", "inventory")); } else if (item == "edit_day_cycle") { - LLFloaterReg::showInstance("env_edit_day_cycle", "edit"); - } - else if (item == "delete_day_cycle") - { - LLFloaterReg::showInstance("env_delete_preset", "day_cycle"); + LLFloaterReg::showInstance("env_edit_extdaycycle", LLSDMap("edit_context", "inventory")); } else { @@ -8614,30 +8786,6 @@ class LLWorldEnableEnvPreset : public view_listener_t { bool handleEvent(const LLSD& userdata) { - std::string item = userdata.asString(); - - if (item == "delete_water") - { - LLWaterParamManager::preset_name_list_t user_waters; - LLWaterParamManager::instance().getUserPresetNames(user_waters); - return !user_waters.empty(); - } - else if (item == "delete_sky") - { - LLWLParamManager::preset_name_list_t user_skies; - LLWLParamManager::instance().getUserPresetNames(user_skies); - return !user_skies.empty(); - } - else if (item == "delete_day_cycle") - { - LLDayCycleManager::preset_name_list_t user_days; - LLDayCycleManager::instance().getUserPresetNames(user_days); - return !user_days.empty(); - } - else - { - LL_WARNS() << "Unknown item" << LL_ENDL; - } return false; } @@ -8656,7 +8804,6 @@ class LLWorldPostProcess : public view_listener_t void handle_flush_name_caches() { - SUBSYSTEM_CLEANUP(LLAvatarNameCache); if (gCacheName) gCacheName->clear(); } @@ -8666,18 +8813,42 @@ class LLUploadCostCalculator : public view_listener_t bool handleEvent(const LLSD& userdata) { - std::string menu_name = userdata.asString(); + std::vector<std::string> fields; + std::string str = userdata.asString(); + boost::split(fields, str, boost::is_any_of(",")); + if (fields.size()<1) + { + return false; + } + std::string menu_name = fields[0]; + std::string asset_type_str = "texture"; + if (fields.size()>1) + { + asset_type_str = fields[1]; + } + LL_DEBUGS("Benefits") << "userdata " << userdata << " menu_name " << menu_name << " asset_type_str " << asset_type_str << LL_ENDL; + calculateCost(asset_type_str); gMenuHolder->childSetLabelArg(menu_name, "[COST]", mCostStr); return true; } - void calculateCost(); + void calculateCost(const std::string& asset_type_str); public: LLUploadCostCalculator() { - calculateCost(); + } +}; + +class LLUpdateMembershipLabel : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + const std::string label_str = LLAgentBenefitsMgr::isCurrent("Base") ? LLTrans::getString("MembershipUpgradeText") : LLTrans::getString("MembershipPremiumText"); + gMenuHolder->childSetLabelArg("Membership", "[Membership]", label_str); + + return true; } }; @@ -8703,19 +8874,27 @@ class LLToggleUIHints : public view_listener_t } }; -void LLUploadCostCalculator::calculateCost() +void LLUploadCostCalculator::calculateCost(const std::string& asset_type_str) { - S32 upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload(); + S32 upload_cost = -1; - // getPriceUpload() returns -1 if no data available yet. - if(upload_cost >= 0) + if (asset_type_str == "texture") { - mCostStr = llformat("%d", upload_cost); + upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); } - else + else if (asset_type_str == "animation") + { + upload_cost = LLAgentBenefitsMgr::current().getAnimationUploadCost(); + } + else if (asset_type_str == "sound") { - mCostStr = llformat("%d", gSavedSettings.getU32("DefaultUploadCost")); + upload_cost = LLAgentBenefitsMgr::current().getSoundUploadCost(); } + if (upload_cost < 0) + { + LL_WARNS() << "Unable to find upload cost for asset_type_str " << asset_type_str << LL_ENDL; + } + mCostStr = std::to_string(upload_cost); } void show_navbar_context_menu(LLView* ctrl, S32 x, S32 y) @@ -8822,11 +9001,13 @@ void initialize_menus() view_listener_t::addEnable(new LLUploadCostCalculator(), "Upload.CalculateCosts"); + view_listener_t::addEnable(new LLUpdateMembershipLabel(), "Membership.UpdateLabel"); + enable.add("Conversation.IsConversationLoggingAllowed", boost::bind(&LLFloaterIMContainer::isConversationLoggingAllowed)); // Agent commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying)); - enable.add("Agent.enableFlying", boost::bind(&LLAgent::enableFlying)); + enable.add("Agent.enableFlyLand", boost::bind(&enable_fly_land)); commit.add("Agent.PressMicrophone", boost::bind(&LLAgent::pressMicrophone, _2)); commit.add("Agent.ReleaseMicrophone", boost::bind(&LLAgent::releaseMicrophone, _2)); commit.add("Agent.ToggleMicrophone", boost::bind(&LLAgent::toggleMicrophone, _2)); @@ -8842,6 +9023,7 @@ void initialize_menus() view_listener_t::addMenu(new LLEnableHoverHeight(), "Edit.EnableHoverHeight"); view_listener_t::addMenu(new LLEnableEditPhysics(), "Edit.EnableEditPhysics"); commit.add("CustomizeAvatar", boost::bind(&handle_customize_avatar)); + commit.add("NowWearing", boost::bind(&handle_now_wearing)); commit.add("EditOutfit", boost::bind(&handle_edit_outfit)); commit.add("EditShape", boost::bind(&handle_edit_shape)); commit.add("HoverHeight", boost::bind(&handle_hover_height)); @@ -8874,9 +9056,6 @@ void initialize_menus() view_listener_t::addMenu(new LLViewStatusDoNotDisturb(), "View.Status.CheckDoNotDisturb"); view_listener_t::addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments"); - // Me > Movement - view_listener_t::addMenu(new LLAdvancedAgentFlyingInfo(), "Agent.getFlying"); - //Communicate Nearby chat view_listener_t::addMenu(new LLCommunicateNearbyChat(), "Communicate.NearbyChat"); @@ -8898,6 +9077,7 @@ void initialize_menus() view_listener_t::addMenu(new LLWorldTeleportHome(), "World.TeleportHome"); view_listener_t::addMenu(new LLWorldSetAway(), "World.SetAway"); view_listener_t::addMenu(new LLWorldSetDoNotDisturb(), "World.SetDoNotDisturb"); + view_listener_t::addMenu(new LLWorldLindenHome(), "World.LindenHome"); view_listener_t::addMenu(new LLWorldEnableCreateLandmark(), "World.EnableCreateLandmark"); view_listener_t::addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation"); @@ -8923,7 +9103,7 @@ void initialize_menus() view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY"); view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid"); view_listener_t::addMenu(new LLToolsSelectNextPartFace(), "Tools.SelectNextPart"); - commit.add("Tools.Link", boost::bind(&LLSelectMgr::linkObjects, LLSelectMgr::getInstance())); + commit.add("Tools.Link", boost::bind(&handle_link_objects)); commit.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance())); view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations"); view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys"); @@ -8952,7 +9132,6 @@ void initialize_menus() // Help menu // most items use the ShowFloater method view_listener_t::addMenu(new LLToggleHowTo(), "Help.ToggleHowTo"); - enable.add("Help.HowToVisible", boost::bind(&enable_how_to_visible, _2)); // Advanced menu view_listener_t::addMenu(new LLAdvancedToggleConsole(), "Advanced.ToggleConsole"); @@ -9097,6 +9276,8 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop"); view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException"); view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash"); + view_listener_t::addMenu(new LLAdvancedForceErrorCoroutineCrash(), "Advanced.ForceErrorCoroutineCrash"); + view_listener_t::addMenu(new LLAdvancedForceErrorThreadCrash(), "Advanced.ForceErrorThreadCrash"); view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer"); // Advanced (toplevel) @@ -9144,11 +9325,8 @@ void initialize_menus() view_listener_t::addMenu(new LLAdminOnSaveState(), "Admin.OnSaveState"); // Self context menu - view_listener_t::addMenu(new LLSelfStandUp(), "Self.StandUp"); - enable.add("Self.EnableStandUp", boost::bind(&enable_standup_self)); - view_listener_t::addMenu(new LLSelfSitDown(), "Self.SitDown"); - enable.add("Self.EnableSitDown", boost::bind(&enable_sitdown_self)); - enable.add("Self.ShowSitDown", boost::bind(&show_sitdown_self)); + view_listener_t::addMenu(new LLSelfToggleSitStand(), "Self.ToggleSitStand"); + enable.add("Self.EnableSitStand", boost::bind(&enable_sit_stand)); view_listener_t::addMenu(new LLSelfRemoveAllAttachments(), "Self.RemoveAllAttachments"); view_listener_t::addMenu(new LLSelfEnableRemoveAllAttachments(), "Self.EnableRemoveAllAttachments"); @@ -9214,6 +9392,7 @@ void initialize_menus() enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1)); view_listener_t::addMenu(new LLObjectEnableReturn(), "Object.EnableReturn"); + enable.add("Object.EnableDuplicate", boost::bind(&LLSelectMgr::canDuplicate, LLSelectMgr::getInstance())); view_listener_t::addMenu(new LLObjectEnableReportAbuse(), "Object.EnableReportAbuse"); enable.add("Avatar.EnableMute", boost::bind(&enable_object_mute)); @@ -9234,6 +9413,7 @@ void initialize_menus() // Land pie menu view_listener_t::addMenu(new LLLandBuild(), "Land.Build"); view_listener_t::addMenu(new LLLandSit(), "Land.Sit"); + view_listener_t::addMenu(new LLLandCanSit(), "Land.CanSit"); view_listener_t::addMenu(new LLLandBuyPass(), "Land.BuyPass"); view_listener_t::addMenu(new LLLandEdit(), "Land.Edit"); @@ -9253,6 +9433,7 @@ void initialize_menus() view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile"); view_listener_t::addMenu(new LLToggleAgentProfile(), "ToggleAgentProfile"); view_listener_t::addMenu(new LLToggleControl(), "ToggleControl"); + view_listener_t::addMenu(new LLToggleShaderControl(), "ToggleShaderControl"); view_listener_t::addMenu(new LLCheckControl(), "CheckControl"); view_listener_t::addMenu(new LLGoToObject(), "GoToObject"); commit.add("PayObject", boost::bind(&handle_give_money_dialog)); diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index 6882405407..36b6971c81 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -82,7 +82,6 @@ void handle_detach(void*); 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); @@ -110,6 +109,10 @@ void handle_object_return(); void handle_object_delete(); void handle_object_edit(); +void handle_attachment_edit(const LLUUID& inv_item_id); +void handle_attachment_touch(const LLUUID& inv_item_id); +bool enable_attachment_touch(const LLUUID& inv_item_id); + void handle_buy_land(); // Takes avatar UUID, or if no UUID passed, uses last selected object @@ -185,10 +188,14 @@ extern LLContextMenu *gMenuMuteParticle; extern LLMenuGL* gAttachSubMenu; extern LLMenuGL* gDetachSubMenu; extern LLMenuGL* gTakeOffClothes; +extern LLMenuGL* gDetachAvatarMenu; +extern LLMenuGL* gDetachHUDAvatarMenu; extern LLContextMenu* gAttachScreenPieMenu; extern LLContextMenu* gDetachScreenPieMenu; +extern LLContextMenu* gDetachHUDAttSelfMenu; extern LLContextMenu* gAttachPieMenu; extern LLContextMenu* gDetachPieMenu; +extern LLContextMenu* gDetachAttSelfMenu; extern LLContextMenu* gAttachBodyPartPieMenus[9]; extern LLContextMenu* gDetachBodyPartPieMenus[9]; diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index a9a91b158b..15181dcd9f 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -30,6 +30,7 @@ // project includes #include "llagent.h" +#include "llagentbenefits.h" #include "llagentcamera.h" #include "llfilepicker.h" #include "llfloaterreg.h" @@ -67,7 +68,6 @@ #include "llviewerassetupload.h" // linden libraries -#include "lleconomy.h" #include "llnotificationsutil.h" #include "llsdserialize.h" #include "llsdutil.h" @@ -85,8 +85,6 @@ class LLFileEnableUpload : public view_listener_t bool handleEvent(const LLSD& userdata) { return true; -// bool new_value = gStatusBar && LLGlobalEconomy::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::getInstance()->getPriceUpload()); -// return new_value; } }; @@ -393,7 +391,9 @@ const void upload_single_file(const std::vector<std::string>& filenames, LLFileP } if (type == LLFilePicker::FFLOAD_ANIM) { - if (filename.rfind(".anim") != std::string::npos) + std::string filename_lc(filename); + LLStringUtil::toLower(filename_lc); + if (filename_lc.rfind(".anim") != std::string::npos) { LLFloaterReg::showInstance("upload_anim_anim", LLSD(filename)); } @@ -406,22 +406,18 @@ const void upload_single_file(const std::vector<std::string>& filenames, LLFileP return; } - -const void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type) +void do_bulk_upload(std::vector<std::string> filenames, const LLSD& notification, const LLSD& response) { - // TODO: - // Check user balance for entire cost - // Charge user entire cost - // Loop, uploading - // If an upload fails, refund the user for that one - // - // Also fix single upload to charge first, then refund + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) + { + // Cancel upload + return; + } - S32 expected_upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload(); for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) { std::string filename = (*in_iter); - if (!check_file_extension(filename, type)) continue; std::string name = gDirUtilp->getBaseFileName(filename, true); std::string asset_name = name; @@ -430,6 +426,13 @@ const void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker:: LLStringUtil::stripNonprintable(asset_name); LLStringUtil::trim(asset_name); + std::string ext = gDirUtilp->getExtension(filename); + LLAssetType::EType asset_type; + U32 codec; + S32 expected_upload_cost; + if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) && + LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost)) + { LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo( filename, asset_name, @@ -440,9 +443,96 @@ const void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker:: LLFloaterPerms::getEveryonePerms("Uploads"), expected_upload_cost)); - upload_new_resource(uploadInfo, NULL, NULL); + upload_new_resource(uploadInfo); } } +} + +bool get_bulk_upload_expected_cost(const std::vector<std::string>& filenames, S32& total_cost, S32& file_count, S32& bvh_count) +{ + total_cost = 0; + file_count = 0; + bvh_count = 0; + for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) + { + std::string filename = (*in_iter); + std::string ext = gDirUtilp->getExtension(filename); + + if (ext == "bvh") + { + bvh_count++; + } + + LLAssetType::EType asset_type; + U32 codec; + S32 cost; + + if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) && + LLAgentBenefitsMgr::current().findUploadCost(asset_type, cost)) + { + total_cost += cost; + file_count++; + } + } + + return file_count > 0; +} + +const void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type) +{ + // TODO: + // Check user balance for entire cost + // Charge user entire cost + // Loop, uploading + // If an upload fails, refund the user for that one + // + // Also fix single upload to charge first, then refund + + // FIXME PREMIUM what about known types that can't be bulk uploaded + // (bvh)? These will fail in the item by item upload but won't be + // mentioned in the notification. + std::vector<std::string> filtered_filenames; + for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) + { + const std::string& filename = *in_iter; + if (check_file_extension(filename, type)) + { + filtered_filenames.push_back(filename); + } + } + + S32 expected_upload_cost; + S32 expected_upload_count; + S32 bvh_count; + if (get_bulk_upload_expected_cost(filtered_filenames, expected_upload_cost, expected_upload_count, bvh_count)) + { + LLSD args; + args["COST"] = expected_upload_cost; + args["COUNT"] = expected_upload_count; + LLNotificationsUtil::add("BulkUploadCostConfirmation", args, LLSD(), boost::bind(do_bulk_upload, filtered_filenames, _1, _2)); + + if (filtered_filenames.size() > expected_upload_count) + { + if (bvh_count == filtered_filenames.size() - expected_upload_count) + { + LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload"); + } + else + { + LLNotificationsUtil::add("BulkUploadIncompatibleFiles"); + } + } + } + else if (bvh_count == filtered_filenames.size()) + { + LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload"); + } + else + { + LLNotificationsUtil::add("BulkUploadNoCompatibleFiles"); + } + +} class LLFileUploadImage : public view_listener_t { @@ -464,7 +554,7 @@ class LLFileUploadModel : public view_listener_t LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::getInstance("upload_model"); if (fmp && !fmp->isModelLoading()) { - fmp->loadModel(3); + fmp->loadHighLodModel(); } return TRUE; @@ -595,10 +685,17 @@ class LLFileTakeSnapshotToDisk : public view_listener_t S32 width = gViewerWindow->getWindowWidthRaw(); S32 height = gViewerWindow->getWindowHeightRaw(); - if (gSavedSettings.getBOOL("HighResSnapshot")) + bool render_ui = gSavedSettings.getBOOL("RenderUIInSnapshot"); + bool render_hud = gSavedSettings.getBOOL("RenderHUDInSnapshot"); + + BOOL high_res = gSavedSettings.getBOOL("HighResSnapshot"); + if (high_res) { width *= 2; height *= 2; + // not compatible with UI/HUD + render_ui = false; + render_hud = false; } if (gViewerWindow->rawSnapshot(raw, @@ -606,8 +703,11 @@ class LLFileTakeSnapshotToDisk : public view_listener_t height, TRUE, FALSE, - gSavedSettings.getBOOL("RenderUIInSnapshot"), - FALSE)) + render_ui, + render_hud, + FALSE, + LLSnapshotModel::SNAPSHOT_TYPE_COLOR, + high_res ? S32_MAX : MAX_SNAPSHOT_IMAGE_SIZE)) //per side { LLPointer<LLImageFormatted> formatted; LLSnapshotModel::ESnapshotFormat fmt = (LLSnapshotModel::ESnapshotFormat) gSavedSettings.getS32("SnapshotFormat"); @@ -693,7 +793,7 @@ LLUUID upload_new_resource( bool show_inventory) { - LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo( + LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLNewFileResourceUploadInfo>( src_filename, name, desc, compression_info, destination_folder_type, inv_type, @@ -730,10 +830,7 @@ void upload_done_callback( if(!(can_afford_transaction(expected_upload_cost))) { - LLStringUtil::format_map_t args; - args["NAME"] = data->mAssetInfo.getName(); - args["AMOUNT"] = llformat("%d", expected_upload_cost); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost ); + LLBuyCurrencyHTML::openCurrencyFloater( "", expected_upload_cost ); is_balance_sufficient = FALSE; } else if(region) @@ -776,7 +873,7 @@ void upload_done_callback( create_inventory_item(gAgent.getID(), gAgent.getSessionID(), folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(), data->mAssetInfo.getDescription(), data->mAssetInfo.mType, - data->mInventoryType, NOT_WEARABLE, next_owner_perms, + data->mInventoryType, NO_INV_SUBTYPE, next_owner_perms, LLPointer<LLInventoryCallback>(NULL)); } else @@ -812,7 +909,7 @@ void upload_done_callback( LLStringUtil::trim(asset_name); std::string display_name = LLStringUtil::null; - LLAssetStorage::LLStoreAssetCallback callback = NULL; + LLAssetStorage::LLStoreAssetCallback callback; void *userdata = NULL; upload_new_resource( next_file, @@ -867,10 +964,7 @@ void upload_new_resource( if (balance < uploadInfo->getExpectedUploadCost()) { // insufficient funds, bail on this upload - LLStringUtil::format_map_t args; - args["NAME"] = uploadInfo->getName(); - args["AMOUNT"] = llformat("%d", uploadInfo->getExpectedUploadCost()); - LLBuyCurrencyHTML::openCurrencyFloater(LLTrans::getString("UploadingCosts", args), uploadInfo->getExpectedUploadCost()); + LLBuyCurrencyHTML::openCurrencyFloater("", uploadInfo->getExpectedUploadCost()); return; } } diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index 4e8348b5e5..4e6250d9b4 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -60,7 +60,7 @@ LLUUID upload_new_resource( void upload_new_resource( LLResourceUploadInfo::ptr_t &uploadInfo, - LLAssetStorage::LLStoreAssetCallback callback = NULL, + LLAssetStorage::LLStoreAssetCallback callback = LLAssetStorage::LLStoreAssetCallback(), void *userdata = NULL); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 6e5c77e4a9..39c891c9c1 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -32,7 +32,6 @@ #include "llaudioengine.h" #include "llavataractions.h" #include "llavatarnamecache.h" // IDEVO HACK -#include "lleconomy.h" #include "lleventtimer.h" #include "llfloaterreg.h" #include "llfolderview.h" @@ -51,6 +50,7 @@ #include "mean_collision_data.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llagentcamera.h" #include "llcallingcard.h" #include "llbuycurrencyhtml.h" @@ -116,7 +116,6 @@ #include "llviewerregion.h" #include "llfloaterregionrestarting.h" -#include <boost/algorithm/string/split.hpp> // #include <boost/foreach.hpp> #include "llnotificationmanager.h" // @@ -374,6 +373,11 @@ void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_ LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")"<< LL_ENDL; if(can_afford_transaction(amount)) { + if (uuid.isNull()) + { + LL_WARNS() << "Failed to send L$ gift to to Null UUID." << LL_ENDL; + return; + } // gStatusBar->debitBalance(amount); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_MoneyTransferRequest); @@ -401,6 +405,7 @@ void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_ void send_complete_agent_movement(const LLHost& sim_host) { + LL_DEBUGS("Teleport", "Messaging") << "Sending CompleteAgentMovement to sim_host " << sim_host << LL_ENDL; LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_CompleteAgentMovement); msg->nextBlockFast(_PREHASH_AgentData); @@ -772,7 +777,6 @@ void response_group_invitation_coro(std::string url, LLUUID group_id, bool notif 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); @@ -903,7 +907,7 @@ bool join_group_response(const LLSD& notification, const LLSD& response) if(option == 0 && !group_id.isNull()) { // check for promotion or demotion. - S32 max_groups = gMaxAgentGroups; + S32 max_groups = LLAgentBenefitsMgr::current().getGroupMembershipLimit(); if(gAgent.isInGroup(group_id)) ++max_groups; if(gAgent.mGroups.size() < max_groups) @@ -1671,8 +1675,20 @@ void LLOfferInfo::fromLLSD(const LLSD& params) *this = params; } -void LLOfferInfo::send_auto_receive_response(void) -{ +void LLOfferInfo::sendReceiveResponse(bool accept, const LLUUID &destination_folder_id) +{ + if(IM_INVENTORY_OFFERED == mIM) + { + // add buddy to recent people list + LLRecentPeople::instance().add(mFromID); + } + + if (mTransactionID.isNull()) + { + // Not provided, message won't work + return; + } + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_ImprovedInstantMessage); msg->nextBlockFast(_PREHASH_AgentData); @@ -1691,23 +1707,42 @@ void LLOfferInfo::send_auto_receive_response(void) msg->addU32Fast(_PREHASH_ParentEstateID, 0); msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); - - // Auto Receive Message. The math for the dialog works, because the accept + + // ACCEPT. The math for the dialog works, because the accept // for inventory_offered, task_inventory_offer or // group_notice_inventory is 1 greater than the offer integer value. // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED - msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1)); - msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData), - sizeof(mFolderID.mData)); - // send the message - msg->sendReliable(mHost); - - if(IM_INVENTORY_OFFERED == mIM) + // Decline for inventory_offered, task_inventory_offer or + // group_notice_inventory is 2 greater than the offer integer value. + + EInstantMessage im = mIM; + if (mIM == IM_GROUP_NOTICE_REQUESTED) { - // add buddy to recent people list - LLRecentPeople::instance().add(mFromID); + // Request has no responder dialogs + im = IM_GROUP_NOTICE; + } + + if (accept) + { + msg->addU8Fast(_PREHASH_Dialog, (U8)(im + 1)); + msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(destination_folder_id.mData), + sizeof(destination_folder_id.mData)); } + else + { + msg->addU8Fast(_PREHASH_Dialog, (U8)(im + 2)); + msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE); + } + // send the message + msg->sendReliable(mHost); + + // transaction id is usable only once + // Note: a bit of a hack, clicking group notice attachment will not close notice + // so we reset no longer usable transaction id to know not to send message again + // Once capabilities for responses will be implemented LLOfferInfo will have to + // remember that it already responded in another way and ignore IOR_DECLINE + mTransactionID.setNull(); } void LLOfferInfo::handleRespond(const LLSD& notification, const LLSD& response) @@ -1767,7 +1802,10 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& // TODO: when task inventory offers can also be handled the new way, migrate the code that sets these strings here: from_string = chatHistory_string = mFromName; - + + // accept goes to proper folder, decline gets accepted to trash, muted gets declined + bool accept_to_trash = true; + LLNotificationFormPtr modified_form(notification_ptr ? new LLNotificationForm(*notification_ptr->getForm()) : new LLNotificationForm()); switch(button) @@ -1799,11 +1837,11 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& } break; case IM_GROUP_NOTICE: + case IM_GROUP_NOTICE_REQUESTED: opener = new LLOpenTaskGroupOffer; - send_auto_receive_response(); + sendReceiveResponse(true, mFolderID); break; case IM_TASK_INVENTORY_OFFERED: - case IM_GROUP_NOTICE_REQUESTED: // This is an offer from a task or group. // We don't use a new instance of an opener // We instead use the singular observer gOpenTaskOffer @@ -1838,6 +1876,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& { modified_form->setElementEnabled("Mute", false); } + accept_to_trash = false; // for notices, but IOR_MUTE normally doesn't happen for notices // MUTE falls through to decline case IOR_DECLINE: { @@ -1851,21 +1890,32 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) ) // muting for SL-42269 { chat.mMuted = TRUE; + accept_to_trash = false; // will send decline message } // *NOTE dzaporozhan // Disabled logging to old chat floater to fix crash in group notices - EXT-4149 // LLFloaterChat::addChatHistory(chat); - LLDiscardAgentOffer* discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID); - discard_agent_offer->startFetch(); - if ((catp && gInventory.isCategoryComplete(mObjectID)) || (itemp && itemp->isFinished())) + if (mObjectID.notNull()) //make sure we can discard { - discard_agent_offer->done(); + LLDiscardAgentOffer* discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID); + discard_agent_offer->startFetch(); + if ((catp && gInventory.isCategoryComplete(mObjectID)) || (itemp && itemp->isFinished())) + { + discard_agent_offer->done(); + } + else + { + opener = discard_agent_offer; + } } - else + else if (mIM == IM_GROUP_NOTICE) { - opener = discard_agent_offer; + // group notice needs to request object to trash so that user will see it later + // Note: muted agent offers go to trash, not sure if we should do same for notices + LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + sendReceiveResponse(accept_to_trash, trash); } if (modified_form != NULL) @@ -1878,9 +1928,14 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& } default: // close button probably - // The item has already been fetched and is in your inventory, we simply won't highlight it + // In case of agent offers item has already been fetched and is in your inventory, we simply won't highlight it // OR delete it if the notification gets killed, since we don't want that to be a vector for // losing inventory offers. + if (mIM == IM_GROUP_NOTICE) + { + LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + sendReceiveResponse(true, trash); + } break; } @@ -1925,29 +1980,10 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const } } } - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ImprovedInstantMessage); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_MessageBlock); - msg->addBOOLFast(_PREHASH_FromGroup, FALSE); - msg->addUUIDFast(_PREHASH_ToAgentID, mFromID); - msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); - msg->addUUIDFast(_PREHASH_ID, mTransactionID); - msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary - std::string name; - LLAgentUI::buildFullname(name); - msg->addStringFast(_PREHASH_FromAgentName, name); - msg->addStringFast(_PREHASH_Message, ""); - msg->addU32Fast(_PREHASH_ParentEstateID, 0); - msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); - msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); - LLInventoryObserver* opener = NULL; - + std::string from_string; // Used in the pop-up. std::string chatHistory_string; // Used in chat history. + if (mFromObject == TRUE) { if (mFromGroup) @@ -1991,23 +2027,15 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const from_string = chatHistory_string = mFromName; } - bool is_do_not_disturb = gAgent.isDoNotDisturb(); - + LLUUID destination; + bool accept = true; + + // If user accepted, accept to proper folder, if user discarded, accept to trash. switch(button) { case IOR_ACCEPT: - // ACCEPT. The math for the dialog works, because the accept - // for inventory_offered, task_inventory_offer or - // group_notice_inventory is 1 greater than the offer integer value. - // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, - // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED - msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1)); - msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData), - sizeof(mFolderID.mData)); - // send the message - msg->sendReliable(mHost); - - //don't spam them if they are getting flooded + destination = mFolderID; + //don't spam user if flooded if (check_offer_throttle(mFromName, true)) { log_message = "<nolink>" + chatHistory_string + "</nolink> " + LLTrans::getString("InvOfferGaveYou") + " " + getSanitizedDescription() + LLTrans::getString("."); @@ -2015,66 +2043,24 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const args["MESSAGE"] = log_message; LLNotificationsUtil::add("SystemMessageTip", args); } - - // we will want to open this item when it comes back. - LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID - << LL_ENDL; - switch (mIM) - { - case IM_TASK_INVENTORY_OFFERED: - case IM_GROUP_NOTICE: - case IM_GROUP_NOTICE_REQUESTED: - { - // This is an offer from a task or group. - // We don't use a new instance of an opener - // We instead use the singular observer gOpenTaskOffer - // Since it already exists, we don't need to actually do anything - } - break; - default: - LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL; - break; - } // end switch (mIM) break; - case IOR_MUTE: // MUTE falls through to decline + accept = false; case IOR_DECLINE: - // DECLINE. The math for the dialog works, because the decline - // for inventory_offered, task_inventory_offer or - // group_notice_inventory is 2 greater than the offer integer value. - // Generates IM_INVENTORY_DECLINED, IM_TASK_INVENTORY_DECLINED, - // or IM_GROUP_NOTICE_INVENTORY_DECLINED default: // close button probably (or any of the fall-throughs from above) - msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 2)); - msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE); - // send the message - msg->sendReliable(mHost); - - if (gSavedSettings.getBOOL("LogInventoryDecline")) + destination = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (accept && LLMuteList::getInstance()->isMuted(mFromID, mFromName)) { - 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); - - LLSD args; - args["MESSAGE"] = log_message; - LLNotificationsUtil::add("SystemMessageTip", args); - } - - if (is_do_not_disturb && (!mFromGroup && !mFromObject)) - { - send_do_not_disturb_message(msg,mFromID); + // Note: muted offers are usually declined automatically, + // but user can mute object after receiving message + accept = false; } break; } - - if(opener) - { - gInventory.addObserver(opener); - } + + sendReceiveResponse(accept, destination); if(!mPersist) { @@ -2233,8 +2219,12 @@ protected: } }; +static LLTrace::BlockTimerStatHandle FTM_PROCESS_IMPROVED_IM("Process IM"); + void process_improved_im(LLMessageSystem *msg, void **user_data) { + LL_RECORD_BLOCK_TIME(FTM_PROCESS_IMPROVED_IM); + LLUUID from_id; BOOL from_group; LLUUID to_id; @@ -2886,12 +2876,12 @@ BOOL LLPostTeleportNotifiers::tick() // We're going to pretend to be a new agent void process_teleport_finish(LLMessageSystem* msg, void**) { - LL_DEBUGS("Messaging") << "Got teleport location message" << LL_ENDL; + LL_DEBUGS("Teleport","Messaging") << "Received TeleportFinish message" << LL_ENDL; LLUUID agent_id; msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id); if (agent_id != gAgent.getID()) { - LL_WARNS("Messaging") << "Got teleport notification for wrong agent!" << LL_ENDL; + LL_WARNS("Teleport","Messaging") << "Got teleport notification for wrong agent " << agent_id << " expected " << gAgent.getID() << ", ignoring!" << LL_ENDL; return; } @@ -2901,12 +2891,13 @@ void process_teleport_finish(LLMessageSystem* msg, void**) { // Server either ignored teleport cancel message or did not receive it in time. // This message can't be ignored since teleport is complete at server side + LL_INFOS("Teleport") << "Restoring canceled teleport request" << LL_ENDL; gAgent.restoreCanceledTeleportRequest(); } else { // Race condition? Make sure all variables are set correctly for teleport to work - LL_WARNS("Messaging") << "Teleport 'finish' message without 'start'" << LL_ENDL; + LL_WARNS("Teleport","Messaging") << "Teleport 'finish' message without 'start'. Setting state to TELEPORT_REQUESTED" << LL_ENDL; gTeleportDisplay = TRUE; LLViewerMessage::getInstance()->mTeleportStartedSignal(); gAgent.setTeleportState(LLAgent::TELEPORT_REQUESTED); @@ -2915,7 +2906,7 @@ void process_teleport_finish(LLMessageSystem* msg, void**) } else if (gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING) { - LL_WARNS("Messaging") << "Teleport message in the middle of other teleport" << LL_ENDL; + LL_WARNS("Teleport","Messaging") << "Teleport message in the middle of other teleport" << LL_ENDL; } // Teleport is finished; it can't be cancelled now. @@ -2943,11 +2934,18 @@ 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); + LL_DEBUGS("Teleport") << "TeleportFinish message params are:" + << " sim_ip " << sim_ip + << " sim_port " << sim_port + << " region_handle " << region_handle + << " teleport_flags " << teleport_flags + << " seedCap " << seedCap + << LL_ENDL; + // 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) && (!gAgent.isGodlike())) @@ -2989,7 +2987,7 @@ void process_teleport_finish(LLMessageSystem* msg, void**) gAgent.standUp(); // now, use the circuit info to tell simulator about us! - LL_INFOS("Messaging") << "process_teleport_finish() Enabling " + LL_INFOS("Teleport","Messaging") << "process_teleport_finish() sending UseCircuitCode to enable sim_host " << sim_host << " with code " << msg->mOurCircuitCode << LL_ENDL; msg->newMessageFast(_PREHASH_UseCircuitCode); msg->nextBlockFast(_PREHASH_CircuitCode); @@ -2998,11 +2996,12 @@ void process_teleport_finish(LLMessageSystem* msg, void**) msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); msg->sendReliable(sim_host); + LL_INFOS("Teleport") << "Calling send_complete_agent_movement() and setting state to TELEPORT_MOVING" << LL_ENDL; send_complete_agent_movement(sim_host); gAgent.setTeleportState( LLAgent::TELEPORT_MOVING ); gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]); - LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_teleport_finish(). Seed cap == " + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability(). Seed cap == " << seedCap << LL_ENDL; regionp->setSeedCapability(seedCap); @@ -3035,6 +3034,8 @@ void process_avatar_init_complete(LLMessageSystem* msg, void**) void process_agent_movement_complete(LLMessageSystem* msg, void**) { + LL_INFOS("Teleport","Messaging") << "Received ProcessAgentMovementComplete" << LL_ENDL; + gShiftFrame = true; gAgentMovementCompleted = true; @@ -3044,13 +3045,13 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) { - LL_WARNS("Messaging") << "Incorrect id in process_agent_movement_complete()" - << LL_ENDL; + LL_WARNS("Teleport", "Messaging") << "Incorrect agent or session id in process_agent_movement_complete()" + << " agent " << agent_id << " expected " << gAgent.getID() + << " session " << session_id << " expected " << gAgent.getSessionID() + << ", ignoring" << LL_ENDL; return; } - LL_DEBUGS("Messaging") << "process_agent_movement_complete()" << LL_ENDL; - // *TODO: check timestamp to make sure the movement compleation // makes sense. LLVector3 agent_pos; @@ -3067,7 +3068,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) { // Could happen if you were immediately god-teleported away on login, // maybe other cases. Continue, but warn. - LL_WARNS("Messaging") << "agent_movement_complete() with NULL avatarp." << LL_ENDL; + LL_WARNS("Teleport", "Messaging") << "agent_movement_complete() with NULL avatarp." << LL_ENDL; } F32 x, y; @@ -3077,19 +3078,21 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) { if (gAgent.getRegion()) { - LL_WARNS("Messaging") << "current region " << gAgent.getRegion()->getOriginGlobal() << LL_ENDL; + LL_WARNS("Teleport", "Messaging") << "current region origin " + << gAgent.getRegion()->getOriginGlobal() << " id " << gAgent.getRegion()->getRegionID() << LL_ENDL; } - LL_WARNS("Messaging") << "Agent being sent to invalid home region: " - << x << ":" << y - << " current pos " << gAgent.getPositionGlobal() - << LL_ENDL; + LL_WARNS("Teleport", "Messaging") << "Agent being sent to invalid home region: " + << x << ":" << y + << " current pos " << gAgent.getPositionGlobal() + << ", calling forceDisconnect()" + << LL_ENDL; LLAppViewer::instance()->forceDisconnect(LLTrans::getString("SentToInvalidRegion")); return; } - LL_INFOS("Messaging") << "Changing home region to " << x << ":" << y << LL_ENDL; + LL_INFOS("Teleport","Messaging") << "Changing home region to region id " << regionp->getRegionID() << " handle " << region_handle << " == x,y " << x << "," << y << LL_ENDL; // set our upstream host the new simulator and shuffle things as // appropriate. @@ -3117,6 +3120,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) gAgentCamera.slamLookAt(look_at); gAgentCamera.updateCamera(); + LL_INFOS("Teleport") << "Agent movement complete, setting state to TELEPORT_START_ARRIVAL" << LL_ENDL; gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL ); if (isAgentAvatarValid()) @@ -3130,6 +3134,8 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) else { // This is initial log-in or a region crossing + LL_INFOS("Teleport") << "State is not TELEPORT_MOVING, so this is initial log-in or region crossing. " + << "Setting state to TELEPORT_NONE" << LL_ENDL; gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); if(LLStartUp::getStartupState() < STATE_STARTED) @@ -3760,6 +3766,7 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) void process_time_synch(LLMessageSystem *mesgsys, void **user_data) { LLVector3 sun_direction; + LLVector3 moon_direction; LLVector3 sun_ang_velocity; F32 phase; U64 space_time_usec; @@ -3781,12 +3788,10 @@ void process_time_synch(LLMessageSystem *mesgsys, void **user_data) 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); - if ( !(gSavedSettings.getBOOL("SkyOverrideSimSunPosition") || gSky.getOverrideSun()) ) - { - gSky.setSunDirection(sun_direction, sun_ang_velocity); - } + /* LAPRAS + We decode these parts of the message but ignore them + as the real values are provided elsewhere. */ + (void)sun_direction, (void)moon_direction, (void)phase; } void process_sound_trigger(LLMessageSystem *msg, void **) @@ -4045,6 +4050,8 @@ 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(); @@ -4057,8 +4064,6 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) 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 @@ -4097,6 +4102,14 @@ 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; } } } @@ -4271,7 +4284,7 @@ void process_clear_follow_cam_properties(LLMessageSystem *mesgsys, void **user_d mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id); - LLFollowCamMgr::removeFollowCamParams(source_id); + LLFollowCamMgr::getInstance()->removeFollowCamParams(source_id); } void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data) @@ -4303,7 +4316,7 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat switch(type) { case FOLLOWCAM_PITCH: - LLFollowCamMgr::setPitch(source_id, value); + LLFollowCamMgr::getInstance()->setPitch(source_id, value); break; case FOLLOWCAM_FOCUS_OFFSET_X: focus_offset.mV[VX] = value; @@ -4318,29 +4331,29 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat settingFocusOffset = true; break; case FOLLOWCAM_POSITION_LAG: - LLFollowCamMgr::setPositionLag(source_id, value); + LLFollowCamMgr::getInstance()->setPositionLag(source_id, value); break; case FOLLOWCAM_FOCUS_LAG: - LLFollowCamMgr::setFocusLag(source_id, value); + LLFollowCamMgr::getInstance()->setFocusLag(source_id, value); break; case FOLLOWCAM_DISTANCE: - LLFollowCamMgr::setDistance(source_id, value); + LLFollowCamMgr::getInstance()->setDistance(source_id, value); break; case FOLLOWCAM_BEHINDNESS_ANGLE: - LLFollowCamMgr::setBehindnessAngle(source_id, value); + LLFollowCamMgr::getInstance()->setBehindnessAngle(source_id, value); break; case FOLLOWCAM_BEHINDNESS_LAG: - LLFollowCamMgr::setBehindnessLag(source_id, value); + LLFollowCamMgr::getInstance()->setBehindnessLag(source_id, value); break; case FOLLOWCAM_POSITION_THRESHOLD: - LLFollowCamMgr::setPositionThreshold(source_id, value); + LLFollowCamMgr::getInstance()->setPositionThreshold(source_id, value); break; case FOLLOWCAM_FOCUS_THRESHOLD: - LLFollowCamMgr::setFocusThreshold(source_id, value); + LLFollowCamMgr::getInstance()->setFocusThreshold(source_id, value); break; case FOLLOWCAM_ACTIVE: //if 1, set using followcam,. - LLFollowCamMgr::setCameraActive(source_id, value != 0.f); + LLFollowCamMgr::getInstance()->setCameraActive(source_id, value != 0.f); break; case FOLLOWCAM_POSITION_X: settingPosition = true; @@ -4367,10 +4380,10 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat focus.mV[ 2 ] = value; break; case FOLLOWCAM_POSITION_LOCKED: - LLFollowCamMgr::setPositionLocked(source_id, value != 0.f); + LLFollowCamMgr::getInstance()->setPositionLocked(source_id, value != 0.f); break; case FOLLOWCAM_FOCUS_LOCKED: - LLFollowCamMgr::setFocusLocked(source_id, value != 0.f); + LLFollowCamMgr::getInstance()->setFocusLocked(source_id, value != 0.f); break; default: @@ -4380,15 +4393,15 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat if ( settingPosition ) { - LLFollowCamMgr::setPosition(source_id, position); + LLFollowCamMgr::getInstance()->setPosition(source_id, position); } if ( settingFocus ) { - LLFollowCamMgr::setFocus(source_id, focus); + LLFollowCamMgr::getInstance()->setFocus(source_id, focus); } if ( settingFocusOffset ) { - LLFollowCamMgr::setFocusOffset(source_id, focus_offset); + LLFollowCamMgr::getInstance()->setFocusOffset(source_id, focus_offset); } } //end Ventrella @@ -5043,6 +5056,15 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) // notification was specified using the new mechanism, so we can just handle it here std::string notificationID; msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID); + + //SL-13824 skip notification when both joining a group and leaving a group + //remove this after server stops sending these messages + if (notificationID == "JoinGroupSuccess" || + notificationID == "GroupDepart") + { + return true; + } + if (!LLNotifications::getInstance()->templateExists(notificationID)) { return false; @@ -5108,7 +5130,14 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) std::string snap_filename = gDirUtilp->getLindenUserDir(); snap_filename += gDirUtilp->getDirDelimiter(); snap_filename += LLStartUp::getScreenHomeFilename(); - gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, FALSE, LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::SNAPSHOT_FORMAT_PNG); + gViewerWindow->saveSnapshot(snap_filename, + gViewerWindow->getWindowWidthRaw(), + gViewerWindow->getWindowHeightRaw(), + FALSE, //UI + gSavedSettings.getBOOL("RenderHUDInSnapshot"), + FALSE, + LLSnapshotModel::SNAPSHOT_TYPE_COLOR, + LLSnapshotModel::SNAPSHOT_FORMAT_PNG); } if (notificationID == "RegionRestartMinutes" || @@ -5163,12 +5192,27 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) } } - // Error Notification can come with and without reason - if (notificationID == "JoinGroupError" && llsdBlock.has("reason")) - { - LLNotificationsUtil::add("JoinGroupErrorReason", llsdBlock); - return true; - } + // 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; @@ -5191,7 +5235,14 @@ static void process_special_alert_messages(const std::string & message) std::string snap_filename = gDirUtilp->getLindenUserDir(); snap_filename += gDirUtilp->getDirDelimiter(); snap_filename += LLStartUp::getScreenHomeFilename(); - gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, FALSE, LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::SNAPSHOT_FORMAT_PNG); + gViewerWindow->saveSnapshot(snap_filename, + gViewerWindow->getWindowWidthRaw(), + gViewerWindow->getWindowHeightRaw(), + FALSE, + gSavedSettings.getBOOL("RenderHUDInSnapshot"), + FALSE, + LLSnapshotModel::SNAPSHOT_TYPE_COLOR, + LLSnapshotModel::SNAPSHOT_FORMAT_PNG); } } @@ -5435,16 +5486,7 @@ 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*/) { - LLGlobalEconomy::processEconomyData(msg, LLGlobalEconomy::getInstance()); - - S32 upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload(); - - LL_INFOS_ONCE("Messaging") << "EconomyData message arrived; upload cost is L$" << upload_cost << LL_ENDL; - - gMenuHolder->getChild<LLUICtrl>("Upload Image")->setLabelArg("[COST]", llformat("%d", upload_cost)); - gMenuHolder->getChild<LLUICtrl>("Upload Sound")->setLabelArg("[COST]", llformat("%d", upload_cost)); - gMenuHolder->getChild<LLUICtrl>("Upload Animation")->setLabelArg("[COST]", llformat("%d", upload_cost)); - gMenuHolder->getChild<LLUICtrl>("Bulk Upload")->setLabelArg("[COST]", llformat("%d", upload_cost)); + LL_DEBUGS("Benefits") << "Received economy data, not currently used" << LL_ENDL; } void notify_cautioned_script_question(const LLSD& notification, const LLSD& response, S32 orig_questions, BOOL granted) @@ -5701,8 +5743,9 @@ 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 ); - if( owner_name == self_name ) + LLAgentUI::buildFullname( self_name ); // does not include ' Resident' + std::string clean_owner_name = LLCacheName::cleanFullName(owner_name); // removes ' Resident' + if( clean_owner_name == self_name ) { throttle_name = taskid.getString(); } @@ -5737,7 +5780,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data) S32 count = 0; LLSD args; args["OBJECTNAME"] = object_name; - args["NAME"] = LLCacheName::cleanFullName(owner_name); + args["NAME"] = clean_owner_name; S32 known_questions = 0; bool has_not_only_debit = questions ^ SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_DEBIT].permbit; // check the received permission flags against each permission @@ -5937,6 +5980,8 @@ std::string formatted_time(const time_t& the_time) void process_teleport_failed(LLMessageSystem *msg, void**) { + LL_WARNS("Teleport","Messaging") << "Received TeleportFailed message" << LL_ENDL; + std::string message_id; // Tag from server, like "RegionEntryAccessBlocked" std::string big_reason; // Actual message to display LLSD args; @@ -5955,6 +6000,7 @@ void process_teleport_failed(LLMessageSystem *msg, void**) // Nothing found in the map - use what the server returned in the original message block msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, big_reason); } + LL_WARNS("Teleport") << "AlertInfo message_id " << message_id << " reason: " << big_reason << LL_ENDL; LLSD llsd_block; std::string llsd_raw; @@ -5964,10 +6010,11 @@ void process_teleport_failed(LLMessageSystem *msg, void**) std::istringstream llsd_data(llsd_raw); if (!LLSDSerialize::deserialize(llsd_block, llsd_data, llsd_raw.length())) { - LL_WARNS() << "process_teleport_failed: Attempted to read alert parameter data into LLSD but failed:" << llsd_raw << LL_ENDL; + LL_WARNS("Teleport") << "process_teleport_failed: Attempted to read alert parameter data into LLSD but failed:" << llsd_raw << LL_ENDL; } else { + LL_WARNS("Teleport") << "AlertInfo llsd block received: " << llsd_block << LL_ENDL; if(llsd_block.has("REGION_NAME")) { std::string region_name = llsd_block["REGION_NAME"].asString(); @@ -5983,6 +6030,7 @@ void process_teleport_failed(LLMessageSystem *msg, void**) { if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) { + LL_WARNS("Teleport") << "called handle_teleport_access_blocked, setting state to TELEPORT_NONE" << LL_ENDL; gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); } return; @@ -6005,22 +6053,27 @@ void process_teleport_failed(LLMessageSystem *msg, void**) args["REASON"] = message_id; } } + LL_WARNS("Teleport") << "Displaying CouldNotTeleportReason string, REASON= " << args["REASON"] << LL_ENDL; LLNotificationsUtil::add("CouldNotTeleportReason", args); if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) { + LL_WARNS("Teleport") << "End of process_teleport_failed(). Reason message arg is " << args["REASON"] + << ". Setting state to TELEPORT_NONE" << LL_ENDL; gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); } } void process_teleport_local(LLMessageSystem *msg,void**) { + LL_INFOS("Teleport","Messaging") << "Received TeleportLocal message" << LL_ENDL; + LLUUID agent_id; msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id); if (agent_id != gAgent.getID()) { - LL_WARNS("Messaging") << "Got teleport notification for wrong agent!" << LL_ENDL; + LL_WARNS("Teleport", "Messaging") << "Got teleport notification for wrong agent " << agent_id << " expected " << gAgent.getID() << ", ignoring!" << LL_ENDL; return; } @@ -6032,6 +6085,7 @@ void process_teleport_local(LLMessageSystem *msg,void**) msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at); msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); + LL_INFOS("Teleport") << "Message params are location_id " << location_id << " teleport_flags " << teleport_flags << LL_ENDL; if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) { if( gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL ) @@ -6044,6 +6098,8 @@ void process_teleport_local(LLMessageSystem *msg,void**) } else { + LL_WARNS("Teleport") << "State is not TELEPORT_LOCAL: " << gAgent.getTeleportStateName() + << ", setting state to TELEPORT_NONE" << LL_ENDL; gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); } } diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index 2d6636f30d..78829a6a56 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -254,7 +254,7 @@ public: /*virtual*/ void fromLLSD(const LLSD& params); /*virtual*/ void handleRespond(const LLSD& notification, const LLSD& response); - void send_auto_receive_response(void); + void send_auto_receive_response() { sendReceiveResponse(true, mFolderID); } // TODO - replace all references with handleRespond() bool inventory_offer_callback(const LLSD& notification, const LLSD& response); @@ -264,6 +264,7 @@ private: void initRespondFunctionMap(); std::string getSanitizedDescription(); + void sendReceiveResponse(bool accept, const LLUUID &destination_folder_id); typedef boost::function<bool (const LLSD&, const LLSD&)> respond_function_t; typedef std::map<std::string, respond_function_t> respond_function_map_t; diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp index a593905060..be05ac0d3a 100644 --- a/indra/newview/llviewernetwork.cpp +++ b/indra/newview/llviewernetwork.cpp @@ -130,7 +130,7 @@ void LLGridManager::initialize(const std::string& grid_file) "https://secondlife.aditi.lindenlab.com/helpers/", DEFAULT_LOGIN_PAGE, SL_UPDATE_QUERY_URL, - "https://my.aditi.lindenlab.com/", + "https://my.secondlife-beta.com/", "Aditi"); LLSD other_grids; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 1353a27982..b88baf6aa7 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -142,6 +142,9 @@ 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; +const F64 INVENTORY_UPDATE_WAIT_TIME_DESYNC = 5; // seconds +const F64 INVENTORY_UPDATE_WAIT_TIME_OUTDATED = 1; + static LLTrace::BlockTimerStatHandle FTM_CREATE_OBJECT("Create Object"); // static @@ -265,10 +268,12 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mData(NULL), mAudioSourcep(NULL), mAudioGain(1.f), + mSoundCutOffRadius(0.f), mAppAngle(0.f), mPixelArea(1024.f), mInventory(NULL), mInventorySerialNum(0), + mExpectedInventorySerialNum(0), mInvRequestState(INVENTORY_REQUEST_STOPPED), mInvRequestXFerId(0), mInventoryDirty(FALSE), @@ -279,6 +284,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mOnActiveList(FALSE), mOnMap(FALSE), mStatic(FALSE), + mSeatCount(0), mNumFaces(0), mRotTime(0.f), mAngularVelocityRot(), @@ -482,7 +488,7 @@ void LLViewerObject::markDead() if (flagCameraSource()) { - LLFollowCamMgr::removeFollowCamParams(mID); + LLFollowCamMgr::getInstance()->removeFollowCamParams(mID); } sNumZombieObjects++; @@ -890,7 +896,12 @@ void LLViewerObject::addChild(LLViewerObject *childp) if(childp->setParent(this)) { mChildList.push_back(childp); - childp->afterReparent(); + childp->afterReparent(); + + if (childp->isAvatar()) + { + mSeatCount++; + } } } @@ -919,6 +930,11 @@ void LLViewerObject::removeChild(LLViewerObject *childp) { childp->setParent(NULL); } + + if (childp->isAvatar()) + { + mSeatCount--; + } break; } } @@ -976,21 +992,10 @@ BOOL LLViewerObject::isChild(LLViewerObject *childp) const return FALSE; } - // returns TRUE if at least one avatar is sitting on this object BOOL LLViewerObject::isSeat() const { - for (child_list_t::const_iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* child = *iter; - if (child->isAvatar()) - { - return TRUE; - } - } - return FALSE; - + return mSeatCount > 0; } BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp) @@ -1241,6 +1246,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, LLUUID audio_uuid; LLUUID owner_id; // only valid if audio_uuid or particle system is not null F32 gain; + F32 cutoff; U8 sound_flags; mesgsys->getU32Fast( _PREHASH_ObjectData, _PREHASH_CRC, crc, block_num); @@ -1249,6 +1255,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // HACK: Owner id only valid if non-null sound id or particle system mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id, block_num ); mesgsys->getF32Fast( _PREHASH_ObjectData, _PREHASH_Gain, gain, block_num ); + mesgsys->getF32Fast( _PREHASH_ObjectData, _PREHASH_Radius, cutoff, 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); @@ -1257,6 +1264,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num, MAX_OBJECT_BINARY_DATA_SIZE); mTotalCRC = crc; + mSoundCutOffRadius = cutoff; // Owner ID used for sound muting or particle system muting setAttachedSound(audio_uuid, owner_id, gain, sound_flags); @@ -1279,7 +1287,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { case (60 + 16): // pull out collision normal for avatar - htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + htolememcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); ((LLVOAvatar*)this)->setFootPlane(collision_plane); count += sizeof(LLVector4); // fall through @@ -1287,23 +1295,23 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, this_update_precision = 32; // this is a terse update // pos - htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); count += sizeof(LLVector3); // vel - htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); count += sizeof(LLVector3); // acc - htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); count += sizeof(LLVector3); // theta { LLVector3 vec; - htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy(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)); + htolememcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); if (new_angv.isExactlyZero()) { // reset rotation time @@ -1319,7 +1327,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, break; case(32 + 16): // pull out collision normal for avatar - htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + htolememcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); ((LLVOAvatar*)this)->setFootPlane(collision_plane); count += sizeof(LLVector4); // fall through @@ -1329,7 +1337,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // 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); + htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1340,7 +1348,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, 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); + htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1351,7 +1359,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, U16_to_F32(val[VZ], -size, size))); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1362,7 +1370,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, U16_to_F32(val[VZ], -size, size))); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 4); + htolememcpy(valswizzle, &data[count], MVT_U16Quat, 4); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1374,7 +1382,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1570,7 +1578,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { case(60 + 16): // pull out collision normal for avatar - htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + htolememcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); ((LLVOAvatar*)this)->setFootPlane(collision_plane); count += sizeof(LLVector4); // fall through @@ -1578,23 +1586,23 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // this is a terse 32 update // pos this_update_precision = 32; - htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); count += sizeof(LLVector3); // vel - htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); count += sizeof(LLVector3); // acc - htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); count += sizeof(LLVector3); // theta { LLVector3 vec; - htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy(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)); + htolememcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); if (new_angv.isExactlyZero()) { // reset rotation time @@ -1610,7 +1618,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, break; case(32 + 16): // pull out collision normal for avatar - htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + htolememcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); ((LLVOAvatar*)this)->setFootPlane(collision_plane); count += sizeof(LLVector4); // fall through @@ -1620,7 +1628,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, 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); + htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1631,7 +1639,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, 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); + htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1642,7 +1650,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, U16_to_F32(val[VZ], -size, size)); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1653,7 +1661,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, U16_to_F32(val[VZ], -size, size)); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 8); + htolememcpy(valswizzle, &data[count], MVT_U16Quat, 8); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1665,7 +1673,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1953,6 +1961,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } mTotalCRC = crc; + mSoundCutOffRadius = cutoff; setAttachedSound(sound_uuid, owner_id, gain, sound_flags); @@ -2802,13 +2811,13 @@ void LLViewerObject::doUpdateInventory( { // best guess. perm.setOwnerAndGroup(LLUUID::null, gAgent.getID(), item->getPermissions().getGroup(), is_atomic); - --mInventorySerialNum; + --mExpectedInventorySerialNum; } else { // dummy it up. perm.setOwnerAndGroup(LLUUID::null, LLUUID::null, LLUUID::null, is_atomic); - --mInventorySerialNum; + --mExpectedInventorySerialNum; } } LLViewerInventoryItem* oldItem = item; @@ -2816,7 +2825,11 @@ void LLViewerObject::doUpdateInventory( new_item->setPermissions(perm); mInventory->push_front(new_item); doInventoryCallback(); - ++mInventorySerialNum; + ++mExpectedInventorySerialNum; + } + else if (is_new) + { + ++mExpectedInventorySerialNum; } } @@ -2883,7 +2896,7 @@ void LLViewerObject::moveInventory(const LLUUID& folder_id, if(!item->getPermissions().allowCopyBy(gAgent.getID())) { deleteInventoryItem(item_id); - ++mInventorySerialNum; + ++mExpectedInventorySerialNum; } } } @@ -2974,6 +2987,9 @@ void LLViewerObject::fetchInventoryFromServer() if (!isInventoryPending()) { delete mInventory; + mInventory = NULL; + + // Results in processTaskInv LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_RequestTaskInventory); msg->nextBlockFast(_PREHASH_AgentData); @@ -2983,11 +2999,44 @@ void LLViewerObject::fetchInventoryFromServer() msg->addU32Fast(_PREHASH_LocalID, mLocalID); msg->sendReliable(mRegionp->getHost()); - // this will get reset by dirtyInventory or doInventoryCallback + // This will get reset by doInventoryCallback or processTaskInv mInvRequestState = INVENTORY_REQUEST_PENDING; } } +void LLViewerObject::fetchInventoryDelayed(const F64 &time_seconds) +{ + // unless already waiting, drop previous request and shedule an update + if (mInvRequestState != INVENTORY_REQUEST_WAIT) + { + if (mInvRequestXFerId != 0) + { + // abort download. + gXferManager->abortRequestById(mInvRequestXFerId, -1); + mInvRequestXFerId = 0; + } + mInvRequestState = INVENTORY_REQUEST_WAIT; // affects isInventoryPending() + LLCoros::instance().launch("LLViewerObject::fetchInventoryDelayedCoro()", + boost::bind(&LLViewerObject::fetchInventoryDelayedCoro, mID, time_seconds)); + } +} + +//static +void LLViewerObject::fetchInventoryDelayedCoro(const LLUUID task_inv, const F64 time_seconds) +{ + llcoro::suspendUntilTimeout(time_seconds); + LLViewerObject *obj = gObjectList.findObject(task_inv); + if (obj) + { + // Might be good idea to prolong delay here in case expected serial changed. + // As it is, it will get a response with obsolete serial and will delay again. + + // drop waiting state to unlock isInventoryPending() + obj->mInvRequestState = INVENTORY_REQUEST_STOPPED; + obj->fetchInventoryFromServer(); + } +} + LLControlAvatar *LLViewerObject::getControlAvatar() { return getRootEdit()->mControlAvatar.get(); @@ -3146,74 +3195,97 @@ S32 LLFilenameAndTask::sCount = 0; // static void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data) { - LLUUID task_id; - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_TaskID, task_id); - LLViewerObject* object = gObjectList.findObject(task_id); - if(!object) - { - LL_WARNS() << "LLViewerObject::processTaskInv object " - << task_id << " does not exist." << LL_ENDL; - return; - } + LLUUID task_id; + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_TaskID, task_id); + LLViewerObject* object = gObjectList.findObject(task_id); + if (!object) + { + LL_WARNS() << "LLViewerObject::processTaskInv object " + << task_id << " does not exist." << LL_ENDL; + return; + } - 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); + 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; - } + if (ft->mSerial == object->mInventorySerialNum + && ft->mSerial < object->mExpectedInventorySerialNum) + { + // Loop Protection. + // We received same serial twice. + // Viewer did some changes to inventory that couldn't be saved server side + // or something went wrong to cause serial to be out of sync. + // Drop xfer and restart after some time, assign server's value as expected + LL_WARNS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client expected serial: " << object->mExpectedInventorySerialNum << LL_ENDL; + object->mExpectedInventorySerialNum = ft->mSerial; + object->fetchInventoryDelayed(INVENTORY_UPDATE_WAIT_TIME_DESYNC); + } + else if (ft->mSerial < object->mExpectedInventorySerialNum) + { + // Out of date message, record to current serial for loop protection, but do not load it + // Drop xfer and restart after some time + if (ft->mSerial < object->mInventorySerialNum) + { + LL_WARNS() << "Task serial decreased. Potentially out of order packet or desync." << LL_ENDL; + } + object->mInventorySerialNum = ft->mSerial; + object->fetchInventoryDelayed(INVENTORY_UPDATE_WAIT_TIME_OUTDATED); + } + else if (ft->mSerial >= object->mExpectedInventorySerialNum) + { + // We received version we expected or newer. Load it. + object->mInventorySerialNum = ft->mSerial; + object->mExpectedInventorySerialNum = ft->mSerial; - std::string unclean_filename; - msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename); - ft->mFilename = LLDir::getScrubbedFileName(unclean_filename); + std::string unclean_filename; + msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename); + ft->mFilename = LLDir::getScrubbedFileName(unclean_filename); - if(ft->mFilename.empty()) - { - LL_DEBUGS() << "Task has no inventory" << LL_ENDL; - // mock up some inventory to make a drop target. - if(object->mInventory) - { - object->mInventory->clear(); // will deref and delete it - } - else - { - object->mInventory = new LLInventoryObject::object_list_t(); - } - LLPointer<LLInventoryObject> obj; - obj = new LLInventoryObject(object->mID, LLUUID::null, - LLAssetType::AT_CATEGORY, - "Contents"); - object->mInventory->push_front(obj); - object->doInventoryCallback(); - delete ft; - return; - } - 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; - } + if (ft->mFilename.empty()) + { + LL_DEBUGS() << "Task has no inventory" << LL_ENDL; + // mock up some inventory to make a drop target. + if (object->mInventory) + { + object->mInventory->clear(); // will deref and delete it + } + else + { + object->mInventory = new LLInventoryObject::object_list_t(); + } + LLPointer<LLInventoryObject> obj; + obj = new LLInventoryObject(object->mID, LLUUID::null, + LLAssetType::AT_CATEGORY, + "Contents"); + object->mInventory->push_front(obj); + object->doInventoryCallback(); + delete ft; + return; + } + 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) @@ -3227,6 +3299,13 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS && ft->mSerial >= object->mInventorySerialNum) { object->mInventorySerialNum = ft->mSerial; + LL_DEBUGS() << "Receiving inventory task file for serial " << object->mInventorySerialNum << " taskid: " << ft->mTaskID << LL_ENDL; + if (ft->mSerial < object->mExpectedInventorySerialNum) + { + // User managed to change something while inventory was loading + LL_DEBUGS() << "Processing file that is potentially out of date for task: " << ft->mTaskID << LL_ENDL; + } + if (object->loadTaskInvFile(ft->mFilename)) { @@ -3376,7 +3455,7 @@ void LLViewerObject::removeInventory(const LLUUID& item_id) msg->addUUIDFast(_PREHASH_ItemID, item_id); msg->sendReliable(mRegionp->getHost()); deleteInventoryItem(item_id); - ++mInventorySerialNum; + ++mExpectedInventorySerialNum; } bool LLViewerObject::isTextureInInventory(LLViewerInventoryItem* item) @@ -4721,7 +4800,7 @@ LLViewerTexture* LLViewerObject::getBakedTextureForMagicId(const LLUUID& id) } LLVOAvatar* avatar = getAvatar(); - if (avatar) + if (avatar && !isHUDAttachment()) { LLAvatarAppearanceDefines::EBakedTextureIndex texIndex = LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::assetIdToBakedTextureIndex(id); LLViewerTexture* bakedTexture = avatar->getBakedTexture(texIndex); @@ -5839,6 +5918,8 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow if( gAgent.canAccessMaturityAtGlobal(this->getPositionGlobal()) ) { //LL_INFOS() << "Playing attached sound " << audio_uuid << LL_ENDL; + // recheck cutoff radius in case this update was an object-update with new value + mAudioSourcep->checkCutOffRadius(); mAudioSourcep->play(audio_uuid); } } diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 873b300489..250c4ac328 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -114,7 +114,7 @@ class LLViewerObject public LLTrace::MemTrackable<LLViewerObject> { protected: - ~LLViewerObject(); // use unref() + virtual ~LLViewerObject(); // use unref() // TomY: Provide for a list of extra parameter structures, mapped by structure name struct ExtraParameter @@ -403,6 +403,7 @@ public: // Owner id is this object's owner void setAttachedSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const U8 flags); void adjustAudioGain(const F32 gain); + F32 getSoundCutOffRadius() const { return mSoundCutOffRadius; } void clearAttachedSound() { mAudioSourcep = NULL; } // Create if necessary @@ -474,6 +475,8 @@ public: void updateInventoryLocal(LLInventoryItem* item, U8 key); // Update without messaging. void updateTextureInventory(LLViewerInventoryItem* item, U8 key, bool is_new); LLInventoryObject* getInventoryObject(const LLUUID& item_id); + + // Get content except for root category void getInventoryContents(LLInventoryObject::object_list_t& objects); LLInventoryObject* getInventoryRoot(); LLViewerInventoryItem* getInventoryItemByAsset(const LLUUID& asset_id); @@ -623,9 +626,13 @@ private: static void initObjectDataMap(); - // forms task inventory request if none are pending + // forms task inventory request if none are pending, marks request as pending void fetchInventoryFromServer(); + // forms task inventory request after some time passed, marks request as pending + void fetchInventoryDelayed(const F64 &time_seconds); + static void fetchInventoryDelayedCoro(const LLUUID task_inv, const F64 time_seconds); + public: // // Viewer-side only types - use the LL_PCODE_APP mask. @@ -784,6 +791,7 @@ protected: LLPointer<LLViewerPartSourceScript> mPartSourcep; // Particle source associated with this object. LLAudioSourceVO* mAudioSourcep; F32 mAudioGain; + F32 mSoundCutOffRadius; F32 mAppAngle; // Apparent visual arc in degrees F32 mPixelArea; // Apparent area in pixels @@ -804,12 +812,14 @@ protected: typedef std::list<LLInventoryCallbackInfo*> callback_list_t; callback_list_t mInventoryCallbacks; S16 mInventorySerialNum; + S16 mExpectedInventorySerialNum; enum EInventoryRequestState { INVENTORY_REQUEST_STOPPED, - INVENTORY_REQUEST_PENDING, - INVENTORY_XFER + INVENTORY_REQUEST_WAIT, // delay before requesting + INVENTORY_REQUEST_PENDING, // just did fetchInventoryFromServer() + INVENTORY_XFER // processed response from 'fetch', now doing an xfer }; EInventoryRequestState mInvRequestState; U64 mInvRequestXFerId; @@ -822,6 +832,7 @@ protected: BOOL mOnActiveList; BOOL mOnMap; // On the map. BOOL mStatic; // Object doesn't move. + S32 mSeatCount; S32 mNumFaces; F32 mRotTime; // Amount (in seconds) that object has rotated according to angular velocity (llSetTargetOmega) diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 2bf04dc204..63e48d1dd0 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -1921,7 +1921,7 @@ void LLViewerObjectList::generatePickList(LLCamera &camera) attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - if (LLViewerObject* attached_object = (*attachment_iter)) + if (LLViewerObject* attached_object = attachment_iter->get()) { mSelectPickList.insert(attached_object); LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp index 00a652384c..6365df09e1 100644 --- a/indra/newview/llvieweroctree.cpp +++ b/indra/newview/llvieweroctree.cpp @@ -1116,10 +1116,6 @@ void LLOcclusionCullingGroup::checkOcclusion() LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_WAIT); while (!available && max_loop-- > 0) { - //do some usefu work while we wait - F32 max_time = llmin(gFrameIntervalSeconds.value()*10.f, 1.f); - LLAppViewer::instance()->updateTextureThreads(max_time); - glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); } } @@ -1272,7 +1268,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh { LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_DRAW_WATER); - LLGLSquashToFarClip squash(glh_get_current_projection(), 1); + LLGLSquashToFarClip squash; if (camera->getOrigin().isExactlyZero()) { //origin is invalid, draw entire box gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); diff --git a/indra/newview/llviewerparcelaskplay.cpp b/indra/newview/llviewerparcelaskplay.cpp new file mode 100644 index 0000000000..afbe2c94de --- /dev/null +++ b/indra/newview/llviewerparcelaskplay.cpp @@ -0,0 +1,306 @@ +/** + * @file llviewerparcelaskplay.cpp + * @brief stores data about parcel media user wants to auto-play and shows related notifications + * + * $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 "llviewerparcelaskplay.h" + +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llparcel.h" +#include "llstartup.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llagent.h" +#include "llsdserialize.h" + +#include <boost/lexical_cast.hpp> + + +// class LLViewerParcelAskPlay + +LLViewerParcelAskPlay::LLViewerParcelAskPlay() : +pNotification(NULL) +{ +} + +LLViewerParcelAskPlay::~LLViewerParcelAskPlay() +{ + +} + +void LLViewerParcelAskPlay::initSingleton() +{ + +} +void LLViewerParcelAskPlay::cleanupSingleton() +{ + if (LLNotifications::instanceExists()) + { + cancelNotification(); + } +} + +void LLViewerParcelAskPlay::askToPlay(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, ask_callback cb) +{ + EAskPlayMode mode = getPlayMode(region_id, parcel_id); + + switch (mode) + { + case ASK_PLAY_IGNORE: + cb(region_id, parcel_id, url, false); + break; + case ASK_PLAY_PLAY: + cb(region_id, parcel_id, url, true); + break; + case ASK_PLAY_ASK: + default: + { + // create or re-create notification + // Note: will create and immediately cancel one notification if region has both media and music + // since ask play does not distinguish media from music and media can be used as music + cancelNotification(); + + if (LLStartUp::getStartupState() > STATE_PRECACHE) + { + LLSD args; + args["URL"] = url; + LLSD payload; + payload["url"] = url; // or we can extract it from notification["substitutions"] + payload["parcel_id"] = parcel_id; + payload["region_id"] = region_id; + pNotification = LLNotificationsUtil::add("ParcelPlayingMedia", args, payload, boost::bind(onAskPlayResponse, _1, _2, cb)); + } + else + { + // workaround: avoid 'new notifications arrived' on startup and just play + // (alternative: move to different channel, may be create new one...) + cb(region_id, parcel_id, url, true); + } + } + } +} + +void LLViewerParcelAskPlay::cancelNotification() +{ + if (pNotification) + { + if (!pNotification->isCancelled()) + { + // Force a responce + // Alternative is to mark notification as unique + pNotification->setIgnored(false); + LLNotifications::getInstance()->cancel(pNotification); + } + pNotification = NULL; + } +} + +void LLViewerParcelAskPlay::resetCurrentParcelSetting() +{ + LLParcel *agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (agent_parcel && gAgent.getRegion()) + { + LLViewerParcelAskPlay::resetSetting(gAgent.getRegion()->getRegionID(), agent_parcel->getLocalID()); + } +} + +void LLViewerParcelAskPlay::resetSetting(const LLUUID ®ion_id, const S32 &parcel_id) +{ + region_map_t::iterator found = mRegionMap.find(region_id); + if (found != mRegionMap.end()) + { + found->second.erase(parcel_id); + } +} + +void LLViewerParcelAskPlay::resetSettings() +{ + if (LLViewerParcelAskPlay::instanceExists()) + { + LLViewerParcelAskPlay::getInstance()->mRegionMap.clear(); + } + LLFile::remove(getAskPlayFilename()); +} + +void LLViewerParcelAskPlay::setSetting(const LLUUID ®ion_id, const S32 &parcel_id, const LLViewerParcelAskPlay::ParcelData &data) +{ + mRegionMap[region_id][parcel_id] = data; +} + +LLViewerParcelAskPlay::ParcelData* LLViewerParcelAskPlay::getSetting(const LLUUID ®ion_id, const S32 &parcel_id) +{ + region_map_t::iterator found = mRegionMap.find(region_id); + if (found != mRegionMap.end()) + { + parcel_data_map_t::iterator found_parcel = found->second.find(parcel_id); + if (found_parcel != found->second.end()) + { + return &(found_parcel->second); + } + } + return NULL; +} + +LLViewerParcelAskPlay::EAskPlayMode LLViewerParcelAskPlay::getPlayMode(const LLUUID ®ion_id, const S32 &parcel_id) +{ + EAskPlayMode mode = ASK_PLAY_ASK; + ParcelData* data = getSetting(region_id, parcel_id); + if (data) + { + mode = data->mMode; + // refresh date + data->mDate = LLDate::now(); + } + return mode; +} + +void LLViewerParcelAskPlay::setPlayMode(const LLUUID ®ion_id, const S32 &parcel_id, LLViewerParcelAskPlay::EAskPlayMode mode) +{ + ParcelData data; + data.mMode = mode; + data.mDate = LLDate::now(); + setSetting(region_id, parcel_id, data); +} + +//static +void LLViewerParcelAskPlay::onAskPlayResponse(const LLSD& notification, const LLSD& response, ask_callback cb) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + LLUUID region_id = notification["payload"]["region_id"]; + S32 parcel_id = notification["payload"]["parcel_id"]; + std::string url = notification["payload"]["url"]; + + bool play = option == 1; + + cb(region_id, parcel_id, url, play); + + LLViewerParcelAskPlay *inst = getInstance(); + bool save_choice = inst->pNotification->isIgnored(); // checkbox selected + if (save_choice) + { + EAskPlayMode mode = (play) ? ASK_PLAY_PLAY : ASK_PLAY_IGNORE; + inst->setPlayMode(region_id, parcel_id, mode); + } +} + +// static +std::string LLViewerParcelAskPlay::getAskPlayFilename() +{ + return gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "media_autoplay.xml"); +} + +void LLViewerParcelAskPlay::loadSettings() +{ + mRegionMap.clear(); + + std::string path = getAskPlayFilename(); + if (!gDirUtilp->fileExists(path)) + { + return; + } + + LLSD autoplay_llsd; + llifstream file; + file.open(path.c_str()); + if (!file.is_open()) + { + return; + } + S32 status = LLSDSerialize::fromXML(autoplay_llsd, file); + file.close(); + + if (status == LLSDParser::PARSE_FAILURE || !autoplay_llsd.isMap()) + { + return; + } + + for (LLSD::map_const_iterator iter_region = autoplay_llsd.beginMap(); + iter_region != autoplay_llsd.endMap(); ++iter_region) + { + LLUUID region_id = LLUUID(iter_region->first); + mRegionMap[region_id] = parcel_data_map_t(); + + const LLSD &parcel_map = iter_region->second; + + if (parcel_map.isMap()) + { + for (LLSD::map_const_iterator iter_parcel = parcel_map.beginMap(); + iter_parcel != parcel_map.endMap(); ++iter_parcel) + { + if (!iter_parcel->second.isMap()) + { + break; + } + S32 parcel_id = boost::lexical_cast<S32>(iter_parcel->first.c_str()); + ParcelData data; + data.mMode = (EAskPlayMode)(iter_parcel->second["mode"].asInteger()); + data.mDate = iter_parcel->second["date"].asDate(); + mRegionMap[region_id][parcel_id] = data; + } + } + } +} + +void LLViewerParcelAskPlay::saveSettings() +{ + LLSD write_llsd; + std::string key; + for (region_map_t::iterator iter_region = mRegionMap.begin(); + iter_region != mRegionMap.end(); ++iter_region) + { + if (iter_region->second.empty()) + { + continue; + } + key = iter_region->first.asString(); + write_llsd[key] = LLSD(); + + for (parcel_data_map_t::iterator iter_parcel = iter_region->second.begin(); + iter_parcel != iter_region->second.end(); ++iter_parcel) + { + if ((iter_parcel->second.mDate.secondsSinceEpoch() + (F64SecondsImplicit)U32Days(30)) > LLTimer::getTotalSeconds()) + { + // write unexpired parcels + std::string parcel_id = boost::lexical_cast<std::string>(iter_parcel->first); + write_llsd[key][parcel_id] = LLSD(); + write_llsd[key][parcel_id]["mode"] = (LLSD::Integer)iter_parcel->second.mMode; + write_llsd[key][parcel_id]["date"] = iter_parcel->second.mDate; + } + } + } + + llofstream file; + file.open(getAskPlayFilename().c_str()); + if (file.is_open()) + { + LLSDSerialize::toPrettyXML(write_llsd, file); + file.close(); + } +} + diff --git a/indra/newview/llviewerparcelaskplay.h b/indra/newview/llviewerparcelaskplay.h new file mode 100644 index 0000000000..dc711917d2 --- /dev/null +++ b/indra/newview/llviewerparcelaskplay.h @@ -0,0 +1,89 @@ +/** + * @file llviewerparcelaskplay.h + * @brief stores data about parcel media user wants to auto-play and shows related notifications + * + * $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 LLVIEWERPARCELASKPLAY_H +#define LLVIEWERPARCELASKPLAY_H + +#include "llnotificationptr.h" +#include "lluuid.h" + +class LLViewerParcelAskPlay : public LLSingleton<LLViewerParcelAskPlay> +{ + LLSINGLETON(LLViewerParcelAskPlay); + ~LLViewerParcelAskPlay(); + void initSingleton(); + void cleanupSingleton(); +public: + // functor expects functor(region_id, parcel_id, url, play/stop) + typedef boost::function<void(const LLUUID&, const S32&, const std::string&, const bool&)> ask_callback; + void askToPlay(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, ask_callback cb); + void cancelNotification(); + + void resetCurrentParcelSetting(); + void resetSetting(const LLUUID ®ion_id, const S32 &parcel_id); + static void resetSettings(); + + void loadSettings(); + void saveSettings(); + + S32 hasData() { return !mRegionMap.empty(); } // subsitution for 'isInitialized' + +private: + enum EAskPlayMode{ + ASK_PLAY_IGNORE = 0, + ASK_PLAY_PLAY, + ASK_PLAY_ASK + }; + + class ParcelData + { + public: + LLDate mDate; + EAskPlayMode mMode; + }; + + void setSetting(const LLUUID ®ion_id, const S32 &parcel_id, const ParcelData &data); + ParcelData* getSetting(const LLUUID ®ion_id, const S32 &parcel_id); + EAskPlayMode getPlayMode(const LLUUID ®ion_id, const S32 &parcel_id); + void setPlayMode(const LLUUID ®ion_id, const S32 &parcel_id, EAskPlayMode); + + static void onAskPlayResponse(const LLSD& notification, const LLSD& response, ask_callback cb); + + static std::string getAskPlayFilename(); + +private: + // Variables + + typedef std::map<S32, ParcelData> parcel_data_map_t; + typedef std::map<LLUUID, parcel_data_map_t> region_map_t; + region_map_t mRegionMap; + + // only one notification is supposed to exists and be visible + LLNotificationPtr pNotification; +}; + + +#endif // LLVIEWERPARCELASKPLAY_H diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index d31fc0d606..83b05e6b4d 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -45,31 +45,26 @@ #include "llviewertexture.h" #include "llcorehttputil.h" -// Static Variables -S32 LLViewerParcelMedia::sMediaParcelLocalID = 0; -LLUUID LLViewerParcelMedia::sMediaRegionID; -viewer_media_t LLViewerParcelMedia::sMediaImpl; - - -// static -void LLViewerParcelMedia::initClass() +LLViewerParcelMedia::LLViewerParcelMedia(): +mMediaParcelLocalID(0) { LLMessageSystem* msg = gMessageSystem; - msg->setHandlerFunc("ParcelMediaCommandMessage", processParcelMediaCommandMessage ); - msg->setHandlerFunc("ParcelMediaUpdate", processParcelMediaUpdate ); - LLViewerParcelMediaAutoPlay::initClass(); + msg->setHandlerFunc("ParcelMediaCommandMessage", parcelMediaCommandMessageHandler ); + msg->setHandlerFunc("ParcelMediaUpdate", parcelMediaUpdateHandler ); + + // LLViewerParcelMediaAutoPlay will regularly check and autoplay media, + // might be good idea to just integrate it into LLViewerParcelMedia + LLSingleton<LLViewerParcelMediaAutoPlay>::getInstance(); } -//static -void LLViewerParcelMedia::cleanupClass() +LLViewerParcelMedia::~LLViewerParcelMedia() { // This needs to be destroyed before global destructor time. - sMediaImpl = NULL; + mMediaImpl = NULL; } ////////////////////////////////////////////////////////////////////////////////////////// -// static void LLViewerParcelMedia::update(LLParcel* parcel) { if (/*LLViewerMedia::hasMedia()*/ true) @@ -79,7 +74,7 @@ void LLViewerParcelMedia::update(LLParcel* parcel) { if(!gAgent.getRegion()) { - sMediaRegionID = LLUUID() ; + mMediaRegionID = LLUUID() ; stop() ; LL_DEBUGS("Media") << "no agent region, bailing out." << LL_ENDL; return ; @@ -89,11 +84,13 @@ void LLViewerParcelMedia::update(LLParcel* parcel) S32 parcelid = parcel->getLocalID(); LLUUID regionid = gAgent.getRegion()->getRegionID(); - if (parcelid != sMediaParcelLocalID || regionid != sMediaRegionID) + bool location_changed = false; + if (parcelid != mMediaParcelLocalID || regionid != mMediaRegionID) { LL_DEBUGS("Media") << "New parcel, parcel id = " << parcelid << ", region id = " << regionid << LL_ENDL; - sMediaParcelLocalID = parcelid; - sMediaRegionID = regionid; + mMediaParcelLocalID = parcelid; + mMediaRegionID = regionid; + location_changed = true; } std::string mediaUrl = std::string ( parcel->getMediaURL () ); @@ -108,19 +105,21 @@ void LLViewerParcelMedia::update(LLParcel* parcel) LLStringUtil::trim(mediaUrl); // If no parcel media is playing, nothing left to do - if(sMediaImpl.isNull()) + if(mMediaImpl.isNull()) { + // media will be autoplayed by LLViewerParcelMediaAutoPlay return; } // Media is playing...has something changed? - else if (( sMediaImpl->getMediaURL() != mediaUrl ) - || ( sMediaImpl->getMediaTextureID() != parcel->getMediaID() ) - || ( sMediaImpl->getMimeType() != parcel->getMediaType() )) + else if (( mMediaImpl->getMediaURL() != mediaUrl ) + || ( mMediaImpl->getMediaTextureID() != parcel->getMediaID() ) + || ( mMediaImpl->getMimeType() != parcel->getMediaType() )) { - // Only play if the media types are the same. - if(sMediaImpl->getMimeType() == parcel->getMediaType()) + // Only play if the media types are the same and parcel stays same. + if(mMediaImpl->getMimeType() == parcel->getMediaType() + && !location_changed) { play(parcel); } @@ -136,25 +135,6 @@ void LLViewerParcelMedia::update(LLParcel* parcel) stop(); } } - /* - else - { - // no audio player, do a first use dialog if there is media here - if (parcel) - { - std::string mediaUrl = std::string ( parcel->getMediaURL () ); - if (!mediaUrl.empty ()) - { - if (gWarningSettings.getBOOL("QuickTimeInstalled")) - { - gWarningSettings.setBOOL("QuickTimeInstalled", FALSE); - - LLNotificationsUtil::add("NoQuickTime" ); - }; - } - } - } - */ } // static @@ -176,30 +156,30 @@ void LLViewerParcelMedia::play(LLParcel* parcel) S32 media_width = parcel->getMediaWidth(); S32 media_height = parcel->getMediaHeight(); - if(sMediaImpl) + if(mMediaImpl) { // If the url and mime type are the same, call play again - if(sMediaImpl->getMediaURL() == media_url - && sMediaImpl->getMimeType() == mime_type - && sMediaImpl->getMediaTextureID() == placeholder_texture_id) + if(mMediaImpl->getMediaURL() == media_url + && mMediaImpl->getMimeType() == mime_type + && mMediaImpl->getMediaTextureID() == placeholder_texture_id) { LL_DEBUGS("Media") << "playing with existing url " << media_url << LL_ENDL; - sMediaImpl->play(); + mMediaImpl->play(); } // Else if the texture id's are the same, navigate and rediscover type // MBW -- This causes other state from the previous parcel (texture size, autoscale, and looping) to get re-used incorrectly. // It's also not really necessary -- just creating a new instance is fine. -// else if(sMediaImpl->getMediaTextureID() == placeholder_texture_id) +// else if(mMediaImpl->getMediaTextureID() == placeholder_texture_id) // { -// sMediaImpl->navigateTo(media_url, mime_type, true); +// mMediaImpl->navigateTo(media_url, mime_type, true); // } else { // Since the texture id is different, we need to generate a new impl // Delete the old one first so they don't fight over the texture. - sMediaImpl = NULL; + mMediaImpl = NULL; // A new impl will be created below. } @@ -208,19 +188,19 @@ void LLViewerParcelMedia::play(LLParcel* parcel) // Don't ever try to play if the media type is set to "none/none" if(stricmp(mime_type.c_str(), LLMIMETypes::getDefaultMimeType().c_str()) != 0) { - if(!sMediaImpl) + if(!mMediaImpl) { LL_DEBUGS("Media") << "new media impl with mime type " << mime_type << ", url " << media_url << LL_ENDL; // There is no media impl, make a new one - sMediaImpl = LLViewerMedia::newMediaImpl( + mMediaImpl = LLViewerMedia::getInstance()->newMediaImpl( placeholder_texture_id, media_width, media_height, media_auto_scale, media_loop); - sMediaImpl->setIsParcelMedia(true); - sMediaImpl->navigateTo(media_url, mime_type, true); + mMediaImpl->setIsParcelMedia(true); + mMediaImpl->navigateTo(media_url, mime_type, true); } //LLFirstUse::useMedia(); @@ -232,7 +212,7 @@ void LLViewerParcelMedia::play(LLParcel* parcel) // static void LLViewerParcelMedia::stop() { - if(sMediaImpl.isNull()) + if(mMediaImpl.isNull()) { return; } @@ -241,27 +221,27 @@ void LLViewerParcelMedia::stop() LLViewerMediaFocus::getInstance()->clearFocus(); // This will unload & kill the media instance. - sMediaImpl = NULL; + mMediaImpl = NULL; } // static void LLViewerParcelMedia::pause() { - if(sMediaImpl.isNull()) + if(mMediaImpl.isNull()) { return; } - sMediaImpl->pause(); + mMediaImpl->pause(); } // static void LLViewerParcelMedia::start() { - if(sMediaImpl.isNull()) + if(mMediaImpl.isNull()) { return; } - sMediaImpl->start(); + mMediaImpl->start(); //LLFirstUse::useMedia(); @@ -271,17 +251,17 @@ void LLViewerParcelMedia::start() // static void LLViewerParcelMedia::seek(F32 time) { - if(sMediaImpl.isNull()) + if(mMediaImpl.isNull()) { return; } - sMediaImpl->seek(time); + mMediaImpl->seek(time); } // static void LLViewerParcelMedia::focus(bool focus) { - sMediaImpl->focus(focus); + mMediaImpl->focus(focus); } // static @@ -289,9 +269,9 @@ LLPluginClassMediaOwner::EMediaStatus LLViewerParcelMedia::getStatus() { LLPluginClassMediaOwner::EMediaStatus result = LLPluginClassMediaOwner::MEDIA_NONE; - if(sMediaImpl.notNull() && sMediaImpl->hasMedia()) + if(mMediaImpl.notNull() && mMediaImpl->hasMedia()) { - result = sMediaImpl->getMediaPlugin()->getStatus(); + result = mMediaImpl->getMediaPlugin()->getStatus(); } return result; @@ -300,15 +280,15 @@ LLPluginClassMediaOwner::EMediaStatus LLViewerParcelMedia::getStatus() // static std::string LLViewerParcelMedia::getMimeType() { - return sMediaImpl.notNull() ? sMediaImpl->getMimeType() : LLMIMETypes::getDefaultMimeType(); + return mMediaImpl.notNull() ? mMediaImpl->getMimeType() : LLMIMETypes::getDefaultMimeType(); } //static std::string LLViewerParcelMedia::getURL() { std::string url; - if(sMediaImpl.notNull()) - url = sMediaImpl->getMediaURL(); + if(mMediaImpl.notNull()) + url = mMediaImpl->getMediaURL(); if(stricmp(LLViewerParcelMgr::getInstance()->getAgentParcel()->getMediaType().c_str(), LLMIMETypes::getDefaultMimeType().c_str()) != 0) { @@ -325,19 +305,24 @@ std::string LLViewerParcelMedia::getURL() //static std::string LLViewerParcelMedia::getName() { - if(sMediaImpl.notNull()) - return sMediaImpl->getName(); + if(mMediaImpl.notNull()) + return mMediaImpl->getName(); return ""; } viewer_media_t LLViewerParcelMedia::getParcelMedia() { - return sMediaImpl; + return mMediaImpl; } ////////////////////////////////////////////////////////////////////////////////////////// // static -void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg, void ** ) +void LLViewerParcelMedia::parcelMediaCommandMessageHandler(LLMessageSystem *msg, void **) +{ + getInstance()->processParcelMediaCommandMessage(msg); +} + +void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg) { // extract the agent id // LLUUID agent_id; @@ -392,7 +377,7 @@ void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg if (flags & (1<<PARCEL_MEDIA_COMMAND_TIME)) { - if(sMediaImpl.isNull()) + if(mMediaImpl.isNull()) { LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); play(parcel); @@ -403,7 +388,12 @@ void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg ////////////////////////////////////////////////////////////////////////////////////////// // static -void LLViewerParcelMedia::processParcelMediaUpdate( LLMessageSystem *msg, void ** ) +void LLViewerParcelMedia::parcelMediaUpdateHandler(LLMessageSystem *msg, void **) +{ + getInstance()->processParcelMediaUpdate(msg); +} + +void LLViewerParcelMedia::processParcelMediaUpdate( LLMessageSystem *msg) { LLUUID media_id; std::string media_url; diff --git a/indra/newview/llviewerparcelmedia.h b/indra/newview/llviewerparcelmedia.h index 534f65b419..779a65bdf8 100644 --- a/indra/newview/llviewerparcelmedia.h +++ b/indra/newview/llviewerparcelmedia.h @@ -37,50 +37,53 @@ class LLViewerParcelMediaNavigationObserver; // This class understands land parcels, network traffic, LSL media // transport commands, and talks to the LLViewerMedia class to actually // do playback. It allows us to remove code from LLViewerParcelMgr. -class LLViewerParcelMedia : public LLViewerMediaObserver +class LLViewerParcelMedia : public LLViewerMediaObserver, public LLSingleton<LLViewerParcelMedia> { + LLSINGLETON(LLViewerParcelMedia); + ~LLViewerParcelMedia(); LOG_CLASS(LLViewerParcelMedia); - public: - static void initClass(); - static void cleanupClass(); - - static void update(LLParcel* parcel); - // 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); - // user clicked play button in media transport controls - - static void stop(); - // user clicked stop button in media transport controls - - static void pause(); - static void start(); - // restart after pause - no need for all the setup - - static void focus(bool focus); - - static void seek(F32 time); - // jump to timecode time - - static LLPluginClassMediaOwner::EMediaStatus getStatus(); - static std::string getMimeType(); - static std::string getURL(); - static std::string getName(); - static viewer_media_t getParcelMedia(); - - static void processParcelMediaCommandMessage( LLMessageSystem *msg, void ** ); - static void processParcelMediaUpdate( LLMessageSystem *msg, void ** ); - static void sendMediaNavigateMessage(const std::string& url); - - // inherited from LLViewerMediaObserver - virtual void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); - - public: - static S32 sMediaParcelLocalID; - static LLUUID sMediaRegionID; - // HACK: this will change with Media on a Prim - static viewer_media_t sMediaImpl; +public: + void update(LLParcel* parcel); + // called when the agent's parcel has a new URL, or the agent has + // walked on to a new parcel with media + + void play(LLParcel* parcel); + // user clicked play button in media transport controls + + void stop(); + // user clicked stop button in media transport controls + + void pause(); + void start(); + // restart after pause - no need for all the setup + + void focus(bool focus); + + void seek(F32 time); + // jump to timecode time + + LLPluginClassMediaOwner::EMediaStatus getStatus(); + std::string getMimeType(); + std::string getURL(); + std::string getName(); + viewer_media_t getParcelMedia(); + bool hasParcelMedia() { return mMediaImpl.notNull(); } + + static void parcelMediaCommandMessageHandler( LLMessageSystem *msg, void ** ); + static void parcelMediaUpdateHandler( LLMessageSystem *msg, void ** ); + void sendMediaNavigateMessage(const std::string& url); + + // inherited from LLViewerMediaObserver + virtual void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); + +private: + void processParcelMediaCommandMessage(LLMessageSystem *msg); + void processParcelMediaUpdate(LLMessageSystem *msg); + + S32 mMediaParcelLocalID; + LLUUID mMediaRegionID; + // HACK: this will change with Media on a Prim + viewer_media_t mMediaImpl; }; diff --git a/indra/newview/llviewerparcelmediaautoplay.cpp b/indra/newview/llviewerparcelmediaautoplay.cpp index 57ee583eae..db8fcb4dc4 100644 --- a/indra/newview/llviewerparcelmediaautoplay.cpp +++ b/indra/newview/llviewerparcelmediaautoplay.cpp @@ -24,17 +24,20 @@ * $/LicenseInfo$ */ + #include "llviewerprecompiledheaders.h" + #include "llviewerparcelmediaautoplay.h" -#include "llviewerparcelmedia.h" + +#include "llparcel.h" #include "llviewercontrol.h" #include "llviewermedia.h" -#include "llviewerregion.h" -#include "llparcel.h" +#include "llviewerparcelaskplay.h" +#include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" -#include "lluuid.h" -#include "message.h" +#include "llviewerregion.h" #include "llviewertexturelist.h" // for texture stats +#include "message.h" #include "llagent.h" #include "llmimetypes.h" @@ -51,29 +54,10 @@ LLViewerParcelMediaAutoPlay::LLViewerParcelMediaAutoPlay() : { } -static LLViewerParcelMediaAutoPlay *sAutoPlay = NULL; - -// static -void LLViewerParcelMediaAutoPlay::initClass() -{ - if (!sAutoPlay) - sAutoPlay = new LLViewerParcelMediaAutoPlay; -} - -// static -void LLViewerParcelMediaAutoPlay::cleanupClass() -{ - if (sAutoPlay) - delete sAutoPlay; -} - // static void LLViewerParcelMediaAutoPlay::playStarted() { - if (sAutoPlay) - { - sAutoPlay->mPlayed = TRUE; - } + LLSingleton<LLViewerParcelMediaAutoPlay>::getInstance()->mPlayed = TRUE; } BOOL LLViewerParcelMediaAutoPlay::tick() @@ -122,7 +106,7 @@ BOOL LLViewerParcelMediaAutoPlay::tick() (mTimeInParcel > AUTOPLAY_TIME) && // and if we've been here for so many seconds (!this_media_url.empty()) && // and if the parcel has media (stricmp(this_media_type.c_str(), LLMIMETypes::getDefaultMimeType().c_str()) != 0) && - (LLViewerParcelMedia::sMediaImpl.isNull())) // and if the media is not already playing + (!LLViewerParcelMedia::getInstance()->hasParcelMedia())) // and if the media is not already playing { if (this_media_texture_id.notNull()) // and if the media texture is good { @@ -141,11 +125,28 @@ BOOL LLViewerParcelMediaAutoPlay::tick() { if (this_parcel) { - if (gSavedSettings.getBOOL("ParcelMediaAutoPlayEnable")) + static LLCachedControl<S32> autoplay_mode(gSavedSettings, "ParcelMediaAutoPlayEnable"); + + switch (autoplay_mode()) { - // and last but not least, only play when autoplay is enabled - LLViewerParcelMedia::play(this_parcel); - } + case 0: + // Disabled + break; + case 1: + // Play, default value for ParcelMediaAutoPlayEnable + LLViewerParcelMedia::getInstance()->play(this_parcel); + break; + case 2: + default: + { + // Ask + LLViewerParcelAskPlay::getInstance()->askToPlay(this_region->getRegionID(), + this_parcel->getLocalID(), + this_parcel->getMediaURL(), + onStartMediaResponse); + break; + } + } } mPlayed = TRUE; @@ -158,5 +159,18 @@ BOOL LLViewerParcelMediaAutoPlay::tick() return FALSE; // continue ticking forever please. } - +//static +void LLViewerParcelMediaAutoPlay::onStartMediaResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play) +{ + if (play) + { + LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + + // make sure we are still there + if (parcel->getLocalID() == parcel_id && gAgent.getRegion()->getRegionID() == region_id) + { + LLViewerParcelMedia::getInstance()->play(parcel); + } + } +} diff --git a/indra/newview/llviewerparcelmediaautoplay.h b/indra/newview/llviewerparcelmediaautoplay.h index a052362829..d71fd4c075 100644 --- a/indra/newview/llviewerparcelmediaautoplay.h +++ b/indra/newview/llviewerparcelmediaautoplay.h @@ -31,16 +31,18 @@ #include "lluuid.h" // timer to automatically play media -class LLViewerParcelMediaAutoPlay : LLEventTimer +class LLViewerParcelMediaAutoPlay : LLEventTimer, public LLSingleton<LLViewerParcelMediaAutoPlay> { - public: - LLViewerParcelMediaAutoPlay(); + LLSINGLETON(LLViewerParcelMediaAutoPlay); +public: virtual BOOL tick(); - static void initClass(); - static void cleanupClass(); static void playStarted(); private: + // for askToPlay + static void onStartMediaResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play); + + private: S32 mLastParcelID; LLUUID mLastRegionID; BOOL mPlayed; diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 416d5d8e2e..06172e366d 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -42,6 +42,7 @@ // Viewer includes #include "llagent.h" #include "llagentaccess.h" +#include "llviewerparcelaskplay.h" #include "llviewerwindow.h" #include "llviewercontrol.h" //#include "llfirstuse.h" @@ -69,6 +70,8 @@ #include "llvieweraudio.h" #include "llcorehttputil.h" +#include "llenvironment.h" + const F32 PARCEL_COLLISION_DRAW_SECS = 1.f; @@ -645,6 +648,31 @@ LLParcel *LLViewerParcelMgr::getAgentParcel() const return mAgentParcel; } + +LLParcel * LLViewerParcelMgr::getAgentOrSelectedParcel() const +{ + LLParcel *parcel(nullptr); + + LLParcelSelectionHandle sel_handle(getFloatingParcelSelection()); + if (sel_handle) + { + LLParcelSelection *selection(sel_handle.get()); + if (selection) + { + parcel = selection->getParcel(); + if (parcel && (parcel->getLocalID() == INVALID_PARCEL_ID)) + { + parcel = NULL; + } + } + } + + if (!parcel) + parcel = LLViewerParcelMgr::instance().getAgentParcel(); + + return parcel; +} + // Return whether the agent can build on the land they are on bool LLViewerParcelMgr::allowAgentBuild() const { @@ -1285,6 +1313,13 @@ const std::string& LLViewerParcelMgr::getAgentParcelName() const } +const S32 LLViewerParcelMgr::getAgentParcelId() const +{ + if (mAgentParcel) + return mAgentParcel->getLocalID(); + return INVALID_PARCEL_ID; +} + void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_agent_region) { if(!parcel) @@ -1515,6 +1550,8 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use BOOL region_deny_transacted_override = false; // Deprecated BOOL region_deny_age_unverified_override = false; BOOL region_allow_access_override = true; + BOOL region_allow_environment_override = true; + S32 parcel_environment_version = 0; BOOL agent_parcel_update = false; // updating previous(existing) agent parcel S32 other_clean_time = 0; @@ -1605,6 +1642,12 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use msg->getBOOLFast(_PREHASH_RegionAllowAccessBlock, _PREHASH_RegionAllowAccessOverride, region_allow_access_override); } + if (msg->getNumberOfBlocks(_PREHASH_ParcelEnvironmentBlock)) + { + msg->getS32Fast(_PREHASH_ParcelEnvironmentBlock, _PREHASH_ParcelEnvironmentVersion, parcel_environment_version); + msg->getBOOLFast(_PREHASH_ParcelEnvironmentBlock, _PREHASH_RegionAllowEnvironmentOverride, region_allow_environment_override); + } + msg->getS32("ParcelData", "OtherCleanTime", other_clean_time ); LL_DEBUGS("ParcelMgr") << "Processing parcel " << local_id << " update, target(sequence): " << sequence_id << LL_ENDL; @@ -1624,6 +1667,9 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use } } + S32 cur_parcel_environment_version = parcel->getParcelEnvironmentVersion(); + bool environment_changed = (cur_parcel_environment_version != parcel_environment_version); + parcel->init(owner_id, FALSE, FALSE, FALSE, claim_date, claim_price_per_meter, rent_price_per_meter, @@ -1649,6 +1695,9 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use parcel->setRegionDenyAnonymousOverride(region_deny_anonymous_override); parcel->setRegionDenyAgeUnverifiedOverride(region_deny_age_unverified_override); parcel->setRegionAllowAccessOverride(region_allow_access_override); + parcel->setParcelEnvironmentVersion(cur_parcel_environment_version); + parcel->setRegionAllowEnvironmentOverride(region_allow_environment_override); + parcel->unpackMessage(msg); if (parcel == parcel_mgr.mAgentParcel) @@ -1666,9 +1715,6 @@ 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 - gAgent.changeParcels(); - if (instance->mTeleportInProgress) { instance->mTeleportInProgress = FALSE; @@ -1682,12 +1728,24 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use instance->mTeleportFinishedSignal(instance->mTeleportInProgressPosition, false); } } - } - else if (agent_parcel_update) - { - // updated agent parcel - parcel_mgr.mAgentParcel->unpackMessage(msg); - } + parcel->setParcelEnvironmentVersion(parcel_environment_version); + LL_DEBUGS("ENVIRONMENT") << "Parcel environment version is " << parcel->getParcelEnvironmentVersion() << LL_ENDL; + + // Notify anything that wants to know when the agent changes parcels + gAgent.changeParcels(); + instance->mTeleportInProgress = FALSE; + } + else if (agent_parcel_update) + { + parcel->setParcelEnvironmentVersion(parcel_environment_version); + // updated agent parcel + parcel_mgr.mAgentParcel->unpackMessage(msg); + if ((LLEnvironment::instance().isExtendedEnvironmentEnabled() && environment_changed)) + { + LL_DEBUGS("ENVIRONMENT") << "Parcel environment version is " << parcel->getParcelEnvironmentVersion() << LL_ENDL; + LLEnvironment::instance().requestParcel(local_id); + } + } } // Handle updating selections, if necessary. @@ -1822,7 +1880,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use else { // Check for video - LLViewerParcelMedia::update(parcel); + LLViewerParcelMedia::getInstance()->update(parcel); // Then check for music if (gAudiop) @@ -1832,6 +1890,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use // Only update stream if parcel changed (recreated) or music is playing (enabled) if (!agent_parcel_update || gSavedSettings.getBOOL("MediaTentativeAutoPlay")) { + LLViewerParcelAskPlay::getInstance()->cancelNotification(); std::string music_url_raw = parcel->getMusicURL(); // Trim off whitespace from front and back @@ -1841,9 +1900,14 @@ 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(music_url); + LLViewerRegion *region = LLWorld::getInstance()->getRegion(msg->getSender()); + if (region) + { + optionally_start_music(music_url, parcel->mLocalID, region->getRegionID()); + } } else { @@ -1864,25 +1928,61 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use else { // Public land has no music + LLViewerParcelAskPlay::getInstance()->cancelNotification(); LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade(); } }//if gAudiop }; } -void LLViewerParcelMgr::optionally_start_music(const std::string& music_url) +//static +void LLViewerParcelMgr::onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play) +{ + if (play) + { + LL_INFOS("ParcelMgr") << "Starting parcel music " << url << LL_ENDL; + LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(url); + } +} + +void LLViewerParcelMgr::optionally_start_music(const std::string &music_url, const S32 &local_id, const LLUUID ®ion_id) { - if (gSavedSettings.getBOOL("AudioStreamingMusic")) + static LLCachedControl<bool> streaming_music(gSavedSettings, "AudioStreamingMusic", true); + if (streaming_music) { + static LLCachedControl<S32> autoplay_mode(gSavedSettings, "ParcelMediaAutoPlayEnable", 1); + static LLCachedControl<bool> tentative_autoplay(gSavedSettings, "MediaTentativeAutoPlay", true); // only play music when you enter a new parcel if the UI control for this // was not *explicitly* stopped by the user. (part of SL-4878) LLPanelNearByMedia* nearby_media_panel = gStatusBar->getNearbyMediaPanel(); - if ((nearby_media_panel && - nearby_media_panel->getParcelAudioAutoStart()) || - // or they have expressed no opinion in the UI, but have autoplay on... - (!nearby_media_panel && - gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && - gSavedSettings.getBOOL("MediaTentativeAutoPlay"))) + + // ask mode //todo constants + if (autoplay_mode == 2) + { + // stop previous stream + LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null); + + // if user set media to play - ask + if ((nearby_media_panel && nearby_media_panel->getParcelAudioAutoStart()) + || (!nearby_media_panel && tentative_autoplay)) + { + LLViewerParcelAskPlay::getInstance()->askToPlay(region_id, + local_id, + music_url, + onStartMusicResponse); + } + else + { + LLViewerParcelAskPlay::getInstance()->cancelNotification(); + } + } + // autoplay + else if ((nearby_media_panel + && nearby_media_panel->getParcelAudioAutoStart()) + // or they have expressed no opinion in the UI, but have autoplay on... + || (!nearby_media_panel + && autoplay_mode == 1 + && tentative_autoplay)) { LL_INFOS("ParcelMgr") << "Starting parcel music " << music_url << LL_ENDL; LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(music_url); @@ -2577,3 +2677,9 @@ void LLViewerParcelMgr::onTeleportFailed() { mTeleportFailedSignal(); } + +bool LLViewerParcelMgr::getTeleportInProgress() +{ + return mTeleportInProgress // case where parcel data arrives after teleport + || gAgent.getTeleportState() > LLAgent::TELEPORT_NONE; // For LOCAL, no mTeleportInProgress +} diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index 29219843c9..508a63c398 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -154,6 +154,7 @@ public: //LLParcel *getParcelSelection() const; LLParcel *getAgentParcel() const; + LLParcel *getAgentOrSelectedParcel() const; BOOL inAgentParcel(const LLVector3d &pos_global) const; @@ -262,13 +263,15 @@ public: // accessors for mAgentParcel const std::string& getAgentParcelName() const; + const S32 getAgentParcelId() const; // Create a landmark at the "appropriate" location for the // currently selected parcel. // *NOTE: Taken out 2005-03-21. Phoenix. //void makeLandmarkAtSelection(); - static void optionally_start_music(const std::string& music_url); + static void onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play); + static void optionally_start_music(const std::string &music_url, const S32 &local_id, const LLUUID ®ion_id); static void processParcelOverlay(LLMessageSystem *msg, void **user_data); static void processParcelProperties(LLMessageSystem *msg, void **user_data); @@ -285,6 +288,7 @@ public: boost::signals2::connection setTeleportFailedCallback(teleport_failed_callback_t cb); void onTeleportFinished(bool local, const LLVector3d& new_pos); void onTeleportFailed(); + bool getTeleportInProgress(); static BOOL isParcelOwnedByAgent(const LLParcel* parcelp, U64 group_proxy_power); static BOOL isParcelModifiableByAgent(const LLParcel* parcelp, U64 group_proxy_power); diff --git a/indra/newview/llviewerpartsource.cpp b/indra/newview/llviewerpartsource.cpp index 998ae52fe0..f042040e98 100644 --- a/indra/newview/llviewerpartsource.cpp +++ b/indra/newview/llviewerpartsource.cpp @@ -136,7 +136,7 @@ void LLViewerPartSourceScript::update(const F32 dt) { mOwnerAvatarp = find_avatar(mOwnerUUID); } - if (mOwnerAvatarp.notNull() && LLVOAvatar::AV_DO_NOT_RENDER == mOwnerAvatarp->getVisualMuteSettings()) + if (mOwnerAvatarp.notNull() && LLVOAvatar::AOA_NORMAL != mOwnerAvatarp->getOverallAppearance()) { return; } diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h index 999d9092bd..bbbacce8fa 100644 --- a/indra/newview/llviewerprecompiledheaders.h +++ b/indra/newview/llviewerprecompiledheaders.h @@ -29,6 +29,8 @@ #ifndef LL_LLVIEWERPRECOMPILEDHEADERS_H #define LL_LLVIEWERPRECOMPILEDHEADERS_H +#include "llwin32headers.h" + // This file MUST be the first one included by each .cpp file // in viewer. // It is used to precompile headers for improved build speed. diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 5b227c641b..7628a6c7ef 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -80,6 +80,9 @@ #include "lleventcoro.h" #include "llcorehttputil.h" #include "llcallstack.h" +#include "llsettingsdaycycle.h" + +#include <boost/regex.hpp> #ifdef LL_WINDOWS #pragma warning(disable:4355) @@ -101,6 +104,7 @@ const U32 DEFAULT_MAX_REGION_WIDE_PRIM_COUNT = 15000; BOOL LLViewerRegion::sVOCacheCullingEnabled = FALSE; S32 LLViewerRegion::sLastCameraUpdated = 0; S32 LLViewerRegion::sNewObjectCreationThrottle = -1; +LLViewerRegion::vocache_entry_map_t LLViewerRegion::sRegionCacheCleanup; typedef std::map<std::string, std::string> CapabilityMap; @@ -141,15 +145,22 @@ public: // build a secondlife://{PLACE} SLurl from this SLapp std::string url = "secondlife://"; + boost::regex name_rx("[A-Za-z0-9()_%]+"); + boost::regex coord_rx("[0-9]+"); for (int i = 0; i < num_params; i++) { if (i > 0) { url += "/"; } + if (!boost::regex_match(params[i].asString(), i > 0 ? coord_rx : name_rx)) + { + return false; + } + url += params[i].asString(); } - + // Process the SLapp as if it was a secondlife://{PLACE} SLurl LLURLDispatcher::dispatch(url, "clicked", web, true); return true; @@ -289,13 +300,21 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) LL_INFOS("AppInit", "Capabilities") << "Requesting seed from " << url << " region name " << regionp->getName() + << " region id " << regionp->getRegionID() + << " handle " << regionp->getHandle() << " (attempt #" << mSeedCapAttempts + 1 << ")" << LL_ENDL; + LL_DEBUGS("AppInit", "Capabilities") << "Capabilities requested: " << capabilityNames << LL_ENDL; regionp = NULL; result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames); ++mSeedCapAttempts; + if (LLApp::isExiting()) + { + return; + } + regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); if (!regionp) //region was removed { @@ -342,9 +361,9 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) log_capabilities(mCapabilities); #endif + LL_DEBUGS("AppInit", "Capabilities", "Teleport") << "received caps for handle " << regionHandle + << " region name " << regionp->getName() << LL_ENDL; regionp->setCapabilitiesReceived(true); - LL_DEBUGS("AppInit", "Capabilities") << "received caps for handle " << regionHandle - << " region name " << regionp->getName() << LL_ENDL; if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) { @@ -397,7 +416,7 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle) LLSD capabilityNames = LLSD::emptyArray(); buildCapabilityNames(capabilityNames); - LL_INFOS("AppInit", "Capabilities") << "Requesting second Seed from " << url << LL_ENDL; + LL_INFOS("AppInit", "Capabilities") << "Requesting second Seed from " << url << " for region " << regionp->getRegionID() << LL_ENDL; regionp = NULL; result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames); @@ -410,6 +429,11 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle) break; // no retry } + if (LLApp::isExiting()) + { + break; + } + regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); if (!regionp) //region was removed { @@ -513,6 +537,11 @@ void LLViewerRegionImpl::requestSimulatorFeatureCoro(std::string url, U64 region continue; } + if (LLApp::isExiting()) + { + break; + } + // remove the http_result from the llsd result.erase("http_result"); @@ -607,6 +636,8 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, 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 LLAvatarPartition(this)); //PARTITION_AVATAR + mImpl->mObjectPartition.push_back(new LLControlAVPartition(this)); //PARTITION_CONTROL_AV mImpl->mObjectPartition.push_back(new LLHUDParticlePartition(this));//PARTITION_HUD_PARTICLE mImpl->mObjectPartition.push_back(new LLVOCachePartition(this)); //PARTITION_VO_CACHE mImpl->mObjectPartition.push_back(NULL); //PARTITION_NONE @@ -631,6 +662,9 @@ void LLViewerRegion::initStats() mAlive = false; // can become false if circuit disconnects } +static LLTrace::BlockTimerStatHandle FTM_CLEANUP_REGION_OBJECTS("Cleanup Region Objects"); +static LLTrace::BlockTimerStatHandle FTM_SAVE_REGION_CACHE("Save Region Cache"); + LLViewerRegion::~LLViewerRegion() { mDead = TRUE; @@ -645,7 +679,10 @@ LLViewerRegion::~LLViewerRegion() disconnectAllNeighbors(); LLViewerPartSim::getInstance()->cleanupRegion(this); - gObjectList.killObjects(this); + { + LL_RECORD_BLOCK_TIME(FTM_CLEANUP_REGION_OBJECTS); + gObjectList.killObjects(this); + } delete mImpl->mCompositionp; delete mParcelOverlay; @@ -656,7 +693,10 @@ LLViewerRegion::~LLViewerRegion() #endif std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer()); - saveObjectCache(); + { + LL_RECORD_BLOCK_TIME(FTM_SAVE_REGION_CACHE); + saveObjectCache(); + } delete mImpl; mImpl = NULL; @@ -725,6 +765,8 @@ void LLViewerRegion::saveObjectCache() mCacheDirty = FALSE; } + // Map of LLVOCacheEntry takes time to release, store map for cleanup on idle + sRegionCacheCleanup.insert(mImpl->mCacheMap.begin(), mImpl->mCacheMap.end()); mImpl->mCacheMap.clear(); } @@ -1486,6 +1528,16 @@ void LLViewerRegion::idleUpdate(F32 max_update_time) return; } +// static +void LLViewerRegion::idleCleanup(F32 max_update_time) +{ + LLTimer update_timer; + while (!sRegionCacheCleanup.empty() && (max_update_time - update_timer.getElapsedTimeF32() > 0)) + { + sRegionCacheCleanup.erase(sRegionCacheCleanup.begin()); + } +} + //update the throttling number for new object creation void LLViewerRegion::calcNewObjectCreationThrottle() { @@ -2180,7 +2232,7 @@ void LLViewerRegion::requestSimulatorFeatures() LLCoros::instance().launch("LLViewerRegionImpl::requestSimulatorFeatureCoro", boost::bind(&LLViewerRegionImpl::requestSimulatorFeatureCoro, mImpl, url, getHandle())); - LL_INFOS("AppInit", "SimulatorFeatures") << "Launching " << coroname << " requesting simulator features from " << url << LL_ENDL; + LL_INFOS("AppInit", "SimulatorFeatures") << "Launching " << coroname << " requesting simulator features from " << url << " for region " << getRegionID() << LL_ENDL; } else { @@ -2198,7 +2250,7 @@ void LLViewerRegion::setSimulatorFeaturesReceived(bool received) mSimulatorFeaturesReceived = received; if (received) { - mSimulatorFeaturesReceivedSignal(getRegionID()); + mSimulatorFeaturesReceivedSignal(getRegionID(), this); mSimulatorFeaturesReceivedSignal.disconnect_all_slots(); } } @@ -2895,8 +2947,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("EstateAccess"); capabilityNames.append("EstateChangeInfo"); capabilityNames.append("EventQueueGet"); - capabilityNames.append("FlickrConnect"); - capabilityNames.append("TwitterConnect"); + capabilityNames.append("ExtEnvironment"); capabilityNames.append("FetchLib2"); capabilityNames.append("FetchLibDescendents2"); @@ -2918,6 +2969,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("IsExperienceAdmin"); capabilityNames.append("IsExperienceContributor"); capabilityNames.append("RegionExperiences"); + capabilityNames.append("ExperienceQuery"); capabilityNames.append("GetMetadata"); capabilityNames.append("GetObjectCost"); capabilityNames.append("GetObjectPhysicsData"); @@ -2968,9 +3020,12 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("UpdateNotecardTaskInventory"); capabilityNames.append("UpdateScriptAgent"); capabilityNames.append("UpdateScriptTask"); + capabilityNames.append("UpdateSettingsAgentInventory"); + capabilityNames.append("UpdateSettingsTaskInventory"); capabilityNames.append("UploadBakedTexture"); capabilityNames.append("UserInfo"); capabilityNames.append("ViewerAsset"); + capabilityNames.append("ViewerBenefits"); capabilityNames.append("ViewerMetrics"); capabilityNames.append("ViewerStartAuction"); capabilityNames.append("ViewerStats"); @@ -2984,7 +3039,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url) if (getCapability("Seed") == url) { setCapabilityDebug("Seed", url); - LL_WARNS("CrossingCaps") << "Received duplicate seed capability, posting to seed " << + LL_WARNS("CrossingCaps") << "Received duplicate seed capability for " << getRegionID() << ", posting to seed " << url << LL_ENDL; //Instead of just returning we build up a second set of seed caps and compare them @@ -3005,7 +3060,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url) LLCoros::instance().launch("LLViewerRegionImpl::requestBaseCapabilitiesCoro", boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCoro, mImpl, getHandle())); - LL_INFOS("AppInit", "Capabilities") << "Launching " << coroname << " requesting seed capabilities from " << url << LL_ENDL; + LL_INFOS("AppInit", "Capabilities") << "Launching " << coroname << " requesting seed capabilities from " << url << " for region " << getRegionID() << LL_ENDL; } S32 LLViewerRegion::getNumSeedCapRetries() @@ -3137,9 +3192,9 @@ void LLViewerRegion::setCapabilitiesReceived(bool received) // so that they can safely use getCapability(). if (received) { - mCapabilitiesReceivedSignal(getRegionID()); + mCapabilitiesReceivedSignal(getRegionID(), this); - //LLFloaterPermsDefault::sendInitialPerms(); + LLFloaterPermsDefault::sendInitialPerms(); // This is a single-shot signal. Forget callbacks to save resources. mCapabilitiesReceivedSignal.disconnect_all_slots(); @@ -3315,5 +3370,12 @@ U32 LLViewerRegion::getMaxMaterialsPerTransaction() const return max_entries; } - +std::string LLViewerRegion::getSimHostName() +{ + if (mSimulatorFeaturesReceived) + { + return mSimulatorFeatures.has("HostName") ? mSimulatorFeatures["HostName"].asString() : getHost().getHostName(); + } + return std::string("..."); +} diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 2548ff1423..fcbf56c81f 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -86,13 +86,15 @@ public: PARTITION_GRASS, PARTITION_VOLUME, PARTITION_BRIDGE, + PARTITION_AVATAR, + PARTITION_CONTROL_AV, // Animesh PARTITION_HUD_PARTICLE, PARTITION_VO_CACHE, PARTITION_NONE, NUM_PARTITIONS } eObjectPartitions; - typedef boost::signals2::signal<void(const LLUUID& region_id)> caps_received_signal_t; + typedef boost::signals2::signal<void(const LLUUID& region_id, LLViewerRegion* regionp)> caps_received_signal_t; LLViewerRegion(const U64 &handle, const LLHost &host, @@ -131,6 +133,7 @@ public: inline BOOL isPrelude() const; inline BOOL getAllowTerraform() const; inline BOOL getRestrictPushObject() const; + inline BOOL getAllowEnvironmentOverride() const; inline BOOL getReleaseNotesRequested() const; bool isAlive(); // can become false if circuit disconnects @@ -229,6 +232,9 @@ public: F32 getWidth() const { return mWidth; } + // regions are expensive to release, this function gradually releases cache from memory + static void idleCleanup(F32 max_update_time); + void idleUpdate(F32 max_update_time); void lightIdleUpdate(); bool addVisibleGroup(LLViewerOctreeGroup* group); @@ -387,6 +393,8 @@ public: BOOL isPaused() const {return mPaused;} S32 getLastUpdate() const {return mLastUpdate;} + std::string getSimHostName(); + static BOOL isNewObjectCreationThrottleDisabled() {return sNewObjectCreationThrottle < 0;} private: @@ -547,6 +555,9 @@ private: LLSD mSimulatorFeatures; + typedef std::map<U32, LLPointer<LLVOCacheEntry> > vocache_entry_map_t; + static vocache_entry_map_t sRegionCacheCleanup; + // the materials capability throttle LLFrameTimer mMaterialsCapThrottleTimer; LLFrameTimer mRenderInfoRequestTimer; @@ -637,6 +648,11 @@ inline BOOL LLViewerRegion::getRestrictPushObject() const return ((mRegionFlags & REGION_FLAGS_RESTRICT_PUSHOBJECT) != 0); } +inline BOOL LLViewerRegion::getAllowEnvironmentOverride() const +{ + return ((mRegionFlags & REGION_FLAGS_ALLOW_ENVIRONMENT_OVERRIDE) != 0); +} + inline BOOL LLViewerRegion::getReleaseNotesRequested() const { return mReleaseNotesRequested; diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 6d8b27ff2d..be5c22e7c3 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -31,27 +31,24 @@ #include "llfeaturemanager.h" #include "llviewershadermgr.h" - -#include "llfile.h" -#include "llviewerwindow.h" -#include "llwindow.h" #include "llviewercontrol.h" -#include "pipeline.h" + +#include "llrender.h" +#include "llenvironment.h" +#include "llatmosphere.h" #include "llworld.h" -#include "llwlparammanager.h" -#include "llwaterparammanager.h" #include "llsky.h" #include "llvosky.h" -#include "llrender.h" + +#include "pipeline.h" + +#include "llfile.h" +#include "llviewerwindow.h" +#include "llwindow.h" + #include "lljoint.h" #include "llskinningutil.h" -#ifdef LL_RELEASE_FOR_DOWNLOAD -#define UNIFORM_ERRS LL_WARNS_ONCE("Shader") -#else -#define UNIFORM_ERRS LL_ERRS("Shader") -#endif - static LLStaticHashedString sTexture0("texture0"); static LLStaticHashedString sTexture1("texture1"); static LLStaticHashedString sTex0("tex0"); @@ -154,6 +151,7 @@ LLGLSLShader gSkinnedObjectShinySimpleWaterProgram; LLGLSLShader gTerrainProgram; LLGLSLShader gTerrainWaterProgram; LLGLSLShader gWaterProgram; +LLGLSLShader gWaterEdgeProgram; LLGLSLShader gUnderWaterProgram; //interface shaders @@ -178,7 +176,8 @@ LLGLSLShader gImpostorProgram; // WindLight shader handles LLGLSLShader gWLSkyProgram; LLGLSLShader gWLCloudProgram; - +LLGLSLShader gWLSunProgram; +LLGLSLShader gWLMoonProgram; // Effects Shaders LLGLSLShader gGlowProgram; @@ -200,6 +199,7 @@ LLGLSLShader gDeferredSkinnedBumpProgram; LLGLSLShader gDeferredSkinnedAlphaProgram; LLGLSLShader gDeferredBumpProgram; LLGLSLShader gDeferredTerrainProgram; +LLGLSLShader gDeferredTerrainWaterProgram; LLGLSLShader gDeferredTreeProgram; LLGLSLShader gDeferredTreeShadowProgram; LLGLSLShader gDeferredAvatarProgram; @@ -215,6 +215,7 @@ LLGLSLShader gDeferredSoftenWaterProgram; LLGLSLShader gDeferredShadowProgram; LLGLSLShader gDeferredShadowCubeProgram; LLGLSLShader gDeferredShadowAlphaMaskProgram; +LLGLSLShader gDeferredShadowFullbrightAlphaMaskProgram; LLGLSLShader gDeferredAvatarShadowProgram; LLGLSLShader gDeferredAvatarAlphaShadowProgram; LLGLSLShader gDeferredAvatarAlphaMaskShadowProgram; @@ -238,6 +239,8 @@ LLGLSLShader gFXAAProgram; LLGLSLShader gDeferredPostNoDoFProgram; LLGLSLShader gDeferredWLSkyProgram; LLGLSLShader gDeferredWLCloudProgram; +LLGLSLShader gDeferredWLSunProgram; +LLGLSLShader gDeferredWLMoonProgram; LLGLSLShader gDeferredStarProgram; LLGLSLShader gDeferredFullbrightShinyProgram; LLGLSLShader gDeferredSkinnedFullbrightShinyProgram; @@ -249,17 +252,20 @@ LLGLSLShader gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2]; LLGLSLShader gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2]; LLViewerShaderMgr::LLViewerShaderMgr() : - mVertexShaderLevel(SHADER_COUNT, 0), + mShaderLevel(SHADER_COUNT, 0), mMaxAvatarShaderLevel(0) -{ - /// Make sure WL Sky is the first program - //ONLY shaders that need WL Param management should be added here +{ + /// Make sure WL Sky is the first program + //ONLY shaders that need WL Param management should be added here mShaderList.push_back(&gWLSkyProgram); mShaderList.push_back(&gWLCloudProgram); + mShaderList.push_back(&gWLSunProgram); + mShaderList.push_back(&gWLMoonProgram); mShaderList.push_back(&gAvatarProgram); mShaderList.push_back(&gObjectShinyProgram); mShaderList.push_back(&gObjectShinyNonIndexedProgram); mShaderList.push_back(&gWaterProgram); + mShaderList.push_back(&gWaterEdgeProgram); mShaderList.push_back(&gAvatarEyeballProgram); mShaderList.push_back(&gObjectSimpleProgram); mShaderList.push_back(&gObjectSimpleImpostorProgram); @@ -314,22 +320,6 @@ LLViewerShaderMgr::LLViewerShaderMgr() : mShaderList.push_back(&gDeferredSunProgram); mShaderList.push_back(&gDeferredSoftenProgram); mShaderList.push_back(&gDeferredSoftenWaterProgram); - mShaderList.push_back(&gDeferredMaterialProgram[1]); - mShaderList.push_back(&gDeferredMaterialProgram[5]); - mShaderList.push_back(&gDeferredMaterialProgram[9]); - mShaderList.push_back(&gDeferredMaterialProgram[13]); - mShaderList.push_back(&gDeferredMaterialProgram[1+LLMaterial::SHADER_COUNT]); - mShaderList.push_back(&gDeferredMaterialProgram[5+LLMaterial::SHADER_COUNT]); - mShaderList.push_back(&gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT]); - mShaderList.push_back(&gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT]); - mShaderList.push_back(&gDeferredMaterialWaterProgram[1]); - mShaderList.push_back(&gDeferredMaterialWaterProgram[5]); - mShaderList.push_back(&gDeferredMaterialWaterProgram[9]); - mShaderList.push_back(&gDeferredMaterialWaterProgram[13]); - mShaderList.push_back(&gDeferredMaterialWaterProgram[1+LLMaterial::SHADER_COUNT]); - mShaderList.push_back(&gDeferredMaterialWaterProgram[5+LLMaterial::SHADER_COUNT]); - mShaderList.push_back(&gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT]); - mShaderList.push_back(&gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT]); mShaderList.push_back(&gDeferredAlphaProgram); mShaderList.push_back(&gDeferredAlphaImpostorProgram); mShaderList.push_back(&gDeferredAlphaWaterProgram); @@ -345,14 +335,17 @@ LLViewerShaderMgr::LLViewerShaderMgr() : mShaderList.push_back(&gDeferredAvatarEyesProgram); mShaderList.push_back(&gDeferredWaterProgram); mShaderList.push_back(&gDeferredUnderWaterProgram); + mShaderList.push_back(&gDeferredTerrainWaterProgram); mShaderList.push_back(&gDeferredAvatarAlphaProgram); mShaderList.push_back(&gDeferredWLSkyProgram); mShaderList.push_back(&gDeferredWLCloudProgram); + mShaderList.push_back(&gDeferredWLMoonProgram); + mShaderList.push_back(&gDeferredWLSunProgram); } LLViewerShaderMgr::~LLViewerShaderMgr() { - mVertexShaderLevel.clear(); + mShaderLevel.clear(); mShaderList.clear(); } @@ -389,9 +382,9 @@ void LLViewerShaderMgr::initAttribsAndUniforms(void) //============================================================================ // Set Levels -S32 LLViewerShaderMgr::getVertexShaderLevel(S32 type) +S32 LLViewerShaderMgr::getShaderLevel(S32 type) { - return LLPipeline::sDisableShaders ? 0 : mVertexShaderLevel[type]; + return LLPipeline::sDisableShaders ? 0 : mShaderLevel[type]; } //============================================================================ @@ -399,306 +392,350 @@ S32 LLViewerShaderMgr::getVertexShaderLevel(S32 type) void LLViewerShaderMgr::setShaders() { - //setShaders might be called redundantly by gSavedSettings, so return on reentrance - static bool reentrance = false; - - if (!gPipeline.mInitialized || !sInitialized || reentrance || sSkipReload) - { - return; - } - - static LLCachedControl<U32> max_texture_index(gSavedSettings, "RenderMaxTextureIndex", 16); - LLGLSLShader::sIndexedTextureChannels = llmax(llmin(gGLManager.mNumTextureImageUnits, (S32) max_texture_index), 1); - - //NEVER use more than 16 texture channels (work around for prevalent driver bug) - LLGLSLShader::sIndexedTextureChannels = llmin(LLGLSLShader::sIndexedTextureChannels, 16); - - if (gGLManager.mGLSLVersionMajor < 1 || - (gGLManager.mGLSLVersionMajor == 1 && gGLManager.mGLSLVersionMinor <= 20)) - { //NEVER use indexed texture rendering when GLSL version is 1.20 or earlier - LLGLSLShader::sIndexedTextureChannels = 1; - } - - reentrance = true; - - if (LLRender::sGLCoreProfile) - { - if (!gSavedSettings.getBOOL("VertexShaderEnable")) - { //vertex shaders MUST be enabled to use core profile - gSavedSettings.setBOOL("VertexShaderEnable", TRUE); - } - } - - //setup preprocessor definitions - LLShaderMgr::instance()->mDefinitions["NUM_TEX_UNITS"] = llformat("%d", gGLManager.mNumTextureImageUnits); - - // Make sure the compiled shader map is cleared before we recompile shaders. - mShaderObjects.clear(); - - initAttribsAndUniforms(); - gPipeline.releaseGLBuffers(); - - if (gSavedSettings.getBOOL("VertexShaderEnable")) - { - LLPipeline::sWaterReflections = gGLManager.mHasCubeMap; - LLPipeline::sRenderGlow = gSavedSettings.getBOOL("RenderGlow"); - LLPipeline::updateRenderDeferred(); - } - else - { - LLPipeline::sRenderGlow = FALSE; - LLPipeline::sWaterReflections = FALSE; - } - - //hack to reset buffers that change behavior with shaders - gPipeline.resetVertexBuffers(); - - if (gViewerWindow) - { - gViewerWindow->setCursor(UI_CURSOR_WAIT); - } - - // Lighting - gPipeline.setLightingDetail(-1); - - // Shaders - LL_INFOS("ShaderLoading") << "\n~~~~~~~~~~~~~~~~~~\n Loading Shaders:\n~~~~~~~~~~~~~~~~~~" << LL_ENDL; - LL_INFOS("ShaderLoading") << llformat("Using GLSL %d.%d", gGLManager.mGLSLVersionMajor, gGLManager.mGLSLVersionMinor) << LL_ENDL; - - for (S32 i = 0; i < SHADER_COUNT; i++) - { - mVertexShaderLevel[i] = 0; - } - mMaxAvatarShaderLevel = 0; - - LLGLSLShader::sNoFixedFunction = false; - LLVertexBuffer::unbind(); - if (LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable") - && (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 10) - && gSavedSettings.getBOOL("VertexShaderEnable")) - { - //using shaders, disable fixed function - LLGLSLShader::sNoFixedFunction = true; - - S32 light_class = 2; - S32 env_class = 2; - S32 obj_class = 2; - S32 effect_class = 2; - S32 wl_class = 2; - S32 water_class = 2; - S32 deferred_class = 0; - S32 transform_class = gGLManager.mHasTransformFeedback ? 1 : 0; - - static LLCachedControl<bool> use_transform_feedback(gSavedSettings, "RenderUseTransformFeedback", false); - if (!use_transform_feedback) - { - transform_class = 0; - } - - if (LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && - gSavedSettings.getBOOL("RenderDeferred") && - gSavedSettings.getBOOL("RenderAvatarVP") && - gSavedSettings.getBOOL("WindLightUseAtmosShaders")) - { - if (gSavedSettings.getS32("RenderShadowDetail") > 0) - { //shadows - deferred_class = 2; - } - else - { //no shadows - deferred_class = 1; - } - - //make sure hardware skinning is enabled - //gSavedSettings.setBOOL("RenderAvatarVP", TRUE); - - //make sure atmospheric shaders are enabled - //gSavedSettings.setBOOL("WindLightUseAtmosShaders", TRUE); - } - - - if (!(LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders") - && gSavedSettings.getBOOL("WindLightUseAtmosShaders"))) - { - // user has disabled WindLight in their settings, downgrade - // windlight shaders to stub versions. - wl_class = 1; - } - - - // Trigger a full rebuild of the fallback skybox / cubemap if we've toggled windlight shaders - if (mVertexShaderLevel[SHADER_WINDLIGHT] != wl_class && gSky.mVOSkyp.notNull()) - { - gSky.mVOSkyp->forceSkyUpdate(); - } - - - // Load lighting shaders - mVertexShaderLevel[SHADER_LIGHTING] = light_class; - mVertexShaderLevel[SHADER_INTERFACE] = light_class; - mVertexShaderLevel[SHADER_ENVIRONMENT] = env_class; - mVertexShaderLevel[SHADER_WATER] = water_class; - mVertexShaderLevel[SHADER_OBJECT] = obj_class; - mVertexShaderLevel[SHADER_EFFECT] = effect_class; - mVertexShaderLevel[SHADER_WINDLIGHT] = wl_class; - mVertexShaderLevel[SHADER_DEFERRED] = deferred_class; - mVertexShaderLevel[SHADER_TRANSFORM] = transform_class; - - BOOL loaded = loadBasicShaders(); - - if (loaded) - { - gPipeline.mVertexShadersEnabled = TRUE; - gPipeline.mVertexShadersLoaded = 1; - - // Load all shaders to set max levels - loaded = loadShadersEnvironment(); - - if (loaded) - { - loaded = loadShadersWater(); - } - - if (loaded) - { - loaded = loadShadersWindLight(); - } - - if (loaded) - { - loaded = loadShadersEffects(); - } - - if (loaded) - { - loaded = loadShadersInterface(); - } - - if (loaded) - - { - loaded = loadTransformShaders(); - } - - if (loaded) - { - // Load max avatar shaders to set the max level - mVertexShaderLevel[SHADER_AVATAR] = 3; - mMaxAvatarShaderLevel = 3; - - if (gSavedSettings.getBOOL("RenderAvatarVP") && loadShadersObject()) - { //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) - { - 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); - } - } - else - { //hardware skinning not possible, neither is deferred rendering - mVertexShaderLevel[SHADER_AVATAR] = 0; - mVertexShaderLevel[SHADER_DEFERRED] = 0; - - if (gSavedSettings.getBOOL("RenderAvatarVP")) - { - gSavedSettings.setBOOL("RenderDeferred", FALSE); - gSavedSettings.setBOOL("RenderAvatarCloth", FALSE); - gSavedSettings.setBOOL("RenderAvatarVP", FALSE); - } - - loadShadersAvatar(); // unloads - - loaded = loadShadersObject(); - } - } + //setShaders might be called redundantly by gSavedSettings, so return on reentrance + static bool reentrance = false; + + if (!gPipeline.mInitialized || !sInitialized || reentrance || sSkipReload) + { + return; + } + + if (!gGLManager.mHasShaderObjects + || !gGLManager.mHasVertexShader + || !gGLManager.mHasFragmentShader) + { + // Viewer will show 'hardware requirements' warning later + LL_INFOS("ShaderLoading") << "Shaders not supported" << LL_ENDL; + return; + } + + static LLCachedControl<U32> max_texture_index(gSavedSettings, "RenderMaxTextureIndex", 16); + LLGLSLShader::sIndexedTextureChannels = llmax(llmin(gGLManager.mNumTextureImageUnits, (S32) max_texture_index), 1); + + //NEVER use more than 16 texture channels (work around for prevalent driver bug) + LLGLSLShader::sIndexedTextureChannels = llmin(LLGLSLShader::sIndexedTextureChannels, 16); + + if (gGLManager.mGLSLVersionMajor < 1 || + (gGLManager.mGLSLVersionMajor == 1 && gGLManager.mGLSLVersionMinor <= 20)) + { //NEVER use indexed texture rendering when GLSL version is 1.20 or earlier + LLGLSLShader::sIndexedTextureChannels = 1; + } + + reentrance = true; + + //setup preprocessor definitions + LLShaderMgr::instance()->mDefinitions["NUM_TEX_UNITS"] = llformat("%d", gGLManager.mNumTextureImageUnits); + + // Make sure the compiled shader map is cleared before we recompile shaders. + mVertexShaderObjects.clear(); + mFragmentShaderObjects.clear(); + + initAttribsAndUniforms(); + gPipeline.releaseGLBuffers(); - 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); - reentrance = false; - setShaders(); - return; - } - - if (gSavedSettings.getBOOL("VertexShaderEnable")) - { //disable shaders outright and try again - gSavedSettings.setBOOL("VertexShaderEnable", FALSE); - reentrance = false; - setShaders(); - return; - } - } - - if (loaded && !loadShadersDeferred()) - { //everything else succeeded but deferred failed, disable deferred and try again - gSavedSettings.setBOOL("RenderDeferred", FALSE); - reentrance = false; - setShaders(); - return; - } - } - else - { - LLGLSLShader::sNoFixedFunction = false; - gPipeline.mVertexShadersEnabled = FALSE; - gPipeline.mVertexShadersLoaded = 0; - mVertexShaderLevel[SHADER_LIGHTING] = 0; - mVertexShaderLevel[SHADER_INTERFACE] = 0; - mVertexShaderLevel[SHADER_ENVIRONMENT] = 0; - mVertexShaderLevel[SHADER_WATER] = 0; - mVertexShaderLevel[SHADER_OBJECT] = 0; - mVertexShaderLevel[SHADER_EFFECT] = 0; - mVertexShaderLevel[SHADER_WINDLIGHT] = 0; - mVertexShaderLevel[SHADER_AVATAR] = 0; - } - } - else - { - LLGLSLShader::sNoFixedFunction = false; - gPipeline.mVertexShadersEnabled = FALSE; - gPipeline.mVertexShadersLoaded = 0; - mVertexShaderLevel[SHADER_LIGHTING] = 0; - mVertexShaderLevel[SHADER_INTERFACE] = 0; - mVertexShaderLevel[SHADER_ENVIRONMENT] = 0; - mVertexShaderLevel[SHADER_WATER] = 0; - mVertexShaderLevel[SHADER_OBJECT] = 0; - mVertexShaderLevel[SHADER_EFFECT] = 0; - mVertexShaderLevel[SHADER_WINDLIGHT] = 0; - mVertexShaderLevel[SHADER_AVATAR] = 0; - } - - if (gViewerWindow) - { - gViewerWindow->setCursor(UI_CURSOR_ARROW); - } - gPipeline.createGLBuffers(); + LLPipeline::sWaterReflections = gGLManager.mHasCubeMap; + LLPipeline::sRenderGlow = gSavedSettings.getBOOL("RenderGlow"); + LLPipeline::updateRenderDeferred(); + + //hack to reset buffers that change behavior with shaders + gPipeline.resetVertexBuffers(); + + if (gViewerWindow) + { + gViewerWindow->setCursor(UI_CURSOR_WAIT); + } + + // Lighting + gPipeline.setLightingDetail(-1); + + // Shaders + LL_INFOS("ShaderLoading") << "\n~~~~~~~~~~~~~~~~~~\n Loading Shaders:\n~~~~~~~~~~~~~~~~~~" << LL_ENDL; + LL_INFOS("ShaderLoading") << llformat("Using GLSL %d.%d", gGLManager.mGLSLVersionMajor, gGLManager.mGLSLVersionMinor) << LL_ENDL; + + for (S32 i = 0; i < SHADER_COUNT; i++) + { + mShaderLevel[i] = 0; + } + mMaxAvatarShaderLevel = 0; + + LLGLSLShader::sNoFixedFunction = false; + LLVertexBuffer::unbind(); + + llassert((gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 10)); + + bool canRenderDeferred = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred"); + bool hasWindLightShaders = LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders"); + S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail"); + bool useRenderDeferred = canRenderDeferred && gSavedSettings.getBOOL("RenderDeferred") && gSavedSettings.getBOOL("RenderAvatarVP"); + bool doingWindLight = hasWindLightShaders && gSavedSettings.getBOOL("WindLightUseAtmosShaders"); + + //using shaders, disable fixed function + LLGLSLShader::sNoFixedFunction = true; + + S32 light_class = 3; + S32 interface_class = 2; + S32 env_class = 2; + S32 obj_class = 2; + S32 effect_class = 2; + S32 wl_class = 1; + S32 water_class = 2; + S32 deferred_class = 0; + S32 transform_class = gGLManager.mHasTransformFeedback ? 1 : 0; + + static LLCachedControl<bool> use_transform_feedback(gSavedSettings, "RenderUseTransformFeedback", false); + if (!use_transform_feedback) + { + transform_class = 0; + } + + if (useRenderDeferred) + { + //shadows + switch (shadow_detail) + { + case 1: + deferred_class = 2; // PCF shadows + break; + + case 2: + deferred_class = 2; // PCF shadows + break; + + case 0: + default: + deferred_class = 1; // no shadows + break; + } + } + + if (doingWindLight) + { + // user has disabled WindLight in their settings, downgrade + // windlight shaders to stub versions. + wl_class = 2; + } + else + { + light_class = 2; + } + + // Trigger a full rebuild of the fallback skybox / cubemap if we've toggled windlight shaders + if (!wl_class || (mShaderLevel[SHADER_WINDLIGHT] != wl_class && gSky.mVOSkyp.notNull())) + { + gSky.mVOSkyp->forceSkyUpdate(); + } + + // Load lighting shaders + mShaderLevel[SHADER_LIGHTING] = light_class; + mShaderLevel[SHADER_INTERFACE] = interface_class; + mShaderLevel[SHADER_ENVIRONMENT] = env_class; + mShaderLevel[SHADER_WATER] = water_class; + mShaderLevel[SHADER_OBJECT] = obj_class; + mShaderLevel[SHADER_EFFECT] = effect_class; + mShaderLevel[SHADER_WINDLIGHT] = wl_class; + mShaderLevel[SHADER_DEFERRED] = deferred_class; + mShaderLevel[SHADER_TRANSFORM] = transform_class; + + BOOL loaded = loadBasicShaders(); + if (loaded) + { + LL_INFOS() << "Loaded basic shaders." << LL_ENDL; + } + else + { + LL_WARNS() << "Failed to load basic shaders." << LL_ENDL; + llassert(loaded); + } + + if (loaded) + { + gPipeline.mVertexShadersEnabled = TRUE; + gPipeline.mVertexShadersLoaded = 1; + + // Load all shaders to set max levels + loaded = loadShadersEnvironment(); + + if (loaded) + { + LL_INFOS() << "Loaded environment shaders." << LL_ENDL; + } + else + { + LL_WARNS() << "Failed to load environment shaders." << LL_ENDL; + llassert(loaded); + } + + if (loaded) + { + loaded = loadShadersWater(); + if (loaded) + { + LL_INFOS() << "Loaded water shaders." << LL_ENDL; + } + else + { + LL_WARNS() << "Failed to load water shaders." << LL_ENDL; + llassert(loaded); + } + } + + if (loaded) + { + loaded = loadShadersWindLight(); + if (loaded) + { + LL_INFOS() << "Loaded windlight shaders." << LL_ENDL; + } + else + { + LL_WARNS() << "Failed to load windlight shaders." << LL_ENDL; + llassert(loaded); + } + } + + if (loaded) + { + loaded = loadShadersEffects(); + if (loaded) + { + LL_INFOS() << "Loaded effects shaders." << LL_ENDL; + } + else + { + LL_WARNS() << "Failed to load effects shaders." << LL_ENDL; + llassert(loaded); + } + } + + if (loaded) + { + loaded = loadShadersInterface(); + if (loaded) + { + LL_INFOS() << "Loaded interface shaders." << LL_ENDL; + } + else + { + LL_WARNS() << "Failed to load interface shaders." << LL_ENDL; + llassert(loaded); + } + } + + if (loaded) + + { + loaded = loadTransformShaders(); + if (loaded) + { + LL_INFOS() << "Loaded transform shaders." << LL_ENDL; + } + else + { + LL_WARNS() << "Failed to load transform shaders." << LL_ENDL; + llassert(loaded); + } + } + + if (loaded) + { + // Load max avatar shaders to set the max level + mShaderLevel[SHADER_AVATAR] = 3; + mMaxAvatarShaderLevel = 3; + + if (gSavedSettings.getBOOL("RenderAvatarVP") && loadShadersObject()) + { //hardware skinning is enabled and rigged attachment shaders loaded correctly + BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth"); + + // cloth is a class3 shader + S32 avatar_class = avatar_cloth ? 3 : 1; + + // Set the actual level + mShaderLevel[SHADER_AVATAR] = avatar_class; + + loaded = loadShadersAvatar(); + llassert(loaded); + + if (mShaderLevel[SHADER_AVATAR] != avatar_class) + { + if (mShaderLevel[SHADER_AVATAR] == 0) + { + gSavedSettings.setBOOL("RenderAvatarVP", FALSE); + } + if(llmax(mShaderLevel[SHADER_AVATAR]-1,0) >= 3) + { + avatar_cloth = true; + } + else + { + avatar_cloth = false; + } + gSavedSettings.setBOOL("RenderAvatarCloth", avatar_cloth); + } + } + else + { //hardware skinning not possible, neither is deferred rendering + mShaderLevel[SHADER_AVATAR] = 0; + mShaderLevel[SHADER_DEFERRED] = 0; + + if (gSavedSettings.getBOOL("RenderAvatarVP")) + { + gSavedSettings.setBOOL("RenderDeferred", FALSE); + gSavedSettings.setBOOL("RenderAvatarCloth", FALSE); + gSavedSettings.setBOOL("RenderAvatarVP", FALSE); + } + + loadShadersAvatar(); // unloads + + loaded = loadShadersObject(); + llassert(loaded); + } + } + + 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); + LL_WARNS() << "Falling back to no windlight shaders." << LL_ENDL; + reentrance = false; + setShaders(); + return; + } + } + + llassert(loaded); + + if (loaded && !loadShadersDeferred()) + { //everything else succeeded but deferred failed, disable deferred and try again + gSavedSettings.setBOOL("RenderDeferred", FALSE); + LL_WARNS() << "Falling back to no deferred shaders." << LL_ENDL; + reentrance = false; + setShaders(); + return; + } + } + else + { + LLGLSLShader::sNoFixedFunction = false; + gPipeline.mVertexShadersEnabled = FALSE; + gPipeline.mVertexShadersLoaded = 0; + mShaderLevel[SHADER_LIGHTING] = 0; + mShaderLevel[SHADER_INTERFACE] = 0; + mShaderLevel[SHADER_ENVIRONMENT] = 0; + mShaderLevel[SHADER_WATER] = 0; + mShaderLevel[SHADER_OBJECT] = 0; + mShaderLevel[SHADER_EFFECT] = 0; + mShaderLevel[SHADER_WINDLIGHT] = 0; + mShaderLevel[SHADER_AVATAR] = 0; + } + + if (gViewerWindow) + { + gViewerWindow->setCursor(UI_CURSOR_ARROW); + } + gPipeline.createGLBuffers(); - reentrance = false; + reentrance = false; } void LLViewerShaderMgr::unloadShaders() @@ -780,6 +817,7 @@ void LLViewerShaderMgr::unloadShaders() gWaterProgram.unload(); + gWaterEdgeProgram.unload(); gUnderWaterProgram.unload(); gTerrainProgram.unload(); gTerrainWaterProgram.unload(); @@ -795,6 +833,8 @@ void LLViewerShaderMgr::unloadShaders() gWLSkyProgram.unload(); gWLCloudProgram.unload(); + gWLSunProgram.unload(); + gWLMoonProgram.unload(); gPostColorFilterProgram.unload(); gPostNightVisionProgram.unload(); @@ -814,15 +854,15 @@ void LLViewerShaderMgr::unloadShaders() gTransformColorProgram.unload(); gTransformTangentProgram.unload(); - mVertexShaderLevel[SHADER_LIGHTING] = 0; - mVertexShaderLevel[SHADER_OBJECT] = 0; - mVertexShaderLevel[SHADER_AVATAR] = 0; - mVertexShaderLevel[SHADER_ENVIRONMENT] = 0; - mVertexShaderLevel[SHADER_WATER] = 0; - mVertexShaderLevel[SHADER_INTERFACE] = 0; - mVertexShaderLevel[SHADER_EFFECT] = 0; - mVertexShaderLevel[SHADER_WINDLIGHT] = 0; - mVertexShaderLevel[SHADER_TRANSFORM] = 0; + mShaderLevel[SHADER_LIGHTING] = 0; + mShaderLevel[SHADER_OBJECT] = 0; + mShaderLevel[SHADER_AVATAR] = 0; + mShaderLevel[SHADER_ENVIRONMENT] = 0; + mShaderLevel[SHADER_WATER] = 0; + mShaderLevel[SHADER_INTERFACE] = 0; + mShaderLevel[SHADER_EFFECT] = 0; + mShaderLevel[SHADER_WINDLIGHT] = 0; + mShaderLevel[SHADER_TRANSFORM] = 0; gPipeline.mVertexShadersLoaded = 0; } @@ -856,7 +896,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders() 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); @@ -865,34 +905,55 @@ BOOL LLViewerShaderMgr::loadBasicShaders() // (in order of shader function call depth for reference purposes, deepest level first) vector< pair<string, S32> > shaders; - shaders.push_back( make_pair( "windlight/atmosphericsVarsV.glsl", mVertexShaderLevel[SHADER_WINDLIGHT] ) ); - shaders.push_back( make_pair( "windlight/atmosphericsVarsWaterV.glsl", mVertexShaderLevel[SHADER_WINDLIGHT] ) ); - shaders.push_back( make_pair( "windlight/atmosphericsHelpersV.glsl", mVertexShaderLevel[SHADER_WINDLIGHT] ) ); - shaders.push_back( make_pair( "lighting/lightFuncV.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - shaders.push_back( make_pair( "lighting/sumLightsV.glsl", sum_lights_class ) ); - shaders.push_back( make_pair( "lighting/lightV.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - shaders.push_back( make_pair( "lighting/lightFuncSpecularV.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - shaders.push_back( make_pair( "lighting/sumLightsSpecularV.glsl", sum_lights_class ) ); - shaders.push_back( make_pair( "lighting/lightSpecularV.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - shaders.push_back( make_pair( "windlight/atmosphericsV.glsl", mVertexShaderLevel[SHADER_WINDLIGHT] ) ); - shaders.push_back( make_pair( "avatar/avatarSkinV.glsl", 1 ) ); - shaders.push_back( make_pair( "avatar/objectSkinV.glsl", 1 ) ); + shaders.push_back( make_pair( "windlight/atmosphericsVarsV.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); + shaders.push_back( make_pair( "windlight/atmosphericsVarsWaterV.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); + shaders.push_back( make_pair( "windlight/atmosphericsHelpersV.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); + shaders.push_back( make_pair( "lighting/lightFuncV.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + shaders.push_back( make_pair( "lighting/sumLightsV.glsl", sum_lights_class ) ); + shaders.push_back( make_pair( "lighting/lightV.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + shaders.push_back( make_pair( "lighting/lightFuncSpecularV.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + shaders.push_back( make_pair( "lighting/sumLightsSpecularV.glsl", sum_lights_class ) ); + shaders.push_back( make_pair( "lighting/lightSpecularV.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + shaders.push_back( make_pair( "windlight/atmosphericsFuncs.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); + shaders.push_back( make_pair( "windlight/atmosphericsV.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); + shaders.push_back( make_pair( "avatar/avatarSkinV.glsl", 1 ) ); + shaders.push_back( make_pair( "avatar/objectSkinV.glsl", 1 ) ); if (gGLManager.mGLSLVersionMajor >= 2 || gGLManager.mGLSLVersionMinor >= 30) { - shaders.push_back( make_pair( "objects/indexedTextureV.glsl", 1 ) ); + shaders.push_back( make_pair( "objects/indexedTextureV.glsl", 1 ) ); } - shaders.push_back( make_pair( "objects/nonindexedTextureV.glsl", 1 ) ); + shaders.push_back( make_pair( "objects/nonindexedTextureV.glsl", 1 ) ); boost::unordered_map<std::string, std::string> attribs; attribs["MAX_JOINTS_PER_MESH_OBJECT"] = boost::lexical_cast<std::string>(LLSkinningUtil::getMaxJointCount()); + BOOL ambient_kill = gSavedSettings.getBOOL("AmbientDisable"); + BOOL sunlight_kill = gSavedSettings.getBOOL("SunlightDisable"); + BOOL local_light_kill = gSavedSettings.getBOOL("LocalLightDisable"); + + if (ambient_kill) + { + attribs["AMBIENT_KILL"] = "1"; + } + + if (sunlight_kill) + { + attribs["SUNLIGHT_KILL"] = "1"; + } + + if (local_light_kill) + { + attribs["LOCAL_LIGHT_KILL"] = "1"; + } + // 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, &attribs) == 0) { + LL_SHADER_LOADING_WARNS() << "Failed to load vertex shader " << shaders[i].first << LL_ENDL; return FALSE; } } @@ -908,43 +969,51 @@ BOOL LLViewerShaderMgr::loadBasicShaders() ch = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); } - std::vector<S32> index_channels; - index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsVarsF.glsl", mVertexShaderLevel[SHADER_WINDLIGHT] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsVarsWaterF.glsl", mVertexShaderLevel[SHADER_WINDLIGHT] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/gammaF.glsl", mVertexShaderLevel[SHADER_WINDLIGHT]) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsF.glsl", mVertexShaderLevel[SHADER_WINDLIGHT] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/transportF.glsl", mVertexShaderLevel[SHADER_WINDLIGHT] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "environment/waterFogF.glsl", mVertexShaderLevel[SHADER_WATER] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightNonIndexedF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightAlphaMaskNonIndexedF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightNonIndexedF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightNonIndexedAlphaMaskF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightWaterNonIndexedF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightWaterAlphaMaskNonIndexedF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightWaterNonIndexedF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightShinyNonIndexedF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightShinyNonIndexedF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightShinyWaterNonIndexedF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightShinyWaterNonIndexedF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightAlphaMaskF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightFullbrightF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightFullbrightAlphaMaskF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightWaterF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightWaterAlphaMaskF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightFullbrightWaterF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightFullbrightWaterAlphaMaskF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightShinyF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightFullbrightShinyF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightShinyWaterF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightFullbrightShinyWaterF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); - + std::vector<S32> index_channels; + index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsVarsF.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsVarsWaterF.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsHelpersF.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/gammaF.glsl", mShaderLevel[SHADER_WINDLIGHT]) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsFuncs.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsF.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/transportF.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "environment/waterFogF.glsl", mShaderLevel[SHADER_WATER] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "environment/encodeNormF.glsl", mShaderLevel[SHADER_ENVIRONMENT] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "environment/srgbF.glsl", mShaderLevel[SHADER_ENVIRONMENT] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/deferredUtil.glsl", 1) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/shadowUtil.glsl", 1) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/aoUtil.glsl", 1) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightAlphaMaskNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightNonIndexedAlphaMaskF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightWaterNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightWaterAlphaMaskNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightWaterNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightShinyNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightShinyNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightShinyWaterNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightShinyWaterNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightAlphaMaskF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightFullbrightF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightFullbrightAlphaMaskF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightWaterF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightWaterAlphaMaskF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightFullbrightWaterF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightFullbrightWaterAlphaMaskF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightShinyF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightFullbrightShinyF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightShinyWaterF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightFullbrightShinyWaterF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); + 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, &attribs, index_channels[i]) == 0) { + LL_SHADER_LOADING_WARNS() << "Failed to load fragment shader " << shaders[i].first << LL_ENDL; return FALSE; } } @@ -956,7 +1025,7 @@ BOOL LLViewerShaderMgr::loadShadersEnvironment() { BOOL success = TRUE; - if (mVertexShaderLevel[SHADER_ENVIRONMENT] == 0) + if (mShaderLevel[SHADER_ENVIRONMENT] == 0) { gTerrainProgram.unload(); return TRUE; @@ -968,19 +1037,23 @@ BOOL LLViewerShaderMgr::loadShadersEnvironment() gTerrainProgram.mFeatures.calculatesLighting = true; gTerrainProgram.mFeatures.calculatesAtmospherics = true; gTerrainProgram.mFeatures.hasAtmospherics = true; + gTerrainProgram.mFeatures.hasTransport = true; + gTerrainProgram.mFeatures.hasGamma = true; + gTerrainProgram.mFeatures.hasSrgb = true; gTerrainProgram.mFeatures.mIndexedTextureChannels = 0; gTerrainProgram.mFeatures.disableTextureIndex = true; gTerrainProgram.mFeatures.hasGamma = true; - gTerrainProgram.mShaderFiles.clear(); - 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, NULL); + gTerrainProgram.mShaderFiles.clear(); + 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 = mShaderLevel[SHADER_ENVIRONMENT]; + success = gTerrainProgram.createShader(NULL, NULL); + llassert(success); } if (!success) { - mVertexShaderLevel[SHADER_ENVIRONMENT] = 0; + mShaderLevel[SHADER_ENVIRONMENT] = 0; return FALSE; } @@ -994,9 +1067,10 @@ BOOL LLViewerShaderMgr::loadShadersWater() BOOL success = TRUE; BOOL terrainWaterSuccess = TRUE; - if (mVertexShaderLevel[SHADER_WATER] == 0) + if (mShaderLevel[SHADER_WATER] == 0) { gWaterProgram.unload(); + gWaterEdgeProgram.unload(); gUnderWaterProgram.unload(); gTerrainWaterProgram.unload(); return TRUE; @@ -1009,11 +1083,32 @@ BOOL LLViewerShaderMgr::loadShadersWater() gWaterProgram.mFeatures.calculatesAtmospherics = true; gWaterProgram.mFeatures.hasGamma = true; gWaterProgram.mFeatures.hasTransport = true; + gWaterProgram.mFeatures.hasSrgb = true; gWaterProgram.mShaderFiles.clear(); 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]; + gWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; + gWaterProgram.mShaderLevel = mShaderLevel[SHADER_WATER]; success = gWaterProgram.createShader(NULL, NULL); + llassert(success); + } + + if (success) + { + // load water shader + gWaterEdgeProgram.mName = "Water Edge Shader"; + gWaterEdgeProgram.mFeatures.calculatesAtmospherics = true; + gWaterEdgeProgram.mFeatures.hasGamma = true; + gWaterEdgeProgram.mFeatures.hasTransport = true; + gWaterEdgeProgram.mFeatures.hasSrgb = true; + gWaterEdgeProgram.mShaderFiles.clear(); + gWaterEdgeProgram.mShaderFiles.push_back(make_pair("environment/waterV.glsl", GL_VERTEX_SHADER_ARB)); + gWaterEdgeProgram.mShaderFiles.push_back(make_pair("environment/waterF.glsl", GL_FRAGMENT_SHADER_ARB)); + gWaterEdgeProgram.addPermutation("WATER_EDGE", "1"); + gWaterEdgeProgram.mShaderGroup = LLGLSLShader::SG_WATER; + gWaterEdgeProgram.mShaderLevel = mShaderLevel[SHADER_WATER]; + success = gWaterEdgeProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -1021,13 +1116,14 @@ BOOL LLViewerShaderMgr::loadShadersWater() //load under water vertex shader gUnderWaterProgram.mName = "Underwater Shader"; gUnderWaterProgram.mFeatures.calculatesAtmospherics = true; + gUnderWaterProgram.mFeatures.hasWaterFog = true; gUnderWaterProgram.mShaderFiles.clear(); gUnderWaterProgram.mShaderFiles.push_back(make_pair("environment/waterV.glsl", GL_VERTEX_SHADER_ARB)); gUnderWaterProgram.mShaderFiles.push_back(make_pair("environment/underWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gUnderWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_WATER]; - gUnderWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - + gUnderWaterProgram.mShaderLevel = mShaderLevel[SHADER_WATER]; + gUnderWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gUnderWaterProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -1041,31 +1137,40 @@ BOOL LLViewerShaderMgr::loadShadersWater() gTerrainWaterProgram.mFeatures.mIndexedTextureChannels = 0; gTerrainWaterProgram.mFeatures.disableTextureIndex = true; gTerrainWaterProgram.mShaderFiles.clear(); - gTerrainWaterProgram.mShaderFiles.push_back(make_pair("environment/terrainV.glsl", GL_VERTEX_SHADER_ARB)); + gTerrainWaterProgram.mShaderFiles.push_back(make_pair("environment/terrainWaterV.glsl", GL_VERTEX_SHADER_ARB)); gTerrainWaterProgram.mShaderFiles.push_back(make_pair("environment/terrainWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gTerrainWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_ENVIRONMENT]; + gTerrainWaterProgram.mShaderLevel = mShaderLevel[SHADER_ENVIRONMENT]; gTerrainWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; + + gTerrainWaterProgram.clearPermutations(); + + if (LLPipeline::RenderDeferred) + { + gTerrainWaterProgram.addPermutation("ALM", "1"); + } + terrainWaterSuccess = gTerrainWaterProgram.createShader(NULL, NULL); + llassert(terrainWaterSuccess); } /// Keep track of water shader levels - if (gWaterProgram.mShaderLevel != mVertexShaderLevel[SHADER_WATER] - || gUnderWaterProgram.mShaderLevel != mVertexShaderLevel[SHADER_WATER]) + if (gWaterProgram.mShaderLevel != mShaderLevel[SHADER_WATER] + || gUnderWaterProgram.mShaderLevel != mShaderLevel[SHADER_WATER]) { - mVertexShaderLevel[SHADER_WATER] = llmin(gWaterProgram.mShaderLevel, gUnderWaterProgram.mShaderLevel); + mShaderLevel[SHADER_WATER] = llmin(gWaterProgram.mShaderLevel, gUnderWaterProgram.mShaderLevel); } if (!success) { - mVertexShaderLevel[SHADER_WATER] = 0; + mShaderLevel[SHADER_WATER] = 0; return FALSE; } // 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) + if (mShaderLevel[SHADER_WATER] > 1 && !terrainWaterSuccess) { - mVertexShaderLevel[SHADER_WATER]--; + mShaderLevel[SHADER_WATER]--; return loadShadersWater(); } @@ -1078,7 +1183,7 @@ BOOL LLViewerShaderMgr::loadShadersEffects() { BOOL success = TRUE; - if (mVertexShaderLevel[SHADER_EFFECT] == 0) + if (mShaderLevel[SHADER_EFFECT] == 0) { gGlowProgram.unload(); gGlowExtractProgram.unload(); @@ -1093,7 +1198,7 @@ BOOL LLViewerShaderMgr::loadShadersEffects() gGlowProgram.mShaderFiles.clear(); 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]; + gGlowProgram.mShaderLevel = mShaderLevel[SHADER_EFFECT]; success = gGlowProgram.createShader(NULL, NULL); if (!success) { @@ -1107,7 +1212,7 @@ BOOL LLViewerShaderMgr::loadShadersEffects() gGlowExtractProgram.mShaderFiles.clear(); 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]; + gGlowExtractProgram.mShaderLevel = mShaderLevel[SHADER_EFFECT]; success = gGlowExtractProgram.createShader(NULL, NULL); if (!success) { @@ -1121,7 +1226,13 @@ BOOL LLViewerShaderMgr::loadShadersEffects() BOOL LLViewerShaderMgr::loadShadersDeferred() { - if (mVertexShaderLevel[SHADER_DEFERRED] == 0) + bool use_sun_shadow = mShaderLevel[SHADER_DEFERRED] > 1; + + BOOL ambient_kill = gSavedSettings.getBOOL("AmbientDisable"); + BOOL sunlight_kill = gSavedSettings.getBOOL("SunlightDisable"); + BOOL local_light_kill = gSavedSettings.getBOOL("LocalLightDisable"); + + if (mShaderLevel[SHADER_DEFERRED] == 0) { gDeferredTreeProgram.unload(); gDeferredTreeShadowProgram.unload(); @@ -1136,6 +1247,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredBumpProgram.unload(); gDeferredImpostorProgram.unload(); gDeferredTerrainProgram.unload(); + gDeferredTerrainWaterProgram.unload(); gDeferredLightProgram.unload(); for (U32 i = 0; i < LL_DEFERRED_MULTI_LIGHT_COUNT; ++i) { @@ -1149,9 +1261,14 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredSoftenWaterProgram.unload(); gDeferredShadowProgram.unload(); gDeferredShadowCubeProgram.unload(); - gDeferredShadowAlphaMaskProgram.unload(); + gDeferredShadowAlphaMaskProgram.unload(); + gDeferredShadowFullbrightAlphaMaskProgram.unload(); gDeferredAvatarShadowProgram.unload(); + gDeferredAvatarAlphaShadowProgram.unload(); + gDeferredAvatarAlphaMaskShadowProgram.unload(); gDeferredAttachmentShadowProgram.unload(); + gDeferredAttachmentAlphaShadowProgram.unload(); + gDeferredAttachmentAlphaMaskShadowProgram.unload(); gDeferredAvatarProgram.unload(); gDeferredAvatarAlphaProgram.unload(); gDeferredAlphaProgram.unload(); @@ -1171,6 +1288,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredUnderWaterProgram.unload(); gDeferredWLSkyProgram.unload(); gDeferredWLCloudProgram.unload(); + gDeferredWLSunProgram.unload(); + gDeferredWLMoonProgram.unload(); gDeferredStarProgram.unload(); gDeferredFullbrightShinyProgram.unload(); gDeferredSkinnedFullbrightShinyProgram.unload(); @@ -1197,7 +1316,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredHighlightProgram.mShaderFiles.clear(); gDeferredHighlightProgram.mShaderFiles.push_back(make_pair("interface/highlightV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredHighlightProgram.mShaderFiles.push_back(make_pair("deferred/highlightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredHighlightProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gDeferredHighlightProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gDeferredHighlightProgram.createShader(NULL, NULL); } @@ -1207,7 +1326,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredHighlightNormalProgram.mShaderFiles.clear(); gDeferredHighlightNormalProgram.mShaderFiles.push_back(make_pair("interface/highlightNormV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredHighlightNormalProgram.mShaderFiles.push_back(make_pair("deferred/highlightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredHighlightNormalProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gDeferredHighlightNormalProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gHighlightNormalProgram.createShader(NULL, NULL); } @@ -1217,83 +1336,97 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredHighlightSpecularProgram.mShaderFiles.clear(); gDeferredHighlightSpecularProgram.mShaderFiles.push_back(make_pair("interface/highlightSpecV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredHighlightSpecularProgram.mShaderFiles.push_back(make_pair("deferred/highlightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredHighlightSpecularProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gDeferredHighlightSpecularProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gDeferredHighlightSpecularProgram.createShader(NULL, NULL); } if (success) { gDeferredDiffuseProgram.mName = "Deferred Diffuse Shader"; + gDeferredDiffuseProgram.mFeatures.encodesNormal = true; + gDeferredDiffuseProgram.mFeatures.hasSrgb = true; gDeferredDiffuseProgram.mShaderFiles.clear(); gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseIndexedF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredDiffuseProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; - gDeferredDiffuseProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredDiffuseProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredDiffuseProgram.createShader(NULL, NULL); } if (success) { gDeferredDiffuseAlphaMaskProgram.mName = "Deferred Diffuse Alpha Mask Shader"; + gDeferredDiffuseAlphaMaskProgram.mFeatures.encodesNormal = true; gDeferredDiffuseAlphaMaskProgram.mShaderFiles.clear(); gDeferredDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskIndexedF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredDiffuseAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; - gDeferredDiffuseAlphaMaskProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredDiffuseAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredDiffuseAlphaMaskProgram.createShader(NULL, NULL); } if (success) { gDeferredNonIndexedDiffuseAlphaMaskProgram.mName = "Deferred Diffuse Non-Indexed Alpha Mask Shader"; + gDeferredNonIndexedDiffuseAlphaMaskProgram.mFeatures.encodesNormal = true; 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)); - gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredNonIndexedDiffuseAlphaMaskProgram.createShader(NULL, NULL); + llassert(success); } - + if (success) { gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mName = "Deferred Diffuse Non-Indexed Alpha Mask Shader"; + gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mFeatures.encodesNormal = true; gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderFiles.clear(); gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderFiles.push_back(make_pair("deferred/diffuseNoColorV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskNoColorF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredNonIndexedDiffuseProgram.mName = "Non Indexed Deferred Diffuse Shader"; gDeferredNonIndexedDiffuseProgram.mShaderFiles.clear(); + gDeferredNonIndexedDiffuseProgram.mFeatures.encodesNormal = true; + gDeferredNonIndexedDiffuseProgram.mFeatures.hasSrgb = true; gDeferredNonIndexedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredNonIndexedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredNonIndexedDiffuseProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredNonIndexedDiffuseProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredNonIndexedDiffuseProgram.createShader(NULL, NULL); + llassert(success); } - if (success) { gDeferredSkinnedDiffuseProgram.mName = "Deferred Skinned Diffuse Shader"; gDeferredSkinnedDiffuseProgram.mFeatures.hasObjectSkinning = true; + gDeferredSkinnedDiffuseProgram.mFeatures.encodesNormal = true; + gDeferredSkinnedDiffuseProgram.mFeatures.hasSrgb = true; gDeferredSkinnedDiffuseProgram.mShaderFiles.clear(); gDeferredSkinnedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredSkinnedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredSkinnedDiffuseProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredSkinnedDiffuseProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredSkinnedDiffuseProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredSkinnedBumpProgram.mName = "Deferred Skinned Bump Shader"; gDeferredSkinnedBumpProgram.mFeatures.hasObjectSkinning = true; + gDeferredSkinnedBumpProgram.mFeatures.encodesNormal = true; gDeferredSkinnedBumpProgram.mShaderFiles.clear(); gDeferredSkinnedBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredSkinnedBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredSkinnedBumpProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredSkinnedBumpProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredSkinnedBumpProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -1304,16 +1437,47 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredSkinnedAlphaProgram.mFeatures.hasLighting = false; gDeferredSkinnedAlphaProgram.mFeatures.isAlphaLighting = true; gDeferredSkinnedAlphaProgram.mFeatures.disableTextureIndex = true; + gDeferredSkinnedAlphaProgram.mFeatures.hasSrgb = true; + gDeferredSkinnedAlphaProgram.mFeatures.encodesNormal = true; + gDeferredSkinnedAlphaProgram.mFeatures.calculatesAtmospherics = true; + gDeferredSkinnedAlphaProgram.mFeatures.hasAtmospherics = true; + gDeferredSkinnedAlphaProgram.mFeatures.hasTransport = true; + gDeferredSkinnedAlphaProgram.mFeatures.hasGamma = true; + gDeferredSkinnedAlphaProgram.mFeatures.hasShadows = true; + gDeferredSkinnedAlphaProgram.mShaderFiles.clear(); 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.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + + gDeferredSkinnedAlphaProgram.clearPermutations(); 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"); + gDeferredSkinnedAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1"); + + if (use_sun_shadow) + { + gDeferredSkinnedAlphaProgram.addPermutation("HAS_SHADOW", "1"); + } + + if (ambient_kill) + { + gDeferredSkinnedAlphaProgram.addPermutation("AMBIENT_KILL", "1"); + } + + if (sunlight_kill) + { + gDeferredSkinnedAlphaProgram.addPermutation("SUNLIGHT_KILL", "1"); + } + + if (local_light_kill) + { + gDeferredSkinnedAlphaProgram.addPermutation("LOCAL_LIGHT_KILL", "1"); + } + success = gDeferredSkinnedAlphaProgram.createShader(NULL, NULL); - + llassert(success); + // Hack to include uniforms for lighting without linking in lighting file gDeferredSkinnedAlphaProgram.mFeatures.calculatesLighting = true; gDeferredSkinnedAlphaProgram.mFeatures.hasLighting = true; @@ -1322,11 +1486,13 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredBumpProgram.mName = "Deferred Bump Shader"; + gDeferredBumpProgram.mFeatures.encodesNormal = true; gDeferredBumpProgram.mShaderFiles.clear(); gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredBumpProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredBumpProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredBumpProgram.createShader(NULL, NULL); + llassert(success); } gDeferredMaterialProgram[1].mFeatures.hasLighting = false; @@ -1351,6 +1517,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() { if (success) { + mShaderList.push_back(&gDeferredMaterialProgram[i]); + gDeferredMaterialProgram[i].mName = llformat("Deferred Material Shader %d", i); U32 alpha_mode = i & 0x3; @@ -1358,48 +1526,138 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() 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; - } + gDeferredMaterialProgram[i].mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredMaterialProgram[i].createShader(NULL, NULL); - } + gDeferredMaterialProgram[i].clearPermutations(); - if (success) - { - gDeferredMaterialWaterProgram[i].mName = llformat("Deferred Underwater Material Shader %d", i); + bool has_normal_map = (i & 0x8) > 0; + bool has_specular_map = (i & 0x4) > 0; - U32 alpha_mode = i & 0x3; + if (has_normal_map) + { + gDeferredMaterialProgram[i].addPermutation("HAS_NORMAL_MAP", "1"); + } - 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) + if (has_specular_map) { - gDeferredMaterialWaterProgram[i].mFeatures.hasObjectSkinning = true; + gDeferredMaterialProgram[i].addPermutation("HAS_SPECULAR_MAP", "1"); } - success = gDeferredMaterialWaterProgram[i].createShader(NULL, NULL);//&mWLUniforms); + if (ambient_kill) + { + gDeferredMaterialProgram[i].addPermutation("AMBIENT_KILL", "1"); + } + + if (sunlight_kill) + { + gDeferredMaterialProgram[i].addPermutation("SUNLIGHT_KILL", "1"); + } + + if (local_light_kill) + { + gDeferredMaterialProgram[i].addPermutation("LOCAL_LIGHT_KILL", "1"); + } + + gDeferredMaterialProgram[i].addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode)); + + if (use_sun_shadow) + { + gDeferredMaterialProgram[i].addPermutation("HAS_SUN_SHADOW", "1"); + } + + bool has_skin = i & 0x10; + gDeferredMaterialProgram[i].mFeatures.hasSrgb = true; + gDeferredMaterialProgram[i].mFeatures.hasTransport = true; + gDeferredMaterialProgram[i].mFeatures.encodesNormal = true; + gDeferredMaterialProgram[i].mFeatures.calculatesAtmospherics = true; + gDeferredMaterialProgram[i].mFeatures.hasAtmospherics = true; + gDeferredMaterialProgram[i].mFeatures.hasGamma = true; + gDeferredMaterialProgram[i].mFeatures.hasShadows = use_sun_shadow; + + if (has_skin) + { + gDeferredMaterialProgram[i].addPermutation("HAS_SKIN", "1"); + gDeferredMaterialProgram[i].mFeatures.hasObjectSkinning = true; + } + + success = gDeferredMaterialProgram[i].createShader(NULL, NULL); + llassert(success); + } + + if (success) + { + mShaderList.push_back(&gDeferredMaterialWaterProgram[i]); + + 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 = mShaderLevel[SHADER_DEFERRED]; + gDeferredMaterialWaterProgram[i].mShaderGroup = LLGLSLShader::SG_WATER; + + gDeferredMaterialWaterProgram[i].clearPermutations(); + + bool has_normal_map = (i & 0x8) > 0; + bool has_specular_map = (i & 0x4) > 0; + + if (has_normal_map) + { + gDeferredMaterialWaterProgram[i].addPermutation("HAS_NORMAL_MAP", "1"); + } + + if (has_specular_map) + { + gDeferredMaterialWaterProgram[i].addPermutation("HAS_SPECULAR_MAP", "1"); + } + + gDeferredMaterialWaterProgram[i].addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode)); + if (use_sun_shadow) + { + gDeferredMaterialWaterProgram[i].addPermutation("HAS_SUN_SHADOW", "1"); + } + + bool has_skin = i & 0x10; + if (has_skin) + { + gDeferredMaterialWaterProgram[i].addPermutation("HAS_SKIN", "1"); + } + gDeferredMaterialWaterProgram[i].addPermutation("WATER_FOG","1"); + + if (ambient_kill) + { + gDeferredMaterialWaterProgram[i].addPermutation("AMBIENT_KILL", "1"); + } + + if (sunlight_kill) + { + gDeferredMaterialWaterProgram[i].addPermutation("SUNLIGHT_KILL", "1"); + } + + if (local_light_kill) + { + gDeferredMaterialWaterProgram[i].addPermutation("LOCAL_LIGHT_KILL", "1"); + } + + gDeferredMaterialWaterProgram[i].mFeatures.hasWaterFog = true; + gDeferredMaterialWaterProgram[i].mFeatures.hasSrgb = true; + gDeferredMaterialWaterProgram[i].mFeatures.encodesNormal = true; + gDeferredMaterialWaterProgram[i].mFeatures.calculatesAtmospherics = true; + gDeferredMaterialWaterProgram[i].mFeatures.hasAtmospherics = true; + gDeferredMaterialWaterProgram[i].mFeatures.hasGamma = true; + + gDeferredMaterialWaterProgram[i].mFeatures.hasTransport = true; + gDeferredMaterialWaterProgram[i].mFeatures.hasShadows = use_sun_shadow; + + if (has_skin) + { + gDeferredMaterialWaterProgram[i].mFeatures.hasObjectSkinning = true; + } + + success = gDeferredMaterialWaterProgram[i].createShader(NULL, NULL);//&mWLUniforms); + llassert(success); } } @@ -1426,9 +1684,10 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() { gDeferredTreeProgram.mName = "Deferred Tree Shader"; gDeferredTreeProgram.mShaderFiles.clear(); + gDeferredTreeProgram.mFeatures.encodesNormal = true; gDeferredTreeProgram.mShaderFiles.push_back(make_pair("deferred/treeV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredTreeProgram.mShaderFiles.push_back(make_pair("deferred/treeF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredTreeProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredTreeProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredTreeProgram.createShader(NULL, NULL); } @@ -1436,44 +1695,95 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() { gDeferredTreeShadowProgram.mName = "Deferred Tree Shadow Shader"; gDeferredTreeShadowProgram.mShaderFiles.clear(); + gDeferredTreeShadowProgram.mFeatures.isDeferred = true; + gDeferredTreeShadowProgram.mFeatures.hasShadows = true; gDeferredTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredTreeShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredTreeShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredTreeShadowProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredImpostorProgram.mName = "Deferred Impostor Shader"; + gDeferredImpostorProgram.mFeatures.hasSrgb = true; + gDeferredImpostorProgram.mFeatures.encodesNormal = true; + //gDeferredImpostorProgram.mFeatures.isDeferred = true; gDeferredImpostorProgram.mShaderFiles.clear(); gDeferredImpostorProgram.mShaderFiles.push_back(make_pair("deferred/impostorV.glsl", GL_VERTEX_SHADER_ARB)); - gDeferredImpostorProgram.mShaderFiles.push_back(make_pair("deferred/impostorF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredImpostorProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; - success = gDeferredImpostorProgram.createShader(NULL, NULL); + gDeferredImpostorProgram.mShaderFiles.push_back(make_pair("deferred/impostorF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredImpostorProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + success = gDeferredImpostorProgram.createShader(NULL, NULL); + llassert(success); } if (success) - { + { gDeferredLightProgram.mName = "Deferred Light Shader"; + gDeferredLightProgram.mFeatures.isDeferred = true; + gDeferredLightProgram.mFeatures.hasShadows = true; + gDeferredLightProgram.mFeatures.hasSrgb = true; + gDeferredLightProgram.mShaderFiles.clear(); 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]; + gDeferredLightProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + + gDeferredLightProgram.clearPermutations(); + + if (ambient_kill) + { + gDeferredLightProgram.addPermutation("AMBIENT_KILL", "1"); + } + + if (sunlight_kill) + { + gDeferredLightProgram.addPermutation("SUNLIGHT_KILL", "1"); + } + + if (local_light_kill) + { + gDeferredLightProgram.addPermutation("LOCAL_LIGHT_KILL", "1"); + } success = gDeferredLightProgram.createShader(NULL, NULL); + llassert(success); } for (U32 i = 0; i < LL_DEFERRED_MULTI_LIGHT_COUNT; i++) { - if (success) - { + if (success) + { gDeferredMultiLightProgram[i].mName = llformat("Deferred MultiLight Shader %d", i); + gDeferredMultiLightProgram[i].mFeatures.isDeferred = true; + gDeferredMultiLightProgram[i].mFeatures.hasShadows = true; + gDeferredMultiLightProgram[i].mFeatures.hasSrgb = true; + + gDeferredMultiLightProgram[i].clearPermutations(); 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].mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredMultiLightProgram[i].addPermutation("LIGHT_COUNT", llformat("%d", i+1)); + + if (ambient_kill) + { + gDeferredMultiLightProgram[i].addPermutation("AMBIENT_KILL", "1"); + } + + if (sunlight_kill) + { + gDeferredMultiLightProgram[i].addPermutation("SUNLIGHT_KILL", "1"); + } + + if (local_light_kill) + { + gDeferredMultiLightProgram[i].addPermutation("LOCAL_LIGHT_KILL", "1"); + } + success = gDeferredMultiLightProgram[i].createShader(NULL, NULL); + llassert(success); } } @@ -1481,22 +1791,54 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() { gDeferredSpotLightProgram.mName = "Deferred SpotLight Shader"; gDeferredSpotLightProgram.mShaderFiles.clear(); + gDeferredSpotLightProgram.mFeatures.hasSrgb = true; + gDeferredSpotLightProgram.mFeatures.isDeferred = true; + gDeferredSpotLightProgram.mFeatures.hasShadows = true; + + gDeferredSpotLightProgram.clearPermutations(); gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/spotLightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredSpotLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredSpotLightProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + + if (ambient_kill) + { + gDeferredSpotLightProgram.addPermutation("AMBIENT_KILL", "1"); + } + + if (sunlight_kill) + { + gDeferredSpotLightProgram.addPermutation("SUNLIGHT_KILL", "1"); + } + + if (local_light_kill) + { + gDeferredSpotLightProgram.addPermutation("LOCAL_LIGHT_KILL", "1"); + } success = gDeferredSpotLightProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredMultiSpotLightProgram.mName = "Deferred MultiSpotLight Shader"; + gDeferredMultiSpotLightProgram.mFeatures.hasSrgb = true; + gDeferredMultiSpotLightProgram.mFeatures.isDeferred = true; + gDeferredMultiSpotLightProgram.mFeatures.hasShadows = true; + + gDeferredMultiSpotLightProgram.clearPermutations(); gDeferredMultiSpotLightProgram.mShaderFiles.clear(); gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiPointLightV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiSpotLightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredMultiSpotLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredMultiSpotLightProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + + if (local_light_kill) + { + gDeferredMultiSpotLightProgram.addPermutation("LOCAL_LIGHT_KILL", "1"); + } success = gDeferredMultiSpotLightProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -1504,37 +1846,48 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() std::string fragment; std::string vertex = "deferred/sunLightV.glsl"; - if (gSavedSettings.getBOOL("RenderDeferredSSAO")) - { - fragment = "deferred/sunLightSSAOF.glsl"; - } - else - { - fragment = "deferred/sunLightF.glsl"; - if (mVertexShaderLevel[SHADER_DEFERRED] == 1) - { //no shadows, no SSAO, no frag coord - vertex = "deferred/sunLightNoFragCoordV.glsl"; - } - } - - gDeferredSunProgram.mName = "Deferred Sun Shader"; + bool use_ao = gSavedSettings.getBOOL("RenderDeferredSSAO"); + + if (use_ao) + { + fragment = "deferred/sunLightSSAOF.glsl"; + } + else + { + fragment = "deferred/sunLightF.glsl"; + if (mShaderLevel[SHADER_DEFERRED] == 1) + { //no shadows, no SSAO, no frag coord + vertex = "deferred/sunLightNoFragCoordV.glsl"; + } + } + + gDeferredSunProgram.mName = "Deferred Sun Shader"; + gDeferredSunProgram.mFeatures.isDeferred = true; + gDeferredSunProgram.mFeatures.hasShadows = true; + gDeferredSunProgram.mFeatures.hasAmbientOcclusion = use_ao; + + gDeferredSunProgram.mName = "Deferred Sun Shader"; gDeferredSunProgram.mShaderFiles.clear(); gDeferredSunProgram.mShaderFiles.push_back(make_pair(vertex, GL_VERTEX_SHADER_ARB)); gDeferredSunProgram.mShaderFiles.push_back(make_pair(fragment, GL_FRAGMENT_SHADER_ARB)); - gDeferredSunProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredSunProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredSunProgram.createShader(NULL, NULL); + success = gDeferredSunProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredBlurLightProgram.mName = "Deferred Blur Light Shader"; + gDeferredBlurLightProgram.mFeatures.isDeferred = true; + gDeferredBlurLightProgram.mShaderFiles.clear(); gDeferredBlurLightProgram.mShaderFiles.push_back(make_pair("deferred/blurLightV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredBlurLightProgram.mShaderFiles.push_back(make_pair("deferred/blurLightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredBlurLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredBlurLightProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredBlurLightProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -1545,63 +1898,105 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAlphaProgram.mFeatures.hasLighting = false; gDeferredAlphaProgram.mFeatures.isAlphaLighting = true; gDeferredAlphaProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels - if (mVertexShaderLevel[SHADER_DEFERRED] < 1) - { - gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; - } - else - { //shave off some texture units for shadow maps - gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1); - } - - 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]; + gDeferredAlphaProgram.mFeatures.hasSrgb = true; + gDeferredAlphaProgram.mFeatures.encodesNormal = true; + gDeferredAlphaProgram.mFeatures.calculatesAtmospherics = true; + gDeferredAlphaProgram.mFeatures.hasAtmospherics = true; + gDeferredAlphaProgram.mFeatures.hasGamma = true; + gDeferredAlphaProgram.mFeatures.hasTransport = true; + gDeferredAlphaProgram.mFeatures.hasShadows = use_sun_shadow; + + if (mShaderLevel[SHADER_DEFERRED] < 1) + { + gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; + } + else + { //shave off some texture units for shadow maps + gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1); + } + + 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.clearPermutations(); + gDeferredAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1"); + gDeferredAlphaProgram.addPermutation("USE_INDEXED_TEX", "1"); + if (use_sun_shadow) + { + gDeferredAlphaProgram.addPermutation("HAS_SHADOW", "1"); + } + + if (ambient_kill) + { + gDeferredAlphaProgram.addPermutation("AMBIENT_KILL", "1"); + } + + if (sunlight_kill) + { + gDeferredAlphaProgram.addPermutation("SUNLIGHT_KILL", "1"); + } + + if (local_light_kill) + { + gDeferredAlphaProgram.addPermutation("LOCAL_LIGHT_KILL", "1"); + } + + gDeferredAlphaProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + + success = gDeferredAlphaProgram.createShader(NULL, NULL); + llassert(success); + + // Hack + gDeferredAlphaProgram.mFeatures.calculatesLighting = true; + gDeferredAlphaProgram.mFeatures.hasLighting = true; + } - success = gDeferredAlphaProgram.createShader(NULL, NULL); - - // Hack - gDeferredAlphaProgram.mFeatures.calculatesLighting = true; - gDeferredAlphaProgram.mFeatures.hasLighting = true; - } - - if (success) - { - gDeferredAlphaImpostorProgram.mName = "Deferred Alpha Shader"; + if (success) + { + gDeferredAlphaImpostorProgram.mName = "Deferred Alpha Impostor Shader"; +// Begin Hack gDeferredAlphaImpostorProgram.mFeatures.calculatesLighting = false; gDeferredAlphaImpostorProgram.mFeatures.hasLighting = false; + + gDeferredAlphaImpostorProgram.mFeatures.hasSrgb = true; 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.mFeatures.encodesNormal = true; + gDeferredAlphaImpostorProgram.mFeatures.hasShadows = use_sun_shadow; - 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"); + if (mShaderLevel[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.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + 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)); - success = gDeferredAlphaImpostorProgram.createShader(NULL, NULL); + gDeferredAlphaImpostorProgram.clearPermutations(); + gDeferredAlphaImpostorProgram.addPermutation("USE_INDEXED_TEX", "1"); + gDeferredAlphaImpostorProgram.addPermutation("FOR_IMPOSTOR", "1"); + gDeferredAlphaImpostorProgram.addPermutation("USE_VERTEX_COLOR", "1"); - // Hack - gDeferredAlphaImpostorProgram.mFeatures.calculatesLighting = true; - gDeferredAlphaImpostorProgram.mFeatures.hasLighting = true; - } + if (use_sun_shadow) + { + gDeferredAlphaImpostorProgram.addPermutation("HAS_SHADOW", "1"); + } + + gDeferredAlphaImpostorProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + + success = gDeferredAlphaImpostorProgram.createShader(NULL, NULL); + llassert(success); + +// End Hack + gDeferredAlphaImpostorProgram.mFeatures.calculatesLighting = true; + gDeferredAlphaImpostorProgram.mFeatures.hasLighting = true; + } if (success) { @@ -1610,7 +2005,16 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() 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.hasWaterFog = true; + gDeferredAlphaWaterProgram.mFeatures.hasSrgb = true; + gDeferredAlphaWaterProgram.mFeatures.encodesNormal = true; + gDeferredAlphaWaterProgram.mFeatures.calculatesAtmospherics = true; + gDeferredAlphaWaterProgram.mFeatures.hasAtmospherics = true; + gDeferredAlphaWaterProgram.mFeatures.hasGamma = true; + gDeferredAlphaWaterProgram.mFeatures.hasTransport = true; + gDeferredAlphaWaterProgram.mFeatures.hasShadows = use_sun_shadow; + + if (mShaderLevel[SHADER_DEFERRED] < 1) { gDeferredAlphaWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; } @@ -1622,13 +2026,34 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() 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.clearPermutations(); 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]; + gDeferredAlphaWaterProgram.addPermutation("USE_VERTEX_COLOR", "1"); + if (use_sun_shadow) + { + gDeferredAlphaWaterProgram.addPermutation("HAS_SHADOW", "1"); + } + + if (ambient_kill) + { + gDeferredAlphaWaterProgram.addPermutation("AMBIENT_KILL", "1"); + } + + if (sunlight_kill) + { + gDeferredAlphaWaterProgram.addPermutation("SUNLIGHT_KILL", "1"); + } + + if (local_light_kill) + { + gDeferredAlphaWaterProgram.addPermutation("LOCAL_LIGHT_KILL", "1"); + } + gDeferredAlphaWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredAlphaWaterProgram.createShader(NULL, NULL); + llassert(success); // Hack gDeferredAlphaWaterProgram.mFeatures.calculatesLighting = true; @@ -1642,11 +2067,16 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarEyesProgram.mFeatures.hasGamma = true; gDeferredAvatarEyesProgram.mFeatures.hasTransport = true; gDeferredAvatarEyesProgram.mFeatures.disableTextureIndex = true; + gDeferredAvatarEyesProgram.mFeatures.hasSrgb = true; + gDeferredAvatarEyesProgram.mFeatures.encodesNormal = true; + gDeferredAvatarEyesProgram.mFeatures.hasShadows = true; + gDeferredAvatarEyesProgram.mShaderFiles.clear(); gDeferredAvatarEyesProgram.mShaderFiles.push_back(make_pair("deferred/avatarEyesV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredAvatarEyesProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredAvatarEyesProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredAvatarEyesProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredAvatarEyesProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -1655,12 +2085,14 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightProgram.mFeatures.calculatesAtmospherics = true; gDeferredFullbrightProgram.mFeatures.hasGamma = true; gDeferredFullbrightProgram.mFeatures.hasTransport = true; + gDeferredFullbrightProgram.mFeatures.hasSrgb = true; gDeferredFullbrightProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; gDeferredFullbrightProgram.mShaderFiles.clear(); gDeferredFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredFullbrightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredFullbrightProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -1669,13 +2101,15 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightAlphaMaskProgram.mFeatures.calculatesAtmospherics = true; gDeferredFullbrightAlphaMaskProgram.mFeatures.hasGamma = true; gDeferredFullbrightAlphaMaskProgram.mFeatures.hasTransport = true; + gDeferredFullbrightAlphaMaskProgram.mFeatures.hasSrgb = 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]; + gDeferredFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredFullbrightAlphaMaskProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -1684,14 +2118,17 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightWaterProgram.mFeatures.calculatesAtmospherics = true; gDeferredFullbrightWaterProgram.mFeatures.hasGamma = true; gDeferredFullbrightWaterProgram.mFeatures.hasTransport = true; + gDeferredFullbrightWaterProgram.mFeatures.hasWaterFog = true; + gDeferredFullbrightWaterProgram.mFeatures.hasSrgb = 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.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; gDeferredFullbrightWaterProgram.addPermutation("WATER_FOG","1"); success = gDeferredFullbrightWaterProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -1700,59 +2137,71 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.calculatesAtmospherics = true; gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasGamma = true; gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasTransport = true; + gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasWaterFog = true; + gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasSrgb = 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.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredFullbrightAlphaMaskWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("HAS_ALPHA_MASK","1"); gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("WATER_FOG","1"); success = gDeferredFullbrightAlphaMaskWaterProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredFullbrightShinyProgram.mName = "Deferred FullbrightShiny Shader"; gDeferredFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true; + gDeferredFullbrightShinyProgram.mFeatures.hasAtmospherics = true; gDeferredFullbrightShinyProgram.mFeatures.hasGamma = true; gDeferredFullbrightShinyProgram.mFeatures.hasTransport = true; + gDeferredFullbrightShinyProgram.mFeatures.hasSrgb = 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]; + gDeferredFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredFullbrightShinyProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredSkinnedFullbrightProgram.mName = "Skinned Fullbright Shader"; gDeferredSkinnedFullbrightProgram.mFeatures.calculatesAtmospherics = true; + gDeferredSkinnedFullbrightProgram.mFeatures.hasAtmospherics = true; gDeferredSkinnedFullbrightProgram.mFeatures.hasGamma = true; gDeferredSkinnedFullbrightProgram.mFeatures.hasTransport = true; gDeferredSkinnedFullbrightProgram.mFeatures.hasObjectSkinning = true; gDeferredSkinnedFullbrightProgram.mFeatures.disableTextureIndex = true; + gDeferredSkinnedFullbrightProgram.mFeatures.hasSrgb = 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]; + gDeferredSkinnedFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gDeferredSkinnedFullbrightProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredSkinnedFullbrightShinyProgram.mName = "Skinned Fullbright Shiny Shader"; gDeferredSkinnedFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true; + gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasAtmospherics = true; gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasGamma = true; gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasTransport = true; gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasObjectSkinning = true; gDeferredSkinnedFullbrightShinyProgram.mFeatures.disableTextureIndex = true; + gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasSrgb = 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]; + gDeferredSkinnedFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gDeferredSkinnedFullbrightShinyProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -1765,8 +2214,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredEmissiveProgram.mShaderFiles.clear(); gDeferredEmissiveProgram.mShaderFiles.push_back(make_pair("deferred/emissiveV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredEmissiveProgram.mShaderFiles.push_back(make_pair("deferred/emissiveF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredEmissiveProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredEmissiveProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredEmissiveProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -1776,11 +2226,16 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredWaterProgram.mFeatures.calculatesAtmospherics = true; gDeferredWaterProgram.mFeatures.hasGamma = true; gDeferredWaterProgram.mFeatures.hasTransport = true; + gDeferredWaterProgram.mFeatures.encodesNormal = true; + gDeferredWaterProgram.mFeatures.hasSrgb = 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]; + gDeferredWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + gDeferredWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gDeferredWaterProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -1788,23 +2243,54 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() // load water shader gDeferredUnderWaterProgram.mName = "Deferred Under Water Shader"; gDeferredUnderWaterProgram.mFeatures.calculatesAtmospherics = true; + gDeferredUnderWaterProgram.mFeatures.hasWaterFog = true; gDeferredUnderWaterProgram.mFeatures.hasGamma = true; gDeferredUnderWaterProgram.mFeatures.hasTransport = true; + gDeferredUnderWaterProgram.mFeatures.hasSrgb = true; + gDeferredUnderWaterProgram.mFeatures.encodesNormal = true; + //gDeferredUnderWaterProgram.mFeatures.hasShadows = 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]; + gDeferredUnderWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + gDeferredUnderWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gDeferredUnderWaterProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredSoftenProgram.mName = "Deferred Soften Shader"; gDeferredSoftenProgram.mShaderFiles.clear(); + gDeferredSoftenProgram.mFeatures.hasSrgb = true; + gDeferredSoftenProgram.mFeatures.calculatesAtmospherics = true; + gDeferredSoftenProgram.mFeatures.hasAtmospherics = true; + gDeferredSoftenProgram.mFeatures.hasTransport = true; + gDeferredSoftenProgram.mFeatures.hasGamma = true; + gDeferredSoftenProgram.mFeatures.isDeferred = true; + gDeferredSoftenProgram.mFeatures.hasShadows = use_sun_shadow; + + gDeferredSoftenProgram.clearPermutations(); gDeferredSoftenProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredSoftenProgram.mShaderFiles.push_back(make_pair("deferred/softenLightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredSoftenProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredSoftenProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + + if (ambient_kill) + { + gDeferredSoftenProgram.addPermutation("AMBIENT_KILL", "1"); + } + + if (sunlight_kill) + { + gDeferredSoftenProgram.addPermutation("SUNLIGHT_KILL", "1"); + } + + if (local_light_kill) + { + gDeferredSoftenProgram.addPermutation("LOCAL_LIGHT_KILL", "1"); + } if (gSavedSettings.getBOOL("RenderDeferredSSAO")) { //if using SSAO, take screen space light map into account as if shadows are enabled @@ -1812,6 +2298,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() } success = gDeferredSoftenProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -1821,9 +2308,33 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredSoftenWaterProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredSoftenWaterProgram.mShaderFiles.push_back(make_pair("deferred/softenLightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredSoftenWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredSoftenWaterProgram.clearPermutations(); + gDeferredSoftenWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredSoftenWaterProgram.addPermutation("WATER_FOG", "1"); gDeferredSoftenWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; + gDeferredSoftenWaterProgram.mFeatures.hasWaterFog = true; + gDeferredSoftenWaterProgram.mFeatures.hasSrgb = true; + gDeferredSoftenWaterProgram.mFeatures.calculatesAtmospherics = true; + gDeferredSoftenWaterProgram.mFeatures.hasAtmospherics = true; + gDeferredSoftenWaterProgram.mFeatures.hasTransport = true; + gDeferredSoftenWaterProgram.mFeatures.hasGamma = true; + gDeferredSoftenWaterProgram.mFeatures.isDeferred = true; + gDeferredSoftenWaterProgram.mFeatures.hasShadows = use_sun_shadow; + + if (ambient_kill) + { + gDeferredSoftenWaterProgram.addPermutation("AMBIENT_KILL", "1"); + } + + if (sunlight_kill) + { + gDeferredSoftenWaterProgram.addPermutation("SUNLIGHT_KILL", "1"); + } + + if (local_light_kill) + { + gDeferredSoftenWaterProgram.addPermutation("LOCAL_LIGHT_KILL", "1"); + } if (gSavedSettings.getBOOL("RenderDeferredSSAO")) { //if using SSAO, take screen space light map into account as if shadows are enabled @@ -1831,55 +2342,98 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() } success = gDeferredSoftenWaterProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredShadowProgram.mName = "Deferred Shadow Shader"; + gDeferredShadowProgram.mFeatures.isDeferred = true; + gDeferredShadowProgram.mFeatures.hasShadows = true; gDeferredShadowProgram.mShaderFiles.clear(); gDeferredShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; - gDeferredShadowProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0"); + gDeferredShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + if (gGLManager.mHasDepthClamp) + { + gDeferredShadowProgram.addPermutation("DEPTH_CLAMP", "1"); + } success = gDeferredShadowProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredShadowCubeProgram.mName = "Deferred Shadow Cube Shader"; + gDeferredShadowCubeProgram.mFeatures.isDeferred = true; + gDeferredShadowCubeProgram.mFeatures.hasShadows = true; gDeferredShadowCubeProgram.mShaderFiles.clear(); gDeferredShadowCubeProgram.mShaderFiles.push_back(make_pair("deferred/shadowCubeV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredShadowCubeProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredShadowCubeProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0"); - gDeferredShadowCubeProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + if (gGLManager.mHasDepthClamp) + { + gDeferredShadowCubeProgram.addPermutation("DEPTH_CLAMP", "1"); + } + gDeferredShadowCubeProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredShadowCubeProgram.createShader(NULL, NULL); + llassert(success); } if (success) { + gDeferredShadowFullbrightAlphaMaskProgram.mName = "Deferred Shadow Fullbright Alpha Mask Shader"; + gDeferredShadowFullbrightAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; + + gDeferredShadowFullbrightAlphaMaskProgram.mShaderFiles.clear(); + gDeferredShadowFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredShadowFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskF.glsl", GL_FRAGMENT_SHADER_ARB)); + + gDeferredShadowFullbrightAlphaMaskProgram.clearPermutations(); + if (gGLManager.mHasDepthClamp) + { + gDeferredShadowFullbrightAlphaMaskProgram.addPermutation("DEPTH_CLAMP", "1"); + } + gDeferredShadowFullbrightAlphaMaskProgram.addPermutation("IS_FULLBRIGHT", "1"); + gDeferredShadowFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + success = gDeferredShadowFullbrightAlphaMaskProgram.createShader(NULL, NULL); + llassert(success); + } + + if (success) + { gDeferredShadowAlphaMaskProgram.mName = "Deferred Shadow Alpha Mask Shader"; gDeferredShadowAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; + gDeferredShadowAlphaMaskProgram.mShaderFiles.clear(); gDeferredShadowAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredShadowAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredShadowAlphaMaskProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0"); - gDeferredShadowAlphaMaskProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + if (gGLManager.mHasDepthClamp) + { + gDeferredShadowAlphaMaskProgram.addPermutation("DEPTH_CLAMP", "1"); + } + gDeferredShadowAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredShadowAlphaMaskProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredAvatarShadowProgram.mName = "Deferred Avatar Shadow Shader"; gDeferredAvatarShadowProgram.mFeatures.hasSkinning = true; + gDeferredAvatarShadowProgram.mShaderFiles.clear(); 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.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0"); - gDeferredAvatarShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + if (gGLManager.mHasDepthClamp) + { + gDeferredAvatarShadowProgram.addPermutation("DEPTH_CLAMP", "1"); + } + gDeferredAvatarShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredAvatarShadowProgram.createShader(NULL, NULL); + llassert(success); } - if (success) + if (success) { gDeferredAvatarAlphaShadowProgram.mName = "Deferred Avatar Alpha Shadow Shader"; gDeferredAvatarAlphaShadowProgram.mFeatures.hasSkinning = true; @@ -1887,8 +2441,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarAlphaShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaShadowV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredAvatarAlphaShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaShadowF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredAvatarAlphaShadowProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0"); - gDeferredAvatarAlphaShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredAvatarAlphaShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredAvatarAlphaShadowProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -1899,23 +2454,29 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarAlphaMaskShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaShadowV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredAvatarAlphaMaskShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaMaskShadowF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredAvatarAlphaMaskShadowProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0"); - gDeferredAvatarAlphaMaskShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredAvatarAlphaMaskShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredAvatarAlphaMaskShadowProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredAttachmentShadowProgram.mName = "Deferred Attachment Shadow Shader"; gDeferredAttachmentShadowProgram.mFeatures.hasObjectSkinning = true; + gDeferredAttachmentShadowProgram.mShaderFiles.clear(); gDeferredAttachmentShadowProgram.mShaderFiles.push_back(make_pair("deferred/attachmentShadowV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredAttachmentShadowProgram.mShaderFiles.push_back(make_pair("deferred/attachmentShadowF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredAttachmentShadowProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0"); - gDeferredAttachmentShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + if (gGLManager.mHasDepthClamp) + { + gDeferredAttachmentShadowProgram.addPermutation("DEPTH_CLAMP", "1"); + } + gDeferredAttachmentShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredAttachmentShadowProgram.createShader(NULL, NULL); + llassert(success); } - - if (success) + + if (success) { gDeferredAttachmentAlphaShadowProgram.mName = "Deferred Attachment Alpha Shadow Shader"; gDeferredAttachmentAlphaShadowProgram.mFeatures.hasObjectSkinning = true; @@ -1923,8 +2484,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAttachmentAlphaShadowProgram.mShaderFiles.push_back(make_pair("deferred/attachmentAlphaShadowV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredAttachmentAlphaShadowProgram.mShaderFiles.push_back(make_pair("deferred/attachmentAlphaShadowF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredAttachmentAlphaShadowProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0"); - gDeferredAttachmentAlphaShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredAttachmentAlphaShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredAttachmentAlphaShadowProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -1935,29 +2497,70 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAttachmentAlphaMaskShadowProgram.mShaderFiles.push_back(make_pair("deferred/attachmentAlphaShadowV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredAttachmentAlphaMaskShadowProgram.mShaderFiles.push_back(make_pair("deferred/attachmentAlphaMaskShadowF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredAttachmentAlphaMaskShadowProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0"); - gDeferredAttachmentAlphaMaskShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredAttachmentAlphaMaskShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredAttachmentAlphaMaskShadowProgram.createShader(NULL, NULL); + llassert(success); } if (success) { - gTerrainProgram.mName = "Deferred Terrain Shader"; + gDeferredTerrainProgram.mName = "Deferred Terrain Shader"; + gDeferredTerrainProgram.mFeatures.encodesNormal = true; + gDeferredTerrainProgram.mFeatures.hasSrgb = true; + gDeferredTerrainProgram.mFeatures.calculatesLighting = false; + gDeferredTerrainProgram.mFeatures.hasLighting = false; + gDeferredTerrainProgram.mFeatures.isAlphaLighting = true; + gDeferredTerrainProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels + gDeferredTerrainProgram.mFeatures.hasWaterFog = true; + gDeferredTerrainProgram.mFeatures.calculatesAtmospherics = true; + gDeferredTerrainProgram.mFeatures.hasAtmospherics = true; + gDeferredTerrainProgram.mFeatures.hasGamma = true; + gDeferredTerrainProgram.mFeatures.hasTransport = true; + gDeferredTerrainProgram.mShaderFiles.clear(); 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, NULL); + gDeferredTerrainProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + success = gDeferredTerrainProgram.createShader(NULL, NULL); + llassert(success); + } + + if (success) + { + gDeferredTerrainWaterProgram.mName = "Deferred Terrain Underwater Shader"; + gDeferredTerrainWaterProgram.mFeatures.encodesNormal = true; + gDeferredTerrainWaterProgram.mFeatures.hasSrgb = true; + gDeferredTerrainWaterProgram.mFeatures.calculatesLighting = false; + gDeferredTerrainWaterProgram.mFeatures.hasLighting = false; + gDeferredTerrainWaterProgram.mFeatures.isAlphaLighting = true; + gDeferredTerrainWaterProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels + gDeferredTerrainWaterProgram.mFeatures.hasWaterFog = true; + gDeferredTerrainWaterProgram.mFeatures.calculatesAtmospherics = true; + gDeferredTerrainWaterProgram.mFeatures.hasAtmospherics = true; + gDeferredTerrainWaterProgram.mFeatures.hasGamma = true; + gDeferredTerrainWaterProgram.mFeatures.hasTransport = true; + + gDeferredTerrainWaterProgram.mShaderFiles.clear(); + gDeferredTerrainWaterProgram.mShaderFiles.push_back(make_pair("deferred/terrainV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredTerrainWaterProgram.mShaderFiles.push_back(make_pair("deferred/terrainF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredTerrainWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + gDeferredTerrainWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; + gDeferredTerrainWaterProgram.addPermutation("WATER_FOG", "1"); + success = gDeferredTerrainWaterProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredAvatarProgram.mName = "Avatar Shader"; gDeferredAvatarProgram.mFeatures.hasSkinning = true; + gDeferredAvatarProgram.mFeatures.encodesNormal = true; gDeferredAvatarProgram.mShaderFiles.clear(); 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]; + gDeferredAvatarProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredAvatarProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -1968,15 +2571,45 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarAlphaProgram.mFeatures.hasLighting = false; gDeferredAvatarAlphaProgram.mFeatures.isAlphaLighting = true; gDeferredAvatarAlphaProgram.mFeatures.disableTextureIndex = true; + gDeferredAvatarAlphaProgram.mFeatures.hasSrgb = true; + gDeferredAvatarAlphaProgram.mFeatures.encodesNormal = true; + gDeferredAvatarAlphaProgram.mFeatures.calculatesAtmospherics = true; + gDeferredAvatarAlphaProgram.mFeatures.hasAtmospherics = true; + gDeferredAvatarAlphaProgram.mFeatures.hasTransport = true; + gDeferredAvatarAlphaProgram.mFeatures.hasGamma = true; + gDeferredAvatarAlphaProgram.mFeatures.isDeferred = true; + gDeferredAvatarAlphaProgram.mFeatures.hasShadows = true; + gDeferredAvatarAlphaProgram.mShaderFiles.clear(); - 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.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.clearPermutations(); 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]; + if (use_sun_shadow) + { + gDeferredAvatarAlphaProgram.addPermutation("HAS_SHADOW", "1"); + } + + if (ambient_kill) + { + gDeferredAvatarAlphaProgram.addPermutation("AMBIENT_KILL", "1"); + } + + if (sunlight_kill) + { + gDeferredAvatarAlphaProgram.addPermutation("SUNLIGHT_KILL", "1"); + } + + if (local_light_kill) + { + gDeferredAvatarAlphaProgram.addPermutation("LOCAL_LIGHT_KILL", "1"); + } + gDeferredAvatarAlphaProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredAvatarAlphaProgram.createShader(NULL, NULL); + llassert(success); gDeferredAvatarAlphaProgram.mFeatures.calculatesLighting = true; gDeferredAvatarAlphaProgram.mFeatures.hasLighting = true; @@ -1985,95 +2618,160 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredPostGammaCorrectProgram.mName = "Deferred Gamma Correction Post Process"; + gDeferredPostGammaCorrectProgram.mFeatures.hasSrgb = true; + gDeferredPostGammaCorrectProgram.mFeatures.isDeferred = true; gDeferredPostGammaCorrectProgram.mShaderFiles.clear(); gDeferredPostGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredPostGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredGammaCorrect.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredPostGammaCorrectProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredPostGammaCorrectProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredPostGammaCorrectProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gFXAAProgram.mName = "FXAA Shader"; + gFXAAProgram.mFeatures.isDeferred = true; gFXAAProgram.mShaderFiles.clear(); gFXAAProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredV.glsl", GL_VERTEX_SHADER_ARB)); gFXAAProgram.mShaderFiles.push_back(make_pair("deferred/fxaaF.glsl", GL_FRAGMENT_SHADER_ARB)); - gFXAAProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gFXAAProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gFXAAProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredPostProgram.mName = "Deferred Post Shader"; + gFXAAProgram.mFeatures.isDeferred = true; gDeferredPostProgram.mShaderFiles.clear(); gDeferredPostProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredPostProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredPostProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredPostProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredPostProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredCoFProgram.mName = "Deferred CoF Shader"; gDeferredCoFProgram.mShaderFiles.clear(); + gDeferredCoFProgram.mFeatures.isDeferred = true; gDeferredCoFProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredCoFProgram.mShaderFiles.push_back(make_pair("deferred/cofF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredCoFProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredCoFProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredCoFProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredDoFCombineProgram.mName = "Deferred DoFCombine Shader"; + gDeferredDoFCombineProgram.mFeatures.isDeferred = true; gDeferredDoFCombineProgram.mShaderFiles.clear(); gDeferredDoFCombineProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredDoFCombineProgram.mShaderFiles.push_back(make_pair("deferred/dofCombineF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredDoFCombineProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredDoFCombineProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredDoFCombineProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredPostNoDoFProgram.mName = "Deferred Post Shader"; + gDeferredPostNoDoFProgram.mFeatures.isDeferred = true; gDeferredPostNoDoFProgram.mShaderFiles.clear(); gDeferredPostNoDoFProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredPostNoDoFProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoDoFF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredPostNoDoFProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredPostNoDoFProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredPostNoDoFProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredWLSkyProgram.mName = "Deferred Windlight Sky Shader"; - //gWLSkyProgram.mFeatures.hasGamma = true; gDeferredWLSkyProgram.mShaderFiles.clear(); + gDeferredWLSkyProgram.mFeatures.calculatesAtmospherics = true; + gDeferredWLSkyProgram.mFeatures.hasTransport = true; + gDeferredWLSkyProgram.mFeatures.hasGamma = true; + gDeferredWLSkyProgram.mFeatures.hasSrgb = true; + gDeferredWLSkyProgram.mShaderFiles.push_back(make_pair("deferred/skyV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredWLSkyProgram.mShaderFiles.push_back(make_pair("deferred/skyF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredWLSkyProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredWLSkyProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredWLSkyProgram.mShaderGroup = LLGLSLShader::SG_SKY; + success = gDeferredWLSkyProgram.createShader(NULL, NULL); + llassert(success); } if (success) { gDeferredWLCloudProgram.mName = "Deferred Windlight Cloud Program"; gDeferredWLCloudProgram.mShaderFiles.clear(); + gDeferredWLCloudProgram.mFeatures.calculatesAtmospherics = true; + gDeferredWLCloudProgram.mFeatures.hasTransport = true; + gDeferredWLCloudProgram.mFeatures.hasGamma = true; + gDeferredWLCloudProgram.mFeatures.hasSrgb = true; + gDeferredWLCloudProgram.mShaderFiles.push_back(make_pair("deferred/cloudsV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredWLCloudProgram.mShaderFiles.push_back(make_pair("deferred/cloudsF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredWLCloudProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredWLCloudProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredWLCloudProgram.mShaderGroup = LLGLSLShader::SG_SKY; success = gDeferredWLCloudProgram.createShader(NULL, NULL); + llassert(success); } if (success) { + gDeferredWLSunProgram.mName = "Deferred Windlight Sun Program"; + gDeferredWLSunProgram.mFeatures.calculatesAtmospherics = true; + gDeferredWLSunProgram.mFeatures.hasTransport = true; + gDeferredWLSunProgram.mFeatures.hasGamma = true; + gDeferredWLSunProgram.mFeatures.hasAtmospherics = true; + gDeferredWLSunProgram.mFeatures.isFullbright = true; + gDeferredWLSunProgram.mFeatures.disableTextureIndex = true; + gDeferredWLSunProgram.mFeatures.hasSrgb = true; + gDeferredWLSunProgram.mShaderFiles.clear(); + gDeferredWLSunProgram.mShaderFiles.push_back(make_pair("deferred/sunDiscV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredWLSunProgram.mShaderFiles.push_back(make_pair("deferred/sunDiscF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredWLSunProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + gDeferredWLSunProgram.mShaderGroup = LLGLSLShader::SG_SKY; + success = gDeferredWLSunProgram.createShader(NULL, NULL); + llassert(success); + } + + if (success) + { + gDeferredWLMoonProgram.mName = "Deferred Windlight Moon Program"; + gDeferredWLMoonProgram.mFeatures.calculatesAtmospherics = true; + gDeferredWLMoonProgram.mFeatures.hasTransport = true; + gDeferredWLMoonProgram.mFeatures.hasGamma = true; + gDeferredWLMoonProgram.mFeatures.hasAtmospherics = true; + gDeferredWLMoonProgram.mFeatures.hasSrgb = true; + gDeferredWLMoonProgram.mFeatures.isFullbright = true; + gDeferredWLMoonProgram.mFeatures.disableTextureIndex = true; + + gDeferredWLMoonProgram.mShaderFiles.clear(); + gDeferredWLMoonProgram.mShaderFiles.push_back(make_pair("deferred/moonV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredWLMoonProgram.mShaderFiles.push_back(make_pair("deferred/moonF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredWLMoonProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + gDeferredWLMoonProgram.mShaderGroup = LLGLSLShader::SG_SKY; + success = gDeferredWLMoonProgram.createShader(NULL, NULL); + llassert(success); + } + + if (success) + { gDeferredStarProgram.mName = "Deferred Star Program"; 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)); - gDeferredStarProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredStarProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredStarProgram.mShaderGroup = LLGLSLShader::SG_SKY; success = gDeferredStarProgram.createShader(NULL, NULL); + llassert(success); } if (success) @@ -2082,7 +2780,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gNormalMapGenProgram.mShaderFiles.clear(); gNormalMapGenProgram.mShaderFiles.push_back(make_pair("deferred/normgenV.glsl", GL_VERTEX_SHADER_ARB)); gNormalMapGenProgram.mShaderFiles.push_back(make_pair("deferred/normgenF.glsl", GL_FRAGMENT_SHADER_ARB)); - gNormalMapGenProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gNormalMapGenProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gNormalMapGenProgram.mShaderGroup = LLGLSLShader::SG_SKY; success = gNormalMapGenProgram.createShader(NULL, NULL); } @@ -2094,7 +2792,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() { BOOL success = TRUE; - if (mVertexShaderLevel[SHADER_OBJECT] == 0) + if (mShaderLevel[SHADER_OBJECT] == 0) { gObjectShinyProgram.unload(); gObjectFullbrightShinyProgram.unload(); @@ -2155,12 +2853,12 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectSimpleNonIndexedProgram.mFeatures.hasGamma = true; gObjectSimpleNonIndexedProgram.mFeatures.hasAtmospherics = true; gObjectSimpleNonIndexedProgram.mFeatures.hasLighting = true; + gObjectSimpleNonIndexedProgram.mFeatures.hasAlphaMask = true; // Fix for MAINT-8836 gObjectSimpleNonIndexedProgram.mFeatures.disableTextureIndex = true; - gObjectSimpleNonIndexedProgram.mFeatures.hasAlphaMask = 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]; + gObjectSimpleNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectSimpleNonIndexedProgram.createShader(NULL, NULL); } @@ -2176,7 +2874,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectSimpleNonIndexedTexGenProgram.mShaderFiles.clear(); gObjectSimpleNonIndexedTexGenProgram.mShaderFiles.push_back(make_pair("objects/simpleTexGenV.glsl", GL_VERTEX_SHADER_ARB)); gObjectSimpleNonIndexedTexGenProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectSimpleNonIndexedTexGenProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectSimpleNonIndexedTexGenProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectSimpleNonIndexedTexGenProgram.createShader(NULL, NULL); } @@ -2193,7 +2891,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectSimpleNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gObjectSimpleNonIndexedWaterProgram.createShader(NULL, NULL); } @@ -2210,7 +2908,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectSimpleNonIndexedTexGenWaterProgram.mShaderFiles.clear(); gObjectSimpleNonIndexedTexGenWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleTexGenV.glsl", GL_VERTEX_SHADER_ARB)); gObjectSimpleNonIndexedTexGenWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectSimpleNonIndexedTexGenWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectSimpleNonIndexedTexGenWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectSimpleNonIndexedTexGenWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gObjectSimpleNonIndexedTexGenWaterProgram.createShader(NULL, NULL); } @@ -2228,7 +2926,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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]; + gObjectAlphaMaskNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectAlphaMaskNonIndexedProgram.createShader(NULL, NULL); } @@ -2245,7 +2943,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectAlphaMaskNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gObjectAlphaMaskNonIndexedWaterProgram.createShader(NULL, NULL); } @@ -2263,7 +2961,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectAlphaMaskNoColorProgram.mShaderFiles.clear(); gObjectAlphaMaskNoColorProgram.mShaderFiles.push_back(make_pair("objects/simpleNoColorV.glsl", GL_VERTEX_SHADER_ARB)); gObjectAlphaMaskNoColorProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectAlphaMaskNoColorProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectAlphaMaskNoColorProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectAlphaMaskNoColorProgram.createShader(NULL, NULL); } @@ -2280,7 +2978,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectAlphaMaskNoColorWaterProgram.mShaderFiles.clear(); gObjectAlphaMaskNoColorWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleNoColorV.glsl", GL_VERTEX_SHADER_ARB)); gObjectAlphaMaskNoColorWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectAlphaMaskNoColorWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectAlphaMaskNoColorWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectAlphaMaskNoColorWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gObjectAlphaMaskNoColorWaterProgram.createShader(NULL, NULL); } @@ -2298,7 +2996,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gTreeProgram.mShaderFiles.clear(); gTreeProgram.mShaderFiles.push_back(make_pair("objects/treeV.glsl", GL_VERTEX_SHADER_ARB)); gTreeProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB)); - gTreeProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gTreeProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gTreeProgram.createShader(NULL, NULL); } @@ -2315,7 +3013,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gTreeWaterProgram.mShaderFiles.clear(); gTreeWaterProgram.mShaderFiles.push_back(make_pair("objects/treeV.glsl", GL_VERTEX_SHADER_ARB)); gTreeWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gTreeWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gTreeWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gTreeWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gTreeWaterProgram.createShader(NULL, NULL); } @@ -2331,7 +3029,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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]; + gObjectFullbrightNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectFullbrightNonIndexedProgram.createShader(NULL, NULL); } @@ -2343,10 +3041,11 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectFullbrightNonIndexedWaterProgram.mFeatures.hasWaterFog = true; gObjectFullbrightNonIndexedWaterProgram.mFeatures.hasTransport = true; gObjectFullbrightNonIndexedWaterProgram.mFeatures.disableTextureIndex = true; + gObjectFullbrightNonIndexedWaterProgram.mFeatures.hasSrgb = 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.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectFullbrightNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gObjectFullbrightNonIndexedWaterProgram.createShader(NULL, NULL); } @@ -2359,10 +3058,11 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectEmissiveNonIndexedProgram.mFeatures.hasTransport = true; gObjectEmissiveNonIndexedProgram.mFeatures.isFullbright = true; gObjectEmissiveNonIndexedProgram.mFeatures.disableTextureIndex = true; + gObjectEmissiveNonIndexedProgram.mFeatures.hasSrgb = 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]; + gObjectEmissiveNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectEmissiveNonIndexedProgram.createShader(NULL, NULL); } @@ -2377,7 +3077,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectEmissiveNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gObjectEmissiveNonIndexedWaterProgram.createShader(NULL, NULL); } @@ -2389,11 +3089,12 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectFullbrightNoColorProgram.mFeatures.hasGamma = true; gObjectFullbrightNoColorProgram.mFeatures.hasTransport = true; gObjectFullbrightNoColorProgram.mFeatures.isFullbright = true; + gObjectFullbrightNoColorProgram.mFeatures.hasSrgb = true; gObjectFullbrightNoColorProgram.mFeatures.disableTextureIndex = true; gObjectFullbrightNoColorProgram.mShaderFiles.clear(); gObjectFullbrightNoColorProgram.mShaderFiles.push_back(make_pair("objects/fullbrightNoColorV.glsl", GL_VERTEX_SHADER_ARB)); gObjectFullbrightNoColorProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectFullbrightNoColorProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectFullbrightNoColorProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectFullbrightNoColorProgram.createShader(NULL, NULL); } @@ -2408,7 +3109,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectFullbrightNoColorWaterProgram.mShaderFiles.clear(); gObjectFullbrightNoColorWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightNoColorV.glsl", GL_VERTEX_SHADER_ARB)); gObjectFullbrightNoColorWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectFullbrightNoColorWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectFullbrightNoColorWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectFullbrightNoColorWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gObjectFullbrightNoColorWaterProgram.createShader(NULL, NULL); } @@ -2425,7 +3126,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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]; + gObjectShinyNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectShinyNonIndexedProgram.createShader(NULL, NULL); } @@ -2441,12 +3142,12 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectShinyNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gObjectShinyNonIndexedWaterProgram.createShader(NULL, NULL); } - if (success) + if (success) { gObjectFullbrightShinyNonIndexedProgram.mName = "Non Indexed Fullbright Shiny Shader"; gObjectFullbrightShinyNonIndexedProgram.mFeatures.calculatesAtmospherics = true; @@ -2458,7 +3159,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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]; + gObjectFullbrightShinyNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectFullbrightShinyNonIndexedProgram.createShader(NULL, NULL); } @@ -2475,7 +3176,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectFullbrightShinyNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gObjectFullbrightShinyNonIndexedWaterProgram.createShader(NULL, NULL); } @@ -2484,10 +3185,11 @@ BOOL LLViewerShaderMgr::loadShadersObject() { gImpostorProgram.mName = "Impostor Shader"; gImpostorProgram.mFeatures.disableTextureIndex = true; + gImpostorProgram.mFeatures.hasSrgb = true; gImpostorProgram.mShaderFiles.clear(); gImpostorProgram.mShaderFiles.push_back(make_pair("objects/impostorV.glsl", GL_VERTEX_SHADER_ARB)); gImpostorProgram.mShaderFiles.push_back(make_pair("objects/impostorF.glsl", GL_FRAGMENT_SHADER_ARB)); - gImpostorProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gImpostorProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gImpostorProgram.createShader(NULL, NULL); } @@ -2504,7 +3206,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectPreviewProgram.mShaderFiles.clear(); gObjectPreviewProgram.mShaderFiles.push_back(make_pair("objects/previewV.glsl", GL_VERTEX_SHADER_ARB)); gObjectPreviewProgram.mShaderFiles.push_back(make_pair("objects/previewF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectPreviewProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectPreviewProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectPreviewProgram.createShader(NULL, NULL); gObjectPreviewProgram.mFeatures.hasLighting = true; } @@ -2521,7 +3223,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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]; + gObjectSimpleProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectSimpleProgram.createShader(NULL, NULL); } @@ -2541,7 +3243,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectSimpleImpostorProgram.mShaderFiles.clear(); gObjectSimpleImpostorProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB)); gObjectSimpleImpostorProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectSimpleImpostorProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectSimpleImpostorProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectSimpleImpostorProgram.createShader(NULL, NULL); } @@ -2558,7 +3260,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectSimpleWaterProgram.mShaderFiles.clear(); gObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB)); gObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectSimpleWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectSimpleWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectSimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gObjectSimpleWaterProgram.createShader(NULL, NULL); } @@ -2572,10 +3274,11 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectBumpProgram.mFeatures.hasAtmospherics = true; gObjectBumpProgram.mFeatures.hasLighting = true; gObjectBumpProgram.mFeatures.mIndexedTextureChannels = 0;*/ + gObjectBumpProgram.mFeatures.encodesNormal = true; gObjectBumpProgram.mShaderFiles.clear(); gObjectBumpProgram.mShaderFiles.push_back(make_pair("objects/bumpV.glsl", GL_VERTEX_SHADER_ARB)); gObjectBumpProgram.mShaderFiles.push_back(make_pair("objects/bumpF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectBumpProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectBumpProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectBumpProgram.createShader(NULL, NULL); if (success) { //lldrawpoolbump assumes "texture0" has channel 0 and "texture1" has channel 1 @@ -2600,7 +3303,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectSimpleAlphaMaskProgram.mShaderFiles.clear(); gObjectSimpleAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB)); gObjectSimpleAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectSimpleAlphaMaskProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectSimpleAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectSimpleAlphaMaskProgram.createShader(NULL, NULL); } @@ -2617,7 +3320,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectSimpleWaterAlphaMaskProgram.mShaderFiles.clear(); gObjectSimpleWaterAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB)); gObjectSimpleWaterAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectSimpleWaterAlphaMaskProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectSimpleWaterAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectSimpleWaterAlphaMaskProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gObjectSimpleWaterAlphaMaskProgram.createShader(NULL, NULL); } @@ -2629,11 +3332,12 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectFullbrightProgram.mFeatures.hasGamma = true; gObjectFullbrightProgram.mFeatures.hasTransport = true; gObjectFullbrightProgram.mFeatures.isFullbright = true; + gObjectFullbrightProgram.mFeatures.hasSrgb = true; gObjectFullbrightProgram.mFeatures.mIndexedTextureChannels = 0; gObjectFullbrightProgram.mShaderFiles.clear(); gObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB)); gObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectFullbrightProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectFullbrightProgram.createShader(NULL, NULL); } @@ -2648,7 +3352,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectFullbrightWaterProgram.mShaderFiles.clear(); gObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB)); gObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectFullbrightWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectFullbrightWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gObjectFullbrightWaterProgram.createShader(NULL, NULL); } @@ -2660,11 +3364,12 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectEmissiveProgram.mFeatures.hasGamma = true; gObjectEmissiveProgram.mFeatures.hasTransport = true; gObjectEmissiveProgram.mFeatures.isFullbright = true; + gObjectEmissiveProgram.mFeatures.hasSrgb = true; gObjectEmissiveProgram.mFeatures.mIndexedTextureChannels = 0; gObjectEmissiveProgram.mShaderFiles.clear(); gObjectEmissiveProgram.mShaderFiles.push_back(make_pair("objects/emissiveV.glsl", GL_VERTEX_SHADER_ARB)); gObjectEmissiveProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectEmissiveProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectEmissiveProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectEmissiveProgram.createShader(NULL, NULL); } @@ -2679,7 +3384,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectEmissiveWaterProgram.mShaderFiles.clear(); gObjectEmissiveWaterProgram.mShaderFiles.push_back(make_pair("objects/emissiveV.glsl", GL_VERTEX_SHADER_ARB)); gObjectEmissiveWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectEmissiveWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectEmissiveWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectEmissiveWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gObjectEmissiveWaterProgram.createShader(NULL, NULL); } @@ -2692,11 +3397,12 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectFullbrightAlphaMaskProgram.mFeatures.hasTransport = true; gObjectFullbrightAlphaMaskProgram.mFeatures.isFullbright = true; gObjectFullbrightAlphaMaskProgram.mFeatures.hasAlphaMask = true; + gObjectFullbrightAlphaMaskProgram.mFeatures.hasSrgb = true; gObjectFullbrightAlphaMaskProgram.mFeatures.mIndexedTextureChannels = 0; gObjectFullbrightAlphaMaskProgram.mShaderFiles.clear(); gObjectFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB)); gObjectFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectFullbrightAlphaMaskProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectFullbrightAlphaMaskProgram.createShader(NULL, NULL); } @@ -2712,7 +3418,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectFullbrightWaterAlphaMaskProgram.mShaderFiles.clear(); gObjectFullbrightWaterAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB)); gObjectFullbrightWaterAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectFullbrightWaterAlphaMaskProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectFullbrightWaterAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectFullbrightWaterAlphaMaskProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gObjectFullbrightWaterAlphaMaskProgram.createShader(NULL, NULL); } @@ -2729,7 +3435,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectShinyProgram.mShaderFiles.clear(); gObjectShinyProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB)); gObjectShinyProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectShinyProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectShinyProgram.createShader(NULL, NULL); } @@ -2745,7 +3451,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectShinyWaterProgram.mShaderFiles.clear(); gObjectShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectShinyWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectShinyWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gObjectShinyWaterProgram.createShader(NULL, NULL); } @@ -2762,7 +3468,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectFullbrightShinyProgram.mShaderFiles.clear(); gObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB)); gObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectFullbrightShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gObjectFullbrightShinyProgram.createShader(NULL, NULL); } @@ -2779,12 +3485,12 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectFullbrightShinyWaterProgram.mShaderFiles.clear(); gObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB)); gObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectFullbrightShinyWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + gObjectFullbrightShinyWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectFullbrightShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gObjectFullbrightShinyWaterProgram.createShader(NULL, NULL); } - if (mVertexShaderLevel[SHADER_AVATAR] > 0) + if (mShaderLevel[SHADER_AVATAR] > 0) { //load hardware skinned attachment shaders if (success) { @@ -2800,7 +3506,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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]; + gSkinnedObjectSimpleProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gSkinnedObjectSimpleProgram.createShader(NULL, NULL); } @@ -2814,10 +3520,11 @@ BOOL LLViewerShaderMgr::loadShadersObject() gSkinnedObjectFullbrightProgram.mFeatures.hasObjectSkinning = true; gSkinnedObjectFullbrightProgram.mFeatures.hasAlphaMask = true; gSkinnedObjectFullbrightProgram.mFeatures.disableTextureIndex = true; + gSkinnedObjectFullbrightProgram.mFeatures.hasSrgb = 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]; + gSkinnedObjectFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gSkinnedObjectFullbrightProgram.createShader(NULL, NULL); } @@ -2830,10 +3537,11 @@ BOOL LLViewerShaderMgr::loadShadersObject() gSkinnedObjectEmissiveProgram.mFeatures.isFullbright = true; gSkinnedObjectEmissiveProgram.mFeatures.hasObjectSkinning = true; gSkinnedObjectEmissiveProgram.mFeatures.disableTextureIndex = true; + gSkinnedObjectEmissiveProgram.mFeatures.hasSrgb = 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]; + gSkinnedObjectEmissiveProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gSkinnedObjectEmissiveProgram.createShader(NULL, NULL); } @@ -2850,7 +3558,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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]; + gSkinnedObjectEmissiveWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gSkinnedObjectEmissiveWaterProgram.createShader(NULL, NULL); } @@ -2868,7 +3576,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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]; + gSkinnedObjectFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gSkinnedObjectFullbrightShinyProgram.createShader(NULL, NULL); } @@ -2886,7 +3594,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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]; + gSkinnedObjectShinySimpleProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gSkinnedObjectShinySimpleProgram.createShader(NULL, NULL); } @@ -2907,7 +3615,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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]; + gSkinnedObjectSimpleWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gSkinnedObjectSimpleWaterProgram.createShader(NULL, NULL); } @@ -2926,7 +3634,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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]; + gSkinnedObjectFullbrightWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gSkinnedObjectFullbrightWaterProgram.createShader(NULL, NULL); } @@ -2946,7 +3654,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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]; + gSkinnedObjectFullbrightShinyWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gSkinnedObjectFullbrightShinyWaterProgram.createShader(NULL, NULL); } @@ -2966,14 +3674,14 @@ BOOL LLViewerShaderMgr::loadShadersObject() 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]; + gSkinnedObjectShinySimpleWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = gSkinnedObjectShinySimpleWaterProgram.createShader(NULL, NULL); } } if( !success ) { - mVertexShaderLevel[SHADER_OBJECT] = 0; + mShaderLevel[SHADER_OBJECT] = 0; return FALSE; } @@ -2984,7 +3692,7 @@ BOOL LLViewerShaderMgr::loadShadersAvatar() { BOOL success = TRUE; - if (mVertexShaderLevel[SHADER_AVATAR] == 0) + if (mShaderLevel[SHADER_AVATAR] == 0) { gAvatarProgram.unload(); gAvatarWaterProgram.unload(); @@ -3007,7 +3715,7 @@ BOOL LLViewerShaderMgr::loadShadersAvatar() gAvatarProgram.mShaderFiles.clear(); 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]; + gAvatarProgram.mShaderLevel = mShaderLevel[SHADER_AVATAR]; success = gAvatarProgram.createShader(NULL, NULL); if (success) @@ -3025,15 +3733,15 @@ BOOL LLViewerShaderMgr::loadShadersAvatar() gAvatarWaterProgram.mShaderFiles.push_back(make_pair("avatar/avatarV.glsl", GL_VERTEX_SHADER_ARB)); gAvatarWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); // Note: no cloth under water: - gAvatarWaterProgram.mShaderLevel = llmin(mVertexShaderLevel[SHADER_AVATAR], 1); + gAvatarWaterProgram.mShaderLevel = llmin(mShaderLevel[SHADER_AVATAR], 1); gAvatarWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; success = gAvatarWaterProgram.createShader(NULL, NULL); } /// Keep track of avatar levels - if (gAvatarProgram.mShaderLevel != mVertexShaderLevel[SHADER_AVATAR]) + if (gAvatarProgram.mShaderLevel != mShaderLevel[SHADER_AVATAR]) { - mMaxAvatarShaderLevel = mVertexShaderLevel[SHADER_AVATAR] = gAvatarProgram.mShaderLevel; + mMaxAvatarShaderLevel = mShaderLevel[SHADER_AVATAR] = gAvatarProgram.mShaderLevel; } } @@ -3045,7 +3753,7 @@ BOOL LLViewerShaderMgr::loadShadersAvatar() 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]; + gAvatarPickProgram.mShaderLevel = mShaderLevel[SHADER_AVATAR]; success = gAvatarPickProgram.createShader(NULL, NULL); } @@ -3063,13 +3771,13 @@ BOOL LLViewerShaderMgr::loadShadersAvatar() 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]; + gAvatarEyeballProgram.mShaderLevel = mShaderLevel[SHADER_AVATAR]; success = gAvatarEyeballProgram.createShader(NULL, NULL); } if( !success ) { - mVertexShaderLevel[SHADER_AVATAR] = 0; + mShaderLevel[SHADER_AVATAR] = 0; mMaxAvatarShaderLevel = 0; return FALSE; } @@ -3081,7 +3789,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() { BOOL success = TRUE; - if (mVertexShaderLevel[SHADER_INTERFACE] == 0) + if (mShaderLevel[SHADER_INTERFACE] == 0) { gHighlightProgram.unload(); return TRUE; @@ -3093,7 +3801,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gHighlightProgram.mShaderFiles.clear(); gHighlightProgram.mShaderFiles.push_back(make_pair("interface/highlightV.glsl", GL_VERTEX_SHADER_ARB)); gHighlightProgram.mShaderFiles.push_back(make_pair("interface/highlightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gHighlightProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gHighlightProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gHighlightProgram.createShader(NULL, NULL); } @@ -3103,7 +3811,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() 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]; + gHighlightNormalProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gHighlightNormalProgram.createShader(NULL, NULL); } @@ -3113,7 +3821,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() 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]; + gHighlightSpecularProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gHighlightSpecularProgram.createShader(NULL, NULL); } @@ -3123,7 +3831,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gUIProgram.mShaderFiles.clear(); gUIProgram.mShaderFiles.push_back(make_pair("interface/uiV.glsl", GL_VERTEX_SHADER_ARB)); gUIProgram.mShaderFiles.push_back(make_pair("interface/uiF.glsl", GL_FRAGMENT_SHADER_ARB)); - gUIProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gUIProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gUIProgram.createShader(NULL, NULL); } @@ -3133,7 +3841,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gPathfindingProgram.mShaderFiles.clear(); gPathfindingProgram.mShaderFiles.push_back(make_pair("interface/pathfindingV.glsl", GL_VERTEX_SHADER_ARB)); gPathfindingProgram.mShaderFiles.push_back(make_pair("interface/pathfindingF.glsl", GL_FRAGMENT_SHADER_ARB)); - gPathfindingProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gPathfindingProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gPathfindingProgram.createShader(NULL, NULL); } @@ -3143,7 +3851,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gPathfindingNoNormalsProgram.mShaderFiles.clear(); gPathfindingNoNormalsProgram.mShaderFiles.push_back(make_pair("interface/pathfindingNoNormalV.glsl", GL_VERTEX_SHADER_ARB)); gPathfindingNoNormalsProgram.mShaderFiles.push_back(make_pair("interface/pathfindingF.glsl", GL_FRAGMENT_SHADER_ARB)); - gPathfindingNoNormalsProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gPathfindingNoNormalsProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gPathfindingNoNormalsProgram.createShader(NULL, NULL); } @@ -3153,7 +3861,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gCustomAlphaProgram.mShaderFiles.clear(); gCustomAlphaProgram.mShaderFiles.push_back(make_pair("interface/customalphaV.glsl", GL_VERTEX_SHADER_ARB)); gCustomAlphaProgram.mShaderFiles.push_back(make_pair("interface/customalphaF.glsl", GL_FRAGMENT_SHADER_ARB)); - gCustomAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gCustomAlphaProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gCustomAlphaProgram.createShader(NULL, NULL); } @@ -3163,7 +3871,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gSplatTextureRectProgram.mShaderFiles.clear(); gSplatTextureRectProgram.mShaderFiles.push_back(make_pair("interface/splattexturerectV.glsl", GL_VERTEX_SHADER_ARB)); gSplatTextureRectProgram.mShaderFiles.push_back(make_pair("interface/splattexturerectF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSplatTextureRectProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gSplatTextureRectProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gSplatTextureRectProgram.createShader(NULL, NULL); if (success) { @@ -3179,7 +3887,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gGlowCombineProgram.mShaderFiles.clear(); gGlowCombineProgram.mShaderFiles.push_back(make_pair("interface/glowcombineV.glsl", GL_VERTEX_SHADER_ARB)); gGlowCombineProgram.mShaderFiles.push_back(make_pair("interface/glowcombineF.glsl", GL_FRAGMENT_SHADER_ARB)); - gGlowCombineProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gGlowCombineProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gGlowCombineProgram.createShader(NULL, NULL); if (success) { @@ -3196,7 +3904,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gGlowCombineFXAAProgram.mShaderFiles.clear(); gGlowCombineFXAAProgram.mShaderFiles.push_back(make_pair("interface/glowcombineFXAAV.glsl", GL_VERTEX_SHADER_ARB)); gGlowCombineFXAAProgram.mShaderFiles.push_back(make_pair("interface/glowcombineFXAAF.glsl", GL_FRAGMENT_SHADER_ARB)); - gGlowCombineFXAAProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gGlowCombineFXAAProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gGlowCombineFXAAProgram.createShader(NULL, NULL); if (success) { @@ -3214,7 +3922,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gTwoTextureAddProgram.mShaderFiles.clear(); gTwoTextureAddProgram.mShaderFiles.push_back(make_pair("interface/twotextureaddV.glsl", GL_VERTEX_SHADER_ARB)); gTwoTextureAddProgram.mShaderFiles.push_back(make_pair("interface/twotextureaddF.glsl", GL_FRAGMENT_SHADER_ARB)); - gTwoTextureAddProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gTwoTextureAddProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gTwoTextureAddProgram.createShader(NULL, NULL); if (success) { @@ -3231,7 +3939,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gTwoTextureCompareProgram.mShaderFiles.clear(); gTwoTextureCompareProgram.mShaderFiles.push_back(make_pair("interface/twotexturecompareV.glsl", GL_VERTEX_SHADER_ARB)); gTwoTextureCompareProgram.mShaderFiles.push_back(make_pair("interface/twotexturecompareF.glsl", GL_FRAGMENT_SHADER_ARB)); - gTwoTextureCompareProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gTwoTextureCompareProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gTwoTextureCompareProgram.createShader(NULL, NULL); if (success) { @@ -3248,7 +3956,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gOneTextureFilterProgram.mShaderFiles.clear(); gOneTextureFilterProgram.mShaderFiles.push_back(make_pair("interface/onetexturefilterV.glsl", GL_VERTEX_SHADER_ARB)); gOneTextureFilterProgram.mShaderFiles.push_back(make_pair("interface/onetexturefilterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gOneTextureFilterProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gOneTextureFilterProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gOneTextureFilterProgram.createShader(NULL, NULL); if (success) { @@ -3264,7 +3972,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gOneTextureNoColorProgram.mShaderFiles.clear(); gOneTextureNoColorProgram.mShaderFiles.push_back(make_pair("interface/onetexturenocolorV.glsl", GL_VERTEX_SHADER_ARB)); gOneTextureNoColorProgram.mShaderFiles.push_back(make_pair("interface/onetexturenocolorF.glsl", GL_FRAGMENT_SHADER_ARB)); - gOneTextureNoColorProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gOneTextureNoColorProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gOneTextureNoColorProgram.createShader(NULL, NULL); if (success) { @@ -3279,7 +3987,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gSolidColorProgram.mShaderFiles.clear(); gSolidColorProgram.mShaderFiles.push_back(make_pair("interface/solidcolorV.glsl", GL_VERTEX_SHADER_ARB)); gSolidColorProgram.mShaderFiles.push_back(make_pair("interface/solidcolorF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSolidColorProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gSolidColorProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gSolidColorProgram.createShader(NULL, NULL); if (success) { @@ -3295,7 +4003,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gOcclusionProgram.mShaderFiles.clear(); gOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionV.glsl", GL_VERTEX_SHADER_ARB)); gOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionF.glsl", GL_FRAGMENT_SHADER_ARB)); - gOcclusionProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gOcclusionProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gOcclusionProgram.createShader(NULL, NULL); } @@ -3305,7 +4013,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gOcclusionCubeProgram.mShaderFiles.clear(); gOcclusionCubeProgram.mShaderFiles.push_back(make_pair("interface/occlusionCubeV.glsl", GL_VERTEX_SHADER_ARB)); gOcclusionCubeProgram.mShaderFiles.push_back(make_pair("interface/occlusionF.glsl", GL_FRAGMENT_SHADER_ARB)); - gOcclusionCubeProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gOcclusionCubeProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gOcclusionCubeProgram.createShader(NULL, NULL); } @@ -3315,7 +4023,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gDebugProgram.mShaderFiles.clear(); gDebugProgram.mShaderFiles.push_back(make_pair("interface/debugV.glsl", GL_VERTEX_SHADER_ARB)); gDebugProgram.mShaderFiles.push_back(make_pair("interface/debugF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDebugProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gDebugProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gDebugProgram.createShader(NULL, NULL); } @@ -3325,7 +4033,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gClipProgram.mShaderFiles.clear(); gClipProgram.mShaderFiles.push_back(make_pair("interface/clipV.glsl", GL_VERTEX_SHADER_ARB)); gClipProgram.mShaderFiles.push_back(make_pair("interface/clipF.glsl", GL_FRAGMENT_SHADER_ARB)); - gClipProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gClipProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gClipProgram.createShader(NULL, NULL); } @@ -3335,7 +4043,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() 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]; + gDownsampleDepthProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gDownsampleDepthProgram.createShader(NULL, NULL); } @@ -3345,7 +4053,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gBenchmarkProgram.mShaderFiles.clear(); gBenchmarkProgram.mShaderFiles.push_back(make_pair("interface/benchmarkV.glsl", GL_VERTEX_SHADER_ARB)); gBenchmarkProgram.mShaderFiles.push_back(make_pair("interface/benchmarkF.glsl", GL_FRAGMENT_SHADER_ARB)); - gBenchmarkProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gBenchmarkProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gBenchmarkProgram.createShader(NULL, NULL); } @@ -3355,17 +4063,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gDownsampleDepthRectProgram.mShaderFiles.clear(); gDownsampleDepthRectProgram.mShaderFiles.push_back(make_pair("interface/downsampleDepthV.glsl", GL_VERTEX_SHADER_ARB)); gDownsampleDepthRectProgram.mShaderFiles.push_back(make_pair("interface/downsampleDepthRectF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDownsampleDepthRectProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; - success = gDownsampleDepthRectProgram.createShader(NULL, NULL); - } - - if (success) - { - gDownsampleDepthRectProgram.mName = "DownsampleDepthRect Shader"; - gDownsampleDepthRectProgram.mShaderFiles.clear(); - gDownsampleDepthRectProgram.mShaderFiles.push_back(make_pair("interface/downsampleDepthV.glsl", GL_VERTEX_SHADER_ARB)); - gDownsampleDepthRectProgram.mShaderFiles.push_back(make_pair("interface/downsampleDepthRectF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDownsampleDepthRectProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gDownsampleDepthRectProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gDownsampleDepthRectProgram.createShader(NULL, NULL); } @@ -3375,13 +4073,13 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gAlphaMaskProgram.mShaderFiles.clear(); gAlphaMaskProgram.mShaderFiles.push_back(make_pair("interface/alphamaskV.glsl", GL_VERTEX_SHADER_ARB)); gAlphaMaskProgram.mShaderFiles.push_back(make_pair("interface/alphamaskF.glsl", GL_FRAGMENT_SHADER_ARB)); - gAlphaMaskProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + gAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = gAlphaMaskProgram.createShader(NULL, NULL); } if( !success ) { - mVertexShaderLevel[SHADER_INTERFACE] = 0; + mShaderLevel[SHADER_INTERFACE] = 0; return FALSE; } @@ -3392,36 +4090,80 @@ BOOL LLViewerShaderMgr::loadShadersWindLight() { BOOL success = TRUE; - if (mVertexShaderLevel[SHADER_WINDLIGHT] < 2) + if (mShaderLevel[SHADER_WINDLIGHT] < 2) { gWLSkyProgram.unload(); gWLCloudProgram.unload(); + gWLSunProgram.unload(); + gWLMoonProgram.unload(); return TRUE; } - if (success) - { - gWLSkyProgram.mName = "Windlight Sky Shader"; - //gWLSkyProgram.mFeatures.hasGamma = true; - gWLSkyProgram.mShaderFiles.clear(); - gWLSkyProgram.mShaderFiles.push_back(make_pair("windlight/skyV.glsl", GL_VERTEX_SHADER_ARB)); - 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, NULL); - } + if (success) + { + gWLSkyProgram.mName = "Windlight Sky Shader"; + gWLSkyProgram.mShaderFiles.clear(); + gWLSkyProgram.mFeatures.calculatesAtmospherics = true; + gWLSkyProgram.mFeatures.hasTransport = true; + gWLSkyProgram.mFeatures.hasGamma = true; + gWLSkyProgram.mFeatures.hasSrgb = true; + gWLSkyProgram.mShaderFiles.push_back(make_pair("windlight/skyV.glsl", GL_VERTEX_SHADER_ARB)); + gWLSkyProgram.mShaderFiles.push_back(make_pair("windlight/skyF.glsl", GL_FRAGMENT_SHADER_ARB)); + gWLSkyProgram.mShaderLevel = mShaderLevel[SHADER_WINDLIGHT]; + gWLSkyProgram.mShaderGroup = LLGLSLShader::SG_SKY; + success = gWLSkyProgram.createShader(NULL, NULL); + } - if (success) - { - gWLCloudProgram.mName = "Windlight Cloud Program"; - //gWLCloudProgram.mFeatures.hasGamma = true; - gWLCloudProgram.mShaderFiles.clear(); - gWLCloudProgram.mShaderFiles.push_back(make_pair("windlight/cloudsV.glsl", GL_VERTEX_SHADER_ARB)); - 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, NULL); - } + if (success) + { + gWLCloudProgram.mName = "Windlight Cloud Program"; + gWLCloudProgram.mShaderFiles.clear(); + gWLCloudProgram.mFeatures.calculatesAtmospherics = true; + gWLCloudProgram.mFeatures.hasTransport = true; + gWLCloudProgram.mFeatures.hasGamma = true; + gWLCloudProgram.mFeatures.hasSrgb = true; + gWLCloudProgram.mShaderFiles.push_back(make_pair("windlight/cloudsV.glsl", GL_VERTEX_SHADER_ARB)); + gWLCloudProgram.mShaderFiles.push_back(make_pair("windlight/cloudsF.glsl", GL_FRAGMENT_SHADER_ARB)); + gWLCloudProgram.mShaderLevel = mShaderLevel[SHADER_WINDLIGHT]; + gWLCloudProgram.mShaderGroup = LLGLSLShader::SG_SKY; + success = gWLCloudProgram.createShader(NULL, NULL); + } + + if (success) + { + gWLSunProgram.mName = "Windlight Sun Program"; + gWLSunProgram.mShaderFiles.clear(); + gWLSunProgram.mFeatures.calculatesAtmospherics = true; + gWLSunProgram.mFeatures.hasTransport = true; + gWLSunProgram.mFeatures.hasGamma = true; + gWLSunProgram.mFeatures.hasAtmospherics = true; + gWLSunProgram.mFeatures.isFullbright = true; + gWLSunProgram.mFeatures.disableTextureIndex = true; + gWLSunProgram.mShaderGroup = LLGLSLShader::SG_SKY; + gWLSunProgram.mShaderFiles.push_back(make_pair("windlight/sunDiscV.glsl", GL_VERTEX_SHADER_ARB)); + gWLSunProgram.mShaderFiles.push_back(make_pair("windlight/sunDiscF.glsl", GL_FRAGMENT_SHADER_ARB)); + gWLSunProgram.mShaderLevel = mShaderLevel[SHADER_WINDLIGHT]; + gWLSunProgram.mShaderGroup = LLGLSLShader::SG_SKY; + success = gWLSunProgram.createShader(NULL, NULL); + } + + if (success) + { + gWLMoonProgram.mName = "Windlight Moon Program"; + gWLMoonProgram.mShaderFiles.clear(); + gWLMoonProgram.mFeatures.calculatesAtmospherics = true; + gWLMoonProgram.mFeatures.hasTransport = true; + gWLMoonProgram.mFeatures.hasGamma = true; + gWLMoonProgram.mFeatures.hasAtmospherics = true; + gWLMoonProgram.mFeatures.isFullbright = true; + gWLMoonProgram.mFeatures.disableTextureIndex = true; + gWLMoonProgram.mShaderGroup = LLGLSLShader::SG_SKY; + gWLMoonProgram.mShaderFiles.push_back(make_pair("windlight/moonV.glsl", GL_VERTEX_SHADER_ARB)); + gWLMoonProgram.mShaderFiles.push_back(make_pair("windlight/moonF.glsl", GL_FRAGMENT_SHADER_ARB)); + gWLMoonProgram.mShaderLevel = mShaderLevel[SHADER_WINDLIGHT]; + gWLMoonProgram.mShaderGroup = LLGLSLShader::SG_SKY; + success = gWLMoonProgram.createShader(NULL, NULL); + } return success; } @@ -3430,7 +4172,7 @@ BOOL LLViewerShaderMgr::loadTransformShaders() { BOOL success = TRUE; - if (mVertexShaderLevel[SHADER_TRANSFORM] < 1) + if (mShaderLevel[SHADER_TRANSFORM] < 1) { gTransformPositionProgram.unload(); gTransformTexCoordProgram.unload(); @@ -3442,10 +4184,10 @@ BOOL LLViewerShaderMgr::loadTransformShaders() if (success) { - gTransformPositionProgram.mName = "Position Transform Shader"; + gTransformPositionProgram.mName = "Position Transform Shader"; gTransformPositionProgram.mShaderFiles.clear(); gTransformPositionProgram.mShaderFiles.push_back(make_pair("transform/positionV.glsl", GL_VERTEX_SHADER_ARB)); - gTransformPositionProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + gTransformPositionProgram.mShaderLevel = mShaderLevel[SHADER_TRANSFORM]; const char* varyings[] = { "position_out", @@ -3460,7 +4202,7 @@ BOOL LLViewerShaderMgr::loadTransformShaders() gTransformTexCoordProgram.mName = "TexCoord Transform Shader"; gTransformTexCoordProgram.mShaderFiles.clear(); gTransformTexCoordProgram.mShaderFiles.push_back(make_pair("transform/texcoordV.glsl", GL_VERTEX_SHADER_ARB)); - gTransformTexCoordProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + gTransformTexCoordProgram.mShaderLevel = mShaderLevel[SHADER_TRANSFORM]; const char* varyings[] = { "texcoord_out", @@ -3474,7 +4216,7 @@ BOOL LLViewerShaderMgr::loadTransformShaders() gTransformNormalProgram.mName = "Normal Transform Shader"; gTransformNormalProgram.mShaderFiles.clear(); gTransformNormalProgram.mShaderFiles.push_back(make_pair("transform/normalV.glsl", GL_VERTEX_SHADER_ARB)); - gTransformNormalProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + gTransformNormalProgram.mShaderLevel = mShaderLevel[SHADER_TRANSFORM]; const char* varyings[] = { "normal_out", @@ -3488,7 +4230,7 @@ BOOL LLViewerShaderMgr::loadTransformShaders() gTransformColorProgram.mName = "Color Transform Shader"; gTransformColorProgram.mShaderFiles.clear(); gTransformColorProgram.mShaderFiles.push_back(make_pair("transform/colorV.glsl", GL_VERTEX_SHADER_ARB)); - gTransformColorProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + gTransformColorProgram.mShaderLevel = mShaderLevel[SHADER_TRANSFORM]; const char* varyings[] = { "color_out", @@ -3502,7 +4244,7 @@ BOOL LLViewerShaderMgr::loadTransformShaders() 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]; + gTransformTangentProgram.mShaderLevel = mShaderLevel[SHADER_TRANSFORM]; const char* varyings[] = { "tangent_out", @@ -3522,8 +4264,7 @@ std::string LLViewerShaderMgr::getShaderDirPrefix(void) void LLViewerShaderMgr::updateShaderUniforms(LLGLSLShader * shader) { - LLWLParamManager::getInstance()->updateShaderUniforms(shader); - LLWaterParamManager::getInstance()->updateShaderUniforms(shader); + LLEnvironment::instance().updateShaderUniforms(shader); } LLViewerShaderMgr::shader_iter LLViewerShaderMgr::beginShaders() const diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 9edaa97e57..081221f15b 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -48,7 +48,7 @@ public: void initAttribsAndUniforms(void); void setShaders(); void unloadShaders(); - S32 getVertexShaderLevel(S32 type); + S32 getShaderLevel(S32 type); BOOL loadBasicShaders(); BOOL loadShadersEffects(); BOOL loadShadersDeferred(); @@ -60,7 +60,7 @@ public: BOOL loadShadersWindLight(); BOOL loadTransformShaders(); - std::vector<S32> mVertexShaderLevel; + std::vector<S32> mShaderLevel; S32 mMaxAvatarShaderLevel; enum EShaderClass @@ -129,24 +129,6 @@ public: /* virtual */ void updateShaderUniforms(LLGLSLShader * shader); private: - - std::vector<std::string> mShinyUniforms; - - //water parameters - std::vector<std::string> mWaterUniforms; - - std::vector<std::string> mWLUniforms; - - //terrain parameters - std::vector<std::string> mTerrainUniforms; - - //glow parameters - std::vector<std::string> mGlowUniforms; - - std::vector<std::string> mGlowExtractUniforms; - - std::vector<std::string> mAvatarUniforms; - // the list of shaders we need to propagate parameters to. std::vector<LLGLSLShader *> mShaderList; @@ -255,6 +237,7 @@ extern LLGLSLShader gSkinnedObjectShinySimpleWaterProgram; extern LLGLSLShader gTerrainProgram; extern LLGLSLShader gTerrainWaterProgram; extern LLGLSLShader gWaterProgram; +extern LLGLSLShader gWaterEdgeProgram; extern LLGLSLShader gUnderWaterProgram; extern LLGLSLShader gGlowProgram; extern LLGLSLShader gGlowExtractProgram; @@ -281,6 +264,8 @@ extern LLGLSLShader gImpostorProgram; // WindLight shader handles extern LLGLSLShader gWLSkyProgram; extern LLGLSLShader gWLCloudProgram; +extern LLGLSLShader gWLSunProgram; +extern LLGLSLShader gWLMoonProgram; // Post Process Shaders extern LLGLSLShader gPostColorFilterProgram; @@ -301,6 +286,7 @@ extern LLGLSLShader gDeferredSkinnedBumpProgram; extern LLGLSLShader gDeferredSkinnedAlphaProgram; extern LLGLSLShader gDeferredBumpProgram; extern LLGLSLShader gDeferredTerrainProgram; +extern LLGLSLShader gDeferredTerrainWaterProgram; extern LLGLSLShader gDeferredTreeProgram; extern LLGLSLShader gDeferredTreeShadowProgram; extern LLGLSLShader gDeferredLightProgram; @@ -315,6 +301,7 @@ extern LLGLSLShader gDeferredSoftenWaterProgram; extern LLGLSLShader gDeferredShadowProgram; extern LLGLSLShader gDeferredShadowCubeProgram; extern LLGLSLShader gDeferredShadowAlphaMaskProgram; +extern LLGLSLShader gDeferredShadowFullbrightAlphaMaskProgram; extern LLGLSLShader gDeferredPostProgram; extern LLGLSLShader gDeferredCoFProgram; extern LLGLSLShader gDeferredDoFCombineProgram; @@ -339,6 +326,8 @@ extern LLGLSLShader gDeferredAvatarEyesProgram; extern LLGLSLShader gDeferredAvatarAlphaProgram; extern LLGLSLShader gDeferredWLSkyProgram; extern LLGLSLShader gDeferredWLCloudProgram; +extern LLGLSLShader gDeferredWLSunProgram; +extern LLGLSLShader gDeferredWLMoonProgram; extern LLGLSLShader gDeferredStarProgram; extern LLGLSLShader gDeferredFullbrightShinyProgram; extern LLGLSLShader gDeferredSkinnedFullbrightShinyProgram; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 15b2ac8acf..314c1a1f1e 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -55,14 +55,15 @@ #include "llviewerregion.h" #include "llvoavatar.h" #include "llvoavatarself.h" -#include "llviewerwindow.h" // *TODO: remove, only used for width/height #include "llworld.h" #include "llfeaturemanager.h" #include "llviewernetwork.h" #include "llmeshrepository.h" //for LLMeshRepository::sBytesReceived #include "llsdserialize.h" +#include "llsdutil.h" #include "llcorehttputil.h" #include "llvoicevivox.h" +#include "lluiusage.h" namespace LLStatViewer { @@ -359,16 +360,19 @@ void update_statistics() record(LLStatViewer::REBUILD_STACKTIME, last_frame_recording.getSum(*stat_type_t::getInstance("Sort Draw State"))); record(LLStatViewer::RENDER_STACKTIME, last_frame_recording.getSum(*stat_type_t::getInstance("Render Geometry"))); - LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(gAgent.getRegion()->getHost()); - if (cdp) + if (gAgent.getRegion() && isAgentAvatarValid()) { - sample(LLStatViewer::SIM_PING, F64Milliseconds (cdp->getPingDelay())); - gAvgSimPing = ((gAvgSimPing * gSimPingCount) + cdp->getPingDelay()) / (gSimPingCount + 1); - gSimPingCount++; - } - else - { - sample(LLStatViewer::SIM_PING, U32Seconds(10)); + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(gAgent.getRegion()->getHost()); + if (cdp) + { + sample(LLStatViewer::SIM_PING, F64Milliseconds(cdp->getPingDelay())); + gAvgSimPing = ((gAvgSimPing * gSimPingCount) + cdp->getPingDelay()) / (gSimPingCount + 1); + gSimPingCount++; + } + else + { + sample(LLStatViewer::SIM_PING, U32Seconds(10)); + } } if (LLViewerStats::instance().getRecording().getSum(LLStatViewer::FPS)) @@ -423,7 +427,7 @@ void update_statistics() * If you move stats around here, make the corresponding changes in * those locations, too. */ -void send_stats() +void send_viewer_stats(bool include_preferences) { // IW 9/23/02 I elected not to move this into LLViewerStats // because it depends on too many viewer.cpp globals. @@ -470,7 +474,7 @@ void send_stats() // send fps only for time app spends in foreground agent["fps"] = (F32)gForegroundFrameCount / gForegroundTime.getElapsedTimeF32(); - agent["version"] = LLVersionInfo::getChannelAndVersion(); + agent["version"] = LLVersionInfo::instance().getChannelAndVersion(); std::string language = LLUI::getLanguage(); agent["language"] = language; @@ -511,6 +515,8 @@ void send_stats() system["gpu_version"] = gGLManager.mDriverVersionVendorString; system["opengl_version"] = gGLManager.mGLVersionString; + gGLManager.asLLSD(system["gl"]); + S32 shader_level = 0; if (LLPipeline::sRenderDeferred) { @@ -570,7 +576,10 @@ void send_stats() fail["failed_resends"] = (S32) gMessageSystem->mFailedResendPackets; fail["off_circuit"] = (S32) gMessageSystem->mOffCircuitPackets; fail["invalid"] = (S32) gMessageSystem->mInvalidOnCircuitPackets; + fail["missing_updater"] = (S32) LLAppViewer::instance()->isUpdaterMissing(); + body["ui"] = LLUIUsage::instance().asLLSD(); + body["stats"]["voice"] = LLVoiceVivoxStats::getInstance()->read(); // Misc stats, two strings and two ints @@ -579,29 +588,61 @@ void send_stats() // If the current revision is recent, ping the previous author before overriding LLSD &misc = body["stats"]["misc"]; - // Screen size so the UI team can figure out how big the widgets - // appear and use a "typical" size for end user tests. - - S32 window_width = gViewerWindow->getWindowWidthRaw(); - S32 window_height = gViewerWindow->getWindowHeightRaw(); - S32 window_size = (window_width * window_height) / 1024; - misc["string_1"] = llformat("%d", window_size); - misc["string_2"] = llformat("Texture Time: %.2f, Total Time: %.2f", gTextureTimer.getElapsedTimeF32(), gFrameTimeSeconds.value()); - - F32 unbaked_time = LLVOAvatar::sUnbakedTime * 1000.f / gFrameTimeSeconds; - misc["int_1"] = LLSD::Integer(unbaked_time); // Steve: 1.22 - F32 grey_time = LLVOAvatar::sGreyTime * 1000.f / gFrameTimeSeconds; - misc["int_2"] = LLSD::Integer(grey_time); // Steve: 1.22 - - LL_INFOS() << "Misc Stats: int_1: " << misc["int_1"] << " int_2: " << misc["int_2"] << LL_ENDL; +#ifdef LL_WINDOWS + // Probe for Vulkan capability (Dave Houlton 05/2020) + // + // Check for presense of a Vulkan loader dll, as a proxy for a Vulkan-capable gpu. + // False-positives and false-negatives are possible, but unlikely. We'll get a good + // approximation of Vulkan capability within current user systems from this. More + // detailed information on versions and extensions can come later. + static bool vulkan_oneshot = false; + static bool vulkan_detected = false; + + if (!vulkan_oneshot) + { + HMODULE vulkan_loader = LoadLibraryExA("vulkan-1.dll", NULL, LOAD_LIBRARY_AS_DATAFILE); + if (NULL != vulkan_loader) + { + vulkan_detected = true; + FreeLibrary(vulkan_loader); + } + vulkan_oneshot = true; + } + + misc["string_1"] = vulkan_detected ? llformat("Vulkan driver is detected") : llformat("No Vulkan driver detected"); + +#else + misc["string_1"] = llformat("Unused"); +#endif // LL_WINDOWS + + misc["string_2"] = llformat("Unused"); + misc["int_1"] = LLSD::Integer(0); + misc["int_2"] = LLSD::Integer(0); + + 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.getBOOL("UseDisplayNames"); body["DisplayNamesShowUsername"] = gSavedSettings.getBOOL("NameTagShowUsernames"); - + + // Preferences + if (include_preferences) + { + bool diffs_only = true; // only log preferences that differ from default + body["preferences"]["settings"] = gSavedSettings.asLLSD(diffs_only); + body["preferences"]["settings_per_account"] = gSavedPerAccountSettings.asLLSD(diffs_only); + } + body["MinimalSkin"] = false; + LL_INFOS("LogViewerStatsPacket") << "Sending viewer statistics: " << body << LL_ENDL; + if (debugLoggingEnabled("LogViewerStatsPacket")) + { + std::string filename("viewer_stats_packet.xml"); + llofstream of(filename.c_str()); + LLSDSerialize::toPrettyXML(body,of); + } // The session ID token must never appear in logs body["session_id"] = gAgentSessionID; diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index d8d92d61d3..04870e0c26 100644 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -294,7 +294,7 @@ static const F32 SEND_STATS_PERIOD = 300.0f; // The following are from (older?) statistics code found in appviewer. void update_statistics(); -void send_stats(); +void send_viewer_stats(bool include_preferences); extern LLFrameTimer gTextureTimer; extern U32Bytes gTotalTextureData; diff --git a/indra/newview/llviewertexlayer.cpp b/indra/newview/llviewertexlayer.cpp index 7f7d190b92..c501dd0035 100644 --- a/indra/newview/llviewertexlayer.cpp +++ b/indra/newview/llviewertexlayer.cpp @@ -54,7 +54,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), mNeedsUpdate(TRUE), mNumLowresUpdates(0) { diff --git a/indra/newview/llviewertexlayer.h b/indra/newview/llviewertexlayer.h index 027ae255ec..dec7f0ddfc 100644 --- a/indra/newview/llviewertexlayer.h +++ b/indra/newview/llviewertexlayer.h @@ -111,7 +111,7 @@ protected: // Pass these along for tex layer rendering. virtual void preRender(BOOL clear_depth) { preRenderTexLayerSet(); } virtual void postRender(BOOL success) { postRenderTexLayerSet(success); } - virtual BOOL render() { return renderTexLayerSet(); } + virtual BOOL render() { return renderTexLayerSet(mBoundTarget); } //-------------------------------------------------------------------- // Updates diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index 7d2d6e25c7..e2de7ac825 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -31,6 +31,7 @@ #include "llagent.h" #include "llaudioengine.h" #include "llavataractions.h" +#include "llenvironment.h" #include "llfloaterreg.h" #include "llfloatersidepanelcontainer.h" #include "llfloaterworldmap.h" @@ -239,7 +240,7 @@ public: /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) { - LLUI::getWindow()->setCursor(UI_CURSOR_HAND); + LLUI::getInstance()->getWindow()->setCursor(UI_CURSOR_HAND); return TRUE; } virtual BOOL handleToolTip(S32 x, S32 y, MASK mask ) @@ -540,7 +541,9 @@ LLUIImagePtr LLEmbeddedItems::getItemImage(llwchar ext_char) const case LLAssetType::AT_ANIMATION: img_name = "Inv_Animation"; break; case LLAssetType::AT_GESTURE: img_name = "Inv_Gesture"; break; case LLAssetType::AT_MESH: img_name = "Inv_Mesh"; break; - default: img_name = "Inv_Invalid"; break; // use the Inv_Invalid icon for undefined object types (see MAINT-3981) + 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) + } return LLUI::getUIImage(img_name); @@ -852,8 +855,18 @@ BOOL LLViewerTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask, if (getEnabled() && acceptsTextInput()) { + bool supported = false; switch( cargo_type ) { + case DAD_SETTINGS: + { + supported = LLEnvironment::instance().isExtendedEnvironmentEnabled(); + if (!supported && tooltip_msg.empty()) + { + tooltip_msg.assign(LLTrans::getString("TooltipNotecardNotAllowedTypeDrop")); + } + break; + } case DAD_CALLINGCARD: case DAD_TEXTURE: case DAD_SOUND: @@ -867,52 +880,50 @@ BOOL LLViewerTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask, case DAD_GESTURE: case DAD_MESH: { - LLInventoryItem *item = (LLInventoryItem *)cargo_data; - if( item && allowsEmbeddedItems() ) + supported = true; + break; + } + + default: + supported = false; + break; + } + + LLInventoryItem *item = (LLInventoryItem *)cargo_data; + if (item && allowsEmbeddedItems() && supported) + { + U32 mask_next = item->getPermissions().getMaskNextOwner(); + if((mask_next & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) + { + if( drop ) { - U32 mask_next = item->getPermissions().getMaskNextOwner(); - if((mask_next & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) - { - if( drop ) - { - deselect(); - S32 old_cursor = mCursorPos; - setCursorAtLocalPos( x, y, TRUE ); - S32 insert_pos = mCursorPos; - setCursorPos(old_cursor); - BOOL inserted = insertEmbeddedItem( insert_pos, item ); - if( inserted && (old_cursor > mCursorPos) ) - { - setCursorPos(mCursorPos + 1); - } - - needsReflow(); - - } - *accept = ACCEPT_YES_COPY_MULTI; - } - else + deselect(); + S32 old_cursor = mCursorPos; + setCursorAtLocalPos( x, y, TRUE ); + S32 insert_pos = mCursorPos; + setCursorPos(old_cursor); + BOOL inserted = insertEmbeddedItem( insert_pos, item ); + if( inserted && (old_cursor > mCursorPos) ) { - *accept = ACCEPT_NO; - if (tooltip_msg.empty()) - { - // *TODO: Translate - tooltip_msg.assign("Only items with unrestricted\n" - "'next owner' permissions \n" - "can be attached to notecards."); - } + setCursorPos(mCursorPos + 1); } + + needsReflow(); } - else + *accept = ACCEPT_YES_COPY_MULTI; + } + else + { + *accept = ACCEPT_NO; + if (tooltip_msg.empty()) { - *accept = ACCEPT_NO; + tooltip_msg.assign(LLTrans::getString("TooltipNotecardOwnerRestrictedDrop")); } - break; } - - default: + } + else + { *accept = ACCEPT_NO; - break; } } else @@ -1112,7 +1123,9 @@ BOOL LLViewerTextEditor::openEmbeddedItem(LLPointer<LLInventoryItem> item, llwch case LLAssetType::AT_CALLINGCARD: openEmbeddedCallingcard( item, wc ); return TRUE; - + case LLAssetType::AT_SETTINGS: + openEmbeddedSetting(item, wc); + return TRUE; case LLAssetType::AT_NOTECARD: case LLAssetType::AT_LSL_TEXT: case LLAssetType::AT_CLOTHING: @@ -1187,6 +1200,18 @@ void LLViewerTextEditor::openEmbeddedCallingcard( LLInventoryItem* item, llwchar } } +void LLViewerTextEditor::openEmbeddedSetting(LLInventoryItem* item, llwchar wc) +{ + if (LLEnvironment::instance().isInventoryEnabled()) + { + showCopyToInvDialog(item, wc); + } + else + { + LLNotificationsUtil::add("NoEnvironmentSettings"); + } +} + void LLViewerTextEditor::showUnsavedAlertDialog( LLInventoryItem* item ) { LLSD payload; diff --git a/indra/newview/llviewertexteditor.h b/indra/newview/llviewertexteditor.h index 44f104dde1..a6d7fef409 100644 --- a/indra/newview/llviewertexteditor.h +++ b/indra/newview/llviewertexteditor.h @@ -107,6 +107,7 @@ private: void openEmbeddedSound( LLInventoryItem* item, llwchar wc ); void openEmbeddedLandmark( LLPointer<LLInventoryItem> item_ptr, llwchar wc ); void openEmbeddedCallingcard( LLInventoryItem* item, llwchar wc); + void openEmbeddedSetting(LLInventoryItem* item, llwchar wc); void showCopyToInvDialog( LLInventoryItem* item, llwchar wc ); void showUnsavedAlertDialog( LLInventoryItem* item ); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 93562cfab2..ca01bb46aa 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -98,8 +98,8 @@ 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; +U32 LLViewerTexture::sMinLargeImageSize = 65536; //256 * 256. +U32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA; bool LLViewerTexture::sFreezeImageUpdates = false; F32 LLViewerTexture::sCurrentTime = 0.0f; F32 LLViewerTexture::sTexelPixelRatio = 1.0f; @@ -1238,6 +1238,8 @@ void LLViewerFetchedTexture::loadFromFastCache() { if (mBoostLevel == LLGLTexture::BOOST_ICON) { + // Shouldn't do anything usefull since texures in fast cache are 16x16, + // it is here in case fast cache changes. 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)) @@ -1485,7 +1487,8 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) mOrigWidth = mRawImage->getWidth(); mOrigHeight = mRawImage->getHeight(); - + // This is only safe because it's a local image and fetcher doesn't use raw data + // from local images, but this might become unsafe in case of changes to fetcher if (mBoostLevel == BOOST_PREVIEW) { mRawImage->biasedScaleToPowerOfTwo(1024); @@ -1541,6 +1544,26 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) return FALSE; } + if (mGLTexturep->getHasExplicitFormat()) + { + LLGLenum format = mGLTexturep->getPrimaryFormat(); + S8 components = mRawImage->getComponents(); + if ((format == GL_RGBA && components < 4) + || (format == GL_RGB && components < 3)) + { + LL_WARNS() << "Can't create a texture " << mID << ": invalid image format " << std::hex << format << " vs components " << (U32)components << LL_ENDL; + // Was expecting specific format but raw texture has insufficient components for + // such format, using such texture will result in crash or will display wrongly + // if we change format. Texture might be corrupted server side, so just set as + // missing and clear cashed texture (do not cause reload loop, will retry&recover + // during new session) + setIsMissingAsset(); + destroyRawImage(); + LLAppViewer::getTextureCache()->removeFromCache(mID); + return FALSE; + } + } + res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel); notifyAboutCreatingTexture(); @@ -1989,6 +2012,7 @@ bool LLViewerFetchedTexture::updateFetch() if (mRawImage.notNull()) sRawCount--; if (mAuxRawImage.notNull()) sAuxCount--; + // keep in mind that fetcher still might need raw image, don't modify original bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage, mLastHttpGetStatus); if (mRawImage.notNull()) sRawCount++; @@ -2048,7 +2072,8 @@ bool LLViewerFetchedTexture::updateFetch() 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); + // since we got mRawImage from thread worker and image may be in use (ex: writing cache), make a copy + mRawImage = mRawImage->scaled(expected_width, expected_height); } } @@ -3289,13 +3314,6 @@ void LLViewerLODTexture::processTextureStats() { mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel); } - else if(LLPipeline::sMemAllocationThrottled)//release memory of large textures by decrease their resolutions. - { - if(scaleDown()) - { - mDesiredDiscardLevel = mCachedRawDiscardLevel; - } - } } bool LLViewerLODTexture::scaleDown() @@ -3459,7 +3477,7 @@ void LLViewerMediaTexture::setMediaImpl() { if(!mMediaImplp) { - mMediaImplp = LLViewerMedia::getMediaImplFromTextureID(mID); + mMediaImplp = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mID); } } @@ -3481,7 +3499,10 @@ BOOL LLViewerMediaTexture::findFaces() U32 end = tex->getNumFaces(ch); for(U32 i = 0; i < end; i++) { - mMediaFaceList.push_back((*face_list)[i]); + if ((*face_list)[i]->isMediaAllowed()) + { + mMediaFaceList.push_back((*face_list)[i]); + } } } } diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 7cbcc931b1..69568cc825 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -125,6 +125,8 @@ public: virtual BOOL isMissingAsset() const ; virtual void dump(); // debug info to LL_INFOS() + virtual bool isViewerMediaTexture() const { return false; } + /*virtual*/ bool bindDefaultImage(const S32 stage = 0) ; /*virtual*/ bool bindDebugImage(const S32 stage = 0) ; /*virtual*/ void forceImmediateUpdate() ; @@ -228,8 +230,8 @@ public: static S8 sCameraMovingDiscardBias; static F32 sCameraMovingBias; static S32 sMaxSculptRez ; - static S32 sMinLargeImageSize ; - static S32 sMaxSmallImageSize ; + static U32 sMinLargeImageSize ; + static U32 sMaxSmallImageSize ; static bool sFreezeImageUpdates; static F32 sCurrentTime ; @@ -579,6 +581,8 @@ public: BOOL isPlaying() const {return mIsPlaying;} void setMediaImpl() ; + virtual bool isViewerMediaTexture() const { return true; } + void initVirtualSize() ; void invalidateMediaImpl() ; diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 06524847d1..561319ca5d 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1385,8 +1385,6 @@ S32Megabytes LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, fl { max_texmem = (S32Megabytes)128; } - - LL_WARNS() << "VRAM amount not detected, defaulting to " << max_texmem << " MB" << LL_ENDL; } S32Megabytes system_ram = gSysMemory.getPhysicalMemoryKB(); // In MB @@ -1428,6 +1426,11 @@ void LLViewerTextureList::updateMaxResidentTexMem(S32Megabytes mem) return; //listener will re-enter this function } + if (gGLManager.mVRAM == 0) + { + LL_WARNS() << "VRAM amount not detected, defaulting to " << mem << " MB" << LL_ENDL; + } + // TODO: set available resident texture mem based on use by other subsystems // currently max(12MB, VRAM/4) assumed... diff --git a/indra/newview/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp index 2d7a0f920f..9c4dfd1ca2 100644 --- a/indra/newview/llviewerwearable.cpp +++ b/indra/newview/llviewerwearable.cpp @@ -178,7 +178,7 @@ BOOL LLViewerWearable::isOldVersion() const S32 te_count = 0; for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) { - if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex) te) == mType) + if (LLAvatarAppearance::getDictionary()->getTEWearableType((ETextureIndex) te) == mType) { te_count++; if( !is_in_map(mTEMap, te ) ) @@ -230,7 +230,7 @@ BOOL LLViewerWearable::isDirty() const for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) { - if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex) te) == mType) + if (LLAvatarAppearance::getDictionary()->getTEWearableType((ETextureIndex) te) == mType) { te_map_t::const_iterator current_iter = mTEMap.find(te); if(current_iter != mTEMap.end()) @@ -276,7 +276,7 @@ void LLViewerWearable::setTexturesToDefaults() { for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) { - if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex) te) == mType) + if (LLAvatarAppearance::getDictionary()->getTEWearableType((ETextureIndex) te) == mType) { LLUUID id = getDefaultTextureImageID((ETextureIndex) te); LLViewerFetchedTexture * image = LLViewerTextureManager::getFetchedTexture( id ); @@ -300,7 +300,7 @@ void LLViewerWearable::setTexturesToDefaults() // virtual LLUUID LLViewerWearable::getDefaultTextureImageID(ETextureIndex index) const { - const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(index); + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearance::getDictionary()->getTexture(index); const std::string &default_image_name = texture_dict ? texture_dict->mDefaultImageName : ""; if (default_image_name == "") { @@ -331,7 +331,7 @@ void LLViewerWearable::writeToAvatar(LLAvatarAppearance *avatarp) // Pull texture entries for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) { - if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex) te) == mType) + if (LLAvatarAppearance::getDictionary()->getTEWearableType((ETextureIndex) te) == mType) { te_map_t::const_iterator iter = mTEMap.find(te); LLUUID image_id; @@ -424,7 +424,7 @@ void LLViewerWearable::copyDataFrom(const LLViewerWearable* src) // Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed) for (S32 te = 0; te < TEX_NUM_INDICES; te++) { - if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex) te) == mType) + if (LLAvatarAppearance::getDictionary()->getTEWearableType((ETextureIndex) te) == mType) { te_map_t::const_iterator iter = src->mTEMap.find(te); LLUUID image_id; @@ -463,8 +463,7 @@ void LLViewerWearable::revertValues() { LLWearable::revertValues(); - - LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(LLFloaterSidePanelContainer::getPanel("appearance")); + LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(LLFloaterSidePanelContainer::findPanel("appearance")); if( panel ) { panel->updateScrollingPanelList(); @@ -480,7 +479,7 @@ void LLViewerWearable::saveValues() { LLWearable::saveValues(); - LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(LLFloaterSidePanelContainer::getPanel("appearance")); + LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(LLFloaterSidePanelContainer::findPanel("appearance")); if( panel ) { panel->updateScrollingPanelList(); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index e4d445b95c..abacd96111 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -45,7 +45,8 @@ #include "llmeshrepository.h" #include "llnotificationhandler.h" #include "llpanellogin.h" -#include "llviewerkeyboard.h" +#include "llsetkeybinddialog.h" +#include "llviewerinput.h" #include "llviewermenu.h" #include "llviewquery.h" @@ -173,7 +174,7 @@ #include "llviewergesture.h" #include "llviewertexturelist.h" #include "llviewerinventory.h" -#include "llviewerkeyboard.h" +#include "llviewerinput.h" #include "llviewermedia.h" #include "llviewermediafocus.h" #include "llviewermenu.h" @@ -313,6 +314,99 @@ RecordToChatConsole::RecordToChatConsole(): //////////////////////////////////////////////////////////////////////////// // +// Print Utility +// + +// Convert a normalized float (-1.0 <= x <= +1.0) to a fixed 1.4 format string: +// +// s#.#### +// +// Where: +// s sign character; space if x is positiv, minus if negative +// # decimal digits +// +// This is similar to printf("%+.4f") except positive numbers are NOT cluttered with a leading '+' sign. +// NOTE: This does NOT null terminate the output +void normalized_float_to_string(const float x, char *out_str) +{ + static const unsigned char DECIMAL_BCD2[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99 + }; + + int neg = (x < 0); + int rem = neg + ? (int)(x * -10000.) + : (int)(x * 10000.); + + int d10 = rem % 100; rem /= 100; + int d32 = rem % 100; rem /= 100; + + out_str[6] = '0' + ((DECIMAL_BCD2[ d10 ] >> 0) & 0xF); + out_str[5] = '0' + ((DECIMAL_BCD2[ d10 ] >> 4) & 0xF); + out_str[4] = '0' + ((DECIMAL_BCD2[ d32 ] >> 0) & 0xF); + out_str[3] = '0' + ((DECIMAL_BCD2[ d32 ] >> 4) & 0xF); + out_str[2] = '.'; + out_str[1] = '0' + (rem & 1); + out_str[0] = " -"[neg]; // Could always show '+' for positive but this clutters up the common case +} + +// normalized float +// printf("%-.4f %-.4f %-.4f") +// Params: +// float &matrix_row[4] +// int matrix_cell_index +// string out_buffer (size 32) +// Note: The buffer is assumed to be pre-filled with spaces +#define MATRIX_ROW_N32_TO_STR(matrix_row, i, out_buffer) \ + normalized_float_to_string(matrix_row[i+0], out_buffer + 0); \ + normalized_float_to_string(matrix_row[i+1], out_buffer + 11); \ + normalized_float_to_string(matrix_row[i+2], out_buffer + 22); \ + out_buffer[31] = 0; + + +// regular float +// sprintf(buffer, "%-8.2f %-8.2f %-8.2f", matrix_row[i+0], matrix_row[i+1], matrix_row[i+2]); +// Params: +// float &matrix_row[4] +// int matrix_cell_index +// char out_buffer[32] +// Note: The buffer is assumed to be pre-filled with spaces +#define MATRIX_ROW_F32_TO_STR(matrix_row, i, out_buffer) { \ + static const char *format[3] = { \ + "%-8.2f" , /* 0 */ \ + "> 99K ", /* 1 */ \ + "< -99K " /* 2 */ \ + }; \ + \ + F32 temp_0 = matrix_row[i+0]; \ + F32 temp_1 = matrix_row[i+1]; \ + F32 temp_2 = matrix_row[i+2]; \ + \ + U8 flag_0 = (((U8)(temp_0 < -99999.99)) << 1) | ((U8)(temp_0 > 99999.99)); \ + U8 flag_1 = (((U8)(temp_1 < -99999.99)) << 1) | ((U8)(temp_1 > 99999.99)); \ + U8 flag_2 = (((U8)(temp_2 < -99999.99)) << 1) | ((U8)(temp_2 > 99999.99)); \ + \ + if (temp_0 < 0.f) out_buffer[ 0] = '-'; \ + if (temp_1 < 0.f) out_buffer[11] = '-'; \ + if (temp_2 < 0.f) out_buffer[22] = '-'; \ + \ + sprintf(out_buffer+ 1,format[flag_0],fabsf(temp_0)); out_buffer[ 1+8] = ' '; \ + sprintf(out_buffer+12,format[flag_1],fabsf(temp_1)); out_buffer[12+8] = ' '; \ + sprintf(out_buffer+23,format[flag_2],fabsf(temp_2)); out_buffer[23+8] = 0 ; \ +} + +//////////////////////////////////////////////////////////////////////////// +// // LLDebugText // @@ -333,7 +427,11 @@ private: typedef std::vector<Line> line_list_t; line_list_t mLineList; LLColor4 mTextColor; - + + LLColor4 mBackColor; + LLRect mBackRectCamera1; + LLRect mBackRectCamera2; + void addText(S32 x, S32 y, const std::string &text) { mLineList.push_back(Line(text, x, y)); @@ -346,6 +444,12 @@ public: void update() { + if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { + clearText(); + return; + } + static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic", false) ; std::string wind_vel_text; @@ -360,6 +464,8 @@ public: static const std::string beacon_scripted_touch = LLTrans::getString("BeaconScriptedTouch"); static const std::string beacon_sound = LLTrans::getString("BeaconSound"); static const std::string beacon_media = LLTrans::getString("BeaconMedia"); + static const std::string beacon_sun = LLTrans::getString("BeaconSun"); + static const std::string beacon_moon = LLTrans::getString("BeaconMoon"); static const std::string particle_hiding = LLTrans::getString("ParticleHiding"); // Draw the statistics in a light gray @@ -367,11 +473,22 @@ public: mTextColor = LLColor4( 0.86f, 0.86f, 0.86f, 1.f ); // Draw stuff growing up from right lower corner of screen - S32 xpos = mWindow->getWorldViewWidthScaled() - 400; + S32 x_right = mWindow->getWorldViewWidthScaled(); + S32 xpos = x_right - 400; xpos = llmax(xpos, 0); S32 ypos = 64; const S32 y_inc = 20; + // Camera matrix text is hard to see again a white background + // Add a dark background underneath the matrices for readability (contrast) + mBackRectCamera1.mLeft = xpos; + mBackRectCamera1.mRight = x_right; + mBackRectCamera1.mTop = -1; + mBackRectCamera1.mBottom = -1; + mBackRectCamera2 = mBackRectCamera1; + + mBackColor = LLUIColorTable::instance().getColor( "MenuDefaultBgColor" ); + clearText(); if (gSavedSettings.getBOOL("DebugShowTime")) @@ -604,7 +721,7 @@ public: addText(xpos, ypos, llformat("%d Unique Textures", LLImageGL::sUniqueCount)); ypos += y_inc; - addText(xpos, ypos, llformat("%d Render Calls", last_frame_recording.getSampleCount(LLPipeline::sStatBatchSize))); + addText(xpos, ypos, llformat("%d Render Calls", (U32)last_frame_recording.getSampleCount(LLPipeline::sStatBatchSize))); ypos += y_inc; addText(xpos, ypos, llformat("%d/%d Objects Active", gObjectList.getNumActiveObjects(), gObjectList.getNumObjects())); @@ -707,48 +824,45 @@ public: } if (gSavedSettings.getBOOL("DebugShowRenderMatrices")) { - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[12], gGLProjection[13], gGLProjection[14], gGLProjection[15])); - ypos += y_inc; + char camera_lines[8][32]; + memset(camera_lines, ' ', sizeof(camera_lines)); - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[8], gGLProjection[9], gGLProjection[10], gGLProjection[11])); - ypos += y_inc; - - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[4], gGLProjection[5], gGLProjection[6], gGLProjection[7])); - ypos += y_inc; - - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[0], gGLProjection[1], gGLProjection[2], gGLProjection[3])); - ypos += y_inc; + // Projection last column is always <0,0,-1.0001,0> + // Projection last row is always <0,0,-0.2> + mBackRectCamera1.mBottom = ypos - y_inc + 2; + MATRIX_ROW_N32_TO_STR(gGLProjection, 12,camera_lines[7]); addText(xpos, ypos, std::string(camera_lines[7])); ypos += y_inc; + MATRIX_ROW_N32_TO_STR(gGLProjection, 8,camera_lines[6]); addText(xpos, ypos, std::string(camera_lines[6])); ypos += y_inc; + MATRIX_ROW_N32_TO_STR(gGLProjection, 4,camera_lines[5]); addText(xpos, ypos, std::string(camera_lines[5])); ypos += y_inc; mBackRectCamera1.mTop = ypos + 2; + MATRIX_ROW_N32_TO_STR(gGLProjection, 0,camera_lines[4]); addText(xpos, ypos, std::string(camera_lines[4])); ypos += y_inc; mBackRectCamera2.mBottom = ypos + 2; addText(xpos, ypos, "Projection Matrix"); ypos += y_inc; - - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[12], gGLModelView[13], gGLModelView[14], gGLModelView[15])); - ypos += y_inc; - - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[8], gGLModelView[9], gGLModelView[10], gGLModelView[11])); - ypos += y_inc; - - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[4], gGLModelView[5], gGLModelView[6], gGLModelView[7])); - ypos += y_inc; - - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[0], gGLModelView[1], gGLModelView[2], gGLModelView[3])); - ypos += y_inc; + // View last column is always <0,0,0,1> + MATRIX_ROW_F32_TO_STR(gGLModelView, 12,camera_lines[3]); addText(xpos, ypos, std::string(camera_lines[3])); ypos += y_inc; + MATRIX_ROW_N32_TO_STR(gGLModelView, 8,camera_lines[2]); addText(xpos, ypos, std::string(camera_lines[2])); ypos += y_inc; + MATRIX_ROW_N32_TO_STR(gGLModelView, 4,camera_lines[1]); addText(xpos, ypos, std::string(camera_lines[1])); ypos += y_inc; mBackRectCamera2.mTop = ypos + 2; + MATRIX_ROW_N32_TO_STR(gGLModelView, 0,camera_lines[0]); addText(xpos, ypos, std::string(camera_lines[0])); ypos += y_inc; addText(xpos, ypos, "View Matrix"); ypos += y_inc; } // disable use of glReadPixels which messes up nVidia nSight graphics debugging - if (gSavedSettings.getBOOL("DebugShowColor") && !LLRender::sNsightDebugSupport) - { - U8 color[4]; - LLCoordGL coord = gViewerWindow->getCurrentMouse(); - glReadPixels(coord.mX, coord.mY, 1,1,GL_RGBA, GL_UNSIGNED_BYTE, color); - addText(xpos, ypos, llformat("%d %d %d %d", color[0], color[1], color[2], color[3])); - ypos += y_inc; - } + if (gSavedSettings.getBOOL("DebugShowColor") && !LLRender::sNsightDebugSupport) + { + U8 color[4]; + LLCoordGL coord = gViewerWindow->getCurrentMouse(); + + // Convert x,y to raw pixel coords + S32 x_raw = llround(coord.mX * gViewerWindow->getWindowWidthRaw() / (F32) gViewerWindow->getWindowWidthScaled()); + S32 y_raw = llround(coord.mY * gViewerWindow->getWindowHeightRaw() / (F32) gViewerWindow->getWindowHeightScaled()); + + glReadPixels(x_raw, y_raw, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color); + addText(xpos, ypos, llformat("Pixel <%1d, %1d> R:%1d G:%1d B:%1d A:%1d", x_raw, y_raw, color[0], color[1], color[2], color[3])); + ypos += y_inc; + } - // only display these messages if we are actually rendering beacons at this moment + // only display these messages if we are actually rendering beacons at this moment if (LLPipeline::getRenderBeacons() && LLFloaterReg::instanceVisible("beacons")) { if (LLPipeline::getRenderMOAPBeacons()) @@ -794,6 +908,20 @@ public: } } + static LLUICachedControl<bool> show_sun_beacon("sunbeacon", false); + static LLUICachedControl<bool> show_moon_beacon("moonbeacon", false); + + if (show_sun_beacon) + { + addText(xpos, ypos, beacon_sun); + ypos += y_inc; + } + if (show_moon_beacon) + { + addText(xpos, ypos, beacon_moon); + ypos += y_inc; + } + if(log_texture_traffic) { U32 old_y = ypos ; @@ -861,6 +989,18 @@ public: void draw() { LL_RECORD_BLOCK_TIME(FTM_DISPLAY_DEBUG_TEXT); + + // Camera matrix text is hard to see again a white background + // Add a dark background underneath the matrices for readability (contrast) + if (mBackRectCamera1.mTop >= 0) + { + mBackColor.setAlpha( 0.75f ); + gl_rect_2d(mBackRectCamera1, mBackColor, true); + + mBackColor.setAlpha( 0.66f ); + gl_rect_2d(mBackRectCamera2, mBackColor, true); + } + for (line_list_t::iterator iter = mLineList.begin(); iter != mLineList.end(); ++iter) { @@ -869,7 +1009,6 @@ public: LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, /*use_ellipses*/FALSE, /*use_color*/FALSE); } - mLineList.clear(); } }; @@ -898,7 +1037,18 @@ LLViewerWindow::Params::Params() {} -BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down) +void LLViewerWindow::handlePieMenu(S32 x, S32 y, MASK mask) +{ + 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 + // menu tool. + LLToolPie::getInstance()->handleRightMouseDown(x, y, mask); + } +} + +BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down) { const char* buttonname = ""; const char* buttonstatestr = ""; @@ -922,22 +1072,30 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK switch (clicktype) { - case LLMouseHandler::CLICK_LEFT: + case CLICK_LEFT: mLeftMouseDown = down; buttonname = "Left"; break; - case LLMouseHandler::CLICK_RIGHT: + case CLICK_RIGHT: mRightMouseDown = down; buttonname = "Right"; break; - case LLMouseHandler::CLICK_MIDDLE: + case CLICK_MIDDLE: mMiddleMouseDown = down; buttonname = "Middle"; break; - case LLMouseHandler::CLICK_DOUBLELEFT: + case CLICK_DOUBLELEFT: mLeftMouseDown = down; buttonname = "Left Double Click"; break; + case CLICK_BUTTON4: + buttonname = "Button 4"; + break; + case CLICK_BUTTON5: + buttonname = "Button 5"; + break; + default: + break; // COUNT and NONE } LLView::sMouseHandlerMessage.clear(); @@ -960,7 +1118,7 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mWindow->releaseMouse(); // Indicate mouse was active - LLUI::resetMouseIdleTimer(); + LLUI::getInstance()->resetMouseIdleTimer(); // Don't let the user move the mouse out of the window until mouse up. if( LLToolMgr::getInstance()->getCurrentTool()->clipMouseWhenDown() ) @@ -988,6 +1146,11 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK LLViewerEventRecorder::instance().logMouseEvent(std::string(buttonstatestr),std::string(buttonname)); } + else if (down && clicktype == CLICK_RIGHT) + { + handlePieMenu(x, y, mask); + r = TRUE; + } return r; } @@ -1034,7 +1197,12 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK return TRUE; } - + if (down && clicktype == CLICK_RIGHT) + { + handlePieMenu(x, y, mask); + return TRUE; + } + // If we got this far on a down-click, it wasn't handled. // Up-clicks, though, are always handled as far as the OS is concerned. BOOL default_rtn = !down; @@ -1053,7 +1221,8 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask mMouseDownTimer.reset(); } BOOL down = TRUE; - return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); + //handleMouse() loops back to LLViewerWindow::handleAnyMouseClick + return gViewerInput.handleMouse(window, pos, mask, CLICK_LEFT, down); } BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask) @@ -1061,8 +1230,7 @@ BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK ma // try handling as a double-click first, then a single-click if that // wasn't handled. BOOL down = TRUE; - if (handleAnyMouseClick(window, pos, mask, - LLMouseHandler::CLICK_DOUBLELEFT, down)) + if (gViewerInput.handleMouse(window, pos, mask, CLICK_DOUBLELEFT, down)) { return TRUE; } @@ -1076,47 +1244,24 @@ BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) mMouseDownTimer.stop(); } BOOL down = FALSE; - return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); + return gViewerInput.handleMouse(window, pos, mask, CLICK_LEFT, down); } - - BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) { - S32 x = pos.mX; - S32 y = pos.mY; - x = ll_round((F32)x / mDisplayScale.mV[VX]); - y = ll_round((F32)y / mDisplayScale.mV[VY]); - BOOL down = TRUE; - BOOL handle = handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down); - if (handle) - return handle; - - // *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() && 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 - // menu tool. - LLToolPie::getInstance()->handleRightMouseDown(x, y, mask); - // show_context_menu( x, y, mask ); - } - - return TRUE; + return gViewerInput.handleMouse(window, pos, mask, CLICK_RIGHT, down); } BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { BOOL down = FALSE; - return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down); + return gViewerInput.handleMouse(window, pos, mask, CLICK_RIGHT, down); } BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) { BOOL down = TRUE; - LLVoiceClient::getInstance()->middleMouseState(true); - handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down); + gViewerInput.handleMouse(window, pos, mask, CLICK_MIDDLE, down); // Always handled as far as the OS is concerned. return TRUE; @@ -1267,17 +1412,44 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi return result; } - + BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { BOOL down = FALSE; - LLVoiceClient::getInstance()->middleMouseState(false); - handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down); + gViewerInput.handleMouse(window, pos, mask, CLICK_MIDDLE, down); // Always handled as far as the OS is concerned. return TRUE; } +BOOL LLViewerWindow::handleOtherMouse(LLWindow *window, LLCoordGL pos, MASK mask, S32 button, bool down) +{ + switch (button) + { + case 4: + gViewerInput.handleMouse(window, pos, mask, CLICK_BUTTON4, down); + break; + case 5: + gViewerInput.handleMouse(window, pos, mask, CLICK_BUTTON5, down); + break; + default: + break; + } + + // Always handled as far as the OS is concerned. + return TRUE; +} + +BOOL LLViewerWindow::handleOtherMouseDown(LLWindow *window, LLCoordGL pos, MASK mask, S32 button) +{ + return handleOtherMouse(window, pos, mask, button, TRUE); +} + +BOOL LLViewerWindow::handleOtherMouseUp(LLWindow *window, LLCoordGL pos, MASK mask, S32 button) +{ + return handleOtherMouse(window, pos, mask, button, FALSE); +} + // WARNING: this is potentially called multiple times per frame void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask) { @@ -1295,7 +1467,7 @@ void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask if (mouse_point != mCurrentMousePoint) { - LLUI::resetMouseIdleTimer(); + LLUI::getInstance()->resetMouseIdleTimer(); } saveLastMouse(mouse_point); @@ -1344,6 +1516,7 @@ BOOL LLViewerWindow::handleCloseRequest(LLWindow *window) void LLViewerWindow::handleQuit(LLWindow *window) { + LL_INFOS() << "Window forced quit" << LL_ENDL; LLAppViewer::instance()->forceQuit(); } @@ -1404,9 +1577,6 @@ void LLViewerWindow::handleFocusLost(LLWindow *window) BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated) { - // Let the voice chat code check for its PTT key. Note that this never affects event processing. - LLVoiceClient::getInstance()->keyDown(key, mask); - if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME) { gAgent.clearAFK(); @@ -1425,14 +1595,12 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated) return FALSE; } - return gViewerKeyboard.handleKey(key, mask, repeated); + // remaps, handles ignored cases and returns back to viewer window. + return gViewerInput.handleKey(key, mask, repeated); } 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); - // 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) @@ -1440,13 +1608,13 @@ BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask) tool_inspectp->keyUp(key, mask); } - return gViewerKeyboard.handleKeyUp(key, mask); + return gViewerInput.handleKeyUp(key, mask); } void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) { LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true); - gViewerKeyboard.scanKey(key, key_down, key_up, key_level); + gViewerInput.scanKey(key, key_down, key_up, key_level); return; // Be clear this function returns nothing } @@ -1551,6 +1719,11 @@ void LLViewerWindow::handleScrollWheel(LLWindow *window, S32 clicks) handleScrollWheel( clicks ); } +void LLViewerWindow::handleScrollHWheel(LLWindow *window, S32 clicks) +{ + handleScrollHWheel(clicks); +} + void LLViewerWindow::handleWindowBlock(LLWindow *window) { send_agent_pause(); @@ -1743,8 +1916,8 @@ LLViewerWindow::LLViewerWindow(const Params& p) ms_sleep(5000) ; //wait for 5 seconds. LLSplashScreen::update(LLTrans::getString("ShuttingDown")); -#if LL_LINUX || LL_SOLARIS - 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." +#if LL_LINUX + 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 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" @@ -1755,7 +1928,8 @@ LLViewerWindow::LLViewerWindow(const Params& p) if (!LLAppViewer::instance()->restoreErrorTrap()) { - LL_WARNS("Window") << " Someone took over my signal/exception handler (post createWindow)!" << LL_ENDL; + // this always happens, so downgrading it to INFO + LL_INFOS("Window") << " Someone took over my signal/exception handler (post createWindow; normal)" << LL_ENDL; } const bool do_not_enforce = false; @@ -1796,8 +1970,6 @@ LLViewerWindow::LLViewerWindow(const Params& p) // LL_DEBUGS("Window") << "Loading feature tables." << LL_ENDL; - LLFeatureManager::getInstance()->init(); - // Initialize OpenGL Renderer if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderVBOEnable") || !gGLManager.mHasVertexBufferObject) @@ -1852,7 +2024,7 @@ LLViewerWindow::LLViewerWindow(const Params& p) rvp.mouse_opaque(false); rvp.follows.flags(FOLLOWS_NONE); mRootView = LLUICtrlFactory::create<LLRootView>(rvp); - LLUI::setRootView(mRootView); + LLUI::getInstance()->setRootView(mRootView); // Make avatar head look forward at start mCurrentMousePoint.mX = getWindowWidthScaled() / 2; @@ -1953,6 +2125,11 @@ void LLViewerWindow::initBase() LLPanel* panel_holder = main_view->getChild<LLPanel>("toolbar_view_holder"); // Load the toolbar view from file gToolBarView = LLUICtrlFactory::getInstance()->createFromFile<LLToolBarView>("panel_toolbar_view.xml", panel_holder, LLDefaultChildRegistry::instance()); + if (!gToolBarView) + { + LL_ERRS() << "Failed to initialize viewer: Viewer couldn't process file panel_toolbar_view.xml, " + << "if this problem happens again, please validate your installation." << LL_ENDL; + } gToolBarView->setShape(panel_holder->getLocalRect()); // Hide the toolbars for the moment: we'll make them visible after logging in world (see LLViewerWindow::initWorldUI()) gToolBarView->setVisible(FALSE); @@ -2256,7 +2433,6 @@ void LLViewerWindow::shutdownGL() LLViewerWindow::~LLViewerWindow() { LL_INFOS() << "Destroying Window" << LL_ENDL; - gDebugWindowProc = TRUE; // event catching, at this point it shouldn't output at all destroyWindow(); delete mDebugText; @@ -2347,6 +2523,11 @@ void LLViewerWindow::reshape(S32 width, S32 height) // round up when converting coordinates to make sure there are no gaps at edge of window LLView::sForceReshape = display_scale_changed; mRootView->reshape(llceil((F32)width / mDisplayScale.mV[VX]), llceil((F32)height / mDisplayScale.mV[VY])); + if (display_scale_changed) + { + // Needs only a 'scale change' update, everything else gets handled by LLLayoutStack::updateClass() + LLPanelLogin::reshapePanel(); + } LLView::sForceReshape = FALSE; // clear font width caches @@ -2410,7 +2591,7 @@ void LLViewerWindow::setNormalControlsVisible( BOOL visible ) gStatusBar->setEnabled( visible ); } - LLNavigationBar* navbarp = LLUI::getRootView()->findChild<LLNavigationBar>("navigation_bar"); + LLNavigationBar* navbarp = LLUI::getInstance()->getRootView()->findChild<LLNavigationBar>("navigation_bar"); if (navbarp) { // when it's time to show navigation bar we need to ensure that the user wants to see it @@ -2438,7 +2619,7 @@ void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid) } else { - switch (LLVersionInfo::getViewerMaturity()) + switch (LLVersionInfo::instance().getViewerMaturity()) { case LLVersionInfo::TEST_VIEWER: new_bg_color = LLUIColorTable::instance().getColor( "MenuBarTestBgColor" ); @@ -2520,7 +2701,7 @@ void LLViewerWindow::draw() if (!gSavedSettings.getBOOL("RenderUIBuffer")) { - LLUI::sDirtyRect = getWindowRectScaled(); + LLView::sDirtyRect = getWindowRectScaled(); } // HACK for timecode debugging @@ -2635,6 +2816,13 @@ void LLViewerWindow::draw() // Takes a single keyup event, usually when UI is visible BOOL LLViewerWindow::handleKeyUp(KEY key, MASK mask) { + if (LLSetKeyBindDialog::recordKey(key, mask, FALSE)) + { + LL_DEBUGS() << "KeyUp handled by LLSetKeyBindDialog" << LL_ENDL; + LLViewerEventRecorder::instance().logKeyEvent(key, mask); + return TRUE; + } + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); if (keyboard_focus @@ -2678,23 +2866,74 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) // hide tooltips on keypress LLToolTipMgr::instance().blockToolTips(); - LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); + // Menus get handled on key down instead of key up + // so keybindings have to be recorded before that + if (LLSetKeyBindDialog::recordKey(key, mask, TRUE)) + { + LL_DEBUGS() << "Key handled by LLSetKeyBindDialog" << LL_ENDL; + LLViewerEventRecorder::instance().logKeyEvent(key,mask); + return TRUE; + } + 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()) + && !gFocusMgr.getKeystrokesOnly()) + { +#ifdef LL_WINDOWS + // On windows Alt Gr key generates additional Ctrl event, as result handling situations + // like 'AltGr + D' will result in 'Alt+Ctrl+D'. If it results in WM_CHAR, don't let it + // pass into menu or it will trigger 'develop' menu assigned to this combination on top + // of character handling. + // Alt Gr can be additionally modified by Shift + const MASK alt_gr = MASK_CONTROL | MASK_ALT; + if ((mask & alt_gr) != 0 + && key >= 0x30 + && key <= 0x5A + && (GetKeyState(VK_RMENU) & 0x8000) != 0 + && (GetKeyState(VK_RCONTROL) & 0x8000) == 0) // ensure right control is not pressed, only left one + { + // Alt Gr key is represented as right alt and left control. + // Any alt+ctrl combination is treated as Alt Gr by TranslateMessage() and + // will generate a WM_CHAR message, but here we only treat virtual Alt Graph + // key by checking if this specific combination has unicode char. + // + // I decided to handle only virtual RAlt+LCtrl==AltGr combination to minimize + // impact on menu, but the right way might be to handle all Alt+Ctrl calls. + + BYTE keyboard_state[256]; + if (GetKeyboardState(keyboard_state)) + { + const int char_count = 6; + wchar_t chars[char_count]; + HKL layout = GetKeyboardLayout(0); + // ToUnicodeEx changes buffer state on OS below Win10, which is undesirable, + // but since we already did a TranslateMessage() in gatherInput(), this + // should have no negative effect + int res = ToUnicodeEx(key, 0, keyboard_state, chars, char_count, 1 << 2 /*do not modify buffer flag*/, layout); + if (res == 1 && chars[0] >= 0x20) + { + // Let it fall through to character handler and get a WM_CHAR. + return TRUE; + } + } + } +#endif + + if (!(mask & (MASK_CONTROL | MASK_ALT))) { - return keyboard_focus->handleKey(key, mask, FALSE ); + // We have keyboard focus, and it's not an accelerator + if (keyboard_focus && keyboard_focus->wantsKeyUpKeyDown()) + { + return keyboard_focus->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 TRUE; + } } - 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 (keyboard_focus != NULL); - } - } + } // let menus handle navigation keys for navigation if ((gMenuBarView && gMenuBarView->handleKey(key, mask, TRUE)) @@ -2838,7 +3077,8 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) // 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.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() && + if ( LLStartUp::getStartupState() >= STATE_STARTED && + gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() && !keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) ) { // Initialize nearby chat if it's missing @@ -2892,7 +3132,8 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask) { if (mask != MASK_ALT) { - return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN)); + // remaps, handles ignored cases and returns back to viewer window. + return gViewerInput.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN)); } } @@ -2920,7 +3161,7 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask) void LLViewerWindow::handleScrollWheel(S32 clicks) { - LLUI::resetMouseIdleTimer(); + LLUI::getInstance()->resetMouseIdleTimer(); LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); if( mouse_captor ) @@ -2968,6 +3209,49 @@ void LLViewerWindow::handleScrollWheel(S32 clicks) return; } +void LLViewerWindow::handleScrollHWheel(S32 clicks) +{ + LLUI::getInstance()->resetMouseIdleTimer(); + + LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); + if (mouse_captor) + { + S32 local_x; + S32 local_y; + mouse_captor->screenPointToLocal(mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y); + mouse_captor->handleScrollHWheel(local_x, local_y, clicks); + if (LLView::sDebugMouseHandling) + { + LL_INFOS() << "Scroll Horizontal Wheel handled by captor " << mouse_captor->getName() << LL_ENDL; + } + return; + } + + LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); + if (top_ctrl) + { + S32 local_x; + S32 local_y; + top_ctrl->screenPointToLocal(mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y); + if (top_ctrl->handleScrollHWheel(local_x, local_y, clicks)) return; + } + + if (mRootView->handleScrollHWheel(mCurrentMousePoint.mX, mCurrentMousePoint.mY, clicks)) + { + if (LLView::sDebugMouseHandling) + { + LL_INFOS() << "Scroll Horizontal Wheel" << LLView::sMouseHandlerMessage << LL_ENDL; + } + return; + } + else if (LLView::sDebugMouseHandling) + { + LL_INFOS() << "Scroll Horizontal Wheel not handled by view" << LL_ENDL; + } + + return; +} + void LLViewerWindow::addPopup(LLView* popup) { if (mPopupView) @@ -2999,7 +3283,7 @@ void LLViewerWindow::moveCursorToCenter() S32 x = getWorldViewWidthScaled() / 2; S32 y = getWorldViewHeightScaled() / 2; - LLUI::setMousePositionScreen(x, y); + LLUI::getInstance()->setMousePositionScreen(x, y); //on a forced move, all deltas get zeroed out to prevent jumping mCurrentMousePoint.set(x,y); @@ -3331,7 +3615,8 @@ void LLViewerWindow::updateUI() LLRect screen_sticky_rect = mRootView->getLocalRect(); S32 local_x, local_y; - if (gSavedSettings.getBOOL("DebugShowXUINames")) + static LLCachedControl<bool> debug_show_xui_names(gSavedSettings, "DebugShowXUINames", 0); + if (debug_show_xui_names) { LLToolTip::Params params; @@ -3772,7 +4057,7 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, F32 scale = vovolume->getLightRadius(); gGL.scalef(scale, scale, scale); - LLColor4 color(vovolume->getLightColor(), .5f); + LLColor4 color(vovolume->getLightSRGBColor(), .5f); gGL.color4fv(color.mV); //F32 pixel_area = 100000.f; @@ -3819,12 +4104,12 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, BOOL draw_handles = TRUE; - if (tool == LLToolCompTranslate::getInstance() && !all_selected_objects_move && !LLSelectMgr::getInstance()->isSelfAvatarSelected()) + if (tool == LLToolCompTranslate::getInstance() && !all_selected_objects_move && !LLSelectMgr::getInstance()->isMovableAvatarSelected()) { draw_handles = FALSE; } - if (tool == LLToolCompRotate::getInstance() && !all_selected_objects_move) + if (tool == LLToolCompRotate::getInstance() && !all_selected_objects_move && !LLSelectMgr::getInstance()->isMovableAvatarSelected()) { draw_handles = FALSE; } @@ -4487,12 +4772,12 @@ 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, LLSnapshotModel::ESnapshotLayerType type, LLSnapshotModel::ESnapshotFormat format) +BOOL LLViewerWindow::saveSnapshot(const std::string& filepath, S32 image_width, S32 image_height, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type, LLSnapshotModel::ESnapshotFormat format) { LL_INFOS() << "Saving snapshot to: " << filepath << LL_ENDL; LLPointer<LLImageRaw> raw = new LLImageRaw; - BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, do_rebuild); + BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, show_hud, do_rebuild); if (success) { @@ -4551,26 +4836,22 @@ void LLViewerWindow::resetSnapshotLoc() const gSavedPerAccountSettings.setString("SnapshotBaseDir", std::string()); } -BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type) +BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type) { - return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, do_rebuild, type); + return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, show_hud, do_rebuild, type); } // Saves the image from the screen to a raw image // Since the required size might be bigger than the available screen, this method rerenders the scene in parts (called subimages) and copy // the results over to the final raw image. BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, - BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type, S32 max_size) + BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type, S32 max_size) { if (!raw) { return FALSE; } //check if there is enough memory for the snapshot image - if(LLPipeline::sMemAllocationThrottled) - { - return FALSE ; //snapshot taking is disabled due to memory restriction. - } if(image_width * image_height > (1 << 22)) //if snapshot image is larger than 2K by 2K { if(!LLMemory::tryToAlloc(NULL, image_width * image_height * 3)) @@ -4594,7 +4875,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI); } - BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && LLPipeline::sShowHUDAttachments; + BOOL hide_hud = !show_hud && LLPipeline::sShowHUDAttachments; if (hide_hud) { LLPipeline::sShowHUDAttachments = FALSE; @@ -4634,7 +4915,8 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei if ((image_width <= gGLManager.mGLMaxTextureSize && image_height <= gGLManager.mGLMaxTextureSize) && (image_width > window_width || image_height > window_height) && LLPipeline::sRenderDeferred && !show_ui) { - if (scratch_space.allocate(image_width, image_height, GL_DEPTH_COMPONENT, true, true)) + U32 color_fmt = type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGBA; + if (scratch_space.allocate(image_width, image_height, color_fmt, true, true)) { original_width = gPipeline.mDeferredScreen.getWidth(); original_height = gPipeline.mDeferredScreen.getHeight(); @@ -4748,7 +5030,6 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei { // Required for showing the GUI in snapshots and performing bloom composite overlay // Call even if show_ui is FALSE - LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); render_ui(scale_factor, subfield); swap(); } @@ -5014,6 +5295,14 @@ void LLViewerWindow::revealIntroPanel() } } +void LLViewerWindow::initTextures(S32 location_id) +{ + if (mProgressView) + { + mProgressView->initTextures(location_id, LLGridManager::getInstance()->isInProductionGrid()); + } +} + void LLViewerWindow::setShowProgress(const BOOL show) { if (mProgressView) @@ -5067,7 +5356,6 @@ void LLViewerWindow::setProgressCancelButtonVisible( BOOL b, const std::string& } } - LLProgressView *LLViewerWindow::getProgressView() const { return mProgressView; diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 071a3632dd..8a6df613dc 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -137,7 +137,7 @@ private: }; -static const U32 MAX_SNAPSHOT_IMAGE_SIZE = 6 * 1024; // max snapshot image size 6144 * 6144 +static const U32 MAX_SNAPSHOT_IMAGE_SIZE = 7680; // max snapshot image size 7680 * 7680 UHDTV2 class LLViewerWindow : public LLWindowCallbacks { @@ -175,8 +175,9 @@ public: void initWorldUI(); void setUIVisibility(bool); bool getUIVisibility(); + void handlePieMenu(S32 x, S32 y, MASK mask); - BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down); + BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down); // // LLWindowCallback interface implementation @@ -192,7 +193,10 @@ public: /*virtual*/ BOOL handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); - /*virtual*/ BOOL handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); + /*virtual*/ BOOL handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); + /*virtual*/ BOOL handleOtherMouseDown(LLWindow *window, LLCoordGL pos, MASK mask, S32 button); + /*virtual*/ BOOL handleOtherMouseUp(LLWindow *window, LLCoordGL pos, MASK mask, S32 button); + BOOL handleOtherMouse(LLWindow *window, LLCoordGL pos, MASK mask, S32 button, bool down); /*virtual*/ LLWindowCallbacks::DragNDropResult handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, LLWindowCallbacks::DragNDropAction action, std::string data); void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); void handleMouseDragged(LLWindow *window, LLCoordGL pos, MASK mask); @@ -205,6 +209,7 @@ public: /*virtual*/ void handleMenuSelect(LLWindow *window, S32 menu_item); /*virtual*/ BOOL handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height); /*virtual*/ void handleScrollWheel(LLWindow *window, S32 clicks); + /*virtual*/ void handleScrollHWheel(LLWindow *window, S32 clicks); /*virtual*/ BOOL handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ void handleWindowBlock(LLWindow *window); /*virtual*/ void handleWindowUnblock(LLWindow *window); @@ -299,6 +304,7 @@ public: BOOL getCursorHidden() { return mCursorHidden; } void moveCursorToCenter(); // move to center of window + void initTextures(S32 location_id); void setShowProgress(const BOOL show); BOOL getShowProgress() const; void setProgressString(const std::string& string); @@ -323,6 +329,7 @@ public: BOOL handleKey(KEY key, MASK mask); BOOL handleKeyUp(KEY key, MASK mask); void handleScrollWheel (S32 clicks); + void handleScrollHWheel (S32 clicks); // add and remove views from "popup" layer void addPopup(LLView* popup); @@ -347,10 +354,10 @@ public: // snapshot functionality. // perhaps some of this should move to llfloatershapshot? -MG - BOOL saveSnapshot(const std::string& filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::ESnapshotFormat format = LLSnapshotModel::SNAPSHOT_FORMAT_BMP); + BOOL saveSnapshot(const std::string& filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL show_hud = TRUE, BOOL do_rebuild = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::ESnapshotFormat format = LLSnapshotModel::SNAPSHOT_FORMAT_BMP); BOOL rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect = TRUE, BOOL is_texture = FALSE, - BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE); - BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type); + BOOL show_ui = TRUE, BOOL show_hud = TRUE, BOOL do_rebuild = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE); + BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type); BOOL isSnapshotLocSet() const; void resetSnapshotLoc() const; diff --git a/indra/newview/llviewerwindowlistener.cpp b/indra/newview/llviewerwindowlistener.cpp index 97b405c1d0..acf25b9792 100644 --- a/indra/newview/llviewerwindowlistener.cpp +++ b/indra/newview/llviewerwindowlistener.cpp @@ -50,10 +50,11 @@ LLViewerWindowListener::LLViewerWindowListener(LLViewerWindow* llviewerwindow): // saveSnapshotArgs["width"] = LLSD::Integer(); // saveSnapshotArgs["height"] = LLSD::Integer(); // saveSnapshotArgs["showui"] = LLSD::Boolean(); +// saveSnapshotArgs["showhud"] = LLSD::Boolean(); // saveSnapshotArgs["rebuild"] = LLSD::Boolean(); // saveSnapshotArgs["type"] = LLSD::String(); add("saveSnapshot", - "Save screenshot: [\"filename\"], [\"width\"], [\"height\"], [\"showui\"], [\"rebuild\"], [\"type\"]\n" + "Save screenshot: [\"filename\"], [\"width\"], [\"height\"], [\"showui\"], [\"showhud\"], [\"rebuild\"], [\"type\"]\n" "type: \"COLOR\", \"DEPTH\"\n" "Post on [\"reply\"] an event containing [\"ok\"]", &LLViewerWindowListener::saveSnapshot, @@ -83,6 +84,9 @@ void LLViewerWindowListener::saveSnapshot(const LLSD& event) const bool showui = true; if (event.has("showui")) showui = event["showui"].asBoolean(); + bool showhud = true; + if (event.has("showhud")) + showhud = event["showhud"].asBoolean(); bool rebuild(event["rebuild"]); // defaults to false LLSnapshotModel::ESnapshotLayerType type(LLSnapshotModel::SNAPSHOT_TYPE_COLOR); if (event.has("type")) @@ -96,7 +100,7 @@ void LLViewerWindowListener::saveSnapshot(const LLSD& event) const } type = found->second; } - bool ok = mViewerWindow->saveSnapshot(event["filename"], width, height, showui, rebuild, type); + bool ok = mViewerWindow->saveSnapshot(event["filename"], width, height, showui, showhud, rebuild, type); sendReply(LLSDMap("ok", ok), event); } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index b5db5d4a48..e085a945a8 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -38,6 +38,7 @@ #include "raytrace.h" #include "llagent.h" // Get state values from here +#include "llagentbenefits.h" #include "llagentcamera.h" #include "llagentwearables.h" #include "llanimationstates.h" @@ -78,6 +79,7 @@ #include "llselectmgr.h" #include "llsprite.h" #include "lltargetingmotion.h" +#include "lltoolmgr.h" #include "lltoolmorph.h" #include "llviewercamera.h" #include "llviewertexlayer.h" @@ -196,6 +198,8 @@ const F32 NAMETAG_VERT_OFFSET_WEIGHT = 0.17f; const U32 LLVOAvatar::VISUAL_COMPLEXITY_UNKNOWN = 0; const F64 HUD_OVERSIZED_TEXTURE_DATA_SIZE = 1024 * 1024; +const F32 MAX_TEXTURE_WAIT_TIME_SEC = 60; + enum ERenderName { RENDER_NAME_NEVER, @@ -203,6 +207,8 @@ enum ERenderName RENDER_NAME_FADE }; +#define JELLYDOLLS_SHOULD_IMPOSTOR + //----------------------------------------------------------------------------- // Callback data //----------------------------------------------------------------------------- @@ -569,9 +575,9 @@ private: //----------------------------------------------------------------------------- // Static Data //----------------------------------------------------------------------------- -LLAvatarAppearanceDictionary *LLVOAvatar::sAvatarDictionary = NULL; S32 LLVOAvatar::sFreezeCounter = 0; -U32 LLVOAvatar::sMaxNonImpostors = 12; // overridden based on graphics setting +U32 LLVOAvatar::sMaxNonImpostors = 12; // Set from RenderAvatarMaxNonImpostors +bool LLVOAvatar::sLimitNonImpostors = false; // True unless RenderAvatarMaxNonImpostors is 0 (unlimited) F32 LLVOAvatar::sRenderDistance = 256.f; S32 LLVOAvatar::sNumVisibleAvatars = 0; S32 LLVOAvatar::sNumLODChangesThisFrame = 0; @@ -598,7 +604,6 @@ BOOL LLVOAvatar::sShowFootPlane = FALSE; BOOL LLVOAvatar::sVisibleInFirstPerson = FALSE; F32 LLVOAvatar::sLODFactor = 1.f; F32 LLVOAvatar::sPhysicsLODFactor = 1.f; -bool LLVOAvatar::sUseImpostors = false; // overwridden by RenderAvatarMaxNonImpostors BOOL LLVOAvatar::sJointDebug = FALSE; F32 LLVOAvatar::sUnbakedTime = 0.f; F32 LLVOAvatar::sUnbakedUpdateTime = 0.f; @@ -631,6 +636,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mMeshValid(FALSE), mVisible(FALSE), mLastImpostorUpdateFrameTime(0.f), + mLastImpostorUpdateReason(0), mWindFreq(0.f), mRipplePhase( 0.f ), mBelowWater(FALSE), @@ -653,6 +659,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mNeedsSkin(FALSE), mLastSkinTime(0.f), mUpdatePeriod(1), + mOverallAppearance(AOA_INVISIBLE), mVisualComplexityStale(true), mVisuallyMuteSetting(AV_RENDER_NORMALLY), mMutedAVColor(LLColor4::white /* used for "uninitialize" */), @@ -662,6 +669,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mFullyLoadedInitialized(FALSE), mVisualComplexity(VISUAL_COMPLEXITY_UNKNOWN), mLoadedCallbacksPaused(FALSE), + mLoadedCallbackTextures(0), mRenderUnloadedAvatar(LLCachedControl<bool>(gSavedSettings, "RenderUnloadedAvatar", false)), mLastRezzedStatus(-1), mIsEditingAppearance(FALSE), @@ -696,6 +704,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, setAnimationData("Speed", &mSpeed); mNeedsImpostorUpdate = TRUE; + mLastImpostorUpdateReason = 0; mNeedsAnimUpdate = TRUE; mNeedsExtentUpdate = true; @@ -751,8 +760,8 @@ std::string LLVOAvatar::avString() const } else { - std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus()); - return " Avatar '" + getFullname() + "' " + viz_string + " "; + std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus()); + return " Avatar '" + getFullname() + "' " + viz_string + " "; } } @@ -882,8 +891,9 @@ BOOL LLVOAvatar::hasGray() const S32 LLVOAvatar::getRezzedStatus() const { if (getIsCloud()) return 0; - if (isFullyTextured() && allBakedTexturesCompletelyDownloaded()) return 3; - if (isFullyTextured()) return 2; + bool textured = isFullyTextured(); + if (textured && allBakedTexturesCompletelyDownloaded()) return 3; + if (textured) return 2; llassert(hasGray()); return 1; // gray } @@ -1019,15 +1029,15 @@ void LLVOAvatar::dumpBakedStatus() { LL_CONT << " Unbaked ("; - for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin(); - iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); + for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator iter = LLAvatarAppearance::getDictionary()->getBakedTextures().begin(); + iter != LLAvatarAppearance::getDictionary()->getBakedTextures().end(); ++iter) { const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = iter->second; const ETextureIndex index = baked_dict->mTextureIndex; if (!inst->isTextureDefined(index)) { - LL_CONT << " " << (LLAvatarAppearanceDictionary::getInstance()->getTexture(index) ? LLAvatarAppearanceDictionary::getInstance()->getTexture(index)->mName : ""); + LL_CONT << " " << (LLAvatarAppearance::getDictionary()->getTexture(index) ? LLAvatarAppearance::getDictionary()->getTexture(index)->mName : ""); } } LL_CONT << " ) " << inst->getUnbakedPixelAreaRank(); @@ -1070,6 +1080,7 @@ void LLVOAvatar::resetImpostors() LLVOAvatar* avatar = (LLVOAvatar*) *iter; avatar->mImpostor.release(); avatar->mNeedsImpostorUpdate = TRUE; + avatar->mLastImpostorUpdateReason = 1; } } @@ -1113,6 +1124,7 @@ void LLVOAvatar::initClass() LLJoint::setDebugJointNames(gSavedSettings.getString("DebugAvatarJoints")); LLControlAvatar::sRegionChangedSlot = gAgent.addRegionChangedCallback(&LLControlAvatar::onRegionChanged); + } @@ -1313,72 +1325,84 @@ void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) LL_RECORD_BLOCK_TIME(FTM_AVATAR_EXTENT_UPDATE); S32 box_detail = gSavedSettings.getS32("AvatarBoundingBoxComplexity"); + if (getOverallAppearance() != AOA_NORMAL) + { + if (isControlAvatar()) + { + // Animated objects don't show system avatar but do need to include rigged meshes in their bounding box. + box_detail = 3; + } + else + { + // Jellydolled avatars ignore attachments, etc, use only system avatar. + box_detail = 1; + } + } // 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; + LLVector4a pos; if (dist_vec(zero_pos, mPelvisp->getWorldPosition())<0.001) { // Don't use pelvis until av initialized - pos.load3(getRenderPosition().mV); + pos.load3(getRenderPosition().mV); } else { pos.load3(mPelvisp->getWorldPosition().mV); } - newMin = pos; - newMax = pos; + 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()) + if (box_detail>=1 && !isControlAvatar()) { - 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.size(); joint_num++) - { - LLVector4a trans; - trans.load3( mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation().mV); - update_min_max(newMin, newMax, trans); - } - } - + //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). + 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.size(); joint_num++) + { + LLVector4a trans; + trans.load3( mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation().mV); + 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); + // 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); - //stretch bounding box by static attachments + //stretch bounding box by static attachments if (box_detail >= 2) { float max_attachment_span = get_default_max_prim_scale() * 5.0f; - - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; + + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; - if (attachment->getValid()) - { - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { + if (attachment->getValid()) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { // Don't we need to look at children of attached_object as well? - const LLViewerObject* attached_object = (*attachment_iter); - if (attached_object && !attached_object->isHUDAttachment()) - { + const LLViewerObject* attached_object = attachment_iter->get(); + if (attached_object && !attached_object->isHUDAttachment()) + { const LLVOVolume *vol = dynamic_cast<const LLVOVolume*>(attached_object); if (vol && vol->isAnimatedObject()) { @@ -1400,39 +1424,39 @@ void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) { continue; } - LLDrawable* drawable = attached_object->mDrawable; - if (drawable && !drawable->isState(LLDrawable::RIGGED)) - { - 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]); - } - } - } - } - } - } - } + LLDrawable* drawable = attached_object->mDrawable; + if (drawable && !drawable->isState(LLDrawable::RIGGED)) + { + 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]); + } + } + } + } + } + } + } } // Stretch bounding box by rigged mesh joint boxes if (box_detail>=3) { - updateRiggingInfo(); + updateRiggingInfo(); for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++) { LLJoint *joint = getJoint(joint_num); @@ -1572,13 +1596,16 @@ void LLVOAvatar::renderCollisionVolumes() } } -void LLVOAvatar::renderBones() +void LLVOAvatar::renderBones(const std::string &selected_joint) { LLGLEnable blend(GL_BLEND); avatar_joint_list_t::iterator iter = mSkeleton.begin(); - avatar_joint_list_t::iterator end = mSkeleton.end(); + avatar_joint_list_t::iterator end = mSkeleton.end(); + // For selected joints + static LLVector3 SELECTED_COLOR_OCCLUDED(1.0f, 1.0f, 0.0f); + static LLVector3 SELECTED_COLOR_VISIBLE(0.5f, 0.5f, 0.5f); // 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); @@ -1605,7 +1632,18 @@ void LLVOAvatar::renderBones() LLVector3 pos; LLUUID mesh_id; - if (jointp->hasAttachmentPosOverride(pos,mesh_id)) + F32 sphere_scale = SPHERE_SCALEF; + + // We are in render, so it is preferable to implement selection + // in a different way, but since this is for debug/preview, this + // is low priority + if (jointp->getName() == selected_joint) + { + sphere_scale *= 16; + occ_color = SELECTED_COLOR_OCCLUDED; + visible_color = SELECTED_COLOR_VISIBLE; + } + else if (jointp->hasAttachmentPosOverride(pos,mesh_id)) { occ_color = OVERRIDE_COLOR_OCCLUDED; visible_color = OVERRIDE_COLOR_VISIBLE; @@ -1626,7 +1664,6 @@ void LLVOAvatar::renderBones() LLVector3 begin_pos(0,0,0); LLVector3 end_pos(jointp->getEnd()); - F32 sphere_scale = SPHERE_SCALEF; gGL.pushMatrix(); gGL.multMatrix( &jointp->getXform()->getWorldMatrix().mMatrix[0][0] ); @@ -1799,7 +1836,7 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - LLViewerObject* attached_object = (*attachment_iter); + LLViewerObject* attached_object = attachment_iter->get(); if (attached_object && !attached_object->isDead() && attachment->getValid()) { @@ -1863,7 +1900,7 @@ LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - LLViewerObject* attached_object = (*attachment_iter); + LLViewerObject* attached_object = attachment_iter->get(); if (attached_object->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, face_hit, &local_intersection, tex_coord, normal, tangent)) { @@ -2005,6 +2042,38 @@ void LLVOAvatar::resetVisualParams() } } +void LLVOAvatar::applyDefaultParams() +{ + // These are params from avs with newly created copies of shape, + // skin, hair, eyes, plus gender set as noted. Run arche_tool.py + // to get params from some other xml appearance dump. + std::map<S32, U8> male_params = { + {1,33}, {2,61}, {4,85}, {5,23}, {6,58}, {7,127}, {8,63}, {10,85}, {11,63}, {12,42}, {13,0}, {14,85}, {15,63}, {16,36}, {17,85}, {18,95}, {19,153}, {20,63}, {21,34}, {22,0}, {23,63}, {24,109}, {25,88}, {27,132}, {31,63}, {33,136}, {34,81}, {35,85}, {36,103}, {37,136}, {38,127}, {80,255}, {93,203}, {98,0}, {99,0}, {105,127}, {108,0}, {110,0}, {111,127}, {112,0}, {113,0}, {114,127}, {115,0}, {116,0}, {117,0}, {119,127}, {130,114}, {131,127}, {132,99}, {133,63}, {134,127}, {135,140}, {136,127}, {137,127}, {140,0}, {141,0}, {142,0}, {143,191}, {150,0}, {155,104}, {157,0}, {162,0}, {163,0}, {165,0}, {166,0}, {167,0}, {168,0}, {169,0}, {177,0}, {181,145}, {182,216}, {183,133}, {184,0}, {185,127}, {192,0}, {193,127}, {196,170}, {198,0}, {503,0}, {505,127}, {506,127}, {507,109}, {508,85}, {513,127}, {514,127}, {515,63}, {517,85}, {518,42}, {603,100}, {604,216}, {605,214}, {606,204}, {607,204}, {608,204}, {609,51}, {616,25}, {617,89}, {619,76}, {624,204}, {625,0}, {629,127}, {637,0}, {638,0}, {646,144}, {647,85}, {649,127}, {650,132}, {652,127}, {653,85}, {654,0}, {656,127}, {659,127}, {662,127}, {663,127}, {664,127}, {665,127}, {674,59}, {675,127}, {676,85}, {678,127}, {682,127}, {683,106}, {684,47}, {685,79}, {690,127}, {692,127}, {693,204}, {700,63}, {701,0}, {702,0}, {703,0}, {704,0}, {705,127}, {706,127}, {707,0}, {708,0}, {709,0}, {710,0}, {711,127}, {712,0}, {713,159}, {714,0}, {715,0}, {750,178}, {752,127}, {753,36}, {754,85}, {755,131}, {756,127}, {757,127}, {758,127}, {759,153}, {760,95}, {762,0}, {763,140}, {764,74}, {765,27}, {769,127}, {773,127}, {775,0}, {779,214}, {780,204}, {781,198}, {785,0}, {789,0}, {795,63}, {796,30}, {799,127}, {800,226}, {801,255}, {802,198}, {803,255}, {804,255}, {805,255}, {806,255}, {807,255}, {808,255}, {812,255}, {813,255}, {814,255}, {815,204}, {816,0}, {817,255}, {818,255}, {819,255}, {820,255}, {821,255}, {822,255}, {823,255}, {824,255}, {825,255}, {826,255}, {827,255}, {828,0}, {829,255}, {830,255}, {834,255}, {835,255}, {836,255}, {840,0}, {841,127}, {842,127}, {844,255}, {848,25}, {858,100}, {859,255}, {860,255}, {861,255}, {862,255}, {863,84}, {868,0}, {869,0}, {877,0}, {879,51}, {880,132}, {921,255}, {922,255}, {923,255}, {10000,0}, {10001,0}, {10002,25}, {10003,0}, {10004,25}, {10005,23}, {10006,51}, {10007,0}, {10008,25}, {10009,23}, {10010,51}, {10011,0}, {10012,0}, {10013,25}, {10014,0}, {10015,25}, {10016,23}, {10017,51}, {10018,0}, {10019,0}, {10020,25}, {10021,0}, {10022,25}, {10023,23}, {10024,51}, {10025,0}, {10026,25}, {10027,23}, {10028,51}, {10029,0}, {10030,25}, {10031,23}, {10032,51}, {11000,1}, {11001,127} + }; + std::map<S32, U8> female_params = { + {1,33}, {2,61}, {4,85}, {5,23}, {6,58}, {7,127}, {8,63}, {10,85}, {11,63}, {12,42}, {13,0}, {14,85}, {15,63}, {16,36}, {17,85}, {18,95}, {19,153}, {20,63}, {21,34}, {22,0}, {23,63}, {24,109}, {25,88}, {27,132}, {31,63}, {33,136}, {34,81}, {35,85}, {36,103}, {37,136}, {38,127}, {80,0}, {93,203}, {98,0}, {99,0}, {105,127}, {108,0}, {110,0}, {111,127}, {112,0}, {113,0}, {114,127}, {115,0}, {116,0}, {117,0}, {119,127}, {130,114}, {131,127}, {132,99}, {133,63}, {134,127}, {135,140}, {136,127}, {137,127}, {140,0}, {141,0}, {142,0}, {143,191}, {150,0}, {155,104}, {157,0}, {162,0}, {163,0}, {165,0}, {166,0}, {167,0}, {168,0}, {169,0}, {177,0}, {181,145}, {182,216}, {183,133}, {184,0}, {185,127}, {192,0}, {193,127}, {196,170}, {198,0}, {503,0}, {505,127}, {506,127}, {507,109}, {508,85}, {513,127}, {514,127}, {515,63}, {517,85}, {518,42}, {603,100}, {604,216}, {605,214}, {606,204}, {607,204}, {608,204}, {609,51}, {616,25}, {617,89}, {619,76}, {624,204}, {625,0}, {629,127}, {637,0}, {638,0}, {646,144}, {647,85}, {649,127}, {650,132}, {652,127}, {653,85}, {654,0}, {656,127}, {659,127}, {662,127}, {663,127}, {664,127}, {665,127}, {674,59}, {675,127}, {676,85}, {678,127}, {682,127}, {683,106}, {684,47}, {685,79}, {690,127}, {692,127}, {693,204}, {700,63}, {701,0}, {702,0}, {703,0}, {704,0}, {705,127}, {706,127}, {707,0}, {708,0}, {709,0}, {710,0}, {711,127}, {712,0}, {713,159}, {714,0}, {715,0}, {750,178}, {752,127}, {753,36}, {754,85}, {755,131}, {756,127}, {757,127}, {758,127}, {759,153}, {760,95}, {762,0}, {763,140}, {764,74}, {765,27}, {769,127}, {773,127}, {775,0}, {779,214}, {780,204}, {781,198}, {785,0}, {789,0}, {795,63}, {796,30}, {799,127}, {800,226}, {801,255}, {802,198}, {803,255}, {804,255}, {805,255}, {806,255}, {807,255}, {808,255}, {812,255}, {813,255}, {814,255}, {815,204}, {816,0}, {817,255}, {818,255}, {819,255}, {820,255}, {821,255}, {822,255}, {823,255}, {824,255}, {825,255}, {826,255}, {827,255}, {828,0}, {829,255}, {830,255}, {834,255}, {835,255}, {836,255}, {840,0}, {841,127}, {842,127}, {844,255}, {848,25}, {858,100}, {859,255}, {860,255}, {861,255}, {862,255}, {863,84}, {868,0}, {869,0}, {877,0}, {879,51}, {880,132}, {921,255}, {922,255}, {923,255}, {10000,0}, {10001,0}, {10002,25}, {10003,0}, {10004,25}, {10005,23}, {10006,51}, {10007,0}, {10008,25}, {10009,23}, {10010,51}, {10011,0}, {10012,0}, {10013,25}, {10014,0}, {10015,25}, {10016,23}, {10017,51}, {10018,0}, {10019,0}, {10020,25}, {10021,0}, {10022,25}, {10023,23}, {10024,51}, {10025,0}, {10026,25}, {10027,23}, {10028,51}, {10029,0}, {10030,25}, {10031,23}, {10032,51}, {11000,1}, {11001,127} + }; + std::map<S32, U8> *params = NULL; + if (getSex() == SEX_MALE) + params = &male_params; + else + params = &female_params; + + for( auto it = params->begin(); it != params->end(); ++it) + { + LLVisualParam* param = getVisualParam(it->first); + if( !param ) + { + // invalid id + break; + } + + U8 value = it->second; + F32 newWeight = U8_to_F32(value, param->getMinWeight(), param->getMaxWeight()); + param->setWeight(newWeight); + } +} + //----------------------------------------------------------------------------- // resetSkeleton() //----------------------------------------------------------------------------- @@ -2044,8 +2113,10 @@ void LLVOAvatar::resetSkeleton(bool reset_animations) LL_ERRS() << "Error resetting skeleton" << LL_ENDL; } - // Reset attachment points (buildSkeleton only does bones and CVs) - bool ignore_hud_joints = true; + // Reset attachment points + // BuildSkeleton only does bones and CVs but we still need to reinit huds + // since huds can be animated. + bool ignore_hud_joints = !isSelf(); initAttachmentPoints(ignore_hud_joints); // Fix up collision volumes @@ -2065,15 +2136,30 @@ void LLVOAvatar::resetSkeleton(bool reset_animations) } // Reset tweakable params to preserved state - if (mLastProcessedAppearance) - { - bool slam_params = true; - applyParsedAppearanceMessage(*mLastProcessedAppearance, slam_params); - } + if (getOverallAppearance() == AOA_NORMAL) + { + if (mLastProcessedAppearance) + { + bool slam_params = true; + applyParsedAppearanceMessage(*mLastProcessedAppearance, slam_params); + } + } + else + { + // Stripped down approximation of + // applyParsedAppearanceMessage, but with alternative default + // (jellydoll) params + setCompositeUpdatesEnabled( FALSE ); + gPipeline.markGLRebuild(this); + applyDefaultParams(); + setCompositeUpdatesEnabled( TRUE ); + updateMeshTextures(); + updateMeshVisibility(); + } updateVisualParams(); // Restore attachment pos overrides - updateAttachmentOverrides(); + updateAttachmentOverrides(); // Animations if (reset_animations) @@ -2406,6 +2492,7 @@ S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid) } static LLTrace::BlockTimerStatHandle FTM_AVATAR_UPDATE("Avatar Update"); +static LLTrace::BlockTimerStatHandle FTM_AVATAR_UPDATE_COMPLEXITY("Avatar Update Complexity"); static LLTrace::BlockTimerStatHandle FTM_JOINT_UPDATE("Update Joints"); //------------------------------------------------------------------------ @@ -2448,14 +2535,13 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) return; } - if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR)) + if (!(gPipeline.hasRenderType(mIsControlAvatar ? LLPipeline::RENDER_TYPE_CONTROL_AV : LLPipeline::RENDER_TYPE_AVATAR)) && !(gSavedSettings.getBOOL("DisableAllRenderTypes")) && !isSelf()) { 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()) { @@ -2463,6 +2549,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) } else { + const S32 upd_freq = 4; // force update every upd_freq frames. mNeedsExtentUpdate = ((LLDrawable::getCurrentFrame()+mID.mData[0])%upd_freq==0); } @@ -2547,8 +2634,41 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) } idleUpdateNameTag( mLastRootPos ); + + // Complexity has stale mechanics, but updates still can be very rapid + // so spread avatar complexity calculations over frames to lesen load from + // rapid updates and to make sure all avatars are not calculated at once. + S32 compl_upd_freq = 20; + if (isControlAvatar()) + { + // animeshes do not (or won't) have impostors nor change outfis, + // no need for high frequency + compl_upd_freq = 100; + } + else if (mLastRezzedStatus <= 0) //cloud or init + { + compl_upd_freq = 60; + } + else if (isSelf()) + { + compl_upd_freq = 5; + } + else if (mLastRezzedStatus == 1) //'grey', not fully loaded + { + compl_upd_freq = 40; + } + else if (isInMuteList()) //cheap, buffers value from search + { + compl_upd_freq = 100; + } + + if ((LLFrameTimer::getFrameCount() + mID.mData[0]) % compl_upd_freq == 0) + { + LL_RECORD_BLOCK_TIME(FTM_AVATAR_UPDATE_COMPLEXITY); idleUpdateRenderComplexity(); } + idleUpdateDebugInfo(); +} void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) { @@ -2674,7 +2794,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) BOOL visible = isVisible() || mNeedsAnimUpdate; // update attachments positions - if (detailed_update || !sUseImpostors) + if (detailed_update) { LL_RECORD_BLOCK_TIME(FTM_ATTACHMENT_UPDATE); for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); @@ -2687,7 +2807,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - LLViewerObject* attached_object = (*attachment_iter); + LLViewerObject* attached_object = attachment_iter->get(); BOOL visibleAttachment = visible || (attached_object && !(attached_object->mDrawable->getSpatialBridge() && attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0)); @@ -2734,6 +2854,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) if (angle_diff > F_PI/512.f*distance*mUpdatePeriod) { mNeedsImpostorUpdate = TRUE; + mLastImpostorUpdateReason = 2; } } @@ -2745,6 +2866,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) if (dist_diff/mImpostorDistance > 0.1f) { mNeedsImpostorUpdate = TRUE; + mLastImpostorUpdateReason = 3; } else { @@ -2757,6 +2879,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) if (diff.getLength3().getF32() > 0.05f) { mNeedsImpostorUpdate = TRUE; + mLastImpostorUpdateReason = 4; } else { @@ -2764,6 +2887,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) if (diff.getLength3().getF32() > 0.05f) { mNeedsImpostorUpdate = TRUE; + mLastImpostorUpdateReason = 5; } } } @@ -2772,13 +2896,13 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) if (mDrawable.notNull()) { - mDrawable->movePartition(); + mDrawable->movePartition(); - //force a move if sitting on an active object - if (getParent() && ((LLViewerObject*) getParent())->mDrawable->isActive()) - { - gPipeline.markMoved(mDrawable, TRUE); - } + //force a move if sitting on an active object + if (getParent() && ((LLViewerObject*) getParent())->mDrawable->isActive()) + { + gPipeline.markMoved(mDrawable, TRUE); + } } } @@ -2858,7 +2982,10 @@ F32 LLVOAvatar::calcMorphAmount() void LLVOAvatar::idleUpdateLipSync(bool voice_enabled) { // Use the Lipsync_Ooh and Lipsync_Aah morphs for lip sync - if ( voice_enabled && (LLVoiceClient::getInstance()->lipSyncEnabled()) && LLVoiceClient::getInstance()->getIsSpeaking( mID ) ) + if ( voice_enabled + && mLastRezzedStatus > 0 // no point updating lip-sync for clouds + && (LLVoiceClient::getInstance()->lipSyncEnabled()) + && LLVoiceClient::getInstance()->getIsSpeaking( mID ) ) { F32 ooh_morph_amount = 0.0f; F32 aah_morph_amount = 0.0f; @@ -2952,7 +3079,7 @@ void LLVOAvatar::idleUpdateLoadingEffect() void LLVOAvatar::idleUpdateWindEffect() { // update wind effect - if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) >= LLDrawPoolAvatar::SHADER_LEVEL_CLOTH)) + if ((LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) >= LLDrawPoolAvatar::SHADER_LEVEL_CLOTH)) { F32 hover_strength = 0.f; F32 time_delta = mRippleTimer.getElapsedTimeF32() - mRippleTimeLast; @@ -3206,7 +3333,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) std::string title_str = title->getString(); LLStringFn::replace_ascii_controlchars(title_str,LL_UNKNOWN_CHAR); addNameTagLine(title_str, name_tag_color, LLFontGL::NORMAL, - LLFontGL::getFontSansSerifSmall()); + LLFontGL::getFontSansSerifSmall(), true); } static LLUICachedControl<bool> show_display_names("NameTagShowDisplayNames", true); @@ -3226,7 +3353,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) if (show_display_names) { addNameTagLine(av_name.getDisplayName(), name_tag_color, LLFontGL::NORMAL, - LLFontGL::getFontSansSerif()); + LLFontGL::getFontSansSerif(), true); } // Suppress SLID display if display name matches exactly (ugh) if (show_usernames && !av_name.isDisplayNameDefault()) @@ -3234,14 +3361,14 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) // *HACK: Desaturate the color LLColor4 username_color = name_tag_color * 0.83f; addNameTagLine(av_name.getUserName(), username_color, LLFontGL::NORMAL, - LLFontGL::getFontSansSerifSmall()); + LLFontGL::getFontSansSerifSmall(), true); } } else { const LLFontGL* font = LLFontGL::getFontSansSerif(); std::string full_name = LLCacheName::buildFullName( firstname->getString(), lastname->getString() ); - addNameTagLine(full_name, name_tag_color, LLFontGL::NORMAL, font); + addNameTagLine(full_name, name_tag_color, LLFontGL::NORMAL, font, true); } mNameAway = is_away; @@ -3333,7 +3460,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) } } -void LLVOAvatar::addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font) +void LLVOAvatar::addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font, const bool use_ellipses) { llassert(mNameText); if (mVisibleChat) @@ -3342,7 +3469,7 @@ void LLVOAvatar::addNameTagLine(const std::string& line, const LLColor4& color, } else { - mNameText->addLine(line, color, (LLFontGL::StyleFlags)style, font); + mNameText->addLine(line, color, (LLFontGL::StyleFlags)style, font, use_ellipses); } mNameIsSet |= !line.empty(); } @@ -3504,14 +3631,19 @@ bool LLVOAvatar::isVisuallyMuted() muted = false; } else if (mVisuallyMuteSetting == AV_DO_NOT_RENDER) - { // Always want to see this AV as an impostor + { +#ifdef JELLYDOLLS_SHOULD_IMPOSTOR muted = true; + // Always want to see this AV as an impostor +#else + muted = false; +#endif } else if (isInMuteList()) { muted = true; } - else + else { muted = isTooComplex(); } @@ -3520,7 +3652,7 @@ bool LLVOAvatar::isVisuallyMuted() return muted; } -bool LLVOAvatar::isInMuteList() +bool LLVOAvatar::isInMuteList() const { bool muted = false; F64 now = LLFrameTimer::getTotalSeconds(); @@ -3582,9 +3714,14 @@ void LLVOAvatar::updateAppearanceMessageDebugText() 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", (isSitting() ? "S" : "T")); debug_line += llformat("%s", (isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED) ? "G" : "-")); } + if (mInAir) + { + debug_line += " A"; + + } LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition(); LLVector3 normal; @@ -3597,9 +3734,38 @@ void LLVOAvatar::updateAppearanceMessageDebugText() 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); + const LLVector3& scale = getScale(); + debug_line += llformat(" scale-z %.3f", scale[2]); + S32 is_visible = (S32) isVisible(); + S32 is_m_visible = (S32) mVisible; + debug_line += llformat(" v %d/%d", is_visible, is_m_visible); + + AvatarOverallAppearance aoa = getOverallAppearance(); + if (aoa == AOA_NORMAL) + { + debug_line += " N"; + } + else if (aoa == AOA_JELLYDOLL) + { + debug_line += " J"; + } + else + { + debug_line += " I"; + } + + if (mMeshValid) + { + debug_line += "m"; + } + else + { + debug_line += "-"; + } + if (isImpostor()) + { + debug_line += " Imp" + llformat("%d[%d]:%.1f", mUpdatePeriod, mLastImpostorUpdateReason, ((F32)(gFrameTimeSeconds-mLastImpostorUpdateFrameTime))); + } addDebugText(debug_line); } @@ -3641,13 +3807,13 @@ LLViewerInventoryItem* recursiveGetObjectInventoryItem(LLViewerObject *vobj, LLU void LLVOAvatar::updateAnimationDebugText() { - for (LLMotionController::motion_list_t::iterator iter = mMotionController.getActiveMotions().begin(); - iter != mMotionController.getActiveMotions().end(); ++iter) + for (LLMotionController::motion_list_t::iterator iter = mMotionController.getActiveMotions().begin(); + iter != mMotionController.getActiveMotions().end(); ++iter) + { + LLMotion* motionp = *iter; + if (motionp->getMinPixelArea() < getPixelArea()) { - LLMotion* motionp = *iter; - if (motionp->getMinPixelArea() < getPixelArea()) - { - std::string output; + std::string output; std::string motion_name = motionp->getName(); if (motion_name.empty()) { @@ -3664,73 +3830,74 @@ void LLVOAvatar::updateAnimationDebugText() } } if (motion_name.empty()) + { + std::string name; + if (gAgent.isGodlikeWithoutAdminMenuFakery() || isSelf()) { - std::string name; - if (gAgent.isGodlikeWithoutAdminMenuFakery() || isSelf()) + name = motionp->getID().asString(); + LLVOAvatar::AnimSourceIterator anim_it = mAnimationSources.begin(); + for (; anim_it != mAnimationSources.end(); ++anim_it) { - name = motionp->getID().asString(); - LLVOAvatar::AnimSourceIterator anim_it = mAnimationSources.begin(); - for (; anim_it != mAnimationSources.end(); ++anim_it) + if (anim_it->second == motionp->getID()) { - if (anim_it->second == motionp->getID()) + LLViewerObject* object = gObjectList.findObject(anim_it->first); + if (!object) { - LLViewerObject* object = gObjectList.findObject(anim_it->first); - if (!object) + break; + } + if (object->isAvatar()) + { + if (mMotionController.mIsSelf) + { + // Searching inventory by asset id is really long + // so just mark as inventory + // Also item is likely to be named by LLPreviewAnim + name += "(inventory)"; + } + } + else + { + LLViewerInventoryItem* item = NULL; + if (!object->isInventoryDirty()) + { + item = object->getInventoryItemByAsset(motionp->getID()); + } + if (item) { - break; + name = item->getName(); } - if (object->isAvatar()) + else if (object->isAttachment()) { - if (mMotionController.mIsSelf) - { - // Searching inventory by asset id is really long - // so just mark as inventory - // Also item is likely to be named by LLPreviewAnim - name += "(inventory)"; - } + name += "(att:" + getAttachmentItemName() + ")"; } else { - LLViewerInventoryItem* item = NULL; - if (!object->isInventoryDirty()) - { - item = object->getInventoryItemByAsset(motionp->getID()); - } - if (item) - { - name = item->getName(); - } - else if (object->isAttachment()) - { - name += "(" + getAttachmentItemName() + ")"; - } - else - { - // in-world object, name or content unknown - name += "(in-world)"; - } + // in-world object, name or content unknown + name += "(in-world)"; } - break; } + break; } } - else - { - name = LLUUID::null.asString(); - } - output = llformat("%s - %d", - name.c_str(), - (U32)motionp->getPriority()); } else { - output = llformat("%s - %d", - motion_name.c_str(), - (U32)motionp->getPriority()); + name = LLUUID::null.asString(); } - addDebugText(output); + motion_name = name; } + std::string motion_tag = ""; + if (mPlayingAnimations.find(motionp->getID()) != mPlayingAnimations.end()) + { + motion_tag = "*"; + } + output = llformat("%s%s - %d", + motion_name.c_str(), + motion_tag.c_str(), + (U32)motionp->getPriority()); + addDebugText(output); } + } } void LLVOAvatar::updateDebugText() @@ -3859,7 +4026,14 @@ void LLVOAvatar::updateFootstepSounds() // computeUpdatePeriod() // Factored out from updateCharacter() // Set new value for mUpdatePeriod based on distance and various other factors. -//------------------------------------------------------------------------ +// +// Note 10-2020: it turns out that none of these update period +// calculations have been having any effect, because +// mNeedsImpostorUpdate was not being set in updateCharacter(). So +// it's really open to question whether we want to enable time based updates, and if +// so, at what rate. Leaving the rates as given would lead to +// drastically more frequent impostor updates than we've been doing all these years. +// ------------------------------------------------------------------------ void LLVOAvatar::computeUpdatePeriod() { bool visually_muted = isVisuallyMuted(); @@ -3867,7 +4041,7 @@ void LLVOAvatar::computeUpdatePeriod() && isVisible() && (!isSelf() || visually_muted) && !isUIAvatar() - && sUseImpostors + && (sLimitNonImpostors || visually_muted) && !mNeedsAnimUpdate && !sFreezeCounter) { @@ -3875,11 +4049,14 @@ void LLVOAvatar::computeUpdatePeriod() LLVector4a size; size.setSub(ext[1],ext[0]); F32 mag = size.getLength3().getF32()*0.5f; + + const S32 UPDATE_RATE_SLOW = 64; + const S32 UPDATE_RATE_MED = 48; + const S32 UPDATE_RATE_FAST = 32; - 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; + { // visually muted avatars update at lowest rate + mUpdatePeriod = UPDATE_RATE_SLOW; } else if (! shouldImpostor() || mDrawable->mDistanceWRTCamera < 1.f + mag) @@ -3888,29 +4065,29 @@ void LLVOAvatar::computeUpdatePeriod() // impostor camera near clip plane mUpdatePeriod = 1; } - else if ( shouldImpostor(4) ) + else if ( shouldImpostor(4.0) ) { //background avatars are REALLY slow updating impostors - mUpdatePeriod = 16; + mUpdatePeriod = UPDATE_RATE_SLOW; } - else if ( shouldImpostor(3) ) - { //back 25% of max visible avatars are slow updating impostors - mUpdatePeriod = 8; + else if (mLastRezzedStatus <= 0) + { + // Don't update cloud avatars too often + mUpdatePeriod = UPDATE_RATE_SLOW; } - 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 if ( shouldImpostor(3.0) ) + { //back 25% of max visible avatars are slow updating impostors + mUpdatePeriod = UPDATE_RATE_MED; } - else + else { //nearby avatars, update the impostors more frequently. - mUpdatePeriod = 4; + mUpdatePeriod = UPDATE_RATE_FAST; } } else { mUpdatePeriod = 1; } - } //------------------------------------------------------------------------ @@ -4181,7 +4358,33 @@ void LLVOAvatar::updateRootPositionAndRotation(LLAgent& agent, F32 speed, bool w if (!isSitting() && !was_sit_ground_constrained) { root_pos += LLVector3d(getHoverOffset()); - } + if (getOverallAppearance() == AOA_JELLYDOLL) + { + F32 offz = -0.5 * (getScale()[VZ] - mBodySize.mV[VZ]); + root_pos[2] += offz; + // if (!isSelf() && !isControlAvatar()) + // { + // LL_DEBUGS("Avatar") << "av " << getFullname() + // << " frame " << LLFrameTimer::getFrameCount() + // << " root adjust offz " << offz + // << " scalez " << getScale()[VZ] + // << " bsz " << mBodySize.mV[VZ] + // << LL_ENDL; + // } + } + } + // if (!isSelf() && !isControlAvatar()) + // { + // LL_DEBUGS("Avatar") << "av " << getFullname() << " aoa " << (S32) getOverallAppearance() + // << " frame " << LLFrameTimer::getFrameCount() + // << " scalez " << getScale()[VZ] + // << " bsz " << mBodySize.mV[VZ] + // << " root pos " << root_pos[2] + // << " curr rootz " << mRoot->getPosition()[2] + // << " pp-z " << mPelvisp->getPosition()[2] + // << " renderpos " << getRenderPosition() + // << LL_ENDL; + // } LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this); if (cav) @@ -4192,6 +4395,14 @@ void LLVOAvatar::updateRootPositionAndRotation(LLAgent& agent, F32 speed, bool w else { LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos); + // if (!isSelf() && !isControlAvatar()) + // { + // LL_DEBUGS("Avatar") << "av " << getFullname() + // << " frame " << LLFrameTimer::getFrameCount() + // << " newPosition " << newPosition + // << " renderpos " << getRenderPosition() + // << LL_ENDL; + // } if (newPosition != mRoot->getXform()->getWorldPosition()) { mRoot->touch(); @@ -4222,6 +4433,37 @@ void LLVOAvatar::updateRootPositionAndRotation(LLAgent& agent, F32 speed, bool w } //------------------------------------------------------------------------ +// LLVOAvatar::computeNeedsUpdate() +// +// Most of the logic here is to figure out when to periodically update impostors. +// Non-impostors have mUpdatePeriod == 1 and will need update every frame. +//------------------------------------------------------------------------ +bool LLVOAvatar::computeNeedsUpdate() +{ + const F32 MAX_IMPOSTOR_INTERVAL = 4.0f; + computeUpdatePeriod(); + + bool needs_update_by_frame_count = ((LLDrawable::getCurrentFrame()+mID.mData[0])%mUpdatePeriod == 0); + + bool needs_update_by_max_time = ((gFrameTimeSeconds-mLastImpostorUpdateFrameTime)> MAX_IMPOSTOR_INTERVAL); + bool needs_update = needs_update_by_frame_count || needs_update_by_max_time; + + if (needs_update && !isSelf()) + { + if (needs_update_by_max_time) + { + mNeedsImpostorUpdate = TRUE; + mLastImpostorUpdateReason = 11; + } + else + { + //mNeedsImpostorUpdate = TRUE; + //mLastImpostorUpdateReason = 10; + } + } + return needs_update; +} + // updateCharacter() // // This is called for all avatars, so there are 4 possible situations: @@ -4244,7 +4486,7 @@ void LLVOAvatar::updateRootPositionAndRotation(LLAgent& agent, F32 speed, bool w // simulator. // //------------------------------------------------------------------------ -BOOL LLVOAvatar::updateCharacter(LLAgent &agent) +bool LLVOAvatar::updateCharacter(LLAgent &agent) { updateDebugText(); @@ -4256,6 +4498,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) BOOL visible = isVisible(); bool is_control_avatar = isControlAvatar(); // capture state to simplify tracing bool is_attachment = false; + if (is_control_avatar) { LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this); @@ -4275,24 +4518,30 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) //-------------------------------------------------------------------- // The rest should only be done occasionally for far away avatars. - // Set mUpdatePeriod and visible based on distance and other criteria. + // Set mUpdatePeriod and visible based on distance and other criteria, + // and flag for impostor update if needed. //-------------------------------------------------------------------- - computeUpdatePeriod(); - visible = (LLDrawable::getCurrentFrame()+mID.mData[0])%mUpdatePeriod == 0 ? TRUE : FALSE; - + bool needs_update = computeNeedsUpdate(); + //-------------------------------------------------------------------- - // Early out if not visible and not self + // Early out if does not need update and not self // 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()) + if (!needs_update && !isSelf()) { updateMotions(LLCharacter::HIDDEN_UPDATE); return FALSE; } //-------------------------------------------------------------------- + // Handle transitions between regular rendering, jellydoll, or invisible. + // Can trigger skeleton reset or animation changes + //-------------------------------------------------------------------- + updateOverallAppearance(); + + //-------------------------------------------------------------------- // change animation time quanta based on avatar render load //-------------------------------------------------------------------- // SL-763 the time step quantization does not currently work. @@ -4335,12 +4584,17 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) mSpeed = speed; // update animations - if (mSpecialRenderMode == 1) // Animation Preview + if (!visible) + { + updateMotions(LLCharacter::HIDDEN_UPDATE); + } + else if (mSpecialRenderMode == 1) // Animation Preview { updateMotions(LLCharacter::FORCE_UPDATE); } else { + // Might be better to do HIDDEN_UPDATE if cloud updateMotions(LLCharacter::NORMAL_UPDATE); } @@ -4368,10 +4622,13 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) // Update child joints as needed. mRoot->updateWorldMatrixChildren(); - // System avatar mesh vertices need to be reskinned. - mNeedsSkin = TRUE; + if (visible) + { + // System avatar mesh vertices need to be reskinned. + mNeedsSkin = TRUE; + } - return TRUE; + return visible; } //----------------------------------------------------------------------------- @@ -4568,7 +4825,7 @@ void LLVOAvatar::updateVisibility() attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - if (LLViewerObject *attached_object = (*attachment_iter)) + if (LLViewerObject *attached_object = attachment_iter->get()) { if(attached_object->mDrawable->isVisible()) { @@ -4654,7 +4911,7 @@ U32 LLVOAvatar::renderSkinned() } } - if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) <= 0) + if (LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) <= 0) { if (mNeedsSkin) { @@ -4803,19 +5060,29 @@ U32 LLVOAvatar::renderSkinned() BOOL first_pass = TRUE; if (!LLDrawPoolAvatar::sSkipOpaque) { + if (isUIAvatar() && mIsDummy) + { + LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR); + if (hair_mesh) + { + num_indices += hair_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy); + } + first_pass = FALSE; + } if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender) { - if (isTextureVisible(TEX_HEAD_BAKED) || isUIAvatar()) + + if (isTextureVisible(TEX_HEAD_BAKED) || (getOverallAppearance() == AOA_JELLYDOLL && !isControlAvatar()) || isUIAvatar()) { LLViewerJoint* head_mesh = getViewerJoint(MESH_ID_HEAD); if (head_mesh) { - num_indices += head_mesh->render(mAdjustedPixelArea, TRUE, mIsDummy); + num_indices += head_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy); } first_pass = FALSE; } } - if (isTextureVisible(TEX_UPPER_BAKED) || isUIAvatar()) + if (isTextureVisible(TEX_UPPER_BAKED) || (getOverallAppearance() == AOA_JELLYDOLL && !isControlAvatar()) || isUIAvatar()) { LLViewerJoint* upper_mesh = getViewerJoint(MESH_ID_UPPER_BODY); if (upper_mesh) @@ -4825,7 +5092,7 @@ U32 LLVOAvatar::renderSkinned() first_pass = FALSE; } - if (isTextureVisible(TEX_LOWER_BAKED) || isUIAvatar()) + if (isTextureVisible(TEX_LOWER_BAKED) || (getOverallAppearance() == AOA_JELLYDOLL && !isControlAvatar()) || isUIAvatar()) { LLViewerJoint* lower_mesh = getViewerJoint(MESH_ID_LOWER_BODY); if (lower_mesh) @@ -4882,7 +5149,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass) } first_pass = FALSE; } - if (isTextureVisible(TEX_HAIR_BAKED)) + if (isTextureVisible(TEX_HAIR_BAKED) && (getOverallAppearance() != AOA_JELLYDOLL)) { LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR); if (hair_mesh) @@ -4930,7 +5197,7 @@ U32 LLVOAvatar::renderRigid() gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); } - if (isTextureVisible(TEX_EYES_BAKED) || isUIAvatar()) + if (isTextureVisible(TEX_EYES_BAKED) || (getOverallAppearance() == AOA_JELLYDOLL && !isControlAvatar()) || isUIAvatar()) { LLViewerJoint* eyeball_left = getViewerJoint(MESH_ID_EYEBALL_LEFT); LLViewerJoint* eyeball_right = getViewerJoint(MESH_ID_EYEBALL_RIGHT); @@ -5108,7 +5375,7 @@ void LLVOAvatar::collectLocalTextureUUIDs(std::set<LLUUID>& ids) const { for (U32 texture_index = 0; texture_index < getNumTEs(); texture_index++) { - LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)texture_index); + LLWearableType::EType wearable_type = LLAvatarAppearance::getDictionary()->getTEWearableType((ETextureIndex)texture_index); U32 num_wearables = gAgentWearables.getWearableCount(wearable_type); LLViewerFetchedTexture *imagep = NULL; @@ -5117,7 +5384,7 @@ void LLVOAvatar::collectLocalTextureUUIDs(std::set<LLUUID>& ids) const imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index, wearable_index), TRUE); if (imagep) { - const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)texture_index); + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearance::getDictionary()->getTexture((ETextureIndex)texture_index); if (texture_dict && texture_dict->mIsLocalTexture) { ids.insert(imagep->getID()); @@ -5251,7 +5518,7 @@ void LLVOAvatar::updateTextures() mHasGrey = FALSE; // debug for (U32 texture_index = 0; texture_index < getNumTEs(); texture_index++) { - LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)texture_index); + LLWearableType::EType wearable_type = LLAvatarAppearance::getDictionary()->getTEWearableType((ETextureIndex)texture_index); U32 num_wearables = gAgentWearables.getWearableCount(wearable_type); const LLTextureEntry *te = getTE(texture_index); @@ -5274,7 +5541,7 @@ void LLVOAvatar::updateTextures() imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index, wearable_index), TRUE); if (imagep) { - const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)texture_index); + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearance::getDictionary()->getTexture((ETextureIndex)texture_index); const EBakedTextureIndex baked_index = texture_dict ? texture_dict->mBakedTextureIndex : EBakedTextureIndex::BAKED_NUM_INDICES; if (texture_dict && texture_dict->mIsLocalTexture) { @@ -5317,12 +5584,28 @@ void LLVOAvatar::checkTextureLoading() } if(mLoadedCallbacksPaused == pause) { + if (!pause && mFirstFullyVisible && mLoadedCallbackTextures < mCallbackTextureList.size()) + { + // We still need to update 'loaded' textures count to decide on 'cloud' visibility + // Alternatively this can be done on TextureLoaded callbacks, but is harder to properly track + mLoadedCallbackTextures = 0; + for (LLLoadedCallbackEntry::source_callback_list_t::iterator iter = mCallbackTextureList.begin(); + iter != mCallbackTextureList.end(); ++iter) + { + LLViewerFetchedTexture* tex = gTextureList.findImage(*iter); + if (tex && (tex->getDiscardLevel() >= 0 || tex->isMissingAsset())) + { + mLoadedCallbackTextures++; + } + } + } return ; } if(mCallbackTextureList.empty()) //when is self or no callbacks. Note: this list for self is always empty. { mLoadedCallbacksPaused = pause ; + mLoadedCallbackTextures = 0; return ; //nothing to check. } @@ -5330,7 +5613,9 @@ void LLVOAvatar::checkTextureLoading() { return ; //have not been invisible for enough time. } - + + mLoadedCallbackTextures = pause ? mCallbackTextureList.size() : 0; + for(LLLoadedCallbackEntry::source_callback_list_t::iterator iter = mCallbackTextureList.begin(); iter != mCallbackTextureList.end(); ++iter) { @@ -5351,9 +5636,15 @@ void LLVOAvatar::checkTextureLoading() tex->unpauseLoadedCallbacks(&mCallbackTextureList) ; tex->addTextureStats(START_AREA); //jump start the fetching again + + // technically shouldn't need to account for missing, but callback might not have happened yet + if (tex->getDiscardLevel() >= 0 || tex->isMissingAsset()) + { + mLoadedCallbackTextures++; // consider it loaded (we have at least some data) + } } - } - } + } + } if(!pause) { @@ -5425,7 +5716,7 @@ const std::string LLVOAvatar::getImageURL(const U8 te, const LLUUID &uuid) return url; } - const LLAvatarAppearanceDictionary::TextureEntry* texture_entry = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te); + const LLAvatarAppearanceDictionary::TextureEntry* texture_entry = LLAvatarAppearance::getDictionary()->getTexture((ETextureIndex)te); if (texture_entry != NULL) { url = appearance_service_url + "texture/" + getID().asString() + "/" + texture_entry->mDefaultImageName + "/" + uuid.asString(); @@ -5535,8 +5826,8 @@ void LLVOAvatar::processAnimationStateChanges() stopMotion(ANIM_AGENT_TARGET); if (mEnableDefaultMotions) { - startMotion(ANIM_AGENT_BODY_NOISE); - } + startMotion(ANIM_AGENT_BODY_NOISE); + } } // clear all current animations @@ -5556,23 +5847,32 @@ void LLVOAvatar::processAnimationStateChanges() ++anim_it; } + // if jellydolled, shelve all playing animations + if (getOverallAppearance() != AOA_NORMAL) + { + mPlayingAnimations.clear(); + } + // start up all new anims - for (anim_it = mSignaledAnimations.begin(); anim_it != mSignaledAnimations.end();) + if (getOverallAppearance() == AOA_NORMAL) { - AnimIterator found_anim = mPlayingAnimations.find(anim_it->first); - - // signaled but not playing, or different sequence id, start motion - if (found_anim == mPlayingAnimations.end() || found_anim->second != anim_it->second) + for (anim_it = mSignaledAnimations.begin(); anim_it != mSignaledAnimations.end();) { - if (processSingleAnimationStateChange(anim_it->first, TRUE)) + AnimIterator found_anim = mPlayingAnimations.find(anim_it->first); + + // signaled but not playing, or different sequence id, start motion + if (found_anim == mPlayingAnimations.end() || found_anim->second != anim_it->second) { - mPlayingAnimations[anim_it->first] = anim_it->second; - ++anim_it; - continue; + if (processSingleAnimationStateChange(anim_it->first, TRUE)) + { + mPlayingAnimations[anim_it->first] = anim_it->second; + ++anim_it; + continue; + } } - } - ++anim_it; + ++anim_it; + } } // clear source information for animations which have been stopped @@ -5646,7 +5946,7 @@ BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL } else { - LL_WARNS() << "Failed to start motion!" << LL_ENDL; + LL_WARNS("Motion") << "Failed to start motion!" << LL_ENDL; } } else //stop animation @@ -5753,13 +6053,13 @@ LLUUID LLVOAvatar::remapMotionID(const LLUUID& id) //----------------------------------------------------------------------------- BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset) { - LL_DEBUGS() << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << LL_ENDL; + LL_DEBUGS("Motion") << "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; + LL_DEBUGS("Motion") << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << LL_ENDL; } if (isSelf() && remap_id == ANIM_AGENT_AWAY) @@ -5775,13 +6075,13 @@ BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset) //----------------------------------------------------------------------------- BOOL LLVOAvatar::stopMotion(const LLUUID& id, BOOL stop_immediate) { - LL_DEBUGS() << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << LL_ENDL; + LL_DEBUGS("Motion") << "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; + LL_DEBUGS("Motion") << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << LL_ENDL; } if (isSelf()) @@ -5992,7 +6292,7 @@ void LLVOAvatar::rebuildAttachmentOverrides() for (LLViewerJointAttachment::attachedobjs_vec_t::iterator at_it = attachment_pt->mAttachedObjects.begin(); at_it != attachment_pt->mAttachedObjects.end(); ++at_it) { - LLViewerObject *vo = *at_it; + LLViewerObject *vo = at_it->get(); // Attached animated objects affect joints in their control // avs, not the avs to which they are attached. if (vo && !vo->isAnimatedObject()) @@ -6043,7 +6343,7 @@ void LLVOAvatar::updateAttachmentOverrides() for (LLViewerJointAttachment::attachedobjs_vec_t::iterator at_it = attachment_pt->mAttachedObjects.begin(); at_it != attachment_pt->mAttachedObjects.end(); ++at_it) { - LLViewerObject *vo = *at_it; + LLViewerObject *vo = at_it->get(); // Attached animated objects affect joints in their control // avs, not the avs to which they are attached. if (vo && !vo->isAnimatedObject()) @@ -6135,6 +6435,11 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo, std::set<LL } LLScopedContextString str("addAttachmentOverridesForObject " + getFullname()); + + if (getOverallAppearance() != AOA_NORMAL) + { + return; + } LL_DEBUGS("AnimatedObjects") << "adding" << LL_ENDL; dumpStack("AnimatedObjectsStack"); @@ -6575,7 +6880,7 @@ void LLVOAvatar::initAttachmentPoints(bool ignore_hud_joints) LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *iter; if (info->mIsHUDAttachment && (!isSelf() || ignore_hud_joints)) { - //don't process hud joint for other avatars, or when doing a skeleton reset. + //don't process hud joint for other avatars. continue; } @@ -6793,13 +7098,13 @@ LLDrawable *LLVOAvatar::createDrawable(LLPipeline *pipeline) pipeline->allocDrawable(this); mDrawable->setLit(FALSE); - LLDrawPoolAvatar *poolp = (LLDrawPoolAvatar*) gPipeline.getPool(LLDrawPool::POOL_AVATAR); + LLDrawPoolAvatar *poolp = (LLDrawPoolAvatar*)gPipeline.getPool(mIsControlAvatar ? LLDrawPool::POOL_CONTROL_AV : LLDrawPool::POOL_AVATAR); // Only a single face (one per avatar) //this face will be splitted into several if its vertex buffer is too long. mDrawable->setState(LLDrawable::ACTIVE); mDrawable->addFace(poolp, NULL); - mDrawable->setRenderType(LLPipeline::RENDER_TYPE_AVATAR); + mDrawable->setRenderType(mIsControlAvatar ? LLPipeline::RENDER_TYPE_CONTROL_AV : LLPipeline::RENDER_TYPE_AVATAR); mNumInitFaces = mDrawable->getNumFaces() ; @@ -6824,7 +7129,7 @@ static LLTrace::BlockTimerStatHandle FTM_UPDATE_AVATAR("Update Avatar"); BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable) { LL_RECORD_BLOCK_TIME(FTM_UPDATE_AVATAR); - if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR))) + if (!(gPipeline.hasRenderType(mIsControlAvatar ? LLPipeline::RENDER_TYPE_CONTROL_AV : LLPipeline::RENDER_TYPE_AVATAR))) { return TRUE; } @@ -7060,20 +7365,7 @@ U32 LLVOAvatar::getNumAttachments() const //----------------------------------------------------------------------------- S32 LLVOAvatar::getMaxAttachments() const { - const S32 MAX_AGENT_ATTACHMENTS = 38; - - S32 max_attach = MAX_AGENT_ATTACHMENTS; - - if (gAgent.getRegion()) - { - LLSD features; - gAgent.getRegion()->getSimulatorFeatures(features); - if (features.has("MaxAgentAttachments")) - { - max_attach = features["MaxAgentAttachments"].asInteger(); - } - } - return max_attach; + return LLAgentBenefitsMgr::current().getAttachmentLimit(); } //----------------------------------------------------------------------------- @@ -7107,24 +7399,7 @@ U32 LLVOAvatar::getNumAnimatedObjectAttachments() const //----------------------------------------------------------------------------- S32 LLVOAvatar::getMaxAnimatedObjectAttachments() const { - S32 max_attach = 0; - if (gSavedSettings.getBOOL("AnimatedObjectsIgnoreLimits")) - { - max_attach = getMaxAttachments(); - } - else - { - if (gAgent.getRegion()) - { - LLSD features; - gAgent.getRegion()->getSimulatorFeatures(features); - if (features.has("AnimatedObjects")) - { - max_attach = features["AnimatedObjects"]["MaxAgentAnimatedObjectAttachments"].asInteger(); - } - } - } - return max_attach; + return LLAgentBenefitsMgr::current().getAnimatedObjectLimit(); } //----------------------------------------------------------------------------- @@ -7146,29 +7421,33 @@ void LLVOAvatar::lazyAttach() for (U32 i = 0; i < mPendingAttachment.size(); i++) { LLPointer<LLViewerObject> cur_attachment = mPendingAttachment[i]; - if (cur_attachment->mDrawable) + // Object might have died while we were waiting for drawable + if (!cur_attachment->isDead()) { - if (isSelf()) + if (cur_attachment->mDrawable) { - 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 (isSelf()) + { + 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); + } } - 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); + else + { + still_pending.push_back(cur_attachment); } } - else - { - still_pending.push_back(cur_attachment); - } } mPendingAttachment = still_pending; @@ -7188,7 +7467,7 @@ void LLVOAvatar::resetHUDAttachments() attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - const LLViewerObject* attached_object = (*attachment_iter); + const LLViewerObject* attached_object = attachment_iter->get(); if (attached_object && attached_object->mDrawable.notNull()) { gPipeline.markMoved(attached_object->mDrawable); @@ -7320,6 +7599,19 @@ void LLVOAvatar::sitOnObject(LLViewerObject *sit_object) { gAgentCamera.changeCameraToMouselook(); } + + if (gAgentCamera.getFocusOnAvatar() && LLToolMgr::getInstance()->inEdit()) + { + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if (node && node->mValid) + { + LLViewerObject* root_object = node->getObject(); + if (root_object == sit_object) + { + LLFloaterTools::sPreviousFocusOnAvatar = true; + } + } + } } if (mDrawable.isNull()) @@ -7345,7 +7637,8 @@ void LLVOAvatar::sitOnObject(LLViewerObject *sit_object) mRoot->updateWorldMatrixChildren(); stopMotion(ANIM_AGENT_BODY_NOISE); - + + gAgentCamera.setInitSitRot(gAgent.getFrameAgent().getQuaternion()); } //----------------------------------------------------------------------------- @@ -7363,7 +7656,7 @@ void LLVOAvatar::getOffObject() if (sit_object) { stopMotionFromSource(sit_object->getID()); - LLFollowCamMgr::setCameraActive(sit_object->getID(), FALSE); + LLFollowCamMgr::getInstance()->setCameraActive(sit_object->getID(), FALSE); LLViewerObject::const_child_list_t& child_list = sit_object->getChildren(); for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); @@ -7372,7 +7665,7 @@ void LLVOAvatar::getOffObject() LLViewerObject* child_objectp = *iter; stopMotionFromSource(child_objectp->getID()); - LLFollowCamMgr::setCameraActive(child_objectp->getID(), FALSE); + LLFollowCamMgr::getInstance()->setCameraActive(child_objectp->getID(), FALSE); } } @@ -7472,8 +7765,8 @@ BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const break; // Do nothing } - for (LLAvatarAppearanceDictionary::Textures::const_iterator tex_iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); - tex_iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); + for (LLAvatarAppearanceDictionary::Textures::const_iterator tex_iter = LLAvatarAppearance::getDictionary()->getTextures().begin(); + tex_iter != LLAvatarAppearance::getDictionary()->getTextures().end(); ++tex_iter) { const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = tex_iter->second; @@ -7486,7 +7779,7 @@ BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const if (texture_dict->mIsUsedByBakedTexture) { const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; - return isTextureDefined(LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex); + return isTextureDefined(LLAvatarAppearance::getDictionary()->getBakedTexture(baked_index)->mTextureIndex); } return FALSE; } @@ -7505,7 +7798,7 @@ LLViewerObject * LLVOAvatar::findAttachmentByID( const LLUUID & target_id ) cons attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - LLViewerObject *attached_object = (*attachment_iter); + LLViewerObject *attached_object = attachment_iter->get(); if (attached_object && attached_object->getID() == target_id) { @@ -7566,9 +7859,15 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color) } // virtual +// Do rigged mesh attachments display with this av? bool LLVOAvatar::shouldRenderRigged() const { - return true; + if (getOverallAppearance() == AOA_NORMAL) + { + return true; + } + // TBD - render for AOA_JELLYDOLL? + return false; } // FIXME: We have an mVisible member, set in updateVisibility(), but this @@ -7600,14 +7899,13 @@ bool LLVOAvatar::getIsCloud() const ); } -void LLVOAvatar::updateRezzedStatusTimers() +void LLVOAvatar::updateRezzedStatusTimers(S32 rez_status) { // State machine for rezzed status. Statuses are -1 on startup, 0 // = cloud, 1 = gray, 2 = downloading, 3 = full. // Purpose is to collect time data for each it takes avatar to reach // various loading landmarks: gray, textured (partial), textured fully. - S32 rez_status = getRezzedStatus(); if (rez_status != mLastRezzedStatus) { LL_DEBUGS("Avatar") << avString() << "rez state change: " << mLastRezzedStatus << " -> " << rez_status << LL_ENDL; @@ -7777,8 +8075,21 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse // returns true if the value has changed. BOOL LLVOAvatar::updateIsFullyLoaded() { - const bool loading = getIsCloud(); - updateRezzedStatusTimers(); + S32 rez_status = getRezzedStatus(); + bool loading = getIsCloud(); + if (mFirstFullyVisible && !mIsControlAvatar) + { + loading = ((rez_status < 2) + // Wait at least 60s for unfinished textures to finish on first load, + // don't wait forever, it might fail. Even if it will eventually load by + // itself and update mLoadedCallbackTextures (or fail and clean the list), + // avatars are more time-sensitive than textures and can't wait that long. + || (mLoadedCallbackTextures < mCallbackTextureList.size() && mLastTexCallbackAddedTime.getElapsedTimeF32() < MAX_TEXTURE_WAIT_TIME_SEC) + || !mPendingAttachment.empty() + || (rez_status < 3 && !isFullyBaked()) + ); + } + updateRezzedStatusTimers(rez_status); updateRuthTimer(loading); return processFullyLoadedChange(loading); } @@ -7814,13 +8125,22 @@ void LLVOAvatar::updateRuthTimer(bool loading) BOOL LLVOAvatar::processFullyLoadedChange(bool loading) { - // we wait a little bit before giving the all clear, - // to let textures settle down - const F32 PAUSE = 1.f; + // We wait a little bit before giving the 'all clear', to let things to + // settle down (models to snap into place, textures to get first packets) + const F32 LOADED_DELAY = 1.f; + const F32 FIRST_USE_DELAY = 3.f; + if (loading) mFullyLoadedTimer.reset(); - - mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > PAUSE); + + if (mFirstFullyVisible) + { + mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > FIRST_USE_DELAY); + } + else + { + mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > LOADED_DELAY); + } if (!mPreviousFullyLoaded && !loading && mFullyLoaded) { @@ -7828,12 +8148,14 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading) } // did our loading state "change" from last call? - // runway - why are we updating every 30 calls even if nothing has changed? + // FIXME runway - why are we updating every 30 calls even if nothing has changed? + // This causes updateLOD() to run every 30 frames, among other things. const S32 UPDATE_RATE = 30; BOOL changed = ((mFullyLoaded != mPreviousFullyLoaded) || // if the value is different from the previous call (!mFullyLoadedInitialized) || // if we've never been called before (mFullyLoadedFrameCounter % UPDATE_RATE == 0)); // every now and then issue a change + BOOL fully_loaded_changed = (mFullyLoaded != mPreviousFullyLoaded); mPreviousFullyLoaded = mFullyLoaded; mFullyLoadedInitialized = TRUE; @@ -7844,7 +8166,13 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading) // to know about outfit switching LLAvatarRenderNotifier::getInstance()->updateNotificationState(); } - + + if (fully_loaded_changed && !isSelf() && mFullyLoaded && isImpostor()) + { + // Fix for jellydoll initially invisible + mNeedsImpostorUpdate = TRUE; + mLastImpostorUpdateReason = 6; + } return changed; } @@ -7916,47 +8244,25 @@ void LLVOAvatar::updateMeshVisibility() bool bake_flag[BAKED_NUM_INDICES]; memset(bake_flag, 0, BAKED_NUM_INDICES*sizeof(bool)); - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) + if (getOverallAppearance() == AOA_NORMAL) { - LLViewerJointAttachment* attachment = iter->second; - if (attachment) + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) { - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) + LLViewerJointAttachment* attachment = iter->second; + if (attachment) { - LLViewerObject *objectp = (*attachment_iter); - if (objectp) - { - 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 (LLViewerObject::child_list_t::const_iterator iter1 = child_list.begin(); - iter1 != child_list.end(); ++iter1) + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - LLViewerObject* objectchild = *iter1; - if (objectchild) + LLViewerObject *objectp = attachment_iter->get(); + if (objectp) { - for (int face_index = 0; face_index < objectchild->getNumTEs(); face_index++) + for (int face_index = 0; face_index < objectp->getNumTEs(); face_index++) { - LLTextureEntry* tex_entry = objectchild->getTE(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); @@ -7970,6 +8276,31 @@ void LLVOAvatar::updateMeshVisibility() bake_flag[BAKED_AUX3] |= (tex_entry->getID() == IMG_USE_BAKED_AUX3); } } + + LLViewerObject::const_child_list_t& child_list = objectp->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter1 = child_list.begin(); + iter1 != child_list.end(); ++iter1) + { + 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); + } + } + } } } } @@ -8110,6 +8441,7 @@ void LLVOAvatar::updateMeshTextures() LLViewerTexLayerSet* layerset = getTexLayerSet(i); if (use_lkg_baked_layer[i] && !isUsingLocalAppearance() ) { + // use last known good layer (no new one) LLViewerFetchedTexture* baked_img = LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[i].mLastTextureID); mBakedTextureDatas[i].mIsUsed = TRUE; @@ -8128,6 +8460,7 @@ void LLVOAvatar::updateMeshTextures() } else if (!isUsingLocalAppearance() && is_layer_baked[i]) { + // use new layer LLViewerFetchedTexture* baked_img = LLViewerTextureManager::staticCastToFetchedTexture( getImage( mBakedTextureDatas[i].mTextureIndex, 0 ), TRUE) ; @@ -8147,10 +8480,15 @@ void LLVOAvatar::updateMeshTextures() ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) ) { baked_img->setLoadedCallback(onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ), - src_callback_list, paused); + src_callback_list, paused); } baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ), src_callback_list, paused ); + if (baked_img->getDiscardLevel() < 0 && !paused) + { + // mLoadedCallbackTextures will be updated by checkTextureLoading() below + mLastTexCallbackAddedTime.reset(); + } // this could add paused texture callbacks mLoadedCallbacksPaused |= paused; @@ -8204,8 +8542,8 @@ void LLVOAvatar::updateMeshTextures() for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = - LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin(); - baked_iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); + LLAvatarAppearance::getDictionary()->getBakedTextures().begin(); + baked_iter != LLAvatarAppearance::getDictionary()->getBakedTextures().end(); ++baked_iter) { const EBakedTextureIndex baked_index = baked_iter->first; @@ -8244,7 +8582,7 @@ void LLVOAvatar::updateMeshTextures() attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - LLViewerObject* attached_object = (*attachment_iter); + LLViewerObject* attached_object = attachment_iter->get(); if (attached_object && !attached_object->isDead()) { attached_object->refreshBakeTexture(); @@ -8383,7 +8721,7 @@ void LLVOAvatar::releaseComponentTextures() for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { - const LLAvatarAppearanceDictionary::BakedEntry * bakedDicEntry = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); + const LLAvatarAppearanceDictionary::BakedEntry * bakedDicEntry = LLAvatarAppearance::getDictionary()->getBakedTexture((EBakedTextureIndex)baked_index); // skip if this is a skirt and av is not wearing one, or if we don't have a baked texture UUID if (!isTextureDefined(bakedDicEntry->mTextureIndex) && ( (baked_index != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT) )) @@ -8402,8 +8740,8 @@ void LLVOAvatar::releaseComponentTextures() void LLVOAvatar::dumpAvatarTEs( const std::string& context ) const { LL_DEBUGS("Avatar") << avString() << (isSelf() ? "Self: " : "Other: ") << context << LL_ENDL; - for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); - iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); + for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearance::getDictionary()->getTextures().begin(); + iter != LLAvatarAppearance::getDictionary()->getTextures().end(); ++iter) { const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; @@ -8482,7 +8820,7 @@ LLBBox LLVOAvatar::getHUDBBox() const attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - const LLViewerObject* attached_object = (*attachment_iter); + const LLViewerObject* attached_object = attachment_iter->get(); if (attached_object == NULL) { LL_WARNS() << "HUD attached object is NULL!" << LL_ENDL; @@ -8544,13 +8882,16 @@ 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 ); - + if (image->getDiscardLevel() < 0 && !paused) + { + mLastTexCallbackAddedTime.reset(); + } // this could add paused texture callbacks mLoadedCallbacksPaused |= paused; } } - mMeshTexturesDirty = TRUE; + mMeshTexturesDirty = TRUE; gPipeline.markGLRebuild(this); } } @@ -8890,7 +9231,11 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) mLastProcessedAppearance = contents; bool slam_params = false; - applyParsedAppearanceMessage(*contents, slam_params); + applyParsedAppearanceMessage(*contents, slam_params); + if (getOverallAppearance() != AOA_NORMAL) + { + resetSkeleton(false); + } } void LLVOAvatar::applyParsedAppearanceMessage(LLAppearanceMessageContents& contents, bool slam_params) @@ -9149,8 +9494,8 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture 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; - for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); - iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); + for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearance::getDictionary()->getTextures().begin(); + iter != LLAvatarAppearance::getDictionary()->getTextures().end(); ++iter) { @@ -9197,8 +9542,6 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture // static void LLVOAvatar::onInitialBakedTextureLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) { - - LLUUID *avatar_idp = (LLUUID *)userdata; LLVOAvatar *selfp = (LLVOAvatar *)gObjectList.findObject(*avatar_idp); @@ -9283,7 +9626,7 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id ) } const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = - LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i); + LLAvatarAppearance::getDictionary()->getBakedTexture((EBakedTextureIndex)i); for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); local_tex_iter != baked_dict->mLocalTextures.end(); ++local_tex_iter) @@ -9418,7 +9761,7 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara for (U8 te = 0; te < TEX_NUM_INDICES; te++) { - if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)te) == type) + if (LLAvatarAppearance::getDictionary()->getTEWearableType((ETextureIndex)te) == type) { // MULTIPLE_WEARABLES: extend to multiple wearables? LLViewerTexture* te_image = getImage((ETextureIndex)te, 0); @@ -9785,7 +10128,7 @@ BOOL LLVOAvatar::updateLOD() return FALSE; } - if (isImpostor() && 0 != mDrawable->getNumFaces() && mDrawable->getFace(0)->hasGeometry()) + if (!LLPipeline::sImpostorRender && isImpostor() && 0 != mDrawable->getNumFaces() && mDrawable->getFace(0)->hasGeometry()) { return TRUE; } @@ -9848,7 +10191,7 @@ void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes) for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attach_iter = attachment->mAttachedObjects.begin(); attach_iter != attach_end; ++attach_iter) { - LLViewerObject* attached_object = *attach_iter; + LLViewerObject* attached_object = attach_iter->get(); LLVOVolume *volume = dynamic_cast<LLVOVolume*>(attached_object); if (volume) { @@ -9963,7 +10306,7 @@ void LLVOAvatar::onActiveOverrideMeshesChanged() U32 LLVOAvatar::getPartitionType() const { // Avatars merely exist as drawables in the bridge partition - return LLViewerRegion::PARTITION_BRIDGE; + return mIsControlAvatar ? LLViewerRegion::PARTITION_CONTROL_AV : LLViewerRegion::PARTITION_AVATAR; } //static @@ -9976,10 +10319,10 @@ void LLVOAvatar::updateImpostors() iter != instances_copy.end(); ++iter) { LLVOAvatar* avatar = (LLVOAvatar*) *iter; - if (!avatar->isDead() && avatar->isVisible() - && ( - (avatar->isImpostor() || LLVOAvatar::AV_DO_NOT_RENDER == avatar->getVisualMuteSettings()) && avatar->needsImpostorUpdate()) - ) + if (!avatar->isDead() + && avatar->isVisible() + && avatar->isImpostor() + && avatar->needsImpostorUpdate()) { avatar->calcMutedAVColor(); gPipeline.generateImpostor(avatar); @@ -9992,12 +10335,20 @@ void LLVOAvatar::updateImpostors() // virtual BOOL LLVOAvatar::isImpostor() { - return sUseImpostors && (isVisuallyMuted() || (mUpdatePeriod >= IMPOSTOR_PERIOD)) ? TRUE : FALSE; + return isVisuallyMuted() || (sLimitNonImpostors && (mUpdatePeriod > 1)); } -BOOL LLVOAvatar::shouldImpostor(const U32 rank_factor) const +BOOL LLVOAvatar::shouldImpostor(const F32 rank_factor) { - return (!isSelf() && sUseImpostors && mVisibilityRank > (sMaxNonImpostors * rank_factor)); + if (isSelf()) + { + return false; + } + if (isVisuallyMuted()) + { + return true; + } + return sLimitNonImpostors && (mVisibilityRank > sMaxNonImpostors * rank_factor); } BOOL LLVOAvatar::needsImpostorUpdate() const @@ -10040,16 +10391,16 @@ void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& d } // static -const U32 LLVOAvatar::IMPOSTORS_OFF = 66; /* Must equal the maximum allowed the RenderAvatarMaxNonImpostors +const U32 LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER = 66; /* Must equal the maximum allowed the RenderAvatarMaxNonImpostors * slider in panel_preferences_graphics1.xml */ // static void LLVOAvatar::updateImpostorRendering(U32 newMaxNonImpostorsValue) { U32 oldmax = sMaxNonImpostors; - bool oldflg = sUseImpostors; + bool oldflg = sLimitNonImpostors; - if (IMPOSTORS_OFF <= newMaxNonImpostorsValue) + if (NON_IMPOSTORS_MAX_SLIDER <= newMaxNonImpostorsValue) { sMaxNonImpostors = 0; } @@ -10057,13 +10408,13 @@ void LLVOAvatar::updateImpostorRendering(U32 newMaxNonImpostorsValue) { sMaxNonImpostors = newMaxNonImpostorsValue; } - // the sUseImpostors flag depends on whether or not sMaxNonImpostors is set to the no-limit value (0) - sUseImpostors = (0 != sMaxNonImpostors); - if ( oldflg != sUseImpostors ) + // the sLimitNonImpostors flag depends on whether or not sMaxNonImpostors is set to the no-limit value (0) + sLimitNonImpostors = (0 != sMaxNonImpostors); + if ( oldflg != sLimitNonImpostors ) { LL_DEBUGS("AvatarRender") << "was " << (oldflg ? "use" : "don't use" ) << " impostors (max " << oldmax << "); " - << "now " << (sUseImpostors ? "use" : "don't use" ) << " impostors (max " << sMaxNonImpostors << "); " + << "now " << (sLimitNonImpostors ? "use" : "don't use" ) << " impostors (max " << sMaxNonImpostors << "); " << LL_ENDL; } } @@ -10084,7 +10435,10 @@ void LLVOAvatar::idleUpdateRenderComplexity() // Render Complexity calculateUpdateRenderComplexity(); // Update mVisualComplexity if needed +} +void LLVOAvatar::idleUpdateDebugInfo() +{ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_DRAW_INFO)) { std::string info_line; @@ -10230,7 +10584,8 @@ void LLVOAvatar::accountRenderComplexityForObject( LL_DEBUGS("ARCdetail") << "Attachment costs " << attached_object->getAttachmentItemID() << " total: " << attachment_total_cost << ", volume: " << attachment_volume_cost - << ", textures: " << attachment_texture_cost + << ", " << textures.size() + << " textures: " << attachment_texture_cost << ", " << volume->numChildren() << " children: " << attachment_children_cost << LL_ENDL; @@ -10317,7 +10672,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity() // Diagnostic list of all textures on our avatar static std::set<LLUUID> all_textures; - if (mVisualComplexityStale) + if (mVisualComplexityStale) { U32 cost = VISUAL_COMPLEXITY_UNKNOWN; LLVOVolume::texture_cost_t textures; @@ -10326,14 +10681,27 @@ void LLVOAvatar::calculateUpdateRenderComplexity() for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { const LLAvatarAppearanceDictionary::BakedEntry *baked_dict - = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); + = LLAvatarAppearance::getDictionary()->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 +=COMPLEXITY_BODY_PART_COST; - } + // Same as isTextureVisible(), but doesn't account for isSelf to ensure identical numbers for all avatars + if (isIndexLocalTexture(tex_index)) + { + if (isTextureDefined(tex_index, 0)) + { + cost += COMPLEXITY_BODY_PART_COST; + } + } + else + { + // baked textures can use TE images directly + if (isTextureDefined(tex_index) + && (getTEImage(tex_index)->getID() != IMG_INVISIBLE || LLDrawPoolAlpha::sShowDebugAlpha)) + { + cost += COMPLEXITY_BODY_PART_COST; + } + } } } LL_DEBUGS("ARCdetail") << "Avatar body parts complexity: " << cost << LL_ENDL; @@ -10366,7 +10734,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity() attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - const LLViewerObject* attached_object = (*attachment_iter); + const LLViewerObject* attached_object = attachment_iter->get(); accountRenderComplexityForObject(attached_object, max_attachment_complexity, textures, cost, hud_complexity_list); } @@ -10374,8 +10742,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity() // 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. - if (isSelf()) + if (isSelf() && debugLoggingEnabled("ARCdetail")) { // print any attachment textures we didn't already know about. for (LLVOVolume::texture_cost_t::iterator it = textures.begin(); it != textures.end(); ++it) @@ -10391,8 +10758,8 @@ void LLVOAvatar::calculateUpdateRenderComplexity() } // print any avatar textures we didn't already know about - for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); - iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); + for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearance::getDictionary()->getTextures().begin(); + iter != LLAvatarAppearance::getDictionary()->getTextures().end(); ++iter) { const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; @@ -10445,10 +10812,178 @@ void LLVOAvatar::setVisualMuteSettings(VisualMuteSettings set) { mVisuallyMuteSetting = set; mNeedsImpostorUpdate = TRUE; + mLastImpostorUpdateReason = 7; LLRenderMuteList::getInstance()->saveVisualMuteSetting(getID(), S32(set)); } + +void LLVOAvatar::setOverallAppearanceNormal() +{ + if (isControlAvatar()) + return; + + LLVector3 pelvis_pos = getJoint("mPelvis")->getPosition(); + resetSkeleton(false); + getJoint("mPelvis")->setPosition(pelvis_pos); + + for (auto it = mJellyAnims.begin(); it != mJellyAnims.end(); ++it) + { + bool is_playing = (mPlayingAnimations.find(*it) != mPlayingAnimations.end()); + LL_DEBUGS("Avatar") << "jelly anim " << *it << " " << is_playing << LL_ENDL; + if (!is_playing) + { + // Anim was not requested for this av by sim, but may be playing locally + stopMotion(*it); + } + } + mJellyAnims.clear(); + + processAnimationStateChanges(); +} + +void LLVOAvatar::setOverallAppearanceJellyDoll() +{ + if (isControlAvatar()) + return; + + // stop current animations + { + for ( LLVOAvatar::AnimIterator anim_it= mPlayingAnimations.begin(); + anim_it != mPlayingAnimations.end(); + ++anim_it) + { + { + stopMotion(anim_it->first, TRUE); + } + } + } + processAnimationStateChanges(); + + // Start any needed anims for jellydoll + updateOverallAppearanceAnimations(); + + LLVector3 pelvis_pos = getJoint("mPelvis")->getPosition(); + resetSkeleton(false); + getJoint("mPelvis")->setPosition(pelvis_pos); + +} + +void LLVOAvatar::setOverallAppearanceInvisible() +{ +} + +void LLVOAvatar::updateOverallAppearance() +{ + AvatarOverallAppearance new_overall = getOverallAppearance(); + if (new_overall != mOverallAppearance) + { + switch (new_overall) + { + case AOA_NORMAL: + setOverallAppearanceNormal(); + break; + case AOA_JELLYDOLL: + setOverallAppearanceJellyDoll(); + break; + case AOA_INVISIBLE: + setOverallAppearanceInvisible(); + break; + } + mOverallAppearance = new_overall; + if (!isSelf()) + { + mNeedsImpostorUpdate = TRUE; + mLastImpostorUpdateReason = 8; + } + updateMeshVisibility(); + } + + // This needs to be done even if overall appearance has not + // changed, since sit/stand status can be different. + updateOverallAppearanceAnimations(); +} + +void LLVOAvatar::updateOverallAppearanceAnimations() +{ + if (isControlAvatar()) + return; + + if (getOverallAppearance() == AOA_JELLYDOLL) + { + LLUUID motion_id; + if (isSitting() && getParent()) // sitting on object + { + motion_id = ANIM_AGENT_SIT_FEMALE; + } + else if (isSitting()) // sitting on ground + { + motion_id = ANIM_AGENT_SIT_GROUND_CONSTRAINED; + } + else // standing + { + motion_id = ANIM_AGENT_STAND; + } + if (mJellyAnims.find(motion_id) == mJellyAnims.end()) + { + for (auto it = mJellyAnims.begin(); it != mJellyAnims.end(); ++it) + { + bool is_playing = (mPlayingAnimations.find(*it) != mPlayingAnimations.end()); + LL_DEBUGS("Avatar") << "jelly anim " << *it << " " << is_playing << LL_ENDL; + if (!is_playing) + { + // Anim was not requested for this av by sim, but may be playing locally + stopMotion(*it, TRUE); + } + } + mJellyAnims.clear(); + + startMotion(motion_id); + mJellyAnims.insert(motion_id); + + processAnimationStateChanges(); + } + } +} + +// Based on isVisuallyMuted(), but has 3 possible results. +LLVOAvatar::AvatarOverallAppearance LLVOAvatar::getOverallAppearance() const +{ + AvatarOverallAppearance result = AOA_NORMAL; + + // Priority order (highest priority first) + // * own avatar is always drawn normally + // * if on the "always draw normally" list, draw them normally + // * if on the "always visually mute" list, show as jellydoll + // * if explicitly muted (blocked), show as invisible + // * check against the render cost and attachment limits - if too complex, show as jellydoll + if (isSelf()) + { + result = AOA_NORMAL; + } + else // !isSelf() + { + if (isInMuteList()) + { + result = AOA_INVISIBLE; + } + else if (mVisuallyMuteSetting == AV_ALWAYS_RENDER) + { + result = AOA_NORMAL; + } + else if (mVisuallyMuteSetting == AV_DO_NOT_RENDER) + { // Always want to see this AV as an impostor + result = AOA_JELLYDOLL; + } + else if (isTooComplex()) + { + result = AOA_JELLYDOLL; + } + } + + return result; +} + void LLVOAvatar::calcMutedAVColor() { LLColor4 new_color(mMutedAVColor); @@ -10458,8 +10993,8 @@ void LLVOAvatar::calcMutedAVColor() if (getVisualMuteSettings() == AV_DO_NOT_RENDER) { // explicitly not-rendered avatars are light grey - new_color = LLColor4::grey3; - change_msg = " not rendered: color is grey3"; + new_color = LLColor4::grey4; + change_msg = " not rendered: color is grey4"; } else if (LLMuteList::getInstance()->isMuted(av_id)) // the user blocked them { @@ -10472,26 +11007,31 @@ void LLVOAvatar::calcMutedAVColor() new_color = LLColor4::white; change_msg = " simple imposter "; } +#ifdef COLORIZE_JELLYDOLLS else if ( mMutedAVColor == LLColor4::white || mMutedAVColor == LLColor4::grey3 || mMutedAVColor == LLColor4::grey4 ) - { + { // select a color based on the first byte of the agents uuid so any muted agent is always the same color F32 color_value = (F32) (av_id.mData[0]); - F32 spectrum = (color_value / 256.0); // spectrum is between 0 and 1.f + F32 spectrum = (color_value / 256.0); // spectrum is between 0 and 1.f - // Array of colors. These are arranged so only one RGB color changes between each step, + // Array of colors. These are arranged so only one RGB color changes between each step, // and it loops back to red so there is an even distribution. It is not a heat map - const S32 NUM_SPECTRUM_COLORS = 7; + const S32 NUM_SPECTRUM_COLORS = 7; static LLColor4 * spectrum_color[NUM_SPECTRUM_COLORS] = { &LLColor4::red, &LLColor4::magenta, &LLColor4::blue, &LLColor4::cyan, &LLColor4::green, &LLColor4::yellow, &LLColor4::red }; - - spectrum = spectrum * (NUM_SPECTRUM_COLORS - 1); // Scale to range of number of colors - S32 spectrum_index_1 = floor(spectrum); // Desired color will be after this index - S32 spectrum_index_2 = spectrum_index_1 + 1; // and before this index (inclusive) + + spectrum = spectrum * (NUM_SPECTRUM_COLORS - 1); // Scale to range of number of colors + S32 spectrum_index_1 = floor(spectrum); // Desired color will be after this index + S32 spectrum_index_2 = spectrum_index_1 + 1; // and before this index (inclusive) F32 fractBetween = spectrum - (F32)(spectrum_index_1); // distance between the two indexes (0-1) - - new_color = lerp(*spectrum_color[spectrum_index_1], *spectrum_color[spectrum_index_2], fractBetween); - new_color.normalize(); - new_color *= 0.28f; // Tone it down + new_color = lerp(*spectrum_color[spectrum_index_1], *spectrum_color[spectrum_index_2], fractBetween); + new_color.normalize(); + new_color *= 0.28f; // Tone it down + } +#endif + else + { + new_color = LLColor4::grey4; change_msg = " over limit color "; } @@ -10507,7 +11047,7 @@ BOOL LLVOAvatar::isIndexLocalTexture(ETextureIndex index) { return (index < 0 || index >= TEX_NUM_INDICES) ? false - : LLAvatarAppearanceDictionary::getInstance()->getTexture(index)->mIsLocalTexture; + : LLAvatarAppearance::getDictionary()->getTexture(index)->mIsLocalTexture; } // static @@ -10515,15 +11055,15 @@ BOOL LLVOAvatar::isIndexBakedTexture(ETextureIndex index) { return (index < 0 || index >= TEX_NUM_INDICES) ? false - : LLAvatarAppearanceDictionary::getInstance()->getTexture(index)->mIsBakedTexture; + : LLAvatarAppearance::getDictionary()->getTexture(index)->mIsBakedTexture; } const std::string LLVOAvatar::getBakedStatusForPrintout() const { std::string line; - for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); - iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); + for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearance::getDictionary()->getTextures().begin(); + iter != LLAvatarAppearance::getDictionary()->getTextures().end(); ++iter) { const ETextureIndex index = iter->first; diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 00dccc5d12..74ef589ca4 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -91,6 +91,7 @@ class LLVOAvatar : public: friend class LLVOAvatarSelf; + friend class LLAvatarCheckImpostorMode; /******************************************************************************** ** ** @@ -131,6 +132,7 @@ protected: public: /*virtual*/ void updateGL(); /*virtual*/ LLVOAvatar* asAvatar(); + virtual U32 processUpdateMessage(LLMessageSystem *mesgsys, void **user_data, U32 block_num, @@ -252,6 +254,11 @@ public: virtual bool isControlAvatar() const { return mIsControlAvatar; } // True if this avatar is a control av (no associated user) virtual bool isUIAvatar() const { return mIsUIAvatar; } // True if this avatar is a supplemental av used in some UI views (no associated user) + // If this is an attachment, return the avatar it is attached to. Otherwise NULL. + virtual const LLVOAvatar *getAttachedAvatar() const { return NULL; } + virtual LLVOAvatar *getAttachedAvatar() { return NULL; } + + private: //aligned members LL_ALIGN_16(LLVector4a mImpostorExtents[2]); @@ -262,7 +269,8 @@ public: void updateAppearanceMessageDebugText(); void updateAnimationDebugText(); virtual void updateDebugText(); - virtual BOOL updateCharacter(LLAgent &agent); + virtual bool computeNeedsUpdate(); + virtual bool updateCharacter(LLAgent &agent); void updateFootstepSounds(); void computeUpdatePeriod(); void updateOrientation(LLAgent &agent, F32 speed, F32 delta_time); @@ -284,8 +292,9 @@ public: static void invalidateNameTag(const LLUUID& agent_id); // 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 addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font, const bool use_ellipses = false); void idleUpdateRenderComplexity(); + void idleUpdateDebugInfo(); void accountRenderComplexityForObject(const LLViewerObject *attached_object, const F32 max_attachment_complexity, LLVOVolume::texture_cost_t& textures, @@ -313,12 +322,12 @@ public: public: static S32 sRenderName; static BOOL sRenderGroupTitles; - static const U32 IMPOSTORS_OFF; /* Must equal the maximum allowed the RenderAvatarMaxNonImpostors - * slider in panel_preferences_graphics1.xml */ - static U32 sMaxNonImpostors; //(affected by control "RenderAvatarMaxNonImpostors") - static F32 sRenderDistance; //distance at which avatars will render. + static const U32 NON_IMPOSTORS_MAX_SLIDER; /* Must equal the maximum allowed the RenderAvatarMaxNonImpostors + * slider in panel_preferences_graphics1.xml */ + static U32 sMaxNonImpostors; // affected by control "RenderAvatarMaxNonImpostors" + static bool sLimitNonImpostors; // use impostors for far away avatars + 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 sShowCollisionVolumes; // show skeletal collision volumes static BOOL sVisibleInFirstPerson; @@ -348,7 +357,7 @@ public: BOOL isFullyTextured() const; BOOL hasGray() const; S32 getRezzedStatus() const; // 0 = cloud, 1 = gray, 2 = textured, 3 = textured and fully downloaded. - void updateRezzedStatusTimers(); + void updateRezzedStatusTimers(S32 status); S32 mLastRezzedStatus; @@ -406,6 +415,7 @@ public: void initAttachmentPoints(bool ignore_hud_joints = false); /*virtual*/ void buildCharacter(); void resetVisualParams(); + void applyDefaultParams(); void resetSkeleton(bool reset_animations); LLVector3 mCurRootToHeadOffset; @@ -426,9 +436,12 @@ public: public: U32 renderImpostor(LLColor4U color = LLColor4U(255,255,255,255), S32 diffuse_channel = 0); bool isVisuallyMuted(); - bool isInMuteList(); + bool isInMuteList() const; void forceUpdateVisualMuteSettings(); + // Visual Mute Setting is an input. Does not necessarily determine + // what the avatar looks like, because it interacts with other + // settings like muting, complexity threshold. Should be private or protected. enum VisualMuteSettings { AV_RENDER_NORMALLY = 0, @@ -436,21 +449,50 @@ public: AV_ALWAYS_RENDER = 2 }; void setVisualMuteSettings(VisualMuteSettings set); + +protected: + // If you think you need to access this outside LLVOAvatar, you probably want getOverallAppearance() VisualMuteSettings getVisualMuteSettings() { return mVisuallyMuteSetting; }; +public: + + // Overall Appearance is an output. Depending on whether the + // avatar is blocked/muted, whether it exceeds the complexity + // threshold, etc, avatar will want to be displayed in one of + // these ways. Rendering code that wants to know how to display an + // avatar should be looking at this value, NOT the visual mute + // settings + enum AvatarOverallAppearance + { + AOA_NORMAL, + AOA_JELLYDOLL, + AOA_INVISIBLE + }; + + AvatarOverallAppearance getOverallAppearance() const; + void setOverallAppearanceNormal(); + void setOverallAppearanceJellyDoll(); + void setOverallAppearanceInvisible(); + + void updateOverallAppearance(); + void updateOverallAppearanceAnimations(); + + std::set<LLUUID> mJellyAnims; + U32 renderRigid(); U32 renderSkinned(); F32 getLastSkinTime() { return mLastSkinTime; } U32 renderTransparent(BOOL first_pass); void renderCollisionVolumes(); - void renderBones(); + void renderBones(const std::string &selected_joint = std::string()); void renderJoints(); static void deleteCachedImages(bool clearAll=true); static void destroyGL(); static void restoreGL(); S32 mSpecialRenderMode; // special lighting - private: +private: + AvatarOverallAppearance mOverallAppearance; F32 mAttachmentSurfaceArea; //estimated surface area of attachments U32 mAttachmentVisibleTriangleCount; F32 mAttachmentEstTriangleCount; @@ -467,8 +509,8 @@ public: mutable bool mVisualComplexityStale; U32 mReportedVisualComplexity; // from other viewers through the simulator - bool mCachedInMuteList; - F64 mCachedMuteListUpdateTime; + mutable bool mCachedInMuteList; + mutable F64 mCachedMuteListUpdateTime; VisualMuteSettings mVisuallyMuteSetting; // Always or never visually mute this AV @@ -519,7 +561,7 @@ private: //-------------------------------------------------------------------- public: virtual BOOL isImpostor(); - BOOL shouldImpostor(const U32 rank_factor = 1) const; + BOOL shouldImpostor(const F32 rank_factor = 1.0); BOOL needsImpostorUpdate() const; const LLVector3& getImpostorOffset() const; const LLVector2& getImpostorDim() const; @@ -530,6 +572,7 @@ public: static void updateImpostors(); LLRenderTarget mImpostor; BOOL mNeedsImpostorUpdate; + S32 mLastImpostorUpdateReason; F32SecondsImplicit mLastImpostorUpdateFrameTime; const LLVector3* getLastAnimExtents() const { return mLastAnimExtents; } void setNeedsExtentUpdate(bool val) { mNeedsExtentUpdate = val; } @@ -629,6 +672,8 @@ protected: LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ; BOOL mLoadedCallbacksPaused; + S32 mLoadedCallbackTextures; // count of 'loaded' baked textures, filled from mCallbackTextureList + LLFrameTimer mLastTexCallbackAddedTime; std::set<LLUUID> mTextureIDs; //-------------------------------------------------------------------- // Local Textures @@ -674,9 +719,6 @@ public: public: static BOOL isIndexLocalTexture(LLAvatarAppearanceDefines::ETextureIndex i); static BOOL isIndexBakedTexture(LLAvatarAppearanceDefines::ETextureIndex i); -private: - static const LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary *getDictionary() { return sAvatarDictionary; } - static LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary* sAvatarDictionary; //-------------------------------------------------------------------- // Messaging diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index dcaade55a6..7faca2ee5b 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -465,6 +465,8 @@ BOOL LLVOAvatarSelf::buildMenus() if (gDetachBodyPartPieMenus[i]) { gDetachPieMenu->appendContextSubMenu( gDetachBodyPartPieMenus[i] ); + gDetachAttSelfMenu->appendContextSubMenu(gDetachBodyPartPieMenus[i]); + gDetachAvatarMenu->appendContextSubMenu(gDetachBodyPartPieMenus[i]); } else { @@ -493,12 +495,14 @@ BOOL LLVOAvatarSelf::buildMenus() LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); gDetachPieMenu->addChild(item); - + gDetachAttSelfMenu->addChild(LLUICtrlFactory::create<LLMenuItemCallGL>(item_params)); + gDetachAvatarMenu->addChild(LLUICtrlFactory::create<LLMenuItemCallGL>(item_params)); break; } } } } + // add screen attachments for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); @@ -532,6 +536,8 @@ BOOL LLVOAvatarSelf::buildMenus() item_params.on_enable.parameter = iter->first; item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); gDetachScreenPieMenu->addChild(item); + gDetachHUDAttSelfMenu->addChild(LLUICtrlFactory::create<LLMenuItemCallGL>(item_params)); + gDetachHUDAvatarMenu->addChild(LLUICtrlFactory::create<LLMenuItemCallGL>(item_params)); } } @@ -668,7 +674,7 @@ LLVOAvatarSelf::~LLVOAvatarSelf() *********************************************************************************/ // virtual -BOOL LLVOAvatarSelf::updateCharacter(LLAgent &agent) +bool LLVOAvatarSelf::updateCharacter(LLAgent &agent) { // update screen joint size if (mScreenp) @@ -1079,8 +1085,8 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode) //----------------------------------------------------------------------------- void LLVOAvatarSelf::wearableUpdated(LLWearableType::EType type) { - for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin(); - baked_iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); + for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin(); + baked_iter != sAvatarDictionary->getBakedTextures().end(); ++baked_iter) { const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = baked_iter->second; @@ -1208,7 +1214,7 @@ BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object) // the simulator should automatically handle permission revocation stopMotionFromSource(attachment_id); - LLFollowCamMgr::setCameraActive(viewer_object->getID(), FALSE); + LLFollowCamMgr::getInstance()->setCameraActive(viewer_object->getID(), FALSE); LLViewerObject::const_child_list_t& child_list = viewer_object->getChildren(); for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); @@ -1220,7 +1226,7 @@ BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object) // permissions revocation stopMotionFromSource(child_objectp->getID()); - LLFollowCamMgr::setCameraActive(child_objectp->getID(), FALSE); + LLFollowCamMgr::getInstance()->setCameraActive(child_objectp->getID(), FALSE); } // Make sure the inventory is in sync with the avatar. @@ -1250,7 +1256,7 @@ BOOL LLVOAvatarSelf::detachAttachmentIntoInventory(const LLUUID &item_id) gMessageSystem->nextBlockFast(_PREHASH_ObjectData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id); - gMessageSystem->sendReliable(gAgent.getRegion()->getHost()); + gMessageSystem->sendReliable(gAgent.getRegionHost()); // This object might have been selected, so let the selection manager know it's gone now LLViewerObject *found_obj = gObjectList.findObject(item_id); @@ -1277,7 +1283,7 @@ BOOL LLVOAvatarSelf::detachAttachmentIntoInventory(const LLUUID &item_id) U32 LLVOAvatarSelf::getNumWearables(LLAvatarAppearanceDefines::ETextureIndex i) const { - LLWearableType::EType type = LLAvatarAppearanceDictionary::getInstance()->getTEWearableType(i); + LLWearableType::EType type = sAvatarDictionary->getTEWearableType(i); return gAgentWearables.getWearableCount(type); } @@ -1388,8 +1394,8 @@ BOOL LLVOAvatarSelf::isLocalTextureDataAvailable(const LLViewerTexLayerSet* laye { /* if (layerset == mBakedTextureDatas[BAKED_HEAD].mTexLayerSet) return getLocalDiscardLevel(TEX_HEAD_BODYPAINT) >= 0; */ - for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin(); - baked_iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); + for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin(); + baked_iter != sAvatarDictionary->getBakedTextures().end(); ++baked_iter) { const EBakedTextureIndex baked_index = baked_iter->first; @@ -1402,7 +1408,7 @@ BOOL LLVOAvatarSelf::isLocalTextureDataAvailable(const LLViewerTexLayerSet* laye ++local_tex_iter) { const ETextureIndex tex_index = *local_tex_iter; - const LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType(tex_index); + const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index); const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) { @@ -1432,13 +1438,13 @@ BOOL LLVOAvatarSelf::isLocalTextureDataFinal(const LLViewerTexLayerSet* layerset { if (layerset == mBakedTextureDatas[i].mTexLayerSet) { - const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i); + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = sAvatarDictionary->getBakedTexture((EBakedTextureIndex)i); for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); local_tex_iter != baked_dict->mLocalTextures.end(); ++local_tex_iter) { const ETextureIndex tex_index = *local_tex_iter; - const LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType(tex_index); + const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index); const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) { @@ -1465,13 +1471,13 @@ BOOL LLVOAvatarSelf::isAllLocalTextureDataFinal() const for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { - const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i); + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = sAvatarDictionary->getBakedTexture((EBakedTextureIndex)i); for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); local_tex_iter != baked_dict->mLocalTextures.end(); ++local_tex_iter) { const ETextureIndex tex_index = *local_tex_iter; - const LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType(tex_index); + const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index); const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) { @@ -1493,7 +1499,7 @@ BOOL LLVOAvatarSelf::isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex t BOOL isDefined = TRUE; if (isIndexLocalTexture(type)) { - const LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType(type); + const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(type); const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); if (index >= wearable_count) { @@ -1710,7 +1716,7 @@ void LLVOAvatarSelf::setLocalTexture(ETextureIndex type, LLViewerTexture* src_te LL_ERRS() << "Tried to set local texture with invalid type: (" << (U32) type << ", " << index << ")" << LL_ENDL; return; } - LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getInstance()->getTEWearableType(type); + LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(type); if (!gAgentWearables.getViewerWearable(wearable_type,index)) { // no wearable is loaded, cannot set the texture. @@ -1787,8 +1793,8 @@ void LLVOAvatarSelf::dumpLocalTextures() const /* ETextureIndex baked_equiv[] = { TEX_UPPER_BAKED, if (isTextureDefined(baked_equiv[i])) */ - for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); - iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); + for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = sAvatarDictionary->getTextures().begin(); + iter != sAvatarDictionary->getTextures().end(); ++iter) { const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; @@ -1796,7 +1802,7 @@ void LLVOAvatarSelf::dumpLocalTextures() const continue; const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; - const ETextureIndex baked_equiv = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex; + const ETextureIndex baked_equiv = sAvatarDictionary->getBakedTexture(baked_index)->mTextureIndex; const std::string &name = texture_dict->mName; const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(iter->first, 0); @@ -2031,8 +2037,8 @@ const std::string LLVOAvatarSelf::verboseDebugDumpLocalTextureDataInfo(const LLV { std::ostringstream outbuf; for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = - LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin(); - baked_iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); + sAvatarDictionary->getBakedTextures().begin(); + baked_iter != sAvatarDictionary->getBakedTextures().end(); ++baked_iter) { const EBakedTextureIndex baked_index = baked_iter->first; @@ -2045,9 +2051,9 @@ const std::string LLVOAvatarSelf::verboseDebugDumpLocalTextureDataInfo(const LLV ++local_tex_iter) { const ETextureIndex tex_index = *local_tex_iter; - const std::string tex_name = LLAvatarAppearanceDictionary::getInstance()->getTexture(tex_index)->mName; + const std::string tex_name = sAvatarDictionary->getTexture(tex_index)->mName; outbuf << " tex_index " << (S32) tex_index << " name " << tex_name << "\n"; - const LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType(tex_index); + const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index); const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); if (wearable_count > 0) { @@ -2091,8 +2097,8 @@ const std::string LLVOAvatarSelf::verboseDebugDumpLocalTextureDataInfo(const LLV void LLVOAvatarSelf::dumpAllTextures() const { std::string vd_text = "Local textures per baked index and wearable:\n"; - for (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin(); - baked_iter != LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); + for (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin(); + baked_iter != sAvatarDictionary->getBakedTextures().end(); ++baked_iter) { const LLAvatarAppearanceDefines::EBakedTextureIndex baked_index = baked_iter->first; @@ -2113,8 +2119,8 @@ const std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLViewerTe /* if (layerset == mBakedTextureDatas[BAKED_HEAD].mTexLayerSet) return getLocalDiscardLevel(TEX_HEAD_BODYPAINT) >= 0; */ - for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin(); - baked_iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); + for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin(); + baked_iter != sAvatarDictionary->getBakedTextures().end(); ++baked_iter) { const EBakedTextureIndex baked_index = baked_iter->first; @@ -2127,7 +2133,7 @@ const std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLViewerTe ++local_tex_iter) { const ETextureIndex tex_index = *local_tex_iter; - const LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType(tex_index); + const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index); const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); if (wearable_count > 0) { @@ -2154,14 +2160,14 @@ const std::string LLVOAvatarSelf::debugDumpAllLocalTextureDataInfo() const for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { - const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i); + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = sAvatarDictionary->getBakedTexture((EBakedTextureIndex)i); BOOL is_texture_final = TRUE; for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); local_tex_iter != baked_dict->mLocalTextures.end(); ++local_tex_iter) { const ETextureIndex tex_index = *local_tex_iter; - const LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType(tex_index); + const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index); const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) { @@ -2341,7 +2347,7 @@ const LLUUID& LLVOAvatarSelf::grabBakedTexture(EBakedTextureIndex baked_index) c { if (canGrabBakedTexture(baked_index)) { - ETextureIndex tex_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(baked_index); + ETextureIndex tex_index = sAvatarDictionary->bakedToLocalTextureIndex(baked_index); if (tex_index == TEX_NUM_INDICES) { return LLUUID::null; @@ -2353,7 +2359,7 @@ const LLUUID& LLVOAvatarSelf::grabBakedTexture(EBakedTextureIndex baked_index) c BOOL LLVOAvatarSelf::canGrabBakedTexture(EBakedTextureIndex baked_index) const { - ETextureIndex tex_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(baked_index); + ETextureIndex tex_index = sAvatarDictionary->bakedToLocalTextureIndex(baked_index); if (tex_index == TEX_NUM_INDICES) { return FALSE; @@ -2372,13 +2378,13 @@ BOOL LLVOAvatarSelf::canGrabBakedTexture(EBakedTextureIndex baked_index) const // baked texture. We don't want people copying people's // work via baked textures. - const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(baked_index); + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = sAvatarDictionary->getBakedTexture(baked_index); for (texture_vec_t::const_iterator iter = baked_dict->mLocalTextures.begin(); iter != baked_dict->mLocalTextures.end(); ++iter) { const ETextureIndex t_index = (*iter); - LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType(t_index); + LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(t_index); U32 count = gAgentWearables.getWearableCount(wearable_type); LL_DEBUGS() << "Checking index " << (U32) t_index << " count: " << count << LL_ENDL; @@ -2466,7 +2472,7 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe LLLocalTextureObject* LLVOAvatarSelf::getLocalTextureObject(LLAvatarAppearanceDefines::ETextureIndex i, U32 wearable_index) const { - LLWearableType::EType type = LLAvatarAppearanceDictionary::getInstance()->getTEWearableType(i); + LLWearableType::EType type = sAvatarDictionary->getTEWearableType(i); LLViewerWearable* wearable = gAgentWearables.getViewerWearable(type, wearable_index); if (wearable) { @@ -2540,8 +2546,8 @@ void LLVOAvatarSelf::outputRezDiagnostics() const LL_DEBUGS("Avatar") << "\t\t (" << i << ") \t" << (S32)mDebugBakedTextureTimes[i][0] << " / " << (S32)mDebugBakedTextureTimes[i][1] << LL_ENDL; } - for (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin(); - baked_iter != LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); + for (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin(); + baked_iter != sAvatarDictionary->getBakedTextures().end(); ++baked_iter) { const LLAvatarAppearanceDefines::EBakedTextureIndex baked_index = baked_iter->first; @@ -2607,7 +2613,7 @@ void LLVOAvatarSelf::requestLayerSetUpdate(ETextureIndex index ) case LOCTEX_UPPER_SHIRT: if( mUpperBodyLayerSet ) mUpperBodyLayerSet->requestUpdate(); */ - const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(index); + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = sAvatarDictionary->getTexture(index); if (!texture_dict) return; if (!texture_dict->mIsLocalTexture || !texture_dict->mIsUsedByBakedTexture) @@ -2625,7 +2631,7 @@ LLViewerTexLayerSet* LLVOAvatarSelf::getLayerSet(ETextureIndex index) const case TEX_HEAD_BAKED: case TEX_HEAD_BODYPAINT: return mHeadLayerSet; */ - const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(index); + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = sAvatarDictionary->getTexture(index); if (texture_dict && texture_dict->mIsUsedByBakedTexture) { const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; @@ -2667,11 +2673,6 @@ void LLVOAvatarSelf::onCustomizeStart(bool disable_camera_switch) { gAgentCamera.changeCameraToCustomizeAvatar(); } - -#if 0 - gAgentAvatarp->clearVisualParamWeights(); - gAgentAvatarp->idleUpdateAppearanceAnimation(); -#endif gAgentAvatarp->invalidateAll(); // mark all bakes as dirty, request updates gAgentAvatarp->updateMeshTextures(); // make sure correct textures are applied to the avatar mesh. @@ -2716,8 +2717,8 @@ bool LLVOAvatarSelf::sendAppearanceMessage(LLMessageSystem *mesgsys) const { LLUUID texture_id[TEX_NUM_INDICES]; // pack away current TEs to make sure we don't send them out - for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); - iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); + for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = sAvatarDictionary->getTextures().begin(); + iter != sAvatarDictionary->getTextures().end(); ++iter) { const ETextureIndex index = iter->first; @@ -2733,8 +2734,8 @@ bool LLVOAvatarSelf::sendAppearanceMessage(LLMessageSystem *mesgsys) const bool success = packTEMessage(mesgsys); // unpack TEs to make sure we don't re-trigger a bake - for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); - iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); + for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = sAvatarDictionary->getTextures().begin(); + iter != sAvatarDictionary->getTextures().end(); ++iter) { const ETextureIndex index = iter->first; diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index b0fdae9bf0..279dbd61a6 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -116,7 +116,7 @@ public: // Updates //-------------------------------------------------------------------- public: - /*virtual*/ BOOL updateCharacter(LLAgent &agent); + /*virtual*/ bool updateCharacter(LLAgent &agent); /*virtual*/ void idleUpdateTractorBeam(); bool checkStuckAppearance(); diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index fb28d9bdb5..5ebc65405f 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -44,6 +44,9 @@ F32 LLVOCacheEntry::sFrontPixelThreshold = 1.0f; F32 LLVOCacheEntry::sRearPixelThreshold = 1.0f; BOOL LLVOCachePartition::sNeedsOcclusionCheck = FALSE; +const S32 ENTRY_HEADER_SIZE = 6 * sizeof(S32); +const S32 MAX_ENTRY_BODY_SIZE = 10000; + BOOL check_read(LLAPRFile* apr_file, void* src, S32 n_bytes) { return apr_file->read(src, n_bytes) == n_bytes ; @@ -111,32 +114,22 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file) { S32 size = -1; BOOL success; + static U8 data_buffer[ENTRY_HEADER_SIZE]; mDP.assignBuffer(mBuffer, 0); - - success = check_read(apr_file, &mLocalID, sizeof(U32)); - if(success) - { - success = check_read(apr_file, &mCRC, sizeof(U32)); - } - if(success) - { - success = check_read(apr_file, &mHitCount, sizeof(S32)); - } - if(success) - { - success = check_read(apr_file, &mDupeCount, sizeof(S32)); - } - if(success) - { - success = check_read(apr_file, &mCRCChangeCount, sizeof(S32)); - } - if(success) - { - success = check_read(apr_file, &size, sizeof(S32)); + + success = check_read(apr_file, (void *)data_buffer, ENTRY_HEADER_SIZE); + if (success) + { + memcpy(&mLocalID, data_buffer, sizeof(U32)); + memcpy(&mCRC, data_buffer + sizeof(U32), sizeof(U32)); + memcpy(&mHitCount, data_buffer + (2 * sizeof(U32)), sizeof(S32)); + memcpy(&mDupeCount, data_buffer + (3 * sizeof(U32)), sizeof(S32)); + memcpy(&mCRCChangeCount, data_buffer + (4 * sizeof(U32)), sizeof(S32)); + memcpy(&size, data_buffer + (5 * sizeof(U32)), sizeof(S32)); // Corruption in the cache entries - if ((size > 10000) || (size < 1)) + if ((size > MAX_ENTRY_BODY_SIZE) || (size < 1)) { // We've got a bogus size, skip reading it. // We won't bother seeking, because the rest of this file @@ -345,38 +338,25 @@ void LLVOCacheEntry::dump() const << LL_ENDL; } -BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const +S32 LLVOCacheEntry::writeToBuffer(U8 *data_buffer) const { - BOOL success; - success = check_write(apr_file, (void*)&mLocalID, sizeof(U32)); - if(success) - { - success = check_write(apr_file, (void*)&mCRC, sizeof(U32)); - } - if(success) - { - success = check_write(apr_file, (void*)&mHitCount, sizeof(S32)); - } - if(success) - { - success = check_write(apr_file, (void*)&mDupeCount, sizeof(S32)); - } - if(success) - { - success = check_write(apr_file, (void*)&mCRCChangeCount, sizeof(S32)); - } - if(success) - { - S32 size = mDP.getBufferSize(); - success = check_write(apr_file, (void*)&size, sizeof(S32)); - - if(success) - { - success = check_write(apr_file, (void*)mBuffer, size); - } - } - - return success ; + S32 size = mDP.getBufferSize(); + + if (size > MAX_ENTRY_BODY_SIZE) + { + LL_WARNS() << "Failed to write entry with size above allowed limit: " << size << LL_ENDL; + return 0; + } + + memcpy(data_buffer, &mLocalID, sizeof(U32)); + memcpy(data_buffer + sizeof(U32), &mCRC, sizeof(U32)); + memcpy(data_buffer + (2 * sizeof(U32)), &mHitCount, sizeof(S32)); + memcpy(data_buffer + (3 * sizeof(U32)), &mDupeCount, sizeof(S32)); + memcpy(data_buffer + (4 * sizeof(U32)), &mCRCChangeCount, sizeof(S32)); + memcpy(data_buffer + (5 * sizeof(U32)), &size, sizeof(S32)); + memcpy(data_buffer + ENTRY_HEADER_SIZE, (void*)mBuffer, size); + + return ENTRY_HEADER_SIZE + size; } //static @@ -1045,9 +1025,9 @@ const char* object_cache_dirname = "objectcache"; const char* header_filename = "object.cache"; -LLVOCache::LLVOCache(): +LLVOCache::LLVOCache(bool read_only) : mInitialized(false), - mReadOnly(true), + mReadOnly(read_only), mNumEntries(0), mCacheSize(1) { @@ -1405,11 +1385,11 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca bool success = true ; { std::string filename; + LLUUID cache_id; getObjectCacheFilename(handle, filename); LLAPRFile apr_file(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp); - LLUUID cache_id ; - success = check_read(&apr_file, cache_id.mData, UUID_BYTES) ; + success = check_read(&apr_file, cache_id.mData, UUID_BYTES); if(success) { @@ -1421,7 +1401,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca if(success) { - S32 num_entries; + S32 num_entries; // if removal was enabled during write num_entries might be wrong success = check_read(&apr_file, &num_entries, sizeof(S32)) ; if(success) @@ -1528,27 +1508,57 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: { std::string filename; getObjectCacheFilename(handle, filename); - LLAPRFile apr_file(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); + LLAPRFile apr_file(filename, APR_CREATE|APR_WRITE|APR_BINARY|APR_TRUNCATE, mLocalAPRFilePoolp); - success = check_write(&apr_file, (void*)id.mData, UUID_BYTES) ; - + success = check_write(&apr_file, (void*)id.mData, UUID_BYTES); if(success) { - S32 num_entries = cache_entry_map.size() ; + S32 num_entries = cache_entry_map.size(); // if removal is enabled num_entries might be wrong success = check_write(&apr_file, &num_entries, sizeof(S32)); - - for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); success && iter != cache_entry_map.end(); ++iter) - { - if(!removal_enabled || iter->second->isValid()) - { - success = iter->second->writeToFile(&apr_file) ; - if(!success) - { - break; - } - } - } + if (success) + { + const S32 buffer_size = 32768; //should be large enough for couple MAX_ENTRY_BODY_SIZE + U8 data_buffer[buffer_size]; // generaly entries are fairly small, so collect them and drop onto disk in one go + S32 size_in_buffer = 0; + + // This can have a lot of entries, so might be better to dump them into buffer first and write in one go. + for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); success && iter != cache_entry_map.end(); ++iter) + { + if (!removal_enabled || iter->second->isValid()) + { + S32 size = iter->second->writeToBuffer(data_buffer + size_in_buffer); + + if (size > ENTRY_HEADER_SIZE) // body is minimum of 1 + { + size_in_buffer += size; + } + else + { + success = false; + break; + } + + // Make sure we have space in buffer for next element + if (buffer_size - size_in_buffer < MAX_ENTRY_BODY_SIZE + ENTRY_HEADER_SIZE) + { + success = check_write(&apr_file, (void*)data_buffer, size_in_buffer); + size_in_buffer = 0; + if (!success) + { + break; + } + } + } + } + + if (success && size_in_buffer > 0) + { + // final write + success = check_write(&apr_file, (void*)data_buffer, size_in_buffer); + size_in_buffer = 0; + } + } } } diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index 594d38249b..dd6afd6b85 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -106,7 +106,7 @@ public: F32 getSceneContribution() const { return mSceneContrib;} void dump() const; - BOOL writeToFile(LLAPRFile* apr_file) const; + S32 writeToBuffer(U8 *data_buffer) const; LLDataPackerBinaryBuffer *getDP(); void recordHit(); void recordDupe() { mDupeCount++; } @@ -221,9 +221,9 @@ private: // //Note: LLVOCache is not thread-safe // -class LLVOCache : public LLSingleton<LLVOCache> +class LLVOCache : public LLParamSingleton<LLVOCache> { - LLSINGLETON(LLVOCache); + LLSINGLETON(LLVOCache, bool read_only); ~LLVOCache() ; private: @@ -259,15 +259,14 @@ private: typedef std::map<U64, HeaderEntryInfo*> handle_entry_map_t; public: - void initCache(ELLPath location, U32 size, U32 cache_version) ; + // We need this init to be separate from constructor, since we might construct cache, purge it, then init. + void initCache(ELLPath location, U32 size, U32 cache_version); void removeCache(ELLPath location, bool started = false) ; void readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ; void writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache, bool removal_enabled); void removeEntry(U64 handle) ; - void setReadOnly(bool read_only) {mReadOnly = read_only;} - U32 getCacheEntries() { return mNumEntries; } U32 getCacheEntriesMax() { return mCacheSize; } diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index d651d540b9..345e87eea8 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -288,24 +288,12 @@ void LLVOGrass::idleUpdate(LLAgent &agent, const F64 &time) // So drones work. return; } - - if(LLVOTree::isTreeRenderingStopped()) //stop rendering grass + if (!LLVOTree::isTreeRenderingStopped() && !mNumBlades)//restart grass rendering { - if(mNumBlades) - { - mNumBlades = 0 ; - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); - } - return; - } - else if(!mNumBlades)//restart grass rendering - { - mNumBlades = GRASS_MAX_BLADES ; + mNumBlades = GRASS_MAX_BLADES; gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); - return; } - if (mPatch && (mLastPatchUpdateTime != mPatch->getLastUpdateTime())) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); @@ -352,11 +340,15 @@ BOOL LLVOGrass::updateLOD() { return FALSE; } + + LLFace* face = mDrawable->getFace(0); + if(LLVOTree::isTreeRenderingStopped()) { if(mNumBlades) { mNumBlades = 0 ; + face->setSize(0, 0); gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); } return TRUE ; @@ -366,8 +358,6 @@ BOOL LLVOGrass::updateLOD() mNumBlades = GRASS_MAX_BLADES; } - LLFace* face = mDrawable->getFace(0); - F32 tan_angle = 0.f; S32 num_blades = 0; diff --git a/indra/newview/llvoground.cpp b/indra/newview/llvoground.cpp index 71a7623fb4..52a6395618 100644 --- a/indra/newview/llvoground.cpp +++ b/indra/newview/llvoground.cpp @@ -126,7 +126,7 @@ BOOL LLVOGround::updateGeometry(LLDrawable *drawable) left_dir.normVec(); // Our center top point - LLColor4 ground_color = gSky.getFogColor(); + LLColor4 ground_color = gSky.getSkyFogColor(); ground_color.mV[3] = 1.f; face->setFaceColor(ground_color); diff --git a/indra/newview/llvoicecallhandler.cpp b/indra/newview/llvoicecallhandler.cpp index 2050dab689..1e993d1384 100644 --- a/indra/newview/llvoicecallhandler.cpp +++ b/indra/newview/llvoicecallhandler.cpp @@ -40,7 +40,7 @@ public: bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) { - if (!LLUI::sSettingGroups["config"]->getBOOL("EnableVoiceCall")) + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableVoiceCall")) { LLNotificationsUtil::add("NoVoiceCall", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); return true; diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 5c107cc10b..e2bd1a39c7 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -116,7 +116,7 @@ std::string LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserv /////////////////////////////////////////////////////////////////////////////////////////////// -LLVoiceClient::LLVoiceClient() +LLVoiceClient::LLVoiceClient(LLPumpIO *pump) : mVoiceModule(NULL), m_servicePump(NULL), @@ -125,7 +125,7 @@ LLVoiceClient::LLVoiceClient() mPTTDirty(true), mPTT(true), mUsePTT(true), - mPTTIsMiddleMouse(false), + mPTTMouseButton(0), mPTTKey(0), mPTTIsToggle(false), mUserPTTState(false), @@ -133,6 +133,7 @@ LLVoiceClient::LLVoiceClient() mDisableMic(false) { updateSettings(); + init(pump); } //--------------------------------------------------- @@ -179,6 +180,13 @@ void LLVoiceClient::terminate() { if (mVoiceModule) mVoiceModule->terminate(); mVoiceModule = NULL; + m_servicePump = NULL; + + // Shutdown speaker volume storage before LLSingletonBase::deleteAll() does it + if (LLSpeakerVolumeStorage::instanceExists()) + { + LLSpeakerVolumeStorage::deleteSingleton(); + } } const LLVoiceVersionInfo LLVoiceClient::getVersion() @@ -199,8 +207,6 @@ const LLVoiceVersionInfo LLVoiceClient::getVersion() void LLVoiceClient::updateSettings() { setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled")); - std::string keyString = gSavedSettings.getString("PushToTalkButton"); - setPTTKey(keyString); setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle")); mDisableMic = gSavedSettings.getBOOL("VoiceDisableMic"); @@ -636,23 +642,6 @@ bool LLVoiceClient::getPTTIsToggle() return mPTTIsToggle; } -void LLVoiceClient::setPTTKey(std::string &key) -{ - if(key == "MiddleMouse") - { - mPTTIsMiddleMouse = true; - } - else - { - mPTTIsMiddleMouse = false; - if(!LLKeyboard::keyFromString(key, &mPTTKey)) - { - // If the call failed, don't match any key. - key = KEY_NONE; - } - } -} - void LLVoiceClient::inputUserControlState(bool down) { if(mPTTIsToggle) @@ -673,43 +662,6 @@ void LLVoiceClient::toggleUserPTTState(void) setUserPTTState(!getUserPTTState()); } -void LLVoiceClient::keyDown(KEY key, MASK mask) -{ - if (gKeyboard->getKeyRepeated(key)) - { - // ignore auto-repeat keys - return; - } - - if (!mPTTIsMiddleMouse && LLAgent::isActionAllowed("speak") && (key == mPTTKey)) - { - bool down = gKeyboard->getKeyDown(mPTTKey); - if (down) - { - inputUserControlState(down); - } - } - -} -void LLVoiceClient::keyUp(KEY key, MASK mask) -{ - if (!mPTTIsMiddleMouse && (key == mPTTKey)) - { - bool down = gKeyboard->getKeyDown(mPTTKey); - if (!down) - { - inputUserControlState(down); - } - } -} -void LLVoiceClient::middleMouseState(bool down) -{ - if(mPTTIsMiddleMouse && LLAgent::isActionAllowed("speak")) - { - inputUserControlState(down); - } -} - //------------------------------------------- // nearby speaker accessors @@ -971,7 +923,12 @@ LLSpeakerVolumeStorage::LLSpeakerVolumeStorage() LLSpeakerVolumeStorage::~LLSpeakerVolumeStorage() { - save(); +} + +//virtual +void LLSpeakerVolumeStorage::cleanupSingleton() +{ + save(); } void LLSpeakerVolumeStorage::storeSpeakerVolume(const LLUUID& speaker_id, F32 volume) diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index 758e9cecd7..cf527a4464 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -310,9 +310,9 @@ public: }; -class LLVoiceClient: public LLSingleton<LLVoiceClient> +class LLVoiceClient: public LLParamSingleton<LLVoiceClient> { - LLSINGLETON(LLVoiceClient); + LLSINGLETON(LLVoiceClient, LLPumpIO *pump); LOG_CLASS(LLVoiceClient); ~LLVoiceClient(); @@ -320,7 +320,6 @@ public: typedef boost::signals2::signal<void(void)> 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 const LLVoiceVersionInfo getVersion(); @@ -409,17 +408,11 @@ public: void setUsePTT(bool usePTT); void setPTTIsToggle(bool PTTIsToggle); bool getPTTIsToggle(); - void setPTTKey(std::string &key); - + void updateMicMuteLogic(); - + BOOL lipSyncEnabled(); - - // PTT key triggering - void keyDown(KEY key, MASK mask); - 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); } @@ -472,6 +465,8 @@ public: // Returns NULL if voice effects are not supported, or not enabled. LLVoiceEffectInterface* getVoiceEffectInterface() const; //@} +private: + void init(LLPumpIO *pump); protected: LLVoiceModuleInterface* mVoiceModule; @@ -485,7 +480,7 @@ protected: bool mPTT; bool mUsePTT; - bool mPTTIsMiddleMouse; + S32 mPTTMouseButton; KEY mPTTKey; bool mPTTIsToggle; bool mUserPTTState; @@ -498,9 +493,13 @@ protected: **/ class LLSpeakerVolumeStorage : public LLSingleton<LLSpeakerVolumeStorage> { - LLSINGLETON(LLSpeakerVolumeStorage); + LLSINGLETON_C11(LLSpeakerVolumeStorage); ~LLSpeakerVolumeStorage(); LOG_CLASS(LLSpeakerVolumeStorage); + +protected: + virtual void cleanupSingleton() override; + public: /** diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index e10ba77e16..4d2eac8c09 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -274,6 +274,8 @@ static void killGateway() /////////////////////////////////////////////////////////////////////////////////////////////// +bool LLVivoxVoiceClient::sShuttingDown = false; + LLVivoxVoiceClient::LLVivoxVoiceClient() : mSessionTerminateRequested(false), mRelogRequested(false), @@ -338,15 +340,15 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() : mPlayRequestCount(0), mAvatarNameCacheConnection(), - mIsInTuningMode(false), - mIsInChannel(false), - mIsJoiningSession(false), - mIsWaitingForFonts(false), - mIsLoggingIn(false), - mIsLoggedIn(false), - mIsProcessingChannels(false), - mIsCoroutineActive(false), - mVivoxPump("vivoxClientPump") + mIsInTuningMode(false), + mIsInChannel(false), + mIsJoiningSession(false), + mIsWaitingForFonts(false), + mIsLoggingIn(false), + mIsLoggedIn(false), + mIsProcessingChannels(false), + mIsCoroutineActive(false), + mVivoxPump("vivoxClientPump") { mSpeakerVolume = scale_speaker_volume(0); @@ -357,7 +359,7 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() : // gMuteListp->addObserver(&mutelist_listener); -#if LL_DARWIN || LL_LINUX || LL_SOLARIS +#if LL_DARWIN || LL_LINUX // HACK: THIS DOES NOT BELONG HERE // When the vivox daemon dies, the next write attempt on our socket generates a SIGPIPE, which kills us. // This should cause us to ignore SIGPIPE and handle the error through proper channels. @@ -381,6 +383,7 @@ LLVivoxVoiceClient::~LLVivoxVoiceClient() { mAvatarNameCacheConnection.disconnect(); } + sShuttingDown = true; } //--------------------------------------------------- @@ -388,9 +391,9 @@ LLVivoxVoiceClient::~LLVivoxVoiceClient() void LLVivoxVoiceClient::init(LLPumpIO *pump) { // constructor will set up LLVoiceClient::getInstance() - LLVivoxVoiceClient::getInstance()->mPump = pump; + mPump = pump; -// LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro();", +// LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro", // boost::bind(&LLVivoxVoiceClient::voiceControlCoro, LLVivoxVoiceClient::getInstance())); } @@ -411,8 +414,12 @@ void LLVivoxVoiceClient::terminate() } else { + mRelogRequested = false; killGateway(); } + + sShuttingDown = true; + mPump = NULL; } //--------------------------------------------------- @@ -527,7 +534,7 @@ void LLVivoxVoiceClient::connectorCreate() << "<FileNameSuffix>.log</FileNameSuffix>" << "<LogLevel>" << vivoxLogLevel << "</LogLevel>" << "</Logging>" - << "<Application>" << LLVersionInfo::getChannel().c_str() << " " << LLVersionInfo::getVersion().c_str() << "</Application>" + << "<Application>" << LLVersionInfo::instance().getChannel() << " " << LLVersionInfo::instance().getVersion() << "</Application>" //<< "<Application></Application>" //Name can cause problems per vivox. << "<MaxCalls>12</MaxCalls>" << "</Request>\n\n\n"; @@ -645,7 +652,6 @@ void LLVivoxVoiceClient::idle(void* user_data) { } - //========================================================================= // the following are methods to support the coroutine implementation of the // voice connection and processing. They should only be called in the context @@ -660,23 +666,47 @@ void LLVivoxVoiceClient::voiceControlCoro() U32 retry = 0; - while (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) + while (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE && !sShuttingDown) { LL_DEBUGS("Voice") << "Suspending voiceControlCoro() momentarily for teleport. Tuning: " << mTuningMode << ". Relog: " << mRelogRequested << LL_ENDL; llcoro::suspendUntilTimeout(1.0); } + if (sShuttingDown) + { + mIsCoroutineActive = false; + return; + } + do { bool success = startAndConnectSession(); if (success) { - if (mTuningMode) + // enable/disable the automatic VAD and explicitly set the initial values of + // the VAD variables ourselves when it is off - see SL-15072 for more details + // note: we set the other parameters too even if the auto VAD is on which is ok + unsigned int vad_auto = gSavedSettings.getU32("VivoxVadAuto"); + unsigned int vad_hangover = gSavedSettings.getU32("VivoxVadHangover"); + unsigned int vad_noise_floor = gSavedSettings.getU32("VivoxVadNoiseFloor"); + unsigned int vad_sensitivity = gSavedSettings.getU32("VivoxVadSensitivity"); + setupVADParams(vad_auto, vad_hangover, vad_noise_floor, vad_sensitivity); + + // watch for changes to the VAD settings via Debug Settings UI and act on them accordingly + gSavedSettings.getControl("VivoxVadAuto")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); + gSavedSettings.getControl("VivoxVadHangover")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); + gSavedSettings.getControl("VivoxVadNoiseFloor")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); + gSavedSettings.getControl("VivoxVadSensitivity")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); + + if (mTuningMode && !sShuttingDown) { performMicTuning(); } - waitForChannel(); // this doesn't normally return unless relog is needed or shutting down + if (!sShuttingDown) + { + waitForChannel(); // this doesn't normally return unless relog is needed or shutting down + } LL_DEBUGS("Voice") << "lost channel RelogRequested=" << mRelogRequested << LL_ENDL; endAndDisconnectSession(); @@ -691,7 +721,7 @@ void LLVivoxVoiceClient::voiceControlCoro() << "disconnected" << " RelogRequested=" << mRelogRequested << LL_ENDL; - if (mRelogRequested) + if (mRelogRequested && !sShuttingDown) { if (!success) { @@ -706,19 +736,18 @@ void LLVivoxVoiceClient::voiceControlCoro() LL_INFOS("Voice") << "will attempt to reconnect to voice" << LL_ENDL; } - while (isGatewayRunning() || gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) + while (isGatewayRunning() || (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE && !sShuttingDown)) { LL_INFOS("Voice") << "waiting for SLVoice to exit" << LL_ENDL; llcoro::suspendUntilTimeout(1.0); } } } - while (mVoiceEnabled && mRelogRequested); + while (mVoiceEnabled && mRelogRequested && !sShuttingDown); mIsCoroutineActive = false; LL_INFOS("Voice") << "exiting" << LL_ENDL; } - bool LLVivoxVoiceClient::startAndConnectSession() { bool ok = false; @@ -758,7 +787,7 @@ bool LLVivoxVoiceClient::endAndDisconnectSession() bool LLVivoxVoiceClient::callbackEndDaemon(const LLSD& data) { - if (!LLAppViewer::isExiting() && mVoiceEnabled) + if (!sShuttingDown && mVoiceEnabled) { LL_WARNS("Voice") << "SLVoice terminated " << ll_stream_notation_sd(data) << LL_ENDL; terminateAudioSession(false); @@ -806,6 +835,21 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() LLProcess::Params params; params.executable = exe_path; + // VOICE-88: Cycle through [portbase..portbase+portrange) on + // successive tries because attempting to relaunch (after manually + // disabling and then re-enabling voice) with the same port can + // cause SLVoice's bind() call to fail with EADDRINUSE. We expect + // that eventually the OS will time out previous ports, which is + // why we cycle instead of incrementing indefinitely. + U32 portbase = gSavedSettings.getU32("VivoxVoicePort"); + static U32 portoffset = 0; + static const U32 portrange = 100; + std::string host(gSavedSettings.getString("VivoxVoiceHost")); + U32 port = portbase + portoffset; + portoffset = (portoffset + 1) % portrange; + params.args.add("-i"); + params.args.add(STRINGIZE(host << ':' << port)); + std::string loglevel = gSavedSettings.getString("VivoxDebugLevel"); if (loglevel.empty()) { @@ -824,6 +868,20 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() params.args.add("-lf"); params.args.add(log_folder); + // set log file basename and .log + params.args.add("-lp"); + params.args.add("SLVoice"); + params.args.add("-ls"); + params.args.add(".log"); + + // rotate any existing log + std::string new_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SLVoice.log"); + std::string old_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SLVoice.old"); + if (gDirUtilp->fileExists(new_log)) + { + LLFile::rename(new_log, old_log); + } + std::string shutdown_timeout = gSavedSettings.getString("VivoxShutdownTimeout"); if (!shutdown_timeout.empty()) { @@ -848,7 +906,7 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() sGatewayPtr = LLProcess::create(params); - mDaemonHost = LLHost(gSavedSettings.getString("VivoxVoiceHost").c_str(), gSavedSettings.getU32("VivoxVoicePort")); + mDaemonHost = LLHost(host.c_str(), port); } else { @@ -886,7 +944,7 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() LL_DEBUGS("Voice") << "Connecting to vivox daemon:" << mDaemonHost << LL_ENDL; LLVoiceVivoxStats::getInstance()->reset(); - while (!mConnected) + while (!mConnected && !sShuttingDown) { LLVoiceVivoxStats::getInstance()->connectionAttemptStart(); LL_DEBUGS("Voice") << "Attempting to connect to vivox daemon: " << mDaemonHost << LL_ENDL; @@ -905,12 +963,22 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() } //--------------------------------------------------------------------- + if (sShuttingDown && !mConnected) + { + return false; + } + llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS); - while (!mPump) - { // Can't do this until we have the pump available. + while (!mPump && !sShuttingDown) + { // Can't use the pump until we have it available. llcoro::suspend(); } + + if (sShuttingDown) + { + return false; + } // MBW -- Note to self: pumps and pipes examples in // indra/test/io.cpp @@ -923,8 +991,10 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() readChain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(mSocket))); readChain.push_back(LLIOPipe::ptr_t(new LLVivoxProtocolParser())); + mPump->addChain(readChain, NEVER_CHAIN_EXPIRY_SECS); + //--------------------------------------------------------------------- llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS); @@ -941,12 +1011,17 @@ bool LLVivoxVoiceClient::provisionVoiceAccount() { LL_INFOS("Voice") << "Provisioning voice account." << LL_ENDL; - while (!gAgent.getRegion() || !gAgent.getRegion()->capabilitiesReceived()) + while ((!gAgent.getRegion() || !gAgent.getRegion()->capabilitiesReceived()) && !sShuttingDown) { LL_DEBUGS("Voice") << "no capabilities for voice provisioning; waiting " << LL_ENDL; // *TODO* Pump a message for wake up. llcoro::suspend(); } + + if (sShuttingDown) + { + return false; + } std::string url = gAgent.getRegionCapability("ProvisionVoiceAccountRequest"); @@ -973,7 +1048,14 @@ bool LLVivoxVoiceClient::provisionVoiceAccount() { F32 timeout = pow(PROVISION_RETRY_TIMEOUT, static_cast<float>(retryCount)); LL_WARNS("Voice") << "Provision CAP 404. Retrying in " << timeout << " seconds." << LL_ENDL; - llcoro::suspendUntilTimeout(timeout); + if (sShuttingDown) + { + return false; + } + else + { + llcoro::suspendUntilTimeout(timeout); + } } else if (!status) { @@ -985,10 +1067,15 @@ bool LLVivoxVoiceClient::provisionVoiceAccount() { provisioned = true; } - } while (!provisioned && retryCount <= PROVISION_RETRY_MAX); + } while (!provisioned && retryCount <= PROVISION_RETRY_MAX && !sShuttingDown); + + if (sShuttingDown && !provisioned) + { + return false; + } LLVoiceVivoxStats::getInstance()->provisionAttemptEnd(provisioned); - if (! provisioned ) + if (!provisioned) { LL_WARNS("Voice") << "Could not access voice provision cap after " << retryCount << " attempts." << LL_ENDL; return false; @@ -1024,13 +1111,16 @@ bool LLVivoxVoiceClient::provisionVoiceAccount() bool LLVivoxVoiceClient::establishVoiceConnection() { - LLEventPump &voiceConnectPump = LLEventPumps::instance().obtain("vivoxClientPump"); - if (!mVoiceEnabled && mIsInitialized) { LL_WARNS("Voice") << "cannot establish connection; enabled "<<mVoiceEnabled<<" initialized "<<mIsInitialized<<LL_ENDL; return false; } + + if (sShuttingDown) + { + return false; + } LLSD result; bool connected(false); @@ -1042,7 +1132,7 @@ bool LLVivoxVoiceClient::establishVoiceConnection() connectorCreate(); do { - result = llcoro::suspendUntilEventOn(voiceConnectPump); + result = llcoro::suspendUntilEventOn(mVivoxPump); LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; if (result.has("connector")) @@ -1051,7 +1141,7 @@ bool LLVivoxVoiceClient::establishVoiceConnection() connected = LLSD::Boolean(result["connector"]); if (!connected) { - if (result.has("retry") && ++retries <= CONNECT_RETRY_MAX) + if (result.has("retry") && ++retries <= CONNECT_RETRY_MAX && !sShuttingDown) { F32 timeout = LLSD::Real(result["retry"]); timeout *= retries; @@ -1079,7 +1169,7 @@ bool LLVivoxVoiceClient::establishVoiceConnection() LL_DEBUGS("Voice") << (connected ? "" : "not ") << "connected, " << (giving_up ? "" : "not ") << "giving up" << LL_ENDL; - } while (!connected && !giving_up); + } while (!connected && !giving_up && !sShuttingDown); if (giving_up) { @@ -1094,7 +1184,6 @@ bool LLVivoxVoiceClient::establishVoiceConnection() bool LLVivoxVoiceClient::breakVoiceConnection(bool corowait) { LL_DEBUGS("Voice") << "( wait=" << corowait << ")" << LL_ENDL; - LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); bool retval(true); mShutdownComplete = false; @@ -1104,7 +1193,7 @@ bool LLVivoxVoiceClient::breakVoiceConnection(bool corowait) { LLSD timeoutResult(LLSDMap("connector", "timeout")); - LLSD result = llcoro::suspendUntilEventOnWithTimeout(voicePump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult); + LLSD result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult); LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; retval = result.has("connector"); @@ -1126,7 +1215,7 @@ bool LLVivoxVoiceClient::breakVoiceConnection(bool corowait) { mConnected = false; LLSD vivoxevent(LLSDMap("connector", LLSD::Boolean(false))); - LLEventPumps::instance().post("vivoxClientPump", vivoxevent); + mVivoxPump.post(vivoxevent); } mShutdownComplete = true; } @@ -1143,8 +1232,6 @@ bool LLVivoxVoiceClient::breakVoiceConnection(bool corowait) bool LLVivoxVoiceClient::loginToVivox() { - LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); - LLSD timeoutResult(LLSDMap("login", "timeout")); int loginRetryCount(0); @@ -1162,14 +1249,14 @@ bool LLVivoxVoiceClient::loginToVivox() send_login = false; } - LLSD result = llcoro::suspendUntilEventOnWithTimeout(voicePump, LOGIN_ATTEMPT_TIMEOUT, timeoutResult); + LLSD result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGIN_ATTEMPT_TIMEOUT, timeoutResult); LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; if (result.has("login")) { std::string loginresp = result["login"]; - if ((loginresp == "retry") || (loginresp == "timeout")) + if (((loginresp == "retry") || (loginresp == "timeout")) && !sShuttingDown) { LL_WARNS("Voice") << "login failed with status '" << loginresp << "' " << " count " << loginRetryCount << "/" << LOGIN_RETRY_MAX @@ -1195,8 +1282,13 @@ bool LLVivoxVoiceClient::loginToVivox() // tell the user there is a problem LL_WARNS("Voice") << "login " << loginresp << " will retry login in " << timeout << " seconds." << LL_ENDL; - - llcoro::suspendUntilTimeout(timeout); + + if (!sShuttingDown) + { + // Todo: this is way to long, viewer can get stuck waiting during shutdown + // either make it listen to pump or split in smaller waits with checks for shutdown + llcoro::suspendUntilTimeout(timeout); + } } else if (loginresp == "failed") { @@ -1211,9 +1303,14 @@ bool LLVivoxVoiceClient::loginToVivox() { account_login = true; } + else if (sShuttingDown) + { + mIsLoggingIn = false; + return false; + } } - } while (!response_ok || !account_login); + } while ((!response_ok || !account_login) && !sShuttingDown); mRelogRequested = false; mIsLoggedIn = true; @@ -1245,17 +1342,28 @@ void LLVivoxVoiceClient::logoutOfVivox(bool wait) if (wait) { - LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); LLSD timeoutResult(LLSDMap("logout", "timeout")); + LLSD result; - LL_DEBUGS("Voice") - << "waiting for logout response on " - << voicePump.getName() - << LL_ENDL; + do + { + LL_DEBUGS("Voice") + << "waiting for logout response on " + << mVivoxPump.getName() + << LL_ENDL; - LLSD result = llcoro::suspendUntilEventOnWithTimeout(voicePump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult); + result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult); - LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; + if (sShuttingDown) + { + break; + } + + LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; + // Don't get confused by prior queued events -- note that it's + // very important that mVivoxPump is an LLEventMailDrop, which + // does queue events. + } while (! result["logout"]); } else { @@ -1269,8 +1377,6 @@ void LLVivoxVoiceClient::logoutOfVivox(bool wait) bool LLVivoxVoiceClient::retrieveVoiceFonts() { - LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); - // Request the set of available voice fonts. refreshVoiceEffectLists(true); @@ -1278,7 +1384,7 @@ bool LLVivoxVoiceClient::retrieveVoiceFonts() LLSD result; do { - result = llcoro::suspendUntilEventOn(voicePump); + result = llcoro::suspendUntilEventOn(mVivoxPump); LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; if (result.has("voice_fonts")) @@ -1394,7 +1500,6 @@ bool LLVivoxVoiceClient::requestParcelVoiceInfo() bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession) { - LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); mIsJoiningSession = true; sessionStatePtr_t oldSession = mAudioSession; @@ -1483,7 +1588,7 @@ bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession) // We are about to start a whole new session. Anything that MIGHT still be in our // maildrop is going to be stale and cause us much wailing and gnashing of teeth. // Just flush it all out and start new. - voicePump.flush(); + mVivoxPump.discard(); // It appears that I need to wait for BOTH the SessionGroup.AddSession response and the SessionStateChangeEvent with state 4 // before continuing from this state. They can happen in either order, and if I don't wait for both, things can get stuck. @@ -1491,7 +1596,13 @@ bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession) // This is a cheap way to make sure both have happened before proceeding. do { - result = llcoro::suspendUntilEventOnWithTimeout(voicePump, SESSION_JOIN_TIMEOUT, timeoutResult); + result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, SESSION_JOIN_TIMEOUT, timeoutResult); + + if (sShuttingDown) + { + mIsJoiningSession = false; + return false; + } LL_INFOS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; if (result.has("session")) @@ -1605,13 +1716,12 @@ bool LLVivoxVoiceClient::terminateAudioSession(bool wait) if (wait) { - LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); LLSD result; do { LLSD timeoutResult(LLSDMap("session", "timeout")); - result = llcoro::suspendUntilEventOnWithTimeout(voicePump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult); + result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult); LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; if (result.has("session")) @@ -1664,12 +1774,12 @@ bool LLVivoxVoiceClient::terminateAudioSession(bool wait) // the region chat. mSessionTerminateRequested = false; - bool status=((mVoiceEnabled || !mIsInitialized) && !mRelogRequested && !LLApp::isExiting()); + bool status=((mVoiceEnabled || !mIsInitialized) && !mRelogRequested && !sShuttingDown); LL_DEBUGS("Voice") << "exiting" << " VoiceEnabled " << mVoiceEnabled << " IsInitialized " << mIsInitialized << " RelogRequested " << mRelogRequested - << " AppExiting " << LLApp::isExiting() + << " ShuttingDown " << (sShuttingDown ? "TRUE" : "FALSE") << " returning " << status << LL_ENDL; return status; @@ -1686,6 +1796,12 @@ bool LLVivoxVoiceClient::waitForChannel() return false; } + if (sShuttingDown) + { + logoutOfVivox(false); + return false; + } + if (LLVoiceClient::instance().getVoiceEffectEnabled()) { retrieveVoiceFonts(); @@ -1707,6 +1823,12 @@ bool LLVivoxVoiceClient::waitForChannel() mIsProcessingChannels = true; llcoro::suspend(); + if (sShuttingDown) + { + mRelogRequested = false; + break; + } + if (mTuningMode) { performMicTuning(); @@ -1720,7 +1842,7 @@ bool LLVivoxVoiceClient::waitForChannel() // the parcel is changed, or we have no pending audio sessions, // so try to request the parcel voice info // if we have the cap, we move to the appropriate state - requestParcelVoiceInfo(); + requestParcelVoiceInfo(); //suspends for http reply } else if (sessionNeedsRelog(mNextAudioSession)) { @@ -1732,7 +1854,7 @@ bool LLVivoxVoiceClient::waitForChannel() { sessionStatePtr_t joinSession = mNextAudioSession; mNextAudioSession.reset(); - if (!runSession(joinSession)) + if (!runSession(joinSession)) //suspends { LL_DEBUGS("Voice") << "runSession returned false; leaving inner loop" << LL_ENDL; break; @@ -1747,11 +1869,18 @@ bool LLVivoxVoiceClient::waitForChannel() } } - if (!mNextAudioSession) + if (!mNextAudioSession && !sShuttingDown) { llcoro::suspendUntilTimeout(1.0); } - } while (mVoiceEnabled && !mRelogRequested); + + if (sShuttingDown) + { + mRelogRequested = false; + break; + } + + } while (mVoiceEnabled && !mRelogRequested && !sShuttingDown); LL_DEBUGS("Voice") << "leaving inner waitForChannel loop" @@ -1761,9 +1890,9 @@ bool LLVivoxVoiceClient::waitForChannel() mIsProcessingChannels = false; - logoutOfVivox(true); + logoutOfVivox(!sShuttingDown /*bool wait*/); - if (mRelogRequested) + if (mRelogRequested && !sShuttingDown) { LL_DEBUGS("Voice") << "Relog Requested, restarting provisioning" << LL_ENDL; if (!provisionVoiceAccount()) @@ -1773,14 +1902,14 @@ bool LLVivoxVoiceClient::waitForChannel() return false; } } - } while (mVoiceEnabled && mRelogRequested && isGatewayRunning()); + } while (mVoiceEnabled && mRelogRequested && isGatewayRunning() && !sShuttingDown); LL_DEBUGS("Voice") << "exiting" << " RelogRequested=" << mRelogRequested << " VoiceEnabled=" << mVoiceEnabled << LL_ENDL; - return true; + return !sShuttingDown; } bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) @@ -1808,13 +1937,17 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) LLSD timeoutEvent(LLSDMap("timeout", LLSD::Boolean(true))); - LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); mIsInChannel = true; mMuteMicDirty = true; while (mVoiceEnabled && isGatewayRunning() && !mSessionTerminateRequested && !mTuningMode) { - sendCaptureAndRenderDevices(); + sendCaptureAndRenderDevices(); // suspends + if (mSessionTerminateRequested) + { + break; + } + if (mAudioSession && mAudioSession->mParticipantsChanged) { mAudioSession->mParticipantsChanged = false; @@ -1860,7 +1993,7 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) sendLocalAudioUpdates(); mIsInitialized = true; - LLSD result = llcoro::suspendUntilEventOnWithTimeout(voicePump, UPDATE_THROTTLE_SECONDS, timeoutEvent); + LLSD result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, UPDATE_THROTTLE_SECONDS, timeoutEvent); if (!result.has("timeout")) // logging the timeout event spams the log { LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; @@ -1931,14 +2064,13 @@ void LLVivoxVoiceClient::sendCaptureAndRenderDevices() void LLVivoxVoiceClient::recordingAndPlaybackMode() { LL_INFOS("Voice") << "In voice capture/playback mode." << LL_ENDL; - LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); while (true) { LLSD command; do { - command = llcoro::suspendUntilEventOn(voicePump); + command = llcoro::suspendUntilEventOn(mVivoxPump); LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(command) << LL_ENDL; } while (!command.has("recplay")); @@ -1971,7 +2103,6 @@ int LLVivoxVoiceClient::voiceRecordBuffer() LL_INFOS("Voice") << "Recording voice buffer" << LL_ENDL; - LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); LLSD result; captureBufferRecordStartSendMessage(); @@ -1979,7 +2110,7 @@ int LLVivoxVoiceClient::voiceRecordBuffer() do { - result = llcoro::suspendUntilEventOnWithTimeout(voicePump, CAPTURE_BUFFER_MAX_TIME, timeoutResult); + result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, CAPTURE_BUFFER_MAX_TIME, timeoutResult); LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; } while (!result.has("recplay")); @@ -2001,7 +2132,6 @@ int LLVivoxVoiceClient::voicePlaybackBuffer() LL_INFOS("Voice") << "Playing voice buffer" << LL_ENDL; - LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); LLSD result; do @@ -2016,7 +2146,7 @@ int LLVivoxVoiceClient::voicePlaybackBuffer() // Update UI, should really use a separate callback. notifyVoiceFontObservers(); - result = llcoro::suspendUntilEventOnWithTimeout(voicePump, CAPTURE_BUFFER_MAX_TIME, timeoutResult); + result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, CAPTURE_BUFFER_MAX_TIME, timeoutResult); LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; } while (!result.has("recplay")); @@ -2044,7 +2174,7 @@ bool LLVivoxVoiceClient::performMicTuning() mIsInTuningMode = true; llcoro::suspend(); - while (mTuningMode) + while (mTuningMode && !sShuttingDown) { if (mCaptureDeviceDirty || mRenderDeviceDirty) @@ -2080,9 +2210,12 @@ bool LLVivoxVoiceClient::performMicTuning() tuningCaptureStartSendMessage(1); // 1-loop, zero, don't loop //--------------------------------------------------------------------- - llcoro::suspend(); + if (!sShuttingDown) + { + llcoro::suspend(); + } - while (mTuningMode && !mCaptureDeviceDirty && !mRenderDeviceDirty) + while (mTuningMode && !mCaptureDeviceDirty && !mRenderDeviceDirty && !sShuttingDown) { // process mic/speaker volume changes if (mTuningMicVolumeDirty || mTuningSpeakerVolumeDirty) @@ -2122,7 +2255,7 @@ bool LLVivoxVoiceClient::performMicTuning() // transition out of mic tuning tuningCaptureStopSendMessage(); - if (mCaptureDeviceDirty || mRenderDeviceDirty) + if ((mCaptureDeviceDirty || mRenderDeviceDirty) && !sShuttingDown) { llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS); } @@ -2537,7 +2670,7 @@ void LLVivoxVoiceClient::tuningStart() mTuningMode = true; if (!mIsCoroutineActive) { - LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro();", + LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro", boost::bind(&LLVivoxVoiceClient::voiceControlCoro, LLVivoxVoiceClient::getInstance())); } else if (mIsInChannel) @@ -3144,6 +3277,73 @@ void LLVivoxVoiceClient::sendLocalAudioUpdates() } } +/** + * Because of the recurring voice cutout issues (SL-15072) we are going to try + * to disable the automatic VAD (Voice Activity Detection) and set the associated + * parameters directly. We will expose them via Debug Settings and that should + * let us iterate on a collection of values that work for us. Hopefully! + * + * From the VIVOX Docs: + * + * VadAuto: A flag indicating if the automatic VAD is enabled (1) or disabled (0) + * + * VadHangover: The time (in milliseconds) that it takes + * for the VAD to switch back to silence from speech mode after the last speech + * frame has been detected. + * + * VadNoiseFloor: A dimensionless value between 0 and + * 20000 (default 576) that controls the maximum level at which the noise floor + * may be set at by the VAD's noise tracking. Too low of a value will make noise + * tracking ineffective (A value of 0 disables noise tracking and the VAD then + * relies purely on the sensitivity property). Too high of a value will make + * long speech classifiable as noise. + * + * VadSensitivity: A dimensionless value between 0 and + * 100, indicating the 'sensitivity of the VAD'. Increasing this value corresponds + * to decreasing the sensitivity of the VAD (i.e. '0' is most sensitive, + * while 100 is 'least sensitive') + */ +void LLVivoxVoiceClient::setupVADParams(unsigned int vad_auto, + unsigned int vad_hangover, + unsigned int vad_noise_floor, + unsigned int vad_sensitivity) +{ + std::ostringstream stream; + + LL_INFOS("Voice") << "Setting the automatic VAD to " + << (vad_auto ? "True" : "False") + << " and discrete values to" + << " VadHangover = " << vad_hangover + << ", VadSensitivity = " << vad_sensitivity + << ", VadNoiseFloor = " << vad_noise_floor + << LL_ENDL; + + // Create a request to set the VAD parameters: + stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetVadProperties.1\">" + << "<VadAuto>" << vad_auto << "</VadAuto>" + << "<VadHangover>" << vad_hangover << "</VadHangover>" + << "<VadSensitivity>" << vad_sensitivity << "</VadSensitivity>" + << "<VadNoiseFloor>" << vad_noise_floor << "</VadNoiseFloor>" + << "</Request>\n\n\n"; + + if (!stream.str().empty()) + { + writeString(stream.str()); + } +} + +void LLVivoxVoiceClient::onVADSettingsChange() +{ + // pick up the VAD variables (one of which was changed) + unsigned int vad_auto = gSavedSettings.getU32("VivoxVadAuto"); + unsigned int vad_hangover = gSavedSettings.getU32("VivoxVadHangover"); + unsigned int vad_noise_floor = gSavedSettings.getU32("VivoxVadNoiseFloor"); + unsigned int vad_sensitivity = gSavedSettings.getU32("VivoxVadSensitivity"); + + // build a VAD params change request and send it to SLVoice + setupVADParams(vad_auto, vad_hangover, vad_noise_floor, vad_sensitivity); +} + ///////////////////////////// // Response/Event handlers @@ -3200,7 +3400,7 @@ void LLVivoxVoiceClient::connectorCreateResponse(int statusCode, std::string &st result["connector"] = LLSD::Boolean(false); } - LLEventPumps::instance().post("vivoxClientPump", result); + mVivoxPump.post(result); } void LLVivoxVoiceClient::loginResponse(int statusCode, std::string &statusString, std::string &accountHandle, int numberOfAliases) @@ -3230,7 +3430,7 @@ void LLVivoxVoiceClient::loginResponse(int statusCode, std::string &statusString result["login"] = LLSD::String("response_ok"); } - LLEventPumps::instance().post("vivoxClientPump", result); + mVivoxPump.post(result); } @@ -3256,7 +3456,7 @@ void LLVivoxVoiceClient::sessionCreateResponse(std::string &requestId, int statu ("session", "failed") ("reason", LLSD::Integer(statusCode))); - LLEventPumps::instance().post("vivoxClientPump", vivoxevent); + mVivoxPump.post(vivoxevent); } else { @@ -3274,7 +3474,7 @@ void LLVivoxVoiceClient::sessionCreateResponse(std::string &requestId, int statu LLSD vivoxevent(LLSDMap("handle", LLSD::String(sessionHandle)) ("session", "created")); - LLEventPumps::instance().post("vivoxClientPump", vivoxevent); + mVivoxPump.post(vivoxevent); } } @@ -3299,7 +3499,7 @@ void LLVivoxVoiceClient::sessionGroupAddSessionResponse(std::string &requestId, LLSD vivoxevent(LLSDMap("handle", LLSD::String(sessionHandle)) ("session", "failed")); - LLEventPumps::instance().post("vivoxClientPump", vivoxevent); + mVivoxPump.post(vivoxevent); } else { @@ -3318,7 +3518,7 @@ void LLVivoxVoiceClient::sessionGroupAddSessionResponse(std::string &requestId, LLSD vivoxevent(LLSDMap("handle", LLSD::String(sessionHandle)) ("session", "added")); - LLEventPumps::instance().post("vivoxClientPump", vivoxevent); + mVivoxPump.post(vivoxevent); } } @@ -3361,7 +3561,7 @@ void LLVivoxVoiceClient::logoutResponse(int statusCode, std::string &statusStrin } LLSD vivoxevent(LLSDMap("logout", LLSD::Boolean(true))); - LLEventPumps::instance().post("vivoxClientPump", vivoxevent); + mVivoxPump.post(vivoxevent); } void LLVivoxVoiceClient::connectorShutdownResponse(int statusCode, std::string &statusString) @@ -3377,7 +3577,7 @@ void LLVivoxVoiceClient::connectorShutdownResponse(int statusCode, std::string & LLSD vivoxevent(LLSDMap("connector", LLSD::Boolean(false))); - LLEventPumps::instance().post("vivoxClientPump", vivoxevent); + mVivoxPump.post(vivoxevent); } void LLVivoxVoiceClient::sessionAddedEvent( @@ -3486,7 +3686,7 @@ void LLVivoxVoiceClient::joinedAudioSession(const sessionStatePtr_t &session) LLSD vivoxevent(LLSDMap("handle", LLSD::String(session->mHandle)) ("session", "joined")); - LLEventPumps::instance().post("vivoxClientPump", vivoxevent); + mVivoxPump.post(vivoxevent); // Add the current user as a participant here. participantStatePtr_t participant(session->addParticipant(sipURIFromName(mAccountName))); @@ -3630,7 +3830,7 @@ void LLVivoxVoiceClient::leftAudioSession(const sessionStatePtr_t &session) LLSD vivoxevent(LLSDMap("handle", LLSD::String(session->mHandle)) ("session", "removed")); - LLEventPumps::instance().post("vivoxClientPump", vivoxevent); + mVivoxPump.post(vivoxevent); } } @@ -3658,7 +3858,7 @@ void LLVivoxVoiceClient::accountLoginStateChangeEvent( case 1: levent["login"] = LLSD::String("account_login"); - LLEventPumps::instance().post("vivoxClientPump", levent); + mVivoxPump.post(levent); break; case 2: break; @@ -3666,7 +3866,7 @@ void LLVivoxVoiceClient::accountLoginStateChangeEvent( case 3: levent["login"] = LLSD::String("account_loggingOut"); - LLEventPumps::instance().post("vivoxClientPump", levent); + mVivoxPump.post(levent); break; case 4: @@ -3679,7 +3879,7 @@ void LLVivoxVoiceClient::accountLoginStateChangeEvent( case 0: levent["login"] = LLSD::String("account_logout"); - LLEventPumps::instance().post("vivoxClientPump", levent); + mVivoxPump.post(levent); break; default: @@ -3714,7 +3914,7 @@ void LLVivoxVoiceClient::mediaCompletionEvent(std::string &sessionGroupHandle, s } if (!result.isUndefined()) - LLEventPumps::instance().post("vivoxClientPump", result); + mVivoxPump.post(result); } void LLVivoxVoiceClient::mediaStreamUpdatedEvent( @@ -5132,7 +5332,7 @@ void LLVivoxVoiceClient::setVoiceEnabled(bool enabled) if (!mIsCoroutineActive) { - LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro();", + LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro", boost::bind(&LLVivoxVoiceClient::voiceControlCoro, LLVivoxVoiceClient::getInstance())); } else @@ -5144,6 +5344,7 @@ void LLVivoxVoiceClient::setVoiceEnabled(bool enabled) { // Turning voice off looses your current channel -- this makes sure the UI isn't out of sync when you re-enable it. LLVoiceChannel::getCurrentVoiceChannel()->deactivate(); + gAgent.setVoiceConnected(false); status = LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED; } @@ -6526,7 +6727,7 @@ void LLVivoxVoiceClient::accountGetSessionFontsResponse(int statusCode, const st // receiving the last one. LLSD result(LLSDMap("voice_fonts", LLSD::Boolean(true))); - LLEventPumps::instance().post("vivoxClientPump", result); + mVivoxPump.post(result); } notifyVoiceFontObservers(); mVoiceFontsReceived = true; @@ -6677,7 +6878,7 @@ void LLVivoxVoiceClient::enablePreviewBuffer(bool enable) else result["recplay"] = "quit"; - LLEventPumps::instance().post("vivoxClientPump", result); + mVivoxPump.post(result); if(mCaptureBufferMode && mIsInChannel) { @@ -6698,7 +6899,7 @@ void LLVivoxVoiceClient::recordPreviewBuffer() mCaptureBufferRecording = true; LLSD result(LLSDMap("recplay", "record")); - LLEventPumps::instance().post("vivoxClientPump", result); + mVivoxPump.post(result); } void LLVivoxVoiceClient::playPreviewBuffer(const LLUUID& effect_id) @@ -6721,7 +6922,7 @@ void LLVivoxVoiceClient::playPreviewBuffer(const LLUUID& effect_id) mCaptureBufferPlaying = true; LLSD result(LLSDMap("recplay", "playback")); - LLEventPumps::instance().post("vivoxClientPump", result); + mVivoxPump.post(result); } void LLVivoxVoiceClient::stopPreviewBuffer() @@ -6730,7 +6931,7 @@ void LLVivoxVoiceClient::stopPreviewBuffer() mCaptureBufferPlaying = false; LLSD result(LLSDMap("recplay", "quit")); - LLEventPumps::instance().post("vivoxClientPump", result); + mVivoxPump.post(result); } bool LLVivoxVoiceClient::isPreviewRecording() @@ -7495,6 +7696,18 @@ void LLVivoxProtocolParser::processResponse(std::string tag) { LLVivoxVoiceClient::getInstance()->accountGetTemplateFontsResponse(statusCode, statusString); } + else if (!stricmp(actionCstr, "Aux.SetVadProperties.1")) + { + // both values of statusCode (old and more recent) indicate valid requests + if (statusCode != 0 && statusCode != 200) + { + LL_WARNS("Voice") << "Aux.SetVadProperties.1 request failed: " + << "statusCode: " << statusCode + << " and " + << "statusString: " << statusString + << LL_ENDL; + } + } /* else if (!stricmp(actionCstr, "Account.ChannelGetList.1")) { diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index 210c726452..75ff5429f3 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -446,7 +446,6 @@ protected: // local audio updates, mic mute, speaker mute, mic volume and speaker volumes void sendLocalAudioUpdates(); - ///////////////////////////// // Response/Event handlers void connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle, std::string &versionID); @@ -473,6 +472,12 @@ protected: void muteListChanged(); ///////////////////////////// + // VAD changes + // disable auto-VAD and configure VAD parameters explicitly + void setupVADParams(unsigned int vad_auto, unsigned int vad_hangover, unsigned int vad_noise_floor, unsigned int vad_sensitivity); + void onVADSettingsChange(); + + ///////////////////////////// // Sending updates of current state void updatePosition(void); void setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot); @@ -912,6 +917,8 @@ private: bool mIsProcessingChannels; bool mIsCoroutineActive; + static bool sShuttingDown; // corutines can last longer than vivox so we need a static variable as a shutdown flag + LLEventMailDrop mVivoxPump; }; diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp index c131cb886f..878d7287ed 100644 --- a/indra/newview/llvosky.cpp +++ b/indra/newview/llvosky.cpp @@ -48,170 +48,63 @@ #include "llworld.h" #include "pipeline.h" #include "lldrawpoolwlsky.h" -#include "llwlparammanager.h" -#include "llwaterparammanager.h" +#include "v3colorutil.h" + +#include "llsettingssky.h" +#include "llenvironment.h" + +#include "lltrace.h" +#include "llfasttimer.h" #undef min #undef max -static const S32 NUM_TILES_X = 8; -static const S32 NUM_TILES_Y = 4; -static const S32 NUM_TILES = NUM_TILES_X * NUM_TILES_Y; +namespace +{ + const S32 NUM_TILES_X = 8; + const S32 NUM_TILES_Y = 4; + const S32 NUM_TILES = NUM_TILES_X * NUM_TILES_Y; + const S32 NUM_CUBEMAP_FACES = 6; // Heavenly body constants -static const F32 SUN_DISK_RADIUS = 0.5f; -static const F32 MOON_DISK_RADIUS = SUN_DISK_RADIUS * 0.9f; -static const F32 SUN_INTENSITY = 1e5; + const F32 SUN_DISK_RADIUS = 0.5f; + const F32 MOON_DISK_RADIUS = SUN_DISK_RADIUS * 0.9f; + const F32 SUN_INTENSITY = 1e5; // Texture coordinates: -static const LLVector2 TEX00 = LLVector2(0.f, 0.f); -static const LLVector2 TEX01 = LLVector2(0.f, 1.f); -static const LLVector2 TEX10 = LLVector2(1.f, 0.f); -static const LLVector2 TEX11 = LLVector2(1.f, 1.f); + const LLVector2 TEX00 = LLVector2(0.f, 0.f); + const LLVector2 TEX01 = LLVector2(0.f, 1.f); + const LLVector2 TEX10 = LLVector2(1.f, 0.f); + const LLVector2 TEX11 = LLVector2(1.f, 1.f); -// Exported globals -LLUUID gSunTextureID = IMG_SUN; -LLUUID gMoonTextureID = IMG_MOON; - -class LLFastLn -{ -public: - LLFastLn() - { - mTable[0] = 0; - for( S32 i = 1; i < 257; i++ ) - { - mTable[i] = log((F32)i); - } - } + LLTrace::BlockTimerStatHandle FTM_VOSKY_UPDATETIMER("VOSky Update Timer Tick"); + LLTrace::BlockTimerStatHandle FTM_VOSKY_CALC("VOSky Update Calculations"); + LLTrace::BlockTimerStatHandle FTM_VOSKY_CREATETEXTURES("VOSky Update Textures"); + LLTrace::BlockTimerStatHandle FTM_VOSKY_UPDATEFORCED("VOSky Update Forced"); - F32 ln( F32 x ) - { - const F32 OO_255 = 0.003921568627450980392156862745098f; - const F32 LN_255 = 5.5412635451584261462455391880218f; + F32Seconds UPDATE_EXPRY(0.25f); - if( x < OO_255 ) - { - return log(x); - } - else - if( x < 1 ) - { - x *= 255.f; - S32 index = llfloor(x); - F32 t = x - index; - F32 low = mTable[index]; - F32 high = mTable[index + 1]; - return low + t * (high - low) - LN_255; - } - else - if( x <= 255 ) - { - S32 index = llfloor(x); - F32 t = x - index; - F32 low = mTable[index]; - F32 high = mTable[index + 1]; - return low + t * (high - low); - } - else - { - return log( x ); - } - } - - F32 pow( F32 x, F32 y ) - { - return (F32)LL_FAST_EXP(y * ln(x)); - } - - -private: - F32 mTable[257]; // index 0 is unused -}; - -static LLFastLn gFastLn; - - -// Functions used a lot. - -inline F32 LLHaze::calcPhase(const F32 cos_theta) const -{ - const F32 g2 = mG * mG; - const F32 den = 1 + g2 - 2 * mG * cos_theta; - return (1 - g2) * gFastLn.pow(den, -1.5); + const F32 UPDATE_MIN_DELTA_THRESHOLD = 0.0005f; } - -inline void color_pow(LLColor3 &col, const F32 e) -{ - col.mV[0] = gFastLn.pow(col.mV[0], e); - col.mV[1] = gFastLn.pow(col.mV[1], e); - col.mV[2] = gFastLn.pow(col.mV[2], e); -} - -inline LLColor3 color_norm(const LLColor3 &col) -{ - const F32 m = color_max(col); - if (m > 1.f) - { - return 1.f/m * col; - } - else return col; -} - -inline void color_gamma_correct(LLColor3 &col) -{ - const F32 gamma_inv = 1.f/1.2f; - if (col.mV[0] != 0.f) - { - col.mV[0] = gFastLn.pow(col.mV[0], gamma_inv); - } - if (col.mV[1] != 0.f) - { - col.mV[1] = gFastLn.pow(col.mV[1], gamma_inv); - } - if (col.mV[2] != 0.f) - { - col.mV[2] = gFastLn.pow(col.mV[2], gamma_inv); - } -} - -static LLColor3 calc_air_sca_sea_level() -{ - static LLColor3 WAVE_LEN(675, 520, 445); - static LLColor3 refr_ind = refr_ind_calc(WAVE_LEN); - static LLColor3 n21 = refr_ind * refr_ind - LLColor3(1, 1, 1); - static LLColor3 n4 = n21 * n21; - static LLColor3 wl2 = WAVE_LEN * WAVE_LEN * 1e-6f; - static LLColor3 wl4 = wl2 * wl2; - static LLColor3 mult_const = fsigma * 2.0f/ 3.0f * 1e24f * (F_PI * F_PI) * n4; - static F32 dens_div_N = F32( ATM_SEA_LEVEL_NDENS / Ndens2); - return dens_div_N * color_div ( mult_const, wl4 ); -} - -// static constants. -LLColor3 const LLHaze::sAirScaSeaLevel = calc_air_sca_sea_level(); -F32 const LLHaze::sAirScaIntense = color_intens(LLHaze::sAirScaSeaLevel); -F32 const LLHaze::sAirScaAvg = LLHaze::sAirScaIntense / 3.f; - - /*************************************** SkyTex ***************************************/ S32 LLSkyTex::sComponents = 4; S32 LLSkyTex::sResolution = 64; -F32 LLSkyTex::sInterpVal = 0.f; S32 LLSkyTex::sCurrent = 0; LLSkyTex::LLSkyTex() : mSkyData(NULL), - mSkyDirs(NULL) + mSkyDirs(NULL), + mIsShiny(false) { } -void LLSkyTex::init() +void LLSkyTex::init(bool isShiny) { + mIsShiny = isShiny; mSkyData = new LLColor4[sResolution * sResolution]; mSkyDirs = new LLVector3[sResolution * sResolution]; @@ -249,6 +142,32 @@ LLSkyTex::~LLSkyTex() mSkyDirs = NULL; } +S32 LLSkyTex::getResolution() +{ + return sResolution; +} + +S32 LLSkyTex::getCurrent() +{ + return sCurrent; +} + +S32 LLSkyTex::stepCurrent() { + sCurrent++; + sCurrent &= 1; + return sCurrent; +} + +S32 LLSkyTex::getNext() +{ + return ((sCurrent+1) & 1); +} + +S32 LLSkyTex::getWhich(const BOOL curr) +{ + int tex = curr ? sCurrent : getNext(); + return tex; +} void LLSkyTex::initEmpty(const S32 tex) { @@ -271,9 +190,8 @@ void LLSkyTex::initEmpty(const S32 tex) createGLImage(tex); } -void LLSkyTex::create(const F32 brightness) +void LLSkyTex::create() { - /// Brightness ignored for now. U8* data = mImageRaw[sCurrent]->getData(); for (S32 i = 0; i < sResolution; ++i) { @@ -289,26 +207,195 @@ void LLSkyTex::create(const F32 brightness) createGLImage(sCurrent); } - - - void LLSkyTex::createGLImage(S32 which) { + mTexture[which]->setExplicitFormat(GL_RGBA8, GL_RGBA); mTexture[which]->createGLTexture(0, mImageRaw[which], 0, TRUE, LLGLTexture::LOCAL); mTexture[which]->setAddressMode(LLTexUnit::TAM_CLAMP); } void LLSkyTex::bindTexture(BOOL curr) { - gGL.getTexUnit(0)->bind(mTexture[getWhich(curr)], true); + int tex = getWhich(curr); + gGL.getTexUnit(0)->bind(mTexture[tex], true); +} + +LLImageRaw* LLSkyTex::getImageRaw(BOOL curr) +{ + int tex = getWhich(curr); + return mImageRaw[tex]; } /*************************************** - Sky + LLHeavenBody ***************************************/ F32 LLHeavenBody::sInterpVal = 0; +LLHeavenBody::LLHeavenBody(const F32 rad) +: mDirectionCached(LLVector3(0,0,0)), + mDirection(LLVector3(0,0,0)), + mIntensity(0.f), + mDiskRadius(rad), + mDraw(FALSE), + mHorizonVisibility(1.f), + mVisibility(1.f), + mVisible(FALSE) +{ + mColor.setToBlack(); + mColorCached.setToBlack(); +} + +const LLQuaternion& LLHeavenBody::getRotation() const +{ + return mRotation; +} + +void LLHeavenBody::setRotation(const LLQuaternion& rot) +{ + mRotation = rot; +} + +const LLVector3& LLHeavenBody::getDirection() const +{ + return mDirection; +} + +void LLHeavenBody::setDirection(const LLVector3 &direction) +{ + mDirection = direction; +} + +void LLHeavenBody::setAngularVelocity(const LLVector3 &ang_vel) +{ + mAngularVelocity = ang_vel; +} + +const LLVector3& LLHeavenBody::getAngularVelocity() const +{ + return mAngularVelocity; +} + +const LLVector3& LLHeavenBody::getDirectionCached() const +{ + return mDirectionCached; +} + +void LLHeavenBody::renewDirection() +{ + mDirectionCached = mDirection; +} + +const LLColor3& LLHeavenBody::getColorCached() const +{ + return mColorCached; +} + +void LLHeavenBody::setColorCached(const LLColor3& c) +{ + mColorCached = c; +} + +const LLColor3& LLHeavenBody::getColor() const +{ + return mColor; +} + +void LLHeavenBody::setColor(const LLColor3& c) +{ + mColor = c; +} + +void LLHeavenBody::renewColor() +{ + mColorCached = mColor; +} + +F32 LLHeavenBody::interpVal() +{ + return sInterpVal; +} + +void LLHeavenBody::setInterpVal(const F32 v) +{ + sInterpVal = v; +} + +LLColor3 LLHeavenBody::getInterpColor() const +{ + return sInterpVal * mColor + (1 - sInterpVal) * mColorCached; +} + +const F32& LLHeavenBody::getVisibility() const +{ + return mVisibility; +} + +void LLHeavenBody::setVisibility(const F32 c) +{ + mVisibility = c; +} + +bool LLHeavenBody::isVisible() const +{ + return mVisible; +} + +void LLHeavenBody::setVisible(const bool v) +{ + mVisible = v; +} + +const F32& LLHeavenBody::getIntensity() const +{ + return mIntensity; +} + +void LLHeavenBody::setIntensity(const F32 c) +{ + mIntensity = c; +} + +void LLHeavenBody::setDiskRadius(const F32 radius) +{ + mDiskRadius = radius; +} + +F32 LLHeavenBody::getDiskRadius() const +{ + return mDiskRadius; +} + +void LLHeavenBody::setDraw(const bool draw) +{ + mDraw = draw; +} + +bool LLHeavenBody::getDraw() const +{ + return mDraw; +} + +const LLVector3& LLHeavenBody::corner(const S32 n) const +{ + return mQuadCorner[n]; +} + +LLVector3& LLHeavenBody::corner(const S32 n) +{ + return mQuadCorner[n]; +} + +const LLVector3* LLHeavenBody::corners() const +{ + return mQuadCorner; +} + +/*************************************** + Sky +***************************************/ + + S32 LLVOSky::sResolution = LLSkyTex::getResolution(); S32 LLVOSky::sTileResX = sResolution/NUM_TILES_X; S32 LLVOSky::sTileResY = sResolution/NUM_TILES_Y; @@ -323,39 +410,24 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) mCloudDensity(0.2f), mWind(0.f), mForceUpdate(FALSE), + mNeedUpdate(TRUE), + mCubeMapUpdateStage(-1), mWorldScale(1.f), mBumpSunDir(0.f, 0.f, 1.f) { - bool error = false; - /// WL PARAMS - dome_radius = 1.f; - dome_offset_ratio = 0.f; - sunlight_color = LLColor3(); - ambient = LLColor3(); - gamma = 1.f; - lightnorm = LLVector4(); - blue_density = LLColor3(); - blue_horizon = LLColor3(); - haze_density = 0.f; - haze_horizon = 1.f; - density_multiplier = 0.f; - max_y = 0.f; - glow = LLColor3(); - cloud_shadow = 0.f; - cloud_color = LLColor3(); - cloud_scale = 0.f; - cloud_pos_density1 = LLColor3(); - cloud_pos_density2 = LLColor3(); mInitialized = FALSE; mbCanSelect = FALSE; mUpdateTimer.reset(); - for (S32 i = 0; i < 6; i++) + mForceUpdateThrottle.setTimerExpirySec(UPDATE_EXPRY); + mForceUpdateThrottle.reset(); + + for (S32 i = 0; i < NUM_CUBEMAP_FACES; i++) { - mSkyTex[i].init(); - mShinyTex[i].init(); + mSkyTex[i].init(false); + mShinyTex[i].init(true); } for (S32 i=0; i<FACE_COUNT; i++) { @@ -366,32 +438,12 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) mAtmHeight = ATM_HEIGHT; mEarthCenter = LLVector3(mCameraPosAgent.mV[0], mCameraPosAgent.mV[1], -EARTH_RADIUS); - mSunDefaultPosition = LLVector3(LLWLParamManager::getInstance()->mCurParams.getVector("lightnorm", error)); - if (gSavedSettings.getBOOL("SkyOverrideSimSunPosition")) - { - initSunDirection(mSunDefaultPosition, LLVector3(0, 0, 0)); - } - mAmbientScale = gSavedSettings.getF32("SkyAmbientScale"); - mNightColorShift = gSavedSettings.getColor3("SkyNightColorShift"); - mFogColor.mV[VRED] = mFogColor.mV[VGREEN] = mFogColor.mV[VBLUE] = 0.5f; - mFogColor.mV[VALPHA] = 0.0f; - mFogRatio = 1.2f; - mSun.setIntensity(SUN_INTENSITY); mMoon.setIntensity(0.1f * SUN_INTENSITY); - mSunTexturep = LLViewerTextureManager::getFetchedTexture(gSunTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); - mSunTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - mMoonTexturep = LLViewerTextureManager::getFetchedTexture(gMoonTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); - mMoonTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - mBloomTexturep = LLViewerTextureManager::getFetchedTexture(IMG_BLOOM1); - mBloomTexturep->setNoDelete() ; - mBloomTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - mHeavenlyBodyUpdated = FALSE ; mDrawRefl = 0; - mHazeConcentration = 0.f; mInterpVal = 0.f; } @@ -406,50 +458,107 @@ LLVOSky::~LLVOSky() void LLVOSky::init() { - const F32 haze_int = color_intens(mHaze.calcSigSca(0)); - mHazeConcentration = haze_int / - (color_intens(LLHaze::calcAirSca(0)) + haze_int); - - calcAtmospherics(); + llassert(!mInitialized); + + // Update sky at least once to get correct initial sun/moon directions and lighting calcs performed + LLEnvironment::instance().getCurrentSky()->update(); + + updateDirections(); + + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + + // invariants across whole sky tex process... + m_atmosphericsVars.blue_density = psky->getBlueDensity(); + m_atmosphericsVars.blue_horizon = psky->getBlueHorizon(); + m_atmosphericsVars.haze_density = psky->getHazeDensity(); + m_atmosphericsVars.haze_horizon = psky->getHazeHorizon(); + m_atmosphericsVars.density_multiplier = psky->getDensityMultiplier(); + m_atmosphericsVars.max_y = psky->getMaxY(); + m_atmosphericsVars.sun_norm = LLEnvironment::instance().getClampedSunNorm(); + m_atmosphericsVars.sunlight = psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor(); + m_atmosphericsVars.ambient = psky->getAmbientColor(); + m_atmosphericsVars.glow = psky->getGlow(); + m_atmosphericsVars.cloud_shadow = psky->getCloudShadow(); + m_atmosphericsVars.dome_radius = psky->getDomeRadius(); + m_atmosphericsVars.dome_offset = psky->getDomeOffset(); + m_atmosphericsVars.light_atten = psky->getLightAttenuation(m_atmosphericsVars.max_y); + m_atmosphericsVars.light_transmittance = psky->getLightTransmittance(m_atmosphericsVars.max_y); + m_atmosphericsVars.total_density = psky->getTotalDensity(); + m_atmosphericsVars.gamma = psky->getGamma(); // Initialize the cached normalized direction vectors - for (S32 side = 0; side < 6; ++side) + for (S32 side = 0; side < NUM_CUBEMAP_FACES; ++side) { for (S32 tile = 0; tile < NUM_TILES; ++tile) { initSkyTextureDirs(side, tile); - createSkyTexture(side, tile); + createSkyTexture(m_atmosphericsVars, side, tile); } - } - - for (S32 i = 0; i < 6; ++i) - { - mSkyTex[i].create(1.0f); - mShinyTex[i].create(1.0f); + mSkyTex[side].create(); + mShinyTex[side].create(); } initCubeMap(); + mInitialized = true; mHeavenlyBodyUpdated = FALSE ; + + mRainbowMap = LLViewerTextureManager::getFetchedTexture(psky->getRainbowTextureId(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); + mHaloMap = LLViewerTextureManager::getFetchedTexture(psky->getHaloTextureId(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); +} + + +void LLVOSky::calc() +{ + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + + // invariants across whole sky tex process... + m_atmosphericsVars.blue_density = psky->getBlueDensity(); + m_atmosphericsVars.blue_horizon = psky->getBlueHorizon(); + m_atmosphericsVars.haze_density = psky->getHazeDensity(); + m_atmosphericsVars.haze_horizon = psky->getHazeHorizon(); + m_atmosphericsVars.density_multiplier = psky->getDensityMultiplier(); + m_atmosphericsVars.distance_multiplier = psky->getDistanceMultiplier(); + m_atmosphericsVars.max_y = psky->getMaxY(); + m_atmosphericsVars.sun_norm = LLEnvironment::instance().getClampedSunNorm(); + m_atmosphericsVars.sunlight = psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor(); + m_atmosphericsVars.ambient = psky->getAmbientColor(); + m_atmosphericsVars.glow = psky->getGlow(); + m_atmosphericsVars.cloud_shadow = psky->getCloudShadow(); + m_atmosphericsVars.dome_radius = psky->getDomeRadius(); + m_atmosphericsVars.dome_offset = psky->getDomeOffset(); + m_atmosphericsVars.light_atten = psky->getLightAttenuation(m_atmosphericsVars.max_y); + m_atmosphericsVars.light_transmittance = psky->getLightTransmittance(m_atmosphericsVars.max_y); + m_atmosphericsVars.gamma = psky->getGamma(); + + mSun.setColor(psky->getSunDiffuse()); + mMoon.setColor(LLColor3(1.0f, 1.0f, 1.0f)); + + mSun.renewDirection(); + mSun.renewColor(); + mMoon.renewDirection(); + mMoon.renewColor(); } void LLVOSky::initCubeMap() { std::vector<LLPointer<LLImageRaw> > images; - for (S32 side = 0; side < 6; side++) + for (S32 side = 0; side < NUM_CUBEMAP_FACES; side++) { images.push_back(mShinyTex[side].getImageRaw()); } - if (mCubeMap) + + if (!mCubeMap && gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps) { - mCubeMap->init(images); + mCubeMap = new LLCubeMap(false); } - else if (gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps) + + if (mCubeMap) { - mCubeMap = new LLCubeMap(); mCubeMap->init(images); } + gGL.getTexUnit(0)->disable(); } @@ -457,7 +566,7 @@ void LLVOSky::initCubeMap() void LLVOSky::cleanupGL() { S32 i; - for (i = 0; i < 6; i++) + for (i = 0; i < NUM_CUBEMAP_FACES; i++) { mSkyTex[i].cleanupGL(); } @@ -470,37 +579,27 @@ void LLVOSky::cleanupGL() void LLVOSky::restoreGL() { S32 i; - for (i = 0; i < 6; i++) + for (i = 0; i < NUM_CUBEMAP_FACES; i++) { mSkyTex[i].restoreGL(); } - mSunTexturep = LLViewerTextureManager::getFetchedTexture(gSunTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); - mSunTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - mMoonTexturep = LLViewerTextureManager::getFetchedTexture(gMoonTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); - mMoonTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - mBloomTexturep = LLViewerTextureManager::getFetchedTexture(IMG_BLOOM1); - mBloomTexturep->setNoDelete() ; - mBloomTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - - calcAtmospherics(); - - if (gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap - && LLCubeMap::sUseCubeMaps) + + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + + if (psky) { - LLCubeMap* cube_map = getCubeMap(); + setSunTextures(psky->getSunTextureId(), psky->getNextSunTextureId()); + setMoonTextures(psky->getMoonTextureId(), psky->getNextMoonTextureId()); + } - std::vector<LLPointer<LLImageRaw> > images; - for (S32 side = 0; side < 6; side++) - { - images.push_back(mShinyTex[side].getImageRaw()); - } + updateDirections(); - if(cube_map) + if (gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps) { - cube_map->init(images); - mForceUpdate = TRUE; + initCubeMap(); } - } + + forceSkyUpdate(); if (mDrawable) { @@ -541,8 +640,10 @@ void LLVOSky::initSkyTextureDirs(const S32 side, const S32 tile) } } -void LLVOSky::createSkyTexture(const S32 side, const S32 tile) +void LLVOSky::createSkyTexture(AtmosphericsVars& vars, const S32 side, const S32 tile) { + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + S32 tile_x = tile % NUM_TILES_X; S32 tile_y = tile / NUM_TILES_X; @@ -554,704 +655,347 @@ void LLVOSky::createSkyTexture(const S32 side, const S32 tile) { for (x = tile_x_pos; x < (tile_x_pos + sTileResX); ++x) { - mSkyTex[side].setPixel(calcSkyColorInDir(mSkyTex[side].getDir(x, y)), x, y); - mShinyTex[side].setPixel(calcSkyColorInDir(mSkyTex[side].getDir(x, y), true), x, y); + mSkyTex[side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mSkyTex[side].getDir(x, y), false), x, y); + mShinyTex[side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mShinyTex[side].getDir(x, y), true), x, y); } } } -static 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]); -} - - -static 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]); -} - - -static inline LLColor3 componentExp(LLColor3 const &v) +void LLVOSky::updateDirections(void) { - return LLColor3(exp(v.mV[0]), - exp(v.mV[1]), - exp(v.mV[2])); -} + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); -static 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)); + mSun.setDirection(psky->getSunDirection()); + mMoon.setDirection(psky->getMoonDirection()); + mSun.setRotation(psky->getSunRotation()); + mMoon.setRotation(psky->getMoonRotation()); + mSun.renewDirection(); + mMoon.renewDirection(); } -static inline LLColor3 componentSaturate(LLColor3 const &v) +void LLVOSky::idleUpdate(LLAgent &agent, const F64 &time) { - 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)); } - -static inline LLColor3 componentSqrt(LLColor3 const &v) +void LLVOSky::forceSkyUpdate() { - return LLColor3(sqrt(v.mV[0]), - sqrt(v.mV[1]), - sqrt(v.mV[2])); -} + mForceUpdate = TRUE; -static 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]; -} + memset(&m_lastAtmosphericsVars, 0x00, sizeof(AtmosphericsVars)); -static inline LLColor3 colorMix(LLColor3 const & left, LLColor3 const & right, F32 amount) -{ - return (left + ((right - left) * amount)); + mCubeMapUpdateStage = -1; } -static inline LLColor3 smear(F32 val) +bool LLVOSky::updateSky() { - return LLColor3(val, val, val); -} + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); -void LLVOSky::initAtmospherics(void) -{ - bool error; - - // uniform parameters for convenience - dome_radius = LLWLParamManager::getInstance()->getDomeRadius(); - dome_offset_ratio = LLWLParamManager::getInstance()->getDomeOffset(); - sunlight_color = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("sunlight_color", error)); - ambient = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("ambient", error)); - //lightnorm = LLWLParamManager::getInstance()->mCurParams.getVector("lightnorm", error); - gamma = LLWLParamManager::getInstance()->mCurParams.getFloat("gamma", error); - blue_density = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("blue_density", error)); - blue_horizon = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("blue_horizon", error)); - haze_density = LLWLParamManager::getInstance()->mCurParams.getFloat("haze_density", error); - haze_horizon = LLWLParamManager::getInstance()->mCurParams.getFloat("haze_horizon", error); - density_multiplier = LLWLParamManager::getInstance()->mCurParams.getFloat("density_multiplier", error); - max_y = LLWLParamManager::getInstance()->mCurParams.getFloat("max_y", error); - glow = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("glow", error)); - cloud_shadow = LLWLParamManager::getInstance()->mCurParams.getFloat("cloud_shadow", error); - cloud_color = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("cloud_color", error)); - cloud_scale = LLWLParamManager::getInstance()->mCurParams.getFloat("cloud_scale", error); - cloud_pos_density1 = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("cloud_pos_density1", error)); - cloud_pos_density2 = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("cloud_pos_density2", error)); - - // light norm is different. We need the sun's direction, not the light direction - // which could be from the moon. And we need to clamp it - // just like for the gpu - LLVector3 sunDir = gSky.getSunDirection(); - - // CFR_TO_OGL - lightnorm = LLVector4(sunDir.mV[1], sunDir.mV[2], sunDir.mV[0], 0); - unclamped_lightnorm = lightnorm; - if(lightnorm.mV[1] < -0.1f) + if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))) { - lightnorm.mV[1] = -0.1f; + return TRUE; } - -} -LLColor4 LLVOSky::calcSkyColorInDir(const LLVector3 &dir, bool isShiny) -{ - F32 saturation = 0.3f; - if (dir.mV[VZ] < -0.02f) + if (mDead) { - LLColor4 col = LLColor4(llmax(mFogColor[0],0.2f), llmax(mFogColor[1],0.2f), llmax(mFogColor[2],0.22f),0.f); - if (isShiny) - { - LLColor3 desat_fog = LLColor3(mFogColor); - F32 brightness = desat_fog.brightness(); - // So that shiny somewhat shows up at night. - if (brightness < 0.15f) - { - brightness = 0.15f; - desat_fog = smear(0.15f); - } - LLColor3 greyscale = smear(brightness); - desat_fog = desat_fog * saturation + greyscale * (1.0f - saturation); - if (!gPipeline.canUseWindLightShaders()) - { - col = LLColor4(desat_fog, 0.f); - } - else - { - col = LLColor4(desat_fog * 0.5f, 0.f); - } - } - float x = 1.0f-fabsf(-0.1f-dir.mV[VZ]); - x *= x; - col.mV[0] *= x*x; - col.mV[1] *= powf(x, 2.5f); - col.mV[2] *= x*x*x; - return col; + // It's dead. Don't update it. + return TRUE; } - // undo OGL_TO_CFR_ROTATION and negate vertical direction. - LLVector3 Pn = LLVector3(-dir[1] , -dir[2], -dir[0]); - - LLColor3 vary_HazeColor(0,0,0); - LLColor3 vary_CloudColorSun(0,0,0); - LLColor3 vary_CloudColorAmbient(0,0,0); - F32 vary_CloudDensity(0); - LLVector2 vary_HorizontalProjection[2]; - vary_HorizontalProjection[0] = LLVector2(0,0); - vary_HorizontalProjection[1] = LLVector2(0,0); - - calcSkyColorWLVert(Pn, vary_HazeColor, vary_CloudColorSun, vary_CloudColorAmbient, - vary_CloudDensity, vary_HorizontalProjection); - - LLColor3 sky_color = calcSkyColorWLFrag(Pn, vary_HazeColor, vary_CloudColorSun, vary_CloudColorAmbient, - vary_CloudDensity, vary_HorizontalProjection); - if (isShiny) + if (gGLManager.mIsDisabled) { - F32 brightness = sky_color.brightness(); - LLColor3 greyscale = smear(brightness); - sky_color = sky_color * saturation + greyscale * (1.0f - saturation); - sky_color *= (0.5f + 0.5f * brightness); - } - return LLColor4(sky_color, 0.0f); -} - -// turn on floating point precision -// in vs2003 for this function. Otherwise -// sky is aliased looking 7:10 - 8:50 -#if LL_MSVC && __MSVC_VER__ < 8 -#pragma optimize("p", on) -#endif - -void LLVOSky::calcSkyColorWLVert(LLVector3 & Pn, LLColor3 & vary_HazeColor, LLColor3 & vary_CloudColorSun, - LLColor3 & vary_CloudColorAmbient, F32 & vary_CloudDensity, - LLVector2 vary_HorizontalProjection[2]) -{ - // project the direction ray onto the sky dome. - F32 phi = acos(Pn[1]); - F32 sinA = sin(F_PI - phi); - if (fabsf(sinA) < 0.01f) - { //avoid division by zero - sinA = 0.01f; + return TRUE; } - F32 Plen = dome_radius * sin(F_PI + phi + asin(dome_offset_ratio * sinA)) / sinA; + static S32 next_frame = 0; + const S32 total_no_tiles = NUM_CUBEMAP_FACES * NUM_TILES; + const S32 cycle_frame_no = total_no_tiles + 1; + + mNeedUpdate = mForceUpdate; - Pn *= Plen; + ++next_frame; + next_frame = next_frame % cycle_frame_no; - vary_HorizontalProjection[0] = LLVector2(Pn[0], Pn[2]); - vary_HorizontalProjection[0] /= - 2.f * Plen; + mInterpVal = (!mInitialized) ? 1 : (F32)next_frame / cycle_frame_no; + LLHeavenBody::setInterpVal( mInterpVal ); + updateDirections(); - // Set altitude - if (Pn[1] > 0.f) - { - Pn *= (max_y / Pn[1]); - } - else + if (!mCubeMap) { - Pn *= (-32000.f / Pn[1]); + mCubeMapUpdateStage = NUM_CUBEMAP_FACES; + mForceUpdate = FALSE; + return TRUE; } + + if (mCubeMapUpdateStage < 0) + { + LL_RECORD_BLOCK_TIME(FTM_VOSKY_CALC); + calc(); - Plen = Pn.length(); - Pn /= Plen; - - // Initialize temp variables - LLColor3 sunlight = sunlight_color; - - // Sunlight attenuation effect (hue and brightness) due to atmosphere - // this is used later for sunlight modulation at various altitudes - LLColor3 light_atten = - (blue_density * 1.0 + smear(haze_density * 0.25f)) * (density_multiplier * max_y); - - // Calculate relative weights - LLColor3 temp2(0.f, 0.f, 0.f); - LLColor3 temp1 = blue_density + smear(haze_density); - LLColor3 blue_weight = componentDiv(blue_density, temp1); - LLColor3 haze_weight = componentDiv(smear(haze_density), temp1); - - // Compute sunlight from P & lightnorm (for long rays like sky) - temp2.mV[1] = llmax(F_APPROXIMATELY_ZERO, llmax(0.f, Pn[1]) * 1.0f + lightnorm[1] ); - - temp2.mV[1] = 1.f / temp2.mV[1]; - componentMultBy(sunlight, componentExp((light_atten * -1.f) * temp2.mV[1])); - - // Distance - temp2.mV[2] = Plen * density_multiplier; - - // Transparency (-> temp1) - temp1 = componentExp((temp1 * -1.f) * temp2.mV[2]); - - - // Compute haze glow - temp2.mV[0] = Pn * LLVector3(lightnorm); - - temp2.mV[0] = 1.f - temp2.mV[0]; - // temp2.x is 0 at the sun and increases away from sun - temp2.mV[0] = llmax(temp2.mV[0], .001f); - // Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) - temp2.mV[0] *= glow.mV[0]; - // Higher glow.x gives dimmer glow (because next step is 1 / "angle") - temp2.mV[0] = pow(temp2.mV[0], glow.mV[2]); - // glow.z should be negative, so we're doing a sort of (1 / "angle") function - - // Add "minimum anti-solar illumination" - temp2.mV[0] += .25f; - - - // Haze color above cloud - vary_HazeColor = (blue_horizon * blue_weight * (sunlight + ambient) - + componentMult(haze_horizon * haze_weight, sunlight * temp2.mV[0] + ambient) - ); - - // Increase ambient when there are more clouds - LLColor3 tmpAmbient = ambient + (LLColor3::white - ambient) * cloud_shadow * 0.5f; - - // Dim sunlight by cloud shadow percentage - sunlight *= (1.f - cloud_shadow); - - // Haze color below cloud - LLColor3 additiveColorBelowCloud = (blue_horizon * blue_weight * (sunlight + tmpAmbient) - + componentMult(haze_horizon * haze_weight, sunlight * temp2.mV[0] + tmpAmbient) - ); - - // Final atmosphere additive - componentMultBy(vary_HazeColor, LLColor3::white - temp1); - - sunlight = sunlight_color; - temp2.mV[1] = llmax(0.f, lightnorm[1] * 2.f); - temp2.mV[1] = 1.f / temp2.mV[1]; - componentMultBy(sunlight, componentExp((light_atten * -1.f) * temp2.mV[1])); + bool same_atmospherics = approximatelyEqual(m_lastAtmosphericsVars, m_atmosphericsVars, UPDATE_MIN_DELTA_THRESHOLD); - // Attenuate cloud color by atmosphere - temp1 = componentSqrt(temp1); //less atmos opacity (more transparency) below clouds + mNeedUpdate = mNeedUpdate || !same_atmospherics; - // At horizon, blend high altitude sky color towards the darker color below the clouds - vary_HazeColor += - componentMult(additiveColorBelowCloud - vary_HazeColor, LLColor3::white - componentSqrt(temp1)); - - if (Pn[1] < 0.f) - { - // Eric's original: - // LLColor3 dark_brown(0.143f, 0.129f, 0.114f); - LLColor3 dark_brown(0.082f, 0.076f, 0.066f); - LLColor3 brown(0.430f, 0.386f, 0.322f); - LLColor3 sky_lighting = sunlight + ambient; - F32 haze_brightness = vary_HazeColor.brightness(); - - if (Pn[1] < -0.05f) - { - vary_HazeColor = colorMix(dark_brown, brown, -Pn[1] * 0.9f) * sky_lighting * haze_brightness; - } - - if (Pn[1] > -0.1f) + if (mNeedUpdate && (mForceUpdateThrottle.hasExpired() || mForceUpdate)) { - vary_HazeColor = colorMix(LLColor3::white * haze_brightness, vary_HazeColor, fabs((Pn[1] + 0.05f) * -20.f)); + // start updating cube map sides + updateFog(LLViewerCamera::getInstance()->getFar()); + mCubeMapUpdateStage = 0; + mForceUpdate = FALSE; } } -} + else if (mCubeMapUpdateStage == NUM_CUBEMAP_FACES) + { + LL_RECORD_BLOCK_TIME(FTM_VOSKY_UPDATEFORCED); + LLSkyTex::stepCurrent(); + + bool is_alm_wl_sky = gPipeline.canUseWindLightShaders(); + + int tex = mSkyTex[0].getWhich(TRUE); + + for (int side = 0; side < NUM_CUBEMAP_FACES; side++) + { + LLImageRaw* raw1 = nullptr; + LLImageRaw* raw2 = nullptr; + + if (!is_alm_wl_sky) + { + raw1 = mSkyTex[side].getImageRaw(TRUE); + raw2 = mSkyTex[side].getImageRaw(FALSE); + raw2->copy(raw1); + mSkyTex[side].createGLImage(tex); + } + + raw1 = mShinyTex[side].getImageRaw(TRUE); + raw2 = mShinyTex[side].getImageRaw(FALSE); + raw2->copy(raw1); + mShinyTex[side].createGLImage(tex); + } + next_frame = 0; + + // update the sky texture + if (!is_alm_wl_sky) + { + for (S32 i = 0; i < NUM_CUBEMAP_FACES; ++i) + { + mSkyTex[i].create(); + } + } + + for (S32 i = 0; i < NUM_CUBEMAP_FACES; ++i) + { + mShinyTex[i].create(); + } + + // update the environment map + initCubeMap(); + + m_lastAtmosphericsVars = m_atmosphericsVars; + + mNeedUpdate = FALSE; + mForceUpdate = FALSE; + + mForceUpdateThrottle.setTimerExpirySec(UPDATE_EXPRY); + gPipeline.markRebuild(gSky.mVOGroundp->mDrawable, LLDrawable::REBUILD_ALL, TRUE); + + if (mDrawable.notNull() && mDrawable->getFace(0) && !mDrawable->getFace(0)->getVertexBuffer()) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); + } + mCubeMapUpdateStage = -1; + } + // run 0 to 5 faces, each face in own frame + else if (mCubeMapUpdateStage >= 0 && mCubeMapUpdateStage < NUM_CUBEMAP_FACES) + { + LL_RECORD_BLOCK_TIME(FTM_VOSKY_CREATETEXTURES); + S32 side = mCubeMapUpdateStage; + // CPU hungry part, createSkyTexture() is math heavy + // Prior to EEP it was mostly per tile, but since EPP it is per face. + // This still can be optimized further + // (i.e. potentially can be made per tile again, can be moved to thread + // instead of executing per face, or may be can be moved to shaders) + for (S32 tile = 0; tile < NUM_TILES; tile++) + { + createSkyTexture(m_atmosphericsVars, side, tile); + } + mCubeMapUpdateStage++; + } -#if LL_MSVC && __MSVC_VER__ < 8 -#pragma optimize("p", off) -#endif + return TRUE; +} -LLColor3 LLVOSky::calcSkyColorWLFrag(LLVector3 & Pn, LLColor3 & vary_HazeColor, LLColor3 & vary_CloudColorSun, - LLColor3 & vary_CloudColorAmbient, F32 & vary_CloudDensity, - LLVector2 vary_HorizontalProjection[2]) +void LLVOSky::updateTextures() { - LLColor3 res; - - LLColor3 color0 = vary_HazeColor; - - if (!gPipeline.canUseWindLightShaders()) + if (mSunTexturep[0]) { - LLColor3 color1 = color0 * 2.0f; - color1 = smear(1.f) - componentSaturate(color1); - componentPow(color1, gamma); - res = smear(1.f) - color1; - } - else - { - res = color0; + mSunTexturep[0]->addTextureStats( (F32)MAX_IMAGE_AREA ); } -# ifndef LL_RELEASE_FOR_DOWNLOAD - - LLColor3 color2 = 2.f * color0; - - LLColor3 color3 = LLColor3(1.f, 1.f, 1.f) - componentSaturate(color2); - componentPow(color3, gamma); - color3 = LLColor3(1.f, 1.f, 1.f) - color3; - - static enum { - OUT_DEFAULT = 0, - OUT_SKY_BLUE = 1, - OUT_RED = 2, - OUT_PN = 3, - OUT_HAZE = 4, - } debugOut = OUT_DEFAULT; - - switch(debugOut) + if (mSunTexturep[1]) { - case OUT_DEFAULT: - break; - case OUT_SKY_BLUE: - res = LLColor3(0.4f, 0.4f, 0.9f); - break; - case OUT_RED: - res = LLColor3(1.f, 0.f, 0.f); - break; - case OUT_PN: - res = LLColor3(Pn[0], Pn[1], Pn[2]); - break; - case OUT_HAZE: - res = vary_HazeColor; - break; - } -# endif // LL_RELEASE_FOR_DOWNLOAD - return res; + mSunTexturep[1]->addTextureStats( (F32)MAX_IMAGE_AREA ); } -LLColor3 LLVOSky::createDiffuseFromWL(LLColor3 diffuse, LLColor3 ambient, LLColor3 sundiffuse, LLColor3 sunambient) + if (mMoonTexturep[0]) { - return componentMult(diffuse, sundiffuse) * 4.0f + - componentMult(ambient, sundiffuse) * 2.0f + sunambient; + mMoonTexturep[0]->addTextureStats( (F32)MAX_IMAGE_AREA ); } -LLColor3 LLVOSky::createAmbientFromWL(LLColor3 ambient, LLColor3 sundiffuse, LLColor3 sunambient) + if (mMoonTexturep[1]) { - return (componentMult(ambient, sundiffuse) + sunambient) * 0.8f; + mMoonTexturep[1]->addTextureStats( (F32)MAX_IMAGE_AREA ); } - -void LLVOSky::calcAtmospherics(void) -{ - initAtmospherics(); - - LLColor3 vary_HazeColor; - LLColor3 vary_SunlightColor; - LLColor3 vary_AmbientColor; + if (mBloomTexturep[0]) { - // Initialize temp variables - LLColor3 sunlight = sunlight_color; - - // Sunlight attenuation effect (hue and brightness) due to atmosphere - // this is used later for sunlight modulation at various altitudes - LLColor3 light_atten = - (blue_density * 1.0 + smear(haze_density * 0.25f)) * (density_multiplier * max_y); - - // Calculate relative weights - LLColor3 temp2(0.f, 0.f, 0.f); - LLColor3 temp1 = blue_density + smear(haze_density); - LLColor3 blue_weight = componentDiv(blue_density, temp1); - LLColor3 haze_weight = componentDiv(smear(haze_density), temp1); - - // Compute sunlight from P & lightnorm (for long rays like sky) - /// USE only lightnorm. - // temp2[1] = llmax(0.f, llmax(0.f, Pn[1]) * 1.0f + lightnorm[1] ); - - // and vary_sunlight will work properly with moon light - F32 lighty = unclamped_lightnorm[1]; - if(lighty < LLSky::NIGHTTIME_ELEVATION_COS) - { - lighty = -lighty; + mBloomTexturep[0]->addTextureStats( (F32)MAX_IMAGE_AREA ); } - temp2.mV[1] = llmax(0.f, lighty); - if(temp2.mV[1] > 0.f) + if (mBloomTexturep[1]) { - temp2.mV[1] = 1.f / temp2.mV[1]; + mBloomTexturep[1]->addTextureStats( (F32)MAX_IMAGE_AREA ); } - componentMultBy(sunlight, componentExp((light_atten * -1.f) * temp2.mV[1])); - - // Distance - temp2.mV[2] = density_multiplier; - - // Transparency (-> temp1) - temp1 = componentExp((temp1 * -1.f) * temp2.mV[2]); - - // vary_AtmosAttenuation = temp1; - - //increase ambient when there are more clouds - LLColor3 tmpAmbient = ambient + (smear(1.f) - ambient) * cloud_shadow * 0.5f; - - //haze color - vary_HazeColor = - (blue_horizon * blue_weight * (sunlight*(1.f - cloud_shadow) + tmpAmbient) - + componentMult(haze_horizon * haze_weight, sunlight*(1.f - cloud_shadow) * temp2.mV[0] + tmpAmbient) - ); - - //brightness of surface both sunlight and ambient - vary_SunlightColor = componentMult(sunlight, temp1) * 1.f; - vary_SunlightColor.clamp(); - vary_SunlightColor = smear(1.0f) - vary_SunlightColor; - vary_SunlightColor = componentPow(vary_SunlightColor, gamma); - vary_SunlightColor = smear(1.0f) - vary_SunlightColor; - vary_AmbientColor = componentMult(tmpAmbient, temp1) * 0.5; - vary_AmbientColor.clamp(); - vary_AmbientColor = smear(1.0f) - vary_AmbientColor; - vary_AmbientColor = componentPow(vary_AmbientColor, gamma); - vary_AmbientColor = smear(1.0f) - vary_AmbientColor; - - componentMultBy(vary_HazeColor, LLColor3(1.f, 1.f, 1.f) - temp1); - } - mSun.setColor(vary_SunlightColor); - mMoon.setColor(LLColor3(1.0f, 1.0f, 1.0f)); +LLDrawable *LLVOSky::createDrawable(LLPipeline *pipeline) +{ + pipeline->allocDrawable(this); + mDrawable->setLit(FALSE); - mSun.renewDirection(); - mSun.renewColor(); - mMoon.renewDirection(); - mMoon.renewColor(); + LLDrawPoolSky *poolp = (LLDrawPoolSky*) gPipeline.getPool(LLDrawPool::POOL_SKY); + poolp->setSkyTex(mSkyTex); + mDrawable->setRenderType(LLPipeline::RENDER_TYPE_SKY); - float dp = getToSunLast() * LLVector3(0,0,1.f); - if (dp < 0) + for (S32 i = 0; i < NUM_CUBEMAP_FACES; ++i) { - dp = 0; + mFace[FACE_SIDE0 + i] = mDrawable->addFace(poolp, NULL); } - // Since WL scales everything by 2, there should always be at least a 2:1 brightness ratio - // between sunlight and point lights in windlight to normalize point lights. - F32 sun_dynamic_range = llmax(gSavedSettings.getF32("RenderSunDynamicRange"), 0.0001f); - LLWLParamManager::getInstance()->mSceneLightStrength = 2.0f * (1.0f + sun_dynamic_range * dp); + mFace[FACE_SUN] = mDrawable->addFace(poolp, nullptr); + mFace[FACE_MOON] = mDrawable->addFace(poolp, nullptr); + mFace[FACE_BLOOM] = mDrawable->addFace(poolp, nullptr); - mSunDiffuse = vary_SunlightColor; - mSunAmbient = vary_AmbientColor; - mMoonDiffuse = vary_SunlightColor; - mMoonAmbient = vary_AmbientColor; + mFace[FACE_SUN]->setMediaAllowed(false); + mFace[FACE_MOON]->setMediaAllowed(false); + mFace[FACE_BLOOM]->setMediaAllowed(false); - mTotalAmbient = vary_AmbientColor; - mTotalAmbient.setAlpha(1); - - mFadeColor = mTotalAmbient + (mSunDiffuse + mMoonDiffuse) * 0.5f; - mFadeColor.setAlpha(0); + return mDrawable; } -void LLVOSky::idleUpdate(LLAgent &agent, const F64 &time) +void LLVOSky::setSunScale(F32 sun_scale) { + mSunScale = sun_scale; } -BOOL LLVOSky::updateSky() +void LLVOSky::setMoonScale(F32 moon_scale) { - if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))) - { - return TRUE; + mMoonScale = moon_scale; } - if (mDead) +void LLVOSky::setSunTextures(const LLUUID& sun_texture, const LLUUID& sun_texture_next) { - // It's dead. Don't update it. - return TRUE; - } - if (gGLManager.mIsDisabled) - { - return TRUE; - } + // We test the UUIDs here because we explicitly do not want the default image returned by getFetchedTexture in that case... + mSunTexturep[0] = sun_texture.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(sun_texture, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); + mSunTexturep[1] = sun_texture_next.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(sun_texture_next, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); - static S32 next_frame = 0; - const S32 total_no_tiles = 6 * NUM_TILES; - const S32 cycle_frame_no = total_no_tiles + 1; + bool can_use_wl = gPipeline.canUseWindLightShaders(); - if (mUpdateTimer.getElapsedTimeF32() > 0.001f) + if (mFace[FACE_SUN]) { - mUpdateTimer.reset(); - const S32 frame = next_frame; - - ++next_frame; - next_frame = next_frame % cycle_frame_no; + if (mSunTexturep[0]) + { + mSunTexturep[0]->setAddressMode(LLTexUnit::TAM_CLAMP); + } - mInterpVal = (!mInitialized) ? 1 : (F32)next_frame / cycle_frame_no; - // sInterpVal = (F32)next_frame / cycle_frame_no; - LLSkyTex::setInterpVal( mInterpVal ); - LLHeavenBody::setInterpVal( mInterpVal ); - calcAtmospherics(); + LLViewerTexture* current_tex0 = mFace[FACE_SUN]->getTexture(LLRender::DIFFUSE_MAP); + LLViewerTexture* current_tex1 = mFace[FACE_SUN]->getTexture(LLRender::ALTERNATE_DIFFUSE_MAP); - if (mForceUpdate || total_no_tiles == frame) - { - LLSkyTex::stepCurrent(); - - const static F32 LIGHT_DIRECTION_THRESHOLD = (F32) cos(DEG_TO_RAD * 1.f); - const static F32 COLOR_CHANGE_THRESHOLD = 0.01f; - - LLVector3 direction = mSun.getDirection(); - direction.normalize(); - const F32 dot_lighting = direction * mLastLightingDirection; - - LLColor3 delta_color; - delta_color.setVec(mLastTotalAmbient.mV[0] - mTotalAmbient.mV[0], - mLastTotalAmbient.mV[1] - mTotalAmbient.mV[1], - mLastTotalAmbient.mV[2] - mTotalAmbient.mV[2]); - - if ( mForceUpdate - || (((dot_lighting < LIGHT_DIRECTION_THRESHOLD) - || (delta_color.length() > COLOR_CHANGE_THRESHOLD) - || !mInitialized) - && !direction.isExactlyZero())) + if (current_tex0 && (mSunTexturep[0] != current_tex0) && current_tex0->isViewerMediaTexture()) { - mLastLightingDirection = direction; - mLastTotalAmbient = mTotalAmbient; - mInitialized = TRUE; + static_cast<LLViewerMediaTexture*>(current_tex0)->removeMediaFromFace(mFace[FACE_SUN]); + } - if (mCubeMap) + if (current_tex1 && (mSunTexturep[1] != current_tex1) && current_tex1->isViewerMediaTexture()) { - if (mForceUpdate) - { - updateFog(LLViewerCamera::getInstance()->getFar()); - for (int side = 0; side < 6; side++) - { - for (int tile = 0; tile < NUM_TILES; tile++) - { - createSkyTexture(side, tile); - } + static_cast<LLViewerMediaTexture*>(current_tex1)->removeMediaFromFace(mFace[FACE_SUN]); } - calcAtmospherics(); + mFace[FACE_SUN]->setTexture(LLRender::DIFFUSE_MAP, mSunTexturep[0]); - for (int side = 0; side < 6; side++) + if (can_use_wl) + { + if (mSunTexturep[1]) { - LLImageRaw* raw1 = mSkyTex[side].getImageRaw(TRUE); - LLImageRaw* raw2 = mSkyTex[side].getImageRaw(FALSE); - raw2->copy(raw1); - mSkyTex[side].createGLImage(mSkyTex[side].getWhich(FALSE)); - - raw1 = mShinyTex[side].getImageRaw(TRUE); - raw2 = mShinyTex[side].getImageRaw(FALSE); - raw2->copy(raw1); - mShinyTex[side].createGLImage(mShinyTex[side].getWhich(FALSE)); + mSunTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP); } - next_frame = 0; + mFace[FACE_SUN]->setTexture(LLRender::ALTERNATE_DIFFUSE_MAP, mSunTexturep[1]); } } } - /// *TODO really, sky texture and env map should be shared on a single texture - /// I'll let Brad take this at some point - - // update the sky texture - for (S32 i = 0; i < 6; ++i) +void LLVOSky::setMoonTextures(const LLUUID& moon_texture, const LLUUID& moon_texture_next) { - mSkyTex[i].create(1.0f); - mShinyTex[i].create(1.0f); - } + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); - // update the environment map - if (mCubeMap) - { - std::vector<LLPointer<LLImageRaw> > images; - images.reserve(6); - for (S32 side = 0; side < 6; side++) - { - images.push_back(mShinyTex[side].getImageRaw(TRUE)); - } - mCubeMap->init(images); - gGL.getTexUnit(0)->disable(); - } + bool can_use_wl = gPipeline.canUseWindLightShaders(); - gPipeline.markRebuild(gSky.mVOGroundp->mDrawable, LLDrawable::REBUILD_ALL, TRUE); - // *TODO: decide whether we need to update the stars vertex buffer in LLVOWLSky -Brad. - //gPipeline.markRebuild(gSky.mVOWLSkyp->mDrawable, LLDrawable::REBUILD_ALL, TRUE); + mMoonTexturep[0] = moon_texture.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(moon_texture, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); + mMoonTexturep[1] = moon_texture_next.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(moon_texture_next, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); - mForceUpdate = FALSE; - } - else + if (mFace[FACE_MOON]) + { + if (mMoonTexturep[0]) { - const S32 side = frame / NUM_TILES; - const S32 tile = frame % NUM_TILES; - createSkyTexture(side, tile); - } + mMoonTexturep[0]->setAddressMode(LLTexUnit::TAM_CLAMP); } + mFace[FACE_MOON]->setTexture(LLRender::DIFFUSE_MAP, mMoonTexturep[0]); - if (mDrawable.notNull() && mDrawable->getFace(0) && !mDrawable->getFace(0)->getVertexBuffer()) + if (mMoonTexturep[1] && can_use_wl) { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); + mMoonTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP); + mFace[FACE_MOON]->setTexture(LLRender::ALTERNATE_DIFFUSE_MAP, mMoonTexturep[1]); } - return TRUE; -} - -void LLVOSky::updateTextures() -{ - if (mSunTexturep) - { - mSunTexturep->addTextureStats( (F32)MAX_IMAGE_AREA ); - mMoonTexturep->addTextureStats( (F32)MAX_IMAGE_AREA ); - mBloomTexturep->addTextureStats( (F32)MAX_IMAGE_AREA ); } } -LLDrawable *LLVOSky::createDrawable(LLPipeline *pipeline) +void LLVOSky::setCloudNoiseTextures(const LLUUID& cloud_noise_texture, const LLUUID& cloud_noise_texture_next) { - pipeline->allocDrawable(this); - mDrawable->setLit(FALSE); + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); - LLDrawPoolSky *poolp = (LLDrawPoolSky*) gPipeline.getPool(LLDrawPool::POOL_SKY); - poolp->setSkyTex(mSkyTex); - mDrawable->setRenderType(LLPipeline::RENDER_TYPE_SKY); + mCloudNoiseTexturep[0] = cloud_noise_texture.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(cloud_noise_texture, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); + mCloudNoiseTexturep[1] = cloud_noise_texture_next.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(cloud_noise_texture_next, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); - for (S32 i = 0; i < 6; ++i) + if (mCloudNoiseTexturep[0]) { - mFace[FACE_SIDE0 + i] = mDrawable->addFace(poolp, NULL); + mCloudNoiseTexturep[0]->setAddressMode(LLTexUnit::TAM_WRAP); } - mFace[FACE_SUN] = mDrawable->addFace(poolp, mSunTexturep); - mFace[FACE_MOON] = mDrawable->addFace(poolp, mMoonTexturep); - mFace[FACE_BLOOM] = mDrawable->addFace(poolp, mBloomTexturep); - - return mDrawable; + if (mCloudNoiseTexturep[1]) + { + mCloudNoiseTexturep[1]->setAddressMode(LLTexUnit::TAM_WRAP); + } } -//by bao -//fake vertex buffer updating -//to guarantee at least updating one VBO buffer every frame -//to walk around the bug caused by ATI card --> DEV-3855 -// -void LLVOSky::createDummyVertexBuffer() +void LLVOSky::setBloomTextures(const LLUUID& bloom_texture, const LLUUID& bloom_texture_next) { - if(!mFace[FACE_DUMMY]) - { - LLDrawPoolSky *poolp = (LLDrawPoolSky*) gPipeline.getPool(LLDrawPool::POOL_SKY); - mFace[FACE_DUMMY] = mDrawable->addFace(poolp, NULL); - } + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); - if(!mFace[FACE_DUMMY]->getVertexBuffer()) - { - LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB); - buff->allocateBuffer(1, 1, TRUE); - mFace[FACE_DUMMY]->setVertexBuffer(buff); - } -} + LLUUID bloom_tex = bloom_texture.isNull() ? psky->GetDefaultBloomTextureId() : bloom_texture; + LLUUID bloom_tex_next = bloom_texture_next.isNull() ? (bloom_texture.isNull() ? psky->GetDefaultBloomTextureId() : bloom_texture) : bloom_texture_next; -static LLTrace::BlockTimerStatHandle FTM_RENDER_FAKE_VBO_UPDATE("Fake VBO Update"); + mBloomTexturep[0] = bloom_tex.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(bloom_tex, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); + mBloomTexturep[1] = bloom_tex_next.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(bloom_tex_next, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); -void LLVOSky::updateDummyVertexBuffer() + if (mBloomTexturep[0]) { - if(!LLVertexBuffer::sEnableVBOs) - return ; + mBloomTexturep[0]->setAddressMode(LLTexUnit::TAM_CLAMP); + } - if(mHeavenlyBodyUpdated) + if (mBloomTexturep[1]) { - mHeavenlyBodyUpdated = FALSE ; - return ; + mBloomTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP); + } } - LL_RECORD_BLOCK_TIME(FTM_RENDER_FAKE_VBO_UPDATE) ; - - if(!mFace[FACE_DUMMY] || !mFace[FACE_DUMMY]->getVertexBuffer()) - createDummyVertexBuffer() ; - - LLStrider<LLVector3> vertices ; - mFace[FACE_DUMMY]->getVertexBuffer()->getVertexStrider(vertices, 0); - *vertices = mCameraPosAgent ; - mFace[FACE_DUMMY]->getVertexBuffer()->flush(); -} -//---------------------------------- -//end of fake vertex buffer updating -//---------------------------------- static LLTrace::BlockTimerStatHandle FTM_GEO_SKY("Sky Geometry"); BOOL LLVOSky::updateGeometry(LLDrawable *drawable) @@ -1260,13 +1004,14 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable) if (mFace[FACE_REFLECTION] == NULL) { LLDrawPoolWater *poolp = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER); - if (gPipeline.getPool(LLDrawPool::POOL_WATER)->getVertexShaderLevel() != 0) + if (gPipeline.getPool(LLDrawPool::POOL_WATER)->getShaderLevel() != 0) { mFace[FACE_REFLECTION] = drawable->addFace(poolp, NULL); } } mCameraPosAgent = drawable->getPositionAgent(); + mEarthCenter.mV[0] = mCameraPosAgent.mV[0]; mEarthCenter.mV[1] = mCameraPosAgent.mV[1]; @@ -1286,7 +1031,7 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable) U16 index_offset; LLFace *face; - for (S32 side = 0; side < 6; ++side) + for (S32 side = 0; side < NUM_CUBEMAP_FACES; ++side) { face = mFace[FACE_SIDE0 + side]; @@ -1341,63 +1086,39 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable) right.normalize(); up.normalize(); - const static F32 elevation_factor = 0.0f/sResolution; - const F32 cos_max_angle = cosHorizon(elevation_factor); - mSun.setDraw(updateHeavenlyBodyGeometry(drawable, FACE_SUN, TRUE, mSun, cos_max_angle, up, right)); - mMoon.setDraw(updateHeavenlyBodyGeometry(drawable, FACE_MOON, FALSE, mMoon, cos_max_angle, up, right)); + bool draw_sun = updateHeavenlyBodyGeometry(drawable, mSunScale, FACE_SUN, mSun, up, right); + bool draw_moon = updateHeavenlyBodyGeometry(drawable, mMoonScale, FACE_MOON, mMoon, up, right); + + draw_sun &= LLEnvironment::getInstance()->getIsSunUp(); + draw_moon &= LLEnvironment::getInstance()->getIsMoonUp(); + + mSun.setDraw(draw_sun); + mMoon.setDraw(draw_moon); const F32 water_height = gAgent.getRegion()->getWaterHeight() + 0.01f; // LLWorld::getInstance()->getWaterHeight() + 0.01f; const F32 camera_height = mCameraPosAgent.mV[2]; const F32 height_above_water = camera_height - water_height; - BOOL sun_flag = FALSE; - + bool sun_flag = FALSE; if (mSun.isVisible()) { - if (mMoon.isVisible()) - { - sun_flag = look_at * mSun.getDirection() > 0; + sun_flag = !mMoon.isVisible() || ((look_at * mSun.getDirection()) > 0); } - else - { - sun_flag = TRUE; - } - } - - if (height_above_water > 0) - { - BOOL render_ref = gPipeline.getPool(LLDrawPool::POOL_WATER)->getVertexShaderLevel() == 0; - if (sun_flag) - { - setDrawRefl(0); + bool above_water = (height_above_water > 0); + bool render_ref = above_water && gPipeline.getPool(LLDrawPool::POOL_WATER)->getShaderLevel() == 0; + setDrawRefl(above_water ? (sun_flag ? 0 : 1) : -1); if (render_ref) { updateReflectionGeometry(drawable, height_above_water, mSun); } - } - else - { - setDrawRefl(1); - if (render_ref) - { - updateReflectionGeometry(drawable, height_above_water, mMoon); - } - } - } - else - { - setDrawRefl(-1); - } LLPipeline::sCompiles++; return TRUE; } -BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, const BOOL is_sun, - LLHeavenBody& hb, const F32 cos_max_angle, - const LLVector3 &up, const LLVector3 &right) +bool LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, F32 scale, const S32 f, LLHeavenBody& hb, const LLVector3 &up, const LLVector3 &right) { mHeavenlyBodyUpdated = TRUE ; @@ -1408,52 +1129,39 @@ BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, cons S32 index_offset; LLFace *facep; - LLVector3 to_dir = hb.getDirection(); - if (!is_sun) + LLQuaternion rot = hb.getRotation(); + LLVector3 to_dir = LLVector3::x_axis * rot; + + LLVector3 hb_right = to_dir % LLVector3::z_axis; + LLVector3 hb_up = hb_right % to_dir; + + // at zenith so math below fails spectacularly + if ((to_dir * LLVector3::z_axis) > 0.99f) { - to_dir.mV[2] = llmax(to_dir.mV[2]+0.1f, 0.1f); + hb_right = LLVector3::y_axis_neg * rot; + hb_up = LLVector3::z_axis * rot; } - LLVector3 draw_pos = to_dir * HEAVENLY_BODY_DIST; + LLVector3 draw_pos = to_dir * HEAVENLY_BODY_DIST; - LLVector3 hb_right = to_dir % LLVector3::z_axis; - LLVector3 hb_up = hb_right % to_dir; hb_right.normalize(); hb_up.normalize(); - //const static F32 cos_max_turn = sqrt(3.f) / 2; // 30 degrees - //const F32 cos_turn_right = 1. / (llmax(cos_max_turn, hb_right * right)); - //const F32 cos_turn_up = 1. / llmax(cos_max_turn, hb_up * up); - const F32 enlargm_factor = ( 1 - to_dir.mV[2] ); F32 horiz_enlargement = 1 + enlargm_factor * 0.3f; F32 vert_enlargement = 1 + enlargm_factor * 0.2f; - // Parameters for the water reflection - hb.setU(HEAVENLY_BODY_FACTOR * horiz_enlargement * hb.getDiskRadius() * hb_right); - hb.setV(HEAVENLY_BODY_FACTOR * vert_enlargement * hb.getDiskRadius() * hb_up); - // End of parameters for the water reflection - - const LLVector3 scaled_right = HEAVENLY_BODY_DIST * hb.getU(); - const LLVector3 scaled_up = HEAVENLY_BODY_DIST * hb.getV(); + const LLVector3 scaled_right = horiz_enlargement * scale * HEAVENLY_BODY_DIST * HEAVENLY_BODY_FACTOR * hb.getDiskRadius() * hb_right; + const LLVector3 scaled_up = vert_enlargement * scale * HEAVENLY_BODY_DIST * HEAVENLY_BODY_FACTOR * hb.getDiskRadius() * hb_up; - //const LLVector3 scaled_right = horiz_enlargement * HEAVENLY_BODY_SCALE * hb.getDiskRadius() * hb_right;//right; - //const LLVector3 scaled_up = vert_enlargement * HEAVENLY_BODY_SCALE * hb.getDiskRadius() * hb_up;//up; LLVector3 v_clipped[4]; - hb.corner(0) = draw_pos - scaled_right + scaled_up; - hb.corner(1) = draw_pos - scaled_right - scaled_up; - hb.corner(2) = draw_pos + scaled_right + scaled_up; - hb.corner(3) = draw_pos + scaled_right - scaled_up; + v_clipped[0] = draw_pos - scaled_right + scaled_up; + v_clipped[1] = draw_pos - scaled_right - scaled_up; + v_clipped[2] = draw_pos + scaled_right + scaled_up; + v_clipped[3] = draw_pos + scaled_right - scaled_up; - - F32 t_left, t_right; - if (!clip_quad_to_horizon(t_left, t_right, v_clipped, hb.corners(), cos_max_angle)) - { - hb.setVisible(FALSE); - return FALSE; - } hb.setVisible(TRUE); facep = mFace[f]; @@ -1503,164 +1211,9 @@ BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, cons facep->getVertexBuffer()->flush(); - if (is_sun) - { - if ((t_left > 0) && (t_right > 0)) - { - F32 t = (t_left + t_right) * 0.5f; - mSun.setHorizonVisibility(0.5f * (1 + cos(t * F_PI))); - } - else - { - mSun.setHorizonVisibility(); - } - updateSunHaloGeometry(drawable); - } - - return TRUE; -} - - - - -// Clips quads with top and bottom sides parallel to horizon. - -BOOL clip_quad_to_horizon(F32& t_left, F32& t_right, LLVector3 v_clipped[4], - const LLVector3 v_corner[4], const F32 cos_max_angle) -{ - t_left = clip_side_to_horizon(v_corner[1], v_corner[0], cos_max_angle); - t_right = clip_side_to_horizon(v_corner[3], v_corner[2], cos_max_angle); - - if ((t_left >= 1) || (t_right >= 1)) - { - return FALSE; - } - - //const BOOL left_clip = (t_left > 0); - //const BOOL right_clip = (t_right > 0); - - //if (!left_clip && !right_clip) - { - for (S32 vtx = 0; vtx < 4; ++vtx) - { - v_clipped[vtx] = v_corner[vtx]; - } - } -/* else - { - v_clipped[0] = v_corner[0]; - v_clipped[1] = left_clip ? ((1 - t_left) * v_corner[1] + t_left * v_corner[0]) - : v_corner[1]; - v_clipped[2] = v_corner[2]; - v_clipped[3] = right_clip ? ((1 - t_right) * v_corner[3] + t_right * v_corner[2]) - : v_corner[3]; - }*/ - return TRUE; } - -F32 clip_side_to_horizon(const LLVector3& V0, const LLVector3& V1, const F32 cos_max_angle) -{ - const LLVector3 V = V1 - V0; - const F32 k2 = 1.f/(cos_max_angle * cos_max_angle) - 1; - const F32 A = V.mV[0] * V.mV[0] + V.mV[1] * V.mV[1] - k2 * V.mV[2] * V.mV[2]; - const F32 B = V0.mV[0] * V.mV[0] + V0.mV[1] * V.mV[1] - k2 * V0.mV[2] * V.mV[2]; - const F32 C = V0.mV[0] * V0.mV[0] + V0.mV[1] * V0.mV[1] - k2 * V0.mV[2] * V0.mV[2]; - - if (fabs(A) < 1e-7) - { - return -0.1f; // v0 is cone origin and v1 is on the surface of the cone. - } - - const F32 det = sqrt(B*B - A*C); - const F32 t1 = (-B - det) / A; - const F32 t2 = (-B + det) / A; - const F32 z1 = V0.mV[2] + t1 * V.mV[2]; - const F32 z2 = V0.mV[2] + t2 * V.mV[2]; - if (z1 * cos_max_angle < 0) - { - return t2; - } - else if (z2 * cos_max_angle < 0) - { - return t1; - } - else if ((t1 < 0) || (t1 > 1)) - { - return t2; - } - else - { - return t1; - } -} - - -void LLVOSky::updateSunHaloGeometry(LLDrawable *drawable ) -{ -#if 0 - const LLVector3* v_corner = mSun.corners(); - - LLStrider<LLVector3> verticesp; - LLStrider<LLVector3> normalsp; - LLStrider<LLVector2> texCoordsp; - LLStrider<U16> indicesp; - S32 index_offset; - LLFace *face; - - const LLVector3 right = 2 * (v_corner[2] - v_corner[0]); - LLVector3 up = 2 * (v_corner[2] - v_corner[3]); - up.normalize(); - F32 size = right.length(); - up = size * up; - const LLVector3 draw_pos = 0.25 * (v_corner[0] + v_corner[1] + v_corner[2] + v_corner[3]); - - LLVector3 v_glow_corner[4]; - - v_glow_corner[0] = draw_pos - right + up; - v_glow_corner[1] = draw_pos - right - up; - v_glow_corner[2] = draw_pos + right + up; - v_glow_corner[3] = draw_pos + right - up; - - face = mFace[FACE_BLOOM]; - - if (face->mVertexBuffer.isNull()) - { - face->setSize(4, 6); - face->setGeomIndex(0); - face->setIndicesIndex(0); - face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); - face->mVertexBuffer->allocateBuffer(4, 6, TRUE); - } - - index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); - if (-1 == index_offset) - { - return; - } - - for (S32 vtx = 0; vtx < 4; ++vtx) - { - *(verticesp++) = v_glow_corner[vtx] + mCameraPosAgent; - } - - *(texCoordsp++) = TEX01; - *(texCoordsp++) = TEX00; - *(texCoordsp++) = TEX11; - *(texCoordsp++) = TEX10; - - *indicesp++ = index_offset + 0; - *indicesp++ = index_offset + 2; - *indicesp++ = index_offset + 1; - - *indicesp++ = index_offset + 1; - *indicesp++ = index_offset + 2; - *indicesp++ = index_offset + 3; -#endif -} - - F32 dtReflection(const LLVector3& p, F32 cos_dir_from_top, F32 sin_dir_from_top, F32 diff_angl_dir) { LLVector3 P = p; @@ -1722,9 +1275,6 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H, LLVector3 look_at_right = look_at % LLVector3::z_axis; look_at_right.normalize(); - const static F32 cos_horizon_angle = cosHorizon(0.0f/sResolution); - //const static F32 horizon_angle = acos(cos_horizon_angle); - const F32 enlargm_factor = ( 1 - to_dir.mV[2] ); F32 horiz_enlargement = 1 + enlargm_factor * 0.3f; F32 vert_enlargement = 1 + enlargm_factor * 0.2f; @@ -1739,22 +1289,10 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H, LLVector3 top_hb = v_corner[0] = stretch_corner[0] = hb_pos - Right + Up; v_corner[1] = stretch_corner[1] = hb_pos - Right - Up; - F32 dt_hor, dt; - dt_hor = clip_side_to_horizon(v_corner[1], v_corner[0], cos_horizon_angle); - LLVector2 TEX0t = TEX00; LLVector2 TEX1t = TEX10; LLVector3 lower_corner = v_corner[1]; - if ((dt_hor > 0) && (dt_hor < 1)) - { - TEX0t = LLVector2(0, dt_hor); - TEX1t = LLVector2(1, dt_hor); - lower_corner = (1 - dt_hor) * v_corner[1] + dt_hor * v_corner[0]; - } - else - dt_hor = llmax(0.0f, llmin(1.0f, dt_hor)); - top_hb.normalize(); const F32 cos_angle_of_view = fabs(top_hb.mV[VZ]); const F32 extension = llmin (5.0f, 1.0f / cos_angle_of_view); @@ -1766,9 +1304,6 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H, stretch_corner[0] = lower_corner + extension * (stretch_corner[0] - lower_corner); stretch_corner[1] = lower_corner + extension * (stretch_corner[1] - lower_corner); - dt = dt_hor; - - F32 cos_dir_from_top[2]; LLVector3 dir = stretch_corner[0]; @@ -1857,9 +1392,8 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H, F32 dt_tex = dtReflection(P, cos_dir_from_top[0], sin_dir_from_top, diff_angl_dir); - dt = dt_tex; - TEX0tt = LLVector2(0, dt); - TEX1tt = LLVector2(1, dt); + TEX0tt = LLVector2(0, dt_tex); + TEX1tt = LLVector2(1, dt_tex); quads++; } else @@ -1870,6 +1404,8 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H, LLFace *face = mFace[FACE_REFLECTION]; + if (face) + { if (!face->getVertexBuffer() || quads*4 != face->getGeomCount()) { face->setSize(quads * 4, quads * 6); @@ -1906,7 +1442,7 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H, const F32 attenuation = min_attenuation + cos_angle_of_view * (max_attenuation - min_attenuation); - LLColor4 hb_refl_col = (1-attenuation) * hb_col + attenuation * mFogColor; + LLColor4 hb_refl_col = (1 - attenuation) * hb_col + attenuation * getSkyFogColor(); face->setFaceColor(hb_refl_col); LLVector3 v_far[2]; @@ -1981,8 +1517,6 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H, left *= raws_inv; right *= raws_inv; - F32 dt_raw = dt; - for (S32 raw = 0; raw < raws; ++raw) { F32 dt_v0 = raw * raws_inv; @@ -1991,8 +1525,7 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H, const LLVector3 BR = v_refl_corner[3] + (F32)raw * right; const LLVector3 EL = BL + left; const LLVector3 ER = BR + right; - dt_v0 = dt_raw; - dt_raw = dt_v1 = dtReflection(EL, cos_dir_from_top[0], sin_dir_from_top, diff_angl_dir); + dt_v0 = dt_v1 = dtReflection(EL, cos_dir_from_top[0], sin_dir_from_top, diff_angl_dir); for (S32 col = 0; col < cols; ++col) { F32 dt_h0 = col * cols_inv; @@ -2022,256 +1555,65 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H, face->getVertexBuffer()->flush(); } - - - +} void LLVOSky::updateFog(const F32 distance) { - if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG)) + LLEnvironment& environment = LLEnvironment::instance(); + if (environment.getCurrentSky() != nullptr) { - if (!LLGLSLShader::sNoFixedFunction) - { - glFogf(GL_FOG_DENSITY, 0); - glFogfv(GL_FOG_COLOR, (F32 *) &LLColor4::white.mV); - glFogf(GL_FOG_END, 1000000.f); + LLVector3 light_dir = LLVector3(environment.getClampedLightNorm()); + m_legacyAtmospherics.updateFog(distance, light_dir); } - return; } - const BOOL hide_clip_plane = TRUE; - LLColor4 target_fog(0.f, 0.2f, 0.5f, 0.f); - - const F32 water_height = gAgent.getRegion() ? gAgent.getRegion()->getWaterHeight() : 0.f; - // LLWorld::getInstance()->getWaterHeight(); - F32 camera_height = gAgentCamera.getCameraPositionAgent().mV[2]; - - F32 near_clip_height = LLViewerCamera::getInstance()->getAtAxis().mV[VZ] * LLViewerCamera::getInstance()->getNear(); - camera_height += near_clip_height; - - F32 fog_distance = 0.f; - LLColor3 res_color[3]; - - LLColor3 sky_fog_color = LLColor3::white; - LLColor3 render_fog_color = LLColor3::white; - - LLVector3 tosun = getToSunLast(); - const F32 tosun_z = tosun.mV[VZ]; - tosun.mV[VZ] = 0.f; - tosun.normalize(); - LLVector3 perp_tosun; - perp_tosun.mV[VX] = -tosun.mV[VY]; - perp_tosun.mV[VY] = tosun.mV[VX]; - LLVector3 tosun_45 = tosun + perp_tosun; - tosun_45.normalize(); - - F32 delta = 0.06f; - tosun.mV[VZ] = delta; - perp_tosun.mV[VZ] = delta; - tosun_45.mV[VZ] = delta; - tosun.normalize(); - perp_tosun.normalize(); - tosun_45.normalize(); - - // Sky colors, just slightly above the horizon in the direction of the sun, perpendicular to the sun, and at a 45 degree angle to the sun. - initAtmospherics(); - res_color[0] = calcSkyColorInDir(tosun); - res_color[1] = calcSkyColorInDir(perp_tosun); - res_color[2] = calcSkyColorInDir(tosun_45); - - sky_fog_color = color_norm(res_color[0] + res_color[1] + res_color[2]); - - F32 full_off = -0.25f; - F32 full_on = 0.00f; - F32 on = (tosun_z - full_off) / (full_on - full_off); - on = llclamp(on, 0.01f, 1.f); - sky_fog_color *= 0.5f * on; - - - // We need to clamp these to non-zero, in order for the gamma correction to work. 0^y = ??? - S32 i; - for (i = 0; i < 3; i++) +void LLVOSky::setSunAndMoonDirectionsCFR(const LLVector3 &sun_dir_cfr, const LLVector3 &moon_dir_cfr) { - sky_fog_color.mV[i] = llmax(0.0001f, sky_fog_color.mV[i]); - } - - color_gamma_correct(sky_fog_color); + mSun.setDirection(sun_dir_cfr); + mMoon.setDirection(moon_dir_cfr); - render_fog_color = sky_fog_color; - - F32 fog_density = 0.f; - fog_distance = mFogRatio * distance; - - if (camera_height > water_height) + // Push the sun "South" as it approaches directly overhead so that we can always see bump mapping + // on the upward facing faces of cubes. { - LLColor4 fog(render_fog_color); - if (!LLGLSLShader::sNoFixedFunction) - { - glFogfv(GL_FOG_COLOR, fog.mV); - } - mGLFogCol = fog; + // Same as dot product with the up direction + clamp. + F32 sunDot = llmax(0.f, sun_dir_cfr.mV[2]); + sunDot *= sunDot; - if (hide_clip_plane) - { - // For now, set the density to extend to the cull distance. - const F32 f_log = 2.14596602628934723963618357029f; // sqrt(fabs(log(0.01f))) - fog_density = f_log/fog_distance; - if (!LLGLSLShader::sNoFixedFunction) - { - glFogi(GL_FOG_MODE, GL_EXP2); - } - } - else - { - const F32 f_log = 4.6051701859880913680359829093687f; // fabs(log(0.01f)) - fog_density = (f_log)/fog_distance; - if (!LLGLSLShader::sNoFixedFunction) - { - glFogi(GL_FOG_MODE, GL_EXP); - } - } - } - else - { - F32 depth = water_height - camera_height; + // Create normalized vector that has the sunDir pushed south about an hour and change. + LLVector3 adjustedDir = (sun_dir_cfr + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f; - // get the water param manager variables - float water_fog_density = LLWaterParamManager::getInstance()->getFogDensity(); - LLColor4 water_fog_color(LLDrawPoolWater::sWaterFogColor.mV); - - // adjust the color based on depth. We're doing linear approximations - float depth_scale = gSavedSettings.getF32("WaterGLFogDepthScale"); - float depth_modifier = 1.0f - llmin(llmax(depth / depth_scale, 0.01f), - gSavedSettings.getF32("WaterGLFogDepthFloor")); - - LLColor4 fogCol = water_fog_color * depth_modifier; - fogCol.setAlpha(1); - - // set the gl fog color - mGLFogCol = fogCol; - - // set the density based on what the shaders use - fog_density = water_fog_density * gSavedSettings.getF32("WaterGLFogDensityScale"); - - if (!LLGLSLShader::sNoFixedFunction) - { - glFogfv(GL_FOG_COLOR, (F32 *) &fogCol.mV); - glFogi(GL_FOG_MODE, GL_EXP2); + // Blend between normal sun dir and adjusted sun dir based on how close we are + // to having the sun overhead. + mBumpSunDir = adjustedDir * sunDot + sun_dir_cfr * (1.0f - sunDot); + mBumpSunDir.normalize(); } + updateDirections(); } - mFogColor = sky_fog_color; - mFogColor.setAlpha(1); - LLDrawPoolWater::sWaterFogEnd = fog_distance*2.2f; - - if (!LLGLSLShader::sNoFixedFunction) +void LLVOSky::setSunDirectionCFR(const LLVector3 &sun_dir_cfr) { - LLGLSFog gls_fog; - glFogf(GL_FOG_END, fog_distance*2.2f); - glFogf(GL_FOG_DENSITY, fog_density); - glHint(GL_FOG_HINT, GL_NICEST); - } - stop_glerror(); -} - - -// Functions used a lot. -F32 color_norm_pow(LLColor3& col, F32 e, BOOL postmultiply) -{ - F32 mv = color_max(col); - if (0 == mv) - { - return 0; - } - - col *= 1.f / mv; - color_pow(col, e); - if (postmultiply) - { - col *= mv; - } - return mv; -} - -// Returns angle (RADIANs) between the horizontal projection of "v" and the x_axis. -// Range of output is 0.0f to 2pi //359.99999...f -// Returns 0.0f when "v" = +/- z_axis. -F32 azimuth(const LLVector3 &v) -{ - F32 azimuth = 0.0f; - if (v.mV[VX] == 0.0f) - { - if (v.mV[VY] > 0.0f) - { - azimuth = F_PI * 0.5f; - } - else if (v.mV[VY] < 0.0f) - { - azimuth = F_PI * 1.5f;// 270.f; - } - } - else - { - azimuth = (F32) atan(v.mV[VY] / v.mV[VX]); - if (v.mV[VX] < 0.0f) - { - azimuth += F_PI; - } - else if (v.mV[VY] < 0.0f) - { - azimuth += F_PI * 2; - } - } - return azimuth; -} - -void LLVOSky::initSunDirection(const LLVector3 &sun_dir, const LLVector3 &sun_ang_velocity) -{ - LLVector3 sun_direction = (sun_dir.length() == 0) ? LLVector3::x_axis : sun_dir; - sun_direction.normalize(); - mSun.setDirection(sun_direction); - mSun.renewDirection(); - mSun.setAngularVelocity(sun_ang_velocity); - mMoon.setDirection(-mSun.getDirection()); - mMoon.renewDirection(); - mLastLightingDirection = mSun.getDirection(); - - calcAtmospherics(); - - if ( !mInitialized ) - { - init(); - LLSkyTex::stepCurrent(); - } -} - -void LLVOSky::setSunDirection(const LLVector3 &sun_dir, const LLVector3 &sun_ang_velocity) -{ - LLVector3 sun_direction = (sun_dir.length() == 0) ? LLVector3::x_axis : sun_dir; - sun_direction.normalize(); + mSun.setDirection(sun_dir_cfr); // Push the sun "South" as it approaches directly overhead so that we can always see bump mapping // on the upward facing faces of cubes. - LLVector3 newDir = sun_direction; - + { // Same as dot product with the up direction + clamp. - F32 sunDot = llmax(0.f, newDir.mV[2]); + F32 sunDot = llmax(0.f, sun_dir_cfr.mV[2]); sunDot *= sunDot; // Create normalized vector that has the sunDir pushed south about an hour and change. - LLVector3 adjustedDir = (newDir + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f; + LLVector3 adjustedDir = (sun_dir_cfr + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f; // Blend between normal sun dir and adjusted sun dir based on how close we are // to having the sun overhead. - mBumpSunDir = adjustedDir * sunDot + newDir * (1.0f - sunDot); + mBumpSunDir = adjustedDir * sunDot + sun_dir_cfr * (1.0f - sunDot); mBumpSunDir.normalize(); + } + updateDirections(); +} - F32 dp = mLastLightingDirection * sun_direction; - mSun.setDirection(sun_direction); - mSun.setAngularVelocity(sun_ang_velocity); - mMoon.setDirection(-sun_direction); - calcAtmospherics(); - if (dp < 0.995f) { //the sun jumped a great deal, update immediately - mForceUpdate = TRUE; - } +void LLVOSky::setMoonDirectionCFR(const LLVector3 &moon_dir_cfr) +{ + mMoon.setDirection(moon_dir_cfr); + updateDirections(); } diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h index 9cfb9773bd..39e42bbb24 100644 --- a/indra/newview/llvosky.h +++ b/indra/newview/llvosky.h @@ -30,86 +30,22 @@ #include "stdtypes.h" #include "v3color.h" #include "v4coloru.h" +#include "llquaternion.h" #include "llviewertexture.h" #include "llviewerobject.h" #include "llframetimer.h" +#include "v3colorutil.h" +#include "llsettingssky.h" +#include "lllegacyatmospherics.h" - -////////////////////////////////// -// -// Lots of constants -// -// 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_DIST = HORIZON_DIST - 20.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; -// Somewhat arbitrary: -const 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; - - -// 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; - -// HACK: Allow server to change sun and moon IDs. -// I can't figure out how to pass the appropriate -// information into the LLVOSky constructor. JC -extern LLUUID gSunTextureID; -extern LLUUID gMoonTextureID; - - -LL_FORCE_INLINE LLColor3 color_div(const LLColor3 &col1, const LLColor3 &col2) -{ - return LLColor3( - col1.mV[0] / col2.mV[0], - col1.mV[1] / col2.mV[1], - col1.mV[2] / col2.mV[2] ); -} - -LLColor3 color_norm(const LLColor3 &col); -BOOL clip_quad_to_horizon(F32& t_left, F32& t_right, LLVector3 v_clipped[4], - const LLVector3 v_corner[4], const F32 cos_max_angle); -F32 clip_side_to_horizon(const LLVector3& v0, const LLVector3& v1, const F32 cos_max_angle); - -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]); -} class LLFace; class LLHaze; - class LLSkyTex { friend class LLVOSky; @@ -121,33 +57,28 @@ private: LLColor4 *mSkyData; LLVector3 *mSkyDirs; // Cache of sky direction vectors static S32 sCurrent; - static F32 sInterpVal; public: - static F32 getInterpVal() { return sInterpVal; } - static void setInterpVal(const F32 v) { sInterpVal = v; } - static BOOL doInterpolate() { return sInterpVal > 0.001f; } - void bindTexture(BOOL curr = TRUE); protected: LLSkyTex(); - void init(); + void init(bool isShiny); void cleanupGL(); void restoreGL(); ~LLSkyTex(); - static S32 getResolution() { return sResolution; } - static S32 getCurrent() { return sCurrent; } - static S32 stepCurrent() { sCurrent++; sCurrent &= 1; return sCurrent; } - static S32 getNext() { return ((sCurrent+1) & 1); } - static S32 getWhich(const BOOL curr) { return curr ? sCurrent : getNext(); } + static S32 getResolution(); + static S32 getCurrent(); + static S32 stepCurrent(); + static S32 getNext(); + static S32 getWhich(const BOOL curr); void initEmpty(const S32 tex); - void create(F32 brightness); + void create(); void setDir(const LLVector3 &dir, const S32 i, const S32 j) { @@ -183,8 +114,10 @@ protected: return col; } - LLImageRaw* getImageRaw(BOOL curr=TRUE) { return mImageRaw[getWhich(curr)]; } + LLImageRaw* getImageRaw(BOOL curr=TRUE); void createGLImage(BOOL curr=TRUE); + + bool mIsShiny; }; /// TODO Move into the stars draw pool (and rename them appropriately). @@ -197,244 +130,70 @@ protected: LLColor3 mColorCached; F32 mIntensity; LLVector3 mDirection; // direction of the local heavenly body + LLQuaternion mRotation; LLVector3 mAngularVelocity; // velocity of the local heavenly body F32 mDiskRadius; - BOOL mDraw; // FALSE - do not draw. + bool mDraw; // FALSE - do not draw. F32 mHorizonVisibility; // number [0, 1] due to how horizon F32 mVisibility; // same but due to other objects being in throng. - BOOL mVisible; + bool mVisible; static F32 sInterpVal; LLVector3 mQuadCorner[4]; - LLVector3 mU; - LLVector3 mV; LLVector3 mO; public: - LLHeavenBody(const F32 rad) : - mDirectionCached(LLVector3(0,0,0)), - mDirection(LLVector3(0,0,0)), - mIntensity(0.f), - mDiskRadius(rad), mDraw(FALSE), - mHorizonVisibility(1.f), mVisibility(1.f), - mVisible(FALSE) - { - mColor.setToBlack(); - mColorCached.setToBlack(); - } + LLHeavenBody(const F32 rad); ~LLHeavenBody() {} - const LLVector3& getDirection() const { return mDirection; } - void setDirection(const LLVector3 &direction) { mDirection = direction; } - void setAngularVelocity(const LLVector3 &ang_vel) { mAngularVelocity = ang_vel; } - const LLVector3& getAngularVelocity() const { return mAngularVelocity; } - - const LLVector3& getDirectionCached() const { return mDirectionCached; } - void renewDirection() { mDirectionCached = mDirection; } - - const LLColor3& getColorCached() const { return mColorCached; } - void setColorCached(const LLColor3& c) { mColorCached = c; } - const LLColor3& getColor() const { return mColor; } - void setColor(const LLColor3& c) { mColor = c; } - - void renewColor() { mColorCached = mColor; } - - static F32 interpVal() { return sInterpVal; } - static void setInterpVal(const F32 v) { sInterpVal = v; } - - LLColor3 getInterpColor() const - { - return sInterpVal * mColor + (1 - sInterpVal) * mColorCached; - } - - const F32& getHorizonVisibility() const { return mHorizonVisibility; } - void setHorizonVisibility(const F32 c = 1) { mHorizonVisibility = c; } - const F32& getVisibility() const { return mVisibility; } - void setVisibility(const F32 c = 1) { mVisibility = c; } - F32 getHaloBrighness() const - { - return llmax(0.f, llmin(0.9f, mHorizonVisibility)) * mVisibility; - } - BOOL isVisible() const { return mVisible; } - void setVisible(const BOOL v) { mVisible = v; } - - const F32& getIntensity() const { return mIntensity; } - void setIntensity(const F32 c) { mIntensity = c; } - - void setDiskRadius(const F32 radius) { mDiskRadius = radius; } - F32 getDiskRadius() const { return mDiskRadius; } - - void setDraw(const BOOL draw) { mDraw = draw; } - BOOL getDraw() const { return mDraw; } + const LLQuaternion& getRotation() const; + void setRotation(const LLQuaternion& rot); - const LLVector3& corner(const S32 n) const { return mQuadCorner[n]; } - LLVector3& corner(const S32 n) { return mQuadCorner[n]; } - const LLVector3* corners() const { return mQuadCorner; } - - const LLVector3& getU() const { return mU; } - const LLVector3& getV() const { return mV; } - void setU(const LLVector3& u) { mU = u; } - void setV(const LLVector3& v) { mV = v; } -}; + const LLVector3& getDirection() const; + void setDirection(const LLVector3 &direction); + void setAngularVelocity(const LLVector3 &ang_vel); + const LLVector3& getAngularVelocity() const; + const LLVector3& getDirectionCached() const; + void renewDirection(); -LL_FORCE_INLINE LLColor3 refr_ind_calc(const LLColor3 &wave_length) -{ - LLColor3 refr_ind; - for (S32 i = 0; i < 3; ++i) - { - const F32 wl2 = wave_length.mV[i] * wave_length.mV[i] * 1e-6f; - refr_ind.mV[i] = 6.43e3f + ( 2.95e6f / ( 146.0f - 1.f/wl2 ) ) + ( 2.55e4f / ( 41.0f - 1.f/wl2 ) ); - refr_ind.mV[i] *= 1.0e-8f; - refr_ind.mV[i] += 1.f; - } - return refr_ind; -} - - -class LLHaze -{ -public: - LLHaze() : mG(0), mFalloff(1), mAbsCoef(0.f) {mSigSca.setToBlack();} - LLHaze(const F32 g, const LLColor3& sca, const F32 fo = 2.f) : - mG(g), mSigSca(0.25f/F_PI * sca), mFalloff(fo), mAbsCoef(0.f) - { - mAbsCoef = color_intens(mSigSca) / sAirScaIntense; - } - - LLHaze(const F32 g, const F32 sca, const F32 fo = 2.f) : mG(g), - mSigSca(0.25f/F_PI * LLColor3(sca, sca, sca)), mFalloff(fo) - { - mAbsCoef = 0.01f * sca / sAirScaAvg; - } - - F32 getG() const { return mG; } + const LLColor3& getColorCached() const; + void setColorCached(const LLColor3& c); + const LLColor3& getColor() const; + void setColor(const LLColor3& c); - void setG(const F32 g) - { - mG = g; - } + void renewColor(); - const LLColor3& getSigSca() const // sea level - { - return mSigSca; - } + static F32 interpVal(); + static void setInterpVal(const F32 v); - void setSigSca(const LLColor3& s) - { - mSigSca = s; - mAbsCoef = 0.01f * color_intens(mSigSca) / sAirScaIntense; - } + LLColor3 getInterpColor() const; - void setSigSca(const F32 s0, const F32 s1, const F32 s2) - { - mSigSca = sAirScaAvg * LLColor3 (s0, s1, s2); - mAbsCoef = 0.01f * (s0 + s1 + s2) / 3; - } + const F32& getVisibility() const; + void setVisibility(const F32 c = 1); - F32 getFalloff() const - { - return mFalloff; - } + bool isVisible() const; + void setVisible(const bool v); - void setFalloff(const F32 fo) - { - mFalloff = fo; - } + const F32& getIntensity() const; + void setIntensity(const F32 c); - F32 getAbsCoef() const - { - return mAbsCoef; - } + void setDiskRadius(const F32 radius); + F32 getDiskRadius() const; - inline static F32 calcFalloff(const F32 h) - { - return (h <= 0) ? 1.0f : (F32)LL_FAST_EXP(-ATM_EXP_FALLOFF * h); - } + void setDraw(const bool draw); + bool getDraw() const; - inline LLColor3 calcSigSca(const F32 h) const - { - return calcFalloff(h * mFalloff) * mSigSca; - } - - inline void calcSigSca(const F32 h, LLColor3 &result) const - { - result = mSigSca; - result *= calcFalloff(h * mFalloff); - } - - LLColor3 calcSigExt(const F32 h) const - { - return calcFalloff(h * mFalloff) * (1 + mAbsCoef) * mSigSca; - } - - F32 calcPhase(const F32 cos_theta) const; - - static inline LLColor3 calcAirSca(const F32 h); - static inline void calcAirSca(const F32 h, LLColor3 &result); - -private: - static LLColor3 const sAirScaSeaLevel; - static F32 const sAirScaIntense; - static F32 const sAirScaAvg; - -protected: - F32 mG; - LLColor3 mSigSca; - F32 mFalloff; // 1 - slow, >1 - faster - F32 mAbsCoef; + const LLVector3& corner(const S32 n) const; + LLVector3& corner(const S32 n); + const LLVector3* corners() const; }; - class LLCubeMap; -// turn on floating point precision -// in vs2003 for this class. Otherwise -// black dots go everywhere from 7:10 - 8:50 -#if LL_MSVC && __MSVC_VER__ < 8 -#pragma optimize("p", on) -#endif - - class LLVOSky : public LLStaticViewerObject { -public: - /// WL PARAMS - F32 dome_radius; - F32 dome_offset_ratio; - LLColor3 sunlight_color; - LLColor3 ambient; - F32 gamma; - LLVector4 lightnorm; - LLVector4 unclamped_lightnorm; - LLColor3 blue_density; - LLColor3 blue_horizon; - F32 haze_density; - F32 haze_horizon; - F32 density_multiplier; - F32 max_y; - LLColor3 glow; - F32 cloud_shadow; - LLColor3 cloud_color; - F32 cloud_scale; - LLColor3 cloud_pos_density1; - LLColor3 cloud_pos_density2; - -public: - void initAtmospherics(void); - void calcAtmospherics(void); - LLColor3 createDiffuseFromWL(LLColor3 diffuse, LLColor3 ambient, LLColor3 sundiffuse, LLColor3 sunambient); - LLColor3 createAmbientFromWL(LLColor3 ambient, LLColor3 sundiffuse, LLColor3 sunambient); - - void calcSkyColorWLVert(LLVector3 & Pn, LLColor3 & vary_HazeColor, LLColor3 & vary_CloudColorSun, - LLColor3 & vary_CloudColorAmbient, F32 & vary_CloudDensity, - LLVector2 vary_HorizontalProjection[2]); - - LLColor3 calcSkyColorWLFrag(LLVector3 & Pn, LLColor3 & vary_HazeColor, LLColor3 & vary_CloudColorSun, - LLColor3 & vary_CloudColorAmbient, F32 & vary_CloudDensity, - LLVector2 vary_HorizontalProjection[2]); - -public: +public: enum { FACE_SIDE0, @@ -447,7 +206,6 @@ public: FACE_MOON, // was 7 FACE_BLOOM, // was 8 FACE_REFLECTION, // was 10 - FACE_DUMMY, //for an ATI bug --bao FACE_COUNT }; @@ -461,8 +219,10 @@ public: void cleanupGL(); void restoreGL(); + void calc(); + /*virtual*/ void idleUpdate(LLAgent &agent, const F64 &time); - BOOL updateSky(); + bool updateSky(); // Graphical stuff for objects - maybe broken out into render class // later? @@ -470,65 +230,31 @@ public: /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); - void initSkyTextureDirs(const S32 side, const S32 tile); - void createSkyTexture(const S32 side, const S32 tile); - - LLColor4 calcSkyColorInDir(const LLVector3& dir, bool isShiny = false); - - LLColor3 calcRadianceAtPoint(const LLVector3& pos) const - { - F32 radiance = mBrightnessScaleGuess * mSun.getIntensity(); - return LLColor3(radiance, radiance, radiance); - } - - const LLHeavenBody& getSun() const { return mSun; } + const LLHeavenBody& getSun() const { return mSun; } const LLHeavenBody& getMoon() const { return mMoon; } - const LLVector3& getToSunLast() const { return mSun.getDirectionCached(); } - const LLVector3& getToSun() const { return mSun.getDirection(); } - const LLVector3& getToMoon() const { return mMoon.getDirection(); } - const LLVector3& getToMoonLast() const { return mMoon.getDirectionCached(); } - BOOL isSunUp() const { return mSun.getDirectionCached().mV[2] > -0.05f; } - void calculateColors(); - - LLColor3 getSunDiffuseColor() const { return mSunDiffuse; } - LLColor3 getMoonDiffuseColor() const { return mMoonDiffuse; } - LLColor4 getSunAmbientColor() const { return mSunAmbient; } - LLColor4 getMoonAmbientColor() const { return mMoonAmbient; } - const LLColor4& getTotalAmbientColor() const { return mTotalAmbient; } - LLColor4 getFogColor() const { return mFogColor; } - LLColor4 getGLFogColor() const { return mGLFogCol; } - - BOOL isSameFace(S32 idx, const LLFace* face) const { return mFace[idx] == face; } - - void initSunDirection(const LLVector3 &sun_dir, const LLVector3 &sun_ang_velocity); - - void setSunDirection(const LLVector3 &sun_dir, const LLVector3 &sun_ang_velocity); + bool isSameFace(S32 idx, const LLFace* face) const { return mFace[idx] == face; } - BOOL updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 side, const BOOL is_sun, - LLHeavenBody& hb, const F32 sin_max_angle, - const LLVector3 &up, const LLVector3 &right); + // directions provided should already be in CFR coord sys (+x at, +z up, +y right) + void setSunAndMoonDirectionsCFR(const LLVector3 &sun_dir, const LLVector3 &moon_dir); + void setSunDirectionCFR(const LLVector3 &sun_direction); + void setMoonDirectionCFR(const LLVector3 &moon_direction); - F32 cosHorizon(const F32 delta = 0) const - { - const F32 sin_angle = EARTH_RADIUS/(EARTH_RADIUS + mCameraPosAgent.mV[2]); - return delta - (F32)sqrt(1.f - sin_angle * sin_angle); - } - - void updateSunHaloGeometry(LLDrawable *drawable); + bool updateHeavenlyBodyGeometry(LLDrawable *drawable, F32 scale, const S32 side, LLHeavenBody& hb, const LLVector3 &up, const LLVector3 &right); void updateReflectionGeometry(LLDrawable *drawable, F32 H, const LLHeavenBody& HB); - - const LLHaze& getHaze() const { return mHaze; } - LLHaze& getHaze() { return mHaze; } - F32 getHazeConcentration() const { return mHazeConcentration; } - void setHaze(const LLHaze& h) { mHaze = h; } F32 getWorldScale() const { return mWorldScale; } void setWorldScale(const F32 s) { mWorldScale = s; } void updateFog(const F32 distance); - void setFogRatio(const F32 fog_ratio) { mFogRatio = fog_ratio; } - LLColor4U getFadeColor() const { return mFadeColor; } - F32 getFogRatio() const { return mFogRatio; } + + void setFogRatio(const F32 fog_ratio) { m_legacyAtmospherics.setFogRatio(fog_ratio); } + F32 getFogRatio() const { return m_legacyAtmospherics.getFogRatio(); } + + LLColor4 getSkyFogColor() const { return m_legacyAtmospherics.getFogColor(); } + LLColor4 getGLFogColor() const { return m_legacyAtmospherics.getGLFogColor(); } + + LLColor4U getFadeColor() const; + void setCloudDensity(F32 cloud_density) { mCloudDensity = cloud_density; } void setWind ( const LLVector3& wind ) { mWind = wind.length(); } @@ -538,24 +264,55 @@ public: LLCubeMap *getCubeMap() const { return mCubeMap; } S32 getDrawRefl() const { return mDrawRefl; } void setDrawRefl(const S32 r) { mDrawRefl = r; } - BOOL isReflFace(const LLFace* face) const { return face == mFace[FACE_REFLECTION]; } + bool isReflFace(const LLFace* face) const { return face == mFace[FACE_REFLECTION]; } LLFace* getReflFace() const { return mFace[FACE_REFLECTION]; } - LLViewerTexture* getSunTex() const { return mSunTexturep; } - LLViewerTexture* getMoonTex() const { return mMoonTexturep; } - LLViewerTexture* getBloomTex() const { return mBloomTexturep; } - void forceSkyUpdate(void) { mForceUpdate = TRUE; } + LLViewerTexture* getSunTex() const { return mSunTexturep[0]; } + LLViewerTexture* getMoonTex() const { return mMoonTexturep[0]; } + LLViewerTexture* getBloomTex() const { return mBloomTexturep[0]; } + LLViewerTexture* getCloudNoiseTex() const { return mCloudNoiseTexturep[0]; } + + LLViewerTexture* getRainbowTex() const { return mRainbowMap; } + LLViewerTexture* getHaloTex() const { return mHaloMap; } + + LLViewerTexture* getSunTexNext() const { return mSunTexturep[1]; } + LLViewerTexture* getMoonTexNext() const { return mMoonTexturep[1]; } + LLViewerTexture* getBloomTexNext() const { return mBloomTexturep[1]; } + LLViewerTexture* getCloudNoiseTexNext() const { return mCloudNoiseTexturep[1]; } + + void setSunTextures(const LLUUID& sun_texture, const LLUUID& sun_texture_next); + void setMoonTextures(const LLUUID& moon_texture, const LLUUID& moon_texture_next); + void setCloudNoiseTextures(const LLUUID& cloud_noise_texture, const LLUUID& cloud_noise_texture_next); + void setBloomTextures(const LLUUID& bloom_texture, const LLUUID& bloom_texture_next); + + void setSunScale(F32 sun_scale); + void setMoonScale(F32 sun_scale); + + void forceSkyUpdate(void); public: LLFace *mFace[FACE_COUNT]; LLVector3 mBumpSunDir; + F32 getInterpVal() const { return mInterpVal; } + protected: ~LLVOSky(); - LLPointer<LLViewerFetchedTexture> mSunTexturep; - LLPointer<LLViewerFetchedTexture> mMoonTexturep; - LLPointer<LLViewerFetchedTexture> mBloomTexturep; + void updateDirections(void); + + void initSkyTextureDirs(const S32 side, const S32 tile); + void createSkyTexture(AtmosphericsVars& vars, const S32 side, const S32 tile); + + LLPointer<LLViewerFetchedTexture> mSunTexturep[2]; + LLPointer<LLViewerFetchedTexture> mMoonTexturep[2]; + LLPointer<LLViewerFetchedTexture> mCloudNoiseTexturep[2]; + LLPointer<LLViewerFetchedTexture> mBloomTexturep[2]; + LLPointer<LLViewerFetchedTexture> mRainbowMap; + LLPointer<LLViewerFetchedTexture> mHaloMap; + + F32 mSunScale = 1.0f; + F32 mMoonScale = 1.0f; static S32 sResolution; static S32 sTileResX; @@ -575,73 +332,30 @@ protected: LLColor3 mBrightestPointNew; F32 mBrightnessScaleGuess; LLColor3 mBrightestPointGuess; - LLHaze mHaze; - F32 mHazeConcentration; - BOOL mWeatherChange; + bool mWeatherChange; F32 mCloudDensity; F32 mWind; - BOOL mInitialized; - BOOL mForceUpdate; //flag to force instantaneous update of cubemap - LLVector3 mLastLightingDirection; - LLColor3 mLastTotalAmbient; + bool mInitialized; + bool mForceUpdate; + bool mNeedUpdate; // flag to force update of cubemap + S32 mCubeMapUpdateStage; // state of cubemap uodate: -1 idle; 0-5 per-face updates; 6 finalizing + F32 mAmbientScale; LLColor3 mNightColorShift; F32 mInterpVal; - - LLColor4 mFogColor; - LLColor4 mGLFogCol; - - F32 mFogRatio; F32 mWorldScale; - LLColor4 mSunAmbient; - LLColor4 mMoonAmbient; - LLColor4 mTotalAmbient; - LLColor3 mSunDiffuse; - LLColor3 mMoonDiffuse; - LLColor4U mFadeColor; // Color to fade in from - - LLPointer<LLCubeMap> mCubeMap; // Cube map for the environment - S32 mDrawRefl; + LLPointer<LLCubeMap> mCubeMap; // Cube map for the environment + S32 mDrawRefl; LLFrameTimer mUpdateTimer; + LLTimer mForceUpdateThrottle; + bool mHeavenlyBodyUpdated ; -public: - //by bao - //fake vertex buffer updating - //to guarantee at least updating one VBO buffer every frame - //to work around the bug caused by ATI card --> DEV-3855 - // - void createDummyVertexBuffer() ; - void updateDummyVertexBuffer() ; - - BOOL mHeavenlyBodyUpdated ; + AtmosphericsVars m_atmosphericsVars; + AtmosphericsVars m_lastAtmosphericsVars; + LLAtmospherics m_legacyAtmospherics; }; -// turn it off -#if LL_MSVC && __MSVC_VER__ < 8 -#pragma optimize("p", off) -#endif - -// Utility functions -F32 azimuth(const LLVector3 &v); -F32 color_norm_pow(LLColor3& col, F32 e, BOOL postmultiply = FALSE); - - -/* Proportion of light that is scattered into 'path' from 'in' over distance dt. */ -/* assumes that vectors 'path' and 'in' are normalized. Scattering coef / 2pi */ - -inline LLColor3 LLHaze::calcAirSca(const F32 h) -{ - return calcFalloff(h) * sAirScaSeaLevel; -} - -inline void LLHaze::calcAirSca(const F32 h, LLColor3 &result) -{ - result = sAirScaSeaLevel; - result *= calcFalloff(h); -} - - #endif diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 369ddebe2d..41099cb570 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -45,6 +45,8 @@ #include "llviewertexturelist.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" +#include "llvolumemgr.h" +#include "llvovolume.h" #include "llworld.h" #include "noise.h" #include "pipeline.h" @@ -85,6 +87,9 @@ LLVOTree::LLVOTree(const LLUUID &id, const LLPCode pcode, LLViewerRegion *region mFrameCount = 0; mWind = mRegionp->mWind.getVelocity(getPositionRegion()); mTrunkLOD = 0; + + // if assert triggers, idleUpdate() needs to be revised and adjusted to new LOD levels + llassert(sMAX_NUM_TREE_LOD_LEVELS == LLVolumeLODGroup::NUM_LODS); } @@ -347,8 +352,11 @@ void LLVOTree::idleUpdate(LLAgent &agent, const F64 &time) return; } - S32 trunk_LOD = sMAX_NUM_TREE_LOD_LEVELS ; + S32 trunk_LOD = sMAX_NUM_TREE_LOD_LEVELS ; // disabled F32 app_angle = getAppAngle()*LLVOTree::sTreeFactor; + F32 distance = mDrawable->mDistanceWRTCamera * LLVOVolume::sDistanceFactor * (F_PI / 3.f); + F32 diameter = getScale().length(); // trees have very broken scale, but length rougtly outlines proper diameter + F32 sz = mBillboardScale * mBillboardRatio * diameter; for (S32 j = 0; j < sMAX_NUM_TREE_LOD_LEVELS; j++) { @@ -357,7 +365,14 @@ void LLVOTree::idleUpdate(LLAgent &agent, const F64 &time) trunk_LOD = j; break; } - } + } + + F32 tan_angle = (LLVOTree::sTreeFactor * 64 * sz) / distance; + S32 cur_detail = LLVolumeLODGroup::getDetailFromTan(ll_round(tan_angle, 0.01f)); // larger value, better quality + + // for trunk_LOD lower value means better quality, but both trunk_LOD and cur_detail have 4 levels + trunk_LOD = llmax(trunk_LOD, LLVolumeLODGroup::NUM_LODS - cur_detail - 1); + trunk_LOD = llmin(trunk_LOD, sMAX_NUM_TREE_LOD_LEVELS); if (mReferenceBuffer.isNull()) { @@ -408,8 +423,9 @@ void LLVOTree::setPixelAreaAndAngle(LLAgent &agent) LLVector3 lookAt = center - viewer_pos_agent; F32 dist = lookAt.normVec() ; F32 cos_angle_to_view_dir = lookAt * LLViewerCamera::getInstance()->getXAxis() ; - - F32 range = dist - getMinScale()/2; + F32 radius = getScale().length()*0.5f; + F32 range = dist - radius; + if (range < F_ALMOST_ZERO || isHUDAttachment()) // range == zero { mAppAngle = 180.f; @@ -536,12 +552,14 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) LLStrider<LLVector3> vertices; LLStrider<LLVector3> normals; + LLStrider<LLColor4U> colors; LLStrider<LLVector2> tex_coords; LLStrider<U16> indicesp; mReferenceBuffer->getVertexStrider(vertices); mReferenceBuffer->getNormalStrider(normals); mReferenceBuffer->getTexCoord0Strider(tex_coords); + mReferenceBuffer->getColorStrider(colors); mReferenceBuffer->getIndexStrider(indicesp); S32 vertex_count = 0; @@ -551,24 +569,27 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) *(normals++) = LLVector3(-SRR2, -SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f); + *(colors++) = LLColor4U::white; vertex_count++; *(normals++) = LLVector3(SRR3, -SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f); + *(colors++) = LLColor4U::white; vertex_count++; *(normals++) = LLVector3(-SRR3, -SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f); + *(colors++) = LLColor4U::white; vertex_count++; *(normals++) = LLVector3(SRR2, -SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f); + *(colors++) = LLColor4U::white; vertex_count++; - - + *(indicesp++) = 0; index_count++; *(indicesp++) = 1; @@ -587,21 +608,25 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) *(normals++) = LLVector3(-SRR2, SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f); + *(colors++) = LLColor4U::white; vertex_count++; *(normals++) = LLVector3(SRR3, SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f); + *(colors++) = LLColor4U::white; vertex_count++; *(normals++) = LLVector3(-SRR3, SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f); + *(colors++) = LLColor4U::white; vertex_count++; *(normals++) = LLVector3(SRR2, SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f); + *(colors++) = LLColor4U::white; vertex_count++; *(indicesp++) = 4; @@ -623,21 +648,25 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) *(normals++) = LLVector3(SRR2, -SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f); + *(colors++) = LLColor4U::white; vertex_count++; *(normals++) = LLVector3(SRR3, SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f); + *(colors++) = LLColor4U::white; vertex_count++; *(normals++) = LLVector3(SRR3, -SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f); + *(colors++) = LLColor4U::white; vertex_count++; *(normals++) = LLVector3(SRR2, SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f); + *(colors++) = LLColor4U::white; vertex_count++; *(indicesp++) = 8; @@ -659,21 +688,25 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) *(normals++) = LLVector3(-SRR2, -SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f); + *(colors++) = LLColor4U::white; vertex_count++; *(normals++) = LLVector3(-SRR3, SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f); + *(colors++) = LLColor4U::white; vertex_count++; *(normals++) = LLVector3(-SRR3, -SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f); + *(colors++) = LLColor4U::white; vertex_count++; *(normals++) = LLVector3(-SRR2, SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f); + *(colors++) = LLColor4U::white; vertex_count++; *(indicesp++) = 12; @@ -786,6 +819,7 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) *(vertices++) = LLVector3(x1*radius, y1*radius, z); *(normals++) = LLVector3(x1, y1, 0.f); *(tex_coords++) = tc; + *(colors++) = LLColor4U::white; vertex_count++; } } @@ -910,15 +944,17 @@ void LLVOTree::updateMesh() LLStrider<LLVector3> vertices; LLStrider<LLVector3> normals; LLStrider<LLVector2> tex_coords; + LLStrider<LLColor4U> colors; LLStrider<U16> indices; U16 idx_offset = 0; buff->getVertexStrider(vertices); buff->getNormalStrider(normals); buff->getTexCoord0Strider(tex_coords); + buff->getColorStrider(colors); buff->getIndexStrider(indices); - genBranchPipeline(vertices, normals, tex_coords, indices, idx_offset, scale_mat, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, 1.0, mTwist, droop, mBranches, alpha); + genBranchPipeline(vertices, normals, tex_coords, colors, indices, idx_offset, scale_mat, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, 1.0, mTwist, droop, mBranches, alpha); mReferenceBuffer->flush(); buff->flush(); @@ -927,6 +963,7 @@ void LLVOTree::updateMesh() void LLVOTree::appendMesh(LLStrider<LLVector3>& vertices, LLStrider<LLVector3>& normals, LLStrider<LLVector2>& tex_coords, + LLStrider<LLColor4U>& colors, LLStrider<U16>& indices, U16& cur_idx, LLMatrix4& matrix, @@ -939,11 +976,13 @@ void LLVOTree::appendMesh(LLStrider<LLVector3>& vertices, LLStrider<LLVector3> v; LLStrider<LLVector3> n; LLStrider<LLVector2> t; + LLStrider<LLColor4U> c; LLStrider<U16> idx; mReferenceBuffer->getVertexStrider(v); mReferenceBuffer->getNormalStrider(n); mReferenceBuffer->getTexCoord0Strider(t); + mReferenceBuffer->getColorStrider(c); mReferenceBuffer->getIndexStrider(idx); //copy/transform vertices into mesh - check @@ -955,6 +994,7 @@ void LLVOTree::appendMesh(LLStrider<LLVector3>& vertices, norm.normalize(); *normals++ = norm; *tex_coords++ = t[index]; + *colors++ = c[index]; } //copy offset indices into mesh - check @@ -972,6 +1012,7 @@ void LLVOTree::appendMesh(LLStrider<LLVector3>& vertices, void LLVOTree::genBranchPipeline(LLStrider<LLVector3>& vertices, LLStrider<LLVector3>& normals, LLStrider<LLVector2>& tex_coords, + LLStrider<LLColor4U>& colors, LLStrider<U16>& indices, U16& index_offset, LLMatrix4& matrix, @@ -1013,7 +1054,7 @@ void LLVOTree::genBranchPipeline(LLStrider<LLVector3>& vertices, LLMatrix4 norm_mat = LLMatrix4(norm.inverse().transpose().m); norm_mat.invert(); - appendMesh(vertices, normals, tex_coords, indices, index_offset, scale_mat, norm_mat, + appendMesh(vertices, normals, tex_coords, colors, indices, index_offset, scale_mat, norm_mat, sLODVertexOffset[trunk_LOD], sLODVertexCount[trunk_LOD], sLODIndexCount[trunk_LOD], sLODIndexOffset[trunk_LOD]); } @@ -1032,7 +1073,7 @@ void LLVOTree::genBranchPipeline(LLStrider<LLVector3>& vertices, LLMatrix4 rot_mat(rot); rot_mat *= trans_mat; - genBranchPipeline(vertices, normals, tex_coords, indices, index_offset, rot_mat, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha); + genBranchPipeline(vertices, normals, tex_coords, colors, 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) @@ -1043,7 +1084,7 @@ void LLVOTree::genBranchPipeline(LLStrider<LLVector3>& vertices, LLMatrix4 rot_mat(70.5f*DEG_TO_RAD, LLVector4(0,0,1)); rot_mat *= trans_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); + genBranchPipeline(vertices, normals, tex_coords, colors, indices, index_offset, rot_mat, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha); } } else @@ -1062,7 +1103,7 @@ void LLVOTree::genBranchPipeline(LLStrider<LLVector3>& vertices, glh::matrix4f norm((F32*) scale_mat.mMatrix); LLMatrix4 norm_mat = LLMatrix4(norm.inverse().transpose().m); - appendMesh(vertices, normals, tex_coords, indices, index_offset, scale_mat, norm_mat, 0, LEAF_VERTICES, LEAF_INDICES, 0); + appendMesh(vertices, normals, tex_coords, colors, indices, index_offset, scale_mat, norm_mat, 0, LEAF_VERTICES, LEAF_INDICES, 0); } } } diff --git a/indra/newview/llvotree.h b/indra/newview/llvotree.h index c16ed70bb4..93c22d2da3 100644 --- a/indra/newview/llvotree.h +++ b/indra/newview/llvotree.h @@ -79,7 +79,8 @@ public: void appendMesh(LLStrider<LLVector3>& vertices, LLStrider<LLVector3>& normals, - LLStrider<LLVector2>& tex_coords, + LLStrider<LLVector2>& tex_coords, + LLStrider<LLColor4U>& colors, LLStrider<U16>& indices, U16& idx_offset, LLMatrix4& matrix, @@ -92,6 +93,7 @@ public: void genBranchPipeline(LLStrider<LLVector3>& vertices, LLStrider<LLVector3>& normals, LLStrider<LLVector2>& tex_coords, + LLStrider<LLColor4U>& colors, LLStrider<U16>& indices, U16& index_offset, LLMatrix4& matrix, diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 33a9c771ea..f063800587 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -189,7 +189,7 @@ public: virtual bool isInterestingEnough() const { - return LLViewerMedia::isInterestingEnough(mObject, getMediaInterest()); + return LLViewerMedia::getInstance()->isInterestingEnough(mObject, getMediaInterest()); } virtual std::string getCapabilityUrl(const std::string &name) const @@ -235,7 +235,8 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re mLastFetchedMediaVersion = -1; memset(&mIndexInTex, 0, sizeof(S32) * LLRender::NUM_VOLUME_TEXTURE_CHANNELS); mMDCImplCount = 0; - mLastRiggingInfoLOD = -1; + mLastRiggingInfoLOD = -1; + mResetDebugText = false; } LLVOVolume::~LLVOVolume() @@ -261,7 +262,10 @@ void LLVOVolume::markDead() { if (!mDead) { - LLSculptIDSize::instance().rem(getVolume()->getParams().getSculptID()); + if (getVolume()) + { + LLSculptIDSize::instance().rem(getVolume()->getParams().getSculptID()); + } if(getMDCImplCount() > 0) { @@ -691,6 +695,11 @@ void LLVOVolume::updateTextureVirtualSize(bool forced) LL_RECORD_BLOCK_TIME(FTM_VOLUME_TEXTURES); // Update the pixel area of all faces + if (mDrawable.isNull()) + { + return; + } + if(!forced) { if(!isVisible()) @@ -1388,6 +1397,15 @@ BOOL LLVOVolume::calcLOD() { std::string debug_object_text = get_debug_object_lod_text(this); setDebugText(debug_object_text); + mResetDebugText = true; + } + } + else + { + if (mResetDebugText) + { + restoreHudText(); + mResetDebugText = false; } } @@ -2063,7 +2081,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() ; + U8 end = (U8)(mMediaImplList.size()) ; for(U8 i = num_tes; i < end ; i++) { removeMediaImpl(i) ; @@ -2705,7 +2723,7 @@ void LLVOVolume::syncMediaData(S32 texture_index, const LLSD &media_data, bool m LLUUID updating_agent = LLTextureEntry::getAgentIDFromMediaVersionString(getMediaURL()); update_from_self = (updating_agent == gAgent.getID()); } - viewer_media_t media_impl = LLViewerMedia::updateMediaImpl(mep, previous_url, update_from_self); + viewer_media_t media_impl = LLViewerMedia::getInstance()->updateMediaImpl(mep, previous_url, update_from_self); addMediaImpl(media_impl, texture_index) ; } @@ -3147,14 +3165,19 @@ void LLVOVolume::setIsLight(BOOL is_light) } } -void LLVOVolume::setLightColor(const LLColor3& color) +void LLVOVolume::setLightSRGBColor(const LLColor3& color) +{ + setLightLinearColor(linearColor3(color)); +} + +void LLVOVolume::setLightLinearColor(const LLColor3& color) { LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); if (param_block) { - if (param_block->getColor() != color) + if (param_block->getLinearColor() != color) { - param_block->setColor(LLColor4(color, param_block->getColor().mV[3])); + param_block->setLinearColor(LLColor4(color, param_block->getLinearColor().mV[3])); parameterChanged(LLNetworkData::PARAMS_LIGHT, true); gPipeline.markTextured(mDrawable); mFaceMappingChanged = TRUE; @@ -3167,9 +3190,9 @@ void LLVOVolume::setLightIntensity(F32 intensity) LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); if (param_block) { - if (param_block->getColor().mV[3] != intensity) + if (param_block->getLinearColor().mV[3] != intensity) { - param_block->setColor(LLColor4(LLColor3(param_block->getColor()), intensity)); + param_block->setLinearColor(LLColor4(LLColor3(param_block->getLinearColor()), intensity)); parameterChanged(LLNetworkData::PARAMS_LIGHT, true); } } @@ -3221,25 +3244,17 @@ BOOL LLVOVolume::getIsLight() const return getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT); } -LLColor3 LLVOVolume::getLightBaseColor() const +LLColor3 LLVOVolume::getLightSRGBBaseColor() const { - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); - if (param_block) - { - return LLColor3(param_block->getColor()); - } - else - { - return LLColor3(1,1,1); - } + return srgbColor3(getLightLinearBaseColor()); } -LLColor3 LLVOVolume::getLightColor() const +LLColor3 LLVOVolume::getLightLinearBaseColor() const { const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); if (param_block) { - return LLColor3(param_block->getColor()) * param_block->getColor().mV[3]; + return LLColor3(param_block->getLinearColor()); } else { @@ -3247,6 +3262,26 @@ LLColor3 LLVOVolume::getLightColor() const } } +LLColor3 LLVOVolume::getLightLinearColor() const +{ + const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + if (param_block) + { + return LLColor3(param_block->getLinearColor()) * param_block->getLinearColor().mV[3]; + } + else + { + return LLColor3(1, 1, 1); + } +} + +LLColor3 LLVOVolume::getLightSRGBColor() const +{ + LLColor3 ret = getLightLinearColor(); + ret = srgbColor3(ret); + return ret; +} + LLUUID LLVOVolume::getLightTextureID() const { if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) @@ -3283,18 +3318,16 @@ F32 LLVOVolume::getSpotLightPriority() const void LLVOVolume::updateSpotLightPriority() { + F32 r = getLightRadius(); LLVector3 pos = mDrawable->getPositionAgent(); + LLVector3 at(0,0,-1); at *= getRenderRotation(); - - F32 r = getLightRadius()*0.5f; - pos += at * r; at = LLViewerCamera::getInstance()->getAtAxis(); - pos -= at * r; - + mSpotLightPriority = gPipeline.calcPixelArea(pos, LLVector3(r,r,r), *LLViewerCamera::getInstance()); if (mLightTexture.notNull()) @@ -3340,7 +3373,7 @@ F32 LLVOVolume::getLightIntensity() const const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); if (param_block) { - return param_block->getColor().mV[3]; + return param_block->getLinearColor().mV[3]; } else { @@ -3361,12 +3394,12 @@ F32 LLVOVolume::getLightRadius() const } } -F32 LLVOVolume::getLightFalloff() const +F32 LLVOVolume::getLightFalloff(const F32 fudge_factor) const { const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); if (param_block) { - return param_block->getFalloff(); + return param_block->getFalloff() * fudge_factor; } else { @@ -3954,7 +3987,25 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const { if (textures.find(img->getID()) == textures.end()) { - S32 texture_cost = 256 + (S32)(ARC_TEXTURE_COST * (img->getFullHeight() / 128.f + img->getFullWidth() / 128.f)); + S32 texture_cost = 0; + S8 type = img->getType(); + if (type == LLViewerTexture::FETCHED_TEXTURE || type == LLViewerTexture::LOD_TEXTURE) + { + const LLViewerFetchedTexture* fetched_texturep = static_cast<const LLViewerFetchedTexture*>(img); + if (fetched_texturep + && fetched_texturep->getFTType() == FTT_LOCAL_FILE + && (img->getID() == IMG_ALPHA_GRAD_2D || img->getID() == IMG_ALPHA_GRAD) + ) + { + // These two textures appear to switch between each other, but are of different sizes (4x256 and 256x256). + // Hardcode cost from larger one to not cause random complexity changes + texture_cost = 320; + } + } + if (texture_cost == 0) + { + texture_cost = 256 + (S32)(ARC_TEXTURE_COST * (img->getFullHeight() / 128.f + img->getFullWidth() / 128.f)); + } textures.insert(texture_cost_t::value_type(img->getID(), texture_cost)); } } @@ -4567,20 +4618,19 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& { U8 mode = mat->getDiffuseAlphaMode(); - if (mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE || - mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE) + if (mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE + || mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE + || (mode == LLMaterial::DIFFUSE_ALPHA_MODE_MASK && mat->getAlphaMaskCutoff() == 0)) { ignore_alpha = true; } } } + BOOL no_texture = !face->getTexture() || !face->getTexture()->hasGLTexture(); + BOOL mask = no_texture ? FALSE : face->getTexture()->getMask(face->surfaceToTexture(tc, p, n)); if (face && - (ignore_alpha || - pick_transparent || - !face->getTexture() || - !face->getTexture()->hasGLTexture() || - face->getTexture()->getMask(face->surfaceToTexture(tc, p, n)))) + (ignore_alpha || pick_transparent || no_texture || mask)) { local_end = p; if (face_hitp != NULL) @@ -4785,18 +4835,44 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons U32 max_joints = LLSkinningUtil::getMaxJointCount(); rigged_vert_count += dst_face.mNumVertices; rigged_face_count++; - for (U32 j = 0; j < dst_face.mNumVertices; ++j) - { - LLMatrix4a final_mat; - LLSkinningUtil::getPerVertexSkinMatrix(weight[j].getF32ptr(), mat, false, final_mat, max_joints); + + #if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS + if (vol_face.mJointIndices) // fast path with preconditioned joint indices + { + LLMatrix4a src[4]; + U8* joint_indices_cursor = vol_face.mJointIndices; + LLVector4a* just_weights = vol_face.mJustWeights; + for (U32 j = 0; j < dst_face.mNumVertices; ++j) + { + LLMatrix4a final_mat; + F32* w = just_weights[j].getF32ptr(); + LLSkinningUtil::getPerVertexSkinMatrixWithIndices(w, joint_indices_cursor, mat, final_mat, src); + joint_indices_cursor += 4; + + LLVector4a& v = vol_face.mPositions[j]; + LLVector4a t; + LLVector4a dst; + bind_shape_matrix.affineTransform(v, t); + final_mat.affineTransform(t, dst); + pos[j] = dst; + } + } + else + #endif + { + for (U32 j = 0; j < dst_face.mNumVertices; ++j) + { + LLMatrix4a final_mat; + 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; - } + LLVector4a& v = vol_face.mPositions[j]; + LLVector4a t; + LLVector4a dst; + bind_shape_matrix.affineTransform(v, t); + final_mat.affineTransform(t, dst); + pos[j] = dst; + } + } //update bounding box // VFExtents change @@ -4850,6 +4926,14 @@ U32 LLVOVolume::getPartitionType() const { return LLViewerRegion::PARTITION_HUD; } + if (isAnimatedObject() && getControlAvatar()) + { + return LLViewerRegion::PARTITION_CONTROL_AV; + } + if (isAttachment()) + { + return LLViewerRegion::PARTITION_AVATAR; + } return LLViewerRegion::PARTITION_VOLUME; } @@ -4880,6 +4964,20 @@ LLVolumeGeometryManager() mSlopRatio = 0.25f; } +LLAvatarBridge::LLAvatarBridge(LLDrawable* drawablep, LLViewerRegion* regionp) + : LLVolumeBridge(drawablep, regionp) +{ + mDrawableType = LLPipeline::RENDER_TYPE_AVATAR; + mPartitionType = LLViewerRegion::PARTITION_AVATAR; +} + +LLControlAVBridge::LLControlAVBridge(LLDrawable* drawablep, LLViewerRegion* regionp) + : LLVolumeBridge(drawablep, regionp) +{ + mDrawableType = LLPipeline::RENDER_TYPE_CONTROL_AV; + mPartitionType = LLViewerRegion::PARTITION_CONTROL_AV; +} + bool can_batch_texture(LLFace* facep) { if (facep->getTextureEntry()->getBumpmap()) @@ -4977,7 +5075,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, if ( type == LLRenderPass::PASS_ALPHA && facep->getTextureEntry()->getMaterialParams().notNull() && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_TANGENT) - && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1) + && LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1) { LL_WARNS_ONCE("RenderMaterials") << "Oh no! No binormals for this alpha blended face!" << LL_ENDL; } @@ -5058,7 +5156,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, } - if (index < 255 && idx >= 0) + if (index < FACE_DO_NOT_BATCH_TEXTURES && idx >= 0) { if (mat || draw_vec[idx]->mMaterial) { //can't batch textures when materials are present (yet) @@ -5104,7 +5202,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, draw_vec[idx]->mEnd += facep->getGeomCount(); draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize()); - if (index < 255 && index >= draw_vec[idx]->mTextureList.size()) + if (index < FACE_DO_NOT_BATCH_TEXTURES && index >= draw_vec[idx]->mTextureList.size()) { draw_vec[idx]->mTextureList.resize(index+1); draw_vec[idx]->mTextureList[index] = tex; @@ -5191,7 +5289,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, draw_info->mDrawMode = LLRender::TRIANGLE_STRIP; } - if (index < 255) + if (index < FACE_DO_NOT_BATCH_TEXTURES) { //initialize texture list for texture batching draw_info->mTextureList.resize(index+1); draw_info->mTextureList[index] = tex; @@ -5224,7 +5322,8 @@ static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj) LLDrawPool* drawpool = face->getPool(); if (drawpool) { - if (drawpool->getType() == LLDrawPool::POOL_AVATAR) + if (drawpool->getType() == LLDrawPool::POOL_AVATAR + || drawpool->getType() == LLDrawPool::POOL_CONTROL_AV) { return (LLDrawPoolAvatar*) drawpool; } @@ -5369,8 +5468,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) U32 useage = group->getSpatialPartition()->mBufferUsage; - LLCachedControl<S32> max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512); - LLCachedControl<S32> max_node_size(gSavedSettings, "RenderMaxNodeSize", 65536); + static LLCachedControl<S32> max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512); + static LLCachedControl<S32> max_node_size(gSavedSettings, "RenderMaxNodeSize", 65536); U32 max_vertices = (max_vbo_size * 1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); U32 max_total = (max_node_size * 1024) / LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); max_vertices = llmin(max_vertices, (U32) 65535); @@ -5503,7 +5602,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) //remove face from old pool if it exists LLDrawPool* old_pool = facep->getPool(); - if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR) + if (old_pool + && (old_pool->getType() == LLDrawPool::POOL_AVATAR || old_pool->getType() == LLDrawPool::POOL_CONTROL_AV)) { ((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep); } @@ -5512,6 +5612,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) LLViewerTexture* tex = facep->getTexture(); U32 type = gPipeline.getPoolTypeFromTE(te, tex); + F32 te_alpha = te->getColor().mV[3]; if (te->getGlow()) { @@ -5519,6 +5620,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } LLMaterial* mat = te->getMaterialParams().get(); + bool fullbright = te->getFullbright(); if (mat && LLPipeline::sRenderDeferred) { @@ -5526,14 +5628,18 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) bool is_alpha = type == LLDrawPool::POOL_ALPHA && (alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND || - te->getColor().mV[3] < 0.999f); + te_alpha < 0.999f); if (is_alpha) { //this face needs alpha blending, override alpha mode alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND; } - if (!is_alpha || te->getColor().mV[3] > 0.f) // //only add the face if it will actually be visible + if (fullbright && (alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE)) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT); + } + else if (!is_alpha || te_alpha > 0.f) // //only add the face if it will actually be visible { U32 mask = mat->getShaderMask(alpha_mode); pool->addRiggedFace(facep, mask); @@ -5545,8 +5651,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } } else if (mat) - { - bool fullbright = te->getFullbright(); + { bool is_alpha = type == LLDrawPool::POOL_ALPHA; U8 mode = mat->getDiffuseAlphaMode(); bool can_be_shiny = mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE || @@ -5883,7 +5988,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) spec_mask = spec_mask | LLVertexBuffer::MAP_EMISSIVE; } - BOOL batch_textures = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1; + BOOL batch_textures = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1; if (batch_textures) { @@ -6130,7 +6235,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace #endif //calculate maximum number of vertices to store in a single buffer - LLCachedControl<S32> max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512); + static LLCachedControl<S32> max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512); U32 max_vertices = (max_vbo_size * 1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); max_vertices = llmin(max_vertices, (U32) 65535); @@ -6318,7 +6423,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace //face has no texture index facep->mDrawInfo = NULL; - facep->setTextureIndex(255); + facep->setTextureIndex(FACE_DO_NOT_BATCH_TEXTURES); if (geom_count + facep->getGeomCount() > max_vertices) { //cut batches on geom count too big @@ -6382,7 +6487,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace facep->setGeomIndex(index_offset); facep->setVertexBuffer(buffer); - if (batch_textures && facep->getTextureIndex() == 255) + if (batch_textures && facep->getTextureIndex() == FACE_DO_NOT_BATCH_TEXTURES) { LL_ERRS() << "Invalid texture index." << LL_ENDL; } @@ -6451,8 +6556,12 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE; } + F32 te_alpha = te->getColor().mV[3]; bool use_legacy_bump = te->getBumpmap() && (te->getBumpmap() < 18) && (!mat || mat->getNormalID().isNull()); - bool opaque = te->getColor().mV[3] >= 0.999f; + bool opaque = te_alpha >= 0.999f; + bool transparent = te_alpha < 0.999f; + + is_alpha = (is_alpha || transparent) ? TRUE : FALSE; if (mat && LLPipeline::sRenderDeferred && !hud_group) { @@ -6481,14 +6590,20 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace } else { - if (mat->getEnvironmentIntensity() > 0 || - te->getShiny() > 0) + if (mat->getEnvironmentIntensity() > 0 || te->getShiny() > 0) { material_pass = true; } else { - registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT); + if (opaque) + { + registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT); + } + else + { + registerFace(group, facep, LLRenderPass::PASS_ALPHA); + } } } } @@ -6496,7 +6611,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace { registerFace(group, facep, LLRenderPass::PASS_SIMPLE); } - else if (te->getColor().mV[3] < 0.999f) + else if (transparent) { registerFace(group, facep, LLRenderPass::PASS_ALPHA); } @@ -6544,7 +6659,10 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace else if (mat) { U8 mode = mat->getDiffuseAlphaMode(); - if (te->getColor().mV[3] < 0.999f) + + is_alpha = (is_alpha || (mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND)); + + if (is_alpha) { mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND; } @@ -6553,7 +6671,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace { registerFace(group, facep, fullbright ? LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK : LLRenderPass::PASS_ALPHA_MASK); } - else if (is_alpha || (te->getColor().mV[3] < 0.999f)) + else if (is_alpha ) { registerFace(group, facep, LLRenderPass::PASS_ALPHA); } @@ -6669,7 +6787,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace { registerFace(group, facep, LLRenderPass::PASS_SIMPLE); } - } + } } diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 13db9c39b7..ce400a3498 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -242,7 +242,11 @@ public: // For Lights void setIsLight(BOOL is_light); - void setLightColor(const LLColor3& color); + //set the gamma-corrected (sRGB) color of this light + void setLightSRGBColor(const LLColor3& color); + //set the linear color of this light + void setLightLinearColor(const LLColor3& color); + void setLightIntensity(F32 intensity); void setLightRadius(F32 radius); void setLightFalloff(F32 falloff); @@ -251,8 +255,21 @@ public: void setSpotLightParams(LLVector3 params); BOOL getIsLight() const; - LLColor3 getLightBaseColor() const; // not scaled by intensity - LLColor3 getLightColor() const; // scaled by intensity + + + // Get the light color in sRGB color space NOT scaled by intensity. + LLColor3 getLightSRGBBaseColor() const; + + // Get the light color in linear color space NOT scaled by intensity. + LLColor3 getLightLinearBaseColor() const; + + // Get the light color in linear color space scaled by intensity + // this is the value that should be fed into shaders + LLColor3 getLightLinearColor() const; + + // Get the light color in sRGB color space scaled by intensity. + LLColor3 getLightSRGBColor() const; + LLUUID getLightTextureID() const; bool isLightSpotlight() const; LLVector3 getSpotLightParams() const; @@ -262,7 +279,7 @@ public: LLViewerTexture* getLightTexture(); F32 getLightIntensity() const; F32 getLightRadius() const; - F32 getLightFalloff() const; + F32 getLightFalloff(const F32 fudge_factor = 1.f) const; F32 getLightCutoff() const; // Flexible Objects @@ -407,6 +424,8 @@ private: S32 mIndexInTex[LLRender::NUM_VOLUME_TEXTURE_CHANNELS]; S32 mMDCImplCount; + bool mResetDebugText; + LLPointer<LLRiggedVolume> mRiggedVolume; // statics diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index ccda92810e..12def24a0d 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -145,7 +145,7 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable) static const unsigned int vertices_per_quad = 4; static const unsigned int indices_per_quad = 6; - const S32 size = gSavedSettings.getBOOL("RenderTransparentWater") && LLGLSLShader::sNoFixedFunction ? 16 : 1; + const S32 size = LLPipeline::sRenderTransparentWater && LLGLSLShader::sNoFixedFunction ? 16 : 1; const S32 num_quads = size * size; face->setSize(vertices_per_quad * num_quads, diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp index 2cb5fc81b0..d428cb1568 100644 --- a/indra/newview/llvowlsky.cpp +++ b/indra/newview/llvowlsky.cpp @@ -32,14 +32,12 @@ #include "llsky.h" #include "lldrawpoolwlsky.h" #include "llface.h" -#include "llwlparammanager.h" #include "llviewercontrol.h" +#include "llenvironment.h" +#include "llsettingssky.h" -#define DOME_SLICES 1 -const F32 LLVOWLSky::DISTANCE_TO_STARS = (HORIZON_DIST - 10.f)*0.25f; - -const U32 LLVOWLSky::MIN_SKY_DETAIL = 3; -const U32 LLVOWLSky::MAX_SKY_DETAIL = 180; +static const U32 MIN_SKY_DETAIL = 8; +static const U32 MAX_SKY_DETAIL = 180; inline U32 LLVOWLSky::getNumStacks(void) { @@ -51,16 +49,6 @@ inline U32 LLVOWLSky::getNumSlices(void) return 2 * llmin(MAX_SKY_DETAIL, llmax(MIN_SKY_DETAIL, gSavedSettings.getU32("WLSkyDetail"))); } -inline U32 LLVOWLSky::getFanNumVerts(void) -{ - return getNumSlices() + 1; -} - -inline U32 LLVOWLSky::getFanNumIndices(void) -{ - return getNumSlices() * 3; -} - inline U32 LLVOWLSky::getStripsNumVerts(void) { return (getNumStacks() - 1) * getNumSlices(); @@ -87,11 +75,6 @@ LLVOWLSky::LLVOWLSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regi initStars(); } -void LLVOWLSky::initSunDirection(LLVector3 const & sun_direction, - LLVector3 const & sun_angular_velocity) -{ -} - void LLVOWLSky::idleUpdate(LLAgent &agent, const F64 &time) { @@ -116,12 +99,16 @@ LLDrawable * LLVOWLSky::createDrawable(LLPipeline * pipeline) inline F32 LLVOWLSky::calcPhi(U32 i) { + // Calc: PI/8 * 1-((1-t^4)*(1-t^4)) { 0<t<1 } + // Demos: \pi/8*\left(1-((1-x^{4})*(1-x^{4}))\right)\ \left\{0<x\le1\right\} + // i should range from [0..SKY_STACKS] so t will range from [0.f .. 1.f] F32 t = float(i) / float(getNumStacks()); // ^4 the parameter of the tesselation to bias things toward 0 (the dome's apex) - t = t*t*t*t; - + t *= t; + t *= t; + // invert and square the parameter of the tesselation to bias things toward 1 (the horizon) t = 1.f - t; t = t*t; @@ -130,167 +117,20 @@ inline F32 LLVOWLSky::calcPhi(U32 i) return (F_PI / 8.f) * t; } -#if !DOME_SLICES -static const F32 Q = (1.f + sqrtf(5.f))/2.f; //golden ratio - -//icosahedron verts (based on asset b0c7b76e-28c6-1f87-a1de-752d5e3cd264, contact Runitai Linden for a copy) -static const LLVector3 icosahedron_vert[] = -{ - LLVector3(0,1.f,Q), - LLVector3(0,-1.f,Q), - LLVector3(0,-1.f,-Q), - LLVector3(0,1.f,-Q), - - LLVector3(Q,0,1.f), - LLVector3(-Q,0,1.f), - LLVector3(-Q,0,-1.f), - LLVector3(Q,0,-1.f), - - LLVector3(1,-Q,0.f), - LLVector3(-1,-Q,0.f), - LLVector3(-1,Q,0.f), - LLVector3(1,Q,0.f), -}; - -//indices -static const U32 icosahedron_ind[] = -{ - 5,0,1, - 10,0,5, - 5,1,9, - 10,5,6, - 6,5,9, - 11,0,10, - 3,11,10, - 3,10,6, - 3,6,2, - 7,3,2, - 8,7,2, - 4,7,8, - 1,4,8, - 9,8,2, - 9,2,6, - 11,3,7, - 4,0,11, - 4,11,7, - 1,0,4, - 1,8,9, -}; - - -//split every triangle in LLVertexBuffer into even fourths (assumes index triangle lists) -void subdivide(LLVertexBuffer& in, LLVertexBuffer* ret) -{ - S32 tri_in = in.getNumIndices()/3; - - ret->allocateBuffer(tri_in*4*3, tri_in*4*3, TRUE); - - LLStrider<LLVector3> vin, vout; - LLStrider<U16> indin, indout; - - ret->getVertexStrider(vout); - in.getVertexStrider(vin); - - ret->getIndexStrider(indout); - in.getIndexStrider(indin); - - - for (S32 i = 0; i < tri_in; i++) - { - LLVector3 v0 = vin[*indin++]; - LLVector3 v1 = vin[*indin++]; - LLVector3 v2 = vin[*indin++]; - - LLVector3 v3 = (v0 + v1) * 0.5f; - LLVector3 v4 = (v1 + v2) * 0.5f; - LLVector3 v5 = (v2 + v0) * 0.5f; - - *vout++ = v0; - *vout++ = v3; - *vout++ = v5; - - *vout++ = v3; - *vout++ = v4; - *vout++ = v5; - - *vout++ = v3; - *vout++ = v1; - *vout++ = v4; - - *vout++ = v5; - *vout++ = v4; - *vout++ = v2; - } - - for (S32 i = 0; i < ret->getNumIndices(); i++) - { - *indout++ = i; - } - -} - -void chop(LLVertexBuffer& in, LLVertexBuffer* out) -{ - //chop off all triangles below horizon - F32 d = LLWLParamManager::sParamMgr->getDomeOffset() * LLWLParamManager::sParamMgr->getDomeRadius(); - - std::vector<LLVector3> vert; - - LLStrider<LLVector3> vin; - LLStrider<U16> index; - - in.getVertexStrider(vin); - in.getIndexStrider(index); - - U32 tri_count = in.getNumIndices()/3; - for (U32 i = 0; i < tri_count; i++) - { - LLVector3 &v1 = vin[index[i*3+0]]; - LLVector3 &v2 = vin[index[i*3+1]]; - LLVector3 &v3 = vin[index[i*3+2]]; - - if (v1.mV[1] > d || - v2.mV[1] > d || - v3.mV[1] > d) - { - v1.mV[1] = llmax(v1.mV[1], d); - v2.mV[1] = llmax(v1.mV[1], d); - v3.mV[1] = llmax(v1.mV[1], d); - - vert.push_back(v1); - vert.push_back(v2); - vert.push_back(v3); - } - } - - out->allocateBuffer(vert.size(), vert.size(), TRUE); - - LLStrider<LLVector3> vout; - out->getVertexStrider(vout); - out->getIndexStrider(index); - - for (U32 i = 0; i < vert.size(); i++) - { - *vout++ = vert[i]; - *index++ = i; - } -} -#endif // !DOME_SLICES - void LLVOWLSky::resetVertexBuffers() { - mFanVerts = NULL; mStripsVerts.clear(); - mStarsVerts = NULL; + mStarsVerts = nullptr; + mFsSkyVerts = nullptr; gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); } void LLVOWLSky::cleanupGL() { - mFanVerts = NULL; mStripsVerts.clear(); - mStarsVerts = NULL; + mStarsVerts = nullptr; + mFsSkyVerts = nullptr; LLDrawPoolWLSky::cleanupGL(); } @@ -305,38 +145,51 @@ static LLTrace::BlockTimerStatHandle FTM_GEO_SKY("Windlight Sky Geometry"); BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) { - LL_RECORD_BLOCK_TIME(FTM_GEO_SKY); + LL_RECORD_BLOCK_TIME(FTM_GEO_SKY); LLStrider<LLVector3> vertices; LLStrider<LLVector2> texCoords; LLStrider<U16> indices; -#if DOME_SLICES - { - mFanVerts = new LLVertexBuffer(LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); - if (!mFanVerts->allocateBuffer(getFanNumVerts(), getFanNumIndices(), TRUE)) + if (mFsSkyVerts.isNull()) + { + mFsSkyVerts = new LLVertexBuffer(LLDrawPoolWLSky::ADV_ATMO_SKY_VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); + + if (!mFsSkyVerts->allocateBuffer(4, 6, TRUE)) { - LL_WARNS() << "Failed to allocate Vertex Buffer on sky update to " - << getFanNumVerts() << " vertices and " - << getFanNumIndices() << " indices" << LL_ENDL; + LL_WARNS() << "Failed to allocate Vertex Buffer on full screen sky update" << LL_ENDL; } - BOOL success = mFanVerts->getVertexStrider(vertices) - && mFanVerts->getTexCoord0Strider(texCoords) - && mFanVerts->getIndexStrider(indices); + BOOL success = mFsSkyVerts->getVertexStrider(vertices) + && mFsSkyVerts->getTexCoord0Strider(texCoords) + && mFsSkyVerts->getIndexStrider(indices); if(!success) { - LL_ERRS() << "Failed updating WindLight sky geometry." << LL_ENDL; + LL_ERRS() << "Failed updating WindLight fullscreen sky geometry." << LL_ENDL; } - buildFanBuffer(vertices, texCoords, indices); + *vertices++ = LLVector3(-1.0f, -1.0f, 0.0f); + *vertices++ = LLVector3( 1.0f, -1.0f, 0.0f); + *vertices++ = LLVector3(-1.0f, 1.0f, 0.0f); + *vertices++ = LLVector3( 1.0f, 1.0f, 0.0f); - mFanVerts->flush(); - } + *texCoords++ = LLVector2(0.0f, 0.0f); + *texCoords++ = LLVector2(1.0f, 0.0f); + *texCoords++ = LLVector2(0.0f, 1.0f); + *texCoords++ = LLVector2(1.0f, 1.0f); + + *indices++ = 0; + *indices++ = 1; + *indices++ = 2; + *indices++ = 1; + *indices++ = 3; + *indices++ = 2; + + mFsSkyVerts->flush(); + } { - LLCachedControl<S32> max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512); - const U32 max_buffer_bytes = max_vbo_size * 1024; + const U32 max_buffer_bytes = gSavedSettings.getS32("RenderMaxVBOSize")*1024; const U32 data_mask = LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK; const U32 max_verts = max_buffer_bytes / LLVertexBuffer::calcVertexSize(data_mask); @@ -398,8 +251,11 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) LL_ERRS() << "Failed updating WindLight sky geometry." << LL_ENDL; } + U32 vertex_count = 0; + U32 index_count = 0; + // fill it - buildStripsBuffer(begin_stack, end_stack, vertices, texCoords, indices); + buildStripsBuffer(begin_stack, end_stack, vertex_count, index_count, vertices, texCoords, indices); // and unlock the buffer segment->flush(); @@ -407,85 +263,6 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) LL_INFOS() << "completed in " << llformat("%.2f", timer.getElapsedTimeF32().value()) << "seconds" << LL_ENDL; } -#else - mStripsVerts = new LLVertexBuffer(LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); - - const F32 RADIUS = LLWLParamManager::sParamMgr->getDomeRadius(); - - LLPointer<LLVertexBuffer> temp = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0); - temp->allocateBuffer(12, 60, TRUE); - - BOOL success = temp->getVertexStrider(vertices) - && temp->getIndexStrider(indices); - - if (success) - { - for (U32 i = 0; i < 12; i++) - { - *vertices++ = icosahedron_vert[i]; - } - - for (U32 i = 0; i < 60; i++) - { - *indices++ = icosahedron_ind[i]; - } - } - - - LLPointer<LLVertexBuffer> temp2; - - for (U32 i = 0; i < 8; i++) - { - temp2 = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0); - subdivide(*temp, temp2); - temp = temp2; - } - - temp->getVertexStrider(vertices); - for (S32 i = 0; i < temp->getNumVerts(); i++) - { - LLVector3 v = vertices[i]; - v.normVec(); - vertices[i] = v*RADIUS; - } - - temp2 = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0); - chop(*temp, temp2); - - mStripsVerts->allocateBuffer(temp2->getNumVerts(), temp2->getNumIndices(), TRUE); - - success = mStripsVerts->getVertexStrider(vertices) - && mStripsVerts->getTexCoordStrider(texCoords) - && mStripsVerts->getIndexStrider(indices); - - LLStrider<LLVector3> v; - temp2->getVertexStrider(v); - LLStrider<U16> ind; - temp2->getIndexStrider(ind); - - if (success) - { - for (S32 i = 0; i < temp2->getNumVerts(); ++i) - { - LLVector3 vert = *v++; - vert.normVec(); - F32 z0 = vert.mV[2]; - F32 x0 = vert.mV[0]; - - vert *= RADIUS; - - *vertices++ = vert; - *texCoords++ = LLVector2((-z0 + 1.f) / 2.f, (-x0 + 1.f) / 2.f); - } - - for (S32 i = 0; i < temp2->getNumIndices(); ++i) - { - *indices++ = *ind++; - } - } - - mStripsVerts->flush(); -#endif updateStarColors(); updateStarGeometry(drawable); @@ -505,6 +282,21 @@ void LLVOWLSky::drawStars(void) } } +void LLVOWLSky::drawFsSky(void) +{ + if (mFsSkyVerts.isNull()) + { + updateGeometry(mDrawable); + } + + LLGLDisable disable_blend(GL_BLEND); + + mFsSkyVerts->setBuffer(LLDrawPoolWLSky::ADV_ATMO_SKY_VERTEX_DATA_MASK); + mFsSkyVerts->drawRange(LLRender::TRIANGLES, 0, mFsSkyVerts->getNumVerts() - 1, mFsSkyVerts->getNumIndices(), 0); + gPipeline.addTrianglesDrawn(mFsSkyVerts->getNumIndices(), LLRender::TRIANGLES); + LLVertexBuffer::unbind(); +} + void LLVOWLSky::drawDome(void) { if (mStripsVerts.empty()) @@ -516,7 +308,6 @@ void LLVOWLSky::drawDome(void) const U32 data_mask = LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK; -#if DOME_SLICES std::vector< LLPointer<LLVertexBuffer> >::const_iterator strips_vbo_iter, end_strips; end_strips = mStripsVerts.end(); for(strips_vbo_iter = mStripsVerts.begin(); strips_vbo_iter != end_strips; ++strips_vbo_iter) @@ -532,21 +323,13 @@ void LLVOWLSky::drawDome(void) gPipeline.addTrianglesDrawn(strips_segment->getNumIndices(), LLRender::TRIANGLE_STRIP); } -#else - mStripsVerts->setBuffer(data_mask); - gGL.syncMatrices(); - glDrawRangeElements( - GL_TRIANGLES, - 0, mStripsVerts->getNumVerts()-1, mStripsVerts->getNumIndices(), - GL_UNSIGNED_SHORT, - mStripsVerts->getIndicesPointer()); -#endif - LLVertexBuffer::unbind(); } void LLVOWLSky::initStars() { + const F32 DISTANCE_TO_STARS = LLEnvironment::instance().getCurrentSky()->getDomeRadius(); + // Initialize star map mStarVertices.resize(getStarsNumVerts()); mStarColors.resize(getStarsNumVerts()); @@ -581,72 +364,15 @@ void LLVOWLSky::initStars() } } -void LLVOWLSky::buildFanBuffer(LLStrider<LLVector3> & vertices, - LLStrider<LLVector2> & texCoords, - LLStrider<U16> & indices) -{ - const F32 RADIUS = LLWLParamManager::getInstance()->getDomeRadius(); - - U32 i, num_slices; - F32 phi0, theta, x0, y0, z0; - - // paranoia checking for SL-55986/SL-55833 - U32 count_verts = 0; - U32 count_indices = 0; - - // apex - *vertices++ = LLVector3(0.f, RADIUS, 0.f); - *texCoords++ = LLVector2(0.5f, 0.5f); - ++count_verts; - - num_slices = getNumSlices(); - - // and fan in a circle around the apex - phi0 = calcPhi(1); - for(i = 0; i < num_slices; ++i) { - theta = 2.f * F_PI * float(i) / float(num_slices); - - // standard transformation from spherical to - // rectangular coordinates - x0 = sin(phi0) * cos(theta); - y0 = cos(phi0); - z0 = sin(phi0) * sin(theta); - - *vertices++ = LLVector3(x0 * RADIUS, y0 * RADIUS, z0 * RADIUS); - // generate planar uv coordinates - // note: x and z are transposed in order for things to animate - // correctly in the global coordinate system where +x is east and - // +y is north - *texCoords++ = LLVector2((-z0 + 1.f) / 2.f, (-x0 + 1.f) / 2.f); - ++count_verts; - - if (i > 0) - { - *indices++ = 0; - *indices++ = i; - *indices++ = i+1; - count_indices += 3; - } - } - - // the last vertex of the last triangle should wrap around to - // the beginning - *indices++ = 0; - *indices++ = num_slices; - *indices++ = 1; - count_indices += 3; - - // paranoia checking for SL-55986/SL-55833 - llassert(getFanNumVerts() == count_verts); - llassert(getFanNumIndices() == count_indices); -} - -void LLVOWLSky::buildStripsBuffer(U32 begin_stack, U32 end_stack, +void LLVOWLSky::buildStripsBuffer(U32 begin_stack, + U32 end_stack, + U32& vertex_count, + U32& index_count, LLStrider<LLVector3> & vertices, LLStrider<LLVector2> & texCoords, LLStrider<U16> & indices) { - const F32 RADIUS = LLWLParamManager::getInstance()->getDomeRadius(); + const F32 RADIUS = LLEnvironment::instance().getCurrentSky()->getDomeRadius(); U32 i, j, num_slices, num_stacks; F32 phi0, theta, x0, y0, z0; @@ -661,7 +387,11 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack, U32 end_stack, llassert(end_stack <= num_stacks); // stacks are iterated one-indexed since phi(0) was handled by the fan above - for(i = begin_stack + 1; i <= end_stack+1; ++i) +#if NEW_TESS + for(i = begin_stack; i <= end_stack; ++i) +#else + for(i = begin_stack + 1; i <= end_stack+1; ++i) +#endif { phi0 = calcPhi(i); @@ -675,7 +405,10 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack, U32 end_stack, y0 = cos(phi0); z0 = sin(phi0) * sin(theta); - if (i == num_stacks-2) +#if NEW_TESS + *vertices++ = LLVector3(x0 * RADIUS, y0 * RADIUS, z0 * RADIUS); +#else + if (i == num_stacks-2) { *vertices++ = LLVector3(x0*RADIUS, y0*RADIUS-1024.f*2.f, z0*RADIUS); } @@ -687,6 +420,8 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack, U32 end_stack, { *vertices++ = LLVector3(x0 * RADIUS, y0 * RADIUS, z0 * RADIUS); } +#endif + ++count_verts; // generate planar uv coordinates @@ -725,6 +460,9 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack, U32 end_stack, *indices++ = i * num_slices + k ; count_indices++ ; } + + vertex_count = count_verts; + index_count = count_indices; } void LLVOWLSky::updateStarColors() @@ -819,7 +557,7 @@ BOOL LLVOWLSky::updateStarGeometry(LLDrawable *drawable) LLVector3 left = at%LLVector3(0,0,1); LLVector3 up = at%left; - F32 sc = 0.5f+ll_frand()*1.25f; + F32 sc = 16.0f + (ll_frand() * 20.0f); left *= sc; up *= sc; diff --git a/indra/newview/llvowlsky.h b/indra/newview/llvowlsky.h index 1d419b5fea..2b7ebe75dd 100644 --- a/indra/newview/llvowlsky.h +++ b/indra/newview/llvowlsky.h @@ -31,17 +31,8 @@ class LLVOWLSky : public LLStaticViewerObject { private: - static const F32 DISTANCE_TO_STARS; - - // anything less than 3 makes it impossible to create a closed dome. - static const U32 MIN_SKY_DETAIL; - // anything bigger than about 180 will cause getStripsNumVerts() to exceed 65535. - static const U32 MAX_SKY_DETAIL; - inline static U32 getNumStacks(void); inline static U32 getNumSlices(void); - inline static U32 getFanNumVerts(void); - inline static U32 getFanNumIndices(void); inline static U32 getStripsNumVerts(void); inline static U32 getStripsNumIndices(void); inline static U32 getStarsNumVerts(void); @@ -50,9 +41,6 @@ private: public: LLVOWLSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); - void initSunDirection(LLVector3 const & sun_direction, - LLVector3 const & sun_angular_velocity); - /*virtual*/ void idleUpdate(LLAgent &agent, const F64 &time); /*virtual*/ BOOL isActive(void) const; /*virtual*/ LLDrawable * createDrawable(LLPipeline *pipeline); @@ -60,6 +48,7 @@ public: void drawStars(void); void drawDome(void); + void drawFsSky(void); // fullscreen sky for advanced atmo void resetVertexBuffers(void); void cleanupGL(); @@ -72,16 +61,13 @@ private: // helper function for initializing the stars. void initStars(); - // helper function for building the fan vertex buffer. - static void buildFanBuffer(LLStrider<LLVector3> & vertices, - LLStrider<LLVector2> & texCoords, - LLStrider<U16> & indices); - // helper function for building the strips vertex buffer. // note begin_stack and end_stack follow stl iterator conventions, // begin_stack is the first stack to be included, end_stack is the first // stack not to be included. static void buildStripsBuffer(U32 begin_stack, U32 end_stack, + U32& vertex_count, + U32& index_count, LLStrider<LLVector3> & vertices, LLStrider<LLVector2> & texCoords, LLStrider<U16> & indices); @@ -93,7 +79,7 @@ private: BOOL updateStarGeometry(LLDrawable *drawable); private: - LLPointer<LLVertexBuffer> mFanVerts; + LLPointer<LLVertexBuffer> mFsSkyVerts; std::vector< LLPointer<LLVertexBuffer> > mStripsVerts; LLPointer<LLVertexBuffer> mStarsVerts; diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp index dd6c77ca7d..0aa0280b25 100644 --- a/indra/newview/llwatchdog.cpp +++ b/indra/newview/llwatchdog.cpp @@ -31,15 +31,6 @@ const U32 WATCHDOG_SLEEP_TIME_USEC = 1000000; -void default_killer_callback() -{ -#ifdef LL_WINDOWS - RaiseException(0,0,0,0); -#else - raise(SIGQUIT); -#endif -} - // This class runs the watchdog timing thread. class LLWatchdogTimerThread : public LLThread { @@ -91,7 +82,11 @@ void LLWatchdogEntry::start() void LLWatchdogEntry::stop() { - LLWatchdog::getInstance()->remove(this); + // this can happen very late in the shutdown sequence + if (! LLWatchdog::wasDeleted()) + { + LLWatchdog::getInstance()->remove(this); + } } // LLWatchdogTimeout @@ -154,11 +149,10 @@ void LLWatchdogTimeout::ping(const std::string& state) } // LLWatchdog -LLWatchdog::LLWatchdog() : - mSuspectsAccessMutex(), - mTimer(NULL), - mLastClockCount(0), - mKillerCallback(&default_killer_callback) +LLWatchdog::LLWatchdog() + :mSuspectsAccessMutex() + ,mTimer(NULL) + ,mLastClockCount(0) { } @@ -180,9 +174,8 @@ void LLWatchdog::remove(LLWatchdogEntry* e) unlockThread(); } -void LLWatchdog::init(killer_event_callback func) +void LLWatchdog::init() { - mKillerCallback = func; if(!mSuspectsAccessMutex && !mTimer) { mSuspectsAccessMutex = new LLMutex(); @@ -249,8 +242,7 @@ void LLWatchdog::run() mTimer->stop(); } - LL_INFOS() << "Watchdog detected error:" << LL_ENDL; - mKillerCallback(); + LL_ERRS() << "Watchdog timer expired; assuming viewer is hung and crashing" << LL_ENDL; } } diff --git a/indra/newview/llwatchdog.h b/indra/newview/llwatchdog.h index 9a6624258e..ce5cf748f4 100644 --- a/indra/newview/llwatchdog.h +++ b/indra/newview/llwatchdog.h @@ -83,9 +83,7 @@ public: void add(LLWatchdogEntry* e); void remove(LLWatchdogEntry* e); - typedef boost::function<void (void)> killer_event_callback; - - void init(killer_event_callback func = NULL); + void init(); void run(); void cleanup(); @@ -98,8 +96,6 @@ private: LLMutex* mSuspectsAccessMutex; LLWatchdogTimerThread* mTimer; U64 mLastClockCount; - - killer_event_callback mKillerCallback; }; #endif // LL_LLTHREADWATCHDOG_H diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp deleted file mode 100644 index b484b6d709..0000000000 --- a/indra/newview/llwaterparammanager.cpp +++ /dev/null @@ -1,442 +0,0 @@ -/** - * @file llwaterparammanager.cpp - * @brief Implementation for the LLWaterParamManager class. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llwaterparammanager.h" - -#include "llrender.h" - -#include "pipeline.h" -#include "llsky.h" - -#include "lldiriterator.h" -#include "llfloaterreg.h" -#include "llsliderctrl.h" -#include "llspinctrl.h" -#include "llcheckboxctrl.h" -#include "lluictrlfactory.h" -#include "llviewercontrol.h" -#include "llviewercamera.h" -#include "llcombobox.h" -#include "lllineeditor.h" -#include "llsdserialize.h" - -#include "v4math.h" -#include "llviewercontrol.h" -#include "lldrawpoolwater.h" -#include "llagent.h" -#include "llagentcamera.h" -#include "llviewerregion.h" - -#include "llwlparammanager.h" -#include "llwaterparamset.h" - -#include "curl/curl.h" - -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), - mUnderWaterFogMod(0.25, "underWaterFogMod"), - mNormalScale(2.f, 2.f, 2.f, "normScale"), - mFresnelScale(0.5f, "fresnelScale"), - mFresnelOffset(0.4f, "fresnelOffset"), - mScaleAbove(0.025f, "scaleAbove"), - mScaleBelow(0.2f, "scaleBelow"), - mBlurMultiplier(0.1f, "blurMultiplier"), - mWave1Dir(.5f, .5f, "wave1Dir"), - mWave2Dir(.5f, .5f, "wave2Dir"), - mDensitySliderValue(1.0f), - mWaterFogKS(1.0f) -{ -} - -LLWaterParamManager::~LLWaterParamManager() -{ -} - -void LLWaterParamManager::loadAllPresets() -{ - // First, load system (coming out of the box) water presets. - loadPresetsFromDir(getSysDir()); - - // Then load user presets. Note that user day presets will modify any system ones already loaded. - loadPresetsFromDir(getUserDir()); -} - -void LLWaterParamManager::loadPresetsFromDir(const std::string& dir) -{ - LL_DEBUGS("AppInit", "Shaders") << "Loading water presets from " << dir << LL_ENDL; - - LLDirIterator dir_iter(dir, "*.xml"); - while (1) - { - std::string file; - if (!dir_iter.next(file)) - { - break; // no more files - } - - std::string path = gDirUtilp->add(dir, file); - if (!loadPreset(path)) - { - LL_WARNS() << "Error loading water preset from " << path << LL_ENDL; - } - } -} - -bool LLWaterParamManager::loadPreset(const std::string& path) -{ - llifstream xml_file; - std::string name(gDirUtilp->getBaseFileName(LLURI::unescape(path), /*strip_exten = */ true)); - - xml_file.open(path.c_str()); - if (!xml_file) - { - return false; - } - - LL_DEBUGS("AppInit", "Shaders") << "Loading water " << name << LL_ENDL; - - LLSD params_data; - LLPointer<LLSDParser> parser = new LLSDXMLParser(); - parser->parse(xml_file, params_data, LLSDSerialize::SIZE_UNLIMITED); - xml_file.close(); - - if (hasParamSet(name)) - { - setParamSet(name, params_data); - } - else - { - addParamSet(name, params_data); - } - - return true; -} - -void LLWaterParamManager::savePreset(const std::string & name) -{ - llassert(!name.empty()); - - // make an empty llsd - LLSD paramsData(LLSD::emptyMap()); - std::string pathName(getUserDir() + LLURI::escape(name) + ".xml"); - - // fill it with LLSD windlight params - paramsData = mParamList[name].getAll(); - - // write to file - llofstream presetsXML(pathName.c_str()); - LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter(); - formatter->format(paramsData, presetsXML, LLSDFormatter::OPTIONS_PRETTY); - presetsXML.close(); - - propagateParameters(); -} - -void LLWaterParamManager::propagateParameters(void) -{ - // bind the variables only if we're using shaders - if(gPipeline.canUseVertexShaders()) - { - LLViewerShaderMgr::shader_iter shaders_iter, end_shaders; - end_shaders = LLViewerShaderMgr::instance()->endShaders(); - for(shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter) - { - if (shaders_iter->mProgramObject != 0 - && shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER) - { - shaders_iter->mUniformsDirty = TRUE; - } - } - } - - bool err; - F32 fog_density_slider = - log(mCurParams.getFloat(mFogDensity.mName, err)) / - log(mFogDensity.mBase); - - setDensitySliderValue(fog_density_slider); -} - -void LLWaterParamManager::updateShaderUniforms(LLGLSLShader * shader) -{ - if (shader->mShaderGroup == LLGLSLShader::SG_WATER) - { - shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, LLWLParamManager::getInstance()->getRotatedLightDir().mV); -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); - } -} - -void LLWaterParamManager::applyParams(const LLSD& params, bool interpolate) -{ - if (params.size() == 0) - { - LL_WARNS() << "Undefined water params" << LL_ENDL; - return; - } - - if (interpolate) - { - LLWLParamManager::getInstance()->mAnimator.startInterpolation(params); - } - else - { - mCurParams.setAll(params); - } -} - -static LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERPARAM("Update Water Params"); - -void LLWaterParamManager::update(LLViewerCamera * cam) -{ - LL_RECORD_BLOCK_TIME(FTM_UPDATE_WATERPARAM); - - // update the shaders and the menu - propagateParameters(); - - // only do this if we're dealing with shaders - if(gPipeline.canUseVertexShaders()) - { - //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); - - F32 modelView[16]; - for (U32 i = 0; i < 16; i++) - { - modelView[i] = (F32) gGLModelView[i]; - } - - 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); - - mWaterPlane = LLVector4(enorm.v[0], enorm.v[1], enorm.v[2], -ep.dot(enorm)); - - LLVector3 sunMoonDir; - if (gSky.getSunDirection().mV[2] > LLSky::NIGHTTIME_ELEVATION_COS) - { - sunMoonDir = gSky.getSunDirection(); - } - else - { - sunMoonDir = gSky.getMoonDirection(); - } - sunMoonDir.normVec(); - mWaterFogKS = 1.f/llmax(sunMoonDir.mV[2], WATER_FOG_LIGHT_CLAMP); - - LLViewerShaderMgr::shader_iter shaders_iter, end_shaders; - end_shaders = LLViewerShaderMgr::instance()->endShaders(); - for(shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter) - { - if (shaders_iter->mProgramObject != 0 - && shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER) - { - shaders_iter->mUniformsDirty = TRUE; - } - } - } -} - -bool LLWaterParamManager::addParamSet(const std::string& name, LLWaterParamSet& param) -{ - // add a new one if not one there already - preset_map_t::iterator mIt = mParamList.find(name); - if(mIt == mParamList.end()) - { - mParamList[name] = param; - mPresetListChangeSignal(); - return true; - } - - return false; -} - -BOOL LLWaterParamManager::addParamSet(const std::string& name, LLSD const & param) -{ - LLWaterParamSet param_set; - param_set.setAll(param); - return addParamSet(name, param_set); -} - -bool LLWaterParamManager::getParamSet(const std::string& name, LLWaterParamSet& param) -{ - // find it and set it - preset_map_t::iterator mIt = mParamList.find(name); - if(mIt != mParamList.end()) - { - param = mParamList[name]; - param.mName = name; - return true; - } - - return false; -} - -bool LLWaterParamManager::hasParamSet(const std::string& name) -{ - LLWaterParamSet dummy; - return getParamSet(name, dummy); -} - -bool LLWaterParamManager::setParamSet(const std::string& name, LLWaterParamSet& param) -{ - mParamList[name] = param; - - return true; -} - -bool LLWaterParamManager::setParamSet(const std::string& name, const LLSD & param) -{ - // quick, non robust (we won't be working with files, but assets) check - if(!param.isMap()) - { - return false; - } - - mParamList[name].setAll(param); - - return true; -} - -bool LLWaterParamManager::removeParamSet(const std::string& name, bool delete_from_disk) -{ - // remove from param list - preset_map_t::iterator it = mParamList.find(name); - if (it == mParamList.end()) - { - LL_WARNS("WindLight") << "No water preset named " << name << LL_ENDL; - return false; - } - - mParamList.erase(it); - - // remove from file system if requested - if (delete_from_disk) - { - if (gDirUtilp->deleteFilesInDir(getUserDir(), LLURI::escape(name) + ".xml") < 1) - { - LL_WARNS("WindLight") << "Error removing water preset " << name << " from disk" << LL_ENDL; - } - } - - // signal interested parties - mPresetListChangeSignal(); - return true; -} - -bool LLWaterParamManager::isSystemPreset(const std::string& preset_name) const -{ - // *TODO: file system access is excessive here. - return gDirUtilp->fileExists(getSysDir() + LLURI::escape(preset_name) + ".xml"); -} - -void LLWaterParamManager::getPresetNames(preset_name_list_t& presets) const -{ - presets.clear(); - - for (preset_map_t::const_iterator it = mParamList.begin(); it != mParamList.end(); ++it) - { - presets.push_back(it->first); - } -} - -void LLWaterParamManager::getPresetNames(preset_name_list_t& user_presets, preset_name_list_t& system_presets) const -{ - user_presets.clear(); - system_presets.clear(); - - for (preset_map_t::const_iterator it = mParamList.begin(); it != mParamList.end(); ++it) - { - if (isSystemPreset(it->first)) - { - system_presets.push_back(it->first); - } - else - { - user_presets.push_back(it->first); - } - } -} - -void LLWaterParamManager::getUserPresetNames(preset_name_list_t& user_presets) const -{ - preset_name_list_t dummy; - getPresetNames(user_presets, dummy); -} - -boost::signals2::connection LLWaterParamManager::setPresetListChangeCallback(const preset_list_signal_t::slot_type& cb) -{ - return mPresetListChangeSignal.connect(cb); -} - -F32 LLWaterParamManager::getFogDensity(void) -{ - bool err; - - F32 fogDensity = mCurParams.getFloat("waterFogDensity", err); - - // modify if we're underwater - const F32 water_height = gAgent.getRegion() ? gAgent.getRegion()->getWaterHeight() : 0.f; - F32 camera_height = gAgentCamera.getCameraPositionAgent().mV[2]; - if(camera_height <= water_height) - { - // raise it to the underwater fog density modifier - fogDensity = pow(fogDensity, mCurParams.getFloat("underWaterFogMod", err)); - } - - return fogDensity; -} - -// virtual static -void LLWaterParamManager::initSingleton() -{ - LL_DEBUGS("Windlight") << "Initializing water" << LL_ENDL; - loadAllPresets(); -} - -// static -std::string LLWaterParamManager::getSysDir() -{ - return gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/water", ""); -} - -// static -std::string LLWaterParamManager::getUserDir() -{ - return gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS , "windlight/water", ""); -} diff --git a/indra/newview/llwaterparammanager.h b/indra/newview/llwaterparammanager.h deleted file mode 100644 index 3f169e439a..0000000000 --- a/indra/newview/llwaterparammanager.h +++ /dev/null @@ -1,413 +0,0 @@ -/** - * @file llwaterparammanager.h - * @brief Implementation for the LLWaterParamManager class. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_WATER_PARAMMANAGER_H -#define LL_WATER_PARAMMANAGER_H - -#include <list> -#include <map> -#include "llwaterparamset.h" -#include "llviewercamera.h" -#include "v4color.h" - -const F32 WATER_FOG_LIGHT_CLAMP = 0.3f; - -// color control -struct WaterColorControl { - - F32 mR, mG, mB, mA, mI; /// the values - std::string mName; /// name to use to dereference params - std::string mSliderName; /// name of the slider in menu - bool mHasSliderName; /// only set slider name for true color types - - inline WaterColorControl(F32 red, F32 green, F32 blue, F32 alpha, - F32 intensity, const std::string& n, const std::string& sliderName = LLStringUtil::null) - : mR(red), mG(green), mB(blue), mA(alpha), mI(intensity), mName(n), mSliderName(sliderName) - { - // if there's a slider name, say we have one - mHasSliderName = false; - if (mSliderName != "") { - mHasSliderName = true; - } - } - - inline WaterColorControl & operator = (LLColor4 const & val) - { - mR = val.mV[0]; - mG = val.mV[1]; - mB = val.mV[2]; - mA = val.mV[3]; - return *this; - } - - inline operator LLColor4 (void) const - { - return LLColor4(mR, mG, mB, mA); - } - - inline WaterColorControl & operator = (LLVector4 const & val) - { - mR = val.mV[0]; - mG = val.mV[1]; - mB = val.mV[2]; - mA = val.mV[3]; - return *this; - } - - inline operator LLVector4 (void) const - { - return LLVector4(mR, mG, mB, mA); - } - - inline operator LLVector3 (void) const - { - return LLVector3(mR, mG, mB); - } - - inline void update(LLWaterParamSet & params) const - { - params.set(mName, mR, mG, mB, mA); - } -}; - -struct WaterVector3Control -{ - F32 mX; - F32 mY; - F32 mZ; - - std::string mName; - - // basic constructor - inline WaterVector3Control(F32 valX, F32 valY, F32 valZ, const std::string& n) - : mX(valX), mY(valY), mZ(valZ), mName(n) - { - } - - inline WaterVector3Control & operator = (LLVector3 const & val) - { - mX = val.mV[0]; - mY = val.mV[1]; - mZ = val.mV[2]; - - return *this; - } - - inline void update(LLWaterParamSet & params) const - { - params.set(mName, mX, mY, mZ); - } - -}; - -struct WaterVector2Control -{ - F32 mX; - F32 mY; - - std::string mName; - - // basic constructor - inline WaterVector2Control(F32 valX, F32 valY, const std::string& n) - : mX(valX), mY(valY), mName(n) - { - } - - inline WaterVector2Control & operator = (LLVector2 const & val) - { - mX = val.mV[0]; - mY = val.mV[1]; - - return *this; - } - - inline void update(LLWaterParamSet & params) const - { - params.set(mName, mX, mY); - } -}; - -// float slider control -struct WaterFloatControl -{ - F32 mX; - std::string mName; - F32 mMult; - - inline WaterFloatControl(F32 val, const std::string& n, F32 m=1.0f) - : mX(val), mName(n), mMult(m) - { - } - - inline WaterFloatControl & operator = (LLVector4 const & val) - { - mX = val.mV[0]; - - return *this; - } - - inline operator F32 (void) const - { - return mX; - } - - inline void update(LLWaterParamSet & params) const - { - params.set(mName, mX); - } -}; - -// float slider control -struct WaterExpFloatControl -{ - F32 mExp; - std::string mName; - F32 mBase; - - inline WaterExpFloatControl(F32 val, const std::string& n, F32 b) - : mExp(val), mName(n), mBase(b) - { - } - - inline WaterExpFloatControl & operator = (F32 val) - { - mExp = log(val) / log(mBase); - - return *this; - } - - inline operator F32 (void) const - { - return pow(mBase, mExp); - } - - inline void update(LLWaterParamSet & params) const - { - params.set(mName, pow(mBase, mExp)); - } -}; - - -/// WindLight parameter manager class - what controls all the wind light shaders -class LLWaterParamManager : public LLSingleton<LLWaterParamManager> -{ - LLSINGLETON(LLWaterParamManager); - ~LLWaterParamManager(); - LOG_CLASS(LLWaterParamManager); -public: - typedef std::list<std::string> preset_name_list_t; - typedef std::map<std::string, LLWaterParamSet> preset_map_t; - typedef boost::signals2::signal<void()> preset_list_signal_t; - - /// save the parameter presets to file - void savePreset(const std::string & name); - - /// send the parameters to the shaders - void propagateParameters(void); - - // display specified water - void applyParams(const LLSD& params, bool interpolate); - - /// update information for the shader - void update(LLViewerCamera * cam); - - /// Update shader uniforms that have changed. - void updateShaderUniforms(LLGLSLShader * shader); - - /// add a param to the list - bool addParamSet(const std::string& name, LLWaterParamSet& param); - - /// add a param to the list - BOOL addParamSet(const std::string& name, LLSD const & param); - - /// get a param from the list - bool getParamSet(const std::string& name, LLWaterParamSet& param); - - /// check whether the preset is in the list - bool hasParamSet(const std::string& name); - - /// set the param in the list with a new param - bool setParamSet(const std::string& name, LLWaterParamSet& param); - - /// set the param in the list with a new param - bool setParamSet(const std::string& name, LLSD const & param); - - /// gets rid of a parameter and any references to it - /// returns true if successful - bool removeParamSet(const std::string& name, bool delete_from_disk); - - /// @return true if the preset comes out of the box - bool isSystemPreset(const std::string& preset_name) const; - - /// @return all named water presets. - const preset_map_t& getPresets() const { return mParamList; } - - /// @return user and system preset names as a single list - void getPresetNames(preset_name_list_t& presets) const; - - /// @return user and system preset names separately - void getPresetNames(preset_name_list_t& user_presets, preset_name_list_t& system_presets) const; - - /// @return list of user presets names - void getUserPresetNames(preset_name_list_t& user_presets) const; - - /// Emitted when a preset gets added or deleted. - boost::signals2::connection setPresetListChangeCallback(const preset_list_signal_t::slot_type& cb); - - /// set the normap map we want for water - bool setNormalMapID(const LLUUID& img); - - void setDensitySliderValue(F32 val); - - /// getters for all the different things water param manager maintains - LLUUID getNormalMapID(void); - LLVector2 getWave1Dir(void); - LLVector2 getWave2Dir(void); - F32 getScaleAbove(void); - F32 getScaleBelow(void); - LLVector3 getNormalScale(void); - F32 getFresnelScale(void); - F32 getFresnelOffset(void); - F32 getBlurMultiplier(void); - F32 getFogDensity(void); - LLColor4 getFogColor(void); - -public: - - LLWaterParamSet mCurParams; - - /// Atmospherics - WaterColorControl mFogColor; - WaterExpFloatControl mFogDensity; - WaterFloatControl mUnderWaterFogMod; - - /// wavelet scales and directions - WaterVector3Control mNormalScale; - WaterVector2Control mWave1Dir; - WaterVector2Control mWave2Dir; - - // controls how water is reflected and refracted - WaterFloatControl mFresnelScale; - WaterFloatControl mFresnelOffset; - WaterFloatControl mScaleAbove; - WaterFloatControl mScaleBelow; - WaterFloatControl mBlurMultiplier; - - F32 mDensitySliderValue; - -private: - /*virtual*/ void initSingleton(); - void loadAllPresets(); - void loadPresetsFromDir(const std::string& dir); - bool loadPreset(const std::string& path); - - static std::string getSysDir(); - static std::string getUserDir(); - - LLVector4 mWaterPlane; - F32 mWaterFogKS; - - // list of all the parameters, listed by name - preset_map_t mParamList; - - preset_list_signal_t mPresetListChangeSignal; -}; - -inline void LLWaterParamManager::setDensitySliderValue(F32 val) -{ - val /= 10.0f; - val = 1.0f - val; - val *= val * val; -// val *= val; - mDensitySliderValue = val; -} - -inline LLUUID LLWaterParamManager::getNormalMapID() -{ - return mCurParams.mParamValues["normalMap"].asUUID(); -} - -inline bool LLWaterParamManager::setNormalMapID(const LLUUID& id) -{ - mCurParams.mParamValues["normalMap"] = id; - return true; -} - -inline LLVector2 LLWaterParamManager::getWave1Dir(void) -{ - bool err; - return mCurParams.getVector2("wave1Dir", err); -} - -inline LLVector2 LLWaterParamManager::getWave2Dir(void) -{ - bool err; - return mCurParams.getVector2("wave2Dir", err); -} - -inline F32 LLWaterParamManager::getScaleAbove(void) -{ - bool err; - return mCurParams.getFloat("scaleAbove", err); -} - -inline F32 LLWaterParamManager::getScaleBelow(void) -{ - bool err; - return mCurParams.getFloat("scaleBelow", err); -} - -inline LLVector3 LLWaterParamManager::getNormalScale(void) -{ - bool err; - return mCurParams.getVector3("normScale", err); -} - -inline F32 LLWaterParamManager::getFresnelScale(void) -{ - bool err; - return mCurParams.getFloat("fresnelScale", err); -} - -inline F32 LLWaterParamManager::getFresnelOffset(void) -{ - bool err; - return mCurParams.getFloat("fresnelOffset", err); -} - -inline F32 LLWaterParamManager::getBlurMultiplier(void) -{ - bool err; - return mCurParams.getFloat("blurMultiplier", err); -} - -inline LLColor4 LLWaterParamManager::getFogColor(void) -{ - bool err; - return LLColor4(mCurParams.getVector4("waterFogColor", err)); -} - -#endif diff --git a/indra/newview/llwaterparamset.cpp b/indra/newview/llwaterparamset.cpp deleted file mode 100644 index 9cc91d2246..0000000000 --- a/indra/newview/llwaterparamset.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/** - * @file llwaterparamset.cpp - * @brief Implementation for the LLWaterParamSet class. - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llwaterparamset.h" -#include "llsd.h" - -#include "llwaterparammanager.h" -#include "lluictrlfactory.h" -#include "llsliderctrl.h" -#include "llviewertexturelist.h" -#include "llviewercontrol.h" -#include "lluuid.h" - -#include <llgl.h> - -#include <sstream> - -LLWaterParamSet::LLWaterParamSet(void) : - mName("Unnamed Preset") -{ - LLSD vec4; - LLSD vec3; - LLSD real(0.0f); - - vec4 = LLSD::emptyArray(); - vec4.append(22.f/255.f); - vec4.append(43.f/255.f); - vec4.append(54.f/255.f); - vec4.append(0.f/255.f); - - vec3 = LLSD::emptyArray(); - vec3.append(2); - vec3.append(2); - vec3.append(2); - - LLSD wave1, wave2; - wave1 = LLSD::emptyArray(); - wave2 = LLSD::emptyArray(); - wave1.append(0.5f); - wave1.append(-.17f); - wave2.append(0.58f); - wave2.append(-.67f); - - mParamValues.insert("waterFogColor", vec4); - mParamValues.insert("waterFogDensity", 16.0f); - mParamValues.insert("underWaterFogMod", 0.25f); - mParamValues.insert("normScale", vec3); - mParamValues.insert("fresnelScale", 0.5f); - mParamValues.insert("fresnelOffset", 0.4f); - mParamValues.insert("scaleAbove", 0.025f); - mParamValues.insert("scaleBelow", 0.2f); - mParamValues.insert("blurMultiplier", 0.01f); - mParamValues.insert("wave1Dir", wave1); - mParamValues.insert("wave2Dir", wave2); - mParamValues.insert("normalMap", DEFAULT_WATER_NORMAL); - -} - -void LLWaterParamSet::set(const std::string& paramName, float x) -{ - // handle case where no array - if(mParamValues[paramName].isReal()) - { - mParamValues[paramName] = x; - } - - // handle array - else if(mParamValues[paramName].isArray() && - mParamValues[paramName][0].isReal()) - { - mParamValues[paramName][0] = x; - } -} - -void LLWaterParamSet::set(const std::string& paramName, float x, float y) { - mParamValues[paramName][0] = x; - mParamValues[paramName][1] = y; -} - -void LLWaterParamSet::set(const std::string& paramName, float x, float y, float z) -{ - mParamValues[paramName][0] = x; - mParamValues[paramName][1] = y; - mParamValues[paramName][2] = z; -} - -void LLWaterParamSet::set(const std::string& paramName, float x, float y, float z, float w) -{ - mParamValues[paramName][0] = x; - mParamValues[paramName][1] = y; - mParamValues[paramName][2] = z; - mParamValues[paramName][3] = w; -} - -void LLWaterParamSet::set(const std::string& paramName, const float * val) -{ - mParamValues[paramName][0] = val[0]; - mParamValues[paramName][1] = val[1]; - mParamValues[paramName][2] = val[2]; - mParamValues[paramName][3] = val[3]; -} - -void LLWaterParamSet::set(const std::string& paramName, const LLVector4 & val) -{ - mParamValues[paramName][0] = val.mV[0]; - mParamValues[paramName][1] = val.mV[1]; - mParamValues[paramName][2] = val.mV[2]; - mParamValues[paramName][3] = val.mV[3]; -} - -void LLWaterParamSet::set(const std::string& paramName, const LLColor4 & val) -{ - mParamValues[paramName][0] = val.mV[0]; - mParamValues[paramName][1] = val.mV[1]; - mParamValues[paramName][2] = val.mV[2]; - mParamValues[paramName][3] = val.mV[3]; -} - -LLVector4 LLWaterParamSet::getVector4(const std::string& paramName, bool& error) -{ - - // test to see if right type - LLSD cur_val = mParamValues.get(paramName); - if (!cur_val.isArray() || cur_val.size() != 4) - { - error = true; - return LLVector4(0,0,0,0); - } - - LLVector4 val; - val.mV[0] = (F32) cur_val[0].asReal(); - val.mV[1] = (F32) cur_val[1].asReal(); - val.mV[2] = (F32) cur_val[2].asReal(); - val.mV[3] = (F32) cur_val[3].asReal(); - - error = false; - return val; -} - -LLVector3 LLWaterParamSet::getVector3(const std::string& paramName, bool& error) -{ - - // test to see if right type - LLSD cur_val = mParamValues.get(paramName); - if (!cur_val.isArray()|| cur_val.size() != 3) - { - error = true; - return LLVector3(0,0,0); - } - - LLVector3 val; - val.mV[0] = (F32) cur_val[0].asReal(); - val.mV[1] = (F32) cur_val[1].asReal(); - val.mV[2] = (F32) cur_val[2].asReal(); - - error = false; - return val; -} - -LLVector2 LLWaterParamSet::getVector2(const std::string& paramName, bool& error) -{ - // test to see if right type - LLSD cur_val = mParamValues.get(paramName); - if (!cur_val.isArray() || cur_val.size() != 2) - { - error = true; - return LLVector2(0,0); - } - - LLVector2 val; - val.mV[0] = (F32) cur_val[0].asReal(); - val.mV[1] = (F32) cur_val[1].asReal(); - - error = false; - return val; -} - -F32 LLWaterParamSet::getFloat(const std::string& paramName, bool& error) -{ - - // test to see if right type - LLSD cur_val = mParamValues.get(paramName); - if (cur_val.isArray() && cur_val.size() != 0) - { - error = false; - return (F32) cur_val[0].asReal(); - } - - if(cur_val.isReal()) - { - error = false; - return (F32) cur_val.asReal(); - } - - error = true; - return 0; -} - -// Added for interpolation effect in DEV-33645 -// Based on LLWLParamSet::mix, but written by Jacob without an intimate knowledge of how WindLight works. -// The function definition existed in the header but was never implemented. If you think there is something -// wrong with this, you're probably right. Ask Jacob, Q, or a member of the original WindLight team. -void LLWaterParamSet::mix(LLWaterParamSet& src, LLWaterParamSet& dest, F32 weight) -{ - // Setup - LLSD srcVal, destVal; // LLSD holders for get/set calls, reusable - - // Iterate through values - for(LLSD::map_iterator iter = mParamValues.beginMap(); iter != mParamValues.endMap(); ++iter) - { - // If param exists in both src and dest, set the holder variables, otherwise skip - if(src.mParamValues.has(iter->first) && dest.mParamValues.has(iter->first)) - { - srcVal = src.mParamValues[iter->first]; - destVal = dest.mParamValues[iter->first]; - } - else - { - continue; - } - - if(iter->second.isReal()) // If it's a real, interpolate directly - { - iter->second = srcVal.asReal() + ((destVal.asReal() - srcVal.asReal()) * weight); - } - else if(iter->second.isArray() && iter->second[0].isReal() // If it's an array of reals, loop through the reals and interpolate on those - && iter->second.size() == srcVal.size() && iter->second.size() == destVal.size()) - { - // Actually do interpolation: old value + (difference in values * factor) - for(int i=0; i < iter->second.size(); ++i) - { - // iter->second[i] = (1.f-weight)*(F32)srcVal[i].asReal() + weight*(F32)destVal[i].asReal(); // old way of doing it -- equivalent but one more operation - iter->second[i] = srcVal[i].asReal() + ((destVal[i].asReal() - srcVal[i].asReal()) * weight); - } - } - else // Else, skip - { - continue; - } - } -} diff --git a/indra/newview/llwaterparamset.h b/indra/newview/llwaterparamset.h deleted file mode 100644 index 368cb0ccba..0000000000 --- a/indra/newview/llwaterparamset.h +++ /dev/null @@ -1,165 +0,0 @@ -/** - * @file llwlparamset.h - * @brief Interface for the LLWaterParamSet class. - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_WATER_PARAM_SET_H -#define LL_WATER_PARAM_SET_H - -#include <string> -#include <map> - -#include "v4math.h" -#include "v4color.h" -#include "llviewershadermgr.h" -#include "llstringtable.h" - -class LLWaterParamSet; - -/// A class representing a set of parameter values for the Water shaders. -class LLWaterParamSet -{ - friend class LLWaterParamManager; - -public: - std::string mName; - -private: - - LLSD mParamValues; - std::vector<LLStaticHashedString> mParamHashedNames; - - void updateHashedNames(); - -public: - - LLWaterParamSet(); - - /// Bind this set of parameter values to the uniforms of a particular shader. - void update(LLGLSLShader * shader) const; - - /// set the total llsd - void setAll(const LLSD& val); - - /// get the total llsd - const LLSD& getAll(); - - /// Set a float parameter. - /// \param paramName The name of the parameter to set. - /// \param x The float value to set. - void set(const std::string& paramName, float x); - - /// Set a float2 parameter. - /// \param paramName The name of the parameter to set. - /// \param x The x component's value to set. - /// \param y The y component's value to set. - void set(const std::string& paramName, float x, float y); - - /// Set a float3 parameter. - /// \param paramName The name of the parameter to set. - /// \param x The x component's value to set. - /// \param y The y component's value to set. - /// \param z The z component's value to set. - void set(const std::string& paramName, float x, float y, float z); - - /// Set a float4 parameter. - /// \param paramName The name of the parameter to set. - /// \param x The x component's value to set. - /// \param y The y component's value to set. - /// \param z The z component's value to set. - /// \param w The w component's value to set. - void set(const std::string& paramName, float x, float y, float z, float w); - - /// Set a float4 parameter. - /// \param paramName The name of the parameter to set. - /// \param val An array of the 4 float values to set the parameter to. - void set(const std::string& paramName, const float * val); - - /// Set a float4 parameter. - /// \param paramName The name of the parameter to set. - /// \param val A struct of the 4 float values to set the parameter to. - void set(const std::string& paramName, const LLVector4 & val); - - /// Set a float4 parameter. - /// \param paramName The name of the parameter to set. - /// \param val A struct of the 4 float values to set the parameter to. - void set(const std::string& paramName, const LLColor4 & val); - - /// Get a float4 parameter. - /// \param paramName The name of the parameter to set. - /// \param error A flag to set if it's not the proper return type - LLVector4 getVector4(const std::string& paramName, bool& error); - - /// Get a float3 parameter. - /// \param paramName The name of the parameter to set. - /// \param error A flag to set if it's not the proper return type - LLVector3 getVector3(const std::string& paramName, bool& error); - - /// Get a float2 parameter. - /// \param paramName The name of the parameter to set. - /// \param error A flag to set if it's not the proper return type - LLVector2 getVector2(const std::string& paramName, bool& error); - - /// Get an integer parameter - /// \param paramName The name of the parameter to set. - /// \param error A flag to set if it's not the proper return type - F32 getFloat(const std::string& paramName, bool& error); - - /// interpolate two parameter sets - /// \param src The parameter set to start with - /// \param dest The parameter set to end with - /// \param weight The amount to interpolate - void mix(LLWaterParamSet& src, LLWaterParamSet& dest, - F32 weight); - -}; - -inline void LLWaterParamSet::setAll(const LLSD& val) -{ - if(val.isMap()) { - LLSD::map_const_iterator mIt = val.beginMap(); - for(; mIt != val.endMap(); mIt++) - { - mParamValues[mIt->first] = mIt->second; - } - } - updateHashedNames(); -} - -inline void LLWaterParamSet::updateHashedNames() -{ - mParamHashedNames.clear(); - // Iterate through values - for(LLSD::map_iterator iter = mParamValues.beginMap(); iter != mParamValues.endMap(); ++iter) - { - mParamHashedNames.push_back(LLStaticHashedString(iter->first)); - } -} - -inline const LLSD& LLWaterParamSet::getAll() -{ - return mParamValues; -} - -#endif // LL_WaterPARAM_SET_H diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index e7bbee5efd..9acc0f8d2f 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -38,6 +38,7 @@ #include "llgesturemgr.h" #include "lltransutil.h" #include "llviewerattachmenu.h" +#include "llviewermenu.h" #include "llvoavatarself.h" class LLFindOutfitItems : public LLInventoryCollectFunctor @@ -639,6 +640,7 @@ LLWearableItemsList::LLWearableItemsList(const LLWearableItemsList::Params& p) : LLInventoryItemsList(p) { setSortOrder(E_SORT_BY_TYPE_LAYER, false); + mMenuWearableType = LLWearableType::WT_NONE; mIsStandalone = p.standalone; if (mIsStandalone) { @@ -730,10 +732,15 @@ void LLWearableItemsList::onRightClick(S32 x, S32 y) getSelectedUUIDs(selected_uuids); if (selected_uuids.empty()) { - return; + if ((mMenuWearableType != LLWearableType::WT_NONE) && (size() == 0)) + { + ContextMenu::instance().show(this, mMenuWearableType, x, y); + } + } + else + { + ContextMenu::instance().show(this, selected_uuids, x, y); } - - ContextMenu::instance().show(this, selected_uuids, x, y); } void LLWearableItemsList::setSortOrder(ESortOrder sort_order, bool sort_now) @@ -784,6 +791,46 @@ void LLWearableItemsList::ContextMenu::show(LLView* spawning_view, const uuid_ve mParent = NULL; // to avoid dereferencing an invalid pointer } +void LLWearableItemsList::ContextMenu::show(LLView* spawning_view, LLWearableType::EType w_type, S32 x, S32 y) +{ + mParent = dynamic_cast<LLWearableItemsList*>(spawning_view); + LLContextMenu* menup = mMenuHandle.get(); + if (menup) + { + //preventing parent (menu holder) from deleting already "dead" context menus on exit + LLView* parent = menup->getParent(); + if (parent) + { + parent->removeChild(menup); + } + delete menup; + mUUIDs.clear(); + } + + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + registrar.add("Wearable.CreateNew", boost::bind(createNewWearableByType, w_type)); + menup = createFromFile("menu_wearable_list_item.xml"); + if (!menup) + { + LL_WARNS() << "Context menu creation failed" << LL_ENDL; + return; + } + setMenuItemVisible(menup, "create_new", true); + setMenuItemEnabled(menup, "create_new", true); + setMenuItemVisible(menup, "wearable_attach_to", false); + setMenuItemVisible(menup, "wearable_attach_to_hud", false); + + std::string new_label = LLTrans::getString("create_new_" + LLWearableType::getTypeName(w_type)); + LLMenuItemGL* menu_item = menup->getChild<LLMenuItemGL>("create_new"); + menu_item->setLabel(new_label); + + mMenuHandle = menup->getHandle(); + menup->show(x, y); + LLMenuGL::showPopup(spawning_view, menup, x, y); + + mParent = NULL; // to avoid dereferencing an invalid pointer +} + // virtual LLContextMenu* LLWearableItemsList::ContextMenu::createMenu() { @@ -794,7 +841,7 @@ LLContextMenu* LLWearableItemsList::ContextMenu::createMenu() // Register handlers common for all wearable types. registrar.add("Wearable.Wear", boost::bind(wear_multiple, ids, true)); registrar.add("Wearable.Add", boost::bind(wear_multiple, ids, false)); - registrar.add("Wearable.Edit", boost::bind(handleMultiple, LLAgentWearables::editWearable, ids)); + registrar.add("Wearable.Edit", boost::bind(handle_item_edit, selected_id)); registrar.add("Wearable.CreateNew", boost::bind(createNewWearable, selected_id)); registrar.add("Wearable.ShowOriginal", boost::bind(show_item_original, selected_id)); registrar.add("Wearable.TakeOffDetach", @@ -809,6 +856,7 @@ LLContextMenu* LLWearableItemsList::ContextMenu::createMenu() // Register handlers for attachments. registrar.add("Attachment.Detach", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), ids)); + registrar.add("Attachment.Touch", boost::bind(handle_attachment_touch, selected_id)); registrar.add("Attachment.Profile", boost::bind(show_item_profile, selected_id)); registrar.add("Object.Attach", boost::bind(LLViewerAttachMenu::attachObjects, ids, _2)); @@ -838,6 +886,7 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu U32 n_already_worn = 0; // number of items worn of same type as selected items U32 n_links = 0; // number of links among the selected items U32 n_editable = 0; // number of editable items among the selected ones + U32 n_touchable = 0; // number of touchable items among the selected ones bool can_be_worn = true; @@ -858,12 +907,17 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu const LLWearableType::EType wearable_type = item->getWearableType(); const bool is_link = item->getIsLinkType(); const bool is_worn = get_is_item_worn(id); - const bool is_editable = gAgentWearables.isWearableModifiable(id); + const bool is_editable = get_is_item_editable(id); + const bool is_touchable = enable_attachment_touch(id); const bool is_already_worn = gAgentWearables.selfHasWearable(wearable_type); if (is_worn) { ++n_worn; } + if (is_touchable) + { + ++n_touchable; + } if (is_editable) { ++n_editable; @@ -893,8 +947,10 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu setMenuItemEnabled(menu, "wear_add", LLAppearanceMgr::instance().canAddWearables(ids)); setMenuItemVisible(menu, "wear_replace", n_worn == 0 && n_already_worn != 0 && can_be_worn); //visible only when one item selected and this item is worn - setMenuItemVisible(menu, "edit", !standalone && mask & (MASK_CLOTHING|MASK_BODYPART) && n_worn == n_items && n_worn == 1); - setMenuItemEnabled(menu, "edit", n_editable == 1 && n_worn == 1 && n_items == 1); + setMenuItemVisible(menu, "touch", !standalone && mask == MASK_ATTACHMENT && n_worn == n_items); + setMenuItemEnabled(menu, "touch", n_touchable && n_worn == 1 && n_items == 1); + setMenuItemVisible(menu, "edit", !standalone && mask & (MASK_CLOTHING|MASK_BODYPART|MASK_ATTACHMENT) && n_worn == n_items); + setMenuItemEnabled(menu, "edit", n_editable && n_worn == 1 && n_items == 1); setMenuItemVisible(menu, "create_new", mask & (MASK_CLOTHING|MASK_BODYPART) && n_items == 1); setMenuItemEnabled(menu, "create_new", LLAppearanceMgr::instance().canAddWearables(ids)); setMenuItemVisible(menu, "show_original", !standalone); @@ -1004,4 +1060,10 @@ void LLWearableItemsList::ContextMenu::createNewWearable(const LLUUID& item_id) LLAgentWearables::createWearable(item->getWearableType(), true); } +// static +void LLWearableItemsList::ContextMenu::createNewWearableByType(LLWearableType::EType type) +{ + LLAgentWearables::createWearable(type, true); +} + // EOF diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h index f3182ed163..ba8488b237 100644 --- a/indra/newview/llwearableitemslist.h +++ b/indra/newview/llwearableitemslist.h @@ -415,6 +415,8 @@ public: public: /*virtual*/ void show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y); + void show(LLView* spawning_view, LLWearableType::EType w_type, S32 x, S32 y); + protected: enum { MASK_CLOTHING = 0x01, @@ -431,6 +433,7 @@ public: static void setMenuItemEnabled(LLContextMenu* menu, const std::string& name, bool val); static void updateMask(U32& mask, LLAssetType::EType at); static void createNewWearable(const LLUUID& item_id); + static void createNewWearableByType(LLWearableType::EType type); LLWearableItemsList* mParent; }; @@ -469,6 +472,8 @@ public: void setSortOrder(ESortOrder sort_order, bool sort_now = true); + void setMenuWearableType(LLWearableType::EType type) { mMenuWearableType = type; } + protected: friend class LLUICtrlFactory; LLWearableItemsList(const LLWearableItemsList::Params& p); @@ -479,6 +484,8 @@ protected: bool mWornIndicationEnabled; ESortOrder mSortOrder; + + LLWearableType::EType mMenuWearableType; }; #endif //LL_LLWEARABLEITEMSLIST_H diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index 61ec02957e..d019b400e8 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -39,7 +39,6 @@ #include "lllogininstance.h" #include "llparcel.h" #include "llsd.h" -#include "lltoastalertpanel.h" #include "llui.h" #include "lluri.h" #include "llversioninfo.h" @@ -57,32 +56,6 @@ bool on_load_url_external_response(const LLSD& notification, const LLSD& response, bool async ); -class URLLoader : public LLToastAlertPanel::URLLoader -{ - virtual void load(const std::string& url , bool force_open_externally) - { - if (force_open_externally) - { - LLWeb::loadURLExternal(url); - } - else - { - LLWeb::loadURL(url); - } - } -}; -static URLLoader sAlertURLLoader; - - -// static -void LLWeb::initClass() -{ - LLToastAlertPanel::setURLLoader(&sAlertURLLoader); -} - - - - // static void LLWeb::loadURL(const std::string& url, const std::string& target, const std::string& uuid) { @@ -121,7 +94,7 @@ void LLWeb::loadURLExternal(const std::string& url, const std::string& uuid) void LLWeb::loadURLExternal(const std::string& url, bool async, const std::string& uuid) { // Act like the proxy window was closed, since we won't be able to track targeted windows in the external browser. - LLViewerMedia::proxyWindowClosed(uuid); + LLViewerMedia::getInstance()->proxyWindowClosed(uuid); if(gSavedSettings.getBOOL("DisableExternalBrowser")) { @@ -184,12 +157,12 @@ std::string LLWeb::expandURLSubstitutions(const std::string &url, const LLSD &default_subs) { LLSD substitution = default_subs; - 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(); + substitution["VERSION"] = LLVersionInfo::instance().getVersion(); + substitution["VERSION_MAJOR"] = LLVersionInfo::instance().getMajor(); + substitution["VERSION_MINOR"] = LLVersionInfo::instance().getMinor(); + substitution["VERSION_PATCH"] = LLVersionInfo::instance().getPatch(); + substitution["VERSION_BUILD"] = LLVersionInfo::instance().getBuild(); + substitution["CHANNEL"] = LLVersionInfo::instance().getChannel(); substitution["GRID"] = LLGridManager::getInstance()->getGridId(); substitution["GRID_LOWERCASE"] = utf8str_tolower(LLGridManager::getInstance()->getGridId()); substitution["OS"] = LLOSInfo::instance().getOSStringSimple(); @@ -264,7 +237,7 @@ bool LLWeb::useExternalBrowser(const std::string &url) up.extractParts(); std::string uri_string = up.host(); - boost::regex pattern = boost::regex("\\b(lindenlab.com|secondlife.com)$", boost::regex::perl|boost::regex::icase); + boost::regex pattern = boost::regex("\\b(lindenlab.com|secondlife.com|secondlife.io)$", boost::regex::perl|boost::regex::icase); boost::match_results<std::string::const_iterator> matches; return !(boost::regex_search(uri_string, matches, pattern)); } diff --git a/indra/newview/llweb.h b/indra/newview/llweb.h index 7149ce9baf..0426f00f27 100644 --- a/indra/newview/llweb.h +++ b/indra/newview/llweb.h @@ -46,8 +46,6 @@ public: BROWSER_INT_LL_EXT_OTHERS = 1, BROWSER_INTERNAL_ONLY = 2 }; - - static void initClass(); /// Load the given url in the operating system's web browser, async if we want to return immediately /// before browser has spawned diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index 8dcef2c7cd..ff899fe895 100644 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -83,7 +83,7 @@ void LLWebProfile::setAuthCookie(const std::string& cookie) LLCore::HttpHeaders::ptr_t LLWebProfile::buildDefaultHeaders() { LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); - LLSD headers = LLViewerMedia::getHeaders(); + LLSD headers = LLViewerMedia::getInstance()->getHeaders(); for (LLSD::map_iterator it = headers.beginMap(); it != headers.endMap(); ++it) { @@ -113,6 +113,7 @@ void LLWebProfile::uploadImageCoro(LLPointer<LLImageFormatted> image, std::strin httpOpts->setWantHeaders(true); httpOpts->setFollowRedirects(false); + httpOpts->setSSLVerifyPeer(false); ; // viewer's cert bundle doesn't appear to agree with web certs from "https://my.secondlife.com/" // Get upload configuration data. std::string configUrl(getProfileURL(std::string()) + "snapshots/s3_upload_config"); diff --git a/indra/newview/llwindebug.h b/indra/newview/llwindebug.h index 7e5818ba1c..524adba652 100644 --- a/indra/newview/llwindebug.h +++ b/indra/newview/llwindebug.h @@ -29,7 +29,11 @@ #include "stdtypes.h" #include "llwin32headerslean.h" + +#pragma warning (push) +#pragma warning (disable:4091) // a microsoft header has warnings. Very nice. #include <dbghelp.h> +#pragma warning (pop) class LLWinDebug: public LLSingleton<LLWinDebug> diff --git a/indra/newview/llwindowlistener.cpp b/indra/newview/llwindowlistener.cpp index 5367262bb6..aa8c79b0d2 100644 --- a/indra/newview/llwindowlistener.cpp +++ b/indra/newview/llwindowlistener.cpp @@ -37,7 +37,7 @@ #include "llview.h" #include "llviewinject.h" #include "llviewerwindow.h" -#include "llviewerkeyboard.h" +#include "llviewerinput.h" #include "llrootview.h" #include "llsdutil.h" #include "stringize.h" @@ -69,7 +69,7 @@ LLWindowListener::LLWindowListener(LLViewerWindow *window, const KeyboardGetter& std::string buttonExplain = "(button values \"LEFT\", \"MIDDLE\", \"RIGHT\")\n"; std::string paramsExplain = - "[\"path\"] is as for LLUI::resolvePath(), described in\n" + "[\"path\"] is as for LLUI::getInstance()->resolvePath(), described in\n" "http://bitbucket.org/lindenlab/viewer-release/src/tip/indra/llui/llui.h\n" "If you omit [\"path\"], you must specify both [\"x\"] and [\"y\"].\n" "If you specify [\"path\"] without both [\"x\"] and [\"y\"], will synthesize (x, y)\n" @@ -209,7 +209,7 @@ void LLWindowListener::getInfo(LLSD const & evt) if (evt.has("path")) { std::string path(evt["path"]); - LLView * target_view = LLUI::resolvePath(LLUI::getRootView(), path); + LLView * target_view = LLUI::getInstance()->resolvePath(LLUI::getInstance()->getRootView(), path); if (target_view != 0) { response.setResponse(target_view->getInfo()); @@ -230,7 +230,7 @@ void LLWindowListener::getInfo(LLSD const & evt) void LLWindowListener::getPaths(LLSD const & request) { Response response(LLSD(), request); - LLView *root(LLUI::getRootView()), *base(NULL); + LLView *root(LLUI::getInstance()->getRootView()), *base(NULL); // Capturing request["under"] as string means we conflate the case in // which there is no ["under"] key with the case in which its value is the // empty string. That seems to make sense to me. @@ -243,7 +243,7 @@ void LLWindowListener::getPaths(LLSD const & request) } else { - base = LLUI::resolvePath(root, under); + base = LLUI::getInstance()->resolvePath(root, under); if (! base) { return response.error(STRINGIZE(request["op"].asString() << " request " @@ -268,7 +268,7 @@ void LLWindowListener::keyDown(LLSD const & evt) if (evt.has("path")) { std::string path(evt["path"]); - LLView * target_view = LLUI::resolvePath(LLUI::getRootView(), path); + LLView * target_view = LLUI::getInstance()->resolvePath(LLUI::getInstance()->getRootView(), path); if (target_view == 0) { response.error(STRINGIZE(evt["op"].asString() << " request " @@ -279,7 +279,7 @@ void LLWindowListener::keyDown(LLSD const & evt) response.setResponse(target_view->getInfo()); gFocusMgr.setKeyboardFocus(target_view); - gViewerKeyboard.handleKey(key, mask, false); + gViewerInput.handleKey(key, mask, false); if(key < 0x80) mWindow->handleUnicodeChar(key, mask); } else @@ -291,7 +291,7 @@ void LLWindowListener::keyDown(LLSD const & evt) } else { - gViewerKeyboard.handleKey(key, mask, false); + gViewerInput.handleKey(key, mask, false); if(key < 0x80) mWindow->handleUnicodeChar(key, mask); } } @@ -303,7 +303,7 @@ void LLWindowListener::keyUp(LLSD const & evt) if (evt.has("path")) { std::string path(evt["path"]); - LLView * target_view = LLUI::resolvePath(LLUI::getRootView(), path); + LLView * target_view = LLUI::getInstance()->resolvePath(LLUI::getInstance()->getRootView(), path); if (target_view == 0 ) { response.error(STRINGIZE(evt["op"].asString() << " request " @@ -407,8 +407,8 @@ static void mouseEvent(const MouseFunc& func, const LLSD& request) } else // ! path.empty() { - LLView* root = LLUI::getRootView(); - LLView* target = LLUI::resolvePath(root, path); + LLView* root = LLUI::getInstance()->getRootView(); + LLView* target = LLUI::getInstance()->resolvePath(root, path); if (! target) { return response.error(STRINGIZE(request["op"].asString() << " request " diff --git a/indra/newview/llwlanimator.cpp b/indra/newview/llwlanimator.cpp deleted file mode 100644 index c8879e73eb..0000000000 --- a/indra/newview/llwlanimator.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/** - * @file llwlanimator.cpp - * @brief Implementation for the LLWLAnimator class. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llwlanimator.h" -#include "llsky.h" -#include "pipeline.h" -#include "llwlparammanager.h" -#include "llwaterparammanager.h" - -extern LLControlGroup gSavedSettings; - -F64 LLWLAnimator::INTERP_TOTAL_SECONDS = 3.f; - -LLWLAnimator::LLWLAnimator() : mStartTime(0.f), mDayRate(1.f), mDayTime(0.f), - mIsRunning(FALSE), mIsInterpolating(FALSE), mTimeType(TIME_LINDEN), - mInterpStartTime(), mInterpEndTime() -{ - mInterpBeginWL = new LLWLParamSet(); - mInterpBeginWater = new LLWaterParamSet(); - mInterpEndWater = new LLWaterParamSet(); -} - -void LLWLAnimator::update(LLWLParamSet& curParams) -{ - //llassert(mUseLindenTime != mUseLocalTime); - - F64 curTime; - curTime = getDayTime(); - - // don't do anything if empty - if(mTimeTrack.size() == 0) - { - return; - } - - // start it off - mFirstIt = mTimeTrack.begin(); - mSecondIt = mTimeTrack.begin(); - mSecondIt++; - - // grab the two tween iterators - while(mSecondIt != mTimeTrack.end() && curTime > mSecondIt->first) - { - mFirstIt++; - mSecondIt++; - } - - // scroll it around when you get to the end - if(mSecondIt == mTimeTrack.end() || mFirstIt->first > curTime) - { - mSecondIt = mTimeTrack.begin(); - mFirstIt = mTimeTrack.end(); - mFirstIt--; - } - - F32 weight = 0; - - if(mFirstIt->first < mSecondIt->first) - { - - // get the delta time and the proper weight - weight = F32 (curTime - mFirstIt->first) / - (mSecondIt->first - mFirstIt->first); - - // handle the ends - } - else if(mFirstIt->first > mSecondIt->first) - { - - // right edge of time line - if(curTime >= mFirstIt->first) - { - weight = F32 (curTime - mFirstIt->first) / - ((1 + mSecondIt->first) - mFirstIt->first); - // left edge of time line - } - else - { - weight = F32 ((1 + curTime) - mFirstIt->first) / - ((1 + mSecondIt->first) - mFirstIt->first); - } - - // handle same as whatever the last one is - } - else - { - weight = 1; - } - - if(mIsInterpolating) - { - // *TODO_JACOB: this is kind of laggy. Not sure why. The part that lags is the curParams.mix call, and none of the other mixes. It works, though. - clock_t current = clock(); - if(current >= mInterpEndTime) - { - mIsInterpolating = false; - return; - } - - // determine moving target for final interpolation value - // *TODO: this will not work with lazy loading of sky presets. - LLWLParamSet buf = LLWLParamSet(); - buf.setAll(LLWLParamManager::getInstance()->mParamList[mFirstIt->second].getAll()); // just give it some values, otherwise it has no params to begin with (see comment in constructor) - buf.mix(LLWLParamManager::getInstance()->mParamList[mFirstIt->second], LLWLParamManager::getInstance()->mParamList[mSecondIt->second], weight); // mix to determine moving target for interpolation finish (as below) - - // mix from previous value to moving target - weight = (current - mInterpStartTime) / (INTERP_TOTAL_SECONDS * CLOCKS_PER_SEC); - curParams.mix(*mInterpBeginWL, buf, weight); - - // mix water - LLWaterParamManager::getInstance()->mCurParams.mix(*mInterpBeginWater, *mInterpEndWater, weight); - } - else - { - // do the interpolation and set the parameters - // *TODO: this will not work with lazy loading of sky presets. - curParams.mix(LLWLParamManager::getInstance()->mParamList[mFirstIt->second], LLWLParamManager::getInstance()->mParamList[mSecondIt->second], weight); - } -} - -F64 LLWLAnimator::getDayTime() -{ - if(!mIsRunning) - { - return mDayTime; - } - else if(mTimeType == TIME_LINDEN) - { - F32 phase = gSky.getSunPhase() / F_PI; - - // we're not solving the non-linear equation that determines sun phase - // we're just linearly interpolating between the major points - - if (phase <= 5.0 / 4.0) - { - // mDayTime from 0.33 to 0.75 (6:00 to 21:00) - mDayTime = (1.0 / 3.0) * phase + (1.0 / 3.0); - } - else if (phase > 7.0 / 4.0) - { - // maximum value for phase is 2 - // mDayTime from 0.25 to 0.33 (3:00 to 6:00) - mDayTime = (1.0 / 3.0) - (1.0 / 3.0) * (2 - phase); - } - else - { - // phase == 3/2 is where day restarts (24:00) - // mDayTime from 0.75 to 0.999 and 0 to 0.25 (21:00 to 03:00) - mDayTime = phase - (1.0 / 2.0); - - if(mDayTime > 1) - { - mDayTime--; - } - } - - return mDayTime; - } - else if(mTimeType == TIME_LOCAL) - { - return getLocalTime(); - } - - // get the time; - mDayTime = (LLTimer::getElapsedSeconds() - mStartTime) / mDayRate; - - // clamp it - if(mDayTime < 0) - { - mDayTime = 0; - } - while(mDayTime > 1) - { - mDayTime--; - } - - return (F32)mDayTime; -} - -void LLWLAnimator::setDayTime(F64 dayTime) -{ - //retroactively set start time; - mStartTime = LLTimer::getElapsedSeconds() - dayTime * mDayRate; - mDayTime = dayTime; - - // clamp it - if(mDayTime < 0) - { - mDayTime = 0; - } - else if(mDayTime > 1) - { - mDayTime = 1; - } -} - - -void LLWLAnimator::setTrack(std::map<F32, LLWLParamKey>& curTrack, - F32 dayRate, F64 dayTime, bool run) -{ - mTimeTrack = curTrack; - mDayRate = dayRate; - setDayTime(dayTime); - - mIsRunning = run; -} - -void LLWLAnimator::startInterpolation(const LLSD& targetWater) -{ - mInterpBeginWL->setAll(LLWLParamManager::getInstance()->mCurParams.getAll()); - mInterpBeginWater->setAll(LLWaterParamManager::getInstance()->mCurParams.getAll()); - - mInterpStartTime = clock(); - mInterpEndTime = mInterpStartTime + clock_t(INTERP_TOTAL_SECONDS) * CLOCKS_PER_SEC; - - // Don't set any ending WL -- this is continuously calculated as the animator updates since it's a moving target - mInterpEndWater->setAll(targetWater); - - mIsInterpolating = true; -} - -std::string LLWLAnimator::timeToString(F32 curTime) -{ - S32 hours; - S32 min; - bool isPM = false; - - // get hours and minutes - hours = (S32) (24.0 * curTime); - curTime -= ((F32) hours / 24.0f); - min = ll_round(24.0f * 60.0f * curTime); - - // handle case where it's 60 - if(min == 60) - { - hours++; - min = 0; - } - - // set for PM - if(hours >= 12 && hours < 24) - { - isPM = true; - } - - // convert to non-military notation - if(hours >= 24) - { - hours = 12; - } - else if(hours > 12) - { - hours -= 12; - } - else if(hours == 0) - { - hours = 12; - } - - // make the string - std::stringstream newTime; - newTime << hours << ":"; - - // double 0 - if(min < 10) - { - newTime << 0; - } - - // finish it - newTime << min << " "; - if(isPM) - { - newTime << "PM"; - } - else - { - newTime << "AM"; - } - - return newTime.str(); -} - -F64 LLWLAnimator::getLocalTime() -{ - char buffer[9]; - time_t rawtime; - struct tm* timeinfo; - - time(&rawtime); - timeinfo = localtime(&rawtime); - strftime(buffer, 9, "%H:%M:%S", timeinfo); - std::string timeStr(buffer); - - F64 tod = ((F64)atoi(timeStr.substr(0,2).c_str())) / 24.f + - ((F64)atoi(timeStr.substr(3,2).c_str())) / 1440.f + - ((F64)atoi(timeStr.substr(6,2).c_str())) / 86400.f; - return tod; -} diff --git a/indra/newview/llwlanimator.h b/indra/newview/llwlanimator.h deleted file mode 100644 index e2e49c7305..0000000000 --- a/indra/newview/llwlanimator.h +++ /dev/null @@ -1,139 +0,0 @@ -/** - * @file llwlanimator.h - * @brief Interface for the LLWLAnimator class. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_WL_ANIMATOR_H -#define LL_WL_ANIMATOR_H - -#include "llwlparamset.h" -#include "llenvmanager.h" -#include "llwaterparamset.h" -#include <string> -#include <map> - -class LLWLAnimator { -public: - typedef enum e_time - { - TIME_LINDEN, - TIME_LOCAL, - TIME_CUSTOM - } ETime; - - F64 mStartTime; - F32 mDayRate; - F64 mDayTime; - - // track to play - std::map<F32, LLWLParamKey> mTimeTrack; - std::map<F32, LLWLParamKey>::iterator mFirstIt, mSecondIt; - - // simple constructor - LLWLAnimator(); - - ~LLWLAnimator() - { - delete mInterpBeginWL; - delete mInterpBeginWater; - delete mInterpEndWater; - } - - // update the parameters - void update(LLWLParamSet& curParams); - - // get time in seconds - //F64 getTime(void); - - // returns a float 0 - 1 saying what time of day is it? - F64 getDayTime(void); - - // sets a float 0 - 1 saying what time of day it is - void setDayTime(F64 dayTime); - - // set an animation track - void setTrack(std::map<F32, LLWLParamKey>& track, - F32 dayRate, F64 dayTime = 0, bool run = true); - - void deactivate() - { - mIsRunning = false; - } - - void activate(ETime time) - { - mIsRunning = true; - mTimeType = time; - } - - void startInterpolation(const LLSD& targetWater); - - bool getIsRunning() - { - return mIsRunning; - } - - bool getUseCustomTime() - { - return mTimeType == TIME_CUSTOM; - } - - bool getUseLocalTime() - { - return mTimeType == TIME_LOCAL; - } - - bool getUseLindenTime() - { - return mTimeType == TIME_LINDEN; - } - - void setTimeType(ETime time) - { - mTimeType = time; - } - - ETime getTimeType() - { - return mTimeType; - } - - /// convert the present time to a digital clock time - static std::string timeToString(F32 curTime); - - /// get local time between 0 and 1 - static F64 getLocalTime(); - -private: - ETime mTimeType; - bool mIsRunning, mIsInterpolating; - LLWLParamSet *mInterpBeginWL; - LLWaterParamSet *mInterpBeginWater, *mInterpEndWater; - clock_t mInterpStartTime, mInterpEndTime; - - static F64 INTERP_TOTAL_SECONDS; -}; - -#endif // LL_WL_ANIMATOR_H - diff --git a/indra/newview/llwldaycycle.cpp b/indra/newview/llwldaycycle.cpp index 106f17f61b..0a331d1823 100644 --- a/indra/newview/llwldaycycle.cpp +++ b/indra/newview/llwldaycycle.cpp @@ -46,6 +46,7 @@ LLWLDayCycle::~LLWLDayCycle() void LLWLDayCycle::loadDayCycle(const LLSD& day_data, LLWLParamKey::EScope scope) { +#if 0 LL_DEBUGS() << "Loading day cycle (day_data.size() = " << day_data.size() << ", scope = " << scope << ")" << LL_ENDL; mTimeMap.clear(); @@ -88,6 +89,7 @@ void LLWLDayCycle::loadDayCycle(const LLSD& day_data, LLWLParamKey::EScope scope // then add the keyframe addKeyframe((F32)day_data[i][0].asReal(), frame); } +#endif } void LLWLDayCycle::loadDayCycleFromFile(const std::string & fileName) @@ -158,35 +160,35 @@ LLSD LLWLDayCycle::asLLSD() return day_data; } -bool LLWLDayCycle::getSkyRefs(std::map<LLWLParamKey, LLWLParamSet>& refs) const -{ - bool result = true; - LLWLParamManager& wl_mgr = LLWLParamManager::instance(); - - refs.clear(); - for (std::map<F32, LLWLParamKey>::const_iterator iter = mTimeMap.begin(); iter != mTimeMap.end(); ++iter) - { - const LLWLParamKey& key = iter->second; - if (!wl_mgr.getParamSet(key, refs[key])) - { - LL_WARNS() << "Cannot find sky [" << key.name << "] referenced by a day cycle" << LL_ENDL; - result = false; - } - } - - return result; -} +// bool LLWLDayCycle::getSkyRefs(std::map<LLWLParamKey, LLWLParamSet>& refs) const +// { +// bool result = true; +// LLWLParamManager& wl_mgr = LLWLParamManager::instance(); +// +// refs.clear(); +// for (std::map<F32, LLWLParamKey>::const_iterator iter = mTimeMap.begin(); iter != mTimeMap.end(); ++iter) +// { +// const LLWLParamKey& key = iter->second; +// if (!wl_mgr.getParamSet(key, refs[key])) +// { +// LL_WARNS() << "Cannot find sky [" << key.name << "] referenced by a day cycle" << LL_ENDL; +// result = false; +// } +// } +// +// return result; +// } bool LLWLDayCycle::getSkyMap(LLSD& sky_map) const { - std::map<LLWLParamKey, LLWLParamSet> refs; - - if (!getSkyRefs(refs)) - { - return false; - } - - sky_map = LLWLParamManager::createSkyMap(refs); +// std::map<LLWLParamKey, LLWLParamSet> refs; +// +// if (!getSkyRefs(refs)) +// { +// return false; +// } +// +// sky_map = LLWLParamManager::createSkyMap(refs); return true; } @@ -235,23 +237,23 @@ bool LLWLDayCycle::changeKeyframeTime(F32 oldTime, F32 newTime) return addKeyframe(newTime, frame); } -bool LLWLDayCycle::changeKeyframeParam(F32 time, LLWLParamKey key) -{ - LL_DEBUGS() << "Changing key frame param (" << time << ", " << key.toLLSD() << ")" << LL_ENDL; - - // just remove and add back - // make sure param exists - LLWLParamSet tmp; - bool stat = LLWLParamManager::getInstance()->getParamSet(key, tmp); - if(stat == false) - { - LL_DEBUGS() << "Failed to change key frame param (" << time << ", " << key.toLLSD() << ")" << LL_ENDL; - return stat; - } - - mTimeMap[time] = key; - return true; -} +// bool LLWLDayCycle::changeKeyframeParam(F32 time, LLWLParamKey key) +// { +// LL_DEBUGS() << "Changing key frame param (" << time << ", " << key.toLLSD() << ")" << LL_ENDL; +// +// // just remove and add back +// // make sure param exists +// LLWLParamSet tmp; +// bool stat = LLWLParamManager::getInstance()->getParamSet(key, tmp); +// if(stat == false) +// { +// LL_DEBUGS() << "Failed to change key frame param (" << time << ", " << key.toLLSD() << ")" << LL_ENDL; +// return stat; +// } +// +// mTimeMap[time] = key; +// return true; +// } bool LLWLDayCycle::removeKeyframe(F32 time) @@ -285,19 +287,19 @@ bool LLWLDayCycle::getKeytime(LLWLParamKey frame, F32& key_time) const return false; } -bool LLWLDayCycle::getKeyedParam(F32 time, LLWLParamSet& param) -{ - // just scroll on through till you find it - std::map<F32, LLWLParamKey>::iterator mIt = mTimeMap.find(time); - if(mIt != mTimeMap.end()) - { - return LLWLParamManager::getInstance()->getParamSet(mIt->second, param); - } - - // return error if not found - LL_DEBUGS() << "Key " << time << " not found" << LL_ENDL; - return false; -} +// bool LLWLDayCycle::getKeyedParam(F32 time, LLWLParamSet& param) +// { +// // just scroll on through till you find it +// std::map<F32, LLWLParamKey>::iterator mIt = mTimeMap.find(time); +// if(mIt != mTimeMap.end()) +// { +// return LLWLParamManager::getInstance()->getParamSet(mIt->second, param); +// } +// +// // return error if not found +// LL_DEBUGS() << "Key " << time << " not found" << LL_ENDL; +// return false; +// } bool LLWLDayCycle::getKeyedParamName(F32 time, std::string & name) { diff --git a/indra/newview/llwldaycycle.h b/indra/newview/llwldaycycle.h index c8585564ed..2f9a2e5c4a 100644 --- a/indra/newview/llwldaycycle.h +++ b/indra/newview/llwldaycycle.h @@ -32,10 +32,8 @@ class LLWLDayCycle; #include <vector> #include <map> #include <string> -#include "llwlparamset.h" -#include "llwlanimator.h" +#include "llenvmanager.h" struct LLWLParamKey; -#include "llenvmanager.h" // for LLEnvKey::EScope class LLWLDayCycle { @@ -78,7 +76,7 @@ public: LLSD asLLSD(); // get skies referenced by this day cycle - bool getSkyRefs(std::map<LLWLParamKey, LLWLParamSet>& refs) const; +// bool getSkyRefs(std::map<LLWLParamKey, LLWLParamSet>& refs) const; // get referenced skies as LLSD bool getSkyMap(LLSD& sky_map) const; @@ -110,7 +108,7 @@ public: /// get the param set at a given time /// returns true if found one - bool getKeyedParam(F32 time, LLWLParamSet& param); +// bool getKeyedParam(F32 time, LLWLParamSet& param); /// get the name /// returns true if it found one diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp index ea65a0c6d9..d55e1b7cd3 100644 --- a/indra/newview/llwlhandlers.cpp +++ b/indra/newview/llwlhandlers.cpp @@ -30,15 +30,15 @@ #include "llagent.h" #include "llviewerregion.h" -#include "llenvmanager.h" #include "llnotificationsutil.h" #include "llcorehttputil.h" +#include "llparcel.h" /**** * LLEnvironmentRequest ****/ // static -bool LLEnvironmentRequest::initiate() +bool LLEnvironmentRequest::initiate(LLEnvironment::environment_apply_fn cb) { LLViewerRegion* cur_region = gAgent.getRegion(); @@ -51,15 +51,15 @@ bool LLEnvironmentRequest::initiate() if (!cur_region->capabilitiesReceived()) { LL_INFOS("WindlightCaps") << "Deferring windlight settings request until we've got region caps" << LL_ENDL; - cur_region->setCapabilitiesReceivedCallback(boost::bind(&LLEnvironmentRequest::onRegionCapsReceived, _1)); + cur_region->setCapabilitiesReceivedCallback([cb](const LLUUID ®ion_id, LLViewerRegion* regionp) { LLEnvironmentRequest::onRegionCapsReceived(region_id, cb); }); return false; } - return doRequest(); + return doRequest(cb); } // static -void LLEnvironmentRequest::onRegionCapsReceived(const LLUUID& region_id) +void LLEnvironmentRequest::onRegionCapsReceived(const LLUUID& region_id, LLEnvironment::environment_apply_fn cb) { if (region_id != gAgent.getRegion()->getRegionID()) { @@ -68,23 +68,26 @@ void LLEnvironmentRequest::onRegionCapsReceived(const LLUUID& region_id) } LL_DEBUGS("WindlightCaps") << "Received region capabilities" << LL_ENDL; - doRequest(); + doRequest(cb); } // static -bool LLEnvironmentRequest::doRequest() +bool LLEnvironmentRequest::doRequest(LLEnvironment::environment_apply_fn cb) { std::string url = gAgent.getRegionCapability("EnvironmentSettings"); if (url.empty()) { LL_INFOS("WindlightCaps") << "Skipping windlight setting request - we don't have this capability" << LL_ENDL; // region is apparently not capable of this; don't respond at all + // (there shouldn't be any regions where this is the case... but + LL_INFOS("ENVIRONMENT") << "No legacy windlight caps... just set the region to be the default day." << LL_ENDL; + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_REGION, LLSettingsDay::GetDefaultAssetId()); return false; } std::string coroname = LLCoros::instance().launch("LLEnvironmentRequest::environmentRequestCoro", - boost::bind(&LLEnvironmentRequest::environmentRequestCoro, url)); + [url, cb]() { LLEnvironmentRequest::environmentRequestCoro(url, cb); }); LL_INFOS("WindlightCaps") << "Requesting region windlight settings via " << url << LL_ENDL; return true; @@ -93,7 +96,7 @@ bool LLEnvironmentRequest::doRequest() S32 LLEnvironmentRequest::sLastRequest = 0; //static -void LLEnvironmentRequest::environmentRequestCoro(std::string url) +void LLEnvironmentRequest::environmentRequestCoro(std::string url, LLEnvironment::environment_apply_fn cb) { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); S32 requestId = ++LLEnvironmentRequest::sLastRequest; @@ -103,6 +106,8 @@ void LLEnvironmentRequest::environmentRequestCoro(std::string url) LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + LL_WARNS("WindlightCaps") << "Using legacy Windlight caps." << LL_ENDL; + if (requestId != LLEnvironmentRequest::sLastRequest) { LL_INFOS("WindlightCaps") << "Got superseded by another responder; ignoring..." << LL_ENDL; @@ -114,11 +119,12 @@ void LLEnvironmentRequest::environmentRequestCoro(std::string url) if (!status) { LL_WARNS("WindlightCaps") << "Got an error, not using region windlight... " << LL_ENDL; - LLEnvManagerNew::getInstance()->onRegionSettingsResponse(LLSD()); + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_REGION, LLSettingsDay::GetDefaultAssetId()); + return; } result = result["content"]; - LL_INFOS("WindlightCaps") << "Received region windlight settings" << LL_ENDL; + LL_INFOS("WindlightCaps") << "Received region legacy windlight settings" << LL_ENDL; LLUUID regionId; if (gAgent.getRegion()) @@ -134,7 +140,12 @@ void LLEnvironmentRequest::environmentRequestCoro(std::string url) return; } - LLEnvManagerNew::getInstance()->onRegionSettingsResponse(result); + if (cb) + { + LLEnvironment::EnvironmentInfo::ptr_t pinfo = LLEnvironment::EnvironmentInfo::extractLegacy(result); + + cb(INVALID_PARCEL_ID, pinfo); + } } @@ -146,7 +157,7 @@ clock_t LLEnvironmentApply::UPDATE_WAIT_SECONDS = clock_t(3.f); clock_t LLEnvironmentApply::sLastUpdate = clock_t(0.f); // static -bool LLEnvironmentApply::initiateRequest(const LLSD& content) +bool LLEnvironmentApply::initiateRequest(const LLSD& content, LLEnvironment::environment_apply_fn cb) { clock_t current = clock(); @@ -162,7 +173,7 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content) sLastUpdate = current; // Send update request. - std::string url = gAgent.getRegionCapability("EnvironmentSettings"); + std::string url = gAgent.getRegionCapability("ExtEnvironment"); if (url.empty()) { LL_WARNS("WindlightCaps") << "Applying windlight settings not supported" << LL_ENDL; @@ -174,11 +185,11 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content) std::string coroname = LLCoros::instance().launch("LLEnvironmentApply::environmentApplyCoro", - boost::bind(&LLEnvironmentApply::environmentApplyCoro, url, content)); + [url, content, cb]() { LLEnvironmentApply::environmentApplyCoro(url, content, cb); }); return true; } -void LLEnvironmentApply::environmentApplyCoro(std::string url, LLSD content) +void LLEnvironmentApply::environmentApplyCoro(std::string url, LLSD content, LLEnvironment::environment_apply_fn cb) { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t @@ -242,13 +253,11 @@ void LLEnvironmentApply::environmentApplyCoro(std::string url, LLSD content) } LL_DEBUGS("WindlightCaps") << "Success in applying windlight settings to region " << result["regionID"].asUUID() << LL_ENDL; - LLEnvManagerNew::instance().onRegionSettingsApplyResponse(true); } while (false); if (!notify.isUndefined()) { LLNotificationsUtil::add("WLRegionApplyFail", notify); - LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false); } } diff --git a/indra/newview/llwlhandlers.h b/indra/newview/llwlhandlers.h index eb2bbf9553..b09d2df60f 100644 --- a/indra/newview/llwlhandlers.h +++ b/indra/newview/llwlhandlers.h @@ -29,19 +29,20 @@ #include "llviewerprecompiledheaders.h" #include "llcoros.h" +#include "llenvironment.h" class LLEnvironmentRequest { LOG_CLASS(LLEnvironmentRequest); public: /// @return true if request was successfully sent - static bool initiate(); + static bool initiate(LLEnvironment::environment_apply_fn cb); private: - static void onRegionCapsReceived(const LLUUID& region_id); - static bool doRequest(); + static void onRegionCapsReceived(const LLUUID& region_id, LLEnvironment::environment_apply_fn cb); + static bool doRequest(LLEnvironment::environment_apply_fn cb); - static void environmentRequestCoro(std::string url); + static void environmentRequestCoro(std::string url, LLEnvironment::environment_apply_fn cb); static S32 sLastRequest; }; @@ -51,13 +52,15 @@ class LLEnvironmentApply LOG_CLASS(LLEnvironmentApply); public: /// @return true if request was successfully sent - static bool initiateRequest(const LLSD& content); + static bool initiateRequest(const LLSD& content, LLEnvironment::environment_apply_fn cb); private: static clock_t sLastUpdate; static clock_t UPDATE_WAIT_SECONDS; - static void environmentApplyCoro(std::string url, LLSD content); + static void environmentApplyCoro(std::string url, LLSD content, LLEnvironment::environment_apply_fn cb); }; + + #endif // LL_LLWLHANDLERS_H diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp deleted file mode 100644 index 4b4393b07b..0000000000 --- a/indra/newview/llwlparammanager.cpp +++ /dev/null @@ -1,710 +0,0 @@ -/** - * @file llwlparammanager.cpp - * @brief Implementation for the LLWLParamManager class. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llwlparammanager.h" - -#include "pipeline.h" -#include "llsky.h" - -#include "lldiriterator.h" -#include "llfloaterreg.h" -#include "llsliderctrl.h" -#include "llspinctrl.h" -#include "llcheckboxctrl.h" -#include "lluictrlfactory.h" -#include "llviewercamera.h" -#include "llcombobox.h" -#include "lllineeditor.h" -#include "llsdserialize.h" - -#include "v4math.h" -#include "llviewerdisplay.h" -#include "llviewercontrol.h" -#include "llviewerwindow.h" -#include "lldrawpoolwater.h" -#include "llagent.h" -#include "llviewerregion.h" - -#include "llwlparamset.h" -#include "llpostprocess.h" - -#include "llviewershadermgr.h" -#include "llglslshader.h" - -#include "curl/curl.h" -#include "llstreamtools.h" - -LLWLParamManager::LLWLParamManager() : - - //set the defaults for the controls - - /// Sun Delta Terrain tweak variables. - mSunDeltaYaw(180.0f), - mSceneLightStrength(2.0f), - mWLGamma(1.0f, "gamma"), - - mBlueHorizon(0.25f, 0.25f, 1.0f, 1.0f, "blue_horizon", "WLBlueHorizon"), - mHazeDensity(1.0f, "haze_density"), - mBlueDensity(0.25f, 0.25f, 0.25f, 1.0f, "blue_density", "WLBlueDensity"), - mDensityMult(1.0f, "density_multiplier", 1000), - mHazeHorizon(1.0f, "haze_horizon"), - mMaxAlt(4000.0f, "max_y"), - - // Lighting - mLightnorm(0.f, 0.707f, -0.707f, 1.f, "lightnorm"), - mSunlight(0.5f, 0.5f, 0.5f, 1.0f, "sunlight_color", "WLSunlight"), - mAmbient(0.5f, 0.75f, 1.0f, 1.19f, "ambient", "WLAmbient"), - mGlow(18.0f, 0.0f, -0.01f, 1.0f, "glow"), - - // Clouds - mCloudColor(0.5f, 0.5f, 0.5f, 1.0f, "cloud_color", "WLCloudColor"), - mCloudMain(0.5f, 0.5f, 0.125f, 1.0f, "cloud_pos_density1"), - mCloudCoverage(0.0f, "cloud_shadow"), - mCloudDetail(0.0f, 0.0f, 0.0f, 1.0f, "cloud_pos_density2"), - mDistanceMult(1.0f, "distance_multiplier"), - mCloudScale(0.42f, "cloud_scale"), - - // sky dome - mDomeOffset(0.96f), - mDomeRadius(15000.f) -{ -} - -LLWLParamManager::~LLWLParamManager() -{ -} - -void LLWLParamManager::clearParamSetsOfScope(LLWLParamKey::EScope scope) -{ - if (LLWLParamKey::SCOPE_LOCAL == scope) - { - LL_WARNS("Windlight") << "Tried to clear windlight sky presets from local system! This shouldn't be called..." << LL_ENDL; - return; - } - - std::set<LLWLParamKey> to_remove; - for(std::map<LLWLParamKey, LLWLParamSet>::iterator iter = mParamList.begin(); iter != mParamList.end(); ++iter) - { - if(iter->first.scope == scope) - { - to_remove.insert(iter->first); - } - } - - for(std::set<LLWLParamKey>::iterator iter = to_remove.begin(); iter != to_remove.end(); ++iter) - { - mParamList.erase(*iter); - } -} - -// returns all skies referenced by the day cycle, with their final names -// side effect: applies changes to all internal structures! -std::map<LLWLParamKey, LLWLParamSet> LLWLParamManager::finalizeFromDayCycle(LLWLParamKey::EScope scope) -{ - LL_DEBUGS() << "mDay before finalizing:" << LL_ENDL; - { - for (std::map<F32, LLWLParamKey>::iterator iter = mDay.mTimeMap.begin(); iter != mDay.mTimeMap.end(); ++iter) - { - LLWLParamKey& key = iter->second; - LL_DEBUGS() << iter->first << "->" << key.name << LL_ENDL; - } - } - - std::map<LLWLParamKey, LLWLParamSet> final_references; - - // Move all referenced to desired scope, renaming if necessary - // First, save skies referenced - std::map<LLWLParamKey, LLWLParamSet> current_references; // all skies referenced by the day cycle, with their current names - // guard against skies with same name and different scopes - std::set<std::string> inserted_names; - std::map<std::string, unsigned int> conflicted_names; // integer later used as a count, for uniquely renaming conflicts - - LLWLDayCycle& cycle = mDay; - for(std::map<F32, LLWLParamKey>::iterator iter = cycle.mTimeMap.begin(); - iter != cycle.mTimeMap.end(); - ++iter) - { - LLWLParamKey& key = iter->second; - std::string desired_name = key.name; - replace_newlines_with_whitespace(desired_name); // already shouldn't have newlines, but just in case - if(inserted_names.find(desired_name) == inserted_names.end()) - { - inserted_names.insert(desired_name); - } - else - { - // make exist in map - conflicted_names[desired_name] = 0; - } - current_references[key] = mParamList[key]; - } - - // forget all old skies in target scope, and rebuild, renaming as needed - clearParamSetsOfScope(scope); - for(std::map<LLWLParamKey, LLWLParamSet>::iterator iter = current_references.begin(); iter != current_references.end(); ++iter) - { - const LLWLParamKey& old_key = iter->first; - - std::string desired_name(old_key.name); - replace_newlines_with_whitespace(desired_name); - - LLWLParamKey new_key(desired_name, scope); // name will be replaced later if necessary - - // if this sky is one with a non-unique name, rename via appending a number - // an existing preset of the target scope gets to keep its name - if (scope != old_key.scope && conflicted_names.find(desired_name) != conflicted_names.end()) - { - std::string& new_name = new_key.name; - - do - { - // if this executes more than once, this is an absurdly pathological case - // (e.g. "x" repeated twice, but "x 1" already exists, so need to use "x 2") - std::stringstream temp; - temp << desired_name << " " << (++conflicted_names[desired_name]); - new_name = temp.str(); - } while (inserted_names.find(new_name) != inserted_names.end()); - - // yay, found one that works - inserted_names.insert(new_name); // track names we consume here; shouldn't be necessary due to ++int? but just in case - - // *TODO factor out below into a rename()? - - LL_INFOS("Windlight") << "Renamed " << old_key.name << " (scope" << old_key.scope << ") to " - << new_key.name << " (scope " << new_key.scope << ")" << LL_ENDL; - - // update name in sky - iter->second.mName = new_name; - - // update keys in day cycle - for(std::map<F32, LLWLParamKey>::iterator frame = cycle.mTimeMap.begin(); frame != cycle.mTimeMap.end(); ++frame) - { - if (frame->second == old_key) - { - frame->second = new_key; - } - } - - // add to master sky map - mParamList[new_key] = iter->second; - } - - final_references[new_key] = iter->second; - } - - LL_DEBUGS() << "mDay after finalizing:" << LL_ENDL; - { - for (std::map<F32, LLWLParamKey>::iterator iter = mDay.mTimeMap.begin(); iter != mDay.mTimeMap.end(); ++iter) - { - LLWLParamKey& key = iter->second; - LL_DEBUGS() << iter->first << "->" << key.name << LL_ENDL; - } - } - - return final_references; -} - -// static -LLSD LLWLParamManager::createSkyMap(std::map<LLWLParamKey, LLWLParamSet> refs) -{ - LLSD skies = LLSD::emptyMap(); - for(std::map<LLWLParamKey, LLWLParamSet>::iterator iter = refs.begin(); iter != refs.end(); ++iter) - { - skies.insert(iter->first.name, iter->second.getAll()); - } - return skies; -} - -void LLWLParamManager::addAllSkies(const LLWLParamKey::EScope scope, const LLSD& sky_presets) -{ - 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; - } -} - -void LLWLParamManager::refreshRegionPresets(const LLSD& region_sky_presets) -{ - // Remove all region sky presets because they may belong to a previously visited region. - clearParamSetsOfScope(LLEnvKey::SCOPE_REGION); - - // Add all sky presets belonging to the current region. - addAllSkies(LLEnvKey::SCOPE_REGION, region_sky_presets); -} - -void LLWLParamManager::loadAllPresets() -{ - // First, load system (coming out of the box) sky presets. - loadPresetsFromDir(getSysDir()); - - // Then load user presets. Note that user day presets will modify any system ones already loaded. - loadPresetsFromDir(getUserDir()); -} - -void LLWLParamManager::loadPresetsFromDir(const std::string& dir) -{ - LL_INFOS("AppInit", "Shaders") << "Loading sky presets from " << dir << LL_ENDL; - - LLDirIterator dir_iter(dir, "*.xml"); - while (1) - { - std::string file; - if (!dir_iter.next(file)) - { - break; // no more files - } - - std::string path = gDirUtilp->add(dir, file); - if (!loadPreset(path)) - { - LL_WARNS() << "Error loading sky preset from " << path << LL_ENDL; - } - } -} - -bool LLWLParamManager::loadPreset(const std::string& path) -{ - llifstream xml_file; - std::string name(gDirUtilp->getBaseFileName(LLURI::unescape(path), /*strip_exten = */ true)); - - xml_file.open(path.c_str()); - if (!xml_file) - { - return false; - } - - LL_DEBUGS("AppInit", "Shaders") << "Loading sky " << name << LL_ENDL; - - LLSD params_data; - LLPointer<LLSDParser> parser = new LLSDXMLParser(); - parser->parse(xml_file, params_data, LLSDSerialize::SIZE_UNLIMITED); - xml_file.close(); - - LLWLParamKey key(name, LLEnvKey::SCOPE_LOCAL); - if (hasParamSet(key)) - { - setParamSet(key, params_data); - } - else - { - addParamSet(key, params_data); - } - - return true; -} - -void LLWLParamManager::savePreset(LLWLParamKey key) -{ - llassert(key.scope == LLEnvKey::SCOPE_LOCAL && !key.name.empty()); - - // make an empty llsd - LLSD paramsData(LLSD::emptyMap()); - std::string pathName(getUserDir() + escapeString(key.name) + ".xml"); - - // fill it with LLSD windlight params - paramsData = mParamList[key].getAll(); - - // write to file - llofstream presetsXML(pathName.c_str()); - LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter(); - formatter->format(paramsData, presetsXML, LLSDFormatter::OPTIONS_PRETTY); - presetsXML.close(); - - propagateParameters(); -} - -void LLWLParamManager::updateShaderUniforms(LLGLSLShader * shader) -{ - if (gPipeline.canUseWindLightShaders()) - { - mCurParams.update(shader); - } - - if (shader->mShaderGroup == LLGLSLShader::SG_DEFAULT) - { - shader->uniform4fv(LLShaderMgr::LIGHTNORM, 1, mRotatedLightDir.mV); - shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV); - } - - else if (shader->mShaderGroup == LLGLSLShader::SG_SKY) - { - shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, mClampedLightDir.mV); - } - - shader->uniform1f(LLShaderMgr::SCENE_LIGHT_STRENGTH, mSceneLightStrength); - -} - -static LLTrace::BlockTimerStatHandle FTM_UPDATE_WLPARAM("Update Windlight Params"); - -void LLWLParamManager::propagateParameters(void) -{ - LL_RECORD_BLOCK_TIME(FTM_UPDATE_WLPARAM); - - LLVector4 sunDir; - LLVector4 moonDir; - - // set the sun direction from SunAngle and EastAngle - F32 sinTheta = sin(mCurParams.getEastAngle()); - F32 cosTheta = cos(mCurParams.getEastAngle()); - - F32 sinPhi = sin(mCurParams.getSunAngle()); - F32 cosPhi = cos(mCurParams.getSunAngle()); - - sunDir.mV[0] = -sinTheta * cosPhi; - sunDir.mV[1] = sinPhi; - sunDir.mV[2] = cosTheta * cosPhi; - sunDir.mV[3] = 0; - - moonDir = -sunDir; - - // is the normal from the sun or the moon - if(sunDir.mV[1] >= 0) - { - mLightDir = sunDir; - } - else if(sunDir.mV[1] < 0 && sunDir.mV[1] > LLSky::NIGHTTIME_ELEVATION_COS) - { - // clamp v1 to 0 so sun never points up and causes weirdness on some machines - LLVector3 vec(sunDir.mV[0], sunDir.mV[1], sunDir.mV[2]); - vec.mV[1] = 0; - vec.normVec(); - mLightDir = LLVector4(vec, 0.f); - } - else - { - mLightDir = moonDir; - } - - // calculate the clamp lightnorm for sky (to prevent ugly banding in sky - // when haze goes below the horizon - mClampedLightDir = sunDir; - - if (mClampedLightDir.mV[1] < -0.1f) - { - mClampedLightDir.mV[1] = -0.1f; - } - - mCurParams.set("lightnorm", mLightDir); - - // bind the variables for all shaders only if we're using WindLight - LLViewerShaderMgr::shader_iter shaders_iter, end_shaders; - end_shaders = LLViewerShaderMgr::instance()->endShaders(); - for(shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter) - { - if (shaders_iter->mProgramObject != 0 - && (gPipeline.canUseWindLightShaders() - || shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER)) - { - shaders_iter->mUniformsDirty = TRUE; - } - } - - // get the cfr version of the sun's direction - LLVector3 cfrSunDir(sunDir.mV[2], sunDir.mV[0], sunDir.mV[1]); - - // set direction and don't allow overriding - gSky.setSunDirection(cfrSunDir, LLVector3(0,0,0)); - gSky.setOverrideSun(TRUE); -} - -void LLWLParamManager::update(LLViewerCamera * cam) -{ - LL_RECORD_BLOCK_TIME(FTM_UPDATE_WLPARAM); - - // update clouds, sun, and general - mCurParams.updateCloudScrolling(); - - // update only if running - if(mAnimator.getIsRunning()) - { - mAnimator.update(mCurParams); - } - - // update the shaders and the menu - propagateParameters(); - - F32 camYaw = cam->getYaw(); - - stop_glerror(); - - // *TODO: potential optimization - this block may only need to be - // executed some of the time. For example for water shaders only. - { - F32 camYawDelta = mSunDeltaYaw * DEG_TO_RAD; - - LLVector3 lightNorm3(mLightDir); - lightNorm3 *= LLQuaternion(-(camYaw + camYawDelta), LLVector3(0.f, 1.f, 0.f)); - mRotatedLightDir = LLVector4(lightNorm3, 0.f); - - LLViewerShaderMgr::shader_iter shaders_iter, end_shaders; - end_shaders = LLViewerShaderMgr::instance()->endShaders(); - for(shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter) - { - if (shaders_iter->mProgramObject != 0 - && (gPipeline.canUseWindLightShaders() - || shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER)) - { - shaders_iter->mUniformsDirty = TRUE; - } - } - } -} - -bool LLWLParamManager::applyDayCycleParams(const LLSD& params, LLEnvKey::EScope scope, F32 time) -{ - mDay.loadDayCycle(params, scope); - resetAnimator(time, true); // set to specified time and start animator - return true; -} - -void LLWLParamManager::setDefaultDay() -{ - mDay.loadDayCycleFromFile("Default.xml"); -} - -bool LLWLParamManager::applySkyParams(const LLSD& params) -{ - mAnimator.deactivate(); - mCurParams.setAll(params); - return true; -} - -void LLWLParamManager::setDefaultSky() -{ - getParamSet(LLWLParamKey("Default", LLWLParamKey::SCOPE_LOCAL), mCurParams); -} - - -void LLWLParamManager::resetAnimator(F32 curTime, bool run) -{ - mAnimator.setTrack(mDay.mTimeMap, mDay.mDayRate, - curTime, run); - - return; -} - -bool LLWLParamManager::addParamSet(const LLWLParamKey& key, LLWLParamSet& param) -{ - // add a new one if not one there already - std::map<LLWLParamKey, LLWLParamSet>::iterator mIt = mParamList.find(key); - if(mIt == mParamList.end()) - { - llassert(!key.name.empty()); - // *TODO: validate params - mParamList[key] = param; - mPresetListChangeSignal(); - return true; - } - - return false; -} - -BOOL LLWLParamManager::addParamSet(const LLWLParamKey& key, LLSD const & param) -{ - LLWLParamSet param_set; - param_set.setAll(param); - return addParamSet(key, param_set); -} - -bool LLWLParamManager::getParamSet(const LLWLParamKey& key, LLWLParamSet& param) -{ - // find it and set it - std::map<LLWLParamKey, LLWLParamSet>::iterator mIt = mParamList.find(key); - if(mIt != mParamList.end()) - { - param = mParamList[key]; - param.mName = key.name; - return true; - } - - return false; -} - -bool LLWLParamManager::hasParamSet(const LLWLParamKey& key) -{ - LLWLParamSet dummy; - return getParamSet(key, dummy); -} - -bool LLWLParamManager::setParamSet(const LLWLParamKey& key, LLWLParamSet& param) -{ - llassert(!key.name.empty()); - // *TODO: validate params - mParamList[key] = param; - - return true; -} - -bool LLWLParamManager::setParamSet(const LLWLParamKey& key, const LLSD & param) -{ - llassert(!key.name.empty()); - // *TODO: validate params - - // quick, non robust (we won't be working with files, but assets) check - // this might not actually be true anymore.... - if(!param.isMap()) - { - return false; - } - - LLWLParamSet param_set; - param_set.setAll(param); - return setParamSet(key, param_set); -} - -void LLWLParamManager::removeParamSet(const LLWLParamKey& key, bool delete_from_disk) -{ - // *NOTE: Removing a sky preset invalidates day cycles that refer to it. - - if (key.scope == LLEnvKey::SCOPE_REGION) - { - LL_WARNS() << "Removing region skies not supported" << LL_ENDL; - llassert(key.scope == LLEnvKey::SCOPE_LOCAL); - return; - } - - // remove from param list - std::map<LLWLParamKey, LLWLParamSet>::iterator it = mParamList.find(key); - if (it == mParamList.end()) - { - LL_WARNS("WindLight") << "No sky preset named " << key.name << LL_ENDL; - return; - } - - mParamList.erase(it); - mDay.removeReferencesTo(key); - - // remove from file system if requested - if (delete_from_disk) - { - std::string path_name(getUserDir()); - std::string escaped_name = escapeString(key.name); - - if(gDirUtilp->deleteFilesInDir(path_name, escaped_name + ".xml") < 1) - { - LL_WARNS("WindLight") << "Error removing sky preset " << key.name << " from disk" << LL_ENDL; - } - } - - // signal interested parties - mPresetListChangeSignal(); -} - -bool LLWLParamManager::isSystemPreset(const std::string& preset_name) const -{ - // *TODO: file system access is excessive here. - return gDirUtilp->fileExists(getSysDir() + escapeString(preset_name) + ".xml"); -} - -void LLWLParamManager::getPresetNames(preset_name_list_t& region, preset_name_list_t& user, preset_name_list_t& sys) const -{ - region.clear(); - user.clear(); - sys.clear(); - - for (std::map<LLWLParamKey, LLWLParamSet>::const_iterator it = mParamList.begin(); it != mParamList.end(); it++) - { - const LLWLParamKey& key = it->first; - const std::string& name = key.name; - - if (key.scope == LLEnvKey::SCOPE_REGION) - { - region.push_back(name); - } - else - { - if (isSystemPreset(name)) - { - sys.push_back(name); - } - else - { - user.push_back(name); - } - } - } -} - -void LLWLParamManager::getUserPresetNames(preset_name_list_t& user) const -{ - preset_name_list_t region, sys; // unused - getPresetNames(region, user, sys); -} - -void LLWLParamManager::getPresetKeys(preset_key_list_t& keys) const -{ - keys.clear(); - - for (std::map<LLWLParamKey, LLWLParamSet>::const_iterator it = mParamList.begin(); it != mParamList.end(); it++) - { - keys.push_back(it->first); - } -} - -boost::signals2::connection LLWLParamManager::setPresetListChangeCallback(const preset_list_signal_t::slot_type& cb) -{ - return mPresetListChangeSignal.connect(cb); -} - -// virtual static -void LLWLParamManager::initSingleton() -{ - LL_DEBUGS("Windlight") << "Initializing sky" << LL_ENDL; - - loadAllPresets(); - - // but use linden time sets it to what the estate is - mAnimator.setTimeType(LLWLAnimator::TIME_LINDEN); -} - -// static -std::string LLWLParamManager::getSysDir() -{ - return gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", ""); -} - -// static -std::string LLWLParamManager::getUserDir() -{ - return gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS , "windlight/skies", ""); -} - -// static -std::string LLWLParamManager::escapeString(const std::string& str) -{ - // Don't use LLURI::escape() because it doesn't encode '-' characters - // which may break handling of some system presets like "A-12AM". - char* curl_str = curl_escape(str.c_str(), str.size()); - std::string escaped_str(curl_str); - curl_free(curl_str); - - return escaped_str; -} diff --git a/indra/newview/llwlparammanager.h b/indra/newview/llwlparammanager.h deleted file mode 100644 index 61f86b747f..0000000000 --- a/indra/newview/llwlparammanager.h +++ /dev/null @@ -1,323 +0,0 @@ -/** - * @file llwlparammanager.h - * @brief Implementation for the LLWLParamManager class. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_WLPARAMMANAGER_H -#define LL_WLPARAMMANAGER_H - -#include <list> -#include <map> -#include "llwlparamset.h" -#include "llwlanimator.h" -#include "llwldaycycle.h" -#include "llviewercamera.h" -#include "lltrans.h" - -class LLGLSLShader; - -// color control -struct WLColorControl { - - F32 r, g, b, i; /// the values - std::string mName; /// name to use to dereference params - std::string mSliderName; /// name of the slider in menu - bool hasSliderName; /// only set slider name for true color types - bool isSunOrAmbientColor; /// flag for if it's the sun or ambient color controller - bool isBlueHorizonOrDensity; /// flag for if it's the Blue Horizon or Density color controller - - inline WLColorControl(F32 red, F32 green, F32 blue, F32 intensity, - const std::string& n, const std::string& sliderName = LLStringUtil::null) - : r(red), g(green), b(blue), i(intensity), mName(n), mSliderName(sliderName) - { - // if there's a slider name, say we have one - hasSliderName = false; - if (mSliderName != "") { - hasSliderName = true; - } - - // if it's the sun controller - isSunOrAmbientColor = false; - if (mSliderName == "WLSunlight" || mSliderName == "WLAmbient") { - isSunOrAmbientColor = true; - } - - isBlueHorizonOrDensity = false; - if (mSliderName == "WLBlueHorizon" || mSliderName == "WLBlueDensity") { - isBlueHorizonOrDensity = true; - } - } - - inline WLColorControl & operator = (LLVector4 const & val) { - r = val.mV[0]; - g = val.mV[1]; - b = val.mV[2]; - i = val.mV[3]; - return *this; - } - - inline operator LLVector4 (void) const { - return LLVector4(r, g, b, i); - } - - inline operator LLVector3 (void) const { - return LLVector3(r, g, b); - } - - inline void update(LLWLParamSet & params) const { - params.set(mName, r, g, b, i); - } -}; - -// float slider control -struct WLFloatControl { - F32 x; - std::string mName; - F32 mult; - - inline WLFloatControl(F32 val, const std::string& n, F32 m=1.0f) - : x(val), mName(n), mult(m) - { - } - - inline WLFloatControl & operator = (F32 val) { - x = val; - return *this; - } - - inline operator F32 (void) const { - return x; - } - - inline void update(LLWLParamSet & params) const { - params.set(mName, x); - } -}; - -/// WindLight parameter manager class - what controls all the wind light shaders -class LLWLParamManager : public LLSingleton<LLWLParamManager> -{ - LLSINGLETON(LLWLParamManager); - ~LLWLParamManager(); - LOG_CLASS(LLWLParamManager); - -public: - typedef std::list<std::string> preset_name_list_t; - typedef std::list<LLWLParamKey> preset_key_list_t; - typedef boost::signals2::signal<void()> preset_list_signal_t; - - /// save the parameter presets to file - void savePreset(const LLWLParamKey key); - - /// Set shader uniforms dirty, so they'll update automatically. - void propagateParameters(void); - - /// Update shader uniforms that have changed. - void updateShaderUniforms(LLGLSLShader * shader); - - /// setup the animator to run - void resetAnimator(F32 curTime, bool run); - - /// update information camera dependent parameters - void update(LLViewerCamera * cam); - - /// apply specified day cycle, setting time to noon by default - bool applyDayCycleParams(const LLSD& params, LLEnvKey::EScope scope, F32 time = 0.5); - - /// Apply Default.xml map - void setDefaultDay(); - - /// apply specified fixed sky params - bool applySkyParams(const LLSD& params); - - void setDefaultSky(); - - // get where the light is pointing - inline LLVector4 getLightDir(void) const; - - // get where the light is pointing - inline LLVector4 getClampedLightDir(void) const; - - // get where the light is pointing - inline LLVector4 getRotatedLightDir(void) const; - - /// get the dome's offset - inline F32 getDomeOffset(void) const; - - /// get the radius of the dome - inline F32 getDomeRadius(void) const; - - /// add a param set (preset) to the list - bool addParamSet(const LLWLParamKey& key, LLWLParamSet& param); - - /// add a param set (preset) to the list - BOOL addParamSet(const LLWLParamKey& key, LLSD const & param); - - /// get a param set (preset) from the list - bool getParamSet(const LLWLParamKey& key, LLWLParamSet& param); - - /// check whether the preset is in the list - bool hasParamSet(const LLWLParamKey& key); - - /// set the param in the list with a new param - bool setParamSet(const LLWLParamKey& key, LLWLParamSet& param); - - /// set the param in the list with a new param - bool setParamSet(const LLWLParamKey& key, LLSD const & param); - - /// gets rid of a parameter and any references to it - /// ignores "delete_from_disk" if the scope is not local - void removeParamSet(const LLWLParamKey& key, bool delete_from_disk); - - /// clear parameter mapping of a given scope - void clearParamSetsOfScope(LLEnvKey::EScope scope); - - /// @return true if the preset comes out of the box - bool isSystemPreset(const std::string& preset_name) const; - - /// @return user and system preset names as a single list - void getPresetNames(preset_name_list_t& region, preset_name_list_t& user, preset_name_list_t& sys) const; - - /// @return user preset names - void getUserPresetNames(preset_name_list_t& user) const; - - /// @return keys of all known presets - void getPresetKeys(preset_key_list_t& keys) const; - - /// Emitted when a preset gets added or deleted. - boost::signals2::connection setPresetListChangeCallback(const preset_list_signal_t::slot_type& cb); - - /// add all skies in LLSD using the given scope - void addAllSkies(LLEnvKey::EScope scope, const LLSD& preset_map); - - /// refresh region-scope presets - void refreshRegionPresets(const LLSD& region_sky_presets); - - // returns all skies referenced by the current day cycle (in mDay), with their final names - // side effect: applies changes to all internal structures! (trashes all unreferenced skies in scope, keys in day cycle rescoped to scope, etc.) - std::map<LLWLParamKey, LLWLParamSet> finalizeFromDayCycle(LLWLParamKey::EScope scope); - - // returns all skies in map (intended to be called with output from a finalize) - static LLSD createSkyMap(std::map<LLWLParamKey, LLWLParamSet> map); - - /// escape string in a way different from LLURI::escape() - static std::string escapeString(const std::string& str); - - // helper variables - LLWLAnimator mAnimator; - - /// actual direction of the sun - LLVector4 mLightDir; - - /// light norm adjusted so haze works correctly - LLVector4 mRotatedLightDir; - - /// clamped light norm for shaders that - /// are adversely affected when the sun goes below the - /// horizon - LLVector4 mClampedLightDir; - - // list of params and how they're cycled for days - LLWLDayCycle mDay; - - LLWLParamSet mCurParams; - - /// Sun Delta Terrain tweak variables. - F32 mSunDeltaYaw; - WLFloatControl mWLGamma; - - F32 mSceneLightStrength; - - /// Atmospherics - WLColorControl mBlueHorizon; - WLFloatControl mHazeDensity; - WLColorControl mBlueDensity; - WLFloatControl mDensityMult; - WLFloatControl mHazeHorizon; - WLFloatControl mMaxAlt; - - /// Lighting - WLColorControl mLightnorm; - WLColorControl mSunlight; - WLColorControl mAmbient; - WLColorControl mGlow; - - /// Clouds - WLColorControl mCloudColor; - WLColorControl mCloudMain; - WLFloatControl mCloudCoverage; - WLColorControl mCloudDetail; - WLFloatControl mDistanceMult; - WLFloatControl mCloudScale; - - /// sky dome - F32 mDomeOffset; - F32 mDomeRadius; - - -private: - - friend class LLWLAnimator; - - void loadAllPresets(); - void loadPresetsFromDir(const std::string& dir); - bool loadPreset(const std::string& path); - - static std::string getSysDir(); - static std::string getUserDir(); - - /*virtual*/ void initSingleton(); - // list of all the parameters, listed by name - std::map<LLWLParamKey, LLWLParamSet> mParamList; - - preset_list_signal_t mPresetListChangeSignal; -}; - -inline F32 LLWLParamManager::getDomeOffset(void) const -{ - return mDomeOffset; -} - -inline F32 LLWLParamManager::getDomeRadius(void) const -{ - return mDomeRadius; -} - -inline LLVector4 LLWLParamManager::getLightDir(void) const -{ - return mLightDir; -} - -inline LLVector4 LLWLParamManager::getClampedLightDir(void) const -{ - return mClampedLightDir; -} - -inline LLVector4 LLWLParamManager::getRotatedLightDir(void) const -{ - return mRotatedLightDir; -} - -#endif - diff --git a/indra/newview/llwlparamset.cpp b/indra/newview/llwlparamset.cpp deleted file mode 100644 index 986f167d8d..0000000000 --- a/indra/newview/llwlparamset.cpp +++ /dev/null @@ -1,423 +0,0 @@ -/** - * @file llwlparamset.cpp - * @brief Implementation for the LLWLParamSet class. - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llwlparamset.h" -#include "llwlanimator.h" - -#include "llwlparammanager.h" -#include "llglslshader.h" -#include "lluictrlfactory.h" -#include "llsliderctrl.h" -#include "pipeline.h" - -#include <llgl.h> - -#include <sstream> - -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 LLTrace::BlockTimerStatHandle FTM_WL_PARAM_UPDATE("WL Param Update"); - -void LLWLParamSet::update(LLGLSLShader * shader) const -{ - LL_RECORD_BLOCK_TIME(FTM_WL_PARAM_UPDATE); - LLSD::map_const_iterator i = mParamValues.beginMap(); - std::vector<LLStaticHashedString>::const_iterator n = mParamHashedNames.begin(); - for(;(i != mParamValues.endMap()) && (n != mParamHashedNames.end());++i, n++) - { - const LLStaticHashedString& param = *n; - - // 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 == sCloudDensity) - { - LLVector4 val; - val.mV[0] = F32(i->second[0].asReal()) + mCloudScrollXOffset; - val.mV[1] = F32(i->second[1].asReal()) + mCloudScrollYOffset; - val.mV[2] = (F32) i->second[2].asReal(); - val.mV[3] = (F32) i->second[3].asReal(); - - stop_glerror(); - shader->uniform4fv(param, 1, val.mV); - stop_glerror(); - } - else if (param == sCloudScale || param == sCloudShadow || - param == sDensityMultiplier || param == sDistanceMultiplier || - param == sHazeDensity || param == sHazeHorizon || - param == sMaxY ) - { - 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) - { - 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); - stop_glerror(); - } - else if (i->second.isReal()) - { - F32 val = (F32) i->second.asReal(); - - stop_glerror(); - shader->uniform1f(param, val); - stop_glerror(); - } - else if (i->second.isInteger()) - { - S32 val = (S32) i->second.asInteger(); - - stop_glerror(); - shader->uniform1i(param, val); - stop_glerror(); - } - else if (i->second.isBoolean()) - { - S32 val = (i->second.asBoolean() ? 1 : 0); - - stop_glerror(); - shader->uniform1i(param, val); - stop_glerror(); - } - } - } - - if (LLPipeline::sRenderDeferred && !LLPipeline::sReflectionRender && !LLPipeline::sUnderWaterRender) - { - shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 2.2); - } else { - shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 1.0); - } -} - -void LLWLParamSet::set(const std::string& paramName, float x) -{ - // handle case where no array - if(mParamValues[paramName].isReal()) - { - mParamValues[paramName] = x; - } - - // handle array - else if(mParamValues[paramName].isArray() && - mParamValues[paramName][0].isReal()) - { - mParamValues[paramName][0] = x; - } -} - -void LLWLParamSet::set(const std::string& paramName, float x, float y) -{ - mParamValues[paramName][0] = x; - mParamValues[paramName][1] = y; -} - -void LLWLParamSet::set(const std::string& paramName, float x, float y, float z) -{ - mParamValues[paramName][0] = x; - mParamValues[paramName][1] = y; - mParamValues[paramName][2] = z; -} - -void LLWLParamSet::set(const std::string& paramName, float x, float y, float z, float w) -{ - mParamValues[paramName][0] = x; - mParamValues[paramName][1] = y; - mParamValues[paramName][2] = z; - mParamValues[paramName][3] = w; -} - -void LLWLParamSet::set(const std::string& paramName, const float * val) -{ - mParamValues[paramName][0] = val[0]; - mParamValues[paramName][1] = val[1]; - mParamValues[paramName][2] = val[2]; - mParamValues[paramName][3] = val[3]; -} - -void LLWLParamSet::set(const std::string& paramName, const LLVector4 & val) -{ - mParamValues[paramName][0] = val.mV[0]; - mParamValues[paramName][1] = val.mV[1]; - mParamValues[paramName][2] = val.mV[2]; - mParamValues[paramName][3] = val.mV[3]; -} - -void LLWLParamSet::set(const std::string& paramName, const LLColor4 & val) -{ - mParamValues[paramName][0] = val.mV[0]; - mParamValues[paramName][1] = val.mV[1]; - mParamValues[paramName][2] = val.mV[2]; - mParamValues[paramName][3] = val.mV[3]; -} - -LLVector4 LLWLParamSet::getVector(const std::string& paramName, bool& error) -{ - // test to see if right type - LLSD cur_val = mParamValues.get(paramName); - if (!cur_val.isArray()) - { - error = true; - return LLVector4(0,0,0,0); - } - - LLVector4 val; - val.mV[0] = (F32) cur_val[0].asReal(); - val.mV[1] = (F32) cur_val[1].asReal(); - val.mV[2] = (F32) cur_val[2].asReal(); - val.mV[3] = (F32) cur_val[3].asReal(); - - error = false; - return val; -} - -F32 LLWLParamSet::getFloat(const std::string& paramName, bool& error) -{ - // test to see if right type - LLSD cur_val = mParamValues.get(paramName); - if (cur_val.isArray() && cur_val.size() != 0) - { - error = false; - return (F32) cur_val[0].asReal(); - } - - if(cur_val.isReal()) - { - error = false; - return (F32) cur_val.asReal(); - } - - error = true; - return 0; -} - -void LLWLParamSet::setSunAngle(float val) -{ - // keep range 0 - 2pi - if(val > F_TWO_PI || val < 0) - { - F32 num = val / F_TWO_PI; - num -= floor(num); - val = F_TWO_PI * num; - } - - mParamValues["sun_angle"] = val; -} - - -void LLWLParamSet::setEastAngle(float val) -{ - // keep range 0 - 2pi - if(val > F_TWO_PI || val < 0) - { - F32 num = val / F_TWO_PI; - num -= floor(num); - val = F_TWO_PI * num; - } - - mParamValues["east_angle"] = val; -} - -void LLWLParamSet::mix(LLWLParamSet& src, LLWLParamSet& dest, F32 weight) -{ - // set up the iterators - - // keep cloud positions and coverage the same - /// TODO masking will do this later - F32 cloudPos1X = (F32) mParamValues["cloud_pos_density1"][0].asReal(); - 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(); - - LLSD srcVal; - LLSD destVal; - - // Iterate through values - for(LLSD::map_iterator iter = mParamValues.beginMap(); iter != mParamValues.endMap(); ++iter) - { - // If param exists in both src and dest, set the holder variables, otherwise skip - if(src.mParamValues.has(iter->first) && dest.mParamValues.has(iter->first)) - { - srcVal = src.mParamValues[iter->first]; - destVal = dest.mParamValues[iter->first]; - } - else - { - continue; - } - - if(iter->second.isReal()) // If it's a real, interpolate directly - { - iter->second = srcVal.asReal() + ((destVal.asReal() - srcVal.asReal()) * weight); - } - else if(iter->second.isArray() && iter->second[0].isReal() // If it's an array of reals, loop through the reals and interpolate on those - && iter->second.size() == srcVal.size() && iter->second.size() == destVal.size()) - { - // Actually do interpolation: old value + (difference in values * factor) - for(int i=0; i < iter->second.size(); ++i) - { - // iter->second[i] = (1.f-weight)*(F32)srcVal[i].asReal() + weight*(F32)destVal[i].asReal(); // old way of doing it -- equivalent but one more operation - iter->second[i] = srcVal[i].asReal() + ((destVal[i].asReal() - srcVal[i].asReal()) * weight); - } - } - else // Else, skip - { - continue; - } - } - - // now mix the extra parameters - setStarBrightness((1 - weight) * (F32) src.getStarBrightness() - + weight * (F32) dest.getStarBrightness()); - - // FIXME: we have established that this assert fails - // frequently. Someone who understands the code needs to figure - // out if it matters. In the meantime, disabling the checks so we - // can stop interfering with other development. - - //llassert(src.getSunAngle() >= - F_PI && - // src.getSunAngle() <= 3 * F_PI); - //llassert(dest.getSunAngle() >= - F_PI && - // dest.getSunAngle() <= 3 * F_PI); - //llassert(src.getEastAngle() >= 0 && - // src.getEastAngle() <= 4 * F_PI); - //llassert(dest.getEastAngle() >= 0 && - // dest.getEastAngle() <= 4 * F_PI); - - // sun angle and east angle require some handling to make sure - // they go in circles. Yes quaternions would work better. - F32 srcSunAngle = src.getSunAngle(); - F32 destSunAngle = dest.getSunAngle(); - F32 srcEastAngle = src.getEastAngle(); - F32 destEastAngle = dest.getEastAngle(); - - if(fabsf(srcSunAngle - destSunAngle) > F_PI) - { - if(srcSunAngle > destSunAngle) - { - destSunAngle += 2 * F_PI; - } - else - { - srcSunAngle += 2 * F_PI; - } - } - - if(fabsf(srcEastAngle - destEastAngle) > F_PI) - { - if(srcEastAngle > destEastAngle) - { - destEastAngle += 2 * F_PI; - } - else - { - srcEastAngle += 2 * F_PI; - } - } - - setSunAngle((1 - weight) * srcSunAngle + weight * destSunAngle); - setEastAngle((1 - weight) * srcEastAngle + weight * destEastAngle); - - // 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; -} - -void LLWLParamSet::updateCloudScrolling(void) -{ - static LLTimer s_cloud_timer; - - F64 delta_t = s_cloud_timer.getElapsedTimeAndResetF64(); - - if(getEnableCloudScrollX()) - { - mCloudScrollXOffset += F32(delta_t * (getCloudScrollX() - 10.f) / 100.f); - } - if(getEnableCloudScrollY()) - { - 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) - { - mParamHashedNames.push_back(LLStaticHashedString(iter->first)); - } -} - diff --git a/indra/newview/llwlparamset.h b/indra/newview/llwlparamset.h deleted file mode 100644 index 6e5f1d3a4b..0000000000 --- a/indra/newview/llwlparamset.h +++ /dev/null @@ -1,246 +0,0 @@ -/** - * @file llwlparamset.h - * @brief Interface for the LLWLParamSet class. - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_WLPARAM_SET_H -#define LL_WLPARAM_SET_H - -#include <string> -#include <map> -#include <vector> - -#include "v4math.h" -#include "v4color.h" -#include "llstaticstringtable.h" - -class LLWLParamSet; -class LLGLSLShader; - -/// A class representing a set of parameter values for the WindLight shaders. -class LLWLParamSet { - - friend class LLWLParamManager; - -public: - std::string mName; - -private: - - LLSD mParamValues; - std::vector<LLStaticHashedString> mParamHashedNames; - - float mCloudScrollXOffset, mCloudScrollYOffset; - - void updateHashedNames(); - -public: - - LLWLParamSet(); - - /// Update this set of shader uniforms from the parameter values. - void update(LLGLSLShader * shader) const; - - /// set the total llsd - void setAll(const LLSD& val); - - /// get the total llsd - const LLSD& getAll(); - - - /// Set a float parameter. - /// \param paramName The name of the parameter to set. - /// \param x The float value to set. - void set(const std::string& paramName, float x); - - /// Set a float2 parameter. - /// \param paramName The name of the parameter to set. - /// \param x The x component's value to set. - /// \param y The y component's value to set. - void set(const std::string& paramName, float x, float y); - - /// Set a float3 parameter. - /// \param paramName The name of the parameter to set. - /// \param x The x component's value to set. - /// \param y The y component's value to set. - /// \param z The z component's value to set. - void set(const std::string& paramName, float x, float y, float z); - - /// Set a float4 parameter. - /// \param paramName The name of the parameter to set. - /// \param x The x component's value to set. - /// \param y The y component's value to set. - /// \param z The z component's value to set. - /// \param w The w component's value to set. - void set(const std::string& paramName, float x, float y, float z, float w); - - /// Set a float4 parameter. - /// \param paramName The name of the parameter to set. - /// \param val An array of the 4 float values to set the parameter to. - void set(const std::string& paramName, const float * val); - - /// Set a float4 parameter. - /// \param paramName The name of the parameter to set. - /// \param val A struct of the 4 float values to set the parameter to. - void set(const std::string& paramName, const LLVector4 & val); - - /// Set a float4 parameter. - /// \param paramName The name of the parameter to set. - /// \param val A struct of the 4 float values to set the parameter to. - void set(const std::string& paramName, const LLColor4 & val); - - /// Get a float4 parameter. - /// \param paramName The name of the parameter to set. - /// \param error A flag to set if it's not the proper return type - LLVector4 getVector(const std::string& paramName, bool& error); - - /// Get a float parameter - /// \param paramName The name of the parameter to set. - /// \param error A flag to set if it's not the proper return type - F32 getFloat(const std::string& paramName, bool& error); - - - // specific getters and setters - - - /// set the star's brightness - /// \param val brightness value - void setStarBrightness(F32 val); - - /// get the star brightness value; - F32 getStarBrightness(); - - void setSunAngle(F32 val); - F32 getSunAngle(); - - void setEastAngle(F32 val); - F32 getEastAngle(); - - - - /// set the cloud scroll x enable value - /// \param val scroll x value - void setEnableCloudScrollX(bool val); - - /// get the scroll x enable value; - bool getEnableCloudScrollX(); - - /// set the star's brightness - /// \param val scroll y bool value - void setEnableCloudScrollY(bool val); - - /// get the scroll enable y value; - bool getEnableCloudScrollY(); - - /// set the cloud scroll x enable value - /// \param val scroll x value - void setCloudScrollX(F32 val); - - /// get the scroll x enable value; - F32 getCloudScrollX(); - - /// set the star's brightness - /// \param val scroll y bool value - void setCloudScrollY(F32 val); - - /// get the scroll enable y value; - F32 getCloudScrollY(); - - /// interpolate two parameter sets - /// \param src The parameter set to start with - /// \param dest The parameter set to end with - /// \param weight The amount to interpolate - void mix(LLWLParamSet& src, LLWLParamSet& dest, - F32 weight); - - void updateCloudScrolling(void); -}; - -inline void LLWLParamSet::setAll(const LLSD& val) -{ - if(val.isMap()) { - mParamValues = val; - } - - updateHashedNames(); -} - -inline const LLSD& LLWLParamSet::getAll() -{ - return mParamValues; -} - -inline void LLWLParamSet::setStarBrightness(float val) { - mParamValues["star_brightness"] = val; -} - -inline F32 LLWLParamSet::getStarBrightness() { - return (F32) mParamValues["star_brightness"].asReal(); -} - -inline F32 LLWLParamSet::getSunAngle() { - return (F32) mParamValues["sun_angle"].asReal(); -} - -inline F32 LLWLParamSet::getEastAngle() { - return (F32) mParamValues["east_angle"].asReal(); -} - - -inline void LLWLParamSet::setEnableCloudScrollX(bool val) { - mParamValues["enable_cloud_scroll"][0] = val; -} - -inline bool LLWLParamSet::getEnableCloudScrollX() { - return mParamValues["enable_cloud_scroll"][0].asBoolean(); -} - -inline void LLWLParamSet::setEnableCloudScrollY(bool val) { - mParamValues["enable_cloud_scroll"][1] = val; -} - -inline bool LLWLParamSet::getEnableCloudScrollY() { - return mParamValues["enable_cloud_scroll"][1].asBoolean(); -} - - -inline void LLWLParamSet::setCloudScrollX(F32 val) { - mParamValues["cloud_scroll_rate"][0] = val; -} - -inline F32 LLWLParamSet::getCloudScrollX() { - return (F32) mParamValues["cloud_scroll_rate"][0].asReal(); -} - -inline void LLWLParamSet::setCloudScrollY(F32 val) { - mParamValues["cloud_scroll_rate"][1] = val; -} - -inline F32 LLWLParamSet::getCloudScrollY() { - return (F32) mParamValues["cloud_scroll_rate"][1].asReal(); -} - - -#endif // LL_WLPARAM_SET_H - diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 89f5eb86b3..a1a1db35d6 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -730,11 +730,20 @@ void LLWorld::updateRegions(F32 max_update_time) { //perform some necessary but very light updates. (*iter)->lightIdleUpdate(); - } + } + } + + if(max_time > 0.f) + { + max_time = llmin((F32)(max_update_time - update_timer.getElapsedTimeF32()), max_update_time * 0.25f); + } + if(max_time > 0.f) + { + LLViewerRegion::idleCleanup(max_time); } sample(sNumActiveCachedObjects, mNumOfActiveCachedObjects); - } +} void LLWorld::clearAllVisibleObjects() { @@ -873,6 +882,57 @@ void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_heigh } } +void LLWorld::precullWaterObjects(LLCamera& camera, LLCullResult* cull, bool include_void_water) +{ + if (!gAgent.getRegion()) + { + return; + } + + if (mRegionList.empty()) + { + LL_WARNS() << "No regions!" << LL_ENDL; + return; + } + + for (region_list_t::iterator iter = mRegionList.begin(); + iter != mRegionList.end(); ++iter) + { + LLViewerRegion* regionp = *iter; + LLVOWater* waterp = regionp->getLand().getWaterObj(); + if (waterp && waterp->mDrawable) + { + waterp->mDrawable->setVisible(camera); + cull->pushDrawable(waterp->mDrawable); + } + } + + if (include_void_water) + { + for (std::list<LLPointer<LLVOWater> >::iterator iter = mHoleWaterObjects.begin(); + iter != mHoleWaterObjects.end(); ++ iter) + { + LLVOWater* waterp = (*iter).get(); + if (waterp && waterp->mDrawable) + { + waterp->mDrawable->setVisible(camera); + cull->pushDrawable(waterp->mDrawable); + } + } + } + + S32 dir; + for (dir = 0; dir < 8; dir++) + { + LLVOWater* waterp = mEdgeWaterObjects[dir]; + if (waterp && waterp->mDrawable) + { + waterp->mDrawable->setVisible(camera); + cull->pushDrawable(waterp->mDrawable); + } + } +} + void LLWorld::updateWaterObjects() { if (!gAgent.getRegion()) @@ -1157,11 +1217,14 @@ public: } }; +static LLTrace::BlockTimerStatHandle FTM_DISABLE_REGION("Disable Region"); // disable the circuit to this simulator // Called in response to "DisableSimulator" message. void process_disable_simulator(LLMessageSystem *mesgsys, void **user_data) -{ - LLHost host = mesgsys->getSender(); +{ + LL_RECORD_BLOCK_TIME(FTM_DISABLE_REGION); + + LLHost host = mesgsys->getSender(); //LL_INFOS() << "Disabling simulator with message from " << host << LL_ENDL; LLWorld::getInstance()->removeRegion(host); diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h index 993fbfb2cc..98552bc4d1 100644 --- a/indra/newview/llworld.h +++ b/indra/newview/llworld.h @@ -138,6 +138,9 @@ public: LLViewerTexture *getDefaultWaterTexture(); void updateWaterObjects(); + + void precullWaterObjects(LLCamera& camera, LLCullResult* cull, bool include_void_water); + void waterHeightRegionInfo(std::string const& sim_name, F32 water_height); void shiftRegions(const LLVector3& offset); diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index ff1f95526e..70cb4f602a 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -1155,7 +1155,7 @@ void LLWorldMapView::drawAvatar(F32 x_pixels, { const F32 HEIGHT_THRESHOLD = 7.f; LLUIImagePtr dot_image = sAvatarLevelImage; - if (unknown_relative_z) + if (unknown_relative_z && llabs(relative_z) > HEIGHT_THRESHOLD) { dot_image = sAvatarUnknownImage; } @@ -1623,7 +1623,7 @@ BOOL LLWorldMapView::handleMouseUp( S32 x, S32 y, MASK mask ) LLRect clip_rect = getRect(); clip_rect.stretch(-8); clip_rect.clipPointToRect(mMouseDownX, mMouseDownY, local_x, local_y); - LLUI::setMousePositionLocal(this, local_x, local_y); + LLUI::getInstance()->setMousePositionLocal(this, local_x, local_y); // finish the pan mPanning = FALSE; diff --git a/indra/newview/llworldmipmap.cpp b/indra/newview/llworldmipmap.cpp index a2e519a61a..040d0deaf3 100644 --- a/indra/newview/llworldmipmap.cpp +++ b/indra/newview/llworldmipmap.cpp @@ -190,6 +190,8 @@ LLPointer<LLViewerFetchedTexture> LLWorldMipmap::loadObjectsTile(U32 grid_x, U32 //LL_INFOS("WorldMap") << "LLWorldMipmap::loadObjectsTile(), URL = " << imageurl << LL_ENDL; LLPointer<LLViewerFetchedTexture> img = LLViewerTextureManager::getFetchedTextureFromUrl(imageurl, FTT_MAP_TILE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + LL_INFOS("MAPURL") << "fetching map tile from " << imageurl << LL_ENDL; + img->setBoostLevel(LLGLTexture::BOOST_MAP); // Return the smart pointer diff --git a/indra/newview/llxmlrpclistener.cpp b/indra/newview/llxmlrpclistener.cpp index 7bc8af4a0b..bae615232e 100644 --- a/indra/newview/llxmlrpclistener.cpp +++ b/indra/newview/llxmlrpclistener.cpp @@ -43,6 +43,7 @@ // other Linden headers #include "llerror.h" +#include "lleventcoro.h" #include "stringize.h" #include "llxmlrpctransaction.h" #include "llsecapi.h" @@ -100,34 +101,17 @@ public: { // from curl.h // skip the "CURLE_" prefix for each of these strings -#define def(sym) (mMap[sym] = #sym + 6) +#define def(sym) (mMap[sym] = &#sym[6]) def(CURLE_OK); def(CURLE_UNSUPPORTED_PROTOCOL); /* 1 */ def(CURLE_FAILED_INIT); /* 2 */ def(CURLE_URL_MALFORMAT); /* 3 */ - def(CURLE_URL_MALFORMAT_USER); /* 4 - NOT USED */ def(CURLE_COULDNT_RESOLVE_PROXY); /* 5 */ def(CURLE_COULDNT_RESOLVE_HOST); /* 6 */ def(CURLE_COULDNT_CONNECT); /* 7 */ - def(CURLE_FTP_WEIRD_SERVER_REPLY); /* 8 */ - def(CURLE_FTP_ACCESS_DENIED); /* 9 a service was denied by the FTP server - due to lack of access - when login fails - this is not returned. */ - def(CURLE_FTP_USER_PASSWORD_INCORRECT); /* 10 - NOT USED */ - def(CURLE_FTP_WEIRD_PASS_REPLY); /* 11 */ - def(CURLE_FTP_WEIRD_USER_REPLY); /* 12 */ - def(CURLE_FTP_WEIRD_PASV_REPLY); /* 13 */ - def(CURLE_FTP_WEIRD_227_FORMAT); /* 14 */ - def(CURLE_FTP_CANT_GET_HOST); /* 15 */ - def(CURLE_FTP_CANT_RECONNECT); /* 16 */ - def(CURLE_FTP_COULDNT_SET_BINARY); /* 17 */ def(CURLE_PARTIAL_FILE); /* 18 */ - def(CURLE_FTP_COULDNT_RETR_FILE); /* 19 */ - def(CURLE_FTP_WRITE_ERROR); /* 20 */ - def(CURLE_FTP_QUOTE_ERROR); /* 21 */ def(CURLE_HTTP_RETURNED_ERROR); /* 22 */ def(CURLE_WRITE_ERROR); /* 23 */ - def(CURLE_MALFORMAT_USER); /* 24 - NOT USED */ def(CURLE_UPLOAD_FAILED); /* 25 - failed upload "command" */ def(CURLE_READ_ERROR); /* 26 - could open/read from file */ def(CURLE_OUT_OF_MEMORY); /* 27 */ @@ -135,29 +119,18 @@ public: instead of a memory allocation error if CURL_DOES_CONVERSIONS is defined */ - def(CURLE_OPERATION_TIMEOUTED); /* 28 - the timeout time was reached */ - def(CURLE_FTP_COULDNT_SET_ASCII); /* 29 - TYPE A failed */ - def(CURLE_FTP_PORT_FAILED); /* 30 - FTP PORT operation failed */ - def(CURLE_FTP_COULDNT_USE_REST); /* 31 - the REST command failed */ - def(CURLE_FTP_COULDNT_GET_SIZE); /* 32 - the SIZE command failed */ + def(CURLE_OPERATION_TIMEDOUT); /* 28 - the timeout time was reached */ def(CURLE_HTTP_RANGE_ERROR); /* 33 - RANGE "command" didn't work */ def(CURLE_HTTP_POST_ERROR); /* 34 */ def(CURLE_SSL_CONNECT_ERROR); /* 35 - wrong when connecting with SSL */ def(CURLE_BAD_DOWNLOAD_RESUME); /* 36 - couldn't resume download */ def(CURLE_FILE_COULDNT_READ_FILE); /* 37 */ - def(CURLE_LDAP_CANNOT_BIND); /* 38 */ - def(CURLE_LDAP_SEARCH_FAILED); /* 39 */ def(CURLE_LIBRARY_NOT_FOUND); /* 40 */ def(CURLE_FUNCTION_NOT_FOUND); /* 41 */ def(CURLE_ABORTED_BY_CALLBACK); /* 42 */ def(CURLE_BAD_FUNCTION_ARGUMENT); /* 43 */ - def(CURLE_BAD_CALLING_ORDER); /* 44 - NOT USED */ def(CURLE_INTERFACE_FAILED); /* 45 - CURLOPT_INTERFACE failed */ - def(CURLE_BAD_PASSWORD_ENTERED); /* 46 - NOT USED */ def(CURLE_TOO_MANY_REDIRECTS ); /* 47 - catch endless re-direct loops */ - def(CURLE_UNKNOWN_TELNET_OPTION); /* 48 - User specified an unknown option */ - def(CURLE_TELNET_OPTION_SYNTAX ); /* 49 - Malformed telnet option */ - def(CURLE_OBSOLETE); /* 50 - NOT USED */ def(CURLE_SSL_PEER_CERTIFICATE); /* 51 - peer's certificate wasn't ok */ def(CURLE_GOT_NOTHING); /* 52 - when this is a specific error */ def(CURLE_SSL_ENGINE_NOTFOUND); /* 53 - SSL crypto engine not found */ @@ -165,26 +138,19 @@ public: default */ def(CURLE_SEND_ERROR); /* 55 - failed sending network data */ def(CURLE_RECV_ERROR); /* 56 - failure in receiving network data */ - def(CURLE_SHARE_IN_USE); /* 57 - share is in use */ + def(CURLE_SSL_CERTPROBLEM); /* 58 - problem with the local certificate */ def(CURLE_SSL_CIPHER); /* 59 - couldn't use specified cipher */ def(CURLE_SSL_CACERT); /* 60 - problem with the CA cert (path?) */ def(CURLE_BAD_CONTENT_ENCODING); /* 61 - Unrecognized transfer encoding */ - def(CURLE_LDAP_INVALID_URL); /* 62 - Invalid LDAP URL */ + def(CURLE_FILESIZE_EXCEEDED); /* 63 - Maximum file size exceeded */ - def(CURLE_FTP_SSL_FAILED); /* 64 - Requested FTP SSL level failed */ + def(CURLE_SEND_FAIL_REWIND); /* 65 - Sending the data requires a rewind that failed */ def(CURLE_SSL_ENGINE_INITFAILED); /* 66 - failed to initialise ENGINE */ def(CURLE_LOGIN_DENIED); /* 67 - user); password or similar was not accepted and we failed to login */ - def(CURLE_TFTP_NOTFOUND); /* 68 - file not found on server */ - def(CURLE_TFTP_PERM); /* 69 - permission problem on server */ - def(CURLE_TFTP_DISKFULL); /* 70 - out of disk space on server */ - def(CURLE_TFTP_ILLEGAL); /* 71 - Illegal TFTP operation */ - def(CURLE_TFTP_UNKNOWNID); /* 72 - Unknown transfer ID */ - def(CURLE_TFTP_EXISTS); /* 73 - File already exists */ - def(CURLE_TFTP_NOSUCHUSER); /* 74 - No such user */ def(CURLE_CONV_FAILED); /* 75 - conversion failed */ def(CURLE_CONV_REQD); /* 76 - caller must register conversion callbacks using curl_easy_setopt options @@ -401,6 +367,8 @@ public: // whether successful or not, send reply on requested LLEventPump replyPump.post(data); + // need to wake up the loginCoro now + llcoro::suspend(); // Because mTransaction is a boost::scoped_ptr, deleting this object // frees our LLXMLRPCTransaction object. diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 8e2539606b..32c8ce66a0 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -240,16 +240,16 @@ void LLXMLRPCTransaction::Handler::onCompleted(LLCore::HttpHandle handle, if (!status) { + mImpl->setHttpStatus(status); + LLSD errordata = status.getErrorData(); + mImpl->mErrorCertData = errordata; + if ((status.toULong() != CURLE_SSL_PEER_CERTIFICATE) && (status.toULong() != CURLE_SSL_CACERT)) { // if we have a curl error that's not already been handled - // (a non cert error), then generate the error message as + // (a non cert error), then generate the warning message as // appropriate - mImpl->setHttpStatus(status); - LLSD errordata = status.getErrorData(); - mImpl->mErrorCertData = errordata; - LL_WARNS() << "LLXMLRPCTransaction error " << status.toHex() << ": " << status.toString() << LL_ENDL; LL_WARNS() << "LLXMLRPCTransaction request URI: " diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index bd73c234a6..cd1b9c7c69 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -88,6 +88,7 @@ #include "llvocache.h" #include "llvoground.h" #include "llvosky.h" +#include "llvowlsky.h" #include "llvotree.h" #include "llvovolume.h" #include "llvosurfacepatch.h" @@ -100,8 +101,6 @@ #include "llviewerstats.h" #include "llviewerjoystick.h" #include "llviewerdisplay.h" -#include "llwlparammanager.h" -#include "llwaterparammanager.h" #include "llspatialpartition.h" #include "llmutelist.h" #include "lltoolpie.h" @@ -116,6 +115,9 @@ #include "llprogressview.h" #include "llcleanup.h" +#include "llenvironment.h" +#include "llsettingsvo.h" + #ifdef _DEBUG // Debug indices is disabled for now for debug performance - djs 4/24/02 //#define DEBUG_INDICES @@ -127,11 +129,20 @@ // #define MATERIALS_IN_REFLECTIONS 0 +// NOTE: Keep in sync with indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml +// NOTE: Unused consts are commented out since some compilers (on macOS) may complain about unused variables. +// const S32 WATER_REFLECT_NONE_WATER_OPAQUE = -2; + const S32 WATER_REFLECT_NONE_WATER_TRANSPARENT = -1; + const S32 WATER_REFLECT_MINIMAL = 0; +// const S32 WATER_REFLECT_TERRAIN = 1; + const S32 WATER_REFLECT_STATIC_OBJECTS = 2; + const S32 WATER_REFLECT_AVATARS = 3; + const S32 WATER_REFLECT_EVERYTHING = 4; + bool gShiftFrame = false; //cached settings bool LLPipeline::RenderAvatarVP; -bool LLPipeline::VertexShaderEnable; bool LLPipeline::WindLightUseAtmosShaders; bool LLPipeline::RenderDeferred; F32 LLPipeline::RenderDeferredSunWash; @@ -187,6 +198,7 @@ F32 LLPipeline::RenderShadowOffset; F32 LLPipeline::RenderShadowBias; F32 LLPipeline::RenderSpotShadowOffset; F32 LLPipeline::RenderSpotShadowBias; +LLDrawable* LLPipeline::RenderSpotLight = nullptr; F32 LLPipeline::RenderEdgeDepthCutoff; F32 LLPipeline::RenderEdgeNormCutoff; LLVector3 LLPipeline::RenderShadowGaussian; @@ -209,6 +221,7 @@ LLTrace::EventStatHandle<S64> LLPipeline::sStatBatchSize("renderbatchsize"); const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f; const F32 BACKLIGHT_NIGHT_MAGNITUDE_OBJECT = 0.08f; +const F32 DEFERRED_LIGHT_FALLOFF = 0.5f; const U32 DEFERRED_VB_MASK = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1; extern S32 gBoxFrame; @@ -253,6 +266,11 @@ LLTrace::BlockTimerStatHandle FTM_PIPELINE("Pipeline"); LLTrace::BlockTimerStatHandle FTM_CLIENT_COPY("Client Copy"); LLTrace::BlockTimerStatHandle FTM_RENDER_DEFERRED("Deferred Shading"); +LLTrace::BlockTimerStatHandle FTM_RENDER_UI_HUD("HUD"); +LLTrace::BlockTimerStatHandle FTM_RENDER_UI_3D("3D"); +LLTrace::BlockTimerStatHandle FTM_RENDER_UI_2D("2D"); +LLTrace::BlockTimerStatHandle FTM_RENDER_UI_DEBUG_TEXT("Debug Text"); +LLTrace::BlockTimerStatHandle FTM_RENDER_UI_SCENE_MON("Scene Mon"); static LLTrace::BlockTimerStatHandle FTM_STATESORT_DRAWABLE("Sort Drawables"); static LLTrace::BlockTimerStatHandle FTM_STATESORT_POSTSORT("Post Sort"); @@ -298,62 +316,6 @@ 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() -{ - return glh_copy_matrix(gGLModelView); -} - -glh::matrix4f glh_get_current_projection() -{ - return glh_copy_matrix(gGLProjection); -} - -glh::matrix4f glh_get_last_modelview() -{ - return glh_copy_matrix(gGLLastModelView); -} - -glh::matrix4f glh_get_last_projection() -{ - return glh_copy_matrix(gGLLastProjection); -} - -void glh_copy_matrix(const glh::matrix4f& src, F32* dst) -{ - for (U32 i = 0; i < 16; i++) - { - dst[i] = src.m[i]; - } -} - -void glh_set_current_modelview(const glh::matrix4f& mat) -{ - glh_copy_matrix(mat, gGLModelView); -} - -void glh_set_current_projection(glh::matrix4f& mat) -{ - glh_copy_matrix(mat, gGLProjection); -} - -glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar) -{ - 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; -} - void display_update_camera(); //---------------------------------------- @@ -377,6 +339,7 @@ bool LLPipeline::sDelayVBUpdate = true; bool LLPipeline::sAutoMaskAlphaDeferred = true; bool LLPipeline::sAutoMaskAlphaNonDeferred = false; bool LLPipeline::sDisableShaders = false; +bool LLPipeline::sRenderTransparentWater = true; bool LLPipeline::sRenderBump = true; bool LLPipeline::sBakeSunlight = false; bool LLPipeline::sNoAlpha = false; @@ -386,6 +349,7 @@ bool LLPipeline::sShadowRender = false; bool LLPipeline::sWaterReflections = false; bool LLPipeline::sRenderGlow = false; bool LLPipeline::sReflectionRender = false; +bool LLPipeline::sDistortionRender = false; bool LLPipeline::sImpostorRender = false; bool LLPipeline::sImpostorRenderAlphaDepthPass = false; bool LLPipeline::sUnderWaterRender = false; @@ -394,10 +358,10 @@ bool LLPipeline::sRenderFrameTest = false; bool LLPipeline::sRenderAttachedLights = true; bool LLPipeline::sRenderAttachedParticles = true; bool LLPipeline::sRenderDeferred = false; -bool LLPipeline::sMemAllocationThrottled = false; S32 LLPipeline::sVisibleLightCount = 0; F32 LLPipeline::sMinRenderSize = 0.f; bool LLPipeline::sRenderingHUDs; +F32 LLPipeline::sDistortionWaterClipPlaneMargin = 1.0125f; // EventHost API LLPipeline listener. static LLPipelineListener sPipelineListener; @@ -456,6 +420,11 @@ LLPipeline::LLPipeline() : mNoiseMap = 0; mTrueNoiseMap = 0; mLightFunc = 0; + + for(U32 i = 0; i < 8; i++) + { + mHWLightColors[i] = LLColor4::black; + } } void LLPipeline::connectRefreshCachedSettingsSafe(const std::string name) @@ -572,7 +541,6 @@ void LLPipeline::init() connectRefreshCachedSettingsSafe("RenderAvatarMaxNonImpostors"); connectRefreshCachedSettingsSafe("RenderDelayVBUpdate"); connectRefreshCachedSettingsSafe("UseOcclusion"); - connectRefreshCachedSettingsSafe("VertexShaderEnable"); connectRefreshCachedSettingsSafe("RenderAvatarVP"); connectRefreshCachedSettingsSafe("WindLightUseAtmosShaders"); connectRefreshCachedSettingsSafe("RenderDeferred"); @@ -759,22 +727,21 @@ void LLPipeline::destroyGL() static LLTrace::BlockTimerStatHandle FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture"); -//static -void LLPipeline::throttleNewMemoryAllocation(bool disable) +void LLPipeline::requestResizeScreenTexture() { - if(sMemAllocationThrottled != disable) - { - sMemAllocationThrottled = disable ; + gResizeScreenTexture = TRUE; +} - if(sMemAllocationThrottled) - { - //send out notification - LLNotification::Params params("LowMemory"); - LLNotifications::instance().add(params); +void LLPipeline::requestResizeShadowTexture() +{ + gResizeShadowTexture = TRUE; +} - //release some memory. - } - } +void LLPipeline::resizeShadowTexture() +{ + releaseShadowTargets(); + allocateShadowBuffer(mScreenWidth, mScreenHeight); + gResizeShadowTexture = FALSE; } void LLPipeline::resizeScreenTexture() @@ -785,25 +752,14 @@ void LLPipeline::resizeScreenTexture() GLuint resX = gViewerWindow->getWorldViewWidthRaw(); GLuint resY = gViewerWindow->getWorldViewHeightRaw(); - if ((resX != mScreen.getWidth()) || (resY != mScreen.getHeight())) + if (gResizeScreenTexture || (resX != mScreen.getWidth()) || (resY != mScreen.getHeight())) { releaseScreenBuffers(); - if (!allocateScreenBuffer(resX,resY)) - { -#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(); - + releaseShadowTargets(); + allocateScreenBuffer(resX,resY); + gResizeScreenTexture = FALSE; } -#endif } - } - } } void LLPipeline::allocatePhysicsBuffer() @@ -973,23 +929,78 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) mDeferredLight.release(); } - F32 scale = RenderShadowResolutionScale; + allocateShadowBuffer(resX, resY); + + //HACK make screenbuffer allocations start failing after 30 seconds + if (gSavedSettings.getBOOL("SimulateFBOFailure")) + { + return false; + } + } + else + { + mDeferredLight.release(); + + releaseShadowTargets(); + + mFXAABuffer.release(); + mScreen.release(); + mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first + mDeferredDepth.release(); + mOcclusionDepth.release(); + + if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; + } + + if (LLPipeline::sRenderDeferred) + { //share depth buffer between deferred targets + mDeferredScreen.shareDepthBuffer(mScreen); + } + + gGL.getTexUnit(0)->disable(); + + stop_glerror(); + + return true; +} + +// must be even to avoid a stripe in the horizontal shadow blur +inline U32 BlurHappySize(U32 x, F32 scale) { return U32( x * scale + 16.0f) & ~0xF; } + +bool LLPipeline::allocateShadowBuffer(U32 resX, U32 resY) +{ + refreshCachedSettings(); + + if (LLPipeline::sRenderDeferred) + { + S32 shadow_detail = RenderShadowDetail; + + const U32 occlusion_divisor = 3; + + F32 scale = llmax(0.f,RenderShadowResolutionScale); + U32 sun_shadow_map_width = BlurHappySize(resX, scale); + U32 sun_shadow_map_height = BlurHappySize(resY, scale); if (shadow_detail > 0) { //allocate 4 sun shadow maps - 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_TEXTURE)) return false; - if (!mShadowOcclusion[i].allocate(mShadow[i].getWidth()/occlusion_divisor, mShadow[i].getHeight()/occlusion_divisor, 0, TRUE, FALSE, LLTexUnit::TT_TEXTURE)) return false; + if (!mShadow[i].allocate(sun_shadow_map_width, sun_shadow_map_height, 0, TRUE, FALSE, LLTexUnit::TT_TEXTURE)) + { + return false; + } + + if (!mShadowOcclusion[i].allocate(sun_shadow_map_width/occlusion_divisor, sun_shadow_map_height/occlusion_divisor, 0, TRUE, FALSE, LLTexUnit::TT_TEXTURE)) + { + return false; + } } } else { for (U32 i = 0; i < 4; i++) { - mShadow[i].release(); - mShadowOcclusion[i].release(); + releaseShadowTarget(i); } } @@ -999,83 +1010,57 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) if (shadow_detail > 1) { //allocate two spot shadow maps U32 spot_shadow_map_width = width; + U32 spot_shadow_map_height = height; for (U32 i = 4; i < 6; i++) { - if (!mShadow[i].allocate(spot_shadow_map_width, height, 0, TRUE, FALSE)) return false; - if (!mShadowOcclusion[i].allocate(mShadow[i].getWidth()/occlusion_divisor, mShadow[i].getHeight()/occlusion_divisor, 0, TRUE, FALSE)) return false; - } - } - else + if (!mShadow[i].allocate(spot_shadow_map_width, spot_shadow_map_height, 0, TRUE, FALSE)) { - for (U32 i = 4; i < 6; i++) - { - mShadow[i].release(); - mShadowOcclusion[i].release(); + return false; } - } - - //HACK make screenbuffer allocations start failing after 30 seconds - if (gSavedSettings.getBOOL("SimulateFBOFailure")) + if (!mShadowOcclusion[i].allocate(spot_shadow_map_width/occlusion_divisor, height/occlusion_divisor, 0, TRUE, FALSE)) { return false; } } + } else { - mDeferredLight.release(); - - for (U32 i = 0; i < 6; i++) + for (U32 i = 4; i < 6; i++) { - mShadow[i].release(); - mShadowOcclusion[i].release(); + releaseShadowTarget(i); } - mFXAABuffer.release(); - mScreen.release(); - mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first - mDeferredDepth.release(); - mOcclusionDepth.release(); - - if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; } - - if (LLPipeline::sRenderDeferred) - { //share depth buffer between deferred targets - mDeferredScreen.shareDepthBuffer(mScreen); } - gGL.getTexUnit(0)->disable(); - - stop_glerror(); - return true; } //static +void LLPipeline::updateRenderTransparentWater() +{ + sRenderTransparentWater = gSavedSettings.getBOOL("RenderTransparentWater"); +} + +//static void LLPipeline::updateRenderBump() { sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); } -//static +// static void LLPipeline::updateRenderDeferred() { - bool deferred = (bool(RenderDeferred && - LLRenderTarget::sUseFBO && - LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && - LLPipeline::sRenderBump && - VertexShaderEnable && - RenderAvatarVP && - WindLightUseAtmosShaders)) && - !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; - } + sRenderDeferred = !gUseWireframe && + RenderDeferred && + LLRenderTarget::sUseFBO && + LLPipeline::sRenderBump && + LLPipeline::sRenderTransparentWater && + RenderAvatarVP && + WindLightUseAtmosShaders && + (bool) LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred"); } -//static +// static void LLPipeline::refreshCachedSettings() { LLPipeline::sAutoMaskAlphaDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaDeferred"); @@ -1092,7 +1077,6 @@ void LLPipeline::refreshCachedSettings() && gSavedSettings.getBOOL("UseOcclusion") && gGLManager.mHasOcclusionQuery) ? 2 : 0; - VertexShaderEnable = gSavedSettings.getBOOL("VertexShaderEnable"); RenderAvatarVP = gSavedSettings.getBOOL("RenderAvatarVP"); WindLightUseAtmosShaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders"); RenderDeferred = gSavedSettings.getBOOL("RenderDeferred"); @@ -1167,7 +1151,7 @@ void LLPipeline::refreshCachedSettings() CameraMaxCoF = gSavedSettings.getF32("CameraMaxCoF"); CameraDoFResScale = gSavedSettings.getF32("CameraDoFResScale"); RenderAutoHideSurfaceAreaLimit = gSavedSettings.getF32("RenderAutoHideSurfaceAreaLimit"); - + RenderSpotLight = nullptr; updateRenderDeferred(); } @@ -1191,6 +1175,7 @@ void LLPipeline::releaseGLBuffers() mWaterRef.release(); mWaterDis.release(); + mBake.release(); mHighlight.release(); for (U32 i = 0; i < 3; i++) @@ -1213,6 +1198,11 @@ void LLPipeline::releaseLUTBuffers() } } +void LLPipeline::releaseShadowBuffers() +{ + releaseShadowTargets(); +} + void LLPipeline::releaseScreenBuffers() { mUIScreen.release(); @@ -1223,72 +1213,59 @@ void LLPipeline::releaseScreenBuffers() mDeferredDepth.release(); mDeferredLight.release(); mOcclusionDepth.release(); +} + +void LLPipeline::releaseShadowTarget(U32 index) +{ + mShadow[index].release(); + mShadowOcclusion[index].release(); +} + +void LLPipeline::releaseShadowTargets() +{ for (U32 i = 0; i < 6; i++) { - mShadow[i].release(); - mShadowOcclusion[i].release(); + releaseShadowTarget(i); } } - 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); - - // 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); - } + mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE,LLTexUnit::TT_TEXTURE); } + // Use FBO for bake tex + mBake.allocate(512, 512, GL_RGBA, TRUE, FALSE, LLTexUnit::TT_TEXTURE, true); // SL-12781 Build > Upload > Model; 3D Preview + mHighlight.allocate(256,256,GL_RGBA, FALSE, FALSE); stop_glerror(); GLuint resX = gViewerWindow->getWorldViewWidthRaw(); GLuint resY = gViewerWindow->getWorldViewHeightRaw(); - - if (LLPipeline::sRenderGlow) - { //screen space glow buffers - const U32 glow_res = llmax(1, - llmin(512, 1 << gSavedSettings.getS32("RenderGlowResolutionPow"))); - for (U32 i = 0; i < 3; i++) - { - mGlow[i].allocate(512,glow_res,GL_RGBA,FALSE,FALSE); - } + // allocate screen space glow buffers + const U32 glow_res = llmax(1, llmin(512, 1 << gSavedSettings.getS32("RenderGlowResolutionPow"))); + for (U32 i = 0; i < 3; i++) + { + mGlow[i].allocate(512, glow_res, GL_RGBA, FALSE, FALSE); + } - allocateScreenBuffer(resX,resY); - mScreenWidth = 0; - mScreenHeight = 0; - } - - if (sRenderDeferred) - { + allocateScreenBuffer(resX, resY); + mScreenWidth = 0; + mScreenHeight = 0; + + if (sRenderDeferred) + { if (!mNoiseMap) { const U32 noiseRes = 128; @@ -1416,12 +1393,9 @@ void LLPipeline::restoreGL() 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; @@ -1436,13 +1410,13 @@ bool LLPipeline::canUseWindLightShaders() const { return (!LLPipeline::sDisableShaders && gWLSkyProgram.mProgramObject != 0 && - LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1); + LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1); } bool LLPipeline::canUseWindLightShadersOnObjects() const { return (canUseWindLightShaders() - && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0); + && LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0); } bool LLPipeline::canUseAntiAliasing() const @@ -1471,7 +1445,7 @@ void LLPipeline::enableShadows(const bool enable_shadows) S32 LLPipeline::getMaxLightingDetail() const { - /*if (mVertexShaderLevel[SHADER_OBJECT] >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS) + /*if (mShaderLevel[SHADER_OBJECT] >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS) { return 3; } @@ -1624,6 +1598,7 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0) break; case LLDrawPool::POOL_AVATAR: + case LLDrawPool::POOL_CONTROL_AV: break; // Do nothing case LLDrawPool::POOL_SKY: @@ -2010,7 +1985,7 @@ void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list) drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED); if (done) { - if (drawablep->isRoot()) + if (drawablep->isRoot() && !drawablep->isState(LLDrawable::ACTIVE)) { drawablep->makeStatic(); } @@ -2158,7 +2133,8 @@ void check_references(LLSpatialGroup* group, LLDrawable* drawable) { for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { - if (drawable == (LLDrawable*)(*i)->getDrawable()) + LLDrawable* drawablep = (LLDrawable*)(*i)->getDrawable(); + if (drawable == drawablep) { LL_ERRS() << "LLDrawable deleted while actively reference by LLPipeline." << LL_ENDL; } @@ -2299,7 +2275,7 @@ void LLPipeline::checkReferences(LLDrawInfo* draw_info) void LLPipeline::checkReferences(LLSpatialGroup* group) { -#if 0 +#if CHECK_PIPELINE_REFERENCES if (sCull) { for (LLCullResult::sg_iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) @@ -2409,15 +2385,11 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl sCull->clear(); - bool to_texture = LLPipeline::sUseOcclusion > 1 && - !hasRenderType(LLPipeline::RENDER_TYPE_HUD) && - LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && - gPipeline.canUseVertexShaders() && - sRenderGlow; + bool to_texture = LLPipeline::sUseOcclusion > 1 && gPipeline.canUseVertexShaders(); if (to_texture) { - if (LLPipeline::sRenderDeferred) + if (LLPipeline::sRenderDeferred && can_use_occlusion) { mOcclusionDepth.bindTarget(); } @@ -2444,38 +2416,6 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl LLGLDisable test(GL_ALPHA_TEST); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - //setup a clip plane in projection matrix for reflection renders (prevents flickering from occlusion culling) - LLViewerRegion* region = gAgent.getRegion(); - LLPlane plane; - - if (planep) - { - plane = *planep; - } - else - { - if (region) - { - LLVector3 pnorm; - F32 height = region->getWaterHeight(); - if (water_clip < 0) - { //camera is above water, clip plane points up - pnorm.setVec(0,0,1); - plane.setVec(pnorm, -height); - } - else if (water_clip > 0) - { //camera is below water, clip plane points down - pnorm = LLVector3(0,0,-1); - plane.setVec(pnorm, height); - } - } - } - - glh::matrix4f modelview = glh_get_last_modelview(); - glh::matrix4f 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; @@ -2495,19 +2435,15 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); } + if (!sReflectionRender) + { + camera.disableUserClipPlane(); + } + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) { LLViewerRegion* region = *iter; - if (water_clip != 0) - { - LLPlane plane(LLVector3(0,0, (F32) -water_clip), (F32) water_clip*region->getWaterHeight()); - camera.setUserClipPlane(plane); - } - else - { - camera.disableUserClipPlane(); - } for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) { @@ -2526,6 +2462,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl if(vo_part) { bool do_occlusion_cull = can_use_occlusion && use_occlusion && !gUseWireframe && 0 > water_clip /* && !gViewerWindow->getProgressView()->getVisible()*/; + do_occlusion_cull &= !sReflectionRender; vo_part->cull(camera, do_occlusion_cull); } } @@ -2535,8 +2472,6 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl gOcclusionCubeProgram.unbind(); } - camera.disableUserClipPlane(); - if (hasRenderType(LLPipeline::RENDER_TYPE_SKY) && gSky.mVOSkyp.notNull() && gSky.mVOSkyp->mDrawable.notNull()) @@ -2558,6 +2493,22 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl } + if (hasRenderType(LLPipeline::RENDER_TYPE_WL_SKY) && + gPipeline.canUseWindLightShaders() && + gSky.mVOWLSkyp.notNull() && + gSky.mVOWLSkyp->mDrawable.notNull()) + { + gSky.mVOWLSkyp->mDrawable->setVisible(camera); + sCull->pushDrawable(gSky.mVOWLSkyp->mDrawable); + } + + bool render_water = !sReflectionRender && (hasRenderType(LLPipeline::RENDER_TYPE_WATER) || hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER)); + + if (render_water) + { + LLWorld::getInstance()->precullWaterObjects(camera, sCull, render_water); + } + gGL.matrixMode(LLRender::MM_PROJECTION); gGL.popMatrix(); gGL.matrixMode(LLRender::MM_MODELVIEW); @@ -2570,7 +2521,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl if (to_texture) { - if (LLPipeline::sRenderDeferred) + if (LLPipeline::sRenderDeferred && can_use_occlusion) { mOcclusionDepth.flush(); } @@ -3123,9 +3074,10 @@ void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera) if (vobj) // this test may not be needed, see above { LLVOAvatar* av = vobj->asAvatar(); - if (av && (av->isImpostor() - || av->isInMuteList() - || (LLVOAvatar::AV_DO_NOT_RENDER == av->getVisualMuteSettings() && !av->needsImpostorUpdate()) )) + if (av && + ((!sImpostorRender && av->isImpostor()) //ignore impostor flag during impostor pass + || av->isInMuteList() + || (LLVOAvatar::AOA_JELLYDOLL == av->getOverallAppearance() && !av->needsImpostorUpdate()) )) { return; } @@ -3401,6 +3353,7 @@ static LLTrace::BlockTimerStatHandle FTM_RESET_DRAWORDER("Reset Draw Order"); void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) { if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_CONTROL_AV, LLPipeline::RENDER_TYPE_GROUND, LLPipeline::RENDER_TYPE_TERRAIN, LLPipeline::RENDER_TYPE_TREE, @@ -3432,7 +3385,8 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) group->setVisible(); for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { - markVisible((LLDrawable*)(*i)->getDrawable(), camera); + LLDrawable* drawablep = (LLDrawable*)(*i)->getDrawable(); + markVisible(drawablep, camera); } if (!sDelayVBUpdate) @@ -3520,7 +3474,8 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) { for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { - stateSort((LLDrawable*)(*i)->getDrawable(), camera); + LLDrawable* drawablep = (LLDrawable*)(*i)->getDrawable(); + stateSort(drawablep, camera); } if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) @@ -3549,6 +3504,14 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) return; } + // SL-11353 + // ignore our own geo when rendering spotlight shadowmaps... + // + if (RenderSpotLight && drawablep == RenderSpotLight) + { + return; + } + if (LLSelectMgr::getInstance()->mHideSelectedObjects) { if (drawablep->getVObj().notNull() && @@ -4062,6 +4025,7 @@ void LLPipeline::postSort(LLCamera& camera) void render_hud_elements() { + LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); gPipeline.disableLights(); LLGLDisable fog(GL_FOG); @@ -4139,12 +4103,13 @@ void LLPipeline::renderHighlights() glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); - if (canUseVertexShaders()) + gGL.setColorMask(false, false); + + if (LLGLSLShader::sNoFixedFunction) { gHighlightProgram.bind(); } - gGL.setColorMask(false, false); for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ++iter) { renderHighlight(iter->mItem->getVObj(), 1.f); @@ -4226,7 +4191,7 @@ void LLPipeline::renderHighlights() //gGL.setSceneBlendType(LLRender::BT_ALPHA); } - if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) + if ((LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) { gHighlightProgram.bind(); gGL.diffuseColor4f(1,1,1,0.5f); @@ -4273,7 +4238,7 @@ void LLPipeline::renderHighlights() // have touch-handlers. mHighlightFaces.clear(); - if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0) + if (LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0) { gHighlightProgram.unbind(); } @@ -4282,7 +4247,7 @@ void LLPipeline::renderHighlights() if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED) && (sRenderHighlightTextureChannel == LLRender::NORMAL_MAP)) { color.setVec(1.0f, 0.5f, 0.5f, 0.5f); - if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) + if ((LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) { gHighlightNormalProgram.bind(); gGL.diffuseColor4f(1,1,1,0.5f); @@ -4303,7 +4268,7 @@ void LLPipeline::renderHighlights() facep->renderSelected(mFaceSelectImagep, color); } - if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) + if ((LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) { gHighlightNormalProgram.unbind(); } @@ -4312,7 +4277,7 @@ void LLPipeline::renderHighlights() if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED) && (sRenderHighlightTextureChannel == LLRender::SPECULAR_MAP)) { color.setVec(0.0f, 0.3f, 1.0f, 0.8f); - if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) + if ((LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) { gHighlightSpecularProgram.bind(); gGL.diffuseColor4f(1,1,1,0.5f); @@ -4333,7 +4298,7 @@ void LLPipeline::renderHighlights() facep->renderSelected(mFaceSelectImagep, color); } - if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) + if ((LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) { gHighlightSpecularProgram.unbind(); } @@ -4560,6 +4525,7 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate) // Render debugging beacons. gObjectList.renderObjectBeacons(); gObjectList.resetObjectBeacons(); + gSky.addSunMoonBeacons(); } else { @@ -4680,6 +4646,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) } gGLLastMatrix = NULL; + gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.loadMatrix(gGLModelView); gGL.setColorMask(true, false); @@ -4766,16 +4733,16 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion) } gGLLastMatrix = NULL; + gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.loadMatrix(gGLModelView); if (occlude) { occlude = false; - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); LLGLSLShader::bindNoShader(); doOcclusion(camera); gGLLastMatrix = NULL; + gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.loadMatrix(gGLModelView); } } @@ -5799,6 +5766,7 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) break; case LLDrawPool::POOL_AVATAR: + case LLDrawPool::POOL_CONTROL_AV: break; // Do nothing case LLDrawPool::POOL_SKY: @@ -5947,6 +5915,7 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) break; case LLDrawPool::POOL_AVATAR: + case LLDrawPool::POOL_CONTROL_AV: break; // Do nothing case LLDrawPool::POOL_SKY: @@ -5990,6 +5959,12 @@ void LLPipeline::setupAvatarLights(bool for_edit) { assertInitialized(); + LLEnvironment& environment = LLEnvironment::instance(); + LLSettingsSky::ptr_t psky = environment.getCurrentSky(); + + bool sun_up = environment.getIsSunUp(); + + if (for_edit) { LLColor4 diffuse(1.f, 1.f, 1.f, 0.f); @@ -6003,13 +5978,6 @@ void LLPipeline::setupAvatarLights(bool for_edit) LLLightState* light = gGL.getLight(1); - if (LLPipeline::sRenderDeferred) - { - /*diffuse.mV[0] = powf(diffuse.mV[0], 2.2f); - diffuse.mV[1] = powf(diffuse.mV[1], 2.2f); - diffuse.mV[2] = powf(diffuse.mV[2], 2.2f);*/ - } - mHWLightColors[1] = diffuse; light->setDiffuse(diffuse); @@ -6024,12 +5992,14 @@ void LLPipeline::setupAvatarLights(bool for_edit) } else if (gAvatarBacklight) // Always true (unless overridden in a devs .ini) { - LLVector3 opposite_pos = -1.f * mSunDir; - LLVector3 orthog_light_pos = mSunDir % LLVector3::z_axis; + LLVector3 light_dir = sun_up ? LLVector3(mSunDir) : LLVector3(mMoonDir); + LLVector3 opposite_pos = -light_dir; + LLVector3 orthog_light_pos = light_dir % LLVector3::z_axis; LLVector4 backlight_pos = LLVector4(lerp(opposite_pos, orthog_light_pos, 0.3f), 0.0f); backlight_pos.normalize(); - LLColor4 light_diffuse = mSunDiffuse; + LLColor4 light_diffuse = sun_up ? mSunDiffuse : mMoonDiffuse; + LLColor4 backlight_diffuse(1.f - light_diffuse.mV[VRED], 1.f - light_diffuse.mV[VGREEN], 1.f - light_diffuse.mV[VBLUE], 1.f); F32 max_component = 0.001f; for (S32 i = 0; i < 3; i++) @@ -6040,7 +6010,7 @@ void LLPipeline::setupAvatarLights(bool for_edit) } } F32 backlight_mag; - if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS) + if (LLEnvironment::instance().getIsSunUp()) { backlight_mag = BACKLIGHT_DAY_MAGNITUDE_OBJECT; } @@ -6050,13 +6020,6 @@ void LLPipeline::setupAvatarLights(bool for_edit) } backlight_diffuse *= backlight_mag / max_component; - if (LLPipeline::sRenderDeferred) - { - /*backlight_diffuse.mV[0] = powf(backlight_diffuse.mV[0], 2.2f); - backlight_diffuse.mV[1] = powf(backlight_diffuse.mV[1], 2.2f); - backlight_diffuse.mV[2] = powf(backlight_diffuse.mV[2], 2.2f);*/ - } - mHWLightColors[1] = backlight_diffuse; LLLightState* light = gGL.getLight(1); @@ -6090,25 +6053,18 @@ static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_ { return max_dist; } - F32 radius = light->getLightRadius(); bool selected = light->isSelected(); - LLVector3 dpos = light->getRenderPosition() - cam_pos; - F32 dist2 = dpos.lengthSquared(); - if (!selected && dist2 > (max_dist + radius)*(max_dist + radius)) - { - return max_dist; - } - F32 dist = (F32) sqrt(dist2); - dist *= 1.f / inten; - dist -= radius; if (selected) { - dist -= 10000.f; // selected lights get highest priority + return 0.f; // selected lights get highest priority } + F32 radius = light->getLightRadius(); + F32 dist = dist_vec(light->getRenderPosition(), cam_pos); + dist = llmax(dist - radius, 0.f); if (light->mDrawable.notNull() && light->mDrawable->isState(LLDrawable::ACTIVE)) { // moving lights get a little higher priority (too much causes artifacts) - dist -= light->getLightRadius()*0.25f; + dist = llmax(dist - light->getLightRadius()*0.25f, 0.f); } return dist; } @@ -6127,13 +6083,18 @@ void LLPipeline::calcNearbyLights(LLCamera& camera) // 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; -// LLVector3 cam_pos = gAgent.getCameraPositionAgent(); - LLVector3 cam_pos = LLViewerJoystick::getInstance()->getOverrideCamera() ? - camera.getOrigin() : - gAgent.getPositionAgent(); - - F32 max_dist = LIGHT_MAX_RADIUS * 4.f; // ignore enitrely lights > 4 * max light rad + LLVector3 cam_pos = camera.getOrigin(); + F32 max_dist; + if (LLPipeline::sRenderDeferred) + { + max_dist = RenderFarClip; + } + else + { + max_dist = llmin(RenderFarClip, LIGHT_MAX_RADIUS * 4.f); + } + // UPDATE THE EXISTING NEARBY LIGHTS light_set_t cur_nearby_lights; for (light_set_t::iterator iter = mNearbyLights.begin(); @@ -6167,8 +6128,38 @@ void LLPipeline::calcNearbyLights(LLCamera& camera) continue; } - F32 dist = calc_light_dist(volight, cam_pos, max_dist); - cur_nearby_lights.insert(Light(drawable, dist, light->fade)); + F32 dist = calc_light_dist(volight, cam_pos, max_dist); + F32 fade = light->fade; + // actual fade gets decreased/increased by setupHWLights + // light->fade value is 'time'. + // >=0 and light will become visible as value increases + // <0 and light will fade out + if (dist < max_dist) + { + if (fade < 0) + { + // mark light to fade in + // if fade was -LIGHT_FADE_TIME - it was fully invisible + // if fade -0 - it was fully visible + // visibility goes up from 0 to LIGHT_FADE_TIME. + fade += LIGHT_FADE_TIME; + } + } + else + { + // mark light to fade out + // visibility goes down from -0 to -LIGHT_FADE_TIME. + if (fade >= LIGHT_FADE_TIME) + { + fade = -0.0001f; // was fully visible + } + else if (fade >= 0) + { + // 0.75 visible light should stay 0.75 visible, but should reverse direction + fade -= LIGHT_FADE_TIME; + } + } + cur_nearby_lights.insert(Light(drawable, dist, fade)); } mNearbyLights = cur_nearby_lights; @@ -6187,17 +6178,23 @@ void LLPipeline::calcNearbyLights(LLCamera& camera) { continue; // no lighting from HUD objects } - F32 dist = calc_light_dist(light, cam_pos, max_dist); - if (dist >= max_dist) + if (!sRenderAttachedLights && light && light->isAttachment()) { continue; } - if (!sRenderAttachedLights && light && light->isAttachment()) + LLVOAvatar * av = light->getAvatar(); + if (av && (av->isTooComplex() || av->isInMuteList())) + { + // avatars that are already in the list will be removed by removeMutedAVsLights + continue; + } + F32 dist = calc_light_dist(light, cam_pos, max_dist); + if (dist >= max_dist) { continue; } new_nearby_lights.insert(Light(drawable, dist, 0.f)); - if (new_nearby_lights.size() > (U32)MAX_LOCAL_LIGHTS) + if (!LLPipeline::sRenderDeferred && new_nearby_lights.size() > (U32)MAX_LOCAL_LIGHTS) { new_nearby_lights.erase(--new_nearby_lights.end()); const Light& last = *new_nearby_lights.rbegin(); @@ -6210,7 +6207,7 @@ void LLPipeline::calcNearbyLights(LLCamera& camera) iter != new_nearby_lights.end(); iter++) { const Light* light = &(*iter); - if (mNearbyLights.size() < (U32)MAX_LOCAL_LIGHTS) + if (LLPipeline::sRenderDeferred || mNearbyLights.size() < (U32)MAX_LOCAL_LIGHTS) { mNearbyLights.insert(*light); ((LLDrawable*) light->drawable)->setState(LLDrawable::NEARBY_LIGHT); @@ -6223,10 +6220,22 @@ void LLPipeline::calcNearbyLights(LLCamera& camera) Light* farthest_light = (const_cast<Light*>(&(*(mNearbyLights.rbegin())))); if (light->dist < farthest_light->dist) { - if (farthest_light->fade >= 0.f) - { - farthest_light->fade = -(gFrameIntervalSeconds.value()); - } + // mark light to fade out + // visibility goes down from -0 to -LIGHT_FADE_TIME. + // + // This is a mess, but for now it needs to be in sync + // with fade code above. Ex: code above detects distance < max, + // sets fade time to positive, this code then detects closer + // lights and sets fade time negative, fully compensating + // for the code above + if (farthest_light->fade >= LIGHT_FADE_TIME) + { + farthest_light->fade = -0.0001f; // was fully visible + } + else if (farthest_light->fade >= 0) + { + farthest_light->fade -= LIGHT_FADE_TIME; + } } else { @@ -6249,26 +6258,31 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) { assertInitialized(); - // Ambient + LLEnvironment& environment = LLEnvironment::instance(); + LLSettingsSky::ptr_t psky = environment.getCurrentSky(); + if (!LLGLSLShader::sNoFixedFunction) { gGL.syncMatrices(); - LLColor4 ambient = gSky.getTotalAmbientColor(); - gGL.setAmbientLightColor(ambient); } + // Ambient + LLColor4 ambient = psky->getTotalAmbient(); + gGL.setAmbientLightColor(ambient); + + bool sun_up = environment.getIsSunUp(); + bool moon_up = environment.getIsMoonUp(); + // 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()); - } + LLVector4 sun_dir(environment.getSunDirection(), 0.0f); + LLVector4 moon_dir(environment.getMoonDirection(), 0.0f); + + mSunDir.setVec(sun_dir); + mMoonDir.setVec(moon_dir); + + mSunDiffuse.setVec(psky->getSunlightColor()); + mMoonDiffuse.setVec(psky->getMoonlightColor()); F32 max_color = llmax(mSunDiffuse.mV[0], mSunDiffuse.mV[1], mSunDiffuse.mV[2]); if (max_color > 1.f) @@ -6277,22 +6291,33 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) } mSunDiffuse.clamp(); - LLVector4 light_pos(mSunDir, 0.0f); - LLColor4 light_diffuse = mSunDiffuse; + max_color = llmax(mMoonDiffuse.mV[0], mMoonDiffuse.mV[1], mMoonDiffuse.mV[2]); + if (max_color > 1.f) + { + mMoonDiffuse *= 1.f/max_color; + } + mMoonDiffuse.clamp(); - if (LLPipeline::sRenderDeferred) + // prevent underlighting from having neither lightsource facing us + if (!sun_up && !moon_up) { - /*light_diffuse.mV[0] = powf(light_diffuse.mV[0], 2.2f); - light_diffuse.mV[1] = powf(light_diffuse.mV[1], 2.2f); - light_diffuse.mV[2] = powf(light_diffuse.mV[2], 2.2f);*/ + mSunDiffuse.setVec(LLColor4(0.0, 0.0, 0.0, 1.0)); + mMoonDiffuse.setVec(LLColor4(0.0, 0.0, 0.0, 1.0)); + mSunDir.setVec(LLVector4(0.0, 1.0, 0.0, 0.0)); + mMoonDir.setVec(LLVector4(0.0, 1.0, 0.0, 0.0)); } - mHWLightColors[0] = light_diffuse; + LLVector4 light_dir = sun_up ? mSunDir : mMoonDir; + + mHWLightColors[0] = sun_up ? mSunDiffuse : mMoonDiffuse; LLLightState* light = gGL.getLight(0); - light->setPosition(light_pos); - light->setDiffuse(light_diffuse); - light->setAmbient(LLColor4::black); + light->setPosition(light_dir); + + light->setSunPrimary(sun_up); + light->setDiffuse(mHWLightColors[0]); + light->setDiffuseB(mMoonDiffuse); + light->setAmbient(psky->getTotalAmbient()); light->setSpecular(LLColor4::black); light->setConstantAttenuation(1.f); light->setLinearAttenuation(0.f); @@ -6321,12 +6346,22 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) { continue; } + + if (light->isAttachment()) + { + if (!sRenderAttachedLights) + { + continue; + } + } + if (drawable->isState(LLDrawable::ACTIVE)) { mLightMovingMask |= (1<<cur_light); } - LLColor4 light_color = light->getLightColor(); + //send linear light color to shader + LLColor4 light_color = light->getLightLinearColor(); light_color.mV[3] = 0.0f; F32 fade = iter->fade; @@ -6347,13 +6382,24 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) light_color *= fade; } + if (light_color.magVecSquared() < 0.001f) + { + continue; + } + LLVector3 light_pos(light->getRenderPosition()); LLVector4 light_pos_gl(light_pos, 1.0f); F32 light_radius = llmax(light->getLightRadius(), 0.001f); + F32 size = light_radius * (sRenderDeferred ? 1.5f : 1.0f); - 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 + if (size <= 0.001f) + { + continue; + } + + F32 x = (3.f * (1.f + (light->getLightFalloff() * 2.0f))); // why this magic? probably trying to match a historic behavior. + F32 linatten = x / (light_radius); // % of brightness at radius mHWLightColors[cur_light] = light_color; LLLightState* light_state = gGL.getLight(cur_light); @@ -6364,9 +6410,8 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) light_state->setConstantAttenuation(0.f); if (sRenderDeferred) { - F32 size = light_radius*1.5f; light_state->setLinearAttenuation(size); - light_state->setQuadraticAttenuation(light->getLightFalloff()*0.5f+1.f); + light_state->setQuadraticAttenuation(light->getLightFalloff(DEFERRED_LIGHT_FALLOFF) + 1.f); // get falloff to match for forward deferred rendering lights } else { @@ -6386,7 +6431,9 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) light_state->setSpotCutoff(90.f); light_state->setSpotExponent(2.f); - const LLColor4 specular(0.f, 0.f, 0.f, 0.f); + LLVector3 spotParams = light->getSpotLightParams(); + + const LLColor4 specular(0.f, 0.f, 0.f, spotParams[2]); light_state->setSpecular(specular); } else // omnidirectional (point) light @@ -6394,8 +6441,8 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) 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); + // we use specular.z = 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, 1.f, 0.f); light_state->setSpecular(specular); } cur_light++; @@ -6409,45 +6456,14 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) { mHWLightColors[cur_light] = LLColor4::black; LLLightState* light = gGL.getLight(cur_light); - + light->setSunPrimary(true); 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 - - if (LLPipeline::sRenderDeferred) - { - /*light_color.mV[0] = powf(light_color.mV[0], 2.2f); - light_color.mV[1] = powf(light_color.mV[1], 2.2f); - light_color.mV[2] = powf(light_color.mV[2], 2.2f);*/ - } - - 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); - } + // Bookmark comment to allow searching for mSpecialRenderMode == 3 (avatar edit mode), + // prev site of forward (non-deferred) character light injection, removed by SL-13522 09/20 // Init GL state if (!LLGLSLShader::sNoFixedFunction) @@ -6508,9 +6524,6 @@ void LLPipeline::enableLights(U32 mask) } mLightMask = mask; stop_glerror(); - - LLColor4 ambient = gSky.getTotalAmbientColor(); - gGL.setAmbientLightColor(ambient); } } @@ -6541,7 +6554,7 @@ void LLPipeline::enableLightsDynamic() { gPipeline.enableLightsAvatar(); } - else if (gAgentAvatarp->mSpecialRenderMode >= 1) // anim preview + else if (gAgentAvatarp->mSpecialRenderMode == 2) // anim preview { gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f)); } @@ -6589,7 +6602,7 @@ void LLPipeline::enableLightsPreview() light->enable(); light->setPosition(light_pos); light->setDiffuse(diffuse0); - light->setAmbient(LLColor4::black); + light->setAmbient(ambient); light->setSpecular(specular0); light->setSpotExponent(0.f); light->setSpotCutoff(180.f); @@ -6600,7 +6613,7 @@ void LLPipeline::enableLightsPreview() light->enable(); light->setPosition(light_pos); light->setDiffuse(diffuse1); - light->setAmbient(LLColor4::black); + light->setAmbient(ambient); light->setSpecular(specular1); light->setSpotExponent(0.f); light->setSpotCutoff(180.f); @@ -6610,7 +6623,7 @@ void LLPipeline::enableLightsPreview() light->enable(); light->setPosition(light_pos); light->setDiffuse(diffuse2); - light->setAmbient(LLColor4::black); + light->setAmbient(ambient); light->setSpecular(specular2); light->setSpotExponent(0.f); light->setSpotCutoff(180.f); @@ -6626,13 +6639,11 @@ void LLPipeline::enableLightsAvatarEdit(const LLColor4& color) gGL.setAmbientLightColor(color); } -void LLPipeline::enableLightsFullbright(const LLColor4& color) +void LLPipeline::enableLightsFullbright() { assertInitialized(); U32 mask = 0x1000; // Non-0 mask, set ambient enableLights(mask); - - gGL.setAmbientLightColor(color); } void LLPipeline::disableLights() @@ -7142,7 +7153,8 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start, for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++) { if ((j == LLViewerRegion::PARTITION_VOLUME) || - (j == LLViewerRegion::PARTITION_BRIDGE) || + (j == LLViewerRegion::PARTITION_BRIDGE) || + (j == LLViewerRegion::PARTITION_CONTROL_AV) || (j == LLViewerRegion::PARTITION_TERRAIN) || (j == LLViewerRegion::PARTITION_TREE) || (j == LLViewerRegion::PARTITION_GRASS)) // only check these partitions for now @@ -7204,7 +7216,7 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start, { LLViewerRegion* region = *iter; - LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_BRIDGE); + LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_AVATAR); if (part && hasRenderType(part->mDrawableType)) { LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, pick_rigged, face_hit, &position, tex_coord, normal, tangent); @@ -7458,6 +7470,15 @@ void LLPipeline::renderMaskedObjects(U32 type, U32 mask, bool texture, bool batc gGLLastMatrix = NULL; } +void LLPipeline::renderFullbrightMaskedObjects(U32 type, U32 mask, bool texture, bool batch_texture) +{ + assertInitialized(); + gGL.loadMatrix(gGLModelView); + gGLLastMatrix = NULL; + mFullbrightAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture); + gGL.loadMatrix(gGLModelView); + gGLLastMatrix = NULL; +} void apply_cube_face_rotation(U32 face) { @@ -7521,718 +7542,697 @@ void LLPipeline::bindScreenToTexture() static LLTrace::BlockTimerStatHandle FTM_RENDER_BLOOM("Bloom"); -void LLPipeline::renderBloom(bool for_snapshot, F32 zoom_factor, int subfield) +void LLPipeline::renderFinalize() { - if (!(gPipeline.canUseVertexShaders() && - sRenderGlow)) - { - return; - } + LLVertexBuffer::unbind(); + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); - LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + assertInitialized(); - assertInitialized(); + if (gUseWireframe) + { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } - if (gUseWireframe) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } + LLVector2 tc1(0, 0); + LLVector2 tc2((F32) mScreen.getWidth() * 2, (F32) mScreen.getHeight() * 2); - LLVector2 tc1(0,0); - LLVector2 tc2((F32) mScreen.getWidth()*2, - (F32) mScreen.getHeight()*2); + 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); - 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); - - enableLightsFullbright(LLColor4(1,1,1,1)); + enableLightsFullbright(); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadIdentity(); - LLGLDisable test(GL_ALPHA_TEST); + LLGLDisable test(GL_ALPHA_TEST); - gGL.setColorMask(true, true); - glClearColor(0,0,0,0); - - { - { - LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM_FBO); - mGlow[2].bindTarget(); - mGlow[2].clear(); - } - - gGlowExtractProgram.bind(); - F32 minLum = llmax((F32) RenderGlowMinLuminance, 0.0f); - F32 maxAlpha = RenderGlowMaxExtractAlpha; - F32 warmthAmount = RenderGlowWarmthAmount; - LLVector3 lumWeights = RenderGlowLumWeights; - LLVector3 warmthWeights = RenderGlowWarmthWeights; - - - gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MIN_LUMINANCE, minLum); - gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MAX_EXTRACT_ALPHA, maxAlpha); - 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); - - gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); - - mScreen.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(); - - gGL.getTexUnit(0)->unbind(mScreen.getUsage()); + gGL.setColorMask(true, true); + glClearColor(0, 0, 0, 0); - mGlow[2].flush(); - } + if (sRenderGlow) + { + { + LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM_FBO); + mGlow[2].bindTarget(); + mGlow[2].clear(); + } - tc1.setVec(0,0); - tc2.setVec(2,2); + gGlowExtractProgram.bind(); + F32 minLum = llmax((F32) RenderGlowMinLuminance, 0.0f); + F32 maxAlpha = RenderGlowMaxExtractAlpha; + F32 warmthAmount = RenderGlowWarmthAmount; + LLVector3 lumWeights = RenderGlowLumWeights; + LLVector3 warmthWeights = RenderGlowWarmthWeights; + + gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MIN_LUMINANCE, minLum); + gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MAX_EXTRACT_ALPHA, maxAlpha); + 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); - // power of two between 1 and 1024 - U32 glowResPow = RenderGlowResolutionPow; - const U32 glow_res = llmax(1, - llmin(1024, 1 << glowResPow)); + gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); - S32 kernel = RenderGlowIterations*2; - F32 delta = RenderGlowWidth / glow_res; - // Use half the glow width if we have the res set to less than 9 so that it looks - // almost the same in either case. - if (glowResPow < 9) - { - delta *= 0.5f; - } - F32 strength = RenderGlowStrength; + mScreen.bindTexture(0, 0, LLTexUnit::TFO_POINT); - gGlowProgram.bind(); - gGlowProgram.uniform1f(LLShaderMgr::GLOW_STRENGTH, strength); + gGL.color4f(1, 1, 1, 1); + gPipeline.enableLightsFullbright(); + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1, -1); - for (S32 i = 0; i < kernel; i++) - { - { - LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM_FBO); - mGlow[i%2].bindTarget(); - mGlow[i%2].clear(); - } - - if (i == 0) - { - gGL.getTexUnit(0)->bind(&mGlow[2]); - } - else - { - gGL.getTexUnit(0)->bind(&mGlow[(i-1)%2]); - } + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1, 3); - if (i%2 == 0) - { - gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, delta, 0); - } - else - { - gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, 0, delta); - } + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3, -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(); - - mGlow[i%2].flush(); - } + gGL.end(); - gGlowProgram.unbind(); + gGL.getTexUnit(0)->unbind(mScreen.getUsage()); - /*if (LLRenderTarget::sUseFBO) - { - LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM_FBO); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - }*/ + mGlow[2].flush(); - 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]); + tc1.setVec(0, 0); + tc2.setVec(2, 2); + } - tc2.setVec((F32) mScreen.getWidth(), - (F32) mScreen.getHeight()); + // power of two between 1 and 1024 + U32 glowResPow = RenderGlowResolutionPow; + const U32 glow_res = llmax(1, llmin(1024, 1 << glowResPow)); - gGL.flush(); - - LLVertexBuffer::unbind(); + S32 kernel = RenderGlowIterations * 2; + F32 delta = RenderGlowWidth / glow_res; + // Use half the glow width if we have the res set to less than 9 so that it looks + // almost the same in either case. + if (glowResPow < 9) + { + delta *= 0.5f; + } + F32 strength = RenderGlowStrength; - if (LLPipeline::sRenderDeferred) - { + gGlowProgram.bind(); + gGlowProgram.uniform1f(LLShaderMgr::GLOW_STRENGTH, strength); - bool dof_enabled = !LLViewerCamera::getInstance()->cameraUnderWater() && - (RenderDepthOfFieldInEditMode || !LLToolMgr::getInstance()->inBuildMode()) && - RenderDepthOfField; + for (S32 i = 0; i < kernel; i++) + { + { + LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM_FBO); + mGlow[i % 2].bindTarget(); + mGlow[i % 2].clear(); + } + if (i == 0) + { + gGL.getTexUnit(0)->bind(&mGlow[2]); + } + else + { + gGL.getTexUnit(0)->bind(&mGlow[(i - 1) % 2]); + } - bool multisample = RenderFSAASamples > 1 && mFXAABuffer.isComplete(); + if (i % 2 == 0) + { + gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, delta, 0); + } + else + { + gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, 0, delta); + } - gViewerWindow->setup3DViewport(); - - if (dof_enabled) - { - LLGLSLShader* shader = &gDeferredPostProgram; - LLGLDisable blend(GL_BLEND); + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1, -1); - //depth of field focal plane calculations - static F32 current_distance = 16.f; - static F32 start_distance = 16.f; - static F32 transition_time = 1.f; + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1, 3); - LLVector3 focus_point; + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3, -1); - LLViewerObject* obj = LLViewerMediaFocus::getInstance()->getFocusedObject(); - if (obj && obj->mDrawable && obj->isSelected()) - { //focus on selected media object - S32 face_idx = LLViewerMediaFocus::getInstance()->getFocusedFace(); - if (obj && obj->mDrawable) - { - LLFace* face = obj->mDrawable->getFace(face_idx); - if (face) - { - focus_point = face->getPositionAgent(); - } - } - } - - if (focus_point.isExactlyZero()) - { - if (LLViewerJoystick::getInstance()->getOverrideCamera()) - { //focus on point under cursor - focus_point.set(gDebugRaycastIntersection.getF32ptr()); - } - else if (gAgentCamera.cameraMouselook()) - { //focus on point under mouselook crosshairs - LLVector4a result; - result.clear(); + gGL.end(); - gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, - NULL, - &result); + mGlow[i % 2].flush(); + } - focus_point.set(result.getF32ptr()); - } - else - { - //focus on alt-zoom target - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - focus_point = LLVector3(gAgentCamera.getFocusGlobal()-region->getOriginGlobal()); - } - } - } + gGlowProgram.unbind(); + } + else // !sRenderGlow, skip the glow ping-pong and just clear the result target + { + mGlow[1].bindTarget(); + mGlow[1].clear(); + mGlow[1].flush(); + } - LLVector3 eye = LLViewerCamera::getInstance()->getOrigin(); - F32 target_distance = 16.f; - if (!focus_point.isExactlyZero()) - { - target_distance = LLViewerCamera::getInstance()->getAtAxis() * (focus_point-eye); - } + 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]); - if (transition_time >= 1.f && - fabsf(current_distance-target_distance)/current_distance > 0.01f) - { //large shift happened, interpolate smoothly to new target distance - transition_time = 0.f; - start_distance = current_distance; - } - else if (transition_time < 1.f) - { //currently in a transition, continue interpolating - transition_time += 1.f/CameraFocusTransitionTime*gFrameIntervalSeconds.value(); - transition_time = llmin(transition_time, 1.f); + tc2.setVec((F32) mScreen.getWidth(), (F32) mScreen.getHeight()); - F32 t = cosf(transition_time*F_PI+F_PI)*0.5f+0.5f; - current_distance = start_distance + (target_distance-start_distance)*t; - } - else - { //small or no change, just snap to target distance - current_distance = target_distance; - } + gGL.flush(); - //convert to mm - F32 subject_distance = current_distance*1000.f; - F32 fnumber = CameraFNumber; - F32 default_focal_length = CameraFocalLength; + LLVertexBuffer::unbind(); - F32 fov = LLViewerCamera::getInstance()->getView(); - - const F32 default_fov = CameraFieldOfView * F_PI/180.f; - - //F32 aspect_ratio = (F32) mScreen.getWidth()/(F32)mScreen.getHeight(); - - F32 dv = 2.f*default_focal_length * tanf(default_fov/2.f); + if (LLPipeline::sRenderDeferred) + { - F32 focal_length = dv/(2*tanf(fov/2.f)); - - //F32 tan_pixel_angle = tanf(LLDrawable::sCurPixelAngle); - - // from wikipedia -- c = |s2-s1|/s2 * f^2/(N(S1-f)) - // where N = fnumber - // s2 = dot distance - // s1 = subject distance - // f = focal length - // + bool dof_enabled = !LLViewerCamera::getInstance()->cameraUnderWater() && + (RenderDepthOfFieldInEditMode || !LLToolMgr::getInstance()->inBuildMode()) && + RenderDepthOfField; - F32 blur_constant = focal_length*focal_length/(fnumber*(subject_distance-focal_length)); - blur_constant /= 1000.f; //convert to meters for shader - F32 magnification = focal_length/(subject_distance-focal_length); + bool multisample = RenderFSAASamples > 1 && mFXAABuffer.isComplete(); - { //build diffuse+bloom+CoF - mDeferredLight.bindTarget(); - shader = &gDeferredCoFProgram; + gViewerWindow->setup3DViewport(); - bindDeferredShader(*shader); + if (dof_enabled) + { + LLGLSLShader *shader = &gDeferredPostProgram; + LLGLDisable blend(GL_BLEND); + + // depth of field focal plane calculations + static F32 current_distance = 16.f; + static F32 start_distance = 16.f; + static F32 transition_time = 1.f; + + LLVector3 focus_point; + + LLViewerObject *obj = LLViewerMediaFocus::getInstance()->getFocusedObject(); + if (obj && obj->mDrawable && obj->isSelected()) + { // focus on selected media object + S32 face_idx = LLViewerMediaFocus::getInstance()->getFocusedFace(); + if (obj && obj->mDrawable) + { + LLFace *face = obj->mDrawable->getFace(face_idx); + if (face) + { + focus_point = face->getPositionAgent(); + } + } + } - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); - if (channel > -1) - { - mScreen.bindTexture(0, channel); - } + if (focus_point.isExactlyZero()) + { + if (LLViewerJoystick::getInstance()->getOverrideCamera()) + { // focus on point under cursor + focus_point.set(gDebugRaycastIntersection.getF32ptr()); + } + else if (gAgentCamera.cameraMouselook()) + { // focus on point under mouselook crosshairs + LLVector4a result; + result.clear(); + + gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, NULL, &result); + + focus_point.set(result.getF32ptr()); + } + else + { + // focus on alt-zoom target + LLViewerRegion *region = gAgent.getRegion(); + if (region) + { + focus_point = LLVector3(gAgentCamera.getFocusGlobal() - region->getOriginGlobal()); + } + } + } - shader->uniform1f(LLShaderMgr::DOF_FOCAL_DISTANCE, -subject_distance/1000.f); - shader->uniform1f(LLShaderMgr::DOF_BLUR_CONSTANT, blur_constant); - shader->uniform1f(LLShaderMgr::DOF_TAN_PIXEL_ANGLE, tanf(1.f/LLDrawable::sCurPixelAngle)); - shader->uniform1f(LLShaderMgr::DOF_MAGNIFICATION, magnification); - shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); - shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); + LLVector3 eye = LLViewerCamera::getInstance()->getOrigin(); + F32 target_distance = 16.f; + if (!focus_point.isExactlyZero()) + { + target_distance = LLViewerCamera::getInstance()->getAtAxis() * (focus_point - eye); + } - 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(); + if (transition_time >= 1.f && fabsf(current_distance - target_distance) / current_distance > 0.01f) + { // large shift happened, interpolate smoothly to new target distance + transition_time = 0.f; + start_distance = current_distance; + } + else if (transition_time < 1.f) + { // currently in a transition, continue interpolating + transition_time += 1.f / CameraFocusTransitionTime * gFrameIntervalSeconds.value(); + transition_time = llmin(transition_time, 1.f); - unbindDeferredShader(*shader); - mDeferredLight.flush(); - } + F32 t = cosf(transition_time * F_PI + F_PI) * 0.5f + 0.5f; + current_distance = start_distance + (target_distance - start_distance) * t; + } + else + { // small or no change, just snap to target distance + current_distance = target_distance; + } - U32 dof_width = (U32) (mScreen.getWidth()*CameraDoFResScale); - 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); - gGL.setColorMask(true, false); - - shader = &gDeferredPostProgram; - bindDeferredShader(*shader); - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); - if (channel > -1) - { - mDeferredLight.bindTexture(0, channel); - } + // convert to mm + F32 subject_distance = current_distance * 1000.f; + F32 fnumber = CameraFNumber; + F32 default_focal_length = CameraFocalLength; - 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(); + F32 fov = LLViewerCamera::getInstance()->getView(); - unbindDeferredShader(*shader); - mScreen.flush(); - gGL.setColorMask(true, true); - } - - { //combine result based on alpha - if (multisample) - { - mDeferredLight.bindTarget(); - glViewport(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]); - } + const F32 default_fov = CameraFieldOfView * F_PI / 180.f; - shader = &gDeferredDoFCombineProgram; - bindDeferredShader(*shader); - - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); - if (channel > -1) - { - mScreen.bindTexture(0, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - } + // F32 aspect_ratio = (F32) mScreen.getWidth()/(F32)mScreen.getHeight(); - if (!LLViewerCamera::getInstance()->cameraUnderWater()) - { - shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 2.2); - } else { - shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 1.0); - } + F32 dv = 2.f * default_focal_length * tanf(default_fov / 2.f); - 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); + F32 focal_length = dv / (2 * tanf(fov / 2.f)); - 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(); + // F32 tan_pixel_angle = tanf(LLDrawable::sCurPixelAngle); - unbindDeferredShader(*shader); + // from wikipedia -- c = |s2-s1|/s2 * f^2/(N(S1-f)) + // where N = fnumber + // s2 = dot distance + // s1 = subject distance + // f = focal length + // - if (multisample) - { - mDeferredLight.flush(); - } - } - } - else - { - if (multisample) - { - mDeferredLight.bindTarget(); - } - LLGLSLShader* shader = &gDeferredPostNoDoFProgram; - - bindDeferredShader(*shader); - - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); - if (channel > -1) - { - mScreen.bindTexture(0, channel); - } + F32 blur_constant = focal_length * focal_length / (fnumber * (subject_distance - focal_length)); + blur_constant /= 1000.f; // convert to meters for shader + F32 magnification = focal_length / (subject_distance - focal_length); - if (!LLViewerCamera::getInstance()->cameraUnderWater()) - { - shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 2.2); - } else { - shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 1.0); - } + { // build diffuse+bloom+CoF + mDeferredLight.bindTarget(); + shader = &gDeferredCoFProgram; - 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(); + bindDeferredShader(*shader); - unbindDeferredShader(*shader); + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + if (channel > -1) + { + mScreen.bindTexture(0, channel); + } - if (multisample) - { - mDeferredLight.flush(); - } - } + shader->uniform1f(LLShaderMgr::DOF_FOCAL_DISTANCE, -subject_distance / 1000.f); + shader->uniform1f(LLShaderMgr::DOF_BLUR_CONSTANT, blur_constant); + shader->uniform1f(LLShaderMgr::DOF_TAN_PIXEL_ANGLE, tanf(1.f / LLDrawable::sCurPixelAngle)); + shader->uniform1f(LLShaderMgr::DOF_MAGNIFICATION, magnification); + shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); + shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); - if (multisample) - { - //bake out texture2D with RGBL for FXAA shader - mFXAABuffer.bindTarget(); - - S32 width = mScreen.getWidth(); - S32 height = mScreen.getHeight(); - glViewport(0, 0, width, height); + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1, -1); - LLGLSLShader* shader = &gGlowCombineFXAAProgram; + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1, 3); - shader->bind(); - shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, width, height); + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3, -1); - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); - if (channel > -1) - { - mDeferredLight.bindTexture(0, channel); - } - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex2f(-1,-1); - gGL.vertex2f(-1,3); - gGL.vertex2f(3,-1); - gGL.end(); + gGL.end(); - gGL.flush(); + unbindDeferredShader(*shader); + mDeferredLight.flush(); + } - shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); - shader->unbind(); - - mFXAABuffer.flush(); + U32 dof_width = (U32)(mScreen.getWidth() * CameraDoFResScale); + U32 dof_height = (U32)(mScreen.getHeight() * CameraDoFResScale); - shader = &gFXAAProgram; - shader->bind(); + { // perform DoF sampling at half-res (preserve alpha channel) + mScreen.bindTarget(); + glViewport(0, 0, dof_width, dof_height); + gGL.setColorMask(true, false); - channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP, mFXAABuffer.getUsage()); - if (channel > -1) - { - mFXAABuffer.bindTexture(0, channel); - 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); - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex2f(-1,-1); - gGL.vertex2f(-1,3); - gGL.vertex2f(3,-1); - gGL.end(); + shader = &gDeferredPostProgram; + bindDeferredShader(*shader); + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); + if (channel > -1) + { + mDeferredLight.bindTexture(0, channel); + } - gGL.flush(); - shader->unbind(); - } - } - else - { - U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1; - LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask, 0); - buff->allocateBuffer(3,0,TRUE); + shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); + shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); - LLStrider<LLVector3> v; - LLStrider<LLVector2> uv1; - LLStrider<LLVector2> uv2; + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1, -1); - 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(); + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1, 3); - LLGLDisable blend(GL_BLEND); + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3, -1); - if (LLGLSLShader::sNoFixedFunction) - { - gGlowCombineProgram.bind(); - } - else - { - //tex unit 0 - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR); - //tex unit 1 - gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR); - } - - gGL.getTexUnit(0)->bind(&mGlow[1]); - gGL.getTexUnit(1)->bind(&mScreen); - - LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); - - buff->setBuffer(mask); - buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3); - - if (LLGLSLShader::sNoFixedFunction) - { - gGlowCombineProgram.unbind(); - } - else - { - gGL.getTexUnit(1)->disable(); - gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT); + gGL.end(); - gGL.getTexUnit(0)->activate(); - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - } - - } + unbindDeferredShader(*shader); + mScreen.flush(); + gGL.setColorMask(true, true); + } - gGL.setSceneBlendType(LLRender::BT_ALPHA); + { // combine result based on alpha + if (multisample) + { + mDeferredLight.bindTarget(); + glViewport(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]); + } + + shader = &gDeferredDoFCombineProgram; + bindDeferredShader(*shader); + + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + if (channel > -1) + { + mScreen.bindTexture(0, channel); + } + + 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); + + 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); + + if (multisample) + { + mDeferredLight.flush(); + } + } + } + else + { + if (multisample) + { + mDeferredLight.bindTarget(); + } + LLGLSLShader *shader = &gDeferredPostNoDoFProgram; - if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES)) - { - if (LLGLSLShader::sNoFixedFunction) - { - gSplatTextureRectProgram.bind(); - } + bindDeferredShader(*shader); - gGL.setColorMask(true, false); + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + if (channel > -1) + { + mScreen.bindTexture(0, channel); + } - LLVector2 tc1(0,0); - LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2, - (F32) gViewerWindow->getWorldViewHeightRaw()*2); + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1, -1); - LLGLEnable blend(GL_BLEND); - gGL.color4f(1,1,1,0.75f); + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1, 3); - gGL.getTexUnit(0)->bind(&mPhysicsDisplay); + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3, -1); - 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.end(); - gGL.flush(); + gGL.end(); - if (LLGLSLShader::sNoFixedFunction) - { - gSplatTextureRectProgram.unbind(); - } - } + unbindDeferredShader(*shader); - - if (LLRenderTarget::sUseFBO) - { //copy depth buffer from mScreen to framebuffer - LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(), - 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); - } - + if (multisample) + { + mDeferredLight.flush(); + } + } - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); + if (multisample) + { + // bake out texture2D with RGBL for FXAA shader + mFXAABuffer.bindTarget(); - LLVertexBuffer::unbind(); + S32 width = mScreen.getWidth(); + S32 height = mScreen.getHeight(); + glViewport(0, 0, width, height); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLSLShader *shader = &gGlowCombineFXAAProgram; + + shader->bind(); + shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, width, height); + + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); + if (channel > -1) + { + mDeferredLight.bindTexture(0, channel); + } + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex2f(-1, -1); + gGL.vertex2f(-1, 3); + gGL.vertex2f(3, -1); + gGL.end(); + + gGL.flush(); + + shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); + shader->unbind(); + + mFXAABuffer.flush(); + + shader = &gFXAAProgram; + shader->bind(); + + channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP, mFXAABuffer.getUsage()); + if (channel > -1) + { + mFXAABuffer.bindTexture(0, channel, 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); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex2f(-1, -1); + gGL.vertex2f(-1, 3); + gGL.vertex2f(3, -1); + gGL.end(); + + gGL.flush(); + shader->unbind(); + } + } + else // not deferred + { + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1; + LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask, 0); + buff->allocateBuffer(3, 0, TRUE); + + LLStrider<LLVector3> v; + LLStrider<LLVector2> uv1; + LLStrider<LLVector2> 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); + + if (LLGLSLShader::sNoFixedFunction) + { + gGlowCombineProgram.bind(); + } + else + { + // tex unit 0 + gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR); + // tex unit 1 + gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR, + LLTexUnit::TBS_PREV_COLOR); + } + + gGL.getTexUnit(0)->bind(&mGlow[1]); + gGL.getTexUnit(1)->bind(&mScreen); + + LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); + + buff->setBuffer(mask); + buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3); + + if (LLGLSLShader::sNoFixedFunction) + { + gGlowCombineProgram.unbind(); + } + else + { + gGL.getTexUnit(1)->disable(); + gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT); + gGL.getTexUnit(0)->activate(); + gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); + } + } + + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES)) + { + if (LLGLSLShader::sNoFixedFunction) + { + gSplatTextureRectProgram.bind(); + } + + gGL.setColorMask(true, false); + + LLVector2 tc1(0, 0); + LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw() * 2, + (F32) gViewerWindow->getWorldViewHeightRaw() * 2); + + LLGLEnable blend(GL_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.end(); + gGL.flush(); + + if (LLGLSLShader::sNoFixedFunction) + { + gSplatTextureRectProgram.unbind(); + } + } + + if (LLRenderTarget::sUseFBO) + { // copy depth buffer from mScreen to framebuffer + LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(), 0, 0, + mScreen.getWidth(), mScreen.getHeight(), + GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); + } + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + + LLVertexBuffer::unbind(); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); } 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* light_target) { LL_RECORD_BLOCK_TIME(FTM_BIND_DEFERRED); - if (noise_map == 0xFFFFFFFF) - { - noise_map = mNoiseMap; - } + LLRenderTarget* deferred_target = &mDeferredScreen; + LLRenderTarget* deferred_depth_target = &mDeferredDepth; + LLRenderTarget* deferred_light_target = &mDeferredLight; shader.bind(); S32 channel = 0; - channel = shader.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredScreen.getUsage()); + channel = shader.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, deferred_target->getUsage()); if (channel > -1) { - mDeferredScreen.bindTexture(0,channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + deferred_target->bindTexture(0,channel, LLTexUnit::TFO_POINT); } - channel = shader.enableTexture(LLShaderMgr::DEFERRED_SPECULAR, mDeferredScreen.getUsage()); + channel = shader.enableTexture(LLShaderMgr::DEFERRED_SPECULAR, deferred_target->getUsage()); if (channel > -1) { - mDeferredScreen.bindTexture(1, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + deferred_target->bindTexture(1, channel, LLTexUnit::TFO_POINT); } - channel = shader.enableTexture(LLShaderMgr::DEFERRED_NORMAL, mDeferredScreen.getUsage()); + channel = shader.enableTexture(LLShaderMgr::DEFERRED_NORMAL, deferred_target->getUsage()); if (channel > -1) { - mDeferredScreen.bindTexture(2, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + deferred_target->bindTexture(2, channel, LLTexUnit::TFO_POINT); } - channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, mDeferredDepth.getUsage()); + channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, deferred_depth_target->getUsage()); if (channel > -1) { - gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE); + gGL.getTexUnit(channel)->bind(deferred_depth_target, TRUE); stop_glerror(); + } - //glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); - //glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA); - - stop_glerror(); - - glh::matrix4f projection = glh_get_current_projection(); + glh::matrix4f projection = get_current_projection(); glh::matrix4f inv_proj = projection.inverse(); + if (shader.getUniformLocation(LLShaderMgr::INVERSE_PROJECTION_MATRIX) != -1) + { shader.uniformMatrix4fv(LLShaderMgr::INVERSE_PROJECTION_MATRIX, 1, FALSE, inv_proj.m); + } + + if (shader.getUniformLocation(LLShaderMgr::VIEWPORT) != -1) + { shader.uniform4f(LLShaderMgr::VIEWPORT, (F32) gGLViewport[0], (F32) gGLViewport[1], (F32) gGLViewport[2], (F32) gGLViewport[3]); } + if (sReflectionRender && !shader.getUniformLocation(LLShaderMgr::MODELVIEW_MATRIX)) + { + shader.uniformMatrix4fv(LLShaderMgr::MODELVIEW_MATRIX, 1, FALSE, mReflectionModelView.m); + } + 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); gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } @@ -8244,18 +8244,11 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n stop_glerror(); - channel = shader.enableTexture(LLShaderMgr::DEFERRED_LIGHT, mDeferredLight.getUsage()); + light_target = light_target ? light_target : deferred_light_target; + channel = shader.enableTexture(LLShaderMgr::DEFERRED_LIGHT, light_target->getUsage()); if (channel > -1) { - if (light_index > 0) - { - mScreen.bindTexture(0, channel); - } - else - { - mDeferredLight.bindTexture(0, channel); - } - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + light_target->bindTexture(0, channel, LLTexUnit::TFO_POINT); } channel = shader.enableTexture(LLShaderMgr::DEFERRED_BLOOM); @@ -8268,13 +8261,16 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n for (U32 i = 0; i < 4; i++) { + LLRenderTarget* shadow_target = getShadowTarget(i); + if (shadow_target) + { channel = shader.enableTexture(LLShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_TEXTURE); stop_glerror(); if (channel > -1) { stop_glerror(); - gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + gGL.getTexUnit(channel)->bind(getShadowTarget(i), TRUE); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_ANISOTROPIC); gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); stop_glerror(); @@ -8283,6 +8279,7 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n stop_glerror(); } } + } for (U32 i = 4; i < 6; i++) { @@ -8291,8 +8288,11 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n if (channel > -1) { stop_glerror(); - gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + LLRenderTarget* shadow_target = getShadowTarget(i); + if (shadow_target) + { + gGL.getTexUnit(channel)->bind(shadow_target, TRUE); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_ANISOTROPIC); gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); stop_glerror(); @@ -8301,6 +8301,7 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n stop_glerror(); } } + } stop_glerror(); @@ -8337,6 +8338,34 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n } } + if (gAtmosphere) + { + // bind precomputed textures necessary for calculating sun and sky luminance + channel = shader.enableTexture(LLShaderMgr::TRANSMITTANCE_TEX, LLTexUnit::TT_TEXTURE); + if (channel > -1) + { + shader.bindTexture(LLShaderMgr::TRANSMITTANCE_TEX, gAtmosphere->getTransmittance()); + } + + channel = shader.enableTexture(LLShaderMgr::SCATTER_TEX, LLTexUnit::TT_TEXTURE_3D); + if (channel > -1) + { + shader.bindTexture(LLShaderMgr::SCATTER_TEX, gAtmosphere->getScattering()); + } + + channel = shader.enableTexture(LLShaderMgr::SINGLE_MIE_SCATTER_TEX, LLTexUnit::TT_TEXTURE_3D); + if (channel > -1) + { + shader.bindTexture(LLShaderMgr::SINGLE_MIE_SCATTER_TEX, gAtmosphere->getMieScattering()); + } + + channel = shader.enableTexture(LLShaderMgr::ILLUMINANCE_TEX, LLTexUnit::TT_TEXTURE); + if (channel > -1) + { + shader.bindTexture(LLShaderMgr::ILLUMINANCE_TEX, gAtmosphere->getIlluminance()); + } + } + shader.uniform4fv(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1, mSunClipPlanes.mV); shader.uniform1f(LLShaderMgr::DEFERRED_SUN_WASH, RenderDeferredSunWash); shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_NOISE, RenderShadowNoise); @@ -8361,26 +8390,35 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n //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; + F32 shadow_bias = RenderShadowBias + shadow_bias_error; - shader.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredScreen.getWidth(), mDeferredScreen.getHeight()); + shader.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, deferred_target->getWidth(), deferred_target->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_BIAS, shadow_bias); 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_MOON_DIR, 1, mTransformedMoonDir.mV); 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(LLShaderMgr::DEFERRED_NORM_MATRIX) >= 0) { - glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose(); + glh::matrix4f norm_mat = get_current_modelview().inverse().transpose(); shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_NORM_MATRIX, 1, FALSE, norm_mat.m); } + + shader.uniform4fv(LLShaderMgr::SUNLIGHT_COLOR, 1, mSunDiffuse.mV); + shader.uniform4fv(LLShaderMgr::MOONLIGHT_COLOR, 1, mMoonDiffuse.mV); + + LLEnvironment& environment = LLEnvironment::instance(); + LLSettingsSky::ptr_t sky = environment.getCurrentSky(); + + static_cast<LLSettingsVOSky*>(sky.get())->updateShader(&shader); } LLColor3 pow3f(LLColor3 v, F32 f) @@ -8410,1150 +8448,622 @@ static LLTrace::BlockTimerStatHandle FTM_FULLSCREEN_LIGHTS("Fullscreen Lights"); static LLTrace::BlockTimerStatHandle FTM_PROJECTORS("Projectors"); static LLTrace::BlockTimerStatHandle FTM_POST("Post"); - -void LLPipeline::renderDeferredLighting() -{ - if (!sCull) - { - return; - } - - { - 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 ? GL_MULTISAMPLE_ARB : 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(GL_STENCIL_TEST); - //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(GL_CULL_FACE); - LLGLEnable blend(GL_BLEND); - - glh::matrix4f mat = glh_copy_matrix(gGLModelView); - - LLStrider<LLVector3> vert; - mDeferredVB->getVertexStrider(vert); - - 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); - } - - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); - - if (RenderDeferredSSAO || RenderShadowDetail > 0) - { - mDeferredLight.bindTarget(); - { //paint shadow/SSAO light map (direct lighting lightmap) - LL_RECORD_BLOCK_TIME(FTM_SUN_SHADOW); - bindDeferredShader(gDeferredSunProgram, 0); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - 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(); - - const U32 slice = 32; - F32 offset[slice*3]; - for (U32 i = 0; i < 4; i++) - { - 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); - v.normalize(); - inv_trans.mult_matrix_vec(v); - 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]; - } - } - - gDeferredSunProgram.uniform3fv(sOffset, slice, offset); - gDeferredSunProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredLight.getWidth(), mDeferredLight.getHeight()); - - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - stop_glerror(); - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - stop_glerror(); - } - - unbindDeferredShader(gDeferredSunProgram); - } - mDeferredLight.flush(); - } - - if (RenderDeferredSSAO) - { //soften direct lighting lightmap - LL_RECORD_BLOCK_TIME(FTM_SOFTEN_SHADOW); - //blur lightmap - mScreen.bindTarget(); - glClearColor(1,1,1,1); - mScreen.clear(GL_COLOR_BUFFER_BIT); - 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; - - LLVector3 gauss[32]; // xweight, yweight, offset - - for (U32 i = 0; i < kern_length; i++) - { - 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; - } - - gDeferredBlurLightProgram.uniform2f(sDelta, 1.f, 0.f); - gDeferredBlurLightProgram.uniform1f(sDistFactor, dist_factor); - gDeferredBlurLightProgram.uniform3fv(sKern, kern_length, gauss[0].mV); - gDeferredBlurLightProgram.uniform1f(sKernScale, blur_size * (kern_length/2.f - 0.5f)); - - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - stop_glerror(); - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - stop_glerror(); - } - - mScreen.flush(); - unbindDeferredShader(gDeferredBlurLightProgram); - - bindDeferredShader(gDeferredBlurLightProgram, 1); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - mDeferredLight.bindTarget(); - - gDeferredBlurLightProgram.uniform2f(sDelta, 0.f, 1.f); - - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - stop_glerror(); - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - stop_glerror(); - } - mDeferredLight.flush(); - unbindDeferredShader(gDeferredBlurLightProgram); - } - - 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(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); - - //full screen blit - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); - - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - } - - unbindDeferredShader(LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram); - } - - { //render non-deferred geometry (fullbright, alpha, etc) - LLGLDisable blend(GL_BLEND); - LLGLDisable stencil(GL_STENCIL_TEST); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - - gPipeline.pushRenderTypeMask(); - - gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_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<LLVector4> 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<LLVector4> 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() || vobj->getAvatar()->isInMuteList())) - { - 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++; - - 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) - { //draw box if camera is outside box - if (render_local) - { - if (volume->isLightSpotlight()) - { - drawablep->getVOVolume()->updateSpotLightPriority(); - spot_lights.push_back(drawablep); - continue; - } - - /*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); - 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(); - } - } - else - { - if (volume->isLightSpotlight()) - { - drawablep->getVOVolume()->updateSpotLightPriority(); - fullscreen_spot_lights.push_back(drawablep); - 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)); - 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(); - /*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); - 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)); - } - gDeferredSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION); - 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); - - { - 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; - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - unbindDeferredShader(gDeferredMultiLightProgram[idx]); - } - } - - 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) - { - LL_RECORD_BLOCK_TIME(FTM_PROJECTORS); - LLDrawable* drawablep = *iter; - - LLVOVolume* volume = drawablep->getVOVolume(); - - LLVector3 center = drawablep->getPositionAgent(); - F32* c = center.mV; - F32 s = volume->getLightRadius()*1.5f; - - sVisibleLightCount++; - - glh::vec3f tc(c); - mat.mult_matrix_vec(tc); - - 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, tc.v); - 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); - } - - gDeferredMultiSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION); - unbindDeferredShader(gDeferredMultiSpotLightProgram); - - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - } - } - - 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); - - LLVector2 tc1(0,0); - LLVector2 tc2((F32) mScreen.getWidth()*2, - (F32) mScreen.getHeight()*2); - - mScreen.bindTarget(); - // Apply gamma correction to the frame here. - gDeferredPostGammaCorrectProgram.bind(); - //mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - 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); - } - - gDeferredPostGammaCorrectProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mScreen.getWidth(), mScreen.getHeight()); - - F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); - - gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); - - 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(); - - gGL.getTexUnit(channel)->unbind(mScreen.getUsage()); - gDeferredPostGammaCorrectProgram.unbind(); - mScreen.flush(); - } - - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - - mScreen.bindTarget(); - - { //render non-deferred geometry (alpha, fullbright, glow) - LLGLDisable blend(GL_BLEND); - LLGLDisable stencil(GL_STENCIL_TEST); - - 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_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::renderDeferredLightingToRT(LLRenderTarget* target) +void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) { - if (!sCull) - { - return; - } + if (!sCull) + { + return; + } - { - LL_RECORD_BLOCK_TIME(FTM_RENDER_DEFERRED); - - LLViewerCamera* camera = LLViewerCamera::getInstance(); + LLRenderTarget *deferred_target = &mDeferredScreen; + LLRenderTarget *deferred_depth_target = &mDeferredDepth; + LLRenderTarget *deferred_light_target = &mDeferredLight; - { - LLGLDepthTest depth(GL_TRUE); - mDeferredDepth.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(), - 0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); - } - - LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 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(GL_STENCIL_TEST); - //glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF); - //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + { + LL_RECORD_BLOCK_TIME(FTM_RENDER_DEFERRED); + LLViewerCamera *camera = LLViewerCamera::getInstance(); + { + LLGLDepthTest depth(GL_TRUE); + deferred_depth_target->copyContents(*deferred_target, + 0, + 0, + deferred_target->getWidth(), + deferred_target->getHeight(), + 0, + 0, + deferred_depth_target->getWidth(), + deferred_depth_target->getHeight(), + GL_DEPTH_BUFFER_BIT, + GL_NEAREST); + } - gGL.setColorMask(true, true); - - //draw a cube around every light - LLVertexBuffer::unbind(); + LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); - LLGLEnable cull(GL_CULL_FACE); - LLGLEnable blend(GL_BLEND); + if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); + } - glh::matrix4f mat = glh_copy_matrix(gGLModelView); + // ati doesn't seem to love actually using the stencil buffer on FBO's + LLGLDisable stencil(GL_STENCIL_TEST); + // glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF); + // glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - LLStrider<LLVector3> vert; - mDeferredVB->getVertexStrider(vert); - - 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); - } + gGL.setColorMask(true, true); - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); + // draw a cube around every light + LLVertexBuffer::unbind(); - if (RenderDeferredSSAO || RenderShadowDetail > 0) - { - mDeferredLight.bindTarget(); - { //paint shadow/SSAO light map (direct lighting lightmap) - LL_RECORD_BLOCK_TIME(FTM_SUN_SHADOW); - bindDeferredShader(gDeferredSunProgram); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - glClearColor(1,1,1,1); - mDeferredLight.clear(GL_COLOR_BUFFER_BIT); - glClearColor(0,0,0,0); + LLGLEnable cull(GL_CULL_FACE); + LLGLEnable blend(GL_BLEND); - glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose(); + glh::matrix4f mat = copy_matrix(gGLModelView); - const U32 slice = 32; - F32 offset[slice*3]; - for (U32 i = 0; i < 4; i++) - { - 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); - v.normalize(); - inv_trans.mult_matrix_vec(v); - 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]; - } - } + LLStrider<LLVector3> vert; + mDeferredVB->getVertexStrider(vert); - gDeferredSunProgram.uniform3fv(LLShaderMgr::DEFERRED_SHADOW_OFFSET, slice, offset); - gDeferredSunProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredLight.getWidth(), mDeferredLight.getHeight()); - - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - stop_glerror(); - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - stop_glerror(); - } - - unbindDeferredShader(gDeferredSunProgram); - } - mDeferredLight.flush(); - } - - stop_glerror(); - gGL.popMatrix(); - stop_glerror(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - stop_glerror(); - gGL.popMatrix(); - stop_glerror(); + vert[0].set(-1, 1, 0); + vert[1].set(-1, -3, 0); + vert[2].set(3, 1, 0); - target->bindTarget(); + setupHWLights(NULL); // to set mSun/MoonDir; - //clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky - glClearColor(0,0,0,0); - target->clear(GL_COLOR_BUFFER_BIT); - - if (RenderDeferredAtmospheric) - { //apply sunlight contribution - LL_RECORD_BLOCK_TIME(FTM_ATMOSPHERICS); - bindDeferredShader(gDeferredSoftenProgram); - { - LLGLDepthTest depth(GL_FALSE); - LLGLDisable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); + glh::vec4f tc(mSunDir.mV); + mat.mult_matrix_vec(tc); + mTransformedSunDir.set(tc.v); - //full screen blit - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); + glh::vec4f tc_moon(mMoonDir.mV); + mat.mult_matrix_vec(tc_moon); + mTransformedMoonDir.set(tc_moon.v); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - } + if (RenderDeferredSSAO || RenderShadowDetail > 0) + { + deferred_light_target->bindTarget(); + { // paint shadow/SSAO light map (direct lighting lightmap) + LL_RECORD_BLOCK_TIME(FTM_SUN_SHADOW); + bindDeferredShader(gDeferredSunProgram, deferred_light_target); + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + glClearColor(1, 1, 1, 1); + deferred_light_target->clear(GL_COLOR_BUFFER_BIT); + glClearColor(0, 0, 0, 0); + + glh::matrix4f inv_trans = get_current_modelview().inverse().transpose(); + + const U32 slice = 32; + F32 offset[slice * 3]; + for (U32 i = 0; i < 4; i++) + { + 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); + v.normalize(); + inv_trans.mult_matrix_vec(v); + 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]; + } + } + + gDeferredSunProgram.uniform3fv(sOffset, slice, offset); + gDeferredSunProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, + deferred_light_target->getWidth(), + deferred_light_target->getHeight()); + + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + stop_glerror(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } + + unbindDeferredShader(gDeferredSunProgram); + } + deferred_light_target->flush(); + } - unbindDeferredShader(gDeferredSoftenProgram); - } + if (RenderDeferredSSAO) + { // soften direct lighting lightmap + LL_RECORD_BLOCK_TIME(FTM_SOFTEN_SHADOW); + // blur lightmap + screen_target->bindTarget(); + glClearColor(1, 1, 1, 1); + screen_target->clear(GL_COLOR_BUFFER_BIT); + glClearColor(0, 0, 0, 0); - { //render non-deferred geometry (fullbright, alpha, etc) - LLGLDisable blend(GL_BLEND); - LLGLDisable stencil(GL_STENCIL_TEST); - gGL.setSceneBlendType(LLRender::BT_ALPHA); + bindDeferredShader(gDeferredBlurLightProgram); + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + LLVector3 go = RenderShadowGaussian; + const U32 kern_length = 4; + F32 blur_size = RenderShadowBlurSize; + F32 dist_factor = RenderShadowBlurDistFactor; - gPipeline.pushRenderTypeMask(); - - gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_CLOUDS, - LLPipeline::RENDER_TYPE_WL_SKY, - LLPipeline::END_RENDER_TYPES); - - - renderGeomPostDeferred(*LLViewerCamera::getInstance(), false); - gPipeline.popRenderTypeMask(); - } + // sample symmetrically with the middle sample falling exactly on 0.0 + F32 x = 0.f; - bool render_local = RenderLocalLights; - - if (render_local) - { - gGL.setSceneBlendType(LLRender::BT_ADD); - std::list<LLVector4> fullscreen_lights; - LLDrawable::drawable_list_t spot_lights; - LLDrawable::drawable_list_t fullscreen_spot_lights; + LLVector3 gauss[32]; // xweight, yweight, offset - for (U32 i = 0; i < 2; i++) - { - mTargetShadowSpotLight[i] = NULL; - } + for (U32 i = 0; i < kern_length; i++) + { + 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; + } - std::list<LLVector4> light_colors; + gDeferredBlurLightProgram.uniform2f(sDelta, 1.f, 0.f); + gDeferredBlurLightProgram.uniform1f(sDistFactor, dist_factor); + gDeferredBlurLightProgram.uniform3fv(sKern, kern_length, gauss[0].mV); + gDeferredBlurLightProgram.uniform1f(sKernScale, blur_size * (kern_length / 2.f - 0.5f)); - LLVertexBuffer::unbind(); + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + stop_glerror(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } - { - bindDeferredShader(gDeferredLightProgram); - - if (mCubeVB.isNull()) - { - mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB); - } + screen_target->flush(); + unbindDeferredShader(gDeferredBlurLightProgram); - 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; - } + bindDeferredShader(gDeferredBlurLightProgram, screen_target); - if (volume->isAttachment()) - { - if (!sRenderAttachedLights) - { - continue; - } - } + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + deferred_light_target->bindTarget(); + gDeferredBlurLightProgram.uniform2f(sDelta, 0.f, 1.f); - LLVector4a center; - center.load3(drawablep->getPositionAgent().mV); - const F32* c = center.getF32ptr(); - F32 s = volume->getLightRadius()*1.5f; + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + stop_glerror(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } + deferred_light_target->flush(); + unbindDeferredShader(gDeferredBlurLightProgram); + } - LLColor3 col = volume->getLightColor(); - - if (col.magVecSquared() < 0.001f) - { - continue; - } + stop_glerror(); + gGL.popMatrix(); + stop_glerror(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + stop_glerror(); + gGL.popMatrix(); + stop_glerror(); - if (s <= 0.001f) - { - continue; - } + screen_target->bindTarget(); + // clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky + glClearColor(0, 0, 0, 0); + screen_target->clear(GL_COLOR_BUFFER_BIT); - LLVector4a sa; - sa.splat(s); - if (camera->AABBInFrustumNoFarClip(center, sa) == 0) - { - continue; - } + if (RenderDeferredAtmospheric) + { // apply sunlight contribution + LLGLSLShader &soften_shader = LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram; - 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) - { //draw box if camera is outside box - if (render_local) - { - if (volume->isLightSpotlight()) - { - drawablep->getVOVolume()->updateSpotLightPriority(); - spot_lights.push_back(drawablep); - continue; - } - - /*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); - 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(); - } - } - else - { - if (volume->isLightSpotlight()) - { - drawablep->getVOVolume()->updateSpotLightPriority(); - fullscreen_spot_lights.push_back(drawablep); - continue; - } + LL_RECORD_BLOCK_TIME(FTM_ATMOSPHERICS); + bindDeferredShader(soften_shader); - glh::vec3f tc(c); - mat.mult_matrix_vec(tc); - - fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s)); - light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f)); - } - } - unbindDeferredShader(gDeferredLightProgram); - } + LLEnvironment &environment = LLEnvironment::instance(); + soften_shader.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); + soften_shader.uniform4fv(LLShaderMgr::LIGHTNORM, 1, environment.getClampedLightNorm().mV); - if (!spot_lights.empty()) - { - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - bindDeferredShader(gDeferredSpotLightProgram); + { + LLGLDepthTest depth(GL_FALSE); + LLGLDisable blend(GL_BLEND); + LLGLDisable test(GL_ALPHA_TEST); - mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + // full screen blit + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); - gDeferredSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION); + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter) - { - LL_RECORD_BLOCK_TIME(FTM_PROJECTORS); - LLDrawable* drawablep = *iter; + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - LLVOVolume* volume = drawablep->getVOVolume(); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + } - LLVector4a center; - center.load3(drawablep->getPositionAgent().mV); - const F32* c = center.getF32ptr(); - F32 s = volume->getLightRadius()*1.5f; + unbindDeferredShader(LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram); + } - sVisibleLightCount++; + { // render non-deferred geometry (fullbright, alpha, etc) + LLGLDisable blend(GL_BLEND); + LLGLDisable stencil(GL_STENCIL_TEST); + gGL.setSceneBlendType(LLRender::BT_ALPHA); - 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); - 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)); - } - gDeferredSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION); - unbindDeferredShader(gDeferredSpotLightProgram); - } + gPipeline.pushRenderTypeMask(); - //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); + gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_CLOUDS, + LLPipeline::RENDER_TYPE_WL_SKY, + LLPipeline::END_RENDER_TYPES); - { - LLGLDepthTest depth(GL_FALSE); + renderGeomPostDeferred(*LLViewerCamera::getInstance(), false); + gPipeline.popRenderTypeMask(); + } - //full screen blit - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); + bool render_local = RenderLocalLights; - U32 count = 0; + if (render_local) + { + gGL.setSceneBlendType(LLRender::BT_ADD); + std::list<LLVector4> fullscreen_lights; + LLDrawable::drawable_list_t spot_lights; + LLDrawable::drawable_list_t fullscreen_spot_lights; - const U32 max_count = LL_DEFERRED_MULTI_LIGHT_COUNT; - LLVector4 light[max_count]; - LLVector4 col[max_count]; + for (U32 i = 0; i < 2; i++) + { + mTargetShadowSpotLight[i] = NULL; + } - F32 far_z = 0.f; + std::list<LLVector4> light_colors; - 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; - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - } - } - - unbindDeferredShader(gDeferredMultiLightProgram[0]); + LLVertexBuffer::unbind(); - bindDeferredShader(gDeferredMultiSpotLightProgram); + { + 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); + // mNearbyLights already includes distance calculation and excludes muted avatars. + // It is calculated from mLights + // mNearbyLights also provides fade value to gracefully fade-out out of range lights + for (light_set_t::iterator iter = mNearbyLights.begin(); iter != mNearbyLights.end(); ++iter) + { + LLDrawable * drawablep = iter->drawable; + LLVOVolume * volume = drawablep->getVOVolume(); + if (!volume) + { + continue; + } + + if (volume->isAttachment()) + { + if (!sRenderAttachedLights) + { + continue; + } + } + + LLVector4a center; + center.load3(drawablep->getPositionAgent().mV); + const F32 *c = center.getF32ptr(); + F32 s = volume->getLightRadius() * 1.5f; + + // send light color to shader in linear space + LLColor3 col = volume->getLightLinearColor(); + + if (col.magVecSquared() < 0.001f) + { + continue; + } + + if (s <= 0.001f) + { + continue; + } + + LLVector4a sa; + sa.splat(s); + if (camera->AABBInFrustumNoFarClip(center, sa) == 0) + { + continue; + } + + 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) + { // 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(DEFERRED_LIGHT_FALLOFF)); + gGL.syncMatrices(); + + 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::vec3f tc(c); + mat.mult_matrix_vec(tc); + + fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s)); + light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff(DEFERRED_LIGHT_FALLOFF))); + } + } + + // Bookmark comment to allow searching for mSpecialRenderMode == 3 (avatar edit mode), + // prev site of appended deferred character light, removed by SL-13522 09/20 + + unbindDeferredShader(gDeferredLightProgram); + } - gDeferredMultiSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION); + if (!spot_lights.empty()) + { + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + bindDeferredShader(gDeferredSpotLightProgram); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - 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(); + gDeferredSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION); - LLVector3 center = drawablep->getPositionAgent(); - F32* c = center.mV; - F32 s = volume->getLightRadius()*1.5f; + for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter) + { + LL_RECORD_BLOCK_TIME(FTM_PROJECTORS); + LLDrawable *drawablep = *iter; - sVisibleLightCount++; + LLVOVolume *volume = drawablep->getVOVolume(); - glh::vec3f tc(c); - mat.mult_matrix_vec(tc); - - setupSpotLight(gDeferredMultiSpotLightProgram, drawablep); + LLVector4a center; + center.load3(drawablep->getPositionAgent().mV); + const F32 *c = center.getF32ptr(); + F32 s = volume->getLightRadius() * 1.5f; - 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, tc.v); - 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); - } + sVisibleLightCount++; - gDeferredMultiSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION); - unbindDeferredShader(gDeferredMultiSpotLightProgram); + setupSpotLight(gDeferredSpotLightProgram, drawablep); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - } - } + // send light color to shader in linear space + LLColor3 col = volume->getLightLinearColor(); - gGL.setColorMask(true, true); - } + 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(DEFERRED_LIGHT_FALLOFF)); + gGL.syncMatrices(); - /*target->flush(); + mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, center)); + } + gDeferredSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION); + unbindDeferredShader(gDeferredSpotLightProgram); + } - //gamma correct lighting - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - gGL.loadIdentity(); + // 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); - { - LLGLDepthTest depth(GL_FALSE, GL_FALSE); + { + 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(); + + far_z = llmin(light[count].mV[2] - light[count].mV[3], far_z); + 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; + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + unbindDeferredShader(gDeferredMultiLightProgram[idx]); + } + } + + 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) + { + LL_RECORD_BLOCK_TIME(FTM_PROJECTORS); + LLDrawable *drawablep = *iter; + LLVOVolume *volume = drawablep->getVOVolume(); + LLVector3 center = drawablep->getPositionAgent(); + F32 * c = center.mV; + F32 light_size_final = volume->getLightRadius() * 1.5f; + F32 light_falloff_final = volume->getLightFalloff(DEFERRED_LIGHT_FALLOFF); + + sVisibleLightCount++; + + glh::vec3f tc(c); + mat.mult_matrix_vec(tc); + + setupSpotLight(gDeferredMultiSpotLightProgram, drawablep); + + // send light color to shader in linear space + LLColor3 col = volume->getLightLinearColor(); + + gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v); + gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, light_size_final); + gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); + gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, light_falloff_final); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + } + + gDeferredMultiSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION); + unbindDeferredShader(gDeferredMultiSpotLightProgram); + + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + } + } - LLVector2 tc1(0,0); - LLVector2 tc2((F32) target->getWidth()*2, - (F32) target->getHeight()*2); + gGL.setColorMask(true, true); + } - target->bindTarget(); - // Apply gamma correction to the frame here. - gDeferredPostGammaCorrectProgram.bind(); - //mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - S32 channel = 0; - channel = gDeferredPostGammaCorrectProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, target->getUsage()); - if (channel > -1) - { - target->bindTexture(0,channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - gDeferredPostGammaCorrectProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, target->getWidth(), target->getHeight()); - - F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); + screen_target->flush(); - gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); - - 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(); - - gGL.getTexUnit(channel)->unbind(target->getUsage()); - gDeferredPostGammaCorrectProgram.unbind(); - target->flush(); - } + // gamma correct lighting + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); + { + LLGLDepthTest depth(GL_FALSE, GL_FALSE); - target->bindTarget();*/ + LLVector2 tc1(0, 0); + LLVector2 tc2((F32) screen_target->getWidth() * 2, (F32) screen_target->getHeight() * 2); - { //render non-deferred geometry (alpha, fullbright, glow) - LLGLDisable blend(GL_BLEND); - LLGLDisable stencil(GL_STENCIL_TEST); + screen_target->bindTarget(); + // Apply gamma correction to the frame here. + gDeferredPostGammaCorrectProgram.bind(); + // mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + S32 channel = 0; + channel = gDeferredPostGammaCorrectProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, screen_target->getUsage()); + if (channel > -1) + { + screen_target->bindTexture(0, channel, LLTexUnit::TFO_POINT); + } - 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_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(); - } + gDeferredPostGammaCorrectProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, screen_target->getWidth(), screen_target->getHeight()); + + F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); + + gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f)); + + 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(); + + gGL.getTexUnit(channel)->unbind(screen_target->getUsage()); + gDeferredPostGammaCorrectProgram.unbind(); + screen_target->flush(); + } + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + + screen_target->bindTarget(); + + { // render non-deferred geometry (alpha, fullbright, glow) + LLGLDisable blend(GL_BLEND); + LLGLDisable stencil(GL_STENCIL_TEST); + + 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_PASS_INVISIBLE, + LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY, + LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_CONTROL_AV, + 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(); + gSky.addSunMoonBeacons(); + } + } - //target->flush(); + screen_target->flush(); } void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) @@ -9585,7 +9095,7 @@ void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) 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 light_to_screen = get_current_modelview() * light_to_agent; glh::matrix4f screen_to_light = light_to_screen.inverse(); @@ -9697,12 +9207,16 @@ void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) void LLPipeline::unbindDeferredShader(LLGLSLShader &shader) { + LLRenderTarget* deferred_target = &mDeferredScreen; + LLRenderTarget* deferred_depth_target = &mDeferredDepth; + LLRenderTarget* deferred_light_target = &mDeferredLight; + stop_glerror(); - shader.disableTexture(LLShaderMgr::DEFERRED_NORMAL, mDeferredScreen.getUsage()); - shader.disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredScreen.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_NORMAL, deferred_target->getUsage()); + shader.disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, deferred_target->getUsage()); + shader.disableTexture(LLShaderMgr::DEFERRED_SPECULAR, deferred_target->getUsage()); + shader.disableTexture(LLShaderMgr::DEFERRED_DEPTH, deferred_depth_target->getUsage()); + shader.disableTexture(LLShaderMgr::DEFERRED_LIGHT, deferred_light_target->getUsage()); shader.disableTexture(LLShaderMgr::DIFFUSE_MAP); shader.disableTexture(LLShaderMgr::DEFERRED_BLOOM); @@ -9747,327 +9261,300 @@ inline float sgn(float a) } void LLPipeline::generateWaterReflection(LLCamera& camera_in) -{ - if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate) - { - bool skip_avatar_update = false; - if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson) - { - skip_avatar_update = true; - } - - if (!skip_avatar_update) - { - gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON); - } - LLVertexBuffer::unbind(); +{ + if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate) + { + bool skip_avatar_update = false; + if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson) + { + skip_avatar_update = true; + } - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); + LLCamera camera = camera_in; + camera.setFar(camera_in.getFar() * 0.75f); - LLCamera camera = camera_in; - camera.setFar(camera.getFar()*0.87654321f); - LLPipeline::sReflectionRender = true; - - gPipeline.pushRenderTypeMask(); + bool camera_is_underwater = LLViewerCamera::getInstance()->cameraUnderWater(); - glh::matrix4f projection = glh_get_current_projection(); - glh::matrix4f mat; + LLPipeline::sReflectionRender = true; - stop_glerror(); - LLPlane plane; + gPipeline.pushRenderTypeMask(); - F32 height = gAgent.getRegion()->getWaterHeight(); - F32 to_clip = fabsf(camera.getOrigin().mV[2]-height); - F32 pad = -to_clip*0.05f; //amount to "pad" clip plane by + glh::matrix4f saved_modelview = get_current_modelview(); + glh::matrix4f saved_projection = get_current_projection(); + glh::matrix4f mat; - //plane params - LLVector3 pnorm; - F32 pd; + S32 reflection_detail = RenderReflectionDetail; - S32 water_clip = 0; - if (!LLViewerCamera::getInstance()->cameraUnderWater()) - { //camera is above water, clip plane points up - pnorm.setVec(0,0,1); - pd = -height; - plane.setVec(pnorm, pd); - water_clip = -1; - } - else - { //camera is below water, clip plane points down - pnorm = LLVector3(0,0,-1); - pd = height; - plane.setVec(pnorm, pd); - water_clip = 1; - } + F32 water_height = gAgent.getRegion()->getWaterHeight(); + F32 camera_height = camera_in.getOrigin().mV[VZ]; + F32 distance_to_water = (water_height < camera_height) ? (camera_height - water_height) : (water_height - camera_height); - bool materials_in_water = false; + LLVector3 reflection_offset = LLVector3(0, 0, distance_to_water * 2.0f); + LLVector3 camera_look_at = camera_in.getAtAxis(); + LLVector3 reflection_look_at = LLVector3(camera_look_at.mV[VX], camera_look_at.mV[VY], -camera_look_at.mV[VZ]); + LLVector3 reflect_origin = camera_in.getOrigin() - reflection_offset; + LLVector3 reflect_interest_point = reflect_origin + (reflection_look_at * 5.0f); -#if MATERIALS_IN_REFLECTIONS - materials_in_water = gSavedSettings.getS32("RenderWaterMaterials"); -#endif + camera.setOriginAndLookAt(reflect_origin, LLVector3::z_axis, reflect_interest_point); - if (!LLViewerCamera::getInstance()->cameraUnderWater()) - { //generate planar reflection map + //plane params + LLPlane plane; + LLVector3 pnorm; + S32 water_clip = 0; + if (!camera_is_underwater) + { + //camera is above water, clip plane points up + pnorm.setVec(0,0,1); + plane.setVec(pnorm, -water_height); + water_clip = 1; + } + else + { + //camera is below water, clip plane points down + pnorm = LLVector3(0,0,-1); + plane.setVec(pnorm, water_height); + water_clip = -1; + } - //disable occlusion culling for reflection map for now - S32 occlusion = LLPipeline::sUseOcclusion; - LLPipeline::sUseOcclusion = 0; - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - glClearColor(0,0,0,0); + S32 occlusion = LLPipeline::sUseOcclusion; - mWaterRef.bindTarget(); + //disable occlusion culling for reflection map for now + LLPipeline::sUseOcclusion = 0; - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER0; - gGL.setColorMask(true, true); - mWaterRef.clear(); - gGL.setColorMask(true, false); + if (!camera_is_underwater) + { + //generate planar reflection map + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER0; - mWaterRef.getViewport(gGLViewport); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); - stop_glerror(); + mat.set_scale(glh::vec3f(1, 1, -1)); + mat.set_translate(glh::vec3f(0,0,water_height*2.f)); + mat = saved_modelview * mat; - gGL.pushMatrix(); - mat.set_scale(glh::vec3f(1,1,-1)); - mat.set_translate(glh::vec3f(0,0,height*2.f)); + mReflectionModelView = mat; - glh::matrix4f current = glh_get_current_modelview(); + set_current_modelview(mat); + gGL.loadMatrix(mat.m); - mat = current * mat; + LLViewerCamera::updateFrustumPlanes(camera, FALSE, TRUE); - glh_set_current_modelview(mat); - gGL.loadMatrix(mat.m); + glh::vec3f origin(0, 0, 0); + glh::matrix4f inv_mat = mat.inverse(); + inv_mat.mult_matrix_vec(origin); - LLViewerCamera::updateFrustumPlanes(camera, FALSE, TRUE); + camera.setOrigin(origin.v); - glh::matrix4f inv_mat = mat.inverse(); + glCullFace(GL_FRONT); - glh::vec3f origin(0,0,0); - inv_mat.mult_matrix_vec(origin); + if (LLDrawPoolWater::sNeedsReflectionUpdate) + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + glClearColor(0,0,0,0); + mWaterRef.bindTarget(); + + gGL.setColorMask(true, true); + mWaterRef.clear(); + gGL.setColorMask(true, false); + mWaterRef.getViewport(gGLViewport); + + //initial sky pass (no user clip plane) + //mask out everything but the sky + gPipeline.pushRenderTypeMask(); + { + if (reflection_detail >= WATER_REFLECT_MINIMAL) + { + gPipeline.andRenderTypeMask( + LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_WL_SKY, + LLPipeline::RENDER_TYPE_CLOUDS, + LLPipeline::END_RENDER_TYPES); + } + else + { + gPipeline.andRenderTypeMask( + LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_WL_SKY, + LLPipeline::END_RENDER_TYPES); + } + + updateCull(camera, mSky); + stateSort(camera, mSky); + renderGeom(camera, TRUE); + } + gPipeline.popRenderTypeMask(); + + if (reflection_detail >= WATER_REFLECT_NONE_WATER_TRANSPARENT) + { + gPipeline.pushRenderTypeMask(); + { + clearRenderTypeMask( + LLPipeline::RENDER_TYPE_WATER, + LLPipeline::RENDER_TYPE_VOIDWATER, + LLPipeline::RENDER_TYPE_GROUND, + LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_CLOUDS, + LLPipeline::END_RENDER_TYPES); + + if (reflection_detail > WATER_REFLECT_MINIMAL) + { //mask out selected geometry based on reflection detail + if (reflection_detail < WATER_REFLECT_EVERYTHING) + { + clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES); + if (reflection_detail < WATER_REFLECT_AVATARS) + { + clearRenderTypeMask( + LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_CONTROL_AV, + END_RENDER_TYPES); + if (reflection_detail < WATER_REFLECT_STATIC_OBJECTS) + { + clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES); + } + } + } + + LLGLUserClipPlane clip_plane(plane, mReflectionModelView, saved_projection); + LLGLDisable cull(GL_CULL_FACE); + updateCull(camera, mReflectedObjects, -water_clip, &plane); + stateSort(camera, mReflectedObjects); + renderGeom(camera); + } + } + gPipeline.popRenderTypeMask(); + } + + mWaterRef.flush(); + } - camera.setOrigin(origin.v); + glCullFace(GL_BACK); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); - glCullFace(GL_FRONT); + set_current_modelview(saved_modelview); + } - static LLCullResult ref_result; + //LLPipeline::sUseOcclusion = occlusion; - if (LLDrawPoolWater::sNeedsReflectionUpdate) - { - //initial sky pass (no user clip plane) - { //mask out everything but the sky - gPipeline.pushRenderTypeMask(); - gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_WL_SKY, - LLPipeline::RENDER_TYPE_CLOUDS, - LLPipeline::END_RENDER_TYPES); + camera.setOrigin(camera_in.getOrigin()); + //render distortion map + static bool last_update = true; + if (last_update) + { + gPipeline.pushRenderTypeMask(); - static LLCullResult result; - updateCull(camera, result); - stateSort(camera, result); + camera.setFar(camera_in.getFar()); + clearRenderTypeMask( + LLPipeline::RENDER_TYPE_WATER, + LLPipeline::RENDER_TYPE_VOIDWATER, + LLPipeline::RENDER_TYPE_GROUND, + END_RENDER_TYPES); - if (LLPipeline::sRenderDeferred && materials_in_water) - { - mWaterRef.flush(); + // intentionally inverted so that distortion map contents (objects under the water when we're above it) + // will properly include water fog effects + LLPipeline::sUnderWaterRender = !camera_is_underwater; - gPipeline.grabReferences(result); - gPipeline.mDeferredScreen.bindTarget(); - gGL.setColorMask(true, true); - glClearColor(0,0,0,0); - gPipeline.mDeferredScreen.clear(); + if (LLPipeline::sUnderWaterRender) + { + clearRenderTypeMask( + LLPipeline::RENDER_TYPE_GROUND, + LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_CLOUDS, + LLPipeline::RENDER_TYPE_WL_SKY, + END_RENDER_TYPES); + } + LLViewerCamera::updateFrustumPlanes(camera); - renderGeomDeferred(camera); - } - else - { - renderGeom(camera, TRUE); - } + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gPipeline.popRenderTypeMask(); - } + if (LLPipeline::sUnderWaterRender || LLDrawPoolWater::sNeedsDistortionUpdate) + { + LLPipeline::sDistortionRender = true; - gGL.setColorMask(true, false); - gPipeline.pushRenderTypeMask(); + LLColor3 col = LLEnvironment::instance().getCurrentWater()->getWaterFogColor(); + glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f); - clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER, - LLPipeline::RENDER_TYPE_VOIDWATER, - LLPipeline::RENDER_TYPE_GROUND, - LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_CLOUDS, - LLPipeline::END_RENDER_TYPES); + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1; - S32 detail = RenderReflectionDetail; - if (detail > 0) - { //mask out selected geometry based on reflection detail + mWaterDis.bindTarget(); + mWaterDis.getViewport(gGLViewport); - if (detail < 4) - { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES); - if (detail < 3) - { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); - if (detail < 2) - { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES); - } - } - } + gGL.setColorMask(true, true); + mWaterDis.clear(); + gGL.setColorMask(true, false); + F32 water_dist = water_height * LLPipeline::sDistortionWaterClipPlaneMargin; - LLGLUserClipPlane clip_plane(plane, mat, projection); - LLGLDisable cull(GL_CULL_FACE); - updateCull(camera, ref_result, -water_clip, &plane); - stateSort(camera, ref_result); - } + //clip out geometry on the same side of water as the camera w/ enough margin to not include the water geo itself, + // but not so much as to clip out parts of avatars that should be seen under the water in the distortion map + LLPlane plane(-pnorm, water_dist); + LLGLUserClipPlane clip_plane(plane, saved_modelview, saved_projection); - if (LLDrawPoolWater::sNeedsDistortionUpdate) - { - if (RenderReflectionDetail > 0) - { - gPipeline.grabReferences(ref_result); - LLGLUserClipPlane clip_plane(plane, mat, projection); + gGL.setColorMask(true, true); + mWaterDis.clear(); + gGL.setColorMask(true, false); - if (LLPipeline::sRenderDeferred && materials_in_water) - { - renderGeomDeferred(camera); - } - else - { - renderGeom(camera); - } - } - } + // ignore clip plane if we're underwater and viewing distortion map of objects above waterline + if (camera_is_underwater) + { + clip_plane.disable(); + } - if (LLPipeline::sRenderDeferred && materials_in_water) - { - gPipeline.mDeferredScreen.flush(); - renderDeferredLightingToRT(&mWaterRef); - } + if (reflection_detail >= WATER_REFLECT_NONE_WATER_TRANSPARENT) + { + updateCull(camera, mRefractedObjects, water_clip, &plane); + stateSort(camera, mRefractedObjects); + renderGeom(camera); + } - gPipeline.popRenderTypeMask(); - } - glCullFace(GL_BACK); - gGL.popMatrix(); - mWaterRef.flush(); - glh_set_current_modelview(current); - LLPipeline::sUseOcclusion = occlusion; - } + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.bind(); + } - camera.setOrigin(camera_in.getOrigin()); - //render distortion map - static bool last_update = true; - if (last_update) - { - camera.setFar(camera_in.getFar()); - clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER, - LLPipeline::RENDER_TYPE_VOIDWATER, - LLPipeline::RENDER_TYPE_GROUND, - END_RENDER_TYPES); - stop_glerror(); - - LLPipeline::sUnderWaterRender = ! LLViewerCamera::getInstance()->cameraUnderWater(); + LLWorld::getInstance()->renderPropertyLines(); - if (LLPipeline::sUnderWaterRender) - { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_GROUND, - LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_CLOUDS, - LLPipeline::RENDER_TYPE_WL_SKY, - END_RENDER_TYPES); - } - LLViewerCamera::updateFrustumPlanes(camera); + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.unbind(); + } - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - LLColor4& col = LLDrawPoolWater::sWaterFogColor; - glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f); - mWaterDis.bindTarget(); - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1; - - mWaterDis.getViewport(gGLViewport); - - 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); - static LLCullResult result; - updateCull(camera, result, water_clip, &plane); - stateSort(camera, result); + mWaterDis.flush(); + } - gGL.setColorMask(true, true); - mWaterDis.clear(); - + LLPipeline::sDistortionRender = false; - gGL.setColorMask(true, false); + gPipeline.popRenderTypeMask(); + } + last_update = LLDrawPoolWater::sNeedsReflectionUpdate && LLDrawPoolWater::sNeedsDistortionUpdate; - - 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); + gPipeline.popRenderTypeMask(); - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } - - LLWorld::getInstance()->renderPropertyLines(); - - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.unbind(); - } - } + LLPipeline::sUseOcclusion = occlusion; + LLPipeline::sUnderWaterRender = false; + LLPipeline::sReflectionRender = false; - if (LLPipeline::sRenderDeferred && materials_in_water) - { - gPipeline.mDeferredScreen.flush(); - renderDeferredLightingToRT(&mWaterDis); - } - } + LLDrawPoolWater::sNeedsReflectionUpdate = FALSE; + LLDrawPoolWater::sNeedsDistortionUpdate = FALSE; - mWaterDis.flush(); - LLPipeline::sUnderWaterRender = false; - - } - last_update = LLDrawPoolWater::sNeedsReflectionUpdate && LLDrawPoolWater::sNeedsDistortionUpdate; + if (!LLRenderTarget::sUseFBO) + { + glClear(GL_DEPTH_BUFFER_BIT); + } + glClearColor(0.f, 0.f, 0.f, 0.f); + gViewerWindow->setup3DViewport(); - LLPipeline::sReflectionRender = false; + LLGLState::checkStates(); - if (!LLRenderTarget::sUseFBO) - { - glClear(GL_DEPTH_BUFFER_BIT); - } - glClearColor(0.f, 0.f, 0.f, 0.f); - gViewerWindow->setup3DViewport(); - gPipeline.popRenderTypeMask(); - LLDrawPoolWater::sNeedsReflectionUpdate = FALSE; - LLDrawPoolWater::sNeedsDistortionUpdate = FALSE; - LLPlane npnorm(-pnorm, -pd); - LLViewerCamera::getInstance()->setUserClipPlane(npnorm); - - LLGLState::checkStates(); - - if (!skip_avatar_update) - { - gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode()); - } + if (!skip_avatar_update) + { + gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode()); + } - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; - } + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + } } glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up) @@ -10139,6 +9626,13 @@ glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max) static LLTrace::BlockTimerStatHandle FTM_SHADOW_RENDER("Render Shadows"); static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA("Alpha Shadow"); static LLTrace::BlockTimerStatHandle FTM_SHADOW_SIMPLE("Simple Shadow"); +static LLTrace::BlockTimerStatHandle FTM_SHADOW_GEOM("Shadow Geom"); + +static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_MASKED("Alpha Masked"); +static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_BLEND("Alpha Blend"); +static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_TREE("Alpha Tree"); +static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_GRASS("Alpha Grass"); +static LLTrace::BlockTimerStatHandle FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED("Fullbright Alpha Masked"); void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, bool use_shader, bool use_occlusion, U32 target_width) { @@ -10193,7 +9687,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera gGL.loadMatrix(proj.m); gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.pushMatrix(); - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(view.m); stop_glerror(); gGLLastMatrix = NULL; @@ -10202,6 +9696,8 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera stop_glerror(); + LLEnvironment& environment = LLEnvironment::instance(); + LLVertexBuffer::unbind(); { @@ -10212,10 +9708,18 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera else { gDeferredShadowProgram.bind(); + gDeferredShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); } gGL.diffuseColor4f(1,1,1,1); + + S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail"); + + // if not using VSM, disable color writes + if (shadow_detail <= 2) + { gGL.setColorMask(false, false); + } LL_RECORD_BLOCK_TIME(FTM_SHADOW_SIMPLE); @@ -10233,41 +9737,69 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera if (use_shader) { + LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM); + gDeferredShadowProgram.unbind(); renderGeomShadow(shadow_cam); gDeferredShadowProgram.bind(); + gDeferredShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); } else { + LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM); + renderGeomShadow(shadow_cam); } { LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA); + gDeferredShadowAlphaMaskProgram.bind(); gDeferredShadowAlphaMaskProgram.uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); + gDeferredShadowAlphaMaskProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX; + { + LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_MASKED); renderMaskedObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE); - renderMaskedObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE); + } + + { + LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_BLEND); gDeferredShadowAlphaMaskProgram.setMinimumAlpha(0.598f); renderObjects(LLRenderPass::PASS_ALPHA, mask, TRUE, TRUE); + } + + { + LL_RECORD_BLOCK_TIME(FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED); + gDeferredShadowFullbrightAlphaMaskProgram.bind(); + gDeferredShadowFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); + gDeferredShadowFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); + renderFullbrightMaskedObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE); + } mask = mask & ~LLVertexBuffer::MAP_TEXTURE_INDEX; + { + LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_TREE); gDeferredTreeShadowProgram.bind(); + gDeferredTreeShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); 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); + } + { + LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_GRASS); gDeferredTreeShadowProgram.setMinimumAlpha(0.598f); renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE); } + } //glCullFace(GL_BACK); @@ -10511,7 +10043,7 @@ void LLPipeline::generateHighlight(LLCamera& camera) gGL.setColorMask(true, true); mHighlight.clear(); - if (canUseVertexShaders()) + if (LLGLSLShader::sNoFixedFunction) { gHighlightProgram.bind(); } @@ -10550,8 +10082,16 @@ void LLPipeline::generateHighlight(LLCamera& camera) } } +LLRenderTarget* LLPipeline::getShadowTarget(U32 i) +{ + return &mShadow[i]; +} static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW("Gen Sun Shadow"); +static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_SETUP("Sun Shadow Setup"); +static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_RENDER_DIRECTIONAL("Render Dir"); +static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_SPOT_SETUP("Spot Shadow Setup"); +static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_SPOT_RENDER("Spot Shadow Render"); void LLPipeline::generateSunShadow(LLCamera& camera) { @@ -10590,6 +10130,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera) LLPipeline::RENDER_TYPE_BUMP, LLPipeline::RENDER_TYPE_VOLUME, LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_CONTROL_AV, LLPipeline::RENDER_TYPE_TREE, LLPipeline::RENDER_TYPE_TERRAIN, LLPipeline::RENDER_TYPE_WATER, @@ -10623,11 +10164,13 @@ void LLPipeline::generateSunShadow(LLCamera& camera) gGL.setColorMask(false, false); + LLEnvironment& environment = LLEnvironment::instance(); + //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 saved_proj = get_current_projection(); + glh::matrix4f saved_view = get_current_modelview(); glh::matrix4f inv_view = saved_view.inverse(); glh::matrix4f view[6]; @@ -10636,6 +10179,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera) //clip contains parallel split distances for 3 splits LLVector3 clip = RenderShadowClipPlanes; + LLVector3 caster_dir(environment.getIsSunUp() ? mSunDir : mMoonDir); + //F32 slope_threshold = gSavedSettings.getF32("RenderShadowSlopeThreshold"); //far clip on last split is minimum of camera view distance and 128 @@ -10652,11 +10197,11 @@ void LLPipeline::generateSunShadow(LLCamera& camera) LLPlane shadow_near_clip; { LLVector3 p = gAgent.getPositionAgent(); - p += mSunDir * RenderFarClip*2.f; - shadow_near_clip.setVec(p, mSunDir); + p += caster_dir * RenderFarClip*2.f; + shadow_near_clip.setVec(p, caster_dir); } - LLVector3 lightDir = -mSunDir; + LLVector3 lightDir = -caster_dir; lightDir.normVec(); glh::vec3f light_dir(lightDir.mV); @@ -10731,8 +10276,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera) update_min_max(min, max, fp[i]); } - near_clip = -max.mV[2]; - F32 far_clip = -min.mV[2]*2.f; + near_clip = llclamp(-max.mV[2], 0.01f, 4.0f); + F32 far_clip = llclamp(-min.mV[2]*2.f, 16.0f, 512.0f); //far_clip = llmin(far_clip, 128.f); far_clip = llmin(far_clip, camera.getFar()); @@ -10784,8 +10329,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera) LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SHADOW0+j); //restore render matrices - glh_set_current_modelview(saved_view); - glh_set_current_projection(saved_proj); + set_current_modelview(saved_view); + set_current_projection(saved_proj); LLVector3 eye = camera.getOrigin(); @@ -11098,8 +10643,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera) shadow_cam.setOrigin(0,0,0); - glh_set_current_modelview(view[j]); - glh_set_current_projection(proj[j]); + set_current_modelview(view[j]); + set_current_projection(proj[j]); LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); @@ -11112,8 +10657,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera) 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]); + set_current_modelview(view[j]); + set_current_projection(proj[j]); for (U32 i = 0; i < 16; i++) { @@ -11123,8 +10668,6 @@ void LLPipeline::generateSunShadow(LLCamera& camera) mShadowModelview[j] = view[j]; mShadowProjection[j] = proj[j]; - - mSunShadowMatrix[j] = trans*proj[j]*view[j]*inv_view; stop_glerror(); @@ -11137,15 +10680,13 @@ void LLPipeline::generateSunShadow(LLCamera& camera) { static LLCullResult result[4]; - - renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE, TRUE, target_width); + renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE, FALSE, target_width); } mShadow[j].flush(); if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) { - LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); mShadowCamera[j+4] = shadow_cam; } } @@ -11192,8 +10733,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera) for (S32 i = 0; i < 2; i++) { - glh_set_current_modelview(saved_view); - glh_set_current_projection(saved_proj); + set_current_modelview(saved_view); + set_current_projection(saved_proj); if (mShadowSpotLight[i].isNull()) { @@ -11253,8 +10794,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera) 0.f, 0.f, 0.5f, 0.5f, 0.f, 0.f, 0.f, 1.f); - glh_set_current_modelview(view[i+4]); - glh_set_current_projection(proj[i+4]); + set_current_modelview(view[i+4]); + set_current_projection(proj[i+4]); mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view; @@ -11285,8 +10826,12 @@ void LLPipeline::generateSunShadow(LLCamera& camera) LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SHADOW0 + i + 4); + RenderSpotLight = drawable; + renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE, target_width); + RenderSpotLight = nullptr; + mShadow[i+4].flush(); } } @@ -11298,13 +10843,13 @@ void LLPipeline::generateSunShadow(LLCamera& camera) if (!CameraOffset) { - glh_set_current_modelview(saved_view); - glh_set_current_projection(saved_proj); + set_current_modelview(saved_view); + set_current_projection(saved_proj); } else { - glh_set_current_modelview(view[1]); - glh_set_current_projection(proj[1]); + set_current_modelview(view[1]); + set_current_projection(proj[1]); gGL.loadMatrix(view[1].m); gGL.matrixMode(LLRender::MM_PROJECTION); gGL.loadMatrix(proj[1].m); @@ -11379,7 +10924,9 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) if (visually_muted || too_complex) { - andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); + andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_CONTROL_AV, + END_RENDER_TYPES); } else { @@ -11402,6 +10949,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) LLPipeline::RENDER_TYPE_PASS_INVISIBLE, LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY, LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_CONTROL_AV, LLPipeline::RENDER_TYPE_ALPHA_MASK, LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK, LLPipeline::RENDER_TYPE_INVISIBLE, @@ -11422,7 +10970,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) { LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_MARK_VISIBLE); markVisible(avatar->mDrawable, *viewer_camera); - LLVOAvatar::sUseImpostors = false; // @TODO ??? LLVOAvatar::attachment_map_t::iterator iter; for (iter = avatar->mAttachmentPoints.begin(); @@ -11434,7 +10981,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - if (LLViewerObject* attached_object = (*attachment_iter)) + if (LLViewerObject* attached_object = attachment_iter->get()) { markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera); } @@ -11482,7 +11029,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) 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); - glh_set_current_projection(persp); + set_current_projection(persp); gGL.loadMatrix(persp.m); gGL.matrixMode(LLRender::MM_MODELVIEW); @@ -11493,7 +11040,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat; gGL.loadMatrix(mat.m); - glh_set_current_modelview(mat); + set_current_modelview(mat); glClearColor(0.0f,0.0f,0.0f,0.0f); gGL.setColorMask(true, true); @@ -11662,7 +11209,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) avatar->setImpostorDim(tdim); - LLVOAvatar::sUseImpostors = (0 != LLVOAvatar::sMaxNonImpostors); sUseOcclusion = occlusion; sReflectionRender = false; sImpostorRender = false; diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 29fe1cbd33..0eaa6b141d 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -61,14 +61,7 @@ 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 LLTrace::BlockTimerStatHandle FTM_RENDER_GEOMETRY; extern LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS; @@ -91,6 +84,11 @@ extern LLTrace::BlockTimerStatHandle FTM_STATESORT; extern LLTrace::BlockTimerStatHandle FTM_PIPELINE; extern LLTrace::BlockTimerStatHandle FTM_CLIENT_COPY; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_HUD; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_3D; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_2D; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_DEBUG_TEXT; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_SCENE_MON; class LLPipeline { @@ -102,10 +100,17 @@ public: void restoreGL(); void resetVertexBuffers(); void doResetVertexBuffers(bool forced = false); + void requestResizeScreenTexture(); // set flag only, no work, safer for callbacks... + void requestResizeShadowTexture(); // set flag only, no work, safer for callbacks... + void resizeScreenTexture(); + void resizeShadowTexture(); + void releaseGLBuffers(); void releaseLUTBuffers(); void releaseScreenBuffers(); + void releaseShadowBuffers(); + void createGLBuffers(); void createLUTBuffers(); @@ -127,13 +132,14 @@ public: //attempt to allocate screen buffers at resX, resY //returns true if allocation successful, false otherwise bool allocateScreenBuffer(U32 resX, U32 resY, U32 samples); + bool allocateShadowBuffer(U32 resX, U32 resY); void allocatePhysicsBuffer(); void resetVertexBuffers(LLDrawable* drawable); void generateImpostor(LLVOAvatar* avatar); void bindScreenToTexture(); - void renderBloom(bool for_snapshot, F32 zoom_factor = 1.f, int subfield = 0); + void renderFinalize(); void init(); void cleanup(); @@ -213,6 +219,8 @@ public: U32 addObject(LLViewerObject *obj); void enableShadows(const bool enable_shadows); + void releaseShadowTargets(); + void releaseShadowTarget(U32 index); // void setLocalLighting(const bool local_lighting); // bool isLocalLightingEnabled() const; @@ -261,6 +269,7 @@ public: 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 renderFullbrightMaskedObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false); void renderGroups(LLRenderPass* pass, U32 type, U32 mask, bool texture); @@ -278,15 +287,17 @@ public: void renderGeomDeferred(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* light_target = nullptr); void setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep); void unbindDeferredShader(LLGLSLShader& shader); - void renderDeferredLighting(); - void renderDeferredLightingToRT(LLRenderTarget* target); - + void renderDeferredLighting(LLRenderTarget* light_target); + void postDeferredGammaCorrect(LLRenderTarget* screen_target); + void generateWaterReflection(LLCamera& camera); void generateSunShadow(LLCamera& camera); + LLRenderTarget* getShadowTarget(U32 i); + void generateHighlight(LLCamera& camera); void renderHighlight(const LLViewerObject* obj, F32 fade); void setHighlightObject(LLDrawable* obj) { mHighlightObject = obj; } @@ -313,7 +324,7 @@ public: void enableLightsAvatar(); void enableLightsPreview(); void enableLightsAvatarEdit(const LLColor4& color); - void enableLightsFullbright(const LLColor4& color); + void enableLightsFullbright(); void disableLights(); void shiftObjects(const LLVector3 &offset); @@ -398,14 +409,11 @@ public: static bool getRenderHighlights(); static void setRenderHighlightTextureChannel(LLRender::eTexIndex channel); // sets which UV setup to display in highlight overlay + static void updateRenderTransparentWater(); static void updateRenderBump(); static void updateRenderDeferred(); static void refreshCachedSettings(); - static void throttleNewMemoryAllocation(bool disable); - - - void addDebugBlip(const LLVector3& position, const LLColor4& color); void hidePermanentObjects( std::vector<U32>& restoreList ); @@ -442,6 +450,7 @@ public: RENDER_TYPE_BUMP = LLDrawPool::POOL_BUMP, RENDER_TYPE_MATERIALS = LLDrawPool::POOL_MATERIALS, RENDER_TYPE_AVATAR = LLDrawPool::POOL_AVATAR, + RENDER_TYPE_CONTROL_AV = LLDrawPool::POOL_CONTROL_AV, // Animesh RENDER_TYPE_TREE = LLDrawPool::POOL_TREE, RENDER_TYPE_INVISIBLE = LLDrawPool::POOL_INVISIBLE, RENDER_TYPE_VOIDWATER = LLDrawPool::POOL_VOIDWATER, @@ -566,6 +575,7 @@ public: static bool sAutoMaskAlphaDeferred; static bool sAutoMaskAlphaNonDeferred; static bool sDisableShaders; // if true, rendering will be done without shaders + static bool sRenderTransparentWater; static bool sRenderBump; static bool sBakeSunlight; static bool sNoAlpha; @@ -576,6 +586,7 @@ public: static bool sDynamicLOD; static bool sPickAvatar; static bool sReflectionRender; + static bool sDistortionRender; static bool sImpostorRender; static bool sImpostorRenderAlphaDepthPass; static bool sUnderWaterRender; @@ -585,10 +596,10 @@ public: static bool sRenderAttachedLights; static bool sRenderAttachedParticles; static bool sRenderDeferred; - static bool sMemAllocationThrottled; static S32 sVisibleLightCount; static F32 sMinRenderSize; static bool sRenderingHUDs; + static F32 sDistortionWaterClipPlaneMargin; static LLTrace::EventStatHandle<S64> sStatBatchSize; @@ -607,6 +618,10 @@ public: LLRenderTarget mHighlight; LLRenderTarget mPhysicsDisplay; + LLCullResult mSky; + LLCullResult mReflectedObjects; + LLCullResult mRefractedObjects; + //utility buffer for rendering post effects, gets abused by renderDeferredLighting LLPointer<LLVertexBuffer> mDeferredVB; @@ -625,22 +640,14 @@ public: 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; - - LLPointer<LLDrawable> mShadowSpotLight[2]; - F32 mSpotLightFade[2]; - LLPointer<LLDrawable> mTargetShadowSpotLight[2]; + glh::matrix4f mReflectionModelView; + + LLPointer<LLDrawable> mShadowSpotLight[2]; + F32 mSpotLightFade[2]; + LLPointer<LLDrawable> mTargetShadowSpotLight[2]; LLVector4 mSunClipPlanes; LLVector4 mSunOrthoClipPlanes; - LLVector2 mScreenScale; //water reflection texture @@ -649,6 +656,8 @@ public: //water distortion texture (refraction) LLRenderTarget mWaterDis; + LLRenderTarget mBake; + //texture for making the glow LLRenderTarget mGlow[3]; @@ -657,9 +666,14 @@ public: U32 mTrueNoiseMap; U32 mLightFunc; - LLColor4 mSunDiffuse; - LLVector3 mSunDir; - LLVector3 mTransformedSunDir; + LLColor4 mSunDiffuse; + LLColor4 mMoonDiffuse; + LLVector4 mSunDir; + LLVector4 mMoonDir; + bool mNeedsShadowTargetClear; + + LLVector4 mTransformedSunDir; + LLVector4 mTransformedMoonDir; bool mInitialized; bool mVertexShadersEnabled; @@ -864,7 +878,6 @@ public: //cached settings static bool WindLightUseAtmosShaders; - static bool VertexShaderEnable; static bool RenderAvatarVP; static bool RenderDeferred; static F32 RenderDeferredSunWash; @@ -920,6 +933,7 @@ public: static F32 RenderShadowBias; static F32 RenderSpotShadowOffset; static F32 RenderSpotShadowBias; + static LLDrawable* RenderSpotLight; static F32 RenderEdgeDepthCutoff; static F32 RenderEdgeNormCutoff; static LLVector3 RenderShadowGaussian; diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc index 8587243791..ff2d8b4943 100755 --- a/indra/newview/res/viewerRes.rc +++ b/indra/newview/res/viewerRes.rc @@ -155,7 +155,7 @@ BEGIN VALUE "FileDescription", "Second Life" VALUE "FileVersion", "${VIEWER_VERSION_MAJOR}.${VIEWER_VERSION_MINOR}.${VIEWER_VERSION_PATCH}.${VIEWER_VERSION_REVISION}" VALUE "InternalName", "Second Life" - VALUE "LegalCopyright", "Copyright � 2001, Linden Research, Inc." + VALUE "LegalCopyright", "Copyright (c) 2020, Linden Research, Inc." VALUE "OriginalFilename", "SecondLife.exe" VALUE "ProductName", "Second Life" VALUE "ProductVersion", "${VIEWER_VERSION_MAJOR}.${VIEWER_VERSION_MINOR}.${VIEWER_VERSION_PATCH}.${VIEWER_VERSION_REVISION}" diff --git a/indra/newview/roles_constants.h b/indra/newview/roles_constants.h index 24792dd731..fecf5f9d4a 100644 --- a/indra/newview/roles_constants.h +++ b/indra/newview/roles_constants.h @@ -52,7 +52,6 @@ enum LLRoleChangeType // // KNOWN HOLES: use these for any single bit powers you need -// bit 0x1 << 46 // bit 0x1 << 52 and above // These powers were removed to make group roles simpler @@ -103,6 +102,7 @@ const U64 GP_LAND_ALLOW_CREATE = 0x1LL << 25; // Bypass Create/Edit Objects Re const U64 GP_LAND_ALLOW_LANDMARK = 0x1LL << 26; // Bypass Landmark Restriction const U64 GP_LAND_ALLOW_SET_HOME = 0x1LL << 28; // Bypass Set Home Point Restriction const U64 GP_LAND_ALLOW_HOLD_EVENT = 0x1LL << 41; // Allowed to hold events on group-owned land +const U64 GP_LAND_ALLOW_ENVIRONMENT = 0x1LL << 46; // Allowed to change the environment // Parcel Access const U64 GP_LAND_MANAGE_ALLOWED = 0x1LL << 29; // Manage Allowed List @@ -164,6 +164,7 @@ const U64 GP_DEFAULT_OFFICER = GP_DEFAULT_MEMBER // Superset of GP_DEFAULT_MEMBE | GP_LAND_ALLOW_EDIT_LAND | GP_LAND_ALLOW_FLY | GP_LAND_ALLOW_CREATE + | GP_LAND_ALLOW_ENVIRONMENT | GP_LAND_ALLOW_LANDMARK | GP_LAND_CHANGE_IDENTITY | GP_LAND_CHANGE_MEDIA diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml index e0da7f5d9e..7beb013fba 100644 --- a/indra/newview/skins/default/colors.xml +++ b/indra/newview/skins/default/colors.xml @@ -42,6 +42,9 @@ name="Gray" value="0.5 0.5 0.5 1" /> <color + name="DkGray0" + value="0.27 0.27 0.27 1" /> + <color name="DkGray" value="0.125 0.125 0.125 1" /> <color @@ -334,6 +337,9 @@ name="ContextSilhouetteColor" reference="EmphasisColor" /> <color + name="ConversationFriendColor" + value="0.42 0.85 0.71 1" /> + <color name="DefaultHighlightDark" reference="White_10" /> <color @@ -848,6 +854,9 @@ name="ColorSwatchBorderColor" value="0.45098 0.517647 0.607843 1"/> <color + name="ChatTeleportSeparatorColor" + reference="Black" /> + <color name="ChatTimestampColor" reference="White" /> <color @@ -957,4 +966,7 @@ <color name="OutfitGalleryItemUnselected" value="0.4 0.4 0.4 1" /> + <color + name="AddPaymentPanel" + value="0.27 0.27 0.27 1" /> </colors> diff --git a/indra/newview/skins/default/textures/3p_icons/fmod_logo.png b/indra/newview/skins/default/textures/3p_icons/fmod_logo.png Binary files differnew file mode 100644 index 0000000000..5a50e0ad34 --- /dev/null +++ b/indra/newview/skins/default/textures/3p_icons/fmod_logo.png diff --git a/indra/newview/skins/default/textures/3p_icons/havok_logo.png b/indra/newview/skins/default/textures/3p_icons/havok_logo.png Binary files differnew file mode 100644 index 0000000000..ff1ea3a72e --- /dev/null +++ b/indra/newview/skins/default/textures/3p_icons/havok_logo.png diff --git a/indra/newview/skins/default/textures/3p_icons/vivox_logo.png b/indra/newview/skins/default/textures/3p_icons/vivox_logo.png Binary files differnew file mode 100644 index 0000000000..6f20e87b7a --- /dev/null +++ b/indra/newview/skins/default/textures/3p_icons/vivox_logo.png diff --git a/indra/newview/skins/default/textures/bottomtray/Cam_Rotate_Center.png b/indra/newview/skins/default/textures/bottomtray/Cam_Rotate_Center.png Binary files differnew file mode 100644 index 0000000000..ffc3c85ea2 --- /dev/null +++ b/indra/newview/skins/default/textures/bottomtray/Cam_Rotate_Center.png diff --git a/indra/newview/skins/default/textures/bottomtray/Cam_Tracking_Center.png b/indra/newview/skins/default/textures/bottomtray/Cam_Tracking_Center.png Binary files differnew file mode 100644 index 0000000000..2812d614e6 --- /dev/null +++ b/indra/newview/skins/default/textures/bottomtray/Cam_Tracking_Center.png diff --git a/indra/newview/skins/default/textures/containers/TabTop_Right_Flashing.png b/indra/newview/skins/default/textures/containers/TabTop_Right_Flashing.png Binary files differnew file mode 100644 index 0000000000..fd13bb699d --- /dev/null +++ b/indra/newview/skins/default/textures/containers/TabTop_Right_Flashing.png diff --git a/indra/newview/skins/default/textures/icons/Inv_Settings.png b/indra/newview/skins/default/textures/icons/Inv_Settings.png Binary files differnew file mode 100644 index 0000000000..c43ba349c4 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Inv_Settings.png diff --git a/indra/newview/skins/default/textures/icons/Inv_SettingsDay.png b/indra/newview/skins/default/textures/icons/Inv_SettingsDay.png Binary files differnew file mode 100644 index 0000000000..258ade1327 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Inv_SettingsDay.png diff --git a/indra/newview/skins/default/textures/icons/Inv_SettingsSky.png b/indra/newview/skins/default/textures/icons/Inv_SettingsSky.png Binary files differnew file mode 100644 index 0000000000..77858b23c3 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Inv_SettingsSky.png diff --git a/indra/newview/skins/default/textures/icons/Inv_SettingsWater.png b/indra/newview/skins/default/textures/icons/Inv_SettingsWater.png Binary files differnew file mode 100644 index 0000000000..46fb58c3f2 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Inv_SettingsWater.png diff --git a/indra/newview/skins/default/textures/icons/Inv_Toolbar_SearchVisibility.png b/indra/newview/skins/default/textures/icons/Inv_Toolbar_SearchVisibility.png Binary files differnew file mode 100644 index 0000000000..048da25c92 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Inv_Toolbar_SearchVisibility.png diff --git a/indra/newview/skins/default/textures/icons/Presets_Icon.png b/indra/newview/skins/default/textures/icons/Presets_Icon.png Binary files differindex 5a6628816b..503ee892a5 100644 --- a/indra/newview/skins/default/textures/icons/Presets_Icon.png +++ b/indra/newview/skins/default/textures/icons/Presets_Icon.png diff --git a/indra/newview/skins/default/textures/icons/Presets_Icon_Graphic.png b/indra/newview/skins/default/textures/icons/Presets_Icon_Graphic.png Binary files differnew file mode 100644 index 0000000000..5a6628816b --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Presets_Icon_Graphic.png diff --git a/indra/newview/skins/default/textures/navbar/Landmarks.png b/indra/newview/skins/default/textures/navbar/Landmarks.png Binary files differnew file mode 100644 index 0000000000..2b35de913b --- /dev/null +++ b/indra/newview/skins/default/textures/navbar/Landmarks.png diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 5aba0546f3..03878d9fe7 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -45,6 +45,10 @@ with the same filename but different name <texture name="AddItem_Off" file_name="icons/AddItem_Off.png" preload="false" /> <texture name="AddItem_Press" file_name="icons/AddItem_Press.png" preload="false" /> + <texture name="add_payment_image_center" file_name="windows/add_payment_image_center.png" preload="true" /> + <texture name="add_payment_image_left" file_name="windows/add_payment_image_left.png" preload="true" /> + <texture name="add_payment_image_right" file_name="windows/add_payment_image_right.png" preload="true" /> + <texture name="Arrow_Left_Off" file_name="navbar/Arrow_Left_Off.png" preload="true" /> <texture name="Arrow_Right_Off" file_name="navbar/Arrow_Right_Off.png" preload="true" /> @@ -98,7 +102,7 @@ with the same filename but different name <texture name="BuyArrow_Over" file_name="navbar/BuyArrow_Over.png" preload="true" scale.left="0" scale.top="1" scale.right="0" scale.bottom="0" /> <texture name="BuyArrow_Press" file_name="navbar/BuyArrow_Press.png" preload="true" scale.left="1" scale.top="1" scale.right="0" scale.bottom="0" /> - <texture name="Cam_Avatar_Off" file_name="bottomtray/Cam_Avatar_Off.png" preload="false" /> + <texture name="Cam_Avatar_Off" file_name="bottomtray/Cam_Avatar_Off.png" preload="true" /> <texture name="Cam_FreeCam_Off" file_name="bottomtray/Cam_FreeCam_Off.png" preload="false" /> <texture name="Cam_Orbit_Off" file_name="bottomtray/Cam_Orbit_Off.png" preload="false" /> <texture name="Cam_Pan_Off" file_name="bottomtray/Cam_Pan_Off.png" preload="false" /> @@ -113,8 +117,10 @@ with the same filename but different name <texture name="Cam_Rotate_In" file_name="bottomtray/Cam_Rotate_In.png" preload="false" /> <texture name="Cam_Rotate_Out" file_name="bottomtray/Cam_Rotate_Out.png" preload="false" /> + <texture name="Cam_Rotate_Center" file_name="bottomtray/Cam_Rotate_Center.png" preload="false" /> <texture name="Cam_Tracking_In" file_name="bottomtray/Cam_Tracking_In.png" preload="false" /> <texture name="Cam_Tracking_Out" file_name="bottomtray/Cam_Tracking_Out.png" preload="false" /> + <texture name="Cam_Tracking_Center" file_name="bottomtray/Cam_Tracking_Center.png" preload="false" /> <texture name="Checkbox_Off_Disabled" file_name="widgets/Checkbox_Disabled.png" preload="true" /> <texture name="Checkbox_On_Disabled" file_name="widgets/Checkbox_On_Disabled.png" preload="true" /> @@ -133,7 +139,6 @@ with the same filename but different name <texture name="Command_Chat_Icon" file_name="toolbar_icons/chat.png" preload="true" /> <texture name="Command_Compass_Icon" file_name="toolbar_icons/land.png" preload="true" /> <texture name="Command_Destinations_Icon" file_name="toolbar_icons/destinations.png" preload="true" /> - <texture name="Command_Flickr_Icon" file_name="toolbar_icons/flickr.png" preload="true" /> <texture name="Command_Gestures_Icon" file_name="toolbar_icons/gestures.png" preload="true" /> <texture name="Command_Grid_Status_Icon" file_name="toolbar_icons/grid_status.png" preload="true" /> <texture name="Command_HowTo_Icon" file_name="toolbar_icons/howto.png" preload="true" /> @@ -144,7 +149,7 @@ with the same filename but different name <texture name="Command_MiniCart_Icon" file_name="toolbar_icons/mini_cart.png" preload="true" /> <texture name="Command_MiniMap_Icon" file_name="toolbar_icons/mini_map.png" preload="true" /> <texture name="Command_Move_Icon" file_name="toolbar_icons/move.png" preload="true" /> - <texture name="Command_Outbox_Icon" file_name="toolbar_icons/outbox.png" preload="true" /> + <texture name="Command_Environments_Icon" file_name="toolbar_icons/environments.png" preload="true" /> <texture name="Command_People_Icon" file_name="toolbar_icons/people.png" preload="true" /> <texture name="Command_Picks_Icon" file_name="toolbar_icons/picks.png" preload="true" /> <texture name="Command_Places_Icon" file_name="toolbar_icons/places.png" preload="true" /> @@ -154,7 +159,6 @@ with the same filename but different name <texture name="Command_Search_Icon" file_name="toolbar_icons/search.png" preload="true" /> <texture name="Command_Snapshot_Icon" file_name="toolbar_icons/snapshot.png" preload="true" /> <texture name="Command_Speak_Icon" file_name="toolbar_icons/speak.png" preload="true" /> - <texture name="Command_Twitter_Icon" file_name="toolbar_icons/twitter.png" preload="true" /> <texture name="Command_View_Icon" file_name="toolbar_icons/view.png" preload="true" /> <texture name="Command_Voice_Icon" file_name="toolbar_icons/nearbyvoice.png" preload="true" /> <texture name="Caret_Bottom_Icon" file_name="toolbar_icons/caret_bottom.png" preload="true" scale.left="1" scale.top="23" scale.right="15" scale.bottom="1" /> @@ -206,7 +210,9 @@ with the same filename but different name <texture name="Presets_Icon" file_name="icons/Presets_Icon.png" preload="true" /> - <texture name="Favorite_Star_Active" file_name="navbar/Favorite_Star_Active.png" preload="false" /> + <texture name="Presets_Icon" file_name="icons/Presets_Icon.png" preload="true" /> + <texture name="Presets_Icon_Graphic" file_name="icons/Presets_Icon_Graphic.png" preload="true" /> + <texture name="Favorite_Star_Active" file_name="navbar/Favorite_Star_Active.png" preload="false" /> <texture name="Favorite_Star_Off" file_name="navbar/Favorite_Star_Off.png" preload="false" /> <texture name="Favorite_Star_Press" file_name="navbar/Favorite_Star_Press.png" preload="false" /> <texture name="Favorite_Star_Over" file_name="navbar/Favorite_Star_Over.png" preload="false" /> @@ -255,6 +261,7 @@ with the same filename but different name <texture name="Icon_Gear_Background" file_name="windows/Icon_Gear_Background.png" preload="false" /> <texture name="Icon_Gear_Foreground" file_name="windows/Icon_Gear_Foreground.png" preload="false" /> <texture name="Icon_Gear_Press" file_name="windows/Icon_Gear_Press.png" preload="false" /> + <texture name="Icon_Gear" file_name="windows/Icon_Gear.png" preload="false" /> <texture name="Icon_Help_Foreground" file_name="windows/Icon_Help_Foreground.png" preload="true" /> <texture name="Icon_Help_Press" file_name="windows/Icon_Help_Press.png" preload="true" /> @@ -321,11 +328,20 @@ with the same filename but different name <texture name="Inv_Underpants" file_name="icons/Inv_Underpants.png" preload="false" /> <texture name="Inv_Undershirt" file_name="icons/Inv_Undershirt.png" preload="false" /> <texture name="Inv_Link" file_name="icons/Inv_Link.png" preload="false" /> + <texture name="Inv_Settings" file_name="icons/Inv_Settings.png" preload="false" /> + <texture name="Inv_SettingsSky" file_name="icons/Inv_SettingsSky.png" preload="false" /> + <texture name="Inv_SettingsWater" file_name="icons/Inv_SettingsWater.png" preload="false" /> + <texture name="Inv_SettingsDay" file_name="icons/Inv_SettingsDay.png" preload="false" /> + <texture name="Inv_Invalid" file_name="icons/Inv_Invalid.png" preload="false" /> <texture name="Inv_Unknown" file_name="icons/Inv_UnknownObject.png" preload="false" /> <texture name="Inv_VersionFolderClosed" file_name="icons/Inv_VersionFolderClosed.png" preload="false" /> <texture name="Inv_VersionFolderOpen" file_name="icons/Inv_VersionFolderOpen.png" preload="false" /> - + + <texture name="Inv_Toolbar_SearchVisibility" file_name="icons/Inv_Toolbar_SearchVisibility.png" preload="false" /> + + <texture name="Landmarks_overlay" file_name="navbar/Landmarks.png" preload="false" /> + <texture name="Linden_Dollar_Alert" file_name="widgets/Linden_Dollar_Alert.png"/> <texture name="Linden_Dollar_Background" file_name="widgets/Linden_Dollar_Background.png"/> @@ -489,6 +505,7 @@ with the same filename but different name <texture name="Play_Press" file_name="icons/Play_Press.png" preload="false" /> <texture name="ProgressBar" file_name="widgets/ProgressBar.png" preload="true" scale.left="4" scale.top="11" scale.right="48" scale.bottom="3" /> + <texture name="ProgressBarSolid" file_name="widgets/ProgressBarSolid.png" preload="true" scale.left="4" scale.top="11" scale.right="48" scale.bottom="3" /> <texture name="ProgressTrack" file_name="widgets/ProgressTrack.png" preload="true" scale.left="4" scale.top="13" scale.right="148" scale.bottom="2" /> <texture name="PushButton_Disabled" file_name="widgets/PushButton_Disabled.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" /> @@ -590,7 +607,6 @@ with the same filename but different name <texture name="Snapshot_Email" file_name="snapshot_email.png" preload="false" /> <texture name="Snapshot_Inventory" file_name="toolbar_icons/inventory.png" preload="false" /> <texture name="Snapshot_Profile" file_name="toolbar_icons/profile.png" preload="false" /> - <texture name="startup_logo" file_name="windows/startup_logo.png" preload="true" /> <texture name="login_sl_logo" file_name="windows/login_sl_logo.png" preload="true" /> @@ -626,6 +642,7 @@ with the same filename but different name <texture name="TabTop_Right_Off" file_name="containers/TabTop_Right_Off.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" /> <texture name="TabTop_Right_Selected" file_name="containers/TabTop_Right_Selected.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" /> + <texture name="TabTop_Right_Flashing" file_name="containers/TabTop_Right_Flashing.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" /> <texture name="TabTop_Middle_Off" file_name="containers/TabTop_Middle_Off.png" preload="false" scale.left="8" scale.top="8" scale.right="120" scale.bottom="9" /> <texture name="TabTop_Middle_Selected" file_name="containers/TabTop_Middle_Selected.png" preload="false" scale.left="8" scale.top="8" scale.right="96" scale.bottom="9" /> <texture name="TabTop_Left_Off" file_name="containers/TabTop_Left_Off.png" preload="false" scale.left="8" scale.top="8" scale.right="120" scale.bottom="9" /> @@ -640,6 +657,7 @@ with the same filename but different name <texture name="TextField_Search_Off" file_name="widgets/TextField_Search_Off.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" /> <texture name="TextField_Disabled" file_name="widgets/TextField_Disabled.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" /> <texture name="TextField_Active" file_name="widgets/TextField_Active.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" /> + <texture name="TextField_Search_Highlight" file_name="widgets/TextField_Search_Highlight.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" /> <texture name="Toast_CloseBtn" file_name="windows/Toast_CloseBtn.png" preload="true" /> @@ -681,6 +699,20 @@ with the same filename but different name <texture name="Vertical Drag Handle" file_name="widgets/vertical_drag_handle.png" scale.left="2" scale.right="7" scale.bottom="8" scale.top="120" scale_type="scale_outer"/> + <texture name="VirtualTrackball_Moon_Back" file_name="widgets/track_control_moon_back.png" /> + <texture name="VirtualTrackball_Moon_Front" file_name="widgets/track_control_moon_front.png" /> + <texture name="VirtualTrackball_Rotate_Bottom" file_name="widgets/track_control_rotate_bottom.png" /> + <texture name="VirtualTrackball_Rotate_Left" file_name="widgets/track_control_rotate_left_side.png" /> + <texture name="VirtualTrackball_Rotate_Right" file_name="widgets/track_control_rotate_right_side.png" /> + <texture name="VirtualTrackball_Rotate_Top" file_name="widgets/track_control_rotate_top.png" /> + <texture name="VirtualTrackball_Rotate_Bottom_Active" file_name="widgets/track_control_rotate_bottom_active.png" /> + <texture name="VirtualTrackball_Rotate_Left_Active" file_name="widgets/track_control_rotate_left_side_active.png" /> + <texture name="VirtualTrackball_Rotate_Right_Active" file_name="widgets/track_control_rotate_right_side_active.png" /> + <texture name="VirtualTrackball_Rotate_Top_Active" file_name="widgets/track_control_rotate_top_active.png" /> + <texture name="VirtualTrackball_Sphere" file_name="widgets/track_control_sphere.png" /> + <texture name="VirtualTrackball_Sun_Back" file_name="widgets/track_control_sun_back.png" /> + <texture name="VirtualTrackball_Sun_Front" file_name="widgets/track_control_sun_front.png" /> + <texture name="Volume_Background" file_name="windows/Volume_Background.png" preload="false" scale.left="6" scale.top="33" scale.right="63" scale.bottom="10" /> diff --git a/indra/newview/skins/default/textures/toolbar_icons/environments.png b/indra/newview/skins/default/textures/toolbar_icons/environments.png Binary files differnew file mode 100644 index 0000000000..620db9f793 --- /dev/null +++ b/indra/newview/skins/default/textures/toolbar_icons/environments.png diff --git a/indra/newview/skins/default/textures/widgets/ProgressBarSolid.png b/indra/newview/skins/default/textures/widgets/ProgressBarSolid.png Binary files differnew file mode 100644 index 0000000000..ec0926bfa1 --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/ProgressBarSolid.png diff --git a/indra/newview/skins/default/textures/widgets/SliderThumb_Disabled.png b/indra/newview/skins/default/textures/widgets/SliderThumb_Disabled.png Binary files differindex b627232012..8888e134d1 100644 --- a/indra/newview/skins/default/textures/widgets/SliderThumb_Disabled.png +++ b/indra/newview/skins/default/textures/widgets/SliderThumb_Disabled.png diff --git a/indra/newview/skins/default/textures/widgets/TextField_Search_Highlight.png b/indra/newview/skins/default/textures/widgets/TextField_Search_Highlight.png Binary files differnew file mode 100644 index 0000000000..e3944289c6 --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/TextField_Search_Highlight.png diff --git a/indra/newview/skins/default/textures/widgets/track_control_moon_back.png b/indra/newview/skins/default/textures/widgets/track_control_moon_back.png Binary files differnew file mode 100644 index 0000000000..30f538d35b --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/track_control_moon_back.png diff --git a/indra/newview/skins/default/textures/widgets/track_control_moon_front.png b/indra/newview/skins/default/textures/widgets/track_control_moon_front.png Binary files differnew file mode 100644 index 0000000000..d3882c5e4c --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/track_control_moon_front.png diff --git a/indra/newview/skins/default/textures/widgets/track_control_rotate_bottom.png b/indra/newview/skins/default/textures/widgets/track_control_rotate_bottom.png Binary files differnew file mode 100644 index 0000000000..232c812aae --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/track_control_rotate_bottom.png diff --git a/indra/newview/skins/default/textures/widgets/track_control_rotate_bottom_active.png b/indra/newview/skins/default/textures/widgets/track_control_rotate_bottom_active.png Binary files differnew file mode 100644 index 0000000000..911618b08e --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/track_control_rotate_bottom_active.png diff --git a/indra/newview/skins/default/textures/widgets/track_control_rotate_left_side.png b/indra/newview/skins/default/textures/widgets/track_control_rotate_left_side.png Binary files differnew file mode 100644 index 0000000000..bcc78fc5e4 --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/track_control_rotate_left_side.png diff --git a/indra/newview/skins/default/textures/widgets/track_control_rotate_left_side_active.png b/indra/newview/skins/default/textures/widgets/track_control_rotate_left_side_active.png Binary files differnew file mode 100644 index 0000000000..2fe04b93f1 --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/track_control_rotate_left_side_active.png diff --git a/indra/newview/skins/default/textures/widgets/track_control_rotate_right_side.png b/indra/newview/skins/default/textures/widgets/track_control_rotate_right_side.png Binary files differnew file mode 100644 index 0000000000..d0827abf28 --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/track_control_rotate_right_side.png diff --git a/indra/newview/skins/default/textures/widgets/track_control_rotate_right_side_active.png b/indra/newview/skins/default/textures/widgets/track_control_rotate_right_side_active.png Binary files differnew file mode 100644 index 0000000000..824051562f --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/track_control_rotate_right_side_active.png diff --git a/indra/newview/skins/default/textures/widgets/track_control_rotate_top.png b/indra/newview/skins/default/textures/widgets/track_control_rotate_top.png Binary files differnew file mode 100644 index 0000000000..13a5e9c2e8 --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/track_control_rotate_top.png diff --git a/indra/newview/skins/default/textures/widgets/track_control_rotate_top_active.png b/indra/newview/skins/default/textures/widgets/track_control_rotate_top_active.png Binary files differnew file mode 100644 index 0000000000..9a7493703b --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/track_control_rotate_top_active.png diff --git a/indra/newview/skins/default/textures/widgets/track_control_sphere.png b/indra/newview/skins/default/textures/widgets/track_control_sphere.png Binary files differnew file mode 100644 index 0000000000..a13b7725ea --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/track_control_sphere.png diff --git a/indra/newview/skins/default/textures/widgets/track_control_sun_back.png b/indra/newview/skins/default/textures/widgets/track_control_sun_back.png Binary files differnew file mode 100644 index 0000000000..23c89068f8 --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/track_control_sun_back.png diff --git a/indra/newview/skins/default/textures/widgets/track_control_sun_front.png b/indra/newview/skins/default/textures/widgets/track_control_sun_front.png Binary files differnew file mode 100644 index 0000000000..6dfdc04423 --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/track_control_sun_front.png diff --git a/indra/newview/skins/default/textures/windows/Icon_Gear.png b/indra/newview/skins/default/textures/windows/Icon_Gear.png Binary files differnew file mode 100644 index 0000000000..e1e89b8f32 --- /dev/null +++ b/indra/newview/skins/default/textures/windows/Icon_Gear.png diff --git a/indra/newview/skins/default/textures/windows/add_payment_image_center.png b/indra/newview/skins/default/textures/windows/add_payment_image_center.png Binary files differnew file mode 100644 index 0000000000..b5459136cb --- /dev/null +++ b/indra/newview/skins/default/textures/windows/add_payment_image_center.png diff --git a/indra/newview/skins/default/textures/windows/add_payment_image_left.png b/indra/newview/skins/default/textures/windows/add_payment_image_left.png Binary files differnew file mode 100644 index 0000000000..7fb65e724a --- /dev/null +++ b/indra/newview/skins/default/textures/windows/add_payment_image_left.png diff --git a/indra/newview/skins/default/textures/windows/add_payment_image_right.png b/indra/newview/skins/default/textures/windows/add_payment_image_right.png Binary files differnew file mode 100644 index 0000000000..f1937b6318 --- /dev/null +++ b/indra/newview/skins/default/textures/windows/add_payment_image_right.png diff --git a/indra/newview/skins/default/textures/windows/first_login_image_left.png b/indra/newview/skins/default/textures/windows/first_login_image_left.png Binary files differindex 1fa10fde53..77904d7d12 100644 --- a/indra/newview/skins/default/textures/windows/first_login_image_left.png +++ b/indra/newview/skins/default/textures/windows/first_login_image_left.png diff --git a/indra/newview/skins/default/textures/windows/first_login_image_right.png b/indra/newview/skins/default/textures/windows/first_login_image_right.png Binary files differindex d764d846b7..35ecce9c07 100644 --- a/indra/newview/skins/default/textures/windows/first_login_image_right.png +++ b/indra/newview/skins/default/textures/windows/first_login_image_right.png diff --git a/indra/newview/skins/default/textures/windows/login_sl_logo.png b/indra/newview/skins/default/textures/windows/login_sl_logo.png Binary files differindex 9810d00237..1eede80c83 100644 --- a/indra/newview/skins/default/textures/windows/login_sl_logo.png +++ b/indra/newview/skins/default/textures/windows/login_sl_logo.png diff --git a/indra/newview/skins/default/textures/windows/login_sl_logo_small.png b/indra/newview/skins/default/textures/windows/login_sl_logo_small.png Binary files differindex 0a245442d5..c5933001f0 100644 --- a/indra/newview/skins/default/textures/windows/login_sl_logo_small.png +++ b/indra/newview/skins/default/textures/windows/login_sl_logo_small.png diff --git a/indra/newview/skins/default/xui/da/floater_buy_currency.xml b/indra/newview/skins/default/xui/da/floater_buy_currency.xml index 3c0428b2b0..b7ac181dd4 100644 --- a/indra/newview/skins/default/xui/da/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/da/floater_buy_currency.xml @@ -60,8 +60,7 @@ objektet. </text> <button label="Køb nu" name="buy_btn"/> <button label="Annullér" name="cancel_btn"/> - <text name="info_cannot_buy"> + <floater.string name="info_cannot_buy"> Kan ikke købe - </text> - <button label="Fortsæt til web" name="error_web"/> + </floater.string> </floater> diff --git a/indra/newview/skins/default/xui/da/menu_cof_attachment.xml b/indra/newview/skins/default/xui/da/menu_cof_attachment.xml index 9d7fc0f223..37e9351ab5 100644 --- a/indra/newview/skins/default/xui/da/menu_cof_attachment.xml +++ b/indra/newview/skins/default/xui/da/menu_cof_attachment.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="COF Attachment"> + <menu_item_call label="Berør" name="touch_attach" /> + <menu_item_call label="Redigér" name="edit_item" /> <menu_item_call label="Tag af" name="detach"/> </context_menu> diff --git a/indra/newview/skins/default/xui/da/menu_inventory.xml b/indra/newview/skins/default/xui/da/menu_inventory.xml index f9bdf36f1f..ba96d6dca1 100644 --- a/indra/newview/skins/default/xui/da/menu_inventory.xml +++ b/indra/newview/skins/default/xui/da/menu_inventory.xml @@ -78,6 +78,7 @@ <menu_item_call label="Tag pÃ¥" name="Wearable And Object Wear"/> <menu label="Vedhæft" name="Attach To"/> <menu label="Vedhæft til HUD" name="Attach To HUD"/> + <menu_item_call label="Berør" name="Attachment Touch" /> <menu_item_call label="Redigér" name="Wearable Edit"/> <menu_item_call label="Tilføj" name="Wearable Add"/> <menu_item_call label="Tag af" name="Take Off"/> diff --git a/indra/newview/skins/default/xui/da/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/da/menu_wearable_list_item.xml index 63f4b0b388..67adf74bcd 100644 --- a/indra/newview/skins/default/xui/da/menu_wearable_list_item.xml +++ b/indra/newview/skins/default/xui/da/menu_wearable_list_item.xml @@ -3,6 +3,7 @@ <menu_item_call label="Erstat" name="wear_replace"/> <menu_item_call label="Tag pÃ¥" name="wear_wear"/> <menu_item_call label="Tilføj" name="wear_add"/> + <menu_item_call label="Berør" name="touch" /> <menu_item_call label="Tag af" name="take_off_or_detach"/> <menu_item_call label="Tag af" name="detach"/> <context_menu label="Vedhæft til" name="wearable_attach_to"/> diff --git a/indra/newview/skins/default/xui/da/menu_wearing_gear.xml b/indra/newview/skins/default/xui/da/menu_wearing_gear.xml index 515a15b287..ff58cd68b2 100644 --- a/indra/newview/skins/default/xui/da/menu_wearing_gear.xml +++ b/indra/newview/skins/default/xui/da/menu_wearing_gear.xml @@ -1,5 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <menu name="Gear Wearing"> - <menu_item_call label="Redigér sæt" name="edit"/> + <menu_item_call label="Berør" name="touch"/> + <menu_item_call label="Redigér" name="edit_item"/> + <menu_item_call label="Redigér sæt" name="edit_outfit"/> <menu_item_call label="Tag af" name="takeoff"/> </menu> diff --git a/indra/newview/skins/default/xui/da/menu_wearing_tab.xml b/indra/newview/skins/default/xui/da/menu_wearing_tab.xml index c0db7b6842..adaac35f68 100644 --- a/indra/newview/skins/default/xui/da/menu_wearing_tab.xml +++ b/indra/newview/skins/default/xui/da/menu_wearing_tab.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="Wearing"> + <menu_item_call label="Berør" name="touch_attach"/> + <menu_item_call label="Redigér" name="edit_item"/> <menu_item_call label="Tag af" name="take_off"/> <menu_item_call label="Tag af" name="detach"/> - <menu_item_call label="Redigér sæt" name="edit"/> + <menu_item_call label="Redigér sæt" name="edit_outfit"/> </context_menu> diff --git a/indra/newview/skins/default/xui/da/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/da/panel_preferences_graphics1.xml index e494b2b755..c7770eb81b 100644 --- a/indra/newview/skins/default/xui/da/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/da/panel_preferences_graphics1.xml @@ -29,7 +29,6 @@ <check_box initial_value="true" label="Gennemsigtig vand" name="TransparentWater"/> <check_box initial_value="true" label="Glatte flader og skin" name="BumpShiny"/> <check_box initial_value="true" label="Lokale lys" name="LocalLights"/> - <check_box initial_value="true" label="Basale flader" name="BasicShaders" tool_tip="Ved at slÃ¥ dette valg fra, kan det forhindres at visse grafikkort drivere crasher."/> <check_box initial_value="true" label="Atmosfæriske flader" name="WindLightUseAtmosShaders"/> <check_box initial_value="true" label="Lys og skygger" name="UseLightShaders"/> <check_box initial_value="true" label=""Ambient Occlusion"" name="UseSSAO"/> diff --git a/indra/newview/skins/default/xui/da/strings.xml b/indra/newview/skins/default/xui/da/strings.xml index eee3dc2c77..ec6ba4800d 100644 --- a/indra/newview/skins/default/xui/da/strings.xml +++ b/indra/newview/skins/default/xui/da/strings.xml @@ -560,6 +560,9 @@ Prøv venligst om lidt igen. <string name="mesh"> mesh </string> + <string name="settings"> + indstillinger + </string> <string name="AvatarEditingAppearance"> (Redigering Udseende) </string> diff --git a/indra/newview/skins/default/xui/de/floater_about_land.xml b/indra/newview/skins/default/xui/de/floater_about_land.xml index 4dd64cba2a..8f55b3297f 100644 --- a/indra/newview/skins/default/xui/de/floater_about_land.xml +++ b/indra/newview/skins/default/xui/de/floater_about_land.xml @@ -30,7 +30,7 @@ <floater.string name="Always"> Immer </floater.string> - <tab_container name="landtab" tab_min_width="40" width="489"> + <tab_container name="landtab" tab_min_width="40"> <panel label="ALLGEMEIN" name="land_general_panel"> <panel.string name="new users only"> Nur neue Benutzer diff --git a/indra/newview/skins/default/xui/de/floater_adjust_environment.xml b/indra/newview/skins/default/xui/de/floater_adjust_environment.xml new file mode 100644 index 0000000000..776a866077 --- /dev/null +++ b/indra/newview/skins/default/xui/de/floater_adjust_environment.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_adjust_snapshot" title="Persönliche Beleuchtung"> + <layout_stack name="outer_stack"> + <layout_panel name="env_controls"> + <layout_stack name="settings_stack"> + <layout_panel> + <button label="Zurücksetzen" name="btn_reset" tool_tip="Schließen und auf gemeinsame Umgebung zurücksetzen"/> + <text name="cloud_map_label"> + Wolkenbild: + </text> + </layout_panel> + <layout_panel> + <text name="label"> + Sonne: + </text> + <check_box label="Beacon anzeigen" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <check_box label="Beacon anzeigen" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/de/floater_beacons.xml b/indra/newview/skins/default/xui/de/floater_beacons.xml index 1a052bd814..c44cd407de 100644 --- a/indra/newview/skins/default/xui/de/floater_beacons.xml +++ b/indra/newview/skins/default/xui/de/floater_beacons.xml @@ -18,5 +18,7 @@ <check_box label="Soundquellen" name="sounds"/> <check_box label="Partikelquellen" name="particles"/> <check_box label="Medienquellen" name="moapbeacon"/> + <check_box label="Sonne" name="sun"/> + <check_box label="Mond" name="moon"/> </panel> </floater> diff --git a/indra/newview/skins/default/xui/de/floater_bulk_perms.xml b/indra/newview/skins/default/xui/de/floater_bulk_perms.xml index 9454933264..7a3fa41a24 100644 --- a/indra/newview/skins/default/xui/de/floater_bulk_perms.xml +++ b/indra/newview/skins/default/xui/de/floater_bulk_perms.xml @@ -30,6 +30,7 @@ <icon name="icon_sound" tool_tip="Sounds"/> <check_box label="Texturen" name="check_texture"/> <icon name="icon_texture" tool_tip="Texturen"/> + <icon name="icon_setting" tool_tip="Umgebungseinstellungen"/> <button label="√ Alle" label_selected="Alle" name="check_all"/> <button label="Löschen" label_selected="Keine" name="check_none"/> <text name="newperms"> diff --git a/indra/newview/skins/default/xui/de/floater_buy_currency.xml b/indra/newview/skins/default/xui/de/floater_buy_currency.xml index 65926c088c..eb94df1cad 100644 --- a/indra/newview/skins/default/xui/de/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/de/floater_buy_currency.xml @@ -59,8 +59,7 @@ </text> <button label="Jetzt kaufen" name="buy_btn"/> <button label="Abbrechen" name="cancel_btn"/> - <text name="info_cannot_buy"> + <floater.string name="info_cannot_buy"> Kaufabbruch - </text> - <button label="Weiter zur Kontoseite" name="error_web"/> + </floater.string> </floater> diff --git a/indra/newview/skins/default/xui/de/floater_delete_env_preset.xml b/indra/newview/skins/default/xui/de/floater_delete_env_preset.xml deleted file mode 100644 index ae7d5ef77d..0000000000 --- a/indra/newview/skins/default/xui/de/floater_delete_env_preset.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<floater name="Delete Env Preset" title="UMGEB.-VOREINST. LÖSCHEN"> - <string name="title_water"> - Wasser-Voreinstellung löschen - </string> - <string name="title_sky"> - Himmel-Voreinstellung löschen - </string> - <string name="title_day_cycle"> - Tageszyklus löschen - </string> - <string name="label_water"> - Voreinstellung: - </string> - <string name="label_sky"> - Voreinstellung: - </string> - <string name="label_day_cycle"> - Tageszyklus: - </string> - <string name="msg_confirm_deletion"> - Möchten Sie die ausgewählte Voreinstellung wirklich löschen? - </string> - <string name="msg_sky_is_referenced"> - Eine Voreinstellung, auf die sich ein Tageszyklus bezieht, kann nicht gelöscht werden. - </string> - <string name="combo_label"> - -Voreinstellung auswählen- - </string> - <text name="label"> - Voreinstellung: - </text> - <button label="Löschen" name="delete"/> - <button label="Abbrechen" name="cancel"/> -</floater> diff --git a/indra/newview/skins/default/xui/de/floater_edit_ext_day_cycle.xml b/indra/newview/skins/default/xui/de/floater_edit_ext_day_cycle.xml new file mode 100644 index 0000000000..c21eec1893 --- /dev/null +++ b/indra/newview/skins/default/xui/de/floater_edit_ext_day_cycle.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_edit_extdaycycle" title="Tageszyklus bearbeiten"> + <string name="title_new"> + Neuen Tageszyklus erstellen + </string> + <string name="title_edit"> + Tageszyklus bearbeiten + </string> + <string name="hint_new"> + Geben Sie einen Namen für Ihren Tageszyklus ein, passen Sie die Steuerungen an, um den Tageszyklus zu erstellen, und klicken Sie auf "Speichern". + </string> + <string name="hint_edit"> + Um Ihren Tageszyklus zu bearbeiten, passen Sie die unten angezeigten Steuerungen an und klicken Sie auf „Speichern“. + </string> + <string name="time_label"> + ([HH]:[MM]) + </string> + <string name="sky_track_label"> + Himmel [ALT] + </string> + <string name="sky_label"> + Himmel + </string> + <string name="water_label"> + Wasser + </string> + <string name="commit_parcel"> + Auf Parzelle anwenden + </string> + <string name="commit_region"> + Auf Region anwenden + </string> + <layout_stack name="outer_stack"> + <layout_panel name="name_and_import"> + <text name="label"> + Name des Tageszyklus: + </text> + <button label="Importieren" name="btn_import" tool_tip="Alte Einstellungen von Datenträger importieren."/> + </layout_panel> + <layout_panel name="content"> + <layout_stack name="content_stack"> + <layout_panel name="timeline_track_selection"> + <panel name="timeline_layers"> + <button label="Himmel 4" name="sky4_track"/> + <button label="Himmel 3" name="sky3_track"/> + <button label="Himmel 2" name="sky2_track"/> + <button label="Bodenhöhe" name="sky1_track"/> + <button label="Wasser" name="water_track"/> + </panel> + <panel name="timeline"> + <text name="p0" value="0%[DSC]"/> + <text name="p1" value="25%[DSC]"/> + <text name="p2" value="50%[DSC]"/> + <text name="p3" value="75%[DSC]"/> + <text name="p4" value="100%[DSC]"/> + <multi_slider initial_value="0" name="WLTimeSlider"/> + <multi_slider initial_value="0" name="WLDayCycleFrames"/> + <text name="current_time" value="[PRCNT]%[DSC]"/> + <layout_stack> + <layout_panel> + <button label="Pfad klonen von" name="copy_track"/> + <button label="Pfad laden von" name="load_track"/> + <button label="Pfad löschen" name="clear_track"/> + </layout_panel> + <layout_panel> + <layout_stack name="progress_control"> + <layout_panel name="skip_back"> + <button name="skip_back_btn" tool_tip="Schritt vor"/> + </layout_panel> + <layout_panel name="skip_forward"> + <button name="skip_forward_btn" tool_tip="Schritt zurück"/> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel> + <button label="[FRAME] hinzufügen" name="add_frame"/> + <button label="[FRAME] laden" name="btn_load_frame"/> + <button label="[FRAME] löschen" name="delete_frame"/> + </layout_panel> + </layout_stack> + </panel> + </layout_panel> + <layout_panel name="frame_edit_controls"> + <text name="icn_lock_edit"> + Wählen Sie einen Schlüssel-Frame aus der obigen Zeitlinie, um die Einstellungen zu bearbeiten. + </text> + </layout_panel> + <layout_panel name="frame_settings_water"> + <tab_container name="water_tabs"> + <panel label="Wasser" name="water_panel"/> + </tab_container> + </layout_panel> + <layout_panel name="frame_settings_sky"> + <tab_container name="sky_tabs"> + <panel label="Atmosphäre und Beleuchtung" name="atmosphere_panel"/> + <panel label="Wolken" name="clouds_panel"/> + <panel label="Sonne und Mond" name="moon_panel"/> + </tab_container> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel name="buttons"> + <button label="Speichern" name="save_btn"/> + <button label="Abbrechen" name="cancel_btn"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/de/floater_fixedenvironment.xml b/indra/newview/skins/default/xui/de/floater_fixedenvironment.xml new file mode 100644 index 0000000000..c18e333571 --- /dev/null +++ b/indra/newview/skins/default/xui/de/floater_fixedenvironment.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="Fixed Environment" title="Festgelegte Umgebung"> + <string name="edit_sky"> + Himmel bearbeiten: + </string> + <string name="edit_water"> + Wasser bearbeiten: + </string> + <layout_stack name="floater_stack"> + <layout_panel name="info_panel"> + <button label="Laden" name="btn_load" tool_tip="Einstellungen aus dem Inventar laden"/> + <button label="Importieren" name="btn_import" tool_tip="Alte Einstellungen von Datenträger importieren."/> + </layout_panel> + <layout_panel name="button_panel"> + <layout_stack name="button_bar_ls"> + <layout_panel name="save_btn_lp"> + <button label="Speichern" name="btn_commit"/> + </layout_panel> + <layout_panel name="revert_btn_lp"> + <button label="Abbrechen" name="btn_cancel" tool_tip="Zur zuletzt gespeicherten Version zurückkehren"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/de/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/de/floater_inventory_view_finder.xml index cdacabec90..b361b88aa8 100644 --- a/indra/newview/skins/default/xui/de/floater_inventory_view_finder.xml +++ b/indra/newview/skins/default/xui/de/floater_inventory_view_finder.xml @@ -12,6 +12,7 @@ <check_box label="Sounds" name="check_sound"/> <check_box label="Texturen" name="check_texture"/> <check_box label="Fotos" name="check_snapshot"/> + <check_box label="Einstellungen" name="check_settings"/> <button label="Alle" label_selected="Alle" name="All"/> <button label="Keine" label_selected="Keine" name="None"/> <check_box label="Ordner immer anzeigen" name="check_show_empty"/> diff --git a/indra/newview/skins/default/xui/de/floater_merchant_outbox.xml b/indra/newview/skins/default/xui/de/floater_merchant_outbox.xml deleted file mode 100644 index 4070dee84c..0000000000 --- a/indra/newview/skins/default/xui/de/floater_merchant_outbox.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="floater_merchant_outbox" title="HÄNDLER-OUTBOX"> - <string name="OutboxFolderCount1"> - 1 Ordner - </string> - <string name="OutboxFolderCountN"> - [NUM] Ordner - </string> - <string name="OutboxImporting"> - Ordner übertragen... - </string> - <string name="OutboxInitializing"> - Initialisieren... - </string> - <panel label="" name="panel_1"> - <panel name="panel_2"> - <panel name="outbox_inventory_placeholder_panel"> - <text name="outbox_inventory_placeholder_title"> - Laden... - </text> - </panel> - </panel> - <panel name="panel_3"> - <panel name="outbox_generic_drag_target"> - <text name="text_1"> - Artikel hierher ziehen, um Ordner zu erstellen - </text> - </panel> - <button label="In Marktplatz übertragen" name="outbox_import_btn" tool_tip="In meinen Marktplatz-Laden verschieben"/> - </panel> - </panel> -</floater> diff --git a/indra/newview/skins/default/xui/de/floater_my_environments.xml b/indra/newview/skins/default/xui/de/floater_my_environments.xml new file mode 100644 index 0000000000..ff5556304a --- /dev/null +++ b/indra/newview/skins/default/xui/de/floater_my_environments.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater label="Orte" name="my_environments" title="MEINE UMGEBUNGEN"> + <layout_stack> + <layout_panel label="Filter" name="filter_panel"> + <check_box label="Tage" name="chk_days"/> + <check_box label="Himmel" name="chk_skies"/> + <check_box label="Wasser" name="chk_water"/> + <filter_editor label="Umgebungen filtern" name="flt_search"/> + </layout_panel> + <layout_panel label="Umgebungen" name="list_panel"> + <panel label="pnl_inv_wrap" name="pnl_inv_wrap"/> + </layout_panel> + <layout_panel> + <check_box initial_value="false" label="Alle Ordner anzeigen" name="chk_showfolders"/> + </layout_panel> + <layout_panel name="pnl_control"> + <panel label="bottom_panel" name="pnl_bottom"> + <menu_button name="btn_gear" tool_tip="Weitere Optionen"/> + <menu_button name="btn_newsettings" tool_tip="Neue Einstellung erstellen"/> + <button name="btn_del" tool_tip="Ausgewähltes Objekt löschen"/> + </panel> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/de/floater_perms_default.xml b/indra/newview/skins/default/xui/de/floater_perms_default.xml index 6274739f70..a9b845611a 100644 --- a/indra/newview/skins/default/xui/de/floater_perms_default.xml +++ b/indra/newview/skins/default/xui/de/floater_perms_default.xml @@ -37,6 +37,10 @@ <text name="label_12" tool_tip="Standardberechtigungen für die Erstellung von Kleidungsstücken und Körperteilen festlegen"> Tragbare Objekte </text> + <text name="label_13" tool_tip="Standardberechtigungen für die Erstellung von Umgebungseinstellungen festlegen"> + Einstellungen + </text> + <check_box name="env_settings_c" value="true"/> </panel> <button label="OK" label_selected="OK" name="ok"/> <button label="Abbrechen" label_selected="Abbrechen" name="cancel"/> diff --git a/indra/newview/skins/default/xui/de/floater_pick_track.xml b/indra/newview/skins/default/xui/de/floater_pick_track.xml new file mode 100644 index 0000000000..d5a565a2b0 --- /dev/null +++ b/indra/newview/skins/default/xui/de/floater_pick_track.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="track picker" title="AUSWÄHLEN: PFAD"> + <layout_stack name="adjuster"> + <layout_panel name="pnl_desc"> + <text name="select_description"> + Ursprungshimmel auswählen: + </text> + </layout_panel> + <layout_panel name="pnl_traks"> + <radio_group name="track_selection"> + <radio_item label="Himmel4 [ALT]" name="radio_sky4" value="4"/> + <radio_item label="Himmel3 [ALT]" name="radio_sky3" value="3"/> + <radio_item label="Himmel2 [ALT]" name="radio_sky2" value="2"/> + <radio_item label="Boden" name="radio_sky1" value="1"/> + </radio_group> + </layout_panel> + <layout_panel name="pnl_ok_cancel"> + <button label="OK" label_selected="OK" name="btn_select"/> + <button label="Abbrechen" label_selected="Abbrechen" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/de/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/de/floater_preferences_graphics_advanced.xml index 41e8dc5ef4..cd514f5afd 100644 --- a/indra/newview/skins/default/xui/de/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/de/floater_preferences_graphics_advanced.xml @@ -82,7 +82,6 @@ <check_box initial_value="true" label="Transparentes Wasser" name="TransparentWater"/> <check_box initial_value="true" label="Bumpmapping und Glanz" name="BumpShiny"/> <check_box initial_value="true" label="Lokale Lichtquellen" name="LocalLights"/> - <check_box initial_value="true" label="Einfache Shader" name="BasicShaders" tool_tip="Deaktivieren Sie diese Option, wenn der Grafikkartentreiber Abstürze verursacht"/> <slider label="Terraindetails:" name="TerrainDetail"/> <text name="TerrainDetailText"> Niedrig diff --git a/indra/newview/skins/default/xui/de/floater_preview_texture.xml b/indra/newview/skins/default/xui/de/floater_preview_texture.xml index 526c0813bd..eacd11c3e6 100644 --- a/indra/newview/skins/default/xui/de/floater_preview_texture.xml +++ b/indra/newview/skins/default/xui/de/floater_preview_texture.xml @@ -13,7 +13,7 @@ [WIDTH]px x [HEIGHT]px </text> <text name="aspect_ratio"> - Seitenverhältnis anzeigen + Vorschau Seitenverhältnis </text> <combo_box name="combo_aspect_ratio" tool_tip="Mit einem vordefinierten Seitenverhältnis anzeigen"> <combo_item name="Unconstrained"> diff --git a/indra/newview/skins/default/xui/de/floater_settings_picker.xml b/indra/newview/skins/default/xui/de/floater_settings_picker.xml new file mode 100644 index 0000000000..1fe417bdee --- /dev/null +++ b/indra/newview/skins/default/xui/de/floater_settings_picker.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="settings picker" title="AUSWÄHLEN: EINSTELLUNGEN"> + <floater.string name="pick title"> + Auswahl: + </floater.string> + <floater.string name="pick_track"> + PFAD AUSWÄHLEN + </floater.string> + <floater.string name="pick_settings"> + EINSTELLUNGEN AUSWÄHLEN + </floater.string> + <floater.string name="track_water"> + Wasser + </floater.string> + <floater.string name="track_ground"> + Boden + </floater.string> + <floater.string name="track_sky"> + Himmel[NUM] + </floater.string> + <layout_stack name="test_stack"> + <layout_panel name="inv_list"> + <filter_editor label="Texturen filtern" name="flt_inventory_search"/> + </layout_panel> + <layout_panel name="temp"> + <button label="OK" label_selected="OK" name="btn_select"/> + <button label="Abbrechen" label_selected="Abbrechen" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/de/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/de/floater_texture_ctrl.xml index b794d879f0..81b093b8c2 100644 --- a/indra/newview/skins/default/xui/de/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/de/floater_texture_ctrl.xml @@ -9,18 +9,14 @@ <text name="Multiple"> Mehrere Texturen </text> - <radio_group name="mode_selection"> - <radio_item label="Inventar" name="inventory" value="0"/> - <radio_item label="Lokal" name="local" value="1"/> - </radio_group> - <text name="unknown"> - Größe: [DIMENSIONS] - </text> + <combo_box name="mode_selection"> + <combo_box.item label="Inventar" name="inventory" value="0"/> + <combo_box.item label="Lokal" name="local" value="1"/> + </combo_box> <button label="Standard" label_selected="Standard" name="Default"/> <button label="Leer" label_selected="Leer" name="Blank"/> <button label="Keine" label_selected="Keine" name="None"/> <button label="" label_selected="" name="Pipette"/> - <check_box initial_value="true" label="Jetzt übernehmen" name="apply_immediate_check"/> <text name="preview_disabled" value="Vorschau deaktiviert"/> <filter_editor label="Texturen filtern" name="inventory search editor"/> <check_box initial_value="false" label="Ordner anzeigen" name="show_folders_check"/> @@ -31,6 +27,22 @@ <column label="Name" name="unit_name"/> <column label="ID" name="unit_id_HIDDEN"/> </scroll_list> + <combo_box name="l_bake_use_texture_combo_box" tool_tip="Back-Textur auswählen"> + <combo_box.item label="Keine" name="None"/> + <combo_box.item label="BAKED_HEAD" name="BAKED_HEAD"/> + <combo_box.item label="BAKED_UPPER" name="BAKED_UPPER"/> + <combo_box.item label="BAKED_LOWER" name="BAKED_LOWER"/> + <combo_box.item label="BAKED_EYES" name="BAKED_EYES"/> + <combo_box.item label="BAKED_SKIRT" name="BAKED_SKIRT"/> + <combo_box.item label="BAKED_HAIR" name="BAKED_HAIR"/> + <combo_box.item label="BAKED_LEFTARM" name="BAKED_LEFTARM"/> + <combo_box.item label="BAKED_LEFTLEG" name="BAKED_LEFTLEG"/> + <combo_box.item label="BAKED_AUX1" name="BAKED_AUX1"/> + <combo_box.item label="BAKED_AUX2" name="BAKED_AUX2"/> + <combo_box.item label="BAKED_AUX3" name="BAKED_AUX3"/> + </combo_box> + <check_box initial_value="false" label="Basis-Mesh-Region verbergen" name="hide_base_mesh_region"/> <button label="OK" label_selected="OK" name="Select"/> <button label="Abbrechen" label_selected="Abbrechen" name="Cancel"/> + <check_box initial_value="true" label="Jetzt übernehmen" name="apply_immediate_check"/> </floater> diff --git a/indra/newview/skins/default/xui/de/menu_cof_attachment.xml b/indra/newview/skins/default/xui/de/menu_cof_attachment.xml index 05d3dfca9d..7c7da58866 100644 --- a/indra/newview/skins/default/xui/de/menu_cof_attachment.xml +++ b/indra/newview/skins/default/xui/de/menu_cof_attachment.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="COF Attachment"> + <menu_item_call label="Berühren" name="touch_attach" /> + <menu_item_call label="Bearbeiten" name="edit_item" /> <menu_item_call label="Abnehmen" name="detach"/> </context_menu> diff --git a/indra/newview/skins/default/xui/de/menu_inventory.xml b/indra/newview/skins/default/xui/de/menu_inventory.xml index e02d464a3d..743b8b2073 100644 --- a/indra/newview/skins/default/xui/de/menu_inventory.xml +++ b/indra/newview/skins/default/xui/de/menu_inventory.xml @@ -10,7 +10,6 @@ <menu_item_call label="Aktivieren" name="Marketplace Activate"/> <menu_item_call label="Deaktivieren" name="Marketplace Deactivate"/> <menu_item_call label="Teilen" name="Share"/> - <menu_item_call label="Kaufen" name="Task Buy"/> <menu_item_call label="Öffnen" name="Task Open"/> <menu_item_call label="Abspielen" name="Task Play"/> <menu_item_call label="Eigenschaften" name="Task Properties"/> @@ -34,6 +33,7 @@ <menu_item_call label="Neue Unterhose" name="New Underpants"/> <menu_item_call label="Neue Alpha-Maske" name="New Alpha Mask"/> <menu_item_call label="Neue Tätowierung" name="New Tattoo"/> + <menu_item_call label="Neues Universal" name="New Universal"/> <menu_item_call label="Neue Physik" name="New Physics"/> </menu> <menu label="Neue Körperteile" name="New Body Parts"> @@ -42,6 +42,11 @@ <menu_item_call label="Neues Haar" name="New Hair"/> <menu_item_call label="Neue Augen" name="New Eyes"/> </menu> + <menu label="Neue Einstellungen" name="New Settings"> + <menu_item_call label="Neuer Himmel" name="New Sky"/> + <menu_item_call label="Neues Wasser" name="New Water"/> + <menu_item_call label="Neuer Tageszyklus" name="New Day Cycle"/> + </menu> <menu label="Als Standard verwenden für" name="upload_def"> <menu_item_call label="Hochgeladene Bilder" name="Image uploads"/> <menu_item_call label="Hochgeladene Sounds" name="Sound uploads"/> @@ -100,9 +105,12 @@ <menu_item_call label="Anziehen" name="Wearable And Object Wear"/> <menu label="Anhängen an" name="Attach To"/> <menu label="An HUD hängen" name="Attach To HUD"/> + <menu_item_call label="Berühren" name="Attachment Touch" /> <menu_item_call label="Bearbeiten" name="Wearable Edit"/> <menu_item_call label="Hinzufügen" name="Wearable Add"/> <menu_item_call label="Ausziehen" name="Take Off"/> + <menu_item_call label="Nur auf mich anwenden" name="Settings Apply Local"/> + <menu_item_call label="Auf Parzelle anwenden" name="Settings Apply Parcel"/> <menu_item_call label="In Marktplatz-Auflistungen kopieren" name="Marketplace Copy"/> <menu_item_call label="In Marktplatz-Auflistungen verschieben" name="Marketplace Move"/> <menu_item_call label="--keine Optionen--" name="--no options--"/> diff --git a/indra/newview/skins/default/xui/de/menu_inventory_add.xml b/indra/newview/skins/default/xui/de/menu_inventory_add.xml index af70c08ba1..251b219a12 100644 --- a/indra/newview/skins/default/xui/de/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/de/menu_inventory_add.xml @@ -5,9 +5,7 @@ <menu_item_call label="Sound ([COST] L$)..." name="Upload Sound"/> <menu_item_call label="Animation ([COST] L$)..." name="Upload Animation"/> <menu_item_call label="Modell..." name="Upload Model"/> - <menu_item_call label="Modellassistent..." name="Upload Model Wizard"/> <menu_item_call label="Mehrfach-Upload ([COST] L$ pro Datei)..." name="Bulk Upload"/> - <menu_item_call label="Hochlade-Berechtigungen (Standard) festlegen" name="perm prefs"/> </menu> <menu_item_call label="Neuer Ordner" name="New Folder"/> <menu_item_call label="Neues Skript" name="New Script"/> @@ -25,6 +23,7 @@ <menu_item_call label="Neue Unterhose" name="New Underpants"/> <menu_item_call label="Neues Alpha" name="New Alpha"/> <menu_item_call label="Neue Tätowierung" name="New Tattoo"/> + <menu_item_call label="Neues Universal" name="New Universal"/> <menu_item_call label="Neue Physik" name="New Physics"/> </menu> <menu label="Neue Körperteile" name="New Body Parts"> @@ -33,4 +32,9 @@ <menu_item_call label="Neues Haar" name="New Hair"/> <menu_item_call label="Neue Augen" name="New Eyes"/> </menu> + <menu label="Neue Einstellungen" name="New Settings"> + <menu_item_call label="Neuer Himmel" name="New Sky"/> + <menu_item_call label="Neues Wasser" name="New Water"/> + <menu_item_call label="Neuer Tageszyklus" name="New Day Cycle"/> + </menu> </menu> diff --git a/indra/newview/skins/default/xui/de/menu_outfit_gear.xml b/indra/newview/skins/default/xui/de/menu_outfit_gear.xml index 211cc5c54e..817ec28cff 100644 --- a/indra/newview/skins/default/xui/de/menu_outfit_gear.xml +++ b/indra/newview/skins/default/xui/de/menu_outfit_gear.xml @@ -20,6 +20,7 @@ <menu_item_call label="Neues Alpha" name="New Alpha"/> <menu_item_call label="Neue Physik" name="New Physics"/> <menu_item_call label="Neue Tätowierung" name="New Tattoo"/> + <menu_item_call label="Neues Universal" name="New Universal"/> </menu> <menu label="Neue Körperteile" name="New Body Parts"> <menu_item_call label="Neue Form" name="New Shape"/> diff --git a/indra/newview/skins/default/xui/de/menu_save_settings.xml b/indra/newview/skins/default/xui/de/menu_save_settings.xml new file mode 100644 index 0000000000..458c3fdc14 --- /dev/null +++ b/indra/newview/skins/default/xui/de/menu_save_settings.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="save_settings_menu"> + <menu_item_check label="Speichern" name="save_settings"/> + <menu_item_check label="Speichern unter" name="save_as_new_settings"/> + <menu_item_check label="Festlegen" name="commit_changes"/> + <menu_item_check label="Nur auf mich anwenden" name="apply_local"/> + <menu_item_check label="Auf Parzelle anwenden" name="apply_parcel"/> + <menu_item_check label="Auf Region anwenden" name="apply_region"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/de/menu_settings_add.xml b/indra/newview/skins/default/xui/de/menu_settings_add.xml new file mode 100644 index 0000000000..ebf6c2b314 --- /dev/null +++ b/indra/newview/skins/default/xui/de/menu_settings_add.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_add"> + <menu_item_call label="Neuer Himmel" name="New Sky"/> + <menu_item_call label="Neues Wasser" name="New Water"/> + <menu_item_call label="Neuer Tageszyklus" name="New Day Cycle"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/de/menu_settings_gear.xml b/indra/newview/skins/default/xui/de/menu_settings_gear.xml new file mode 100644 index 0000000000..4be4675899 --- /dev/null +++ b/indra/newview/skins/default/xui/de/menu_settings_gear.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_gear"> + <menu_item_call label="Bearbeiten" name="edit_settings"/> + <menu_item_call label="Nur auf mich anwenden" name="Settings Apply Local"/> + <menu_item_call label="Auf Parzelle anwenden" name="Settings Apply Parcel"/> + <menu_item_call label="Auf Region anwenden" name="Settings Apply Region"/> + <menu_item_call label="Kopieren" name="copy_settings"/> + <menu_item_call label="Einfügen" name="paste_settings"/> + <menu_item_call label="UUID kopieren" name="copy_uuid"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml index 5917a0b529..6ea4ae9ab3 100644 --- a/indra/newview/skins/default/xui/de/menu_viewer.xml +++ b/indra/newview/skins/default/xui/de/menu_viewer.xml @@ -79,30 +79,15 @@ <menu_item_check label="Parzelleneigenschaften" name="Parcel Properties"/> <menu_item_check label="Menü „Erweitert“" name="Show Advanced Menu"/> </menu> - <menu label="Sonne" name="Sun"> + <menu label="Umgebung" name="Environment"> <menu_item_check label="Sonnenaufgang" name="Sunrise"/> <menu_item_check label="Mittag" name="Noon"/> <menu_item_check label="Sonnenuntergang" name="Sunset"/> <menu_item_check label="Mitternacht" name="Midnight"/> - <menu_item_check label="Regionseinstellungen verwenden" name="Use Region Settings"/> - </menu> - <menu label="Umwelt-Editor" name="Environment Editor"> - <menu_item_call label="Umwelt-Einstellungen..." name="Environment Settings"/> - <menu label="Wasser-Voreinstellungen" name="Water Presets"> - <menu_item_call label="Neue Voreinstellung..." name="new_water_preset"/> - <menu_item_call label="Voreinstellung bearbeiten..." name="edit_water_preset"/> - <menu_item_call label="Voreinstellung löschen..." name="delete_water_preset"/> - </menu> - <menu label="Himmel-Voreinstellungen" name="Sky Presets"> - <menu_item_call label="Neue Voreinstellung..." name="new_sky_preset"/> - <menu_item_call label="Voreinstellung bearbeiten..." name="edit_sky_preset"/> - <menu_item_call label="Voreinstellung löschen..." name="delete_sky_preset"/> - </menu> - <menu label="Tag-Voreinstellungen" name="Day Presets"> - <menu_item_call label="Neue Voreinstellung..." name="new_day_preset"/> - <menu_item_call label="Voreinstellung bearbeiten..." name="edit_day_preset"/> - <menu_item_call label="Voreinstellung löschen..." name="delete_day_preset"/> - </menu> + <menu_item_check label="Gemeinsame Umgebung verwenden" name="Use Shared Environment"/> + <menu_item_call label="Meine Umgebungen..." name="my_environs"/> + <menu_item_call label="Persönliche Beleuchtung..." name="adjustment_tool"/> + <menu_item_check label="Wolken pausieren" name="pause_clouds"/> </menu> </menu> <menu label="Bauen" name="BuildTools"> @@ -346,6 +331,9 @@ <menu_item_check label="Automatische Alpha-Masken (nicht aufgeschoben)" name="Automatic Alpha Masks (non-deferred)"/> <menu_item_check label="Animationstexturen" name="Animation Textures"/> <menu_item_check label="Texturen deaktivieren" name="Disable Textures"/> + <menu_item_check label="Umgebung deaktivieren" name="Disable Ambient"/> + <menu_item_check label="Sonnenlicht deaktivieren" name="Disable Sunlight"/> + <menu_item_check label="Lokale Lichtquellen deaktivieren" name="Disable Local Lights"/> <menu_item_check label="Voll-Res-Texturen" name="Rull Res Textures"/> <menu_item_check label="Angehängte Lichter rendern" name="Render Attached Lights"/> <menu_item_check label="Angehängte Partikel rendern" name="Render Attached Particles"/> @@ -477,6 +465,7 @@ <menu_item_call label="Rock" name="Skirt"/> <menu_item_call label="Alpha" name="Alpha"/> <menu_item_call label="Tätowierung" name="Tattoo"/> + <menu_item_call label="Universal" name="Universal"/> <menu_item_call label="Physik" name="Physics"/> <menu_item_call label="Alle Kleider" name="All Clothes"/> </menu> diff --git a/indra/newview/skins/default/xui/de/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/de/menu_wearable_list_item.xml index 283e454a06..e4c2c88f11 100644 --- a/indra/newview/skins/default/xui/de/menu_wearable_list_item.xml +++ b/indra/newview/skins/default/xui/de/menu_wearable_list_item.xml @@ -3,6 +3,7 @@ <menu_item_call label="Ersetzen" name="wear_replace"/> <menu_item_call label="Anziehen" name="wear_wear"/> <menu_item_call label="Hinzufügen" name="wear_add"/> + <menu_item_call label="Berühren" name="touch" /> <menu_item_call label="Ausziehen / Abnehmen" name="take_off_or_detach"/> <menu_item_call label="Abnehmen" name="detach"/> <context_menu label="Anhängen an" name="wearable_attach_to"/> diff --git a/indra/newview/skins/default/xui/de/menu_wearing_gear.xml b/indra/newview/skins/default/xui/de/menu_wearing_gear.xml index dacf898b6a..6cb0d095e7 100644 --- a/indra/newview/skins/default/xui/de/menu_wearing_gear.xml +++ b/indra/newview/skins/default/xui/de/menu_wearing_gear.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <toggleable_menu name="Gear Wearing"> - <menu_item_call label="Outfit bearbeiten" name="edit"/> + <menu_item_call label="Berühren" name="touch"/> + <menu_item_call label="Bearbeiten" name="edit_item"/> + <menu_item_call label="Outfit bearbeiten" name="edit_outfit"/> <menu_item_call label="Ausziehen" name="takeoff"/> <menu_item_call label="Outfitliste in Zwischenablage kopieren" name="copy"/> </toggleable_menu> diff --git a/indra/newview/skins/default/xui/de/menu_wearing_tab.xml b/indra/newview/skins/default/xui/de/menu_wearing_tab.xml index 61002b3dad..c729ef6b00 100644 --- a/indra/newview/skins/default/xui/de/menu_wearing_tab.xml +++ b/indra/newview/skins/default/xui/de/menu_wearing_tab.xml @@ -1,8 +1,9 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="Wearing"> + <menu_item_call label="Berühren" name="touch_attach"/> <menu_item_call label="Ausziehen" name="take_off"/> <menu_item_call label="Abnehmen" name="detach"/> - <menu_item_call label="Outfit bearbeiten" name="edit"/> + <menu_item_call label="Outfit bearbeiten" name="edit_outfit"/> <menu_item_call label="Bearbeiten" name="edit_item"/> <menu_item_call label="Original anzeigen" name="show_original"/> </context_menu> diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index feb1ae23a5..359a835630 100644 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -266,6 +266,10 @@ Möchten Sie den ausgewählten Einwohnern Änderungsrechte gewähren? Möchten Sie den ausgewählten Einwohnern die Änderungsrechte entziehen? <usetemplate name="okcancelbuttons" notext="Nein" yestext="Ja"/> </notification> + <notification name="GroupNameLengthWarning"> + Ein Gruppenname muss zwischen [MIN_LEN] und [MAX_LEN] Zeichen lang sein. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="UnableToCreateGroup"> Gruppe konnte nicht erstellt werden. [MESSAGE] @@ -366,7 +370,7 @@ Fortfahren? Sie haben nicht genug L$, um dieser Gruppe beizutreten. </notification> <notification name="CreateGroupCost"> - Die Gründung dieser Gruppe kostet 100 L$. + Die Erstellung dieser Gruppe kostet L$[COST]. Gruppen müssen mehr als ein Mitglied haben oder sie werden gelöscht. Bitte laden Sie innerhalb von 48 Stunden Mitglieder in Ihre Gruppe ein. <usetemplate canceltext="Abbrechen" name="okcancelbuttons" notext="Abbrechen" yestext="Gruppe für 100 L$ erstellen"/> @@ -508,6 +512,9 @@ Um Medien nur auf einer Fläche einzufügen, wählen Sie „Oberfläche auswähl <notification name="ErrorEncodingSnapshot"> Fehler beim Erstellen des Fotos! </notification> + <notification name="ErrorCannotAffordUpload"> + Du brauchst L$[COST], um diesen Artikel hochzuladen. + </notification> <notification name="ErrorPhotoCannotAfford"> Es kostet L$[COST], um ein Foto in Ihrem Inventar zu speichern. Sie können entweder L$ kaufen oder das Foto auf Ihrem Computer speichern. </notification> @@ -1753,11 +1760,14 @@ Diese Gruppe verlassen? <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="GroupLimitInfo"> - Die Gruppenbegrenzung für Basiskonten ist [MAX_BASIC]; für -[https://secondlife.com/premium/ Premium-]Konten ist sie [MAX_PREMIUM]. -Wenn Sie ein Downgrade Ihres Kontos durchgeführt haben, müssen Sie das Gruppenlimit unter [MAX_BASIC] bringen, bevor sich weitere Personen registrieren können. - -[https://secondlife.com/my/account/membership.php Noch heute upgraden!] + Einwohner mit Basic-Mitgliedschaft können bis zu [MAX_BASIC] Gruppen beitreten. +Premium-Mitgliedschaften erlauben bis zu [MAX_PREMIUM]. [https://secondlife.com/my/account/membership.php? Mehr Informationen oder Upgrade] + <usetemplate name="okbutton" yestext="Schließen"/> + </notification> + <notification name="GroupLimitInfoPlus"> + Einwohner mit Basic-Mitgliedschaft können bis zu [MAX_BASIC] Gruppen beitreten. +Premium-Mitgliedschaften erlauben bis zu [MAX_PREMIUM]. Premium-Plus-Mitgliedschaften +erlauben bis zu [MAX_PREMIUM_PLUS]. [https://secondlife.com/my/account/membership.php? Mehr Informationen oder Upgrade] <usetemplate name="okbutton" yestext="Schließen"/> </notification> <notification name="KickUser"> @@ -1976,6 +1986,11 @@ Tausende Regionen werden verändert und der Spaceserver wird dadurch stark belas Durch Deaktivieren dieser Option können Einstellungen der Parzellenbesitzer zum Schutz vor Belästigungen, zur Aufrechterhaltung der Privatsphäre oder zum Schutz von Minderjährigen vor nicht altersgemäßen Inhalten aufgehoben werden. Bitte sprechen Sie mit den Parzellenbesitzern, falls erforderlich. <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="EstateParcelEnvironmentOverride"> + Durch Deaktivieren dieser Option werden jegliche benutzerdefinierten Umgebungen entfernt, die von den Parzelleneigentümern zu ihren Parzellen hinzugefügt wurden. Bitte sprechen Sie mit den Parzellenbesitzern, falls erforderlich. +Fortfahren? + <usetemplate name="okcancelbuttons" notext="Abbrechen" yestext="OK"/> + </notification> <notification name="RegionEntryAccessBlocked"> Die Region, die Sie besuchen möchten, enthält Inhalte, die Ihre aktuellen Einstellungen überschreiten. Sie können Ihre Einstellungen unter „Ich“ > „Einstellungen“ > „Allgemein“ ändern. <usetemplate name="okbutton" yestext="OK"/> @@ -2455,7 +2470,15 @@ Von einer Webseite zu diesem Formular linken, um anderen leichten Zugang zu dies Diese Tageszyklusdatei verweist auf eine fehlende Himmel-Datei: [SKY]. </notification> <notification name="WLRegionApplyFail"> - Die Einstellungen konnten nicht auf die Region angewendet werden. Verlassen Sie die Region und kehren Sie zurück, um das Problem zu beheben. Angegebener Grund: [FAIL_REASON] + Die Einstellungen konnten nicht auf die Region angewendet werden. Grund: [FAIL_REASON] + </notification> + <notification name="WLLocalTextureDayBlock"> + Eine lokale Textur wird im Pfad [TRACK], Frame #[FRAMENO] ([FRAME]%) im Feld [FIELD] verwendet. +Die Einstellungen können nicht mit lokalen Texturen gespeichert werden. + </notification> + <notification name="WLLocalTextureFixedBlock"> + Im Feld [FIELD] wird eine lokale Textur verwendet. +Die Einstellungen können nicht mit lokalen Texturen gespeichert werden. </notification> <notification name="EnvCannotDeleteLastDayCycleKey"> Der letzte Schlüssel in diesem Tageszyklus kann nicht gelöscht werden, da ein Tageszyklus nicht leer sein kann. Statt den letzten verbleibenden Schlüssel zu löschen, versuchen Sie stattdessen, ihn zu modifizieren und dann einen neuen zu erstellen. @@ -3307,6 +3330,22 @@ Diese werden für ein paar Sekunden sicherheitshalber gesperrt. Sie wurden vom Moderator stummgeschaltet. <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FailedToGetBenefits"> + Leider konnten wir für diese Sitzung keine Informationen zu den Leistungen erhalten. Dies sollte in einer normalen Produktionsumgebung nicht passieren. Kontaktiere bitte den Support. Diese Sitzung wird nicht normal laufen, und wir empfehlen, die Sitzung neu zu starten. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="BulkUploadCostConfirmation"> + Dadurch werden [COUNT] Artikel zu einem Gesamtpreis von L$[COST] hochgeladen. Möchtest du mit dem Hochladen fortfahren? + <usetemplate name="okcancelbuttons" notext="Abbrechen" yestext="Hochladen"/> + </notification> + <notification name="BulkUploadNoCompatibleFiles"> + Ausgewählte Dateien können nicht per Bulk-Upload hochgeladen werden. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="BulkUploadIncompatibleFiles"> + Einige der ausgewählten Dateien können nicht per Bulk-Upload hochgeladen werden. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="UploadCostConfirmation"> Das Hochladen kostet [PRICE] L$. Möchten Sie fortfahren? <usetemplate name="okcancelbuttons" notext="Abbrechen" yestext="Hochladen"/> @@ -4404,4 +4443,76 @@ Wählen Sie eine kleinere Landfläche aus. [REASON] <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FailedToFindSettings"> + Die Einstellungen für [NAME] konnten nicht aus der Datenbank geladen werden. + </notification> + <notification name="FailedToLoadSettingsApply"> + Diese Einstellungen können nicht auf die Umgebung angewendet werden. + </notification> + <notification name="FailedToBuildSettingsDay"> + Diese Einstellungen können nicht auf die Umgebung angewendet werden. + </notification> + <notification name="NoEnvironmentSettings"> + Diese Region unterstützt keine Umgebungseinstellungen. + </notification> + <notification label="Outfit speichern" name="SaveSettingAs"> + Aktuelle Umgebungseinstellungen speichern unter: + <form name="form"> + <input name="message"> + [DESC] (neu) + </input> + <button name="OK" text="OK"/> + <button name="Cancel" text="Abbrechen"/> + </form> + </notification> + <notification name="WLImportFail"> + Alte Windlight-Einstellungen [NAME] konnten nicht aus +[FILE] geladen werden. + +[REASONS] + </notification> + <notification name="WLParcelApplyFail"> + Die Umgebung für diese Parzelle kann nicht eingestellt werden. +Bitte eine Parzelle eingeben oder auswählen, für die Sie die Änderungsrechte besitzen. + </notification> + <notification name="SettingsUnsuported"> + Einstellungen werden von dieser Region nicht unterstützt. +Bitte wechseln sie zu einer Region mit aktivierten Einstellungsmöglichkeiten und versuchen Sie es erneut. + </notification> + <notification name="SettingsConfirmLoss"> + Sie werden die Änderungen an diesem [TYPE] mit der Bezeichnung "[NAME]" verlieren. +Möchten Sie diesen Vorgang wirklich fortsetzen? + <usetemplate ignoretext="Sind Sie sicher, dass Sie die Änderungen verlieren möchten?" name="okcancelignore" notext="Nein" yestext="Ja"/> + </notification> + <notification name="SettingsConfirmReset"> + Sie sind dabei, alle angewendeten Einstellungen zu entfernen. +Möchten Sie diesen Vorgang wirklich fortsetzen? + <usetemplate name="okcancelbuttons" notext="Nein" yestext="Ja"/> + </notification> + <notification name="PersonalSettingsConfirmReset"> + Sie sind dabei, alle angewendeten persönlichen Beleuchtungseinstellungen zu entfernen. +Möchten Sie diesen Vorgang wirklich fortsetzen? + <usetemplate name="okcancelbuttons" notext="Nein" yestext="Ja"/> + </notification> + <notification name="SettingsMakeNoTrans"> + Sie versuchen, nicht transferierbare Einstellungen in diesen Tageszyklus zu importieren. Wenn Sie fortfahren, verlieren die von Ihnen bearbeiteten Einstellungen ebenfalls ihre Transferierbarkeit. + +Diese Änderung kann nicht rückgängig gemacht werden. + +Möchten Sie diesen Vorgang wirklich fortsetzen? + <usetemplate ignoretext="Sind Sie sicher, dass Sie die Transferierbarkeit der Einstellungen aufgeben möchten?" name="okcancelignore" notext="Nein" yestext="Ja"/> + </notification> + <notification name="NoEditFromLibrary"> + Sie können Einstellungen aus der Bibliothek nicht direkt bearbeiten. +Bitte kopieren Sie diese in Ihr Inventar und versuchen Sie es erneut. + </notification> + <notification name="EnvironmentApplyFailed"> + Bei diesen Einstellungen wurde ein Problem festgestellt. Sie können momentan nicht gespeichert oder angewendet werden. + </notification> + <notification name="TrackLoadFailed"> + Pfad konnte nicht in [TRACK] geladen werden. + </notification> + <notification name="TrackLoadMismatch"> + Der Pfad konnte nicht aus [TRACK1] in [TRACK2] geladen werden. + </notification> </notifications> diff --git a/indra/newview/skins/default/xui/de/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/de/panel_edit_tattoo.xml index 075a9d752a..a74d16e50a 100644 --- a/indra/newview/skins/default/xui/de/panel_edit_tattoo.xml +++ b/indra/newview/skins/default/xui/de/panel_edit_tattoo.xml @@ -1,9 +1,11 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_tattoo_panel"> - <panel name="avatar_tattoo_color_panel"> - <texture_picker label="Kopftattoo" name="Head Tattoo" tool_tip="Zum Auswählen eines Bildes hier klicken"/> - <texture_picker label="Obere Tattoos" name="Upper Tattoo" tool_tip="Zum Auswählen eines Bildes hier klicken"/> - <texture_picker label="Untere Tattoos" name="Lower Tattoo" tool_tip="Zum Auswählen eines Bildes hier klicken"/> - <color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/> - </panel> + <scroll_container name="avatar_tattoo_scroll"> + <panel name="avatar_tattoo_color_panel"> + <texture_picker label="Kopf-Tattoo" name="Head Tattoo" tool_tip="Klicken, um ein Bild auszuwählen"/> + <texture_picker label="Oberes Tattoo" name="Upper Tattoo" tool_tip="Klicken, um ein Bild auszuwählen"/> + <texture_picker label="Unteres Tattoo" name="Lower Tattoo" tool_tip="Klicken, um ein Bild auszuwählen"/> + <color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/> + </panel> + </scroll_container> </panel> diff --git a/indra/newview/skins/default/xui/de/panel_edit_universal.xml b/indra/newview/skins/default/xui/de/panel_edit_universal.xml new file mode 100644 index 0000000000..5ae4021b8f --- /dev/null +++ b/indra/newview/skins/default/xui/de/panel_edit_universal.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel name="edit_universal_panel"> + <scroll_container name="avatar_universal_scroll"> + <panel name="avatar_universal_color_panel"> + <texture_picker label="Kopf-Tattoo" name="Head Universal Tattoo" tool_tip="Klicken, um ein Bild auszuwählen"/> + <texture_picker label="Oberes Tattoo" name="Upper Universal Tattoo" tool_tip="Klicken, um ein Bild auszuwählen"/> + <texture_picker label="Unteres Tattoo" name="Lower Universal Tattoo" tool_tip="Klicken, um ein Bild auszuwählen"/> + <texture_picker label="Rock-Tattoo" name="Skirt Tattoo" tool_tip="Klicken, um ein Bild auszuwählen"/> + <texture_picker label="Haar-Tattoo" name="Hair Tattoo" tool_tip="Klicken, um ein Bild auszuwählen"/> + <texture_picker label="Augen-Tattoo" name="Eyes Tattoo" tool_tip="Klicken, um ein Bild auszuwählen"/> + <texture_picker label="Tattoo linker Arm" name="Left Arm Tattoo" tool_tip="Klicken, um ein Bild auszuwählen"/> + <texture_picker label="Tattoo linkes Bein" name="Left Leg Tattoo" tool_tip="Klicken, um ein Bild auszuwählen"/> + <texture_picker label="Aux1-Tattoo" name="Aux1 Tattoo" tool_tip="Klicken, um ein Bild auszuwählen"/> + <texture_picker label="Aux2-Tattoo" name="Aux2 Tattoo" tool_tip="Klicken, um ein Bild auszuwählen"/> + <texture_picker label="Aux3-Tattoo" name="Aux3 Tattoo" tool_tip="Klicken, um ein Bild auszuwählen"/> + <color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/> + </panel> + </scroll_container> +</panel> diff --git a/indra/newview/skins/default/xui/de/panel_edit_wearable.xml b/indra/newview/skins/default/xui/de/panel_edit_wearable.xml index 94a79a0bbd..83593e553f 100644 --- a/indra/newview/skins/default/xui/de/panel_edit_wearable.xml +++ b/indra/newview/skins/default/xui/de/panel_edit_wearable.xml @@ -45,6 +45,9 @@ <string name="edit_tattoo_title"> Tätowierung bearbeiten </string> + <string name="edit_universal_title"> + Universal bearbeiten + </string> <string name="edit_physics_title"> Physik bearbeiten </string> @@ -93,6 +96,9 @@ <string name="tattoo_desc_text"> Tätowierung: </string> + <string name="universal_desc_text"> + Universal: + </string> <string name="physics_desc_text"> Physik: </string> diff --git a/indra/newview/skins/default/xui/de/panel_outbox_inventory.xml b/indra/newview/skins/default/xui/de/panel_outbox_inventory.xml deleted file mode 100644 index 4006022ffc..0000000000 --- a/indra/newview/skins/default/xui/de/panel_outbox_inventory.xml +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<outbox_inventory_panel name="inventory_outbox" tool_tip="Legen Sie Artikel hier ab, um sie zum Verkauf in Ihrem Laden vorzubereiten"/> diff --git a/indra/newview/skins/default/xui/de/panel_people.xml b/indra/newview/skins/default/xui/de/panel_people.xml index 1eb3d4d1b9..81de679429 100644 --- a/indra/newview/skins/default/xui/de/panel_people.xml +++ b/indra/newview/skins/default/xui/de/panel_people.xml @@ -18,7 +18,7 @@ Sie suchen nach Leuten? Verwenden Sie die [secondlife:///app/worldmap Karte]. <string name="no_groups_msg" value="Suchen Sie nach Gruppen? Versuchen Sie es mit der [secondlife:///app/search/groups Suche]."/> <string name="MiniMapToolTipMsg" value="[REGION](Doppelklicken, um Karte zu öffnen; Umschalttaste gedrückt halten und ziehen, um zu schwenken)"/> <string name="AltMiniMapToolTipMsg" value="[REGION](Doppelklicken, um zu teleportieren; Umschalttaste gedrückt halten und ziehen, um zu schwenken)"/> - <string name="GroupCountWithInfo" value="Sie gehören [COUNT] Gruppen an und können [REMAINING] weiteren beitreten. [secondlife:/// Möchten Sie noch mehr?]"/> + <string name="GroupCountWithInfo" value="Du gehörst zu [COUNT] Gruppen, und kannst [REMAINING] weiteren beitreten. [secondlife:/// Erhöhe dein Limit]"/> <tab_container name="tabs"> <panel label="IN DER NÄHE" name="nearby_panel"> <panel label="bottom_panel" name="nearby_buttons_panel"> @@ -51,7 +51,7 @@ Sie suchen nach Leuten? Verwenden Sie die [secondlife:///app/worldmap Karte]. <dnd_button name="minus_btn" tool_tip="Ausgewählte Gruppe verlassen"/> </panel> <text name="groupcount"> - Sie gehören [COUNT] Gruppen an und können [REMAINING] weiteren beitreten. + Du gehörst zu [COUNT] Gruppen, und kannst [REMAINING] weiteren beitreten. </text> </panel> <panel label="AKTUELL" name="recent_panel"> diff --git a/indra/newview/skins/default/xui/de/panel_preferences_chat.xml b/indra/newview/skins/default/xui/de/panel_preferences_chat.xml index 550a99fe0a..51c82c97f8 100644 --- a/indra/newview/skins/default/xui/de/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/de/panel_preferences_chat.xml @@ -13,7 +13,7 @@ <item label="Mittel" name="Medium" value="1"/> <item label="Groß" name="Large" value="2"/> </combo_box> - <check_box label="Blasen-Chat" name="bubble_text_chat"/> + <check_box label="Blasen-Chat" name="bubble_text_chat" left_delta="8"/> </panel> <panel name="im_notification_settings"> <text name="friend_ims"> diff --git a/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml index ff0a6614bd..16fdb69509 100644 --- a/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml @@ -3,10 +3,10 @@ <text name="preset_text"> (Keine) </text> - <text name="QualitySpeed"> + <text name="QualitySpeed" top_delta="20"> Qualität und Geschwindigkeit: </text> - <text name="ShadersPrefText"> + <text name="ShadersPrefText" top_delta="15"> Niedrig </text> <text name="ShadersPrefText2"> @@ -32,10 +32,10 @@ </text> <check_box initial_value="true" label="Freunde immer darstellen" name="AlwaysRenderFriends"/> <button label="Ausnahmen..." name="RenderExceptionsButton"/> - <button label="Einstellungen als Voreinstellung speichern..." name="PrefSaveButton"/> - <button label="Voreinstellung laden..." name="PrefLoadButton"/> + <button label="Einstellungen als Voreinstellung speichern" name="PrefSaveButton" width="235" left="5"/> + <button label="Voreinstellung laden" name="PrefLoadButton" width="120"/> min_val="0.125" - <button label="Voreinstellung löschen..." name="PrefDeleteButton"/> - <button label="Auf empfohlene Einstellungen zurücksetzen" name="Defaults"/> + <button label="Voreinstellung löschen" name="PrefDeleteButton" width="130"/> + <button label="Auf empfohlene Einstellungen zurücksetzen" name="Defaults" width="248"/> <button label="Erweiterte Einstellungen..." name="AdvancedSettings"/> </panel> diff --git a/indra/newview/skins/default/xui/de/panel_preferences_setup.xml b/indra/newview/skins/default/xui/de/panel_preferences_setup.xml index 1435b7f87d..a8509cabac 100644 --- a/indra/newview/skins/default/xui/de/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/de/panel_preferences_setup.xml @@ -35,5 +35,5 @@ <text name="Proxy Settings:"> Proxy-Einstellungen: </text> - <button label="Proxy-Einstellungen ändern" label_selected="Durchsuchen" name="set_proxy"/> + <button label="Proxy-Einstellungen ändern" label_selected="Durchsuchen" name="set_proxy" width="160"/> </panel> diff --git a/indra/newview/skins/default/xui/de/panel_region_environment.xml b/indra/newview/skins/default/xui/de/panel_region_environment.xml index 089a3ae5fc..f5e249b083 100644 --- a/indra/newview/skins/default/xui/de/panel_region_environment.xml +++ b/indra/newview/skins/default/xui/de/panel_region_environment.xml @@ -1,33 +1,116 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Umgebung" name="panel_env_info"> - <text name="water_settings_title"> - Wählen Sie die Wasser- und Himmel-/Tageszykluseinstellungen aus, die alle Besucher Ihrer Region sehen sollen. Mehr Infos - </text> - <radio_group name="region_settings_radio_group"> - <radio_item label="Second Life-Standard verwenden" name="use_sl_default_settings"/> - <radio_item label="Folgende Einstellungen verwenden" name="use_my_settings"/> - </radio_group> - <panel name="user_environment_settings"> - <text name="water_settings_title"> - Wassereinstellung - </text> - <combo_box name="water_settings_preset_combo"> - <combo_box.item label="-Voreinstellung auswählen-" name="item0"/> - </combo_box> - <text name="sky_dayc_settings_title"> - Himmel/Tageszyklus - </text> - <radio_group name="sky_dayc_settings_radio_group"> - <radio_item label="Fester Himmel" name="my_sky_settings"/> - <radio_item label="Tageszyklus" name="my_dayc_settings"/> - </radio_group> - <combo_box name="sky_settings_preset_combo"> - <combo_box.item label="-Voreinstellung auswählen-" name="item0"/> - </combo_box> - <combo_box name="dayc_settings_preset_combo"> - <combo_box.item label="-Voreinstellung auswählen-" name="item0"/> - </combo_box> - </panel> - <button label="Anwenden" name="apply_btn"/> - <button label="Abbrechen" name="cancel_btn"/> + <string name="str_label_use_default"> + Standardeinstellungen verwenden + </string> + <string name="str_label_use_region"> + Regionseinstellungen verwenden + </string> + <string name="str_altitude_desription"> + Himmel [INDEX]([ALTITUDE]m) + </string> + <string name="str_no_parcel"> + Es ist keine Parzelle ausgewählt. Umgebungseinstellungen sind deaktiviert. + </string> + <string name="str_cross_region"> + Umgebungseinstellungen sind außerhalb der Regionsgrenzen nicht verfügbar. + </string> + <string name="str_legacy"> + Umgebungseinstellungen sind für diese Region nicht verfügbar + </string> + <string name="str_disallowed"> + Der Grundbesitzverwalter lässt keine Änderung der Parzellenumgebungen in dieser Region zu. + </string> + <string name="str_too_small"> + Die Parzellengröße muss mindestens 128 Quadratmeter betragen, um eine Umgebung zu unterstützen. + </string> + <string name="str_empty"> + (leer) + </string> + <string name="str_region_env"> + (Regionsumgebung) + </string> + <layout_stack> + <layout_panel name="pnl_environment_disabled"> + <text name="txt_environment_disabled"> + ... + </text> + </layout_panel> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_current"> + <button label="[USEDEFAULT]" name="btn_usedefault"/> + <button label="Inventar verwenden" name="btn_select_inventory"/> + <button label="Anpassen" name="btn_edit"/> + <check_box label="Parzelleneigentümer können die Umgebung außer Kraft setzen" name="chk_allow_override"/> + </layout_panel> + <layout_panel name="pnl_environment_length"> + <text name="lbl_apparent_time"> + [HH]:[MM][AP] ([PRC]%) + </text> + </layout_panel> + <layout_panel name="pnl_environment_buttons"/> + </layout_stack> + </layout_panel> + <layout_panel name="pnl_environment_altitudes"> + <panel name="pnl_alt1"> + <text name="txt_alt1"> + Himmel [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt1"> + Unbekannt + </line_editor> + <settings_drop_target name="sdt_alt1" tool_tip="Ziehen Sie eine Einstellung aus dem Inventar auf dieses Zielfeld, um sie als aktuellen Himmel auszuwählen."/> + </panel> + <panel name="pnl_alt2"> + <text name="txt_alt2"> + Himmel [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt2"> + Unbekannt + </line_editor> + <settings_drop_target name="sdt_alt2" tool_tip="Ziehen Sie eine Einstellung aus dem Inventar auf dieses Zielfeld, um sie als aktuellen Himmel auszuwählen."/> + </panel> + <panel name="pnl_alt3"> + <text name="txt_alt3"> + Himmel [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt3"> + Unbekannt + </line_editor> + <settings_drop_target name="sdt_alt3" tool_tip="Ziehen Sie eine Einstellung aus dem Inventar auf dieses Zielfeld, um sie als aktuellen Himmel auszuwählen."/> + </panel> + <multi_slider initial_value="0" name="sld_altitudes"> + <slider name="sld1" value="1000"/> + <slider name="sld2" value="2000"/> + <slider name="sld3" value="3000"/> + </multi_slider> + <panel name="pnl_ground"> + <text name="txt_ground"> + Boden + </text> + <line_editor name="edt_invname_ground"> + Unbekannt + </line_editor> + <settings_drop_target name="sdt_ground" tool_tip="Ziehen Sie eine Einstellung aus dem Inventar auf dieses Zielfeld, um sie als aktuellen Himmel auf Bodenhöhe auszuwählen."/> + </panel> + <panel name="pnl_water"> + <text name="txt_water"> + Wasser + </text> + <line_editor name="edt_invname_water"> + Unbekannt + </line_editor> + <settings_drop_target name="sdt_water" tool_tip="Ziehen Sie eine Einstellung aus dem Inventar auf dieses Zielfeld, um sie als aktuelles Wasser auszuwählen."/> + </panel> + <button label="Zurücksetzen" name="btn_rst_altitudes" tool_tip="Auf Standardhöhen zurücksetzen"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> </panel> diff --git a/indra/newview/skins/default/xui/de/panel_settings_sky_atmos.xml b/indra/newview/skins/default/xui/de/panel_settings_sky_atmos.xml new file mode 100644 index 0000000000..f14e3fe47f --- /dev/null +++ b/indra/newview/skins/default/xui/de/panel_settings_sky_atmos.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Atmosphäre und Beleuchtung" name="panel_settings_sky_atmos"/> diff --git a/indra/newview/skins/default/xui/de/panel_settings_sky_clouds.xml b/indra/newview/skins/default/xui/de/panel_settings_sky_clouds.xml new file mode 100644 index 0000000000..9d78728eed --- /dev/null +++ b/indra/newview/skins/default/xui/de/panel_settings_sky_clouds.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Wolken" name="panel_settings_sky_clouds"> + <layout_stack> + <layout_panel> + <slider label="X" name="cloud_density_x"/> + <slider label="Y" name="cloud_density_y"/> + <slider label="D" name="cloud_density_d"/> + <slider label="X" name="cloud_detail_x"/> + <slider label="Y" name="cloud_detail_y"/> + <slider label="D" name="cloud_detail_d"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/de/panel_settings_sky_density.xml b/indra/newview/skins/default/xui/de/panel_settings_sky_density.xml new file mode 100644 index 0000000000..d7ee6308d8 --- /dev/null +++ b/indra/newview/skins/default/xui/de/panel_settings_sky_density.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Dichte" name="panel_settings_sky_density"> + <layout_stack> + <layout_panel> + <slider label="Rayleigh-Exponentialterm:" name="rayleigh_exponential"/> + <slider label="Rayleigh-Exponentialskala:" name="rayleigh_exponential_scale"/> + <slider label="Rayleigh-Linearterm:" name="rayleigh_linear"/> + <slider label="Rayleigh-Konstantenterm:" name="rayleigh_constant"/> + <slider label="Rayleigh-Maximalhöhe:" name="rayleigh_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="Mie-Exponentialterm:" name="mie_exponential"/> + <slider label="Mie-Exponentialskala:" name="mie_exponential_scale"/> + <slider label="Mie-Linearterm:" name="mie_linear"/> + <slider label="Mie-Konstantenterm:" name="mie_constant"/> + <slider label="Mie-Anisofaktor." name="mie_aniso_factor"/> + <slider label="Mie-Maximalhöhe:" name="mie_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="Absorptions-Exponentialterm:" name="absorption_exponential"/> + <slider label="Absorptions-Exponentialskala:" name="absorption_exponential_scale"/> + <slider label="Absorptions-Linearterm:" name="absorption_linear"/> + <slider label="Absorptions-Konstantenterm:" name="absorption_constant"/> + <slider label="Absorptions-Maximalhöhe:" name="absorption_max_altitude"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/de/panel_settings_sky_sunmoon.xml b/indra/newview/skins/default/xui/de/panel_settings_sky_sunmoon.xml new file mode 100644 index 0000000000..9234e22d63 --- /dev/null +++ b/indra/newview/skins/default/xui/de/panel_settings_sky_sunmoon.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Sonne und Mond" name="panel_settings_sky_hbodies"> + <layout_stack> + <layout_panel name="sun_layout"> + <check_box label="Beacon anzeigen" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <layout_stack> + <layout_panel name="moon_layout"> + <check_box label="Beacon anzeigen" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/de/panel_settings_water.xml b/indra/newview/skins/default/xui/de/panel_settings_water.xml new file mode 100644 index 0000000000..f11f50dcce --- /dev/null +++ b/indra/newview/skins/default/xui/de/panel_settings_water.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Wasser" name="panel_settings_water"> + <layout_stack name="water_stack1"> + <layout_panel> + <text name="FresnelOffsetText"> + Fresnel-Versatz: + </text> + </layout_panel> + <layout_panel> + <layout_stack name="water_stack2"> + <layout_panel> + <slider label="X:" name="water_normal_scale_x"/> + <slider label="Y:" name="water_normal_scale_y"/> + <slider label="Z:" name="water_normal_scale_z"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/de/panel_tools_texture.xml b/indra/newview/skins/default/xui/de/panel_tools_texture.xml index e0505ce128..9557f2d6d8 100644 --- a/indra/newview/skins/default/xui/de/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/de/panel_tools_texture.xml @@ -1,11 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Textur" name="Texture"> - <panel.string name="string repeats per meter"> - Wiederholungen pro Meter - </panel.string> - <panel.string name="string repeats per face"> - Wiederholungen pro Fläche - </panel.string> <text name="color label"> Farbe </text> @@ -114,4 +108,5 @@ <spinner label="Horizontaler Versatz" name="shinyOffsetU"/> <spinner label="Vertikaler Versatz" name="shinyOffsetV"/> <check_box initial_value="false" label="Planare Flächen ausrichten" name="checkbox planar align" tool_tip="Texturen auf allen ausgewählten Flächen an der zuletzt ausgewählten Fläche ausrichten. Erfordert planares Texture Mapping."/> + <button label="Ausrichten" label_selected="Aktuelle Texturebenen ausrichten" name="button align textures" tool_tip="Aktuelle Texturebenen ausrichten"/> </panel> diff --git a/indra/newview/skins/default/xui/de/role_actions.xml b/indra/newview/skins/default/xui/de/role_actions.xml index 26187678a0..5507fcc04d 100644 --- a/indra/newview/skins/default/xui/de/role_actions.xml +++ b/indra/newview/skins/default/xui/de/role_actions.xml @@ -33,6 +33,7 @@ <action description="Musik- und Medieneinstellungen ändern" longdescription="Die Einstellungen für Streaming-Musik und Filme finden Sie unter „Land-Info“ > „Medien“." name="land change media" value="20"/> <action description="„Terrain bearbeiten“ ein/aus" longdescription="„Terrain bearbeiten“ ein/aus. *WARNUNG* „Land-Info“ > „Optionen“ > „Terrain bearbeiten“ ermöglicht jedem das Terraformen Ihres Grundbesitzes und das Setzen und Verschieben von Linden-Pflanzen. Überlegen Sie sich, wem Sie diese Fähigkeit verleihen. Diese Einstellung finden Sie unter „Land-Info“ > „Optionen“." name="land edit" value="21"/> <action description="„Land-Info“-Optionen einstellen" longdescription="„Sicher (kein Schaden)“ und „Fliegen“ ein- und ausschalten und Einwohnern folgende Aktionen erlauben: „Terrain bearbeiten“, „Bauen“, „Landmarken erstellen“ und „Skripts ausführen“ auf gruppeneigenem Land in „Land-Info“ > Registerkarte „Optionen“." name="land options" value="22"/> + <action description="Ändern Sie die Umgebungseinstellungen und den Tageszyklus." longdescription="Ändern Sie die Umgebungseinstellungen im Reiter "Landinformationen -> Umgebung"." name="land change environment" value="46"/> </action_set> <action_set description="Diese Fähigkeiten ermöglichen es, Mitgliedern das Umgehen von Restriktionen auf gruppeneigenen Parzellen zu erlauben." name="Parcel Powers"> <action description="„Terrain bearbeiten“ zulassen" longdescription="Mitglieder in einer Rolle mit dieser Fähigkeit können auf einer gruppeneigenen Parzelle das Terrain bearbeiten, selbst wenn diese Option unter „Land-Info“ > „Optionen“ deaktiviert ist." name="land allow edit land" value="23"/> diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml index 0fa4ec9aff..43327c132d 100644 --- a/indra/newview/skins/default/xui/de/strings.xml +++ b/indra/newview/skins/default/xui/de/strings.xml @@ -638,6 +638,15 @@ Warten Sie kurz und versuchen Sie dann noch einmal, sich anzumelden. <string name="BUTTON_HELP"> Hilfe anzeigen </string> + <string name="TooltipNotecardNotAllowedTypeDrop"> + Objekte dieses Typs können nicht an Notizkarten +für diese Region angehängt werden. + </string> + <string name="TooltipNotecardOwnerRestrictedDrop"> + An Notizkarten können nur Objekte ohne +Berechtigungseinschränkungen für den +nächsten Eigentümer angehängt werden. + </string> <string name="Searching"> Suchen... </string> @@ -717,6 +726,18 @@ Warten Sie kurz und versuchen Sie dann noch einmal, sich anzumelden. Fehler bei der Upload-Anforderung. Um das Problem zu lösen, besuchen Sie bitte http://secondlife.com/support </string> + <string name="SettingValidationError"> + Validierung für das Importieren der Einstellungen [NAME] fehlgeschlagen + </string> + <string name="SettingImportFileError"> + [FILE] konnte nicht geöffnet werden + </string> + <string name="SettingParseFileError"> + [FILE] konnte nicht geöffnet werden + </string> + <string name="SettingTranslateError"> + Altes Windlight [NAME] konnte nicht übernommen werden + </string> <string name="texture"> Textur </string> @@ -792,6 +813,9 @@ besuchen Sie bitte http://secondlife.com/support <string name="symbolic folder link"> Link zu Ordner </string> + <string name="settings blob"> + Einstellungen + </string> <string name="mesh"> mesh </string> @@ -1122,6 +1146,9 @@ besuchen Sie bitte http://secondlife.com/support <string name="ForceSitAvatar"> Ihren Avatar zwingen, sich zu setzen </string> + <string name="ChangeEnvSettings"> + Umgebungseinstellungen ändern + </string> <string name="NotConnected"> Nicht verbunden </string> @@ -1273,6 +1300,9 @@ besuchen Sie bitte http://secondlife.com/support <string name="tattoo"> Tätowierung </string> + <string name="universal"> + Universal + </string> <string name="physics"> Physik </string> @@ -1315,6 +1345,9 @@ besuchen Sie bitte http://secondlife.com/support <string name="tattoo_not_worn"> Tätowierung nicht getragen </string> + <string name="universal_not_worn"> + Universal nicht getragen + </string> <string name="physics_not_worn"> Physik nicht getragen </string> @@ -1366,6 +1399,9 @@ besuchen Sie bitte http://secondlife.com/support <string name="create_new_tattoo"> Neue Tätowierung erstellen </string> + <string name="create_new_universal"> + Neues Universal erstellen + </string> <string name="create_new_physics"> Neue Physik erstellen </string> @@ -1609,11 +1645,14 @@ Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich unter http://suppo <string name="MarketplaceUpdating"> Aktualisierung läuft... </string> + <string name="UploadFeeInfo"> + Die Gebühr richtet sich nach deiner Abonnementstufe. Bei höheren Stufen werden niedrigere Gebühren erhoben. [https://secondlife.com/my/account/membership.php? Mehr erfahren] + </string> <string name="Open landmarks"> - Landmarken öffnen + Wegweiser öffnen </string> <string name="Unconstrained"> - Variabel + Unbegrenzt </string> <string name="no_transfer" value=" (kein Transferieren)"/> <string name="no_modify" value=" (kein Bearbeiten)"/> @@ -2513,6 +2552,27 @@ Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich unter http://suppo <string name="RegionSettings"> Regionseinstellungen </string> + <string name="NoEnvironmentSettings"> + Diese Region unterstützt keine Umgebungseinstellungen. + </string> + <string name="EnvironmentSun"> + Sonne + </string> + <string name="EnvironmentMoon"> + Mond + </string> + <string name="EnvironmentBloom"> + Bloom + </string> + <string name="EnvironmentCloudNoise"> + Wolkenrauschen + </string> + <string name="EnvironmentNormalMap"> + Normal-Map + </string> + <string name="EnvironmentTransparent"> + Transparent + </string> <string name="ClassifiedClicksTxt"> Klicks: [TELEPORT] teleportieren, [MAP] Karte, [PROFILE] Profil </string> @@ -4729,6 +4789,9 @@ Missbrauchsbericht <string name="New Tattoo"> Neue Tätowierung </string> + <string name="New Universal"> + Neues Universal + </string> <string name="New Physics"> Neue Physik </string> @@ -4855,6 +4918,15 @@ Missbrauchsbericht <string name="Female - Wow"> Weiblich - Wow </string> + <string name="New Daycycle"> + Neuer Tageszyklus + </string> + <string name="New Water"> + Neues Wasser + </string> + <string name="New Sky"> + Neuer Himmel + </string> <string name="/bow"> /verbeugen </string> @@ -5027,6 +5099,15 @@ Bitte überprüfen Sie http://status.secondlifegrid.net, um herauszufinden, ob e <string name="Chat" value=" Chat:"> Chat </string> + <string name="BaseMembership"> + Basis + </string> + <string name="PremiumMembership"> + Premium + </string> + <string name="Premium PlusMembership"> + Premium Plus + </string> <string name="DeleteItems"> Ausgewählte Objekte löschen? </string> @@ -5383,6 +5464,12 @@ Setzen Sie den Editorpfad in Anführungszeichen <string name="BeaconMedia"> Medien-Beacons werden angezeigt (weiß) </string> + <string name="BeaconSun"> + Sonnenrichtungs-Beacon ansehen (orange) + </string> + <string name="BeaconMoon"> + Mondrichtungs-Beacon ansehen (lila) + </string> <string name="ParticleHiding"> Partikel werden ausgeblendet </string> @@ -5410,6 +5497,12 @@ Setzen Sie den Editorpfad in Anführungszeichen <string name="Command_Destinations_Label"> Ziele </string> + <string name="Command_Environments_Label"> + Meine Umgebungen + </string> + <string name="Command_Facebook_Label"> + Facebook + </string> <string name="Command_Flickr_Label"> Flickr </string> @@ -5503,6 +5596,12 @@ Setzen Sie den Editorpfad in Anführungszeichen <string name="Command_Destinations_Tooltip"> Ziele von Interesse </string> + <string name="Command_Environments_Tooltip"> + Meine Umgebungen + </string> + <string name="Command_Facebook_Tooltip"> + Auf Facebook posten + </string> <string name="Command_Flickr_Tooltip"> Auf Flickr hochladen </string> @@ -5698,6 +5797,12 @@ Setzen Sie den Editorpfad in Anführungszeichen <string name="ExperiencePermission12"> automatisch Erlebnisberechtigungen akzeptieren </string> + <string name="ExperiencePermission16"> + ihren Avatar zwingen, sich zu setzen + </string> + <string name="ExperiencePermission17"> + Ändern Ihrer Umgebungseinstellungen + </string> <string name="ExperiencePermissionShortUnknown"> unbekannten Vorgang durchführen: [Permission] </string> @@ -5722,6 +5827,12 @@ Setzen Sie den Editorpfad in Anführungszeichen <string name="ExperiencePermissionShort12"> Berechtigung </string> + <string name="ExperiencePermissionShort16"> + Sitzen + </string> + <string name="ExperiencePermissionShort17"> + Umgebung + </string> <string name="logging_calls_disabled_log_empty"> Unterhaltungen werden nicht protokolliert. Um ein Protokoll zu starten, wählen Sie „Speichern: nur Protokoll“ oder „Speichern: Protokoll und Transkripte“ unter „Einstellungen“ > „Chat“. </string> diff --git a/indra/newview/skins/default/xui/en/control_table_contents_camera.xml b/indra/newview/skins/default/xui/en/control_table_contents_camera.xml new file mode 100644 index 0000000000..24cbb2b885 --- /dev/null +++ b/indra/newview/skins/default/xui/en/control_table_contents_camera.xml @@ -0,0 +1,240 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<contents> + <rows + enabled="false" + name="camera_actions" + value=""> + <columns + type="icontext" + column="lst_action" + font="SansSerif" + halign="left" + label="Camera" + name="lst_action" + value="Cam_FreeCam_Off" /> + </rows> + <rows + name="look_up" + value="look_up"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Look Up" /> + </rows> + <rows + name="look_down" + value="look_down"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Look Down" /> + </rows> + <rows + name="move_forward" + value="move_forward"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Forward" /> + </rows> + <rows + name="move_backward" + value="move_backward"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Backward" /> + </rows> + <rows + name="move_forward_fast" + value="move_forward_fast"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Forward Fast" /> + </rows> + <rows + name="move_backward_fast" + value="move_backward_fast"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Backward Fast" /> + </rows> + <rows + name="spin_over" + value="spin_over"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Spin Over" /> + </rows> + <rows + name="spin_under" + value="spin_under"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Spin Under" /> + </rows> + <rows + name="pan_up" + value="pan_up"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Pan Up" /> + </rows> + <rows + name="pan_down" + value="pan_down"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Pan Down" /> + </rows> + <rows + name="pan_left" + value="pan_left"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Pan Left" /> + </rows> + <rows + name="pan_right" + value="pan_right"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Pan Right" /> + </rows> + <rows + name="pan_in" + value="pan_in"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Pan In" /> + </rows> + <rows + name="pan_out" + value="pan_out"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Pan Out" /> + </rows> + <rows + name="spin_around_ccw" + value="spin_around_ccw"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Camera spin around counterclockwise" + value="Counterclockwise" /> + </rows> + <rows + name="spin_around_cw" + value="spin_around_cw"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Camera spin around clockwise" + value="Clockwise" /> + </rows> + <rows + name="move_forward_sitting" + value="move_forward_sitting"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Forward Sitting" /> + </rows> + <rows + name="move_backward_sitting" + value="move_backward_sitting"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Backward Sitting" /> + </rows> + <rows + name="spin_over_sitting" + value="spin_over_sitting"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Spin Over Sitting" /> + </rows> + <rows + name="spin_under_sitting" + value="spin_under_sitting"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Spin Under Sitting" /> + </rows> + <rows + name="spin_around_ccw_sitting" + value="spin_around_ccw_sitting"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Camera spin around counterclockwise sitting" + value="Counterclockwise Sitting" /> + </rows> + <rows + name="spin_around_cw_sitting" + value="spin_around_cw_sitting"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Camera spin around clockwise sitting" + value="Clockwise Sitting" /> + </rows> +</contents> diff --git a/indra/newview/skins/default/xui/en/control_table_contents_columns_basic.xml b/indra/newview/skins/default/xui/en/control_table_contents_columns_basic.xml new file mode 100644 index 0000000000..e707aaf22c --- /dev/null +++ b/indra/newview/skins/default/xui/en/control_table_contents_columns_basic.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<contents> + <columns + relative_width="0.34" + label="Action" + name="lst_action" /> + <columns + relative_width="0.22" + label="Primary Control" + name="lst_ctrl1" /> + <columns + relative_width="0.22" + label="Alternate 1" + name="lst_ctrl2" /> + <columns + relative_width="0.22" + label="Alternate 2" + name="lst_ctrl3" /> +</contents> diff --git a/indra/newview/skins/default/xui/en/control_table_contents_editing.xml b/indra/newview/skins/default/xui/en/control_table_contents_editing.xml new file mode 100644 index 0000000000..2a3314840a --- /dev/null +++ b/indra/newview/skins/default/xui/en/control_table_contents_editing.xml @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<contents> + <rows + enabled="false" + name="editing_actions" + value=""> + <columns + type="icontext" + column="lst_action" + font="SansSerif" + halign="left" + label="Editing" + name="lst_action" + value="Tool_Dozer" /> + </rows> + <rows + name="edit_avatar_spin_ccw" + value="edit_avatar_spin_ccw"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Camera spin around avatar counterclockwise" + value="Counterclockwise" /> + </rows> + <rows + name="edit_avatar_spin_cw" + value="edit_avatar_spin_cw"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Camera spin around avatar clockwise" + value="Clockwise" /> + </rows> + <rows + name="edit_avatar_spin_over" + value="edit_avatar_spin_over"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Camera spin over avatar" + value="Camera Spin Over" /> + </rows> + <rows + name="edit_avatar_spin_under" + value="edit_avatar_spin_under"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Camera spin under avatar" + value="Camera Spin Under" /> + </rows> + <rows + name="edit_avatar_move_forward" + value="edit_avatar_move_forward"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Forward" /> + </rows> + <rows + name="edit_avatar_move_backward" + value="edit_avatar_move_backward"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Backward" /> + </rows> +</contents> diff --git a/indra/newview/skins/default/xui/en/control_table_contents_media.xml b/indra/newview/skins/default/xui/en/control_table_contents_media.xml new file mode 100644 index 0000000000..ce5d3556b6 --- /dev/null +++ b/indra/newview/skins/default/xui/en/control_table_contents_media.xml @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<contents> + <rows + enabled="false" + name="media_actions" + value=""> + <columns + type="icontext" + column="lst_action" + font="SansSerif" + halign="left" + label="Sound and Media" + name="lst_action" + value="Audio_Press" /> + </rows> + <rows + name="toggle_pause_media" + value="toggle_pause_media"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Play/Pause Media" /> + </rows> + <rows + name="toggle_enable_media" + value="toggle_enable_media"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Play/Stop All Media" /> + </rows> + <rows + name="voice_follow_key" + value="voice_follow_key"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Voice" /> + </rows> + <rows + name="toggle_voice" + value="toggle_voice"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Toggle Voice" /> + </rows> + <rows + name="start_chat" + value="start_chat"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Start Chat" /> + </rows> + <rows + name="start_gesture" + value="start_gesture"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Start Gesture" /> + </rows> +</contents> diff --git a/indra/newview/skins/default/xui/en/control_table_contents_movement.xml b/indra/newview/skins/default/xui/en/control_table_contents_movement.xml new file mode 100644 index 0000000000..b410d2dc1c --- /dev/null +++ b/indra/newview/skins/default/xui/en/control_table_contents_movement.xml @@ -0,0 +1,198 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<contents> + <rows + enabled="false" + name="move_actions" + value=""> + <columns + type="icontext" + column="lst_action" + font="SansSerif" + halign="left" + label="Move Actions" + name="lst_action" + value="Move_Walk_Off" /> + </rows> + <rows + name="walk_to" + value="walk_to"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Walk to location mouse cursor points to" + value="Walk to" /> + </rows> + <rows + name="teleport_to" + value="teleport_to"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Teleport to location mouse cursor points to, but not all locations allow direct teleportation so you might be teleported closer to destination instead" + value="Teleport to" /> + </rows> + <rows + name="push_forward" + value="push_forward"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Move Forward" /> + </rows> + <rows + name="push_backward" + value="push_backward"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Move Backward" /> + </rows> + <rows + name="turn_left" + value="turn_left"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Left" /> + </rows> + <rows + name="turn_right" + value="turn_right"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Right" /> + </rows> + <rows + name="slide_left" + value="slide_left"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Strafe left" /> + </rows> + <rows + name="slide_right" + value="slide_right"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Strafe right" /> + </rows> + <rows + name="jump" + value="jump"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Jump/Up" /> + </rows> + <rows + name="push_down" + value="push_down"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Down" /> + </rows> + <rows + name="run_forward" + value="run_forward"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Run Forward" /> + </rows> + <rows + name="run_backward" + value="run_backward"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Run Backward" /> + </rows> + <rows + name="run_left" + value="run_left"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Run Left" /> + </rows> + <rows + name="run_right" + value="run_right"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Run Right" /> + </rows> + <rows + name="toggle_run" + value="toggle_run"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Toggle Run" /> + </rows> + <rows + name="toggle_fly" + value="toggle_fly"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Fly/Stop flying" /> + </rows> + <rows + name="toggle_sit" + value="toggle_sit"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Sit/Stand" /> + </rows> + <rows + name="stop_moving" + value="stop_moving"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Stop Moving" /> + </rows> +</contents> diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml index 9f853fd960..b2d9e53039 100644 --- a/indra/newview/skins/default/xui/en/floater_about_land.xml +++ b/indra/newview/skins/default/xui/en/floater_about_land.xml @@ -123,8 +123,8 @@ No parcel selected. </panel.string> <panel.string name="time_stamp_template"> - [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local] - </panel.string> + [wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [year,datetime,slt] + </panel.string> <text type="string" length="1" @@ -1800,7 +1800,7 @@ Only large parcels can be listed in search. Music URL: </text> <line_editor - follows="left|top" + follows="left|top|right" height="23" layout="topleft" left="100" @@ -2140,5 +2140,17 @@ Only large parcels can be listed in search. class="land_experiences_panel" filename="panel_region_experiences.xml"> </panel> + <panel + border="true" + follows="all" + label="ENVIRONMENT" + layout="topleft" + left="0" + top="0" + help_topic="land_environment_tab" + name="land_environment_panel" + class="land_environment_panel" + filename="panel_region_environment.xml"> + </panel> </tab_container> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_add_payment_method.xml b/indra/newview/skins/default/xui/en/floater_add_payment_method.xml new file mode 100644 index 0000000000..1f980564d4 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_add_payment_method.xml @@ -0,0 +1,140 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + height="405" + width="900" + layout="topleft" + name="floater_add_payment_method" + single_instance="true" + show_title="false" + legacy_header_height="0" + header_height="0" + background_visible="false" + can_resize="false" + can_drag_on_left="false" + can_minimize="false" + can_close="false"> + <floater.string + name="continue_url"> + https://secondlife.com/my/lindex/buy.php?associate_for_viewer=1 + </floater.string> + <panel + background_opaque="false" + bg_alpha_color="AddPaymentPanel" + border_visible="false" + background_visible="true" + label="wrapper_panel" + layout="topleft" + left="0" + name="wrapper_panel" + top="0" + height="405" + width="900" + follows="all" + translate="false"> + <text + type="string" + length="1" + follows="top|left|right" + font="SansSerifLargeBold" + text_color="White" + layout="topleft" + left="0" + height="14" + top_pad="30" + width="900" + halign="center" + name="title_txt"> + Add a payment method to buy Linden dollars and enjoy more of Second Life. + </text> + <button + follows="top|left|right" + height="24" + label="Get started" + font="SansSerifMedium" + layout="topleft" + left="320" + name="continue_btn" + image_unselected="PushButton_Login" + image_pressed="PushButton_Login_Pressed" + image_hover_unselected="PushButton_Login_Over" + label_color="White" + top_pad ="15" + width="140"/> + <button + follows="top|left|right" + height="24" + label="Later" + layout="topleft" + left_pad="9" + name="close_btn" + width="90"/> + <icon + height="195" + width="260" + image_name="add_payment_image_left" + layout="topleft" + left="30" + name="image_left" + top_pad="30" + use_draw_context_alpha="false"/> + <icon + height="195" + width="260" + image_name="add_payment_image_center" + layout="topleft" + left_pad="30" + name="image_center" + use_draw_context_alpha="false"/> + <icon + height="195" + width="260" + image_name="add_payment_image_right" + layout="topleft" + left_pad="30" + name="image_right" + use_draw_context_alpha="false"/> + <text + type="string" + length="1" + follows="top|left" + font="SansSerifMedium" + text_color="White" + height="75" + width="260" + top_pad="15" + layout="topleft" + word_wrap="true" + left="30" + name="image_left_desc"> + Create an avatar you love. Choose from millions of items in stores and the Second Life Marketplace. Your style is here. + </text> + <text + type="string" + length="1" + follows="top|left" + font="SansSerifMedium" + text_color="White" + height="75" + width="260" + layout="topleft" + word_wrap="true" + left_pad="30" + name="image_center_desc"> + Donate to your favorite performers and hosts. Your support helps them create great experiences. + </text> + <text + type="string" + length="1" + follows="top|left" + font="SansSerifMedium" + text_color="White" + height="75" + width="260" + layout="topleft" + word_wrap="true" + left_pad="30" + name="image_right_desc"> + Make the home of your dreams. With millions of items available to purchase, you can make your retreat unique. + </text> + </panel> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_adjust_environment.xml b/indra/newview/skins/default/xui/en/floater_adjust_environment.xml new file mode 100644 index 0000000000..f4a686bae1 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_adjust_environment.xml @@ -0,0 +1,477 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater layout="topleft" + name="env_adjust_snapshot" + help_topic="day_presets" + save_rect="false" + title="Personal Lighting" + width="845" + height="280" + min_width="500" + min_height="275" + single_instance="true" + can_resize="false"> + <layout_stack name="outer_stack" + width="845" + height="275" + follows="all" + animate="false" + top="0" + orientation="vertical"> + <!-- If I put in a timeline it would go here --> + <layout_panel name="env_controls" + border="false" + bevel_style="in" + auto_resize="true" + user_resize="true" + height="150" + min_height="0" + visible="true"> + <layout_stack name="settings_stack" + width="855" + height="150" + follows="all" + animate="false" + orientation="horizontal"> + <layout_panel border="false" + bevel_style="in" + auto_resize="false" + user_resize="false" + visible="true" + width="160" + height="150"> + <text follows="left|top" + height="10" + layout="topleft" + left="10" + top="5" + width="80">Ambient:</text> + <color_swatch can_apply_immediately="true" + follows="left|top" + height="40" + label_height="0" + layout="topleft" + left_delta="0" + name="ambient_light" + top_pad="5" + width="60"/> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="0" + top_pad="10" + width="80">Blue Horizon:</text> + <color_swatch can_apply_immediately="true" + follows="left|top" + height="40" + label_height="0" + layout="topleft" + left_delta="0" + name="blue_horizon" + top_pad="5" + width="60"/> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="0" + top_pad="10" + width="80">Blue Density:</text> + <color_swatch can_apply_immediately="true" + follows="left|top" + height="40" + label_height="0" + layout="topleft" + left_delta="0" + name="blue_density" + top_pad="5" + width="60"/> + <button + follows="left|top" + height="23" + label="Reset" + tool_tip="Close and reset to Shared Environment" + layout="topleft" + name="btn_reset" + left_delta="-2" + top_pad="10" + width="100"/> + <text follows="right|top" + height="10" + layout="topleft" + right="-12" + top="5" + width="60">Sun Color:</text> + <color_swatch can_apply_immediately="true" + follows="left|top" + height="10" + label_height="0" + layout="topleft" + left_delta="0" + name="sun_color" + top_pad="5" + width="60"/> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="0" + top_pad="5" + width="80">Cloud Color:</text> + <color_swatch can_apply_immediately="true" + follows="left|top" + height="10" + label_height="0" + layout="topleft" + left_delta="0" + name="cloud_color" + top_pad="5" + width="60"/> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="0" + top_pad="10" + name="cloud_map_label" + width="80">Cloud Image:</text> + <texture_picker height="63" + layout="topleft" + left_delta="0" + name="cloud_map" + top_pad="5" + width="60"/> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="0" + top_pad="-13" + name="cloud_map_label" + width="80">Water Image:</text> + <texture_picker height="63" + layout="topleft" + left_delta="0" + name="water_normal_map" + top_pad="5" + width="60"/> + </layout_panel> + <layout_panel border="false" + bevel_style="in" + auto_resize="false" + user_resize="false" + visible="true" + width="200" + height="150"> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="5" + top_pad="5" + width="80">Haze Horizon:</text> + <slider decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="5" + name="haze_horizon" + top_pad="5" + width="185" + can_edit_text="true"/> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_pad="5" + width="80">Haze Density:</text> + <slider decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="5" + name="haze_density" + top_pad="5" + width="185" + can_edit_text="true"/> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_pad="5" + width="185">Cloud Coverage:</text> + <slider decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="1" + name="cloud_coverage" + top_pad="5" + width="185" + can_edit_text="true"/> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_pad="5" + width="185">Cloud Scale:</text> + <slider decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0.01" + max_val="3" + name="cloud_scale" + top_pad="5" + width="185" + can_edit_text="true"/> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_pad="15" + width="80">Scene Gamma:</text> + <slider decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + max_val="20" + name="scene_gamma" + top_pad="5" + width="185" + can_edit_text="true"/> + </layout_panel> + <layout_panel border="false" + bevel_style="in" + auto_resize="false" + user_resize="false" + height="150" + width="310" + min_height="0" + visible="true"> + <text follows="top|left" + font="SansSerifBold" + height="10" + layout="topleft" + name="label" + left="5" + top="5" + width="105">Sun:</text> + <sun_moon_trackball name="sun_rotation" + follows="left|top" + left_delta="0" + top_delta="20" + height="150" + width="150" + thumb_mode="sun"/> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="0" + top_pad="5" + width="200">Azimuth:</text> + <slider decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="359.99" + name="sun_azimuth" + top_pad="5" + width="130" + can_edit_text="true"/> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_pad="5" + width="200">Elevation:</text> + <slider decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="-90" + max_val="90" + name="sun_elevation" + top_pad="5" + width="130" + can_edit_text="true"/> + <check_box control_name="sunbeacon" + width="60" + height="16" + label="Show Beacon" + layout="topleft" + name="sunbeacon" + left_delta="-5" + top_pad="8" + follows="left|top"/> + <text follows="left|top" + height="10" + layout="topleft" + left_pad="95" + top="25" + width="80">Scale:</text> + <slider decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0.25" + max_val="20" + name="sun_scale" + top_delta="15" + width="130" + can_edit_text="true"/> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_pad="5" + width="100">Glow Focus:</text> + <slider decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="-2" + max_val="2" + name="glow_focus" + top_pad="5" + width="130" + can_edit_text="true"/> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_pad="5" + width="200">Glow Size:</text> + <slider decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="1.99" + name="glow_size" + top_pad="5" + width="130" + can_edit_text="true"/> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_pad="10" + width="200">Star Brightness:</text> + <slider decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="500" + name="star_brightness" + top_pad="5" + width="130" + can_edit_text="true"/> + </layout_panel> + <layout_panel border="false" + bevel_style="in" + auto_resize="false" + user_resize="false" + height="150" + width="160" + min_height="0" + visible="true"> + <text follows="top|left" + font="SansSerifBold" + height="10" + layout="topleft" + name="label" + left="5" + top="5" + width="105">Moon:</text> + <sun_moon_trackball name="moon_rotation" + follows="left|top" + left_delta="0" + top_delta="20" + height="150" + width="150" + thumb_mode="moon"/> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="0" + top_pad="5" + width="200">Azimuth:</text> + <slider decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="359.99" + name="moon_azimuth" + top_pad="5" + width="130" + can_edit_text="true"/> + <text follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_pad="5" + width="200">Elevation:</text> + <slider decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="-90" + max_val="90" + name="moon_elevation" + top_pad="5" + width="130" + can_edit_text="true"/> + <check_box control_name="moonbeacon" + follows="left|top" + width="60" + height="16" + label="Show Beacon" + layout="topleft" + name="moonbeacon" + left_delta="0" + top_pad="8"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_animation_anim_preview.xml b/indra/newview/skins/default/xui/en/floater_animation_anim_preview.xml index b5538a511c..c4ffba33fd 100644 --- a/indra/newview/skins/default/xui/en/floater_animation_anim_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_animation_anim_preview.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater legacy_header_height="18" - height="190" + height="180" layout="topleft" name="Anim Preview" help_topic="animation_anim_preview" @@ -60,9 +60,9 @@ height="22" label="Upload (L$[AMOUNT])" layout="topleft" - left="45" + left="35" name="ok_btn" - top_pad="60" + top_pad="15" width="150" /> <button follows="right|bottom" @@ -73,4 +73,17 @@ name="cancel_btn" left_pad="5" width="90" /> + <text + type="string" + length="1" + follows="left|top" + height="35" + layout="topleft" + left="10" + mouse_opaque="false" + skip_link_underline="true" + name="info_text" + word_wrap="true" + top_pad="10" + width="270"/> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_animation_bvh_preview.xml b/indra/newview/skins/default/xui/en/floater_animation_bvh_preview.xml index cb6b2f6ebc..0c62bfe304 100644 --- a/indra/newview/skins/default/xui/en/floater_animation_bvh_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_animation_bvh_preview.xml @@ -2,7 +2,7 @@ <floater legacy_header_height="18" can_minimize="false" - height="610" + height="645" layout="topleft" name="Animation Preview" help_topic="animation_preview" @@ -570,4 +570,17 @@ We recommend BVH files exported from Poser 4. name="cancel_btn" left="142" width="128" /> + <text + type="string" + length="1" + follows="left|top" + height="35" + layout="topleft" + left="10" + mouse_opaque="false" + skip_link_underline="true" + name="info_text" + word_wrap="true" + top_pad="10" + width="270"/> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_avatar.xml b/indra/newview/skins/default/xui/en/floater_avatar.xml index 92c5d8bcbe..3df2683ca8 100644 --- a/indra/newview/skins/default/xui/en/floater_avatar.xml +++ b/indra/newview/skins/default/xui/en/floater_avatar.xml @@ -14,7 +14,7 @@ help_topic="avatar" save_rect="true" save_visibility="true" - title="CHOOSE AN AVATAR" + title="COMPLETE AVATARS" width="700"> <web_browser top="25" diff --git a/indra/newview/skins/default/xui/en/floater_avatar_textures.xml b/indra/newview/skins/default/xui/en/floater_avatar_textures.xml index bac3ea86f1..6540f5e348 100644 --- a/indra/newview/skins/default/xui/en/floater_avatar_textures.xml +++ b/indra/newview/skins/default/xui/en/floater_avatar_textures.xml @@ -28,11 +28,13 @@ name="scroll_content_panel" follows="left|top" min_height="300" + min_width="300" layout="topleft" top="0" background_visible="false" left="0" - height="680"> + height="1165" + width="1015"> <text type="string" length="1" @@ -102,6 +104,14 @@ Textures name="hair_alpha" top_delta="0" width="92" /> + <texture_picker + height="103" + label="Hair Tattoo" + layout="topleft" + left_pad="7" + name="hair_tattoo" + top_delta="0" + width="92" /> <texture_picker height="103" @@ -135,6 +145,14 @@ Textures name="head_tattoo" top_delta="0" width="92" /> + <texture_picker + height="103" + label="Head Unv Tattoo" + layout="topleft" + left_pad="7" + name="head_universal_tattoo" + top_delta="0" + width="92" /> <texture_picker height="103" @@ -160,6 +178,14 @@ Textures name="eyes_alpha" top_delta="0" width="92" /> + <texture_picker + height="103" + label="Eyes Tattoo" + layout="topleft" + left_pad="7" + name="eyes_tattoo" + top_delta="0" + width="92" /> <texture_picker height="103" @@ -225,6 +251,14 @@ Textures name="upper_tattoo" top_delta="0" width="92" /> + <texture_picker + height="103" + label="Upper Unv Tattoo" + layout="topleft" + left_pad="7" + name="upper_universal_tattoo" + top_delta="0" + width="92" /> <texture_picker height="103" @@ -298,6 +332,14 @@ Textures name="lower_tattoo" top_delta="0" width="92" /> + <texture_picker + height="103" + label="Lower Unv Tattoo" + layout="topleft" + left_pad="7" + name="lower_universal_tattoo" + top_delta="0" + width="92" /> <texture_picker height="103" @@ -315,6 +357,99 @@ Textures name="skirt" top_delta="0" width="92" /> + <texture_picker + height="103" + label="Skirt Tattoo" + layout="topleft" + left_pad="7" + name="skirt_tattoo" + top_delta="0" + width="92" /> + + <texture_picker + height="103" + label="Left Arm" + layout="topleft" + left="10" + name="leftarm-baked" + top_delta="100" + width="92" /> + <texture_picker + height="103" + label="Left Arm Tattoo" + layout="topleft" + left_pad="21" + name="leftarm_tattoo" + top_delta="0" + width="92" /> + + <texture_picker + height="103" + label="Left Leg" + layout="topleft" + left="10" + name="leftleg-baked" + top_delta="100" + width="92" /> + <texture_picker + height="103" + label="Left Leg Tattoo" + layout="topleft" + left_pad="21" + name="leftleg_tattoo" + top_delta="0" + width="92" /> + + <texture_picker + height="103" + label="AUX 1" + layout="topleft" + left="10" + name="aux1-baked" + top_delta="100" + width="92" /> + <texture_picker + height="103" + label="AUX 1 Tattoo" + layout="topleft" + left_pad="21" + name="aux1_tattoo" + top_delta="0" + width="92" /> + + <texture_picker + height="103" + label="AUX 2" + layout="topleft" + left="10" + name="aux2-baked" + top_delta="100" + width="92" /> + <texture_picker + height="103" + label="AUX 2 Tattoo" + layout="topleft" + left_pad="21" + name="aux2_tattoo" + top_delta="0" + width="92" /> + + <texture_picker + height="103" + label="AUX 3" + layout="topleft" + left="10" + name="aux3-baked" + top_delta="100" + width="92" /> + <texture_picker + height="103" + label="AUX 3 Tattoo" + layout="topleft" + left_pad="21" + name="aux3_tattoo" + top_delta="0" + width="92" /> </panel> </panel> </scroll_container> diff --git a/indra/newview/skins/default/xui/en/floater_beacons.xml b/indra/newview/skins/default/xui/en/floater_beacons.xml index 3d29356b22..d5947fc0af 100644 --- a/indra/newview/skins/default/xui/en/floater_beacons.xml +++ b/indra/newview/skins/default/xui/en/floater_beacons.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater legacy_header_height="18" - height="245" + height="310" layout="topleft" name="beacons" help_topic="beacons" @@ -12,7 +12,7 @@ width="240"> <panel follows="left|top|right|bottom" - height="240" + height="305" layout="topleft" left="10" name="beacons_panel" @@ -143,6 +143,43 @@ <check_box.commit_callback function="Beacons.UICheck" /> </check_box> + <view_border + bevel_style="in" + height="0" + layout="topleft" + left="0" + name="cost_text_border" + top_pad="5" + width="220"/> + <text + follows="all" + height="16" + font="SansSerif" + left="0" + top_pad="7" + name="label_objects" + text_color="White" + type="string"> + Show direction to: + </text> + <check_box + control_name="sunbeacon" + height="16" + label="Sun" + layout="topleft" + name="sun" > + <check_box.commit_callback + function="Beacons.UICheck" /> + </check_box> + <check_box + control_name="moonbeacon" + height="16" + label="Moon" + layout="topleft" + name="moon" > + <check_box.commit_callback + function="Beacons.UICheck" /> + </check_box> </panel> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_bulk_perms.xml b/indra/newview/skins/default/xui/en/floater_bulk_perms.xml index 9fa93b640f..431c33a339 100644 --- a/indra/newview/skins/default/xui/en/floater_bulk_perms.xml +++ b/indra/newview/skins/default/xui/en/floater_bulk_perms.xml @@ -156,7 +156,20 @@ name="icon_texture" tool_tip="Textures" left_pad="2" /> - + <check_box + control_name="BulkChangeIncludeSettings" + height="16" + name="check_settings" + left="245" + top="25" + width="16" /> + <icon + height="16" + image_name="Inv_Settings" + mouse_opaque="true" + name="icon_setting" + tool_tip="Environment settings" + left_pad="2" /> <button height="23" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/floater_buy_currency.xml b/indra/newview/skins/default/xui/en/floater_buy_currency.xml index 553c5d51d0..e8e83301be 100644 --- a/indra/newview/skins/default/xui/en/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/en/floater_buy_currency.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <floater - legacy_header_height="18" + can_minimize="false" - height="275" + height="285" layout="topleft" title="BUY L$" name="buy currency" @@ -13,315 +13,389 @@ name="buy_currency"> Buy L$ [LINDENS] for approx. [LOCALAMOUNT] </floater.string> + <floater.string + name="info_cannot_buy"> + Unable to Buy + </floater.string> + <floater.string + name="estimated_zero"> + US$ 0.00 + </floater.string> <icon - height="215" + height="245" image_name="Linden_Dollar_Background" layout="topleft" left="0" name="normal_background" - top="17" + top="0" use_draw_context_alpha="false" width="350" /> - <text - type="string" - length="1" - follows="top|left|right" - font="SansSerifHuge" + <layout_stack + animate="false" + name="outer_stack" + layout="topleft" + follows="all" + orientation="vertical" + left="0" + top="0" + width="350" + height="285"> + <layout_panel + auto_resize="false" + name="layout_panel_title" layout="topleft" - left="20" - height="30" - top="25" - width="340" - name="info_need_more"> - You need more L$ - </text> - <text - type="string" - length="1" - follows="top|left" - height="16" + follows="all" + width="350" + height="35"> + <text + type="string" + length="1" + follows="top|left|right" + font="SansSerifLarge" + layout="topleft" + left="20" + height="30" + top="8" + width="340" + name="info_need_more"> + You need more L$ + </text> + <text + type="string" + length="1" + follows="top|left|right" + font="SansSerifLarge" + layout="topleft" + left="20" + height="30" + top="8" + width="300" + name="info_buying"> + Buy L$ + </text> + <view_border + bevel_style="none" + height="0" + layout="topleft" + left="20" + name="text_border" + top_delta="25" + width="300"/> + </layout_panel> + <layout_panel + auto_resize="false" + name="layout_panel_price" layout="topleft" - top="246" - left="15" - width="300" - name="contacting"> - Contacting LindeX... - </text> - <text - type="string" - length="1" - follows="top|left" - font="SansSerifHuge" + follows="all" + width="350" + height="18"> + <text + type="string" + length="1" + follows="top|left" + font="SansSerifMedium" + height="16" + layout="topleft" + left="20" + name="target_price_label" + top_pad="3" + width="210"> + You need + </text> + <text + type="string" + length="1" + font="SansSerifMedium" + follows="top|left" + halign="right" + height="16" + layout="topleft" + left="200" + name="target_price" + top_delta="0" + width="120"> + L$ [AMT] + </text> + </layout_panel> + <layout_panel + auto_resize="false" + name="layout_panel_balance" layout="topleft" - left="20" - height="30" - top="25" - width="300" - name="info_buying"> - Buy L$ - </text> - <text - type="string" - length="1" - follows="top|left" - font="SansSerifMedium" - height="16" - layout="topleft" - left="20" - name="balance_label" - top="65" - width="210"> - I have - </text> - <text - type="string" - length="1" - font="SansSerifMedium" - follows="top|left" - halign="right" - height="16" - layout="topleft" - left="200" - name="balance_amount" - top_delta="0" - width="120"> + follows="all" + width="350" + height="19"> + <text + type="string" + length="1" + follows="top|left" + font="SansSerifMedium" + height="16" + layout="topleft" + left="20" + name="balance_label" + top_pad="5" + width="210"> + You now have + </text> + <text + type="string" + length="1" + font="SansSerifMedium" + follows="top|left" + halign="right" + height="16" + layout="topleft" + left="200" + name="balance_amount" + top_delta="0" + width="120"> L$ [AMT] - </text> - <text - type="string" - length="1" - follows="top|left" - font="SansSerifMedium" - height="16" - top="95" - layout="topleft" - left="20" - name="currency_action" - width="210"> - I want to buy - </text> - <text - font="SansSerifMedium" - type="string" - length="1" - follows="left|top" - height="16" - layout="topleft" - top_delta="0" - left="217" - name="currency_label" - width="15"> - L$ - </text> - <line_editor - type="string" - max_length_bytes="10" - halign="right" - font="SansSerifMedium" - select_on_focus="true" - follows="top|left" - top_delta="-7" - height="22" - label="L$" - left_pad="3" - name="currency_amt" - width="85"> - 1234 - </line_editor> - <text - type="string" - font="SansSerifMedium" - length="1" - follows="top|left" - height="16" - layout="topleft" - left="20" - top="125" - name="buying_label" - width="210"> - For the price - </text> - <text - type="string" - length="1" - font="SansSerifMedium" - text_color="EmphasisColor" - follows="top|left" - halign="right" - height="16" - top_delta="0" - layout="topleft" - left="150" - name="currency_est" - width="170"> - approx. [LOCALAMOUNT] - </text> - <text - type="string" - font="SansSerifSmall" - text_color="EmphasisColor" - length="1" - follows="top|left" - height="16" + </text> + </layout_panel> + <layout_panel + auto_resize="false" + name="layout_panel_required" layout="topleft" - top="125" - left="170" - width="150" - halign="right" - name="getting_data"> - Estimating... - </text> - <text - type="string" - font="SansSerifSmall" - top="145" - length="1" - follows="top|left" - height="16" - halign="right" - left="20" - width="300" - layout="topleft" - name="buy_action"> - [ACTION] - </text> - <text - type="string" - font="SansSerifMedium" - length="1" - follows="top|left" - height="16" - layout="topleft" - left="20" - name="total_label" - top="165" - width="210"> - My new balance will be - </text> - <text - type="string" - length="1" - font="SansSerifMedium" - follows="top|left" - top_delta="0" - height="16" - layout="topleft" - left="200" - halign="right" - name="total_amount" - width="120"> + follows="all" + width="350" + height="22"> + <text + type="string" + length="1" + follows="top|left" + font="SansSerifMedium" + font.style="BOLD" + height="16" + layout="topleft" + left="20" + name="required_label" + top_pad="6" + width="210"> + You should buy at least + </text> + <text + type="string" + length="1" + font="SansSerifMedium" + follows="top|left" + halign="right" + height="16" + layout="topleft" + left="200" + name="required_amount" + top_delta="0" + width="120"> L$ [AMT] - </text> - <text - type="string" - length="1" - text_color="LtGray_50" - follows="top|left" + </text> + </layout_panel> + <layout_panel + auto_resize="false" + name="layout_panel_action" layout="topleft" - halign="right" - top="189" - left="20" - width="300" - height="30" - name="currency_links"> - [http://www.secondlife.com/my/account/payment_method_management.php payment method] | [http://www.secondlife.com/my/account/currency.php currency] - </text> - <text - type="string" - length="1" - text_color="LtGray_50" - follows="top|left" + follows="all" + width="350" + height="90"> + <view_border + bevel_style="none" + height="0" + layout="topleft" + left="20" + name="text_border_2" + top_pad="5" + width="300"/> + <text + type="string" + length="1" + follows="top|left" + font="SansSerifMedium" + height="16" + top_pad="15" + layout="topleft" + left="20" + name="currency_action" + width="210"> + Choose amount to buy + </text> + <text + font="SansSerifMedium" + type="string" + length="1" + follows="left|top" + height="16" + layout="topleft" + top_delta="0" + left="247" + name="currency_label" + width="15"> + L$ + </text> + <line_editor + type="string" + max_length_bytes="10" + halign="right" + font="SansSerifMedium" + select_on_focus="true" + follows="top|left" + top_delta="-4" + height="22" + label="L$" + left_pad="3" + name="currency_amt" + width="55"> + 1234 + </line_editor> + <text + type="string" + length="1" + font="SansSerifMedium" + text_color="EmphasisColor" + follows="top|left" + halign="right" + height="16" + top_pad="4" + layout="topleft" + left="150" + name="currency_est" + width="170"> + Approx. [LOCALAMOUNT] + </text> + <text + type="string" + font="SansSerifSmall" + text_color="EmphasisColor" + length="1" + follows="top|left" + height="16" + layout="topleft" + left="170" + top_delta="0" + width="150" + halign="right" + name="getting_data"> + Estimating... + </text> + <text + type="string" + font="SansSerifMedium" + length="1" + follows="top|left" + height="16" + layout="topleft" + left="20" + name="total_label" + top_pad="10" + width="210"> + Your new balance will be + </text> + <text + type="string" + length="1" + font="SansSerifMedium" + follows="top|left" + top_delta="0" + height="16" + layout="topleft" + left="200" + halign="right" + name="total_amount" + width="120"> + L$ [AMT] + </text> + </layout_panel> + <layout_panel + auto_resize="false" + name="layout_panel_msg" layout="topleft" - halign="right" - top="202" - left="20" - width="300" - height="30" - name="exchange_rate_note"> + follows="all" + width="350" + height="50"> + <view_border + bevel_style="none" + height="0" + layout="topleft" + left="20" + name="text_border_3" + top_pad="0" + width="300"/> + <text + type="string" + length="1" + text_color="LtGray_50" + follows="top|left" + layout="topleft" + halign="right" + top_pad="3" + left="20" + width="300" + height="30" + name="currency_links"> + [http://www.secondlife.com/my/account/payment_method_management.php payment method] | [http://www.secondlife.com/my/account/currency.php currency] + </text> + <text + type="string" + length="1" + text_color="LtGray_50" + follows="top|left" + layout="topleft" + halign="right" + top="19" + left="20" + width="300" + height="30" + name="exchange_rate_note"> Re-enter amount to see the latest exchange rate. - </text> - <text - type="string" - length="1" - text_color="LtGray_50" - follows="top|left" - layout="topleft" - halign="right" - top="208" - left="10" - width="310" - height="35" - name="purchase_warning_repurchase"> - Confirming this purchase only buys L$, not the object. - </text> - <text - type="string" - length="1" - text_color="LtGray_50" - follows="top|left" - layout="topleft" - halign="right" - top="213" - left="20" - width="300" - height="30" - name="purchase_warning_notenough"> - You aren't buying enough L$. Please increase the amount. - </text> - - <button - follows="bottom|left" - height="20" - label="Buy Now" - layout="topleft" - left="151" - name="buy_btn" - top="242" - width="90"/> - <button - follows="bottom|right" - height="20" - label="Cancel" + </text> + <text + type="string" + length="1" + follows="top|left" + layout="topleft" + font="SansSerifMedium" + top="10" + left="20" + width="310" + height="35" + name="purchase_warning_repurchase"> +After you receive your L$, you should try your +purchase again. + </text> + </layout_panel> + <layout_panel + auto_resize="false" + name="layout_panel_buttons" layout="topleft" - left_pad="10" - name="cancel_btn" - width="90"/> - <icon - height="215" - image_name="Linden_Dollar_Alert" - layout="topleft" - left="0" - name="error_background" - top="15" - use_draw_context_alpha="false" - width="350"/> - <text - type="string" - font="SansSerifHuge" - left="165" - width="360" - height="25" - top="25" - name="info_cannot_buy"> - Unable to Buy - </text> - <text - type="string" - width="176" - height="125" - top="60" - left="165" - word_wrap="true" - follows="bottom|right" - name="cannot_buy_message"> - </text> - <button - follows="bottom|left" - height="20" - label="Continue to the Web" - layout="topleft" - left="170" - name="error_web" - top="200" - width="160"/> + follows="all" + width="350" + height="40"> + <text + type="string" + length="1" + follows="top|left" + height="16" + layout="topleft" + top_pad="0" + left="15" + width="300" + name="contacting"> + Contacting LindeX... + </text> + <button + follows="top|left|right" + height="20" + label="Buy L$ now" + layout="topleft" + left="151" + name="buy_btn" + bottom_delta ="8" + width="90"/> + <button + follows="top|left|right" + height="20" + label="Cancel" + layout="topleft" + left_pad="10" + name="cancel_btn" + width="90"/> + </layout_panel> + </layout_stack> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_buy_object.xml b/indra/newview/skins/default/xui/en/floater_buy_object.xml index 49be4290c7..1f7d52dbf5 100644 --- a/indra/newview/skins/default/xui/en/floater_buy_object.xml +++ b/indra/newview/skins/default/xui/en/floater_buy_object.xml @@ -32,6 +32,10 @@ name="no_transfer_text"> (no transfer) </floater.string> + <floater.string + name="mupliple_selected"> + Mupliple selection + </floater.string> <scroll_list background_visible="true" draw_border="false" diff --git a/indra/newview/skins/default/xui/en/floater_camera.xml b/indra/newview/skins/default/xui/en/floater_camera.xml index 72a7b5540c..9deb38e3af 100644 --- a/indra/newview/skins/default/xui/en/floater_camera.xml +++ b/indra/newview/skins/default/xui/en/floater_camera.xml @@ -7,7 +7,7 @@ legacy_header_height="18" can_minimize="true" can_close="true" - height="164" + height="135" layout="topleft" name="camera_floater" help_topic="camera_floater" @@ -16,7 +16,7 @@ title="CAMERA CONTROLS" chrome="true" save_rect="true" - width="228"> + width="400"> <floater.string name="rotate_tooltip"> Rotate Camera Around Focus @@ -33,6 +33,7 @@ name="free_mode_title"> View Object </floater.string> + <string name="inactive_combo_text">Use preset</string> <panel border="false" height="123" @@ -41,112 +42,18 @@ top="0" mouse_opaque="false" name="controls" - width="226"> - <panel - follows="all" - height="102" - layout="topleft" - left="8" - name="preset_views_list" - top="24" - width="212" - visible="false"> - <panel_camera_item - name="front_view"> - <panel_camera_item.mousedown_callback - function="CameraPresets.ChangeView" - parameter="front_view" /> - <panel_camera_item.picture - image_name="Cam_Preset_Front_Off" /> - <panel_camera_item.selected_picture - image_name="Cam_Preset_Front_On" /> - <panel_camera_item.text - name="front_view_text"> - Front View - </panel_camera_item.text> - </panel_camera_item> - <panel_camera_item - name="group_view" - top_pad="4"> - <panel_camera_item.mousedown_callback - function="CameraPresets.ChangeView" - parameter="group_view" /> - <panel_camera_item.picture - image_name="Cam_Preset_Side_Off" /> - <panel_camera_item.selected_picture - image_name="Cam_Preset_Side_On" /> - <panel_camera_item.text - name="side_view_text"> - Side View - </panel_camera_item.text> - </panel_camera_item> - <panel_camera_item - name="rear_view" - layout="topleft" - top_pad="4"> - <panel_camera_item.mousedown_callback - function="CameraPresets.ChangeView" - parameter="rear_view" /> - <panel_camera_item.picture - image_name="Cam_Preset_Back_Off" /> - <panel_camera_item.selected_picture - image_name="Cam_Preset_Back_On" /> - <panel_camera_item.text - name="rear_view_text"> - Rear View - </panel_camera_item.text> - </panel_camera_item> - </panel> - <panel - follows="all" - height="68" - layout="topleft" - left="8" - name="camera_modes_list" - top="24" - width="212" - visible="false"> - <panel_camera_item - name="object_view"> - <panel_camera_item.mousedown_callback - function="CameraPresets.ChangeView" - parameter="object_view" /> - <panel_camera_item.text - name="object_view_text"> - Object View - </panel_camera_item.text> - <panel_camera_item.picture - image_name="Object_View_Off" /> - <panel_camera_item.selected_picture - image_name="Object_View_On" /> - </panel_camera_item> - <panel_camera_item - name="mouselook_view" - layout="topleft"> - <panel_camera_item.mousedown_callback - function="CameraPresets.ChangeView" - parameter="mouselook_view" /> - <panel_camera_item.text - name="mouselook_view_text"> - Mouselook View - </panel_camera_item.text> - <panel_camera_item.picture - image_name="MouseLook_View_Off" /> - <panel_camera_item.selected_picture - image_name="MouseLook_View_On" /> - </panel_camera_item> - </panel> + width="220"> <!--TODO: replace + - images --> <panel border="false" class="camera_zoom_panel" - height="114" + height="123" layout="topleft" left="0" mouse_opaque="false" name="zoom" - top="20" - width="226"> + top="0" + width="220"> <joystick_rotate follows="top|left" height="78" @@ -157,8 +64,8 @@ sound_flags="3" visible="true" tool_tip="Orbit camera around focus" - top="20" - width="78" /> + top="25" + width="78" /> <button follows="top|left" height="18" @@ -169,7 +76,7 @@ left_pad="14" name="zoom_plus_btn" width="18" - top="18"> + top="23"> <commit_callback function="Zoom.plus" /> <mouse_held_callback @@ -214,56 +121,136 @@ scale_image="false" sound_flags="3" tool_tip="Move camera up and down, left and right" - top="20" + top="25" width="78"/> + <text + type="string" + length="1" + follows="left|top" + height="15" + layout="topleft" + left="41" + top_pad="9" + name="precise_ctrs_label" + width="200"> + Use precise controls + </text> </panel> </panel> <panel - border="false" - height="42" + follows="all" + height="102" layout="topleft" - left="2" - top_pad="0" - name="buttons" - width="226"> - <button - height="23" - label="" - layout="topleft" - left="70" - is_toggle="true" - image_overlay="Cam_Avatar_Off" - image_selected="PushButton_Selected_Press" - name="presets_btn" - tab_stop="false" - tool_tip="Preset Views" - top="13" - width="25"> - </button> - <button - height="23" - label="" - layout="topleft" - left_pad="1" - is_toggle="true" - image_overlay="PanOrbit_Off" - image_selected="PushButton_Selected_Press" - name="pan_btn" - tab_stop="false" - tool_tip="Orbit Zoom Pan" - width="25"> - </button> - <button - height="23" - label="" - layout="topleft" - left_pad="1" - image_overlay="Cam_FreeCam_Off" - image_selected="PushButton_Selected_Press" - name="avatarview_btn" - tab_stop="false" - tool_tip="Camera modes" - width="25"> - </button> - </panel> + left_pad="2" + name="buttons_panel" + top="22" + width="212"> + <panel_camera_item + name="front_view" + tool_tip="Front View" + width="30"> + <panel_camera_item.mousedown_callback + function="CameraPresets.ChangeView" + parameter="Front View" /> + <panel_camera_item.picture + image_name="Cam_Preset_Front_Off" /> + <panel_camera_item.selected_picture + image_name="Cam_Preset_Front_On" /> + </panel_camera_item> + <panel_camera_item + name="group_view" + tool_tip="Side View" + width="30" + left_pad="4"> + <panel_camera_item.mousedown_callback + function="CameraPresets.ChangeView" + parameter="Side View" /> + <panel_camera_item.picture + image_name="Cam_Preset_Side_Off" /> + <panel_camera_item.selected_picture + image_name="Cam_Preset_Side_On" /> + </panel_camera_item> + <panel_camera_item + name="rear_view" + tool_tip="Rear View" + width="30" + left_pad="4"> + <panel_camera_item.mousedown_callback + function="CameraPresets.ChangeView" + tool_tip="Rear View" + parameter="Rear View" /> + <panel_camera_item.picture + image_name="Cam_Preset_Back_Off" /> + <panel_camera_item.selected_picture + image_name="Cam_Preset_Back_On" /> + </panel_camera_item> + <panel_camera_item + name="object_view" + tool_tip="Object View" + width="30" + left_pad="4"> + <panel_camera_item.mousedown_callback + function="CameraPresets.ChangeView" + parameter="object_view" /> + <panel_camera_item.picture + image_name="Object_View_Off" /> + <panel_camera_item.selected_picture + image_name="Object_View_On" /> + </panel_camera_item> + <panel_camera_item + name="mouselook_view" + tool_tip="Mouselook View" + width="30" + left_pad="4"> + <panel_camera_item.mousedown_callback + function="CameraPresets.ChangeView" + parameter="mouselook_view" /> + <panel_camera_item.picture + image_name="MouseLook_View_Off" /> + <panel_camera_item.selected_picture + image_name="MouseLook_View_On" /> + </panel_camera_item> + <combo_box + height="23" + left="0" + mouse_opaque="true" + name="preset_combo" + top_pad="10" + width="136"> + <combo_list + mouse_wheel_opaque="true"/> + <combo_box.item + label="Use preset" + name="Use preset" + value="default" /> + </combo_box> + <button + height="16" + width="16" + layout="topleft" + mouse_opaque="true" + name="gear_btn" + tool_tip="My Camera Presets" + top_delta="3" + left_pad="10" + image_selected="Icon_Gear" + image_pressed="Icon_Gear" + image_unselected="Icon_Gear" + is_toggle="true"> + <button.commit_callback + function="CameraPresets.ShowPresetsList"/> + </button> + <button + follows="top|left" + height="25" + label="Save as preset..." + layout="topleft" + left="0" + name="save_preset_btn" + top_pad="18" + width="150"> + <button.commit_callback + function="CameraPresets.Save"/> + </button> + </panel> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_camera_presets.xml b/indra/newview/skins/default/xui/en/floater_camera_presets.xml new file mode 100644 index 0000000000..930357f568 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_camera_presets.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + can_resize="true" + height="200" + min_height="150" + title="MY CAMERA PRESETS" + layout="topleft" + name="floater_camera_presets" + single_instance="true" + min_width="185" + width="250"> + <flat_list_view + allow_select="true" + follows="all" + height="165" + layout="topleft" + left="3" + multi_select="false" + name="preset_list" + top="20" + width="245" /> + </floater> diff --git a/indra/newview/skins/default/xui/en/floater_create_landmark.xml b/indra/newview/skins/default/xui/en/floater_create_landmark.xml new file mode 100644 index 0000000000..bba30626b2 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_create_landmark.xml @@ -0,0 +1,113 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + can_resize="false" + show_title="false" + can_minimize="false" + can_close="false" + header_height="10" + bg_opaque_image="Window_NoTitle_Foreground" + bg_alpha_image="Window_NoTitle_Background" + height="305" + layout="topleft" + name="create_landmark" + width="330"> + <string name="favorites_bar"> + Favorites bar + </string> + <text + follows="left|top" + height="15" + layout="topleft" + left="20" + name="title_label" + top="5" + font="SansSerifLargeBold" + value="Landmark added" + width="290" /> + <text + follows="left|top" + height="15" + layout="topleft" + left="20" + name="name_label" + top_pad="10" + value="Name" + width="290" /> + <line_editor + follows="left|top" + height="22" + layout="topleft" + max_length_bytes="63" + name="title_editor" + prevalidate_callback="ascii" + text_readonly_color="white" + top_pad="5" + width="290" /> + <text + follows="left|top" + height="15" + layout="topleft" + name="folder_label" + top_pad="10" + value="Save this landmark in:" + width="290" /> + <combo_box + follows="bottom|left" + height="23" + layout="topleft" + name="folder_combo" + top_pad="2" + width="290" /> + <text + follows="left|top" + layout="topleft" + top_pad="6" + left="20" + name="new_folder_textbox" + height="20" + parse_urls="true" + skip_link_underline="true" + wrap="true"> + [secondlife:/// Create new folder] + </text> + <text + follows="left|top" + height="15" + layout="topleft" + name="notes_label" + top_pad="10" + value="My notes" + width="290" /> + <text_editor + bg_readonly_color="DkGray0" + follows="all" + height="75" + layout="topleft" + max_length="127" + name="notes_editor" + spellcheck="true" + text_readonly_color="white" + text_type="ascii_with_newline" + top_pad="5" + width="290" + wrap="true" /> + <button + follows="bottom|left|right" + height="23" + label="OK" + layout="topleft" + mouse_opaque="false" + name="ok_btn" + top_pad="10" + left="19" + width="140" /> + <button + follows="bottom|left|right" + height="23" + label="Cancel" + layout="topleft" + left_pad="12" + mouse_opaque="false" + name="cancel_btn" + width="140" /> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_delete_env_preset.xml b/indra/newview/skins/default/xui/en/floater_delete_env_preset.xml deleted file mode 100644 index b5de4166f6..0000000000 --- a/indra/newview/skins/default/xui/en/floater_delete_env_preset.xml +++ /dev/null @@ -1,59 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<floater - legacy_header_height="18" - height="130" - help_topic="" - layout="topleft" - name="Delete Env Preset" - save_rect="true" - title="DELETE ENV PRESET" - width="550"> - - <string name="title_water">Delete Water Preset</string> - <string name="title_sky">Delete Sky Preset</string> - <string name="title_day_cycle">Delete Day Cycle</string> - - <string name="label_water">Preset:</string> - <string name="label_sky">Preset:</string> - <string name="label_day_cycle">Day cycle:</string> - - <string name="msg_confirm_deletion">Are you sure you want to delete the selected preset?</string> - <string name="msg_sky_is_referenced">Cannot remove a preset that is referenced by some day cycle(s).</string> - - <string name="combo_label">-Select a preset-</string> - - <text - follows="top|left|right" - font="SansSerif" - height="10" - layout="topleft" - left="50" - name="label" - top="60" - width="60"> - Preset: - </text> - <combo_box - follows="top|left" - layout="topleft" - left_pad="10" - name="preset_combo" - top_delta="-5" - width="200"/> - <button - follows="bottom|right" - height="23" - label="Delete" - layout="topleft" - left_pad="15" - name="delete" - width="70"/> - <button - follows="bottom|right" - height="23" - label="Cancel" - layout="topleft" - left_pad="5" - name="cancel" - width="70"/> -</floater> diff --git a/indra/newview/skins/default/xui/en/floater_delete_pref_preset.xml b/indra/newview/skins/default/xui/en/floater_delete_pref_preset.xml index 0688fdb42c..3360d7bec9 100644 --- a/indra/newview/skins/default/xui/en/floater_delete_pref_preset.xml +++ b/indra/newview/skins/default/xui/en/floater_delete_pref_preset.xml @@ -4,7 +4,7 @@ height="130" help_topic="floater_delete_preset" layout="topleft" - name="Delete Pref Preset" + name="delete_pref_preset" save_rect="true" title="DELETE PREF PRESET" width="300"> diff --git a/indra/newview/skins/default/xui/en/floater_edit_day_cycle.xml b/indra/newview/skins/default/xui/en/floater_edit_day_cycle.xml deleted file mode 100644 index d9a3ad0c4b..0000000000 --- a/indra/newview/skins/default/xui/en/floater_edit_day_cycle.xml +++ /dev/null @@ -1,485 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater - legacy_header_height="18" - height="381" - layout="topleft" - name="Edit Day cycle" - help_topic="day_presets" - save_rect="true" - title="Edit Day Cycle" - width="705"> - - <string name="title_new">Create a New Day Cycle</string> - <string name="title_edit">Edit Day Cycle</string> - <string name="hint_new">Name your day cycle, adjust the controls to create it, and click "Save".</string> - <string name="hint_edit">To edit your day cycle, adjust the controls below and click "Save".</string> - <string name="combo_label">-Select a preset-</string> - - <text - follows="top|left|right" - height="10" - layout="topleft" - left="10" - name="hint" - top="25" - width="685" /> - <text - follows="top|left|right" - font="SansSerif" - height="10" - layout="topleft" - left="10" - name="label" - top_pad="25" - width="120"> - Preset Name: - </text> - <combo_box - allow_text_entry="true" - follows="top|left" - layout="topleft" - left_pad="10" - max_chars="100" - name="day_cycle_combo" - top_delta="-5" - width="200" /> - <line_editor - height="20" - left_delta="0" - name="day_cycle_name" - top_delta="0" - visible="true" - width="200" /> - <text - follows="top|left|right" - height="95" - layout="topleft" - left_pad="10" - name="note" - top_delta="0" - width="345" - wrap="true"> - Note: if you change the name of your preset, you will be creating a new preset and the existing preset will not be changed. - </text> - <!--======== Controls panel ========--> - <text - follows="left|top|right" - height="10" - layout="topleft" - left="10" - name="hint_item1" - top="100" - width="300"> - - Click on a tab to edit the specific sky settings and time. - </text> - <text - follows="left|top|right" - height="10" - layout="topleft" - name="hint_item2" - top_pad="10" - width="300"> - - Click and drag the tabs to set the transition times. - </text> - <text - follows="left|top|right" - height="10" - layout="topleft" - name="hint_item3" - top_pad="10" - width="300"> - - Use the scrubber to preview your day cycle. - </text> - <panel - follows="top|left" - height="100" - name="day_cycle_slider_panel" - layout="topleft" - left_delta="25" - top_pad="15" - width="660"> - <multi_slider - can_edit_text="true" - control_name="WLTimeSlider" - decimal_digits="0" - draw_track="false" - follows="bottom" - height="10" - increment="0.0833333" - initial_value="0" - layout="topleft" - left="20" - max_sliders="20" - max_val="24" - name="WLTimeSlider" - show_text="false" - top_pad="0" - use_triangle="true" - width="525" /> - <multi_slider - can_edit_text="true" - control_name="WLDayCycleKeys" - decimal_digits="0" - follows="bottom" - height="10" - increment="0.0833333" - initial_value="0" - layout="topleft" - left_delta="0" - max_sliders="20" - max_val="24" - name="WLDayCycleKeys" - show_text="false" - top_pad="15" - width="525" /> - <button - height="20" - label="Add Key" - label_selected="Add Key" - layout="topleft" - left_pad="20" - name="WLAddKey" - top_delta="-18" - width="96" /> - <button - height="20" - label="Delete Key" - label_selected="Delete Key" - layout="topleft" - name="WLDeleteKey" - top_pad="5" - width="96" /> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - height="16" - layout="topleft" - left="8" - name="WL12am" - top="74" - width="55"> - 12am - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - height="16" - layout="topleft" - left_pad="10" - name="WL3am" - top_delta="0" - width="55"> - 3am - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - height="16" - layout="topleft" - left_pad="10" - name="WL6am" - top_delta="0" - width="55"> - 6am - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - height="16" - layout="topleft" - left_pad="10" - name="WL9amHash" - top_delta="0" - width="55"> - 9am - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - height="16" - layout="topleft" - left_pad="10" - name="WL12pmHash" - top_delta="0" - width="55"> - 12pm - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - height="16" - layout="topleft" - left_pad="10" - name="WL3pm" - top_delta="0" - width="55"> - 3pm - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - height="16" - layout="topleft" - left_pad="10" - name="WL6pm" - top_delta="0" - width="55"> - 6pm - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - height="16" - layout="topleft" - left_pad="10" - name="WL9pm" - top_delta="0" - width="55"> - 9pm - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - height="16" - layout="topleft" - left_pad="10" - name="WL12am2" - top_delta="0" - width="55"> - 12am - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - font="SansSerif" - height="14" - layout="topleft" - left="20" - name="WL12amHash" - top="54" - width="6"> - | - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - font="SansSerif" - height="11" - layout="topleft" - left_pad="59" - name="WL3amHash" - top_delta="3" - width="6"> - I - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - font="SansSerif" - height="14" - layout="topleft" - left_pad="59" - name="WL6amHash" - top_delta="-3" - width="6"> - | - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - font="SansSerif" - height="11" - layout="topleft" - left_pad="59" - name="WL9amHash2" - top_delta="3" - width="6"> - I - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - font="SansSerif" - height="14" - layout="topleft" - left_pad="59" - name="WL12pmHash2" - top_delta="-3" - width="6"> - | - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - font="SansSerif" - height="11" - layout="topleft" - left_pad="59" - name="WL3pmHash" - top_delta="3" - width="6"> - I - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - font="SansSerif" - height="14" - layout="topleft" - left_pad="59" - name="WL6pmHash" - top_delta="-3" - width="6"> - | - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - font="SansSerif" - height="11" - layout="topleft" - left_pad="59" - name="WL9pmHash" - top_delta="3" - width="6"> - I - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - font="SansSerif" - height="14" - layout="topleft" - left_pad="59" - name="WL12amHash2" - top_delta="-3" - width="6"> - | - </text> - </panel> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - font="SansSerif" - height="16" - layout="topleft" - left_delta="192" - name="WLCurKeyPresetText" - top_pad="10" - width="80"> - Sky Setting: - </text> - <combo_box - height="18" - label="Preset" - layout="topleft" - left_pad="5" - name="WLSkyPresets" - width="205" /> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-40" - name="WLCurKeyTimeText" - top_pad="15" - width="35"> - Time: - </text> - <time - follows="left|top" - height="16" - label_width="0" - layout="topleft" - left_pad="3" - name="time" - top_delta="-1" - value="6:00 AM" - width="75"/> - <view_border - bevel_style="none" - follows="top|left" - height="0" - layout="topleft" - left="10" - name="horiz_separator" - top_pad="20" - width="685"/> - <loading_indicator - height="23" - layout="topleft" - left="25" - name="progress_indicator" - top="350" - visible="false" - width="23" /> - <check_box - follows="top|left" - height="10" - label="Make this my new day cycle" - layout="topleft" - left="310" - name="make_default_cb" - top_delta="13" - width="230"/> - <button - follows="bottom|right" - height="23" - label="Save" - layout="topleft" - left_pad="0" - name="save" - top_delta="-13" - width="70"/> - <button - follows="bottom|right" - height="23" - label="Cancel" - layout="topleft" - left_pad="15" - name="cancel" - top_delta="0" - width="70"/> - </floater> diff --git a/indra/newview/skins/default/xui/en/floater_edit_ext_day_cycle.xml b/indra/newview/skins/default/xui/en/floater_edit_ext_day_cycle.xml new file mode 100644 index 0000000000..c609e3bd3a --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_edit_ext_day_cycle.xml @@ -0,0 +1,651 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + layout="topleft" + name="env_edit_extdaycycle" + help_topic="day_presets" + save_rect="false" + title="Edit Day Cycle" + width="705" + height="700" + min_width="705" + min_height="700" + single_instance="true" + can_resize="false"> + + <!-- obsolete?, add as hint for 'save' button? --> + <string name="title_new">Create a New Day Cycle</string> + <string name="title_edit">Edit Day Cycle</string> + <string name="hint_new">Name your day cycle, adjust the controls to create it, and click "Save".</string> + <string name="hint_edit">To edit your day cycle, adjust the controls below and click "Save".</string> + + <!-- Substitutions --> + <string name="time_label">([HH]:[MM])</string> + <string name="sky_track_label">Sky [ALT]</string> + <string name="sky_label">Sky</string> + <string name="water_label">Water</string> + + <string name="commit_parcel">Apply To Parcel</string> + <string name="commit_region">Apply To Region</string> + + <!-- Layout --> + <layout_stack name="outer_stack" + width="705" + height="700" + follows="all" + animate="false" + top="0" + orientation="vertical"> + <layout_panel name="name_and_import" + border="false" + auto_resize="false" + user_resize="false" + height="29" + min_height="29" + background_visible="false"> + <!-- This layout_panel is for loading legacy presets --> + <text + follows="top|left" + font="SansSerif" + height="10" + layout="topleft" + name="label" + left="15" + top="5" + width="105"> + Day Cycle Name: + </text> + <line_editor + follows="top|left" + layout="topleft" + left_pad="10" + max_length_bytes="100" + name="day_cycle_name" + prevalidate_callback="ascii" + top="5" + width="200" + height="21" /> + <button + height="23" + label="Import" + follows="right|top" + right="-10" + font="SansSerif" + top_delta="0" + name="btn_import" + tool_tip="Import legacy settings from disk." + width="96" /> + </layout_panel> + <layout_panel name="content" + border="false" + auto_resize="true" + user_resize="false" + background_visible="false"> + <layout_stack name="content_stack" + width="705" + follows="all" + animate="false" + top="0" + orientation="vertical"> + <layout_panel name="timeline_track_selection" + border="false" + bevel_style="in" + auto_resize="false" + user_resize="false" + height="150" + min_height="0" + visible="true"> + <panel name="timeline_layers" + border="false" + follows="left|top" + height="150" + width="110" + top_pad="0" + min_height="0" + visible="true"> + <button + follows="left|top" + height="23" + label="Sky 4" + layout="topleft" + top_pad="5" + left="10" + name="sky4_track" + width="100"> + <button.commit_callback + function="DayCycle.Track" + parameter="4" /> + </button> + <button + follows="left|top" + height="23" + label="Sky 3" + layout="topleft" + top_pad="0" + left="10" + name="sky3_track" + width="100"> + <button.commit_callback + function="DayCycle.Track" + parameter="3" /> + </button> + <button + follows="left|top" + height="23" + label="Sky 2" + layout="topleft" + top_pad="0" + left="10" + name="sky2_track" + width="100"> + <button.commit_callback + function="DayCycle.Track" + parameter="2" /> + </button> + <button + follows="left|top" + height="23" + label="Ground Level" + layout="topleft" + top_pad="0" + left="10" + name="sky1_track" + width="100"> + <button.commit_callback + function="DayCycle.Track" + parameter="1" /> + </button> + <button + follows="left|top" + height="23" + label="Water" + layout="topleft" + top_pad="0" + left="10" + name="water_track" + width="100"> + <button.commit_callback + function="DayCycle.Track" + parameter="0" /> + </button> + </panel> + <panel name="timeline" + border="true" + follows="left|top" + height="150" + min_height="0" + width="595" + min_width="595" + left_pad="0" + visible="true"> + <!-- Todo: These 5 tests might be subjected to a change to be dynamically generated, consider using layout_stack to get dynamic width adjustment--> + <text + follows="left|top" + height="15" + layout="topleft" + left="10" + name="p0" + top_pad="5" + value="0% [DSC]" + width="90" /> + <text + follows="left|top|right" + height="15" + layout="topleft" + left_delta="117" + name="p1" + top_delta="0" + value="25% [DSC]" + width="90" /> + <text + follows="left|top|right" + height="15" + layout="topleft" + left_delta="122" + name="p2" + top_delta="0" + value="50% [DSC]" + width="90" /> + <text + follows="left|top|right" + height="15" + layout="topleft" + left_delta="122" + name="p3" + top_delta="0" + value="75% [DSC]" + width="90" /> + <text + follows="left|top|right" + height="15" + layout="topleft" + left_delta="122" + name="p4" + top_delta="0" + value="100% [DSC]" + width="90" /> + <multi_slider + decimal_digits="0" + draw_track="false" + follows="bottom" + height="10" + increment="0.005" + overlap_threshold="0.026" + initial_value="0" + layout="topleft" + left="10" + max_sliders="1" + max_val="1" + name="WLTimeSlider" + show_text="false" + top_pad="0" + use_triangle="true" + width="525" /> + + <multi_slider + decimal_digits="0" + follows="bottom" + height="10" + increment="0.005" + overlap_threshold="0.026" + loop_overlap="true" + initial_value="0" + layout="topleft" + left="10" + max_sliders="20" + max_val="1" + name="WLDayCycleFrames" + show_text="false" + top_pad="15" + width="525" /> + + <text + follows="left|bottom" + height="25" + layout="topleft" + left_pad="0" + name="current_time" + value="[PRCNT]% [DSC]" + top_delta="-5" + width="56" + word_wrap="true"/> + + <layout_stack + follows="all" + height="200" + animate="false" + top_pad="0" + left="0" + orientation="horizontal"> + <layout_panel + border="false" + bevel_style="in" + auto_resize="false" + user_resize="false" + height="150" + width="200" + min_height="0" + visible="true"> + <button + follows="top|left" + height="23" + width="110" + label="Clone Track From" + left="10" + top_pad="10" + name="copy_track" /> + <button + follows="top|left" + height="23" + width="110" + label="Load Track From" + top_pad="0" + left_delta="0" + name="load_track" /> + <button + follows="top|left" + height="23" + width="110" + label="Clear Track" + top_pad="0" + left_delta="0" + name="clear_track" /> + + </layout_panel> + <layout_panel + border="false" + bevel_style="in" + auto_resize="false" + user_resize="false" + height="150" + width="200" + min_height="0" + visible="true"> + <layout_stack + name="progress_control" + follows="top|left" + height="25" + width="83" + layout="topleft" + animate="false" + left="31" + top="40" + orientation="horizontal"> + + <layout_panel + name="skip_back" + mouse_opaque="false" + auto_resize="false" + layout="topleft" + top="0" + height="25" + min_width="25" + width="25"> + <button + name="skip_back_btn" + follows="top" + image_overlay="SkipBackward_Off" + image_disabled="PushButton_Disabled" + image_disabled_selected="PushButton_Disabled" + image_selected="PushButton_Selected" + image_unselected="PushButton_Off" + hover_glow_amount="0.15" + auto_resize="false" + width="25" + height="25" + layout="topleft" + tool_tip="Step back" + top="0" + left="0"> + <button.commit_callback + function="DayCycle.PlayActions" + parameter="back" /> + </button> + </layout_panel> + + <layout_panel + name="play_layout" + mouse_opaque="false" + auto_resize="false" + layout="topleft" + top="0" + height="25" + min_width="25" + width="25"> + <button + name="play_btn" + follows="top" + image_overlay="Play_Off" + image_disabled="PushButton_Disabled" + image_disabled_selected="PushButton_Disabled" + image_selected="PushButton_Selected" + image_unselected="PushButton_Off" + hover_glow_amount="0.15" + auto_resize="false" + layout="topleft" + height="25" + width="25" + left="0" + top="0"> + <button.commit_callback + function="DayCycle.PlayActions" + parameter="play" /> + </button> + </layout_panel> + + <layout_panel + name="pause_layout" + mouse_opaque="false" + auto_resize="false" + layout="topleft" + top="0" + height="25" + min_width="25" + width="25" + visible="false"> + <button + name="pause_btn" + follows="top" + image_overlay="Pause_Off" + image_disabled="PushButton_Disabled" + image_disabled_selected="PushButton_Disabled" + image_selected="PushButton_Selected" + image_unselected="PushButton_Off" + hover_glow_amount="0.15" + auto_resize="false" + layout="topleft" + height="25" + width="25" + left="0" + top="0"> + <button.commit_callback + function="DayCycle.PlayActions" + parameter="pause" /> + </button> + </layout_panel> + + <layout_panel + name="skip_forward" + mouse_opaque="false" + auto_resize="false" + layout="topleft" + top="0" + height="25" + min_width="25" + width="25"> + <button + name="skip_forward_btn" + follows="top" + image_overlay="SkipForward_Off" + image_disabled="PushButton_Disabled" + image_disabled_selected="PushButton_Disabled" + image_selected="PushButton_Selected" + image_unselected="PushButton_Off" + hover_glow_amount="0.15" + width="25" + height="25" + layout="topleft" + tool_tip="Step forward" + top="0"> + <button.commit_callback + function="DayCycle.PlayActions" + parameter="forward" /> + </button> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel + border="false" + bevel_style="in" + auto_resize="false" + user_resize="false" + width="190" + height="150" + min_height="0" + visible="true"> + <button + + follows="top|right" + height="23" + width="90" + right="-10" + top_pad="10" + label="Add [FRAME]" + name="add_frame" /> + <button + follows="top|left" + height="23" + width="90" + label="Load [FRAME]" + top_pad="0" + left_delta="0" + name="btn_load_frame" /> + <button + follows="left|top" + height="23" + width="90" + label="Delete [FRAME]" + top_pad="0" + left_delta="0" + name="delete_frame" /> + </layout_panel> + </layout_stack> + </panel> + </layout_panel> + <layout_panel name="frame_edit_controls" + auto_resize="false" + user_resize="false" + height="30" + width="700" + min_height="30" + visible="true"> + <!--bg_alpha_color="blue" + background_visible="true" --> + <text + name="icn_lock_edit" + follows="bottom" + height="10" + layout="bottomleft" + left_delta="15" + top_pad="15" + font="SansSerif" + text_color="Yellow" + width="500"> + Select a key frame from the timeline above to edit settings. + </text> + </layout_panel> + <layout_panel name="frame_settings_water" + auto_resize="true" + user_resize="false" + height="420" + width="700" + min_height="0" + visible="false"> + <tab_container + follows="all" + halign="left" + height="420" + layout="topleft" + left="0" + name="water_tabs" + tab_position="top" + tab_width="140" + tab_padding_right="3" + top_pad="0" + width="700"> + <panel + border="true" + class="panel_settings_water" + filename="panel_settings_water.xml" + label="Water" + layout="topleft" + left_delta="0" + top_pad="5" + name="water_panel"/> + </tab_container> + </layout_panel> + <layout_panel name="frame_settings_sky" + auto_resize="true" + user_resize="false" + height="420" + width="700" + min_height="0" + visible="true"> + <tab_container + follows="all" + halign="left" + height="420" + visible="true" + layout="topleft" + left="0" + name="sky_tabs" + tab_position="top" + tab_width="140" + tab_padding_right="3" + top_pad="0" + width="700"> + <panel + border="true" + class="panel_settings_atmos" + filename="panel_settings_sky_atmos.xml" + label="Atmosphere & Lighting" + layout="topleft" + left_delta="0" + top_pad="5" + name="atmosphere_panel" /> + <panel + border="true" + class="panel_settings_cloud" + filename="panel_settings_sky_clouds.xml" + label="Clouds" + layout="topleft" + left_delta="0" + top_pad="5" + name="clouds_panel" /> + <panel + border="true" + class="panel_settings_sunmoon" + filename="panel_settings_sky_sunmoon.xml" + label="Sun & Moon" + layout="topleft" + left_delta="0" + top_pad="5" + name="moon_panel" /> + <!-- added programatically so it doesn't show up whether we want it or not + <panel + border="true" + class="panel_settings_density" + filename="panel_settings_sky_density.xml" + label="Density" + layout="topleft" + left_delta="0" + top_pad="5" + name="density_panel" /> + --> + </tab_container> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel name="buttons" + auto_resize="false" + user_resize="false" + height="26" + min_height="26" + visible="true" + width="700"> + <button + follows="top|left" + height="23" + label="Save" + left="200" + top_pad="0" + name="save_btn" + width="156" /> + + <button + follows="top|left" + height="23" + name="btn_flyout" + label="" + layout="topleft" + left_pad="-20" + top="0" + image_selected="SegmentedBtn_Right_Selected_Press" + image_unselected="SegmentedBtn_Right_Off" + image_pressed="SegmentedBtn_Right_Press" + image_pressed_selected="SegmentedBtn_Right_Selected_Press" + image_overlay="Arrow_Small_Up" + width="20"/> + + <button + follows="top|left" + height="23" + label="Cancel" + layout="topleft" + left_pad="10" + name="cancel_btn" + width="150" /> + + </layout_panel> + </layout_stack> + +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_edit_hover_height.xml b/indra/newview/skins/default/xui/en/floater_edit_hover_height.xml index 52084e5f8e..3570456b44 100644 --- a/indra/newview/skins/default/xui/en/floater_edit_hover_height.xml +++ b/indra/newview/skins/default/xui/en/floater_edit_hover_height.xml @@ -4,18 +4,16 @@ legacy_header_height="225" can_minimize="true" can_close="true" - can_resize="true" - min_height="65" - min_width="515" - height="65" + can_resize="false" + height="80" + width="515" layout="topleft" name="HoverHeight" single_instance="true" help_topic="hover_height" save_rect="true" save_visibility="true" - title="SET HOVER HEIGHT" - width="515"> + title="SET HOVER HEIGHT"> <slider enabled="false" control_name="HoverHeightSlider" @@ -34,4 +32,13 @@ can_edit_text="true" > </slider> + <check_box + control_name="HoverHeightAffectsCamera" + follows="all" + height="15" + label="Bind Camera view" + layout="topleft" + name="BindCameraCheck" + top_pad="7" + width="237"/> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_edit_sky_preset.xml b/indra/newview/skins/default/xui/en/floater_edit_sky_preset.xml deleted file mode 100644 index 56233d91ee..0000000000 --- a/indra/newview/skins/default/xui/en/floater_edit_sky_preset.xml +++ /dev/null @@ -1,953 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater - legacy_header_height="18" - height="375" - layout="topleft" - name="Edit Sky Preset" - help_topic="sky_preset" - save_rect="true" - title="Edit Sky Preset" - width="840"> - - <string name="title_new">Create a New Sky Preset</string> - <string name="title_edit">Edit Sky Preset</string> - <string name="hint_new">Name your preset, adjust the controls to create it, and click "Save".</string> - <string name="hint_edit">To edit your sky preset, adjust the controls and click "Save".</string> - <string name="combo_label">-Select a preset-</string> - - <text - follows="top|left|right" - height="10" - layout="topleft" - left="30" - name="hint" - top="25" - width="700"> - To edit your preset, adjust the controls then click "Save" - </text> - <text - follows="top|left|right" - font="SansSerif" - height="10" - layout="topleft" - left="30" - name="label" - top_pad="25" - width="120"> - Preset Name: - </text> - <combo_box - allow_text_entry="true" - follows="top|left" - layout="topleft" - left_pad="10" - max_chars="100" - name="sky_preset_combo" - top_delta="-5" - width="200"/> - <line_editor - height="20" - left_delta="0" - name="sky_preset_name" - top_delta="0" - width="200" /> - <text - follows="top|left|right" - height="40" - layout="topleft" - left_pad="10" - name="note" - top_delta="0" - width="405" - wrap="true"> - Note: if you change the name of your preset, you will be creating a new preset and the existing preset will not be changed. - </text> - <!--======== Controls panel ========--> - <view_border - bevel_style="none" - follows="top|left" - height="203" - layout="topleft" - left="25" - name="panel_water_preset" - top="122" - visible="true" - width="790"/> - <tab_container - follows="left|top" - height="225" - halign="center" - layout="topleft" - left="22" - name="WindLight Tabs" - tab_position="top" - top="101" - width="794"> - <panel - border="true" - bevel_style="none" - follows="left|top|right|bottom" - height="196" - label="ATMOSPHERE" - layout="topleft" - left="1" - help_topic="sky_preset_atmosphere" - mouse_opaque="false" - name="Atmosphere" - top="60" - width="698"> - - <!--======== Tab Panel I. I conlumn of controls ========--> - - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left="40" - name="BHText" - top="25" - width="200"> - Blue Horizon - </text> - <color_swatch - can_apply_immediately="true" - follows="left|top" - height="37" - label_height="0" - layout="topleft" - left_delta="0" - name="WLBlueHorizon" - top_pad="6" - width="60" /> - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_delta="0" - top_pad="20" - name="BDensText" - width="200"> - Haze Horizon - </text> - <slider - control_name="WLHazeHorizon" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="0.25" - layout="topleft" - left_delta="0" - top_pad="6" - name="WLHazeHorizon" - width="200" /> - - <!--======== Tab Panel I. II conlumn of controls ========--> - - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_pad="55" - name="BDensText2" - top="25" - width="200"> - Blue Density - </text> - <color_swatch - can_apply_immediately="true" - follows="left|top" - height="37" - label_height="0" - layout="topleft" - left_delta="0" - name="WLBlueDensity" - top_pad="6" - width="60" /> - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_delta="0" - name="HDText" - top_pad="20" - width="200"> - Haze Density - </text> - <slider - control_name="WLHazeDensity" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="0.7" - layout="topleft" - left_delta="0" - max_val="4" - name="WLHazeDensity" - top_pad="6" - width="200" /> - - <!--======== Tab Panel I. III conlumn of controls ========--> - - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_pad="55" - name="DensMultText" - top="25" - width="200"> - Density Multiplier - </text> - <slider - control_name="WLDensityMult" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="0.1" - layout="topleft" - left_delta="15" - max_val="0.9" - name="WLDensityMult" - top_pad="6" - width="200" /> - - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-15" - name="WLDistanceMultText" - top_pad="20" - width="200"> - Distance Multiplier - </text> - <slider - control_name="WLDistancMult" - decimal_digits="1" - follows="left|top" - height="10" - initial_value="1.0" - layout="topleft" - left_delta="15" - max_val="100" - name="WLDistanceMult" - top_pad="6" - width="200" /> - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-15" - name="MaxAltText" - top_pad="20" - width="200"> - Max Altitude - </text> - <slider - control_name="WLMaxAltitude" - decimal_digits="0" - follows="left|top" - height="10" - increment="1" - initial_value="500" - layout="topleft" - left_delta="15" - max_val="4000" - name="WLMaxAltitude" - top_pad="6" - width="200" /> - </panel> - <panel - border="true" - bevel_style="none" - follows="left|top|right|bottom" - height="196" - label="LIGHTING" - layout="topleft" - left_delta="0" - help_topic="sky_preset_lighting" - name="Lighting" - top_delta="4" - width="698"> - - <!--======== Tab Panel II. I conlumn of controls ========--> - - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left="20" - name="SLCText" - top="25" - width="150"> - Sun/Moon Color - </text> - <color_swatch - can_apply_immediately="true" - follows="left|top" - height="37" - label_height="0" - layout="topleft" - left_delta="10" - name="WLSunlight" - top_pad="6" - width="60" /> - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-10" - name="WLAmbientText" - top_pad="20" - width="150"> - Ambient - </text> - <color_swatch - can_apply_immediately="true" - follows="left|top" - height="37" - label_height="0" - layout="topleft" - left_delta="10" - name="WLAmbient" - top_pad="6" - width="60" /> - - <!--======== Tab Panel II. II conlumn of controls ========--> - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_pad="100" - name="SunGlowText" - top="25" - width="200"> - Sun Glow - </text> - <slider - control_name="WLGlowB" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="0.1" - label="Focus " - layout="topleft" - left_delta="10" - max_val="0.5" - name="WLGlowB" - top_pad="6" - width="200" /> - <slider - control_name="WLGlowR" - decimal_digits="2" - follows="top|left" - height="10" - increment="0.01" - initial_value="0.25" - label="Size " - layout="topleft" - left_delta="0" - max_val="1.99" - min_val="1" - name="WLGlowR" - top_pad="6" - width="200" /> - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-10" - name="WLStarText" - top_pad="20" - width="200"> - Star Brightness - </text> - <slider - control_name="WLStarAlpha" - decimal_digits="2" - follows="top|left" - height="10" - increment="0.01" - initial_value="0" - layout="topleft" - left_delta="10" - max_val="2" - name="WLStarAlpha" - top_pad="6" - width="200" /> - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-10" - name="SceneGammaText" - top_pad="20" - width="200"> - Scene Gamma - </text> - <slider - control_name="WLGamma" - decimal_digits="2" - follows="top|left" - height="10" - increment="0.01" - initial_value="2.0" - layout="topleft" - left_delta="10" - max_val="10" - name="WLGamma" - top_pad="6" - width="200" /> - - <!--======== Tab Panel II. III conlumn of controls ========--> - - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_pad="60" - name="TODText" - top="25" - width="200"> - Sun/Moon Position - </text> - <multi_slider - can_edit_text="true" - control_name="WLSunPos" - decimal_digits="0" - follows="bottom" - height="10" - increment="0.0833333" - initial_value="0" - layout="topleft" - left_delta="0" - max_sliders="1" - max_val="24" - name="WLSunPos" - show_text="false" - top_pad="0" - width="300" /> - - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - font="SansSerif" - height="14" - layout="topleft" - left_delta="2" - name="WL12amHash" - top_pad="6" - width="6"> - | - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - font="SansSerif" - height="14" - layout="topleft" - left_pad="66" - name="WL6amHash" - top_delta="0" - width="6"> - | - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - font="SansSerif" - height="14" - layout="topleft" - left_pad="67" - name="WL12pmHash2" - top_delta="0" - width="6"> - | - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - font="SansSerif" - height="14" - layout="topleft" - left_pad="67" - name="WL6pmHash" - top_delta="0" - width="6"> - | - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - font="SansSerif" - height="14" - layout="topleft" - left_pad="67" - name="WL12amHash2" - top_delta="0" - width="6"> - | - </text> - - - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - height="16" - layout="topleft" - left_delta="-300" - name="WL12am" - top="74" - width="55"> - 12am - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - height="16" - layout="topleft" - left_pad="20" - name="WL6am" - top_delta="0" - width="55"> - 6am - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - height="16" - layout="topleft" - left_pad="15" - name="WL12pmHash" - top_delta="0" - width="55"> - 12pm - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - height="16" - layout="topleft" - left_pad="18" - name="WL6pm" - top_delta="0" - width="55"> - 6pm - </text> - <text - type="string" - length="1" - border_visible="true" - follows="left|top|right" - height="16" - layout="topleft" - left_pad="15" - name="WL12am2" - top_delta="0" - width="55"> - 12am - </text> - - <time - follows="left|top" - height="16" - label_width="0" - layout="topleft" - left_delta="-175" - name="WLDayTime" - top_pad="15" - value="6:00 AM" - width="75"/> - - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-106" - name="WLEastAngleText" - top_pad="24" - width="200"> - East Angle - </text> - <slider - control_name="WLEastAngle" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="0.0" - layout="topleft" - left_delta="10" - name="WLEastAngle" - top_pad="6" - width="200" /> - - </panel> - <panel - border="true" - bevel_style="none" - follows="left|top|right|bottom" - height="196" - label="CLOUDS" - layout="topleft" - left_delta="0" - mouse_opaque="false" - help_topic="sky_preset_clouds" - name="Clouds" - top_delta="4" - width="698"> - - <!--======== Tab Panel III. I conlumn of controls ========--> - - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left="40" - name="WLCloudColorText" - top="25" - width="200"> - Cloud Color - </text> - <color_swatch - can_apply_immediately="true" - follows="left|top" - height="37" - label_height="0" - layout="topleft" - left_delta="0" - name="WLCloudColor" - top_pad="6" - width="60" /> - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_delta="0" - name="WLCloudColorText2" - top_pad="20" - width="200"> - Cloud XY/Density - </text> - <slider - control_name="WLCloudX" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="0.5" - label="X" - layout="topleft" - left_delta="0" - top_pad="6" - name="WLCloudX" - width="200" /> - <slider - control_name="WLCloudY" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="0.5" - label="Y" - layout="topleft" - left_delta="0" - top_pad="6" - name="WLCloudY" - width="200" /> - <slider - control_name="WLCloudDensity" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="1.0" - label="D" - layout="topleft" - left_delta="0" - name="WLCloudDensity" - top_pad="6" - width="200" /> - - <!--======== Tab Panel III. II conlumn of controls ========--> - - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_pad="55" - name="WLCloudCoverageText" - top="15" - width="200"> - Cloud Coverage - </text> - <slider - control_name="WLCloudCoverage" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="0.5" - layout="topleft" - left_delta="15" - name="WLCloudCoverage" - top_pad="6" - width="200" /> - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-15" - name="WLCloudScaleText" - top_pad="20" - width="200"> - Cloud Scale - </text> - <slider - control_name="WLCloudScale" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="1.0" - layout="topleft" - left_delta="15" - min_val="0.01" - name="WLCloudScale" - top_pad="6" - width="200" /> - - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-13" - name="WLCloudDetailText" - top_pad="20" - width="200"> - Cloud Detail (XY/Density) - </text> - <slider - control_name="WLCloudDetailX" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="0.5" - label="X" - layout="topleft" - left_delta="0" - top_pad="6" - name="WLCloudDetailX" - width="200" /> - <slider - control_name="WLCloudDetailY" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="0.5" - label="Y" - layout="topleft" - left_delta="0" - name="WLCloudDetailY" - top_pad="6" - width="200" /> - <slider - control_name="WLCloudDetailDensity" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="1.0" - label="D" - layout="topleft" - left_delta="0" - name="WLCloudDetailDensity" - top_pad="6" - width="200" /> - - <!--======== Tab Panel III. III conlumn of controls ========--> - - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_pad="55" - name="WLCloudScrollXText" - top="15" - width="150"> - Cloud Scroll X - </text> - <check_box - control_name="WLCloudLockX" - follows="left|top" - height="16" - label="Lock" - layout="topleft" - left_delta="150" - name="WLCloudLockX" - top_delta="0" - width="200" /> - <slider - control_name="WLCloudScrollX" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="0.5" - layout="topleft" - left_delta="-135" - max_val="10" - min_val="-10" - name="WLCloudScrollX" - top_pad="6" - width="200" /> - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-15" - name="WLCloudScrollYText" - top_pad="20" - width="150"> - Cloud Scroll Y - </text> - <check_box - control_name="WLCloudLockY" - follows="left|top" - height="16" - label="Lock" - layout="topleft" - left_delta="150" - name="WLCloudLockY" - width="200" /> - <slider - control_name="WLCloudScrollY" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="0.5" - layout="topleft" - left_delta="-135" - max_val="10" - min_val="-10" - name="WLCloudScrollY" - top_pad="6" - width="200" /> - </panel> - </tab_container> -<!--======== End of Controls panel ========--> - - <check_box - follows="top|left" - height="10" - label="Make this preset my new sky setting" - layout="topleft" - left="380" - name="make_default_cb" - top_pad="30" - width="280"/> - <button - follows="bottom|right" - height="23" - label="Save" - layout="topleft" - left_pad="0" - name="save" - width="70"/> - <button - follows="bottom|right" - height="23" - label="Cancel" - layout="topleft" - left_pad="15" - name="cancel" - width="70"/> - </floater> diff --git a/indra/newview/skins/default/xui/en/floater_edit_water_preset.xml b/indra/newview/skins/default/xui/en/floater_edit_water_preset.xml deleted file mode 100644 index 905983e7fa..0000000000 --- a/indra/newview/skins/default/xui/en/floater_edit_water_preset.xml +++ /dev/null @@ -1,448 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater - legacy_header_height="18" - height="375" - layout="topleft" - name="Edit Water Preset" - help_topic="water_preset" - save_rect="true" - title="Edit Water Preset" - width="725"> - - <string name="title_new">Create a New Water Preset</string> - <string name="title_edit">Edit a Water Preset</string> - <string name="hint_new">Name your preset, adjust the controls to create it, and click "Save".</string> - <string name="hint_edit">To edit your water preset, adjust the controls and click "Save".</string> - <string name="combo_label">-Select a preset-</string> - - <text - follows="top|left|right" - height="10" - layout="topleft" - left="30" - name="hint" - top="25" - width="680"> - To edit your preset, adjust the controls then click "Save" - </text> - - <text - follows="top|left|right" - font="SansSerif" - height="10" - layout="topleft" - left="30" - name="label" - top_pad="25" - width="120"> - Preset Name: - </text> - - <combo_box - allow_text_entry="true" - follows="top|left" - layout="topleft" - left_pad="10" - max_chars="100" - name="water_preset_combo" - top_delta="-5" - width="200"/> - - <line_editor - height="20" - left_delta="0" - name="water_preset_name" - top_delta="0" - width="200" /> - - <text - follows="top|left|right" - height="40" - layout="topleft" - left_pad="10" - name="note" - top_delta="0" - width="340" - wrap="true"> - Note: if you change the name of your preset, you will be creating a new preset and the existing preset will not be changed. - </text> - - <!--======== Controls panel ========--> - <panel - border="false" - bevel_style="none" - follows="top|left" - height="230" - layout="topleft" - left="10" - name="panel_water_preset" - top="100" - width="700"> - -<!--======== I conlumn of controls ========--> - <text - follows="left|top|right" - height="10" - font="SansSerif" - layout="topleft" - left="10" - name="water_color_label" - top="5" - width="215"> - Water Fog Color - </text> - <color_swatch - can_apply_immediately="true" - follows="left|top" - height="37" - label_height="0" - layout="topleft" - left_delta="15" - name="WaterFogColor" - top_pad="8" - width="60" /> - - - <text - follows="left|top|right" - font="SansSerif" - layout="topleft" - left_delta="-15" - top_pad="10" - name="water_fog_density_label" - width="215"> - Fog Density Exponent - </text> - <slider - decimal_digits="1" - follows="left|top" - height="10" - initial_value="0" - layout="topleft" - left_delta="15" - max_val="10" - name="WaterFogDensity" - top_pad="10" - width="200"/> - - - <text - follows="left|top|right" - font="SansSerif" - layout="topleft" - left_delta="-15" - top_pad="15" - name="underwater_fog_modifier_label" - width="215"> - Underwater Fog Modifier - </text> - <slider - decimal_digits="1" - follows="left|top" - height="10" - initial_value="0" - layout="topleft" - left_delta="15" - max_val="10" - name="WaterUnderWaterFogMod" - top_pad="10" - width="200"/> - - - <text - follows="left|top|right" - font="SansSerif" - layout="topleft" - left_delta="-15" - name="BHText" - top_pad="15" - width="215"> - Big Wave Direction - </text> - <slider - control_name="WaterWave1DirX" - decimal_digits="2" - follows="left|top" - increment="0.01" - initial_value="0.7" - label="X" - layout="topleft" - max_val="4" - min_val="-4" - name="WaterWave1DirX" - top_pad="10" - width="216"/> - <slider - control_name="WaterWave1DirY" - decimal_digits="2" - follows="left|top" - increment="0.01" - initial_value="0.7" - label="Y" - layout="topleft" - max_val="4" - min_val="-4" - name="WaterWave1DirY" - top_pad="5" - width="216"/> - -<!--======== II conlumn of controls ========--> - - <text - follows="left|top|right" - font="SansSerif" - height="10" - layout="topleft" - left_pad="20" - name="BDensText" - top="5" - width="215"> - Reflection Wavelet Scale - </text> - <slider - control_name="WaterNormalScaleX" - decimal_digits="1" - follows="left|top" - initial_value="0.7" - layout="topleft" - left_delta="15" - max_val="10" - name="WaterNormalScaleX" - top_pad="10" - width="200"/> - <slider - control_name="WaterNormalScaleY" - decimal_digits="1" - follows="left|top" - initial_value="0.7" - layout="topleft" - max_val="10" - name="WaterNormalScaleY" - top_pad="6" - width="200"/> - <slider - control_name="WaterNormalScaleZ" - decimal_digits="1" - follows="left|top" - initial_value="0.7" - layout="topleft" - max_val="10" - name="WaterNormalScaleZ" - top_pad="6" - width="200"/> - - - <text - follows="left|top|right" - font="SansSerif" - layout="topleft" - left_delta="-15" - name="HDText" - top_pad="16" - width="215"> - Fresnel Scale - </text> - <slider - control_name="WaterFresnelScale" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="0.7" - layout="topleft" - left_delta="15" - name="WaterFresnelScale" - top_pad="10" - width="200"/> - <text - follows="left|top|right" - font="SansSerif" - layout="topleft" - left_delta="-15" - name="FresnelOffsetText" - top_pad="15" - width="215"> - Fresnel Offset - </text> - <slider - control_name="WaterFresnelOffset" - decimal_digits="2" - follows="left" - increment="0.01" - initial_value="0.7" - layout="topleft" - left_delta="15" - name="WaterFresnelOffset" - top_pad="10" - width="200"/> - - - <text - follows="left|top|right" - font="SansSerif" - layout="topleft" - left_delta="-15" - name="BHText2" - top_pad="15" - width="215"> - Little Wave Direction - </text> - <slider - control_name="WaterWave2DirX" - decimal_digits="2" - follows="left|top" - increment="0.01" - initial_value="0.7" - label="X" - layout="topleft" - max_val="4" - min_val="-4" - name="WaterWave2DirX" - top_pad="10" - width="216" /> - <slider - control_name="WaterWave2DirY" - decimal_digits="2" - follows="left|top" - increment="0.01" - initial_value="0.7" - label="Y" - layout="topleft" - max_val="4" - min_val="-4" - name="WaterWave2DirY" - top_pad="6" - width="216" /> - -<!--======== III conlumn of contorls ========--> - - <text - follows="left|top|right" - font="SansSerif" - height="16" - layout="topleft" - left_pad="20" - name="DensMultText" - top="5" - width="215"> - Refract Scale Above - </text> - <slider - control_name="WaterScaleAbove" - decimal_digits="2" - follows="left|top" - increment="0.01" - initial_value="0.1" - layout="topleft" - left_delta="15" - name="WaterScaleAbove" - top_pad="5" - width="200" /> - - <text - type="string" - length="1" - follows="left|top|right" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-15" - name="WaterScaleBelowText" - top_pad="15" - width="215"> - Refract Scale Below - </text> - <slider - control_name="WaterScaleBelow" - decimal_digits="2" - follows="left|top" - height="10" - increment="0.01" - initial_value="0" - layout="topleft" - left_delta="15" - name="WaterScaleBelow" - top_pad="5" - width="200"/> - - <text - follows="left|top|right" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-15" - name="MaxAltText" - top_pad="15" - width="215"> - Blur Multiplier - </text> - <slider - control_name="WaterBlurMult" - follows="left|top" - height="10" - increment="0.001" - initial_value="0" - layout="topleft" - left_delta="15" - max_val="0.16" - name="WaterBlurMult" - top_pad="5" - width="200"/> - - <text - follows="left|top|right" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-15" - name="BHText3" - top_pad="15" - width="215"> - Normal Map - </text> - <texture_picker - height="80" - layout="topleft" - left_delta="15" - name="WaterNormalMap" - top_pad="5" - width="100" /> - </panel> -<!--======== End of Controls panel ========--> - - <view_border - bevel_style="none" - follows="top|left" - height="0" - layout="topleft" - left="10" - name="horiz_separator" - top_pad="5" - width="700"/> - <check_box - follows="top|left" - height="10" - label="Make this preset my new water setting" - layout="topleft" - left="275" - name="make_default_cb" - top_pad="20" - width="280"/> - <button - follows="bottom|right" - height="23" - label="Save" - layout="topleft" - left_pad="0" - name="save" - width="70"/> - <button - follows="bottom|right" - height="23" - label="Cancel" - layout="topleft" - left_pad="15" - name="cancel" - width="70"/> - - </floater> diff --git a/indra/newview/skins/default/xui/en/floater_environment_settings.xml b/indra/newview/skins/default/xui/en/floater_environment_settings.xml deleted file mode 100644 index 1b1cafaca6..0000000000 --- a/indra/newview/skins/default/xui/en/floater_environment_settings.xml +++ /dev/null @@ -1,162 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater - legacy_header_height="18" - height="328" - layout="topleft" - name="Environment Editor Floater" - help_topic="environment_editor_floater" - save_rect="true" - title="ENVIRONMENT SETTINGS" - width="540"> - - <text - follows="top|left|right" - height="15" - layout="topleft" - left="20" - name="note" - top="25" - width="510" - wrap="true"> - Use the options below to customize the environment settings for your viewer. - </text> - - <view_border - bevel_style="none" - follows="top|left" - height="237" - layout="topleft" - left="20" - name="border" - top_pad="8" - width="500"/> - <radio_group - follows="top|left" - height="45" - layout="topleft" - left_delta="10" - name="region_settings_radio_group" - top_delta="20" - width="200"> - <radio_item - label="Use region settings" - layout="topleft" - name="use_region_settings"/> - <radio_item - label="Customize my environment" - layout="topleft" - name="use_my_settings" - top_pad="20"/> - </radio_group> - - <panel - height="170" - layout="topleft" - left="50" - name="user_environment_settings" - top_pad="0" - width="470"> - - <text - follows="top|left|right" - font="SansSerifItalic" - height="15" - layout="topleft" - left_delta="0" - name="note" - top_pad="0" - width="470" - wrap="true"> - Note: your custom settings will not be visible to other users. - </text> - - <!-- Water Setting --> - <text - name="water_settings_title" - follows="top|left" - height="16" - layout="topleft" - left="50" - top="40" - width="200"> - Water Setting - </text> - <combo_box - follows="top|left" - left_pad="2" - name="water_settings_preset_combo" - top_delta="-5" - width="200"> - <combo_box.item - label="-Select a preset-" - name="item0"/> - </combo_box> - - - <!-- Sky/Day Cycle Settings --> - <text - name="sky_dayc_settings_title" - follows="top|left" - height="16" - layout="topleft" - left="50" - top_pad="20" - width="100"> - Sky / Day Cycle - </text> - <radio_group - layout="topleft" - left_delta="50" - name="sky_dayc_settings_radio_group" - top_pad="10" - height="50" - width="150"> - <radio_item - layout="topleft" - label="Fixed sky" - name="my_sky_settings"/> - <radio_item - layout="topleft" - label="Day cycle" - name="my_dayc_settings" - top_pad="25"/> - </radio_group> - <combo_box - follows="top|left" - left_pad="2" - name="sky_settings_preset_combo" - top_delta="-7" - width="200"> - <combo_box.item - label="-Select a preset-" - name="item0"/> - </combo_box> - <combo_box - follows="top|left" - name="dayc_settings_preset_combo" - top_delta="36" - width="200"> - <combo_box.item - label="-Select a preset-" - name="item0"/> - </combo_box> - </panel> - - <button - follows="left|top" - height="23" - label="OK" - layout="topleft" - right="-130" - name="ok_btn" - top_pad="10" - width="100" /> - <button - follows="left|top" - height="23" - label="Cancel" - layout="topleft" - left_pad="10" - name="cancel_btn" - width="100" /> -</floater> diff --git a/indra/newview/skins/default/xui/en/floater_fixedenvironment.xml b/indra/newview/skins/default/xui/en/floater_fixedenvironment.xml new file mode 100644 index 0000000000..a6e20880a9 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_fixedenvironment.xml @@ -0,0 +1,161 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + can_tear_off="false" + can_resize="false" + can_drag_on_left="false" + can_close="true" + can_dock="false" + bevel_style="in" + height="550" + layout="topleft" + name="Fixed Environment" + save_rect="true" + title="Fixed Environment" + save_visibility="false" + help_topic="fixed_environment" + single_instance="true" + width="750"> + <string name="edit_sky">Edit Sky:</string> + <string name="edit_water">Edit Water:</string> + <layout_stack name="floater_stack" + left="5" + top="5" + right="-5" + bottom="-5" + follows="left|top|right|bottom" + orientation="vertical"> + <layout_panel name="info_panel" + auto_resize="false" + user_resize="false" + min_height="60"> + <text + follows="left|top" + top_delta="30" + left_delta="10" + width="35" + height="20" + font="SansSerif"> + Name: + </text> + <line_editor + follows="left|top" + top_delta="-2" + left_delta="45" + width="250" + name="settings_name" + prevalidate_callback="ascii" + max_length_chars="63" + height="20"/> + <button + height="23" + label="Load" + follows="left|top" + left_delta="260" + font="SansSerif" + top_delta="-2" + name="btn_load" + tool_tip="Load a settings from inventory" + width="96" /> + <button + height="23" + label="Import" + follows="right|top" + right="-10" + font="SansSerif" + top_delta="0" + name="btn_import" + tool_tip="Import legacy settings from disk." + width="96" /> + </layout_panel> + <layout_panel name="tab_area" + auto_resize="true" + user_resize="false" + height="11" + min_height="0" + visible="true"> + <tab_container + follows="all" + halign="left" + layout="topleft" + left="0" + name="tab_settings" + tab_position="top" + tab_width="120" + tab_padding_right="3"> + <!-- Tabs inserted here in code --> + </tab_container> + </layout_panel> + <layout_panel name="button_panel" + follows="left|top|right|bottom" + auto_resize="false" + user_resize="false" + height="29" + visible="true"> + <layout_stack + follows="bottom|left|right" + height="23" + layout="topleft" + mouse_opaque="false" + name="button_bar_ls" + left="212" + orientation="horizontal" + top="0" + width="313"> + <layout_panel + follows="bottom|left|right" + height="23" + layout="bottomleft" + left="0" + mouse_opaque="false" + name="save_btn_lp" + auto_resize="true" + width="156"> + <button + follows="bottom|left|right" + height="23" + label="Save" + left="1" + layout="topleft" + name="btn_commit" + top="0" + width="155" /> + <button + follows="bottom|right" + height="23" + name="btn_flyout" + label="" + layout="topleft" + left_pad="-20" + tab_stop="false" + top="0" + image_selected="SegmentedBtn_Right_Selected_Press" + image_unselected="SegmentedBtn_Right_Off" + image_pressed="SegmentedBtn_Right_Press" + image_pressed_selected="SegmentedBtn_Right_Selected_Press" + image_overlay="Arrow_Small_Up" + width="20"/> + </layout_panel> + <layout_panel + follows="bottom|left|right" + height="23" + layout="bottomleft" + left_pad="3" + mouse_opaque="false" + name="revert_btn_lp" + auto_resize="true" + width="147"> + <button + follows="bottom|right" + height="23" + right="-1" + label="Cancel" + layout="topleft" + name="btn_cancel" + top="0" + tool_tip="Revert to last saved version" + width="147" /> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_flickr.xml b/indra/newview/skins/default/xui/en/floater_flickr.xml deleted file mode 100644 index 3b9c4894c1..0000000000 --- a/indra/newview/skins/default/xui/en/floater_flickr.xml +++ /dev/null @@ -1,90 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<floater - positioning="cascading" - can_close="true" - can_resize="false" - help_topic="floater_flickr" - layout="topleft" - name="floater_flickr" - save_rect="true" - single_instance="true" - reuse_instance="true" - title="SHARE TO FLICKR" - height="590" - width="272"> - <panel - height="590" - width="272" - visible="true" - name="background" - follows="all" - top="0" - left="0"> - <tab_container - name="tabs" - tab_group="1" - tab_min_width="70" - tab_height="21" - tab_position="top" - top="7" - height="555" - follows="all" - halign="center"> - <panel - filename="panel_flickr_photo.xml" - class="llflickrphotopanel" - follows="all" - label="PHOTO" - name="panel_flickr_photo"/> - <panel - filename="panel_flickr_account.xml" - class="llflickraccountpanel" - follows="all" - label="ACCOUNT" - name="panel_flickr_account"/> - </tab_container> - <panel - name="connection_status_panel" - follows="left|bottom|right" - height="24"> - <text - name="connection_error_text" - type="string" - follows="left|bottom|right" - bottom="-5" - left="10" - width="250" - height="20" - wrap="true" - halign="left" - valign="center" - text_color="DrYellow" - font="SansSerif"> - Error - </text> - <loading_indicator - follows="left|bottom|right" - height="24" - width="24" - name="connection_loading_indicator" - top_delta="-2" - left="10" - visible="true"/> - <text - name="connection_loading_text" - type="string" - follows="left|bottom|right" - top_delta="2" - left_pad="5" - width="250" - height="20" - wrap="true" - halign="left" - valign="center" - text_color="EmphasisColor" - font="SansSerif"> - Loading... - </text> - </panel> - </panel> -</floater> diff --git a/indra/newview/skins/default/xui/en/floater_forget_user.xml b/indra/newview/skins/default/xui/en/floater_forget_user.xml new file mode 100644 index 0000000000..a9ec1b74a3 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_forget_user.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + height="258" + layout="topleft" + name="groups" + help_topic="forget_username" + title="REMEMBERED USERNAMES" + width="280"> + <scroll_list + height="173" + layout="topleft" + left="12" + name="user_list" + top="24" + width="256"> + <scroll_list.columns + name="user" + width="248" /> + </scroll_list> + <button + height="20" + label="Forget" + label_selected="Forget" + layout="topleft" + left_delta="90" + name="forget" + top_pad="8" + width="80" /> + <check_box + height="20" + label="Also delete local data for this username" + layout="topleft" + left="15" + name="delete_data" + top_pad="5" + width="260" + tool_tip="Deletes local files: chat history, last session screenshot, browser cookies, teleport history, toolbar settings, e t c. Some of local files are shared between grids."/> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_how_to.xml b/indra/newview/skins/default/xui/en/floater_how_to.xml index 8c0077a8cc..baff8e1bc0 100644 --- a/indra/newview/skins/default/xui/en/floater_how_to.xml +++ b/indra/newview/skins/default/xui/en/floater_how_to.xml @@ -1,18 +1,17 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater legacy_header_height="18" - can_resize="true" - can_minimize="true" - height="775" + can_resize="false" + can_minimize="false" + can_close="false" + height="525" layout="topleft" - min_height="360" - left="10000" - top="10" - min_width="335" name="floater_how_to" - help_topic="how_to" single_instance="true" + save_visibility="true" save_rect="true" - title="HOW TO" - width="780" + title="WELCOME ISLAND GUIDEBOOK" + width="310" + rel_x="-0.469309" + rel_y="-0.011166" filename="floater_web_content.xml"/>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml index c64ee5565a..15f02ab9c3 100644 --- a/indra/newview/skins/default/xui/en/floater_im_session.xml +++ b/indra/newview/skins/default/xui/en/floater_im_session.xml @@ -267,6 +267,36 @@ right="-1"> <layout_panel name="input_editor_layout_panel"> + <avatar_icon + follows="left|bottom" + name="avatar_icon" + height="20" + default_icon_name="Generic_Person" + layout="topleft" + left="3" + bottom="-9" + visible="false" + width="20" /> + <group_icon + follows="left|bottom" + name="group_chat_icon" + height="20" + default_icon_name="Generic_Group" + layout="topleft" + left="3" + bottom="-9" + visible="false" + width="20" /> + <icon + follows="left|bottom" + height="20" + image_name="Nearby_chat_icon" + layout="topleft" + left="3" + bottom="-9" + name="nearby_chat_icon" + visible="false" + width="20"/> <chat_editor layout="topleft" expand_lines_count="5" @@ -280,7 +310,7 @@ spellcheck="true" tab_group="3" bottom="-8" - left="5" + left_pad="5" right="-5" wrap="true" /> </layout_panel> diff --git a/indra/newview/skins/default/xui/en/floater_image_preview.xml b/indra/newview/skins/default/xui/en/floater_image_preview.xml index 44d2c14cc8..773d9aafc9 100644 --- a/indra/newview/skins/default/xui/en/floater_image_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_image_preview.xml @@ -2,7 +2,7 @@ <floater legacy_header_height="18" can_minimize="false" - height="460" + height="495" layout="topleft" name="Image Preview" help_topic="image_preview" @@ -120,8 +120,8 @@ Try saving image as 24 bit Targa (.tga). </text> <check_box - control_name="LosslessJ2CUpload" enabled="false" + initial_value="false" follows="bottom|left" height="16" label="Use lossless compression" @@ -148,4 +148,17 @@ Try saving image as 24 bit Targa (.tga). name="ok_btn" top_delta="0" width="125" /> + <text + type="string" + length="1" + follows="left|top" + height="35" + layout="topleft" + left="10" + mouse_opaque="false" + skip_link_underline="true" + name="info_text" + word_wrap="true" + top_pad="10" + width="270"/> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_inspect.xml b/indra/newview/skins/default/xui/en/floater_inspect.xml index 63334e2b24..802a6649c8 100644 --- a/indra/newview/skins/default/xui/en/floater_inspect.xml +++ b/indra/newview/skins/default/xui/en/floater_inspect.xml @@ -13,7 +13,7 @@ width="400"> <floater.string name="timeStamp"> - [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local] + [wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [year,datetime,slt] </floater.string> <scroll_list bottom="268" diff --git a/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml index ca1d299553..d783d1e23c 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml @@ -2,7 +2,7 @@ <floater legacy_header_height="18" can_minimize="false" - height="448" + height="466" layout="topleft" name="Inventory Finder" help_topic="inventory_finder" @@ -195,6 +195,23 @@ name="check_snapshot" top_delta="0" width="126" /> + <icon + height="16" + image_name="Inv_Settings" + layout="topleft" + left="8" + mouse_opaque="true" + name="icon_settings" + top="242" + width="16" /> + <check_box + height="16" + label="Settings" + layout="topleft" + left_pad="2" + name="check_settings" + top_delta="0" + width="126" /> <button follows="left|top" height="20" @@ -203,7 +220,7 @@ layout="topleft" left="8" name="All" - top="242" + top="262" width="100" /> <button height="20" @@ -257,7 +274,7 @@ width="260"/> <check_box height="16" - top="332" + top="352" label="Since Logoff" layout="topleft" left_delta="0" @@ -273,7 +290,7 @@ layout="topleft" left_delta="0" name="- OR -" - top="350" + top="370" width="144"> - OR - </text> @@ -281,7 +298,7 @@ height="16" layout="topleft" name="date_search_direction" - top="368" + top="388" left="8" width="270"> <radio_item @@ -351,6 +368,6 @@ layout="topleft" name="Close" right="-6" - top="414" + top="434" width="76" /> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_joystick.xml b/indra/newview/skins/default/xui/en/floater_joystick.xml index 3dfdf8e1a5..7d2cea1fe5 100644 --- a/indra/newview/skins/default/xui/en/floater_joystick.xml +++ b/indra/newview/skins/default/xui/en/floater_joystick.xml @@ -8,27 +8,32 @@ title="JOYSTICK CONFIGURATION" width="569"> <floater.string - name="NoDevice"> - no device detected + name="JoystickDisabled"> + None </floater.string> - <check_box - bottom="38" - height="10" - control_name="JoystickEnabled" - halign="left" - label="Enable Joystick:" + <text + type="string" layout="topleft" + follows="left|top" + halign="left" + height="12" + top="22" left="14" - name="enable_joystick" - width="60" /> - <text - bottom="32" + width="50" + mouse_opaque="false" + name="joystick_lbl"> + Joystick: + </text> + <combo_box + allow_text_entry="false" + follows="left|top" layout="topleft" - left="120" - name="joystick_type" - width="380" /> + name="joystick_combo" + top="19" + left_pad="4" + width="300"/> <spinner - bottom="48" + bottom="56" height="10" control_name="JoystickAxis1" decimal_digits="0" @@ -42,7 +47,7 @@ name="JoystickAxis1" width="140" /> <spinner - bottom="48" + bottom_delta="0" height="10" control_name="JoystickAxis2" decimal_digits="0" @@ -56,7 +61,7 @@ name="JoystickAxis2" width="140" /> <spinner - bottom="48" + bottom_delta="0" height="10" control_name="JoystickAxis0" decimal_digits="0" @@ -70,7 +75,7 @@ name="JoystickAxis0" width="140" /> <spinner - bottom="68" + bottom="76" height="10" control_name="JoystickAxis4" decimal_digits="0" @@ -84,7 +89,7 @@ name="JoystickAxis4" width="140" /> <spinner - bottom="68" + bottom_delta="0" height="10" control_name="JoystickAxis5" decimal_digits="0" @@ -98,7 +103,7 @@ name="JoystickAxis5" width="140" /> <spinner - bottom="68" + bottom_delta="0" height="10" control_name="JoystickAxis3" decimal_digits="0" @@ -112,7 +117,7 @@ name="JoystickAxis3" width="140" /> <spinner - bottom="88" + bottom="96" height="10" control_name="JoystickAxis6" decimal_digits="0" @@ -162,12 +167,12 @@ left="37" mouse_opaque="false" name="Control Modes:" - top="110" + top="118" width="102"> Control Modes: </text> <check_box - bottom="127" + bottom="134" height="10" control_name="JoystickAvatarEnabled" halign="center" @@ -177,7 +182,7 @@ name="JoystickAvatarEnabled" width="60" /> <check_box - bottom="127" + bottom_delta="0" height="10" control_name="JoystickBuildEnabled" halign="center" @@ -187,7 +192,7 @@ name="JoystickBuildEnabled" width="60" /> <check_box - bottom="127" + bottom_delta="0" height="10" control_name="JoystickFlycamEnabled" halign="center" @@ -203,7 +208,7 @@ left="359" name="axis_view" show_label="true" - top="135" + top="143" width="200"> <stat_bar bar_max="2" @@ -266,7 +271,7 @@ <text type="string" length="1" - bottom="144" + bottom="152" halign="right" layout="topleft" left="3" @@ -275,7 +280,7 @@ X Scale </text> <spinner - bottom="144" + bottom_delta="0" height="10" control_name="AvatarAxisScale1" decimal_digits="2" @@ -287,7 +292,7 @@ name="AvatarAxisScale1" width="56" /> <spinner - bottom="144" + bottom_delta="0" height="10" control_name="BuildAxisScale1" decimal_digits="2" @@ -299,7 +304,7 @@ name="BuildAxisScale1" width="56" /> <spinner - bottom="144" + bottom_delta="0" height="10" control_name="FlycamAxisScale1" decimal_digits="2" @@ -313,7 +318,7 @@ <text type="string" length="1" - bottom="164" + bottom="172" halign="right" layout="topleft" left="3" @@ -322,7 +327,7 @@ Y Scale </text> <spinner - bottom="164" + bottom_delta="0" height="10" control_name="AvatarAxisScale2" decimal_digits="2" @@ -334,7 +339,7 @@ name="AvatarAxisScale2" width="56" /> <spinner - bottom="164" + bottom_delta="0" height="10" control_name="BuildAxisScale2" decimal_digits="2" @@ -346,7 +351,7 @@ name="BuildAxisScale2" width="56" /> <spinner - bottom="164" + bottom_delta="0" height="10" control_name="FlycamAxisScale2" decimal_digits="2" @@ -360,7 +365,7 @@ <text type="string" length="1" - bottom="184" + bottom="192" halign="right" layout="topleft" left="3" @@ -369,7 +374,7 @@ Z Scale </text> <spinner - bottom="184" + bottom_delta="0" height="10" control_name="AvatarAxisScale0" decimal_digits="2" @@ -381,7 +386,7 @@ name="AvatarAxisScale0" width="56" /> <spinner - bottom="184" + bottom_delta="0" height="10" control_name="BuildAxisScale0" decimal_digits="2" @@ -393,7 +398,7 @@ name="BuildAxisScale0" width="56" /> <spinner - bottom="184" + bottom_delta="0" height="10" control_name="FlycamAxisScale0" decimal_digits="2" @@ -407,7 +412,7 @@ <text type="string" length="1" - bottom="204" + bottom="212" halign="right" layout="topleft" left="3" @@ -416,7 +421,7 @@ Pitch Scale </text> <spinner - bottom="204" + bottom_delta="0" height="10" control_name="AvatarAxisScale4" decimal_digits="2" @@ -428,7 +433,7 @@ name="AvatarAxisScale4" width="56" /> <spinner - bottom="204" + bottom_delta="0" height="10" control_name="BuildAxisScale4" decimal_digits="2" @@ -440,7 +445,7 @@ name="BuildAxisScale4" width="56" /> <spinner - bottom="204" + bottom_delta="0" height="10" control_name="FlycamAxisScale4" decimal_digits="2" @@ -454,7 +459,7 @@ <text type="string" length="1" - bottom="224" + bottom="232" halign="right" layout="topleft" left="3" @@ -463,7 +468,7 @@ Yaw Scale </text> <spinner - bottom="224" + bottom_delta="0" height="10" control_name="AvatarAxisScale5" decimal_digits="2" @@ -475,7 +480,7 @@ name="AvatarAxisScale5" width="56" /> <spinner - bottom="224" + bottom_delta="0" height="10" control_name="BuildAxisScale5" decimal_digits="2" @@ -487,7 +492,7 @@ name="BuildAxisScale5" width="56" /> <spinner - bottom="224" + bottom_delta="0" height="10" control_name="FlycamAxisScale5" decimal_digits="2" @@ -501,7 +506,7 @@ <text type="string" length="1" - bottom="244" + bottom="252" halign="right" layout="topleft" left="3" @@ -510,7 +515,7 @@ Roll Scale </text> <spinner - bottom="244" + bottom_delta="0" height="10" control_name="BuildAxisScale3" decimal_digits="2" @@ -522,7 +527,7 @@ name="BuildAxisScale3" width="56" /> <spinner - bottom="244" + bottom_delta="0" height="10" control_name="FlycamAxisScale3" decimal_digits="2" @@ -536,7 +541,7 @@ <text type="string" length="1" - bottom="274" + bottom="282" halign="right" layout="topleft" left="3" @@ -545,7 +550,7 @@ X Dead Zone </text> <spinner - bottom="274" + bottom_delta="0" height="10" control_name="AvatarAxisDeadZone1" decimal_digits="2" @@ -556,7 +561,7 @@ name="AvatarAxisDeadZone1" width="56" /> <spinner - bottom="274" + bottom_delta="0" height="10" control_name="BuildAxisDeadZone1" decimal_digits="2" @@ -567,7 +572,7 @@ name="BuildAxisDeadZone1" width="56" /> <spinner - bottom="274" + bottom_delta="0" height="10" control_name="FlycamAxisDeadZone1" decimal_digits="2" @@ -580,7 +585,7 @@ <text type="string" length="1" - bottom="294" + bottom="302" halign="right" layout="topleft" left="3" @@ -589,7 +594,7 @@ Y Dead Zone </text> <spinner - bottom="294" + bottom_delta="0" height="10" control_name="AvatarAxisDeadZone2" decimal_digits="2" @@ -600,7 +605,7 @@ name="AvatarAxisDeadZone2" width="56" /> <spinner - bottom="294" + bottom_delta="0" height="10" control_name="BuildAxisDeadZone2" decimal_digits="2" @@ -611,7 +616,7 @@ name="BuildAxisDeadZone2" width="56" /> <spinner - bottom="294" + bottom_delta="0" height="10" control_name="FlycamAxisDeadZone2" decimal_digits="2" @@ -624,7 +629,7 @@ <text type="string" length="1" - bottom="314" + bottom="322" halign="right" layout="topleft" left="3" @@ -633,7 +638,7 @@ Z Dead Zone </text> <spinner - bottom="314" + bottom_delta="0" height="10" control_name="AvatarAxisDeadZone0" decimal_digits="2" @@ -644,7 +649,7 @@ name="AvatarAxisDeadZone0" width="56" /> <spinner - bottom="314" + bottom_delta="0" height="10" control_name="BuildAxisDeadZone0" decimal_digits="2" @@ -655,7 +660,7 @@ name="BuildAxisDeadZone0" width="56" /> <spinner - bottom="314" + bottom_delta="0" height="10" control_name="FlycamAxisDeadZone0" decimal_digits="2" @@ -668,7 +673,7 @@ <text type="string" length="1" - bottom="334" + bottom="342" halign="right" layout="topleft" left="2" @@ -677,7 +682,7 @@ Pitch Dead Zone </text> <spinner - bottom="334" + bottom_delta="0" height="10" control_name="AvatarAxisDeadZone4" decimal_digits="2" @@ -688,7 +693,7 @@ name="AvatarAxisDeadZone4" width="56" /> <spinner - bottom="334" + bottom_delta="0" height="10" control_name="BuildAxisDeadZone4" decimal_digits="2" @@ -699,7 +704,7 @@ name="BuildAxisDeadZone4" width="56" /> <spinner - bottom="334" + bottom_delta="0" height="10" control_name="FlycamAxisDeadZone4" decimal_digits="2" @@ -712,7 +717,7 @@ <text type="string" length="1" - bottom="354" + bottom="362" halign="right" layout="topleft" left="3" @@ -721,7 +726,7 @@ Yaw Dead Zone </text> <spinner - bottom="354" + bottom_delta="0" height="10" control_name="AvatarAxisDeadZone5" decimal_digits="2" @@ -732,7 +737,7 @@ name="AvatarAxisDeadZone5" width="56" /> <spinner - bottom="354" + bottom_delta="0" height="10" control_name="BuildAxisDeadZone5" decimal_digits="2" @@ -743,7 +748,7 @@ name="BuildAxisDeadZone5" width="56" /> <spinner - bottom="354" + bottom_delta="0" height="10" control_name="FlycamAxisDeadZone5" decimal_digits="2" @@ -756,7 +761,7 @@ <text type="string" length="1" - bottom="374" + bottom="382" halign="right" layout="topleft" left="3" @@ -765,7 +770,7 @@ Roll Dead Zone </text> <spinner - bottom="374" + bottom_delta="0" height="10" control_name="BuildAxisDeadZone3" decimal_digits="2" @@ -776,7 +781,7 @@ name="BuildAxisDeadZone3" width="56" /> <spinner - bottom="374" + bottom_delta="0" height="10" control_name="FlycamAxisDeadZone3" decimal_digits="2" @@ -789,7 +794,7 @@ <text type="string" length="1" - bottom="402" + bottom="410" halign="right" layout="topleft" left="3" @@ -810,7 +815,7 @@ min_val="1" name="AvatarFeathering" show_text="false" - top="402" + top="410" width="73" /> <slider control_name="BuildFeathering" @@ -845,7 +850,7 @@ <text type="string" length="1" - bottom="430" + bottom="438" halign="right" layout="topleft" left="3" @@ -854,7 +859,7 @@ Zoom Scale </text> <spinner - bottom="430" + bottom_delta="0" height="10" control_name="FlycamAxisScale6" decimal_digits="2" @@ -868,7 +873,7 @@ <text type="string" length="1" - bottom="450" + bottom="458" halign="right" layout="topleft" left="3" @@ -877,7 +882,7 @@ Zoom Dead Zone </text> <spinner - bottom="450" + bottom_delta="0" height="10" control_name="FlycamAxisDeadZone6" decimal_digits="2" @@ -894,7 +899,7 @@ layout="topleft" left="359" name="SpaceNavigatorDefaults" - top="429" + top="437" width="200" /> <button follows="right|bottom" diff --git a/indra/newview/skins/default/xui/en/floater_load_pref_preset.xml b/indra/newview/skins/default/xui/en/floater_load_pref_preset.xml index 5f2eb770e2..49c21f1ea7 100644 --- a/indra/newview/skins/default/xui/en/floater_load_pref_preset.xml +++ b/indra/newview/skins/default/xui/en/floater_load_pref_preset.xml @@ -4,7 +4,7 @@ height="130" help_topic="floater_load_preset" layout="topleft" - name="Load Pref Preset" + name="load_pref_preset" save_rect="true" title="LOAD PREF PRESET" width="300"> diff --git a/indra/newview/skins/default/xui/en/floater_merchant_outbox.xml b/indra/newview/skins/default/xui/en/floater_merchant_outbox.xml deleted file mode 100644 index 7802f65902..0000000000 --- a/indra/newview/skins/default/xui/en/floater_merchant_outbox.xml +++ /dev/null @@ -1,156 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<floater - positioning="cascading" - can_close="true" - can_resize="true" - height="440" - help_topic="floater_merchant_outbox" - min_width="300" - min_height="200" - name="floater_merchant_outbox" - save_rect="true" - save_visibility="false" - reuse_instance="true" - title="MERCHANT OUTBOX" - width="333"> - <string name="OutboxFolderCount0"></string> - <string name="OutboxFolderCount1">1 folder</string> - <string name="OutboxFolderCountN">[NUM] folders</string> - <string name="OutboxImporting">Sending folders...</string> - <string name="OutboxInitializing">Initializing...</string> - <panel - name="panel_1" - follows="all" - layout="topleft" - left="0" - top="0" - label="" - height="440" - width="333"> - <panel - name="panel_2" - follows="all" - left="10" - bottom="370" - width="313" - top="0" - bg_opaque_color="InventoryBackgroundColor"> - <panel - name="outbox_inventory_placeholder_panel" - follows="all" - layout="topleft" - top="0" - left="0" - width="308" - height="370" - bg_opaque_color="InventoryBackgroundColor"> - <text - name="outbox_inventory_placeholder_title" - type="string" - follows="top|left|right" - layout="topleft" - top="10" - left="0" - width="308" - height="25" - wrap="true" - halign="center" - font="SansSerifBold"> - Loading... - </text> - <text - name="outbox_inventory_placeholder_text" - type="string" - follows="top|left|right" - layout="topleft" - top="35" - left="0" - width="308" - height="130" - wrap="true" - halign="left" /> - </panel> - </panel> - <panel - name="panel_3" - follows="bottom|left|right" - left="10" - bottom="435" - width="313" - top="370"> - <panel - name="outbox_generic_drag_target" - mouse_opaque="false" - follows="all" - top="5" - left="5" - width="303" - height="25" - background_visible="false" - bg_alpha_color="EmphasisColor_35" - border="true" - bevel_style="in" - visible="true"> - <text - name="text_1" - type="string" - follows="all" - layout="topleft" - top="6" - height="20" - left="5" - width="293" - halign="center" - font="SansSerifMedium" - font_shadow="hard" - valign="top"> - Drag items here to create folders - </text> - </panel> - <text - name="outbox_folder_count" - type="string" - follows="all" - layout="topleft" - top="40" - left="5" - width="150" - height="20" - wrap="true" - halign="left" - valign="center" - font="SansSerif"/> - <button - label="Send to Marketplace" - tool_tip="Push to my Marketplace Storefront" - is_toggle="false" - name="outbox_import_btn" - follows="bottom|right" - tab_stop="false" - halign="center" - top="37" - left="160" - height="25" - width="150" - enabled="false" /> - </panel> - <layout_stack name="import_progress_indicator" orientation="vertical" left="0" height="440" top="0" width="333" follows="all" visible="false"> - <layout_panel /> - <layout_panel height="24" auto_resize="false"> - <layout_stack orientation="horizontal" left="0" height="24" top="0" width="333" follows="all"> - <layout_panel width="0" /> - <layout_panel width="24" auto_resize="false"> - <loading_indicator - height="24" - layout="topleft" - left="0" - top="0" - width="24" /> - </layout_panel> - <layout_panel width="0" /> - </layout_stack> - </layout_panel> - <layout_panel /> - </layout_stack> - </panel> -</floater> diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 5a86eb06fb..7f863756eb 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -2,15 +2,16 @@ <floater can_close="true" can_drag_on_left="false" - can_minimize="false" - can_resize="false" - height="480" - min_height="480" + can_minimize="true" + can_resize="true" + height="625" + min_height="625" width="980" min_width="980" name="Model Preview" title="UPLOAD MODEL" - help_topic="upload_model" > + help_topic="upload_model" + legacy_header_height="25"> <string name="status_idle"></string> <string name="status_parse_error">Error: Dae parsing issue - see log for details.</string> @@ -33,19 +34,27 @@ <string name="mesh_status_missing_lod">Missing required level of detail.</string> <string name="mesh_status_invalid_material_list">LOD materials are not a subset of reference model.</string> <string name="phys_status_vertex_limit_exceeded">Some physical hulls exceed vertex limitations.</string> + <string name="phys_status_degenerate_triangles">The physics mesh too dense remove the small thin triangles (see preview)</string> <string name="layer_all">All</string> <!-- Text to display in physics layer combo box for "all layers" --> <string name="decomposing">Analyzing...</string> <string name="simplifying">Simplifying...</string> <string name="tbd">TBD</string> + + <!-- Warnings and info from model loader--> + <string name="TooManyJoint">Skinning disabled due to too many joints: [JOINTS], maximum: [MAX]</string> + <string name="UnrecognizedJoint">Rigged to unrecognized joint name [NAME]</string> + <string name="UnknownJoints">Skinning disabled due to [COUNT] unknown joints</string> + <string name="ModelLoaded">Model [MODEL_NAME] loaded</string> + <string name="IncompleteTC">Texture coordinates data is not complete.</string> -<panel - follows="top|left" - height="455" - layout="topleft" - left="3" - name="left_panel" - top_pad="10" - width="630"> + <panel + follows="top|left" + height="595" + layout="topleft" + left="3" + name="left_panel" + top_pad="25" + width="635"> <panel follows="all" height="50" @@ -76,12 +85,16 @@ </panel> <tab_container follows="top|left" - top_pad="15" + top_pad="10" left="0" - height="300" + height="330" width="635" name="import_tab" - tab_position="top"> + tab_position="top" + enable_tabs_flashing="true" + tabs_flashing_color="MenuItemFlashBgColor"> + <last_tab + tab_top_image_flash="TabTop_Right_Flashing"/> <!-- for log tab --> <!-- LOD PANEL --> <panel help_topic="upload_model_lod" @@ -92,12 +105,12 @@ <view_border bevel_style="none" follows="top|left" - height="275" + height="306" layout="topleft" left="3" name="lod_tab_border" top_pad="0" - width="629" /> + width="628" /> <text follows="left|top" height="18" @@ -688,7 +701,7 @@ left="10" name="lod_tab_border" top_pad="20" - width="605" /> + width="614" /> <check_box follows="top|left" height="15" @@ -730,12 +743,12 @@ <view_border bevel_style="none" follows="top|left" - height="275" + height="306" layout="topleft" left="3" name="physics_tab_border" top_pad="0" - width="619"/> + width="628"/> <panel bg_alpha_color="0 0 0 0" bg_opaque_color="0 0 0 0.3" @@ -755,8 +768,9 @@ name="first_step_name" text_color="White" top_pad="0" - width="210"> - Step 1: Level of Detail + width="210" + valign="center"> + Step 1: Pick a physics model : </text> <combo_box follows="left|top" @@ -798,7 +812,7 @@ layout="topleft" left="18" name="physics_tab_border" - top_pad="15" + top_pad="10" width="589"/> <panel bg_alpha_color="0 0 0 0" @@ -807,7 +821,7 @@ follows="top|left" left="18" name="physics analysis" - top_pad="15" + top_pad="10" visible="true" width="589"> <text @@ -819,7 +833,7 @@ name="method_label" text_color="White" top_pad="0"> - Step 2: Analyze + Step 2: Convert to hulls (optional) </text> <text follows="top|left" @@ -905,7 +919,7 @@ layout="topleft" left="18" name="physics_tab_border" - top_pad="15" + top_pad="10" width="589"/> <panel bg_alpha_color="0 0 0 0" @@ -914,7 +928,7 @@ height="66" left="18" name="physics simplification" - top_pad="15" + top_pad="10" width="589"> <text text_color="White" @@ -1013,7 +1027,7 @@ layout="topleft" left="18" name="physics_tab_border" - top_pad="15" + top_pad="10" width="589"/> <panel bg_alpha_color="0 0 0 0" @@ -1075,10 +1089,9 @@ follows="left|top" height="19" layout="topleft" - left_pad="5" - top_delta="0" + top_pad="5" name="physics message" - width="270"> + width="589"> <icon follows="left|top" height="16" @@ -1093,7 +1106,7 @@ layout="topleft" left_pad="2" name="physics_status_message_text" - width="252" + width="573" top_delta="3"/> </panel> </panel> @@ -1105,12 +1118,12 @@ <view_border bevel_style="none" follows="top|left" - height="275" + height="306" layout="topleft" left="3" name="border" top_pad="0" - width="619"/> + width="628"/> <text follows="top|left" height="16" @@ -1157,75 +1170,211 @@ label_text.text_color="White" left="20" top_pad="20"/> - <view_border - bevel_style="none" - follows="top|left" - height="0" - layout="topleft" - name="border" - top_pad="20" - width="579"/> - <text - follows="top|left" - height="15" - left="20" - name="include_label" - text_color="White" - top_pad="20" - width="150"> - For avatar models only: - </text> - <check_box - follows="top|left" - height="15" - label="Include skin weight" - label_text.text_color="White" - name="upload_skin" - top_pad="15"/> - <check_box - follows="top|left" - height="15" - label="Include joint positions" - label_text.text_color="White" - name="upload_joints" - top_pad="15"/> - <check_box - follows="top|left" - height="15" - label="Lock scale if joint position defined" - label_text.text_color="White" - name="lock_scale_if_joint_position" - top_pad="15"/> - <text - follows="top|left" - height="15" - layout="topleft" - left="220" - name="pelvis_offset_label" - text_color="White" - top="134" - width="200"> - Z offset (raise or lower avatar): - </text> - <spinner - follows="top|left" - height="20" - min_val="-3.00" - max_val="3.0" - name="pelvis_offset" - top_pad="10" - value="0.0" - width="80"/> </panel> + <panel + label="Overrides" + layout="topleft" + name="rigging_panel" + title="Rigging"> + <view_border + bevel_style="none" + follows="top|left" + height="306" + layout="topleft" + left="3" + name="avatar_tab_border" + top_pad="0" + width="628" /> + <check_box + follows="top|left" + height="15" + label="Include skin weight" + label_text.text_color="White" + name="upload_skin" + top="8" + left="20"/> + <check_box + follows="top|left" + height="15" + label="Include joint positions" + label_text.text_color="White" + name="upload_joints" + left_delta="0" + top_pad="7"/> + <check_box + follows="top|left" + height="15" + label="Lock scale if joint position defined" + label_text.text_color="White" + name="lock_scale_if_joint_position" + top_pad="7"/> + <text + follows="top|left" + height="15" + layout="topleft" + left="220" + name="pelvis_offset_label" + text_color="White" + top="8" + width="200"> + Z offset (raise or lower avatar): + </text> + <spinner + follows="top|left" + height="20" + min_val="-3.00" + max_val="3.0" + name="pelvis_offset" + top_pad="10" + value="0.0" + width="80"/> + <text + follows="top|left" + height="17" + left="425" + name="skin_too_many_joints" + text_color="Orange" + top="7" + width="195" + word_wrap="true"> + Too many skinned joints + </text> + <text + follows="top|left" + height="32" + left="425" + name="skin_unknown_joint" + text_color="Orange" + top="8" + width="195" + word_wrap="true"> + Model has an unknown joint(s) + </text> + <text + layout="topleft" + follows="top|left" + height="15" + left="20" + name="joints_descr" + top="73" + width="150"> + Joints: + </text> + <scroll_list + layout="topleft" + follows="top|left" + name="joints_list" + column_padding="0" + draw_heading="false" + draw_stripes="false" + commit_on_selection_change="true" + heading_height="23" + height="199" + left_delta="0" + top_pad="0" + width="200"/> + <text + layout="topleft" + follows="top|left" + height="15" + left_delta="0" + name="conflicts_description" + top_pad="2" + width="200"> + [CONFLICTS] conflicts in [JOINTS_COUNT] joints + </text> + <text + layout="topleft" + follows="top|left" + height="15" + left_pad="5" + name="pos_overrides_descr" + top="73" + width="300"> + Position overrides for joint '[JOINT]': + </text> + <scroll_list + layout="topleft" + follows="top|left" + name="pos_overrides_list" + column_padding="0" + draw_heading="true" + draw_stripes="false" + heading_height="23" + height="100" + left_delta="0" + top_pad="0" + width="385"> + <scroll_list.columns + label="Model" + name="model_name" + relative_width="0.49" /> + <scroll_list.columns + label="X" + name="axis_x" + relative_width="0.17" /> + <scroll_list.columns + label="Y" + name="axis_y" + relative_width="0.17" /> + <scroll_list.columns + label="Z" + name="axis_z" + relative_width="0.17" /> + </scroll_list> + </panel> + <panel + label="Log" + layout="topleft" + name="logs_panel" + title="Log"> + <view_border + bevel_style="none" + follows="top|left" + height="289" + layout="topleft" + left="3" + name="log_tab_border" + top_pad="0" + width="628" /> + <text_editor + type="string" + length="1" + embedded_items="false" + follows="top|left" + font="SansSerif" + ignore_tab="false" + layout="topleft" + height="289" + left="4" + top="0" + right="-1" + max_length="65536" + name="log_text" + parse_urls="true" + spellcheck="false" + read_only="true" + word_wrap="true"> + </text_editor> + <check_box + control_name="ImporterDebug" + follows="top|left" + top_pad="9" + left="6" + width="70" + label="Enable detailed logging (can be very slow)" + name="verbose_logging"/> + </panel> </tab_container> <panel - follows="top|left" - height="80" - layout="top|left" - left="0" + follows="top|left|bottom" + layout="topleft" + height="195" + left="4" + border="true" name="weights_and_warning_panel" top_pad="3" - width="625"> + width="629"> <button follows="top|left" label="Calculate weights & fee" @@ -1265,10 +1414,10 @@ label_color="White" layout="topleft" name="reset_btn" - right="-2" + right="-5" top="3" height="20" - width="275"/> + width="265"/> <!-- ========== WEIGHTS ==========--> <text follows="top|left" @@ -1287,7 +1436,7 @@ left_pad="0" name="prim_weight" top_delta="0" - width="120" + width="130" word_wrap="true"> Land impact: [EQ] </text> @@ -1297,7 +1446,7 @@ left_pad="0" name="download_weight" top_delta="0" - width="100" + width="130" word_wrap="true"> Download: [ST] </text> @@ -1307,7 +1456,7 @@ layout="topleft" left_pad="0" name="physics_weight" - width="90" + width="130" word_wrap="true"> Physics: [PH] </text> @@ -1317,19 +1466,150 @@ layout="topleft" left_pad="0" name="server_weight" - width="83" + width="130" word_wrap="true"> Server: [SIM] </text> - <!-- ========== NOTE MESSAGE ========== --> + <!-- =========== Cost breakdown ======== --> + <panel + border="true" + top_pad="5" + layout="topleft" + left="6" + name="price_breakdown_panel" + width="120" + height="100"> + <text + layout="topleft" + left="3"> + Price Breakdown + </text> + <view_border + bevel_style="none" + follows="top|left" + height="0" + layout="topleft" + left="3" + name="price_breakdown_border" + top_pad="5" + width="110"/> + <text + height="80" + top_pad="5" + layout="topleft" + left="3" + name="price_breakdown_labels" + width="70" + word_wrap="false"> +Download: +Physics: +Instances: +Textures: +Model: + </text> + <text + height="80" + top_delta="0" + layout="topleft" + halign="right" + left_pad="0" + name="price_breakdown" + width="40" + word_wrap="false"> +[STREAMING] +[PHYSICS] +[INSTANCES] +[TEXTURES] +[MODEL] + </text> + </panel> + <!-- + Streaming breakdown numbers are available but not fully understood + uncommenting the following sections will display the numbers for debugging purposes + <text + height="80" + top_delta="0" + layout="topleft" + left="130" + name="streaming_breakdown_labels" + width="65" + word_wrap="true"> +Streaming/Download: +High: +Medium: +Low: +Lowest: + </text> <text + height="80" + top_delta="0" + layout="topleft" + left_pad="0" + name="streaming_breakdown" + width="95" + word_wrap="true"> +[STR_TOTAL] +[STR_HIGH] +[STR_MED] +[STR_LOW] +[STR_LOWEST] + </text>--> + <panel + border="true" + layout="topleft" + left_pad="265" + name="physics_costs_panel" + width="120" + height="100"> + <text + layout="topleft" + left="3"> + Physics Costs + </text> + <view_border + bevel_style="none" + follows="top|left" + height="0" + layout="topleft" + left="3" + name="price_breakdown_border" + top_pad="5" + width="110"/> + <text + height="80" + top_pad="5" + layout="topleft" + left="5" + name="physics_breakdown_labels" + width="65"> +Base Hull: +Mesh: +Analysed: + </text> + <text + height="80" + top_delta="0" + layout="topleft" + left_pad="0" + name="physics_breakdown" + width="40" + halign="right" + word_wrap="false" + visible="true"> +[PCH] +[PM] +[PHU] + </text>--> + </panel> + <!-- ========== NOTE MESSAGE ========== --> + <text font="SansSerif" layout="topleft" left="6" name="warning_title" - top_pad="10" + top_pad="5" text_color="DrYellow" - visible="false" + visible="true" width="40"> NOTE: </text> @@ -1340,44 +1620,51 @@ left_pad="1" name="warning_message" parse_urls="true" - top_delta="2" + top_delta="1" wrap="true" width="462" - visible="false"> + visible="true"> You dont have rights to upload mesh models. [[VURL] Find out how] to get certified. + </text> + <text + text_color="Yellow" + layout="topleft" + top_pad="-2" + left="6" + name="status"> +[STATUS] </text> - <text text_color="Yellow" layout="topleft" top_delta="20" left="6" name="status">[STATUS]</text> - </panel> -</panel> - -<text - follows="left|top" - layout="topleft" - left="640" - name="lod_label" - text_color="White" - top="13" - height="15" - width="290"> - Preview: - </text> -<panel - border="true" - bevel_style="none" - follows="top|left" - name="preview_panel" - top_pad="4" - width="290" - height="290"/> - -<panel - follows="all" - height="130" - layout="topleft" - name="right_panel" - top_pad="5" - width="340"> + </panel> + + <text + follows="left|top" + layout="topleft" + left="640" + name="lod_label" + text_color="White" + top="29" + height="15" + width="290"> + Preview: + </text> + <panel + follows="all" + layout="topleft" + border="true" + bevel_style="none" + name="preview_panel" + top_pad="4" + width="325" + height="408"/> + <panel + follows="right|bottom" + can_resize="false" + height="140" + layout="topleft" + name="right_panel" + top_pad="5" + width="340"> <combo_box top_pad="3" follows="left|top" @@ -1386,10 +1673,10 @@ name="preview_lod_combo" width="150" tool_tip="LOD to view in preview render"> - <combo_item name="high"> High </combo_item> - <combo_item name="medium"> Medium </combo_item> - <combo_item name="low"> Low </combo_item> - <combo_item name="lowest"> Lowest </combo_item> + <combo_item name="high"> High </combo_item> + <combo_item name="medium"> Medium </combo_item> + <combo_item name="low"> Low </combo_item> + <combo_item name="lowest"> Lowest </combo_item> </combo_box> <text follows="top|left" @@ -1436,11 +1723,21 @@ </check_box> <check_box follows="top|left" + label="Joint position overrides" + label_text.text_color="White" + word_wrap="down" + width="130" + layout="topleft" + name="show_joint_overrides" + top_pad="8"> + </check_box> + <check_box + follows="top|left" label="Joints" label_text.text_color="White" layout="topleft" name="show_joint_positions" - top_pad="8"> + top_pad="17"> </check_box> <text follows="top|left" @@ -1460,5 +1757,5 @@ max_val="3.0" height="20" width="150"/> -</panel> + </panel> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_my_appearance.xml b/indra/newview/skins/default/xui/en/floater_my_appearance.xml index fdea7a821a..35ad87ceb0 100644 --- a/indra/newview/skins/default/xui/en/floater_my_appearance.xml +++ b/indra/newview/skins/default/xui/en/floater_my_appearance.xml @@ -11,7 +11,7 @@ save_rect="true" single_instance="true" reuse_instance="true" - title="APPEARANCE" + title="AVATAR" min_height="440" min_width="333" width="333"> diff --git a/indra/newview/skins/default/xui/en/floater_my_environments.xml b/indra/newview/skins/default/xui/en/floater_my_environments.xml new file mode 100644 index 0000000000..6aff387dcb --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_my_environments.xml @@ -0,0 +1,200 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<floater + positioning="cascading" + save_rect="true" + single_instance="true" + reuse_instance="true" + legacy_header_height="18" + can_resize="true" + height="465" + name="my_environments" + help_topic="my_environments" + title="MY ENVIRONMENTS" + background_visible="true" + label="Places" + layout="topleft" + min_height="350" + min_width="265" + width="313"> + <layout_stack + follows="all" + layout="topleft" + left="5" + top="20" + right="-5" + bottom="-5" + orientation="vertical"> + <layout_panel + border="true" + bevel_style="in" + auto_resize="false" + tab_group="1" + height="54" + name="filter_panel" + label="Filters" + font="SansSerifBold"> + <icon + height="16" + image_name="Inv_SettingsDay" + layout="topleft" + mouse_opaque="true" + name="icon_settingsdays" + left="4" + width="16" /> + <check_box + height="16" + label="Days" + layout="topleft" + left_pad="2" + name="chk_days" + top_delta="0" + width="60" /> + <icon + height="16" + image_name="Inv_SettingsSky" + layout="topleft" + mouse_opaque="true" + name="icon_settingsskies" + left_pad="10" + width="16" /> + <check_box + height="16" + label="Skies" + layout="topleft" + left_pad="2" + name="chk_skies" + top_delta="0" + width="60" /> + <icon + height="16" + image_name="Inv_SettingsWater" + layout="topleft" + mouse_opaque="true" + name="icon_settingswater" + left_pad="10" + width="16" /> + <check_box + height="16" + label="Water" + layout="topleft" + left_pad="2" + name="chk_water" + top_delta="0" + width="60" /> + <filter_editor + follows="left|top|right" + height="23" + label="Filter Environments" + layout="topleft" + left="4" + name="flt_search" + top_pad="6" + right="-4" /> + </layout_panel> + <layout_panel + auto_resize="true" + user_resize="true" + tab_group="1" + name="list_panel" + label="Environments" + font="SansSerifBold"> + <panel + name="pnl_inv_wrap" + label="pnl_inv_wrap" + follows="all" + layout="topleft" + left="2" + top="2" + right="-2" + bottom="-2" + background_visible="true" + bg_alpha_color="DkGray2" + border="true"> + <asset_filtered_inv_panel + left="0" + top="0" + right="-1" + bottom="-1" + allow_multi_select="false" + follows="all" + layout="topleft" + name="pnl_settings" + filter_asset_type="settings"/> + </panel> + </layout_panel> + <layout_panel + auto_resize="false" + user_resize="false" + tab_group="1" + height="15"> + <check_box + follows="left|bottom" + height="14" + initial_value="false" + label="Show All Folders" + layout="topleft" + name="chk_showfolders" + top="2" + left_delta="-1" + width="200" /> + </layout_panel> + <layout_panel + auto_resize="false" + tab_group="1" + height="31" + name="pnl_control" + font="SansSerifBold"> + <panel + background_visible="true" + bevel_style="none" + top_pad="1" + follows="top|left|right" + height="30" + label="bottom_panel" + layout="topleft" + left="0" + name="pnl_bottom"> + <menu_button + follows="bottom|left" + height="18" + image_disabled="OptionsMenu_Disabled" + image_selected="OptionsMenu_Press" + image_unselected="OptionsMenu_Off" + layout="topleft" + left="10" + menu_filename="menu_settings_gear.xml" + name="btn_gear" + top="5" + tool_tip="More options" + width="18" /> + <menu_button + follows="bottom|left" + font="SansSerifBigBold" + height="18" + image_selected="AddItem_Press" + image_unselected="AddItem_Off" + image_disabled="AddItem_Disabled" + layout="topleft" + left_pad="5" + menu_filename="menu_settings_add.xml" + name="btn_newsettings" + tool_tip="Make new setting" + top_delta="0" + width="18" /> + <button + follows="bottom|right" + font="SansSerifBigBold" + height="18" + image_selected="TrashItem_Press" + image_unselected="TrashItem_Off" + image_disabled="TrashItem_Disabled" + layout="topleft" + name="btn_del" + right="-5" + tool_tip="Remove selected item" + top_delta="0" + width="18" /> + </panel> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_my_scripts.xml b/indra/newview/skins/default/xui/en/floater_my_scripts.xml index 3b0b6723c7..ee6defce9d 100644 --- a/indra/newview/skins/default/xui/en/floater_my_scripts.xml +++ b/indra/newview/skins/default/xui/en/floater_my_scripts.xml @@ -7,7 +7,7 @@ layout="topleft" name="myscripts" save_rect="true" - title="My Scripts" + title="ATTACHMENT SCRIPTS" min_width="620" width="620"> <panel diff --git a/indra/newview/skins/default/xui/en/floater_people.xml b/indra/newview/skins/default/xui/en/floater_people.xml index 701233ba4a..0cc0ca1ce4 100644 --- a/indra/newview/skins/default/xui/en/floater_people.xml +++ b/indra/newview/skins/default/xui/en/floater_people.xml @@ -31,5 +31,11 @@ filename="panel_group_info_sidetray.xml" label="Group Profile" font="SansSerifBold"/> + <panel + class="panel_group_creation_sidetray" + name="panel_group_creation_sidetray" + filename="panel_group_creation_sidetray.xml" + label="Create Group" + font="SansSerifBold"/> </panel_container> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_perms_default.xml b/indra/newview/skins/default/xui/en/floater_perms_default.xml index 1c3af49bfe..49dc719a24 100644 --- a/indra/newview/skins/default/xui/en/floater_perms_default.xml +++ b/indra/newview/skins/default/xui/en/floater_perms_default.xml @@ -488,6 +488,67 @@ left_pad="0" top_delta="0" width="100" /> + <text + name="label_13" + type="string" + length="1" + follows="left|top" + height="16" + layout="topleft" + left="0" + tool_tip="Set default permissions for when Environment settings are created" + width="100"> + Settings + </text> + <icon + follows="left|top" + height="16" + image_name="Inv_Settings" + layout="topleft" + left_pad="2" + width="18"/> + <check_box + height="16" + layout="topleft" + name="env_settings_c" + left_pad="45" + top_delta="0" + value="true" + enabled="false" + width="100"> + </check_box> + <check_box + control_name="SettingsNextOwnerModify" + height="16" + layout="topleft" + name="env_settings_m" + left_pad="0" + top_delta="0" + width="100" /> + <check_box + control_name="SettingsNextOwnerTransfer" + height="16" + layout="topleft" + name="env_settings_t" + left_pad="0" + top_delta="0" + width="100" /> + <check_box + enabled="false" + height="16" + layout="topleft" + name="env_settings_s" + left_pad="0" + top_delta="0" + width="120" /> + <check_box + enabled="false" + height="16" + layout="topleft" + name="env_settings_e" + left_pad="0" + top_delta="0" + width="100" /> </panel> <button height="20" diff --git a/indra/newview/skins/default/xui/en/floater_pick_track.xml b/indra/newview/skins/default/xui/en/floater_pick_track.xml new file mode 100644 index 0000000000..d8a9877be2 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_pick_track.xml @@ -0,0 +1,129 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> + +<floater + legacy_header_height="0" + can_minimize="false" + can_resize="true" + height="140" + layout="topleft" + min_height="140" + min_width="225" + name="track picker" + help_topic="track_picker" + title="PICK: TRACK" + width="225"> + <layout_stack name="adjuster" + follows="all" + animate="false" + top="0" + left="6" + right="-6" + bottom="-10" + orientation="vertical"> + <layout_panel name="pnl_desc" + border="false" + auto_resize="false" + user_resize="false" + height="11" + min_height="10" + bg_alpha_color="blue" + background_visible="false"> + <text + type="string" + length="1" + follows="left|top" + height="10" + layout="topleft" + left="5" + name="select_description" + mouse_opaque="false" + top="0" + width="300"> + Select source sky: + </text> + </layout_panel> + <layout_panel name="pnl_traks" + border="false" + auto_resize="true" + user_resize="false" + height="29" + min_height="29" + bg_alpha_color="blue" + background_visible="false"> + <radio_group + follows="all" + height="60" + layout="topleft" + top="0" + left="3" + right="-3" + bottom="-3" + name="track_selection" + width="100"> + <radio_item + height="20" + label="Sky4 [ALT]" + layout="topleft" + left="0" + name="radio_sky4" + value="4" + top="0" + width="90" /> + <radio_item + height="20" + label="Sky3 [ALT]" + layout="topleft" + left="0" + name="radio_sky3" + value="3" + top_delta="20" + width="90" /> + <radio_item + height="20" + label="Sky2 [ALT]" + layout="topleft" + left="0" + name="radio_sky2" + value="2" + top_delta="20" + width="90" /> + <radio_item + height="20" + label="Ground" + layout="topleft" + left="0" + name="radio_sky1" + value="1" + top_delta="20" + width="90" /> + </radio_group> + </layout_panel> + <layout_panel name="pnl_ok_cancel" + border="false" + auto_resize="false" + user_resize="false" + height="29" + min_height="29"> + <button + follows="top|left" + height="20" + label="OK" + label_selected="OK" + layout="topleft" + left="2" + top="2" + name="btn_select" + width="100" /> + <button + follows="top|left" + height="20" + label="Cancel" + label_selected="Cancel" + layout="topleft" + left_delta="110" + top_delta="0" + name="btn_cancel" + width="100" /> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml index 0e62d50072..ee730dcb01 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences.xml @@ -169,6 +169,13 @@ https://accounts.secondlife.com/change_email/ layout="topleft" help_topic="preferences_uploads_tab" name="uploads" /> + <panel + class="panel_preference_controls" + filename="panel_preferences_controls.xml" + label="Controls" + layout="topleft" + help_topic="preferences_controls_tab" + name="controls" /> </tab_container> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml index bec484a5ea..7786ba8a1c 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml @@ -596,7 +596,10 @@ left="420" name="TransparentWater" top_delta="16" - width="300" /> + width="300"> + <check_box.commit_callback + function="Pref.RenderOptionUpdate" /> + </check_box> <check_box control_name="RenderObjectBump" @@ -609,7 +612,7 @@ top_delta="16" width="300"> <check_box.commit_callback - function="Pref.VertexShaderEnable" /> + function="Pref.RenderOptionUpdate" /> </check_box> <check_box @@ -623,21 +626,6 @@ top_delta="16" width="300" /> - <check_box - control_name="VertexShaderEnable" - height="16" - initial_value="true" - label="Basic shaders" - layout="topleft" - left="420" - name="BasicShaders" - tool_tip="Disabling this option may prevent some graphics card drivers from crashing" - top_delta="16" - width="300"> - <check_box.commit_callback - function="Pref.VertexShaderEnable" /> - </check_box> - <slider control_name="RenderTerrainDetail" follows="left|top" @@ -683,7 +671,7 @@ top_delta="16" width="280"> <check_box.commit_callback - function="Pref.VertexShaderEnable" /> + function="Pref.RenderOptionUpdate" /> </check_box> <check_box @@ -719,6 +707,14 @@ name="Reflections" width="150"> <combo_box.item + label="None; opaque" + name="0" + value="-2"/> + <combo_box.item + label="None; transparent" + name="0" + value="-1"/> + <combo_box.item label="Minimal" name="0" value="0"/> @@ -751,7 +747,7 @@ top_delta="16" width="280"> <check_box.commit_callback - function="Pref.VertexShaderEnable" /> + function="Pref.RenderOptionUpdate" /> </check_box> <slider @@ -800,7 +796,7 @@ top_delta="16" width="260"> <check_box.commit_callback - function="Pref.VertexShaderEnable" /> + function="Pref.RenderOptionUpdate" /> </check_box> <check_box @@ -814,7 +810,7 @@ top_delta="16" width="240"> <check_box.commit_callback - function="Pref.VertexShaderEnable" /> + function="Pref.RenderOptionUpdate" /> </check_box> <check_box @@ -828,8 +824,24 @@ top_delta="16" width="240"> <check_box.commit_callback - function="Pref.VertexShaderEnable" /> + function="Pref.RenderOptionUpdate" /> + </check_box> + + <!-- + <check_box + control_name="RenderUseAdvancedAtmospherics" + height="16" + initial_value="true" + label="Advanced Atmospherics" + layout="topleft" + left="480" + name="UseAdvancedAtmo" + top_delta="16" + width="240"> + <check_box.commit_callback + function="Pref.AdvancedAtmosphericsEnable" /> </check_box> + --> <text type="string" diff --git a/indra/newview/skins/default/xui/en/floater_preferences_view_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_view_advanced.xml new file mode 100644 index 0000000000..4c3c7e4930 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_preferences_view_advanced.xml @@ -0,0 +1,156 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + height="190" + layout="topleft" + name="floaterpreferencesviewadvanced" + help_topic="floaterviewadvanced" + title="CAMERA POSITION" + save_rect="true" + width="280"> + + <text + follows="top|left|right" + name="camera_offset_lbl" + height="16" + layout="topleft" + left="10" + top="10" + width="100"> + Camera offset: + </text> + + <spinner + height="20" + label="X" + label_width="12" + follows="top|left" + left="10" + name="camera_x" + top_pad="5" + min_val="-1e+007" + max_val="1e+007" + width="70"> + <spinner.commit_callback + function="CommitSettings" /> + </spinner> + + <spinner + height="20" + label="Y" + label_width="12" + follows="top|left" + name="camera_y" + left_pad="20" + min_val="-1e+007" + max_val="1e+007" + width="70"> + <spinner.commit_callback + function="CommitSettings" /> + </spinner> + + <spinner + height="20" + label="Z" + label_width="12" + follows="top|left" + name="camera_z" + left_pad="20" + min_val="-1e+007" + max_val="1e+007" + width="70"> + <spinner.commit_callback + function="CommitSettings" /> + </spinner> + + <text + follows="top|left|right" + name="focus_offset_lbl" + height="16" + layout="topleft" + left="10" + top_pad="20" + width="100"> + Focus offset: + </text> + + <spinner + height="20" + label="X" + label_width="12" + follows="top|left" + left="10" + name="focus_x" + top_pad="5" + min_val="-1e+007" + max_val="1e+007" + width="70"> + <spinner.commit_callback + function="CommitSettings" /> + </spinner> + + <spinner + height="20" + label="Y" + label_width="12" + follows="top|left" + name="focus_y" + left_pad="20" + min_val="-1e+007" + max_val="1e+007" + width="70"> + <spinner.commit_callback + function="CommitSettings" /> + </spinner> + + <spinner + height="20" + label="Z" + label_width="12" + follows="top|left" + name="focus_z" + left_pad="20" + min_val="-1e+007" + max_val="1e+007" + width="70"> + <spinner.commit_callback + function="CommitSettings" /> + </spinner> + + <text + follows="top|left|right" + name="offset_scale_lbl" + height="16" + layout="topleft" + left="10" + top_pad="20" + width="140"> + Camera offset scale: + </text> + + <slider + control_name="CameraOffsetScale" + follows="top|left|right" + height="16" + top_pad="5" + increment="0.1" + min_val="-3" + max_val="5" + show_text="false" + layout="topleft" + left="3" + name="offset_scale_sld" + width="196" /> + <spinner + control_name="CameraOffsetScale" + height="20" + follows="top|left|right" + left_pad="5" + name="offset_scale_ctrl" + min_val="-3" + max_val="5" + width="58"> + <spinner.commit_callback + function="CommitSettings" /> + </spinner> + +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_preview_trash.xml b/indra/newview/skins/default/xui/en/floater_preview_trash.xml index 9e50e89ac9..3fa71e7bfe 100644 --- a/indra/newview/skins/default/xui/en/floater_preview_trash.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_trash.xml @@ -14,7 +14,7 @@ reuse_instance="true" can_minimize="false"> <inventory_panel - name="inventory_outbox" + name="inventory_trash" start_folder.name="Trash" show_empty_message="false" start_folder.type="trash" diff --git a/indra/newview/skins/default/xui/en/floater_publish_classified.xml b/indra/newview/skins/default/xui/en/floater_publish_classified.xml index 322e34272c..84e0b489d0 100644 --- a/indra/newview/skins/default/xui/en/floater_publish_classified.xml +++ b/indra/newview/skins/default/xui/en/floater_publish_classified.xml @@ -6,6 +6,7 @@ layout="topleft" name="publish_classified" title="Publishing Classified" + help_topic="profile_edit_classified" width="320"> <text top="20" diff --git a/indra/newview/skins/default/xui/en/floater_save_camera_preset.xml b/indra/newview/skins/default/xui/en/floater_save_camera_preset.xml new file mode 100644 index 0000000000..54fdb6d167 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_save_camera_preset.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8"?> +<floater + legacy_header_height="18" + height="185" + help_topic="floater_save_preset" + layout="topleft" + name="save_camera_preset" + save_rect="true" + title="Save Camera Preset" + width="280"> + + <string name="btn_label_save">Save</string> + <string name="btn_label_replace">Replace</string> + <radio_group + height="85" + layout="topleft" + left="20" + top="15" + width="150" + name="radio_save_preset"> + <radio_item + label="Save as a new preset" + name="new_preset" + top="10" + layout="topleft" + height="16" + value="0"/> + <radio_item + label="Replace a preset" + name="replace_preset" + layout="topleft" + top="70" + height="16" + value="1"/> + </radio_group> + <line_editor + commit_on_focus_lost = "true" + follows="top|left" + height="23" + layout="topleft" + left="41" + name="preset_txt_editor" + width="200" + top="45"/> + <button + follows="top|left" + height="25" + label="Save" + layout="topleft" + top="145" + left="25" + name="save" + width="110"/> + <button + follows="bottom|right" + height="25" + label="Cancel" + layout="topleft" + left_pad="20" + name="cancel" + width="110"/> +<!-- *HACK to correctly draw drop-down list over the buttons--> + <combo_box + follows="top|left" + layout="topleft" + left="41" + name="preset_combo" + top_delta="-40" + width="200"/> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_save_pref_preset.xml b/indra/newview/skins/default/xui/en/floater_save_pref_preset.xml index 7dee28eff3..62260274f5 100644 --- a/indra/newview/skins/default/xui/en/floater_save_pref_preset.xml +++ b/indra/newview/skins/default/xui/en/floater_save_pref_preset.xml @@ -4,14 +4,11 @@ height="145" help_topic="floater_save_preset" layout="topleft" - name="Save Pref Preset" + name="save_pref_preset" save_rect="true" - title="SAVE PREF PRESET" + title="Save Graphic Preset" width="300"> - <string name="title_graphic">Save Graphic Preset</string> - <string name="title_camera">Save Camera Preset</string> - <text follows="top|left|right" height="32" diff --git a/indra/newview/skins/default/xui/en/floater_script_debug.xml b/indra/newview/skins/default/xui/en/floater_script_debug.xml index cd88048d6b..6c49cfa1a8 100644 --- a/indra/newview/skins/default/xui/en/floater_script_debug.xml +++ b/indra/newview/skins/default/xui/en/floater_script_debug.xml @@ -17,5 +17,6 @@ name="Preview Tabs" tab_position="bottom" top="16" - width="448" /> + width="448" + enable_tabs_flashing="true"/> </multi_floater> diff --git a/indra/newview/skins/default/xui/en/floater_select_key.xml b/indra/newview/skins/default/xui/en/floater_select_key.xml index 4e89df5a73..48d9eee4cd 100644 --- a/indra/newview/skins/default/xui/en/floater_select_key.xml +++ b/indra/newview/skins/default/xui/en/floater_select_key.xml @@ -4,10 +4,27 @@ border="false" can_close="false" can_minimize="false" - height="90" + height="116" layout="topleft" name="modal container" - width="240"> + width="272"> + <floater.string + name="keyboard"> + Keyboard + </floater.string> + <floater.string + name="mouse"> + Mouse Buttons + </floater.string> + <floater.string + name="basic_description"> +Press a key to set your trigger. +Allowed input: [INPUT]. + </floater.string> + <floater.string + name="reserved_by_menu"> +Combination [KEYSTR] is reserved by menu. + </floater.string> <text type="string" halign="center" @@ -16,19 +33,47 @@ height="30" layout="topleft" left="30" - name="Save item as:" + name="descritption" top="25" word_wrap="true" - width="180"> - Press a key to set your Speak button trigger. + width="212"> +Press a key to set your trigger. +Allowed input: [INPUT]. </text> + <check_box + follows="top|left" + height="20" + initial_value="false" + label="Apply to all" + layout="topleft" + left="90" + name="apply_all" + tool_tip="Viewer uses different control combinations depending on what you are doing in world, setting this will apply your change to all combinations" + top_pad="8" + width="160" /> + + <button + height="23" + label="Set Empty" + layout="topleft" + left="8" + name="SetEmpty" + top_pad="6" + width="80" /> + <button + height="23" + label="Default" + layout="topleft" + left_pad="8" + name="Default" + top_delta="0" + width="80" /> <button height="23" label="Cancel" - label_selected="Cancel" layout="topleft" - right="-10" + left_pad="8" name="Cancel" - top_pad="8" - width="100" /> + top_delta="0" + width="80" /> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_settings_picker.xml b/indra/newview/skins/default/xui/en/floater_settings_picker.xml new file mode 100644 index 0000000000..3a26c3b547 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_settings_picker.xml @@ -0,0 +1,152 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + can_minimize="false" + can_resize="true" + height="330" + layout="topleft" + min_height="330" + min_width="225" + name="settings picker" + help_topic="settings_picker" + title="PICK: SETTINGS" + width="225"> + + <!-- top static --> + <floater.string + name="pick title"> + Pick: + </floater.string> + <floater.string + name="pick_track"> + SELECT TRACK + </floater.string> + <floater.string + name="pick_settings"> + SELECT SETTINGS + </floater.string> + + <floater.string + name="track_water"> + Water + </floater.string> + <floater.string + name="track_ground"> + Ground + </floater.string> + <floater.string + name="track_sky"> + Sky[NUM] + </floater.string> + + <layout_stack name="test_stack" + follows="all" + animate="false" + top="20" + left="6" + right="-6" + bottom="-10" + orientation="vertical"> + <layout_panel name="inv_list" + border="false" + auto_resize="true" + user_resize="false" + height="29" + min_height="29" + bg_alpha_color="blue" + background_visible="false"> + <filter_editor + follows="left|top|right" + height="23" + label="Filter Settings" + layout="topleft" + left="4" + name="flt_inventory_search" + top="4" + right="-2" /> + <panel + name="pnl_inv_wrap" + follows="all" + layout="topleft" + left="2" + top="28" + right="-2" + bottom="-2" + background_visible="true" + bg_alpha_color="DkGray2"> + <asset_filtered_inv_panel + allow_multi_select="false" + allow_drag="false" + accepts_drag_and_drop="false" + suppress_folder_menu="true" + bg_visible="true" + bg_alpha_color="DkGray2" + border="false" + follows="all" + layout="topleft" + left_delta="0" + name="pnl_inventory" + top="1" + right="-4" + bottom="-1" + filter_asset_type="settings" /> + </panel> + </layout_panel> + <layout_panel name="pnl_combo" + border="false" + auto_resize="false" + user_resize="false" + visible="true" + height="29" + bg_alpha_color="blue" + background_visible="false"> + <combo_box + allow_text_entry="false" + follows="left|top" + height="23" + left="10" + max_chars="100" + mouse_opaque="true" + name="track_selection" + enabled="false" + top="1" + width="190"/> + </layout_panel> + <layout_panel name="temp" + border="false" + auto_resize="false" + user_resize="false" + height="29" + min_height="29"> + <button + follows="top|left" + height="20" + label="OK" + label_selected="OK" + layout="topleft" + left="2" + top="2" + name="btn_select" + width="100" /> + <button + follows="top|left" + height="20" + label="Cancel" + label_selected="Cancel" + layout="topleft" + left_delta="110" + top_delta="0" + name="btn_cancel" + width="100" /> + </layout_panel> + </layout_stack> + + <!-- middle: inventory mode --> + <!-- + + +--> + <!-- bottom static --> + <!-- + --> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_sound_preview.xml b/indra/newview/skins/default/xui/en/floater_sound_preview.xml index af791466b6..3889b975a9 100644 --- a/indra/newview/skins/default/xui/en/floater_sound_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_sound_preview.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater legacy_header_height="18" - height="190" + height="180" layout="topleft" name="Sound Preview" help_topic="sound_preview" @@ -60,9 +60,9 @@ height="22" label="Upload (L$[AMOUNT])" layout="topleft" - left="45" + left="35" name="ok_btn" - top_pad="60" + top_pad="15" width="150" /> <button follows="right|bottom" @@ -73,4 +73,17 @@ name="cancel_btn" left_pad="5" width="90" /> + <text + type="string" + length="1" + follows="left|top" + height="35" + layout="topleft" + left="10" + mouse_opaque="false" + skip_link_underline="true" + name="info_text" + word_wrap="true" + top_pad="10" + width="270"/> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_test_layout_stacks.xml b/indra/newview/skins/default/xui/en/floater_test_layout_stacks.xml index a04050e7eb..a3ed22f422 100644 --- a/indra/newview/skins/default/xui/en/floater_test_layout_stacks.xml +++ b/indra/newview/skins/default/xui/en/floater_test_layout_stacks.xml @@ -1,226 +1,226 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater - can_resize="true" - can_close="true" - bevel_style="in" - height="300" - layout="topleft" - min_height="40" - min_width="420" - name="Test Floater" - title="LAYOUTSTACK TESTS" - width="420"> - <layout_stack name="test_stack" - left="0" - top="0" - width="100" - height="250" - follows="left|top|bottom" - orientation="vertical"> - <layout_panel name="flex" - auto_resize="true" - user_resize="true" - bg_alpha_color="blue" - height="11" - min_height="0" - background_visible="true"> - <text follows="top|left|right" halign="center" text_color="white">flex</text> - </layout_panel> - <layout_panel name="flex" - auto_resize="true" - user_resize="true" - bg_alpha_color="blue" - height="11" - min_height="0" - visible="false" - background_visible="true"> - <text follows="top|left|right" halign="center" text_color="white">flex</text> - </layout_panel> - <layout_panel name="flex" - auto_resize="true" - user_resize="true" - bg_alpha_color="blue" - height="11" - min_height="0" - visible="true" - background_visible="true"> - <text follows="top|left|right" halign="center" text_color="white">flex</text> - </layout_panel> - <layout_panel name="flex" - auto_resize="true" - user_resize="true" - bg_alpha_color="blue" - height="11" - min_height="0" - background_visible="true"> - <text follows="top|left|right" halign="center" text_color="white">flex</text> - </layout_panel> - </layout_stack> - <layout_stack name="test_stack" - left_pad="5" - top="0" - width="100" - height="250" - follows="left|top|bottom" - orientation="vertical"> - <layout_panel name="flex" - auto_resize="true" - user_resize="true" - bg_alpha_color="blue" - height="100" - background_visible="true"> - <text follows="top|left|right" halign="center" text_color="white">flex</text> - </layout_panel> - <layout_panel name="flex" - auto_resize="true" - user_resize="true" - visible="false" - bg_alpha_color="blue" - height="100" - background_visible="true"> - <text follows="top|left|right" halign="center" text_color="white">flex</text> - </layout_panel> - <layout_panel name="fixed" - auto_resize="false" - user_resize="true" - height="50" - min_height="10" - bg_alpha_color="green" - background_visible="true"> - <text follows="top|left|right" halign="center" text_color="black">fixed</text> - </layout_panel> - <layout_panel name="fixed" + can_resize="true" + can_close="true" + bevel_style="in" + height="300" + layout="topleft" + min_height="40" + min_width="420" + name="Test Floater" + title="LAYOUTSTACK TESTS" + width="420"> + <layout_stack name="test_stack" + left="0" + top="0" + width="100" + height="250" + follows="left|top|bottom" + orientation="vertical"> + <layout_panel name="flex" + auto_resize="true" + user_resize="true" + bg_alpha_color="blue" + height="11" + min_height="0" + background_visible="true"> + <text follows="top|left|right" halign="center" text_color="white">flex</text> + </layout_panel> + <layout_panel name="flex" + auto_resize="true" + user_resize="true" + bg_alpha_color="blue" + height="11" + min_height="0" + visible="false" + background_visible="true"> + <text follows="top|left|right" halign="center" text_color="white">flex</text> + </layout_panel> + <layout_panel name="flex" + auto_resize="true" + user_resize="true" + bg_alpha_color="blue" + height="11" + min_height="0" + visible="true" + background_visible="true"> + <text follows="top|left|right" halign="center" text_color="white">flex</text> + </layout_panel> + <layout_panel name="flex" + auto_resize="true" + user_resize="true" + bg_alpha_color="blue" + height="11" + min_height="0" + background_visible="true"> + <text follows="top|left|right" halign="center" text_color="white">flex</text> + </layout_panel> + </layout_stack> + <layout_stack name="test_stack" + left_pad="5" + top="0" + width="100" + height="250" + follows="left|top|bottom" + orientation="vertical"> + <layout_panel name="flex" + auto_resize="true" + user_resize="true" + bg_alpha_color="blue" + height="100" + background_visible="true"> + <text follows="top|left|right" halign="center" text_color="white">flex</text> + </layout_panel> + <layout_panel name="flex" + auto_resize="true" + user_resize="true" + visible="false" + bg_alpha_color="blue" + height="100" + background_visible="true"> + <text follows="top|left|right" halign="center" text_color="white">flex</text> + </layout_panel> + <layout_panel name="fixed" + auto_resize="false" + user_resize="true" + height="50" + min_height="10" + bg_alpha_color="green" + background_visible="true"> + <text follows="top|left|right" halign="center" text_color="black">fixed</text> + </layout_panel> + <layout_panel name="fixed" auto_resize="false" - user_resize="true" + user_resize="true" height="50" min_height="10" bg_alpha_color="green" background_visible="true"> - <text follows="top|left|right" halign="center" text_color="black">fixed</text> - </layout_panel> - <layout_panel name="flex" - auto_resize="true" - user_resize="true" - bg_alpha_color="blue" - height="100" - background_visible="true"> - <text follows="top|left|right" halign="center" text_color="white">flex</text> - </layout_panel> - <layout_panel name="flex" - auto_resize="true" - user_resize="true" - bg_alpha_color="blue" - height="100" - background_visible="true"> - <text follows="top|left|right" halign="center" text_color="white">flex</text> - </layout_panel> - <layout_panel name="flex" - auto_resize="true" - user_resize="true" - bg_alpha_color="blue" - height="100" - background_visible="true"> - <text follows="top|left|right" halign="center" text_color="white">flex</text> - </layout_panel> - <layout_panel name="flex" - auto_resize="true" - user_resize="true" - bg_alpha_color="blue" - height="100" - visible="true" - background_visible="true"> - <text follows="top|left|right" halign="center" text_color="white">flex</text> - </layout_panel> - </layout_stack> - <layout_stack name="test_stack" - left_pad="5" - top="0" - width="100" - height="250" - follows="left|top|bottom" - orientation="vertical"> - <layout_panel name="flex" - auto_resize="true" - user_resize="true" - height="11" - bg_alpha_color="blue" - background_visible="true"> - <text follows="top|left|right" halign="center" text_color="white">flex</text> - </layout_panel> - <layout_panel name="fixed" + <text follows="top|left|right" halign="center" text_color="black">fixed</text> + </layout_panel> + <layout_panel name="flex" + auto_resize="true" + user_resize="true" + bg_alpha_color="blue" + height="100" + background_visible="true"> + <text follows="top|left|right" halign="center" text_color="white">flex</text> + </layout_panel> + <layout_panel name="flex" + auto_resize="true" + user_resize="true" + bg_alpha_color="blue" + height="100" + background_visible="true"> + <text follows="top|left|right" halign="center" text_color="white">flex</text> + </layout_panel> + <layout_panel name="flex" + auto_resize="true" + user_resize="true" + bg_alpha_color="blue" + height="100" + background_visible="true"> + <text follows="top|left|right" halign="center" text_color="white">flex</text> + </layout_panel> + <layout_panel name="flex" + auto_resize="true" + user_resize="true" + bg_alpha_color="blue" + height="100" + visible="true" + background_visible="true"> + <text follows="top|left|right" halign="center" text_color="white">flex</text> + </layout_panel> + </layout_stack> + <layout_stack name="test_stack" + left_pad="5" + top="0" + width="100" + height="250" + follows="left|top|bottom" + orientation="vertical"> + <layout_panel name="flex" + auto_resize="true" + user_resize="true" + height="11" + bg_alpha_color="blue" + background_visible="true"> + <text follows="top|left|right" halign="center" text_color="white">flex</text> + </layout_panel> + <layout_panel name="fixed" auto_resize="false" - user_resize="true" + user_resize="true" height="50" bg_alpha_color="green" background_visible="true"> - <text follows="top|left|right" halign="center" text_color="black">fixed</text> - </layout_panel> - <layout_panel name="flex" - auto_resize="true" - user_resize="true" - bg_alpha_color="blue" - height="11" - background_visible="true"> - <text follows="top|left|right" halign="center" text_color="white">flex</text> - </layout_panel> - </layout_stack> - <layout_stack name="test_stack" - left_pad="5" - top="0" - width="100" - height="250" - follows="left|top|bottom" - orientation="vertical"> - <layout_panel name="fixed" + <text follows="top|left|right" halign="center" text_color="black">fixed</text> + </layout_panel> + <layout_panel name="flex" + auto_resize="true" + user_resize="true" + bg_alpha_color="blue" + height="11" + background_visible="true"> + <text follows="top|left|right" halign="center" text_color="white">flex</text> + </layout_panel> + </layout_stack> + <layout_stack name="test_stack" + left_pad="5" + top="0" + width="100" + height="250" + follows="left|top|bottom" + orientation="vertical"> + <layout_panel name="fixed" auto_resize="false" - user_resize="true" + user_resize="true" height="50" bg_alpha_color="green" background_visible="true"> - <text follows="top|left|right" halign="center" text_color="black">fixed</text> - </layout_panel> - <layout_panel name="fixed" + <text follows="top|left|right" halign="center" text_color="black">fixed</text> + </layout_panel> + <layout_panel name="fixed" auto_resize="false" - user_resize="true" + user_resize="true" height="50" bg_alpha_color="green" background_visible="true"> - <text follows="top|left|right" halign="center" text_color="black">fixed</text> - </layout_panel> - <layout_panel name="fixed" + <text follows="top|left|right" halign="center" text_color="black">fixed</text> + </layout_panel> + <layout_panel name="fixed" auto_resize="false" - user_resize="true" + user_resize="true" height="50" bg_alpha_color="green" background_visible="true"> - <text follows="top|left|right" halign="center" text_color="black">fixed</text> - </layout_panel> - <layout_panel name="flex" - auto_resize="true" - user_resize="true" - bg_alpha_color="blue" - height="11" - min_height="0" - background_visible="true"> - <text follows="top|left|right" halign="center" text_color="white">flex</text> - </layout_panel> - <layout_panel name="flex" - auto_resize="true" - user_resize="true" - bg_alpha_color="blue" - height="11" - min_height="0" - background_visible="true"> - <text follows="top|left|right" halign="center" text_color="white">flex</text> - </layout_panel> - <layout_panel name="flex" - auto_resize="true" - user_resize="true" - bg_alpha_color="blue" - height="11" - min_height="0" - background_visible="true"> - <text follows="top|left|right" halign="center" text_color="white">flex</text> - </layout_panel> - </layout_stack> + <text follows="top|left|right" halign="center" text_color="black">fixed</text> + </layout_panel> + <layout_panel name="flex" + auto_resize="true" + user_resize="true" + bg_alpha_color="blue" + height="11" + min_height="0" + background_visible="true"> + <text follows="top|left|right" halign="center" text_color="white">flex</text> + </layout_panel> + <layout_panel name="flex" + auto_resize="true" + user_resize="true" + bg_alpha_color="blue" + height="11" + min_height="0" + background_visible="true"> + <text follows="top|left|right" halign="center" text_color="white">flex</text> + </layout_panel> + <layout_panel name="flex" + auto_resize="true" + user_resize="true" + bg_alpha_color="blue" + height="11" + min_height="0" + background_visible="true"> + <text follows="top|left|right" halign="center" text_color="white">flex</text> + </layout_panel> + </layout_stack> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml index d122d7491c..3a66911389 100644 --- a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml @@ -48,42 +48,28 @@ </text> <!-- mode selector --> - <radio_group + <combo_box control_name="mode_selection" height="20" layout="topleft" - left="0" - top_pad="80" + left="6" + top_pad="77" name="mode_selection" - follows="left|top"> - <radio_item + follows="left|top" + width="120"> + <combo_box.item label="Inventory" name="inventory" - top_delta="20" - layout="topleft" - height="16" - left="0" - value="0" - width="70" /> - <radio_item + value="0" /> + <combo_box.item label="Local" - left_pad="0" - layout="topleft" - top_delta="0" - height="16" name="local" - value="1" - width="50" /> - <radio_item + value="1" /> + <combo_box.item label="Bake" - left_pad="0" - layout="topleft" - top_delta="0" - height="16" name="bake" - value="2" - width="50" /> - </radio_group> + value="2" /> + </combo_box> <!-- --> <text @@ -92,12 +78,11 @@ follows="left|top" height="14" layout="topleft" - left_delta="12" - name="unknown" + left="8" + name="size_lbl" top_pad="4"> - Size: [DIMENSIONS] + [DIMENSIONS] </text> - <!-- middle: inventory mode --> <button @@ -138,20 +123,21 @@ image_selected="eye_button_active.tga" image_unselected="eye_button_inactive.tga" layout="topleft" - left_delta="-80" - top_delta="-25" + left="18" + top_delta="-23" name="Pipette" width="28" /> <text follows="left|bottom" - height="20" + height="40" layout="topleft" left="8" name="preview_disabled" - top="266" + top="285" value="Preview Disabled" + word_wrap="true" visible="false" - width="120" /> + width="87" /> <filter_editor follows="left|top|right" height="23" @@ -161,7 +147,7 @@ name="inventory search editor" top="20" width="231" /> - <inventory_panel + <asset_filtered_inv_panel allow_multi_select="false" bg_visible="true" bg_alpha_color="DkGray2" @@ -172,7 +158,8 @@ left_delta="0" name="inventory panel" top_pad="4" - width="231" /> + width="231" + filter_asset_type="texture"/> <check_box height="14" initial_value="false" @@ -301,7 +288,8 @@ height="20" initial_value="false" label="Hide Base Mesh Region" - layout="topleft" + +layout="topleft" name="hide_base_mesh_region" left_delta="0" top_pad="10" @@ -315,7 +303,7 @@ label="OK" label_selected="OK" layout="topleft" - left="95" + left="176" top="-30" name="Select" width="100" /> @@ -338,5 +326,5 @@ left="6" name="apply_immediate_check" top_delta="0" - width="120" /> + width="150" /> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_twitter.xml b/indra/newview/skins/default/xui/en/floater_twitter.xml deleted file mode 100644 index 5e8dfb8a52..0000000000 --- a/indra/newview/skins/default/xui/en/floater_twitter.xml +++ /dev/null @@ -1,75 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<floater - positioning="cascading" - can_close="true" - can_resize="false" - help_topic="floater_twitter" - layout="topleft" - name="floater_twitter" - save_rect="true" - single_instance="true" - reuse_instance="true" - title="TWITTER" - height="462" - width="272"> - <tab_container - name="tabs" - tab_group="1" - tab_min_width="70" - tab_height="21" - tab_position="top" - top="7" - height="457" - halign="center"> - <panel - filename="panel_twitter_photo.xml" - class="lltwitterphotopanel" - follows="all" - label="COMPOSE" - name="panel_twitter_photo"/> - <panel - filename="panel_twitter_account.xml" - class="lltwitteraccountpanel" - follows="all" - label="ACCOUNT" - name="panel_twitter_account"/> - </tab_container> - <text - name="connection_error_text" - type="string" - follows="left|bottom|right" - bottom="-5" - left="10" - width="252" - height="20" - wrap="true" - halign="left" - valign="center" - text_color="DrYellow" - font="SansSerif"> - Error - </text> - <loading_indicator - follows="left|bottom|right" - height="24" - width="24" - name="connection_loading_indicator" - top_delta="-2" - left="10" - visible="true"/> - <text - name="connection_loading_text" - type="string" - follows="left|bottom|right" - top_delta="2" - left_pad="5" - width="223" - height="20" - wrap="true" - halign="left" - valign="center" - text_color="EmphasisColor" - font="SansSerif"> - Loading... - </text> -</floater> diff --git a/indra/newview/skins/default/xui/en/floater_url_entry.xml b/indra/newview/skins/default/xui/en/floater_url_entry.xml index 29fb29fabf..2dfc0fd125 100644 --- a/indra/newview/skins/default/xui/en/floater_url_entry.xml +++ b/indra/newview/skins/default/xui/en/floater_url_entry.xml @@ -66,7 +66,7 @@ layout="topleft" left="152" name="loading_label" - visible="true"> + visible="false"> Loading... </text> </floater> diff --git a/indra/newview/skins/default/xui/en/fonts.xml b/indra/newview/skins/default/xui/en/fonts.xml index 6df666a700..ed35546322 100644 --- a/indra/newview/skins/default/xui/en/fonts.xml +++ b/indra/newview/skins/default/xui/en/fonts.xml @@ -13,6 +13,7 @@ <file>msyh.ttc</file> <file load_collection="true">Cambria.ttc</file> <file>malgun.ttf</file> + <file>micross.ttf</file> </os> <os name="Mac"> <file>ヒラギノ角ゴシック W3.ttc</file> @@ -22,9 +23,11 @@ <file>AppleGothic.dfont</file> <file>AppleGothic.ttf</file> <file>AppleSDGothicNeo-Regular.otf</file> + <file>AppleSDGothicNeo.ttc</file> <file>åŽæ–‡ç»†é»‘.ttf</file> <file>PingFang.ttc</file> <file>STIXGeneral.otf</file> + <file>Thonburi.ttc</file> </os> </font> diff --git a/indra/newview/skins/default/xui/en/menu_attachment_other.xml b/indra/newview/skins/default/xui/en/menu_attachment_other.xml index 38f4b7715f..7ad692038e 100644 --- a/indra/newview/skins/default/xui/en/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/en/menu_attachment_other.xml @@ -173,16 +173,13 @@ parameter="avatar_render_settings" /> </menu_item_call> </context_menu> - <menu_item_separator - layout="topleft" name="Impostor seperator"/> - <menu_item_call enabled="false" label="Block Particle Owner" name="Mute Particle"> <menu_item_call.on_click function="Particle.Mute" /> - <menu_item_call.on_enable + <menu_item_call.on_visible function="EnableMuteParticle" /> </menu_item_call> </context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_attachment_self.xml b/indra/newview/skins/default/xui/en/menu_attachment_self.xml index 59faf6a9f5..26b1c86c53 100644 --- a/indra/newview/skins/default/xui/en/menu_attachment_self.xml +++ b/indra/newview/skins/default/xui/en/menu_attachment_self.xml @@ -4,28 +4,7 @@ name="Attachment Pie"> <menu_item_call enabled="false" - label="Touch" - layout="topleft" - name="Attachment Object Touch"> - <menu_item_call.on_click - function="Object.Touch" /> - <menu_item_call.on_enable - function="Object.EnableTouch" - name="EnableTouch"/> - </menu_item_call> - <!--menu_item_call - label="Stand Up" - layout="topleft" - name="Stand Up"> - <menu_item_call.on_click - function="Self.StandUp" - parameter="" /> - <menu_item_call.on_enable - function="Self.EnableStandUp" /> - </menu_item_call--> - <menu_item_call - enabled="false" - label="Edit" + label="Edit item" layout="topleft" name="Edit..."> <menu_item_call.on_click @@ -35,7 +14,7 @@ </menu_item_call> <menu_item_call enabled="false" - label="Detach" + label="Detach item" layout="topleft" name="Detach"> <menu_item_call.on_click @@ -43,98 +22,278 @@ <menu_item_call.on_enable function="Attachment.EnableDetach" /> </menu_item_call> - <menu_item_separator - layout="topleft" /> - <menu_item_call - label="Sit Down" + enabled="false" + label="Touch item" layout="topleft" - name="Sit Down Here"> + name="Attachment Object Touch"> <menu_item_call.on_click - function="Self.SitDown" - parameter="" /> + function="Object.Touch" /> <menu_item_call.on_enable - function="Self.EnableSitDown" /> + function="Object.EnableTouch" + name="EnableTouch"/> </menu_item_call> + <menu_item_separator + layout="topleft" /> <menu_item_call -label="Stand Up" -layout="topleft" -name="Stand Up"> + label="Now wearing..." + name="NowWearing"> <menu_item_call.on_click - function="Self.StandUp" - parameter="" /> + function="NowWearing" /> <menu_item_call.on_enable - function="Self.EnableStandUp" /> + function="Edit.EnableCustomizeAvatar" /> </menu_item_call> <menu_item_call - label="My Appearance" + label="My Outfits..." name="Change Outfit"> <menu_item_call.on_click function="CustomizeAvatar" /> <menu_item_call.on_enable function="Edit.EnableCustomizeAvatar" /> </menu_item_call> - <menu_item_call label="Edit My Outfit" -layout="topleft" -name="Edit Outfit"> + <menu_item_call label="Hover height..." + layout="topleft" + name="Hover Height"> <menu_item_call.on_click - function="EditOutfit" /> + function="HoverHeight" /> <menu_item_call.on_enable - function="Edit.EnableCustomizeAvatar" /> + function="Edit.EnableHoverHeight" /> </menu_item_call> - <menu_item_call label="Edit My Shape" + <menu_item_call label="Shape..." layout="topleft" - name="Edit My Shape"> + name="Edit Shape"> <menu_item_call.on_click function="EditShape" /> <menu_item_call.on_enable function="Edit.EnableEditShape" /> </menu_item_call> - <menu_item_call label="Hover Height" - layout="topleft" - name="Hover Height"> - <menu_item_call.on_click - function="HoverHeight" /> - <menu_item_call.on_enable - function="Edit.EnableHoverHeight" /> + <menu_item_call label="Edit outfit parts..." + layout="topleft" + name="Edit Outfit"> + <menu_item_call.on_click + function="EditOutfit" /> + <menu_item_call.on_enable + function="Edit.EnableCustomizeAvatar" /> </menu_item_call> - <menu_item_call label="Reset Skeleton" + <context_menu + label="Take off" + layout="topleft" + name="Take Off >"> + <context_menu + label="Clothes" + layout="topleft" + name="Clothes >"> + <menu_item_call + enabled="false" + label="Shirt" layout="topleft" - name="Reset Skeleton"> - <menu_item_call.on_click - function="Avatar.ResetSkeleton" /> - </menu_item_call> - <menu_item_call label="Reset Skeleton And Animations" + name="Shirt"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="shirt" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="shirt" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Pants" layout="topleft" - name="Reset Skeleton And Animations"> - <menu_item_call.on_click - function="Avatar.ResetSkeletonAndAnimations" /> - </menu_item_call> - + name="Pants"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="pants" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="pants" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Skirt" + layout="topleft" + name="Skirt"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="skirt" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="skirt" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Shoes" + layout="topleft" + name="Shoes"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="shoes" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="shoes" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Socks" + layout="topleft" + name="Socks"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="socks" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="socks" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Jacket" + layout="topleft" + name="Jacket"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="jacket" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="jacket" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Gloves" + layout="topleft" + name="Gloves"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="gloves" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="gloves" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Undershirt" + layout="topleft" + name="Self Undershirt"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="undershirt" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="undershirt" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Underpants" + layout="topleft" + name="Self Underpants"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="underpants" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="underpants" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Tattoo" + layout="topleft" + name="Self Tattoo"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="tattoo" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="tattoo" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Physics" + layout="topleft" + name="Self Physics"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="physics" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="physics" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Alpha" + layout="topleft" + name="Self Alpha"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="alpha" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="alpha" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="All Clothes" + layout="topleft" + name="All Clothes"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="all" /> + </menu_item_call> + </context_menu> + <context_menu + label="HUD" + layout="topleft" + name="Detach Self HUD" /> + <context_menu + label="Detach" + layout="topleft" + name="Detach Self" /> + <menu_item_call + label="Detach All" + layout="topleft" + name="Detach All"> + <menu_item_call.on_click + function="Self.RemoveAllAttachments" + parameter="" /> + <menu_item_call.on_enable + function="Self.EnableRemoveAllAttachments" /> + </menu_item_call> + </context_menu> + <menu_item_separator/> <menu_item_call - label="My Friends" + label="Sit / stand" layout="topleft" - name="Friends..."> + name="Sit stand"> <menu_item_call.on_click - function="SideTray.PanelPeopleTab" - parameter="friends_panel" /> + function="Self.ToggleSitStand"/> + <menu_item_call.on_enable + function="Self.EnableSitStand" /> </menu_item_call> <menu_item_call - label="My Groups" - layout="topleft" - name="Groups..."> + label="Fly / land" + name="Fly land"> <menu_item_call.on_click - function="SideTray.PanelPeopleTab" - parameter="groups_panel" /> + function="Agent.toggleFlying" /> + <menu_item_call.on_enable + function="Agent.enableFlyLand" /> </menu_item_call> <menu_item_call - label="My Profile" - layout="topleft" - name="Profile..."> + label="Stop animations" + name="Stop Animating My Avatar"> <menu_item_call.on_click - function="ShowAgentProfile" - parameter="agent" /> + function="Tools.StopAllAnimations" /> + </menu_item_call> + <menu_item_separator/> + <menu_item_call label="Reset skeleton" + layout="topleft" + name="Reset Skeleton"> + <menu_item_call.on_click + function="Avatar.ResetSkeleton" /> + </menu_item_call> + <menu_item_call label="Reset skeleton and animations" + layout="topleft" + name="Reset Skeleton And Animations"> + <menu_item_call.on_click + function="Avatar.ResetSkeletonAndAnimations" /> </menu_item_call> <menu_item_call label="Debug Textures" @@ -152,27 +311,27 @@ name="Edit Outfit"> <menu_item_call.on_visible function="Advanced.EnableAppearanceToXML"/> </menu_item_call> - <menu_item_separator - layout="topleft" /> - <menu_item_call - enabled="false" - label="Drop" - layout="topleft" - name="Drop"> - <menu_item_call.on_click - function="Attachment.Drop" /> - <menu_item_call.on_enable - function="Attachment.EnableDrop" /> - </menu_item_call> - <menu_item_separator - layout="topleft" /> <menu_item_call enabled="false" label="Block Particle Owner" name="Mute Particle"> <menu_item_call.on_click function="Particle.Mute" /> - <menu_item_call.on_enable + <menu_item_call.on_visible function="EnableMuteParticle" /> </menu_item_call> + + <menu_item_separator + layout="topleft" /> + + <menu_item_call + enabled="false" + label="Drop item" + layout="topleft" + name="Drop"> + <menu_item_call.on_click + function="Attachment.Drop" /> + <menu_item_call.on_enable + function="Attachment.EnableDrop" /> + </menu_item_call> </context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_avatar_other.xml b/indra/newview/skins/default/xui/en/menu_avatar_other.xml index f9fb847910..acbb9b860d 100644 --- a/indra/newview/skins/default/xui/en/menu_avatar_other.xml +++ b/indra/newview/skins/default/xui/en/menu_avatar_other.xml @@ -165,16 +165,13 @@ </menu_item_call> </context_menu> - <menu_item_separator - layout="topleft" name="Impostor seperator"/> - <menu_item_call enabled="false" label="Block Particle Owner" name="Mute Particle"> <menu_item_call.on_click function="Particle.Mute" /> - <menu_item_call.on_enable + <menu_item_call.on_visible function="EnableMuteParticle" /> </menu_item_call> </context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_avatar_self.xml b/indra/newview/skins/default/xui/en/menu_avatar_self.xml index 9e181d0b6d..500b6fffc2 100644 --- a/indra/newview/skins/default/xui/en/menu_avatar_self.xml +++ b/indra/newview/skins/default/xui/en/menu_avatar_self.xml @@ -3,209 +3,16 @@ layout="topleft" name="Self Pie"> <menu_item_call - label="Sit Down" + label="Now wearing..." layout="topleft" - name="Sit Down Here"> + name="NowWearing"> <menu_item_call.on_click - function="Self.SitDown" - parameter="" /> + function="NowWearing" /> <menu_item_call.on_enable - function="Self.EnableSitDown" /> + function="Edit.EnableCustomizeAvatar" /> </menu_item_call> <menu_item_call - label="Stand Up" - layout="topleft" - name="Stand Up"> - <menu_item_call.on_click - function="Self.StandUp" - parameter="" /> - <menu_item_call.on_enable - function="Self.EnableStandUp" /> - </menu_item_call> - <context_menu - label="Take Off" - layout="topleft" - name="Take Off >"> - <context_menu - label="Clothes" - layout="topleft" - name="Clothes >"> - <menu_item_call - enabled="false" - label="Shirt" - layout="topleft" - name="Shirt"> - <menu_item_call.on_click - function="Edit.TakeOff" - parameter="shirt" /> - <menu_item_call.on_enable - function="Edit.EnableTakeOff" - parameter="shirt" /> - </menu_item_call> - <menu_item_call - enabled="false" - label="Pants" - layout="topleft" - name="Pants"> - <menu_item_call.on_click - function="Edit.TakeOff" - parameter="pants" /> - <menu_item_call.on_enable - function="Edit.EnableTakeOff" - parameter="pants" /> - </menu_item_call> - <menu_item_call - enabled="false" - label="Skirt" - layout="topleft" - name="Skirt"> - <menu_item_call.on_click - function="Edit.TakeOff" - parameter="skirt" /> - <menu_item_call.on_enable - function="Edit.EnableTakeOff" - parameter="skirt" /> - </menu_item_call> - <menu_item_call - enabled="false" - label="Shoes" - layout="topleft" - name="Shoes"> - <menu_item_call.on_click - function="Edit.TakeOff" - parameter="shoes" /> - <menu_item_call.on_enable - function="Edit.EnableTakeOff" - parameter="shoes" /> - </menu_item_call> - <menu_item_call - enabled="false" - label="Socks" - layout="topleft" - name="Socks"> - <menu_item_call.on_click - function="Edit.TakeOff" - parameter="socks" /> - <menu_item_call.on_enable - function="Edit.EnableTakeOff" - parameter="socks" /> - </menu_item_call> - <menu_item_call - enabled="false" - label="Jacket" - layout="topleft" - name="Jacket"> - <menu_item_call.on_click - function="Edit.TakeOff" - parameter="jacket" /> - <menu_item_call.on_enable - function="Edit.EnableTakeOff" - parameter="jacket" /> - </menu_item_call> - <menu_item_call - enabled="false" - label="Gloves" - layout="topleft" - name="Gloves"> - <menu_item_call.on_click - function="Edit.TakeOff" - parameter="gloves" /> - <menu_item_call.on_enable - function="Edit.EnableTakeOff" - parameter="gloves" /> - </menu_item_call> - <menu_item_call - enabled="false" - label="Undershirt" - layout="topleft" - name="Self Undershirt"> - <menu_item_call.on_click - function="Edit.TakeOff" - parameter="undershirt" /> - <menu_item_call.on_enable - function="Edit.EnableTakeOff" - parameter="undershirt" /> - </menu_item_call> - <menu_item_call - enabled="false" - label="Underpants" - layout="topleft" - name="Self Underpants"> - <menu_item_call.on_click - function="Edit.TakeOff" - parameter="underpants" /> - <menu_item_call.on_enable - function="Edit.EnableTakeOff" - parameter="underpants" /> - </menu_item_call> - <menu_item_call - enabled="false" - label="Tattoo" - layout="topleft" - name="Self Tattoo"> - <menu_item_call.on_click - function="Edit.TakeOff" - parameter="tattoo" /> - <menu_item_call.on_enable - function="Edit.EnableTakeOff" - parameter="tattoo" /> - </menu_item_call> - <menu_item_call - enabled="false" - label="Physics" - layout="topleft" - name="Self Physics"> - <menu_item_call.on_click - function="Edit.TakeOff" - parameter="physics" /> - <menu_item_call.on_enable - function="Edit.EnableTakeOff" - parameter="physics" /> - </menu_item_call> - <menu_item_call - enabled="false" - label="Alpha" - layout="topleft" - name="Self Alpha"> - <menu_item_call.on_click - function="Edit.TakeOff" - parameter="alpha" /> - <menu_item_call.on_enable - function="Edit.EnableTakeOff" - parameter="alpha" /> - </menu_item_call> - <menu_item_separator - layout="topleft" /> - <menu_item_call - label="All Clothes" - layout="topleft" - name="All Clothes"> - <menu_item_call.on_click - function="Edit.TakeOff" - parameter="all" /> - </menu_item_call> - </context_menu> - <context_menu - label="HUD" - layout="topleft" - name="Object Detach HUD" /> - <context_menu - label="Detach" - layout="topleft" - name="Object Detach" /> - <menu_item_call - label="Detach All" - layout="topleft" - name="Detach All"> - <menu_item_call.on_click - function="Self.RemoveAllAttachments" - parameter="" /> - <menu_item_call.on_enable - function="Self.EnableRemoveAllAttachments" /> - </menu_item_call> - </context_menu> - <menu_item_call - label="My Appearance" + label="My Outfits..." layout="topleft" name="Chenge Outfit"> <menu_item_call.on_click @@ -213,66 +20,250 @@ <menu_item_call.on_enable function="Edit.EnableCustomizeAvatar" /> </menu_item_call> - <menu_item_call label="Edit My Outfit" - layout="topleft" - name="Edit Outfit"> - <menu_item_call.on_click - function="EditOutfit" /> - <menu_item_call.on_enable - function="Edit.EnableCustomizeAvatar" /> + <menu_item_call label="Hover height..." + layout="topleft" + name="Hover Height"> + <menu_item_call.on_click + function="HoverHeight" /> + <menu_item_call.on_enable + function="Edit.EnableHoverHeight" /> </menu_item_call> - <menu_item_call label="Edit My Shape" + <menu_item_call label="Shape..." layout="topleft" - name="Edit My Shape"> + name="Edit Shape"> <menu_item_call.on_click function="EditShape" /> <menu_item_call.on_enable function="Edit.EnableEditShape" /> </menu_item_call> - <menu_item_call label="Hover Height" - layout="topleft" - name="Hover Height"> - <menu_item_call.on_click - function="HoverHeight" /> - <menu_item_call.on_enable - function="Edit.EnableHoverHeight" /> + <menu_item_call + label="Edit outfit parts..." + layout="topleft" + name="Edit Outfit"> + <menu_item_call.on_click + function="EditOutfit" /> + <menu_item_call.on_enable + function="Edit.EnableCustomizeAvatar" /> </menu_item_call> - <menu_item_call label="Reset Skeleton" + <context_menu + label="Take off" + layout="topleft" + name="Take Off >"> + <context_menu + label="Clothes" + layout="topleft" + name="Clothes >"> + <menu_item_call + enabled="false" + label="Shirt" + layout="topleft" + name="Shirt"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="shirt" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="shirt" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Pants" + layout="topleft" + name="Pants"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="pants" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="pants" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Skirt" + layout="topleft" + name="Skirt"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="skirt" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="skirt" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Shoes" + layout="topleft" + name="Shoes"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="shoes" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="shoes" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Socks" + layout="topleft" + name="Socks"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="socks" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="socks" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Jacket" + layout="topleft" + name="Jacket"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="jacket" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="jacket" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Gloves" + layout="topleft" + name="Gloves"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="gloves" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="gloves" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Undershirt" + layout="topleft" + name="Self Undershirt"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="undershirt" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="undershirt" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Underpants" + layout="topleft" + name="Self Underpants"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="underpants" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="underpants" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Tattoo" + layout="topleft" + name="Self Tattoo"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="tattoo" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="tattoo" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Physics" + layout="topleft" + name="Self Physics"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="physics" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="physics" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Alpha" + layout="topleft" + name="Self Alpha"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="alpha" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="alpha" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="All Clothes" + layout="topleft" + name="All Clothes"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="all" /> + </menu_item_call> + </context_menu> + <context_menu + label="HUD" + layout="topleft" + name="Object Detach HUD" /> + <context_menu + label="Detach" + layout="topleft" + name="Object Detach" /> + <menu_item_call + label="Detach All" + layout="topleft" + name="Detach All"> + <menu_item_call.on_click + function="Self.RemoveAllAttachments" + parameter="" /> + <menu_item_call.on_enable + function="Self.EnableRemoveAllAttachments" /> + </menu_item_call> + </context_menu> + <menu_item_separator/> + <menu_item_call + label="Sit / stand" + layout="topleft" + name="Sit stand"> + <menu_item_call.on_click + function="Self.ToggleSitStand"/> + <menu_item_call.on_enable + function="Self.EnableSitStand" /> + </menu_item_call> + <menu_item_call + label="Fly / land" + name="Fly land"> + <menu_item_call.on_click + function="Agent.toggleFlying" /> + <menu_item_call.on_enable + function="Agent.enableFlyLand" /> + </menu_item_call> + <menu_item_call + label="Stop animations" + name="Stop Animating My Avatar"> + <menu_item_call.on_click + function="Tools.StopAllAnimations" /> + </menu_item_call> + <menu_item_separator/> + <menu_item_call label="Reset skeleton" layout="topleft" name="Reset Skeleton"> <menu_item_call.on_click function="Avatar.ResetSkeleton" /> - </menu_item_call> - <menu_item_call label="Reset Skeleton And Animations" + </menu_item_call> + <menu_item_call label="Reset skeleton and animations" layout="topleft" name="Reset Skeleton And Animations"> <menu_item_call.on_click function="Avatar.ResetSkeletonAndAnimations" /> </menu_item_call> - <menu_item_call - label="My Friends" - layout="topleft" - name="Friends..."> - <menu_item_call.on_click - function="SideTray.PanelPeopleTab" - parameter="friends_panel" /> - </menu_item_call> - <menu_item_call - label="My Groups" - layout="topleft" - name="Groups..."> - <menu_item_call.on_click - function="SideTray.PanelPeopleTab" - parameter="groups_panel" /> - </menu_item_call> - <menu_item_call - label="My Profile" - layout="topleft" - name="Profile..."> - <menu_item_call.on_click - function="ShowAgentProfile" - parameter="agent" /> - </menu_item_call> <menu_item_call label="Debug Textures" name="Debug..."> @@ -289,8 +280,6 @@ <menu_item_call.on_visible function="Advanced.EnableAppearanceToXML"/> </menu_item_call> - <menu_item_separator - layout="topleft" /> <menu_item_call enabled="false" label="Block Particle Owner" @@ -298,7 +287,7 @@ <menu_item_call.on_click function="Particle.Mute" /> - <menu_item_call.on_enable + <menu_item_call.on_visible function="EnableMuteParticle" /> </menu_item_call> </context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_cof_attachment.xml b/indra/newview/skins/default/xui/en/menu_cof_attachment.xml index c402100fb1..3f545c936d 100644 --- a/indra/newview/skins/default/xui/en/menu_cof_attachment.xml +++ b/indra/newview/skins/default/xui/en/menu_cof_attachment.xml @@ -3,6 +3,26 @@ layout="topleft" name="COF Attachment"> <menu_item_call + label="Touch" + layout="topleft" + name="touch_attach"> + <on_click + function="Attachment.Touch" /> + <on_enable + function="Attachment.OnEnable" + parameter="touch" /> + </menu_item_call> + <menu_item_call + label="Edit" + layout="topleft" + name="edit_item"> + <on_click + function="Attachment.Edit" /> + <on_enable + function="Attachment.OnEnable" + parameter="edit" /> + </menu_item_call> + <menu_item_call label="Detach" layout="topleft" name="detach"> diff --git a/indra/newview/skins/default/xui/en/menu_favorites.xml b/indra/newview/skins/default/xui/en/menu_favorites.xml index be380e11e5..0eab7c451b 100644 --- a/indra/newview/skins/default/xui/en/menu_favorites.xml +++ b/indra/newview/skins/default/xui/en/menu_favorites.xml @@ -21,12 +21,12 @@ parameter="about" /> </menu_item_call> <menu_item_call - label="Copy SLurl" + label="Move to Landmarks" layout="topleft" - name="Copy slurl"> + name="Move to Landmarks"> <menu_item_call.on_click function="Favorites.DoToSelected" - parameter="copy_slurl" /> + parameter="move_to_landmarks" /> </menu_item_call> <menu_item_call label="Show on Map" @@ -36,6 +36,25 @@ function="Favorites.DoToSelected" parameter="show_on_map" /> </menu_item_call> + <menu_item_call + label="Copy SLurl" + layout="topleft" + name="Copy slurl"> + <menu_item_call.on_click + function="Favorites.DoToSelected" + parameter="copy_slurl" /> + </menu_item_call> + <menu_item_call + label="Create Pick" + layout="topleft" + name="create_pick"> + <menu_item_call.on_click + function="Favorites.DoToSelected" + parameter="create_pick" /> + <menu_item_call.on_enable + function="Favorites.EnableSelected" + parameter="create_pick" /> + </menu_item_call> <menu_item_separator layout="topleft" /> @@ -59,10 +78,14 @@ function="Favorites.EnableSelected" parameter="can_paste" /> </menu_item_call> - - <menu_item_separator - layout="topleft" /> - + <menu_item_call + label="Rename" + layout="topleft" + name="rename"> + <menu_item_call.on_click + function="Favorites.DoToSelected" + parameter="rename" /> + </menu_item_call> <menu_item_call label="Delete" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml index 1b08767edc..99ca910062 100755 --- a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml +++ b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml @@ -42,7 +42,7 @@ parameter="take_off" /> </menu_item_call> <menu_item_call - label="Upload Photo (L$10)" + label="Upload Photo (L$[UPLOAD_COST])" layout="topleft" name="upload_photo"> <on_click diff --git a/indra/newview/skins/default/xui/en/menu_gesture_gear.xml b/indra/newview/skins/default/xui/en/menu_gesture_gear.xml index c1458977ca..5cae643e44 100644 --- a/indra/newview/skins/default/xui/en/menu_gesture_gear.xml +++ b/indra/newview/skins/default/xui/en/menu_gesture_gear.xml @@ -12,6 +12,16 @@ function="Gesture.Action.ToogleActiveState" /> </menu_item_call> <menu_item_call + label="Rename" + layout="topleft" + name="rename"> + <on_click + function="Gesture.Action.Rename" /> + <on_enable + function="Gesture.EnableAction" + parameter="rename_gesture" /> + </menu_item_call> + <menu_item_call label="Copy" layout="topleft" name="copy_gesture"> diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index 3bdbbb04d7..5a35bbf121 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -152,6 +152,14 @@ parameter="category" /> </menu_item_call> <menu_item_call + label="New Outfit" + layout="topleft" + name="New Outfit"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="outfit" /> + </menu_item_call> + <menu_item_call label="New Script" layout="topleft" name="New Script"> @@ -322,6 +330,41 @@ </menu_item_call> </menu> <menu + label="New Settings" + layout="topleft" + name="New Settings"> + <menu_item_call + label="New Sky" + layout="topleft" + name="New Sky"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="sky"/> + <menu_item_call.on_enable + function="Inventory.EnvironmentEnabled" /> + </menu_item_call> + <menu_item_call + label="New Water" + layout="topleft" + name="New Water"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="water"/> + <menu_item_call.on_enable + function="Inventory.EnvironmentEnabled" /> + </menu_item_call> + <menu_item_call + label="New Day Cycle" + layout="topleft" + name="New Day Cycle"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="daycycle"/> + <menu_item_call.on_enable + function="Inventory.EnvironmentEnabled" /> + </menu_item_call> + </menu> + <menu label="Use as default for" layout="topleft" name="upload_def"> @@ -775,14 +818,6 @@ <menu_item_separator layout="topleft" name="Wearable And Object Separator"/> - <menu_item_call - label="Detach From Yourself" - layout="topleft" - name="Detach From Yourself"> - <menu_item_call.on_click - function="Inventory.DoToSelected" - parameter="detach" /> - </menu_item_call> <!-- COMMENTED OUT for DEV-32347 --> <!-- <menu_item_call @@ -811,6 +846,14 @@ layout="topleft" name="Attach To HUD" /> <menu_item_call + label="Touch" + layout="topleft" + name="Attachment Touch"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="touch" /> + </menu_item_call> + <menu_item_call label="Edit" layout="topleft" name="Wearable Edit"> @@ -827,6 +870,14 @@ parameter="wear_add" /> </menu_item_call> <menu_item_call + label="Detach From Yourself" + layout="topleft" + name="Detach From Yourself"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="detach" /> + </menu_item_call> + <menu_item_call label="Take Off" layout="topleft" name="Take Off"> @@ -834,6 +885,25 @@ function="Inventory.DoToSelected" parameter="take_off" /> </menu_item_call> + <menu_item_separator + layout="topleft" + name="Settings Separator" /> + <menu_item_call + name="Settings Apply Local" + layout="topleft" + label="Apply Only To Myself"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="apply_settings_local" /> + </menu_item_call> + <menu_item_call + name="Settings Apply Parcel" + layout="topleft" + label="Apply To Parcel"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="apply_settings_parcel" /> + </menu_item_call> <menu_item_separator layout="topleft" name="Marketplace Separator" /> diff --git a/indra/newview/skins/default/xui/en/menu_inventory_add.xml b/indra/newview/skins/default/xui/en/menu_inventory_add.xml index 29724b0270..3385a29a6c 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory_add.xml @@ -56,7 +56,7 @@ function="File.VisibleUploadModel"/> </menu_item_call> <menu_item_call - label="Bulk (L$[COST] per file)..." + label="Bulk..." layout="topleft" name="Bulk Upload"> <menu_item_call.on_click @@ -253,4 +253,41 @@ parameter="eyes" /> </menu_item_call> </menu> + <menu + label="New Settings" + layout="topleft" + name="New Settings"> + <menu_item_call + label="New Sky" + layout="topleft" + name="New Sky"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="sky"/> + <menu_item_call.on_enable + function="Inventory.EnvironmentEnabled" /> + + </menu_item_call> + <menu_item_call + label="New Water" + layout="topleft" + name="New Water"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="water"/> + <menu_item_call.on_enable + function="Inventory.EnvironmentEnabled" /> + + </menu_item_call> + <menu_item_call + label="New Day Cycle" + layout="topleft" + name="New Day Cycle"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="daycycle"/> + <menu_item_call.on_enable + function="Inventory.EnvironmentEnabled" /> + </menu_item_call> + </menu> </menu>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/menu_inventory_search_visibility.xml b/indra/newview/skins/default/xui/en/menu_inventory_search_visibility.xml new file mode 100644 index 0000000000..46193f4a7a --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_inventory_search_visibility.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + bottom="806" + layout="topleft" + left="0" + mouse_opaque="false" + name="menu_search_visibility" + visible="false"> + <menu_item_check + label="Search Trash" + layout="topleft" + name="search_trash"> + <on_click + function="Inventory.GearDefault.Custom.Action" + parameter="toggle_search_trash" /> + <on_check + function="Inventory.GearDefault.Check" + parameter="toggle_search_trash" /> + </menu_item_check> + <menu_item_check + label="Search Library" + layout="topleft" + name="search_library"> + <on_click + function="Inventory.GearDefault.Custom.Action" + parameter="toggle_search_library" /> + <on_check + function="Inventory.GearDefault.Check" + parameter="toggle_search_library" /> + </menu_item_check> + <menu_item_separator + layout="topleft" /> + <menu_item_check + label="Include links" + layout="topleft" + name="include_links"> + <on_click + function="Inventory.GearDefault.Custom.Action" + parameter="include_links" /> + <on_check + function="Inventory.GearDefault.Check" + parameter="include_links" /> + </menu_item_check> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_land.xml b/indra/newview/skins/default/xui/en/menu_land.xml index 2ad5cbbe95..1ce0d65b3e 100644 --- a/indra/newview/skins/default/xui/en/menu_land.xml +++ b/indra/newview/skins/default/xui/en/menu_land.xml @@ -18,6 +18,8 @@ <menu_item_call label="Sit Here" name="Sit Here"> + <menu_item_call.on_enable + function="Land.CanSit" /> <menu_item_call.on_click function="Land.Sit" /> </menu_item_call> diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml index 93795be474..40399b33ef 100644 --- a/indra/newview/skins/default/xui/en/menu_login.xml +++ b/indra/newview/skins/default/xui/en/menu_login.xml @@ -57,20 +57,13 @@ tear_off="true" name="Help"> <menu_item_call - label="How to..." + label="Guidebook" name="How To" shortcut="F1"> <menu_item_call.on_click function="Help.ToggleHowTo" parameter="" /> </menu_item_call> - <menu_item_call - label="Quickstart" - name="Quickstart"> - <menu_item_call.on_click - function="Advanced.ShowURL" - parameter="http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Quickstart/ta-p/1087919"/> - </menu_item_call> <menu_item_separator/> <menu_item_call label="Knowledge Base" diff --git a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml index 61cb74f230..32d9d28434 100644 --- a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml +++ b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml @@ -40,7 +40,7 @@ parameter="take_off" /> </menu_item_call> <menu_item_call - label="Upload Photo (L$10)" + label="Upload Photo (L$[UPLOAD_COST])" layout="topleft" name="upload_photo"> <on_click diff --git a/indra/newview/skins/default/xui/en/menu_picks.xml b/indra/newview/skins/default/xui/en/menu_picks.xml index ebb49c9004..a408e6136c 100644 --- a/indra/newview/skins/default/xui/en/menu_picks.xml +++ b/indra/newview/skins/default/xui/en/menu_picks.xml @@ -3,7 +3,17 @@ layout="topleft" name="Picks"> <menu_item_call - label="Info" + label="Teleport" + layout="topleft" + name="pick_teleport"> + <menu_item_call.on_click + function="Pick.Teleport" /> + <menu_item_call.on_enable + function="Pick.Enable" + parameter="teleport" /> + </menu_item_call> + <menu_item_call + label="View Pick" layout="topleft" name="pick_info"> <menu_item_call.on_click @@ -13,7 +23,7 @@ parameter="info" /> </menu_item_call> <menu_item_call - label="Edit" + label="Edit Pick" layout="topleft" name="pick_edit" visible="false"> @@ -24,17 +34,7 @@ parameter="edit" /> </menu_item_call> <menu_item_call - label="Teleport" - layout="topleft" - name="pick_teleport"> - <menu_item_call.on_click - function="Pick.Teleport" /> - <menu_item_call.on_enable - function="Pick.Enable" - parameter="teleport" /> - </menu_item_call> - <menu_item_call - label="Map" + label="Show on map" layout="topleft" name="pick_map"> <menu_item_call.on_click diff --git a/indra/newview/skins/default/xui/en/menu_place_add_button.xml b/indra/newview/skins/default/xui/en/menu_place_add_button.xml index e3a39a1242..ad49f7c3a8 100644 --- a/indra/newview/skins/default/xui/en/menu_place_add_button.xml +++ b/indra/newview/skins/default/xui/en/menu_place_add_button.xml @@ -1,27 +1,30 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<menu +<toggleable_menu layout="topleft" left="0" mouse_opaque="false" - name="menu_folder_gear" + name="menu_create" visible="false"> <menu_item_call - label="Add Folder" + label="Landmark current location" layout="topleft" - name="add_folder"> + name="add_landmark"> <on_click function="Places.LandmarksGear.Add.Action" - parameter="category" /> + parameter="add_landmark_root" /> <on_enable function="Places.LandmarksGear.Enable" - parameter="category" /> + parameter="add_landmark_root" /> </menu_item_call> <menu_item_call - label="Add Landmark" + label="Create folder" layout="topleft" - name="add_landmark"> + name="add_folder"> <on_click function="Places.LandmarksGear.Add.Action" - parameter="add_landmark" /> + parameter="category_root" /> + <on_enable + function="Places.LandmarksGear.Enable" + parameter="category_root" /> </menu_item_call> -</menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml b/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml index 1aeb166e01..e9ada52a8f 100644 --- a/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml +++ b/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml @@ -7,15 +7,18 @@ name="menu_folder_gear" visible="false"> <menu_item_call - label="Add Landmark" + label="Landmark current location" layout="topleft" name="add_landmark"> <on_click function="Places.LandmarksGear.Add.Action" parameter="add_landmark" /> + <on_enable + function="Places.LandmarksGear.Enable" + parameter="add_landmark" /> </menu_item_call> <menu_item_call - label="Add Folder" + label="Create subfolder" layout="topleft" name="add_folder"> <on_click @@ -24,6 +27,9 @@ <on_enable function="Places.LandmarksGear.Enable" parameter="category" /> + <on_visible + function="Places.LandmarksGear.Enable" + parameter="category" /> </menu_item_call> <menu_item_call label="Restore Item" @@ -120,37 +126,4 @@ function="Places.LandmarksGear.Enable" parameter="collapse" /> </menu_item_call> - <menu_item_call - label="Expand all folders" - layout="topleft" - name="expand_all"> - <on_click - function="Places.LandmarksGear.Folding.Action" - parameter="expand_all" /> - <on_enable - function="Places.LandmarksGear.Enable" - parameter="expand_all" /> - </menu_item_call> - <menu_item_call - label="Collapse all folders" - layout="topleft" - name="collapse_all"> - <on_click - function="Places.LandmarksGear.Folding.Action" - parameter="collapse_all" /> - <on_enable - function="Places.LandmarksGear.Enable" - parameter="collapse_all" /> - </menu_item_call> - <menu_item_check - label="Sort by Date" - layout="topleft" - name="sort_by_date"> - <on_check - function="Places.LandmarksGear.Check" - parameter="sort_by_date" /> - <on_click - function="Places.LandmarksGear.Folding.Action" - parameter="sort_by_date" /> - </menu_item_check> </toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml b/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml index ff5fdd3795..c89b498ddf 100644 --- a/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml +++ b/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml @@ -18,7 +18,18 @@ parameter="teleport" /> </menu_item_call> <menu_item_call - label="More Information" + label="Share" + layout="topleft" + name="share"> + <on_click + function="Places.LandmarksGear.Custom.Action" + parameter="share" /> + <on_enable + function="Places.LandmarksGear.Enable" + parameter="share" /> + </menu_item_call> + <menu_item_call + label="View/Edit Landmark" layout="topleft" name="more_info"> <on_click @@ -29,6 +40,28 @@ parameter="more_info" /> </menu_item_call> <menu_item_call + label="Move to Landmarks" + layout="topleft" + name="Move to Landmarks"> + <menu_item_call.on_click + function="Places.LandmarksGear.Custom.Action" + parameter="move_to_landmarks" /> + <menu_item_call.on_visible + function="Places.LandmarksGear.Enable" + parameter="move_to_landmarks" /> + </menu_item_call> + <menu_item_call + label="Move to Favorites" + layout="topleft" + name="Move to Favorites"> + <menu_item_call.on_click + function="Places.LandmarksGear.Custom.Action" + parameter="move_to_favorites" /> + <menu_item_call.on_visible + function="Places.LandmarksGear.Enable" + parameter="move_to_favorites" /> + </menu_item_call> + <menu_item_call label="Show on Map" layout="topleft" name="show_on_map"> @@ -39,26 +72,27 @@ function="Places.LandmarksGear.Enable" parameter="show_on_map" /> </menu_item_call> - <menu_item_separator - layout="topleft" /> <menu_item_call - label="Add Landmark" + label="Copy SLurl" layout="topleft" - name="add_landmark"> + name="copy_slurl"> <on_click - function="Places.LandmarksGear.Add.Action" - parameter="add_landmark" /> - </menu_item_call> + function="Places.LandmarksGear.CopyPaste.Action" + parameter="copy_slurl" /> + <on_enable + function="Places.LandmarksGear.Enable" + parameter="copy_slurl" /> + </menu_item_call> <menu_item_call - label="Add Folder" + label="Create Pick" layout="topleft" - name="add_folder"> + name="create_pick"> <on_click - function="Places.LandmarksGear.Add.Action" - parameter="category" /> + function="Places.LandmarksGear.Custom.Action" + parameter="create_pick" /> <on_enable function="Places.LandmarksGear.Enable" - parameter="category" /> + parameter="create_pick" /> </menu_item_call> <menu_item_call label="Restore Item" @@ -82,7 +116,7 @@ parameter="cut" /> </menu_item_call> <menu_item_call - label="Copy Landmark" + label="Copy" layout="topleft" name="copy_landmark"> <on_click @@ -90,17 +124,6 @@ parameter="copy" /> </menu_item_call> <menu_item_call - label="Copy SLurl" - layout="topleft" - name="copy_slurl"> - <on_click - function="Places.LandmarksGear.CopyPaste.Action" - parameter="copy_slurl" /> - <on_enable - function="Places.LandmarksGear.Enable" - parameter="copy_slurl" /> - </menu_item_call> - <menu_item_call label="Paste" layout="topleft" name="paste"> @@ -133,53 +156,4 @@ function="Places.LandmarksGear.Enable" parameter="delete" /> </menu_item_call> - <menu_item_separator - layout="topleft" /> - <menu_item_call - label="Expand all folders" - layout="topleft" - name="expand_all"> - <on_click - function="Places.LandmarksGear.Folding.Action" - parameter="expand_all" /> - <on_enable - function="Places.LandmarksGear.Enable" - parameter="expand_all" /> - </menu_item_call> - <menu_item_call - label="Collapse all folders" - layout="topleft" - name="collapse_all"> - <on_click - function="Places.LandmarksGear.Folding.Action" - parameter="collapse_all" /> - <on_enable - function="Places.LandmarksGear.Enable" - parameter="collapse_all" /> - </menu_item_call> - <menu_item_check - label="Sort by Date" - layout="topleft" - name="sort_by_date"> - <on_check - function="Places.LandmarksGear.Check" - parameter="sort_by_date" /> - <on_click - function="Places.LandmarksGear.Folding.Action" - parameter="sort_by_date" /> - <on_enable - function="Places.LandmarksGear.Enable" - parameter="sort_by_date" /> - </menu_item_check> - <menu_item_call - label="Create Pick" - layout="topleft" - name="create_pick"> - <on_click - function="Places.LandmarksGear.Custom.Action" - parameter="create_pick" /> - <on_enable - function="Places.LandmarksGear.Enable" - parameter="create_pick" /> - </menu_item_call> </toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_places_gear_sorting.xml b/indra/newview/skins/default/xui/en/menu_places_gear_sorting.xml new file mode 100644 index 0000000000..4193a72e2e --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_places_gear_sorting.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + left="0" + mouse_opaque="false" + name="menu_sorter_gear" + visible="false"> + <menu_item_call + label="Expand all folders" + layout="topleft" + name="expand_all"> + <on_click + function="Places.LandmarksGear.Folding.Action" + parameter="expand_all" /> + <on_enable + function="Places.LandmarksGear.Enable" + parameter="expand_all" /> + </menu_item_call> + <menu_item_call + label="Collapse all folders" + layout="topleft" + name="collapse_all"> + <on_click + function="Places.LandmarksGear.Folding.Action" + parameter="collapse_all" /> + <on_enable + function="Places.LandmarksGear.Enable" + parameter="collapse_all" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_check + label="Sort by Date" + layout="topleft" + name="sort_by_date"> + <on_check + function="Places.LandmarksGear.Check" + parameter="sort_by_date" /> + <on_click + function="Places.LandmarksGear.Folding.Action" + parameter="sort_by_date" /> + <on_enable + function="Places.LandmarksGear.Enable" + parameter="sort_by_date" /> + </menu_item_check> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_save_settings.xml b/indra/newview/skins/default/xui/en/menu_save_settings.xml new file mode 100644 index 0000000000..84dacaa8b8 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_save_settings.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + height="602" + layout="topleft" + mouse_opaque="false" + name="save_settings_menu" + width="120"> + <menu_item_check + name="save_settings" + label="Save"> + <menu_item_check.on_check + function="FlyoutCombo.Button.Check" + userdata="save" /> + <menu_item_check.on_click + function="FlyoutCombo.Button.Action" + userdata="save"/> + </menu_item_check> + <menu_item_check + name="save_as_new_settings" + label="Save As"> + <menu_item_check.on_check + function="FlyoutCombo.Button.Check" + userdata="saveas" /> + <menu_item_check.on_click + function="FlyoutCombo.Button.Action" + userdata="saveas" /> + </menu_item_check> + <menu_item_check + name="commit_changes" + label="Commit"> + <menu_item_check.on_check + function="FlyoutCombo.Button.Check" + userdata="commit" /> + <menu_item_check.on_click + function="FlyoutCombo.Button.Action" + userdata="commit" /> + </menu_item_check> + <menu_item_check + name="apply_local" + label="Apply Only To Myself"> + <menu_item_check.on_check + function="FlyoutCombo.Button.Check" + userdata="local" /> + <menu_item_check.on_click + function="FlyoutCombo.Button.Action" + userdata="local" /> + </menu_item_check> + <menu_item_check + name="apply_parcel" + label="Apply To Parcel"> + <menu_item_check.on_check + function="FlyoutCombo.Button.Check" + userdata="parcel" /> + <menu_item_check.on_click + function="FlyoutCombo.Button.Action" + userdata="parcel" /> + </menu_item_check> + <menu_item_check + name="apply_region" + label="Apply To Region"> + <menu_item_check.on_check + function="FlyoutCombo.Button.Check" + userdata="region" /> + <menu_item_check.on_click + function="FlyoutCombo.Button.Action" + userdata="region" /> + </menu_item_check> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_script_chiclet.xml b/indra/newview/skins/default/xui/en/menu_script_chiclet.xml index db29d9cebc..49e52ebb8d 100644 --- a/indra/newview/skins/default/xui/en/menu_script_chiclet.xml +++ b/indra/newview/skins/default/xui/en/menu_script_chiclet.xml @@ -16,4 +16,12 @@ function="ScriptChiclet.Action" parameter="end" /> </menu_item_call> + <menu_item_call + label="Close All Dialogs" + layout="topleft" + name="Close All"> + <menu_item_call.on_click + function="ScriptChiclet.Action" + parameter="close all" /> + </menu_item_call> </menu> diff --git a/indra/newview/skins/default/xui/en/menu_settings_add.xml b/indra/newview/skins/default/xui/en/menu_settings_add.xml new file mode 100644 index 0000000000..a4782cfdc3 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_settings_add.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + mouse_opaque="false" + name="menu_settings_add" + visible="false"> + <menu_item_call + label="New Sky" + layout="topleft" + name="New Sky"> + <menu_item_call.on_click + function="MyEnvironments.DoCreate" + parameter="sky"/> + <menu_item_call.on_enable + function="MyEnvironments.EnvironmentEnabled" /> + </menu_item_call> + <menu_item_call + label="New Water" + layout="topleft" + name="New Water"> + <menu_item_call.on_click + function="MyEnvironments.DoCreate" + parameter="water"/> + <menu_item_call.on_enable + function="MyEnvironments.EnvironmentEnabled" /> + </menu_item_call> + <menu_item_call + label="New Day Cycle" + layout="topleft" + name="New Day Cycle"> + <menu_item_call.on_click + function="MyEnvironments.DoCreate" + parameter="daycycle"/> + <menu_item_call.on_enable + function="MyEnvironments.EnvironmentEnabled" /> + </menu_item_call> +</toggleable_menu>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/menu_settings_gear.xml b/indra/newview/skins/default/xui/en/menu_settings_gear.xml new file mode 100644 index 0000000000..ea8e328407 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_settings_gear.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + mouse_opaque="false" + name="menu_settings_gear" + visible="false"> + <menu_item_call + label="Edit" + layout="topleft" + name="edit_settings"> + <on_click + function="MyEnvironments.DoEdit" /> + <on_enable + function="MyEnvironments.EnableAction" + parameter="edit" /> + </menu_item_call> + <menu_item_separator + layout="topleft" + name="Separator" /> + <menu_item_call + name="Settings Apply Local" + layout="topleft" + label="Apply Only To Myself"> + <menu_item_call.on_click + function="MyEnvironments.DoApply" + parameter="local" /> + </menu_item_call> + <menu_item_call + name="Settings Apply Parcel" + layout="topleft" + label="Apply To Parcel"> + <menu_item_call.on_click + function="MyEnvironments.DoApply" + parameter="parcel" /> + <menu_item_call.on_enable + function="MyEnvironments.CanApply" + parameter="parcel"/> + </menu_item_call> + <menu_item_call + name="Settings Apply Region" + layout="topleft" + label="Apply To Region"> + <menu_item_call.on_click + function="MyEnvironments.DoApply" + parameter="region" /> + <menu_item_call.on_enable + function="MyEnvironments.CanApply" + parameter="region"/> + </menu_item_call> + <menu_item_separator + layout="topleft" + name="Separator" /> + <menu_item_call + label="Copy" + layout="topleft" + name="copy_settings"> + <on_click + function="MyEnvironments.CopyPaste" + parameter="copy" /> + <on_enable + function="MyEnvironments.EnableAction" + parameter="copy" /> + </menu_item_call> + <menu_item_call + label="Paste" + layout="topleft" + name="paste_settings"> + <on_click + function="MyEnvironments.CopyPaste" + parameter="paste" /> + <on_enable + function="MyEnvironments.EnableAction" + parameter="paste" /> + </menu_item_call> + <menu_item_call + label="Copy UUID" + layout="topleft" + name="copy_uuid"> + <on_click + function="MyEnvironments.CopyPaste" + parameter="copy_uuid" /> + <on_enable + function="MyEnvironments.EnableAction" + parameter="copy_uuid" /> + </menu_item_call> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_teleport_history_gear.xml b/indra/newview/skins/default/xui/en/menu_teleport_history_gear.xml index bc7d4fe33b..c11d668698 100644 --- a/indra/newview/skins/default/xui/en/menu_teleport_history_gear.xml +++ b/indra/newview/skins/default/xui/en/menu_teleport_history_gear.xml @@ -12,7 +12,8 @@ label="Expand all folders" name="Expand all folders"> <menu_item_call.on_click - function="TeleportHistory.ExpandAllFolders" /> + function="TeleportHistory.GearMenu.Action" + parameter="expand_all" /> <on_enable function="TeleportHistory.GearMenu.Enable" parameter="expand_all" /> @@ -21,16 +22,10 @@ label="Collapse all folders" name="Collapse all folders"> <menu_item_call.on_click - function="TeleportHistory.CollapseAllFolders" /> + function="TeleportHistory.GearMenu.Action" + parameter="collapse_all" /> <on_enable function="TeleportHistory.GearMenu.Enable" parameter="collapse_all" /> </menu_item_call> - <menu_item_separator layout="topleft" /> - <menu_item_call - label="Clear Teleport History" - name="Clear Teleport History"> - <menu_item_call.on_click - function="TeleportHistory.ClearTeleportHistory" /> - </menu_item_call> </toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_teleport_history_item.xml b/indra/newview/skins/default/xui/en/menu_teleport_history_item.xml index f939c3996d..153e5a70a9 100644 --- a/indra/newview/skins/default/xui/en/menu_teleport_history_item.xml +++ b/indra/newview/skins/default/xui/en/menu_teleport_history_item.xml @@ -1,26 +1,52 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<context_menu +<toggleable_menu + name="Teleport History Item Menu" layout="topleft" - name="Teleport History Item Context Menu"> + left="0" + mouse_opaque="false" + visible="false"> <menu_item_call label="Teleport" layout="topleft" name="Teleport"> - <menu_item_call.on_click - function="TeleportHistory.Teleport" /> + <on_click + function="TeleportHistory.GearMenu.Action" + parameter="teleport" /> + <on_enable + function="TeleportHistory.GearMenu.Enable" + parameter="teleport" /> </menu_item_call> <menu_item_call - label="More Information" + label="View" layout="topleft" name="More Information"> - <menu_item_call.on_click - function="TeleportHistory.MoreInformation" /> + <on_click + function="TeleportHistory.GearMenu.Action" + parameter="view" /> + <on_enable + function="TeleportHistory.GearMenu.Enable" + parameter="view" /> + </menu_item_call> + <menu_item_call + label="Show on map" + layout="topleft" + name="show_on_map"> + <on_click + function="TeleportHistory.GearMenu.Action" + parameter="show_on_map" /> + <on_enable + function="TeleportHistory.GearMenu.Enable" + parameter="show_on_map" /> </menu_item_call> <menu_item_call label="Copy SLurl" layout="topleft" name="CopyToClipboard"> - <menu_item_call.on_click - function="TeleportHistory.CopyToClipboard" /> + <on_click + function="TeleportHistory.GearMenu.Action" + parameter="copy_slurl" /> + <on_enable + function="TeleportHistory.GearMenu.Enable" + parameter="copy_slurl" /> </menu_item_call> -</context_menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index d92e633e87..14846af4ad 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -15,22 +15,6 @@ function="ShowAgentProfile" parameter="agent" /> </menu_item_call> - <menu_item_call - label="Appearance..." - name="ChangeOutfit"> - <menu_item_call.on_click - function="CustomizeAvatar" /> - <menu_item_call.on_enable - function="Edit.EnableCustomizeAvatar" /> - </menu_item_call> - <menu_item_call - label="Choose an avatar..." - name="Avatar Picker"> - <menu_item_call.on_click - function="Floater.ToggleOrBringToFront" - parameter="avatar" /> - </menu_item_call> - <menu_item_separator/> <menu_item_check label="Inventory..." name="Inventory" @@ -54,10 +38,10 @@ </menu_item_call> <menu_item_call label="Places..." - name="Places"> + name="Places" + shortcut="control|L"> <menu_item_call.on_click - function="Floater.ToggleOrBringToFront" - parameter="places" /> + function="Tools.Link"/> </menu_item_call> <menu_item_call label="Picks..." @@ -74,116 +58,31 @@ parameter="experiences"/> </menu_item_call> <menu_item_call - label="My Scripts..." - name="MyScripts"> - <menu_item_call.on_click - function="Floater.ToggleOrBringToFront" - parameter="my_scripts"/> - </menu_item_call> - <menu_item_separator/> - <menu_item_call label="Camera Controls..." - name="Camera Controls"> + name="Camera Controls" + shortcut="control|K"> <menu_item_call.on_click function="Floater.ToggleOrBringToFront" parameter="camera" /> </menu_item_call> - <menu - create_jump_keys="true" - label="Movement" - name="Movement" - tear_off="true"> - <menu_item_call - label="Sit Down" - layout="topleft" - shortcut="alt|shift|S" - name="Sit Down Here"> - <menu_item_call.on_click - function="Self.SitDown"/> - <menu_item_call.on_visible - function="Self.ShowSitDown"/> - <menu_item_call.on_enable - function="Self.EnableSitDown" /> - </menu_item_call> - <menu_item_call - label="Stand Up" - layout="topleft" - shortcut="alt|shift|S" - name="Stand up"> - <menu_item_call.on_click - function="Self.StandUp"/> - <menu_item_call.on_visible - function="Self.EnableStandUp"/> - <menu_item_call.on_enable - function="Self.EnableStandUp" /> - </menu_item_call> - <menu_item_check - label="Fly" - name="Fly" - shortcut="HOME"> - <menu_item_check.on_check - function="Agent.getFlying" /> - <menu_item_check.on_click - function="Agent.toggleFlying" /> - <menu_item_check.on_enable - function="Agent.enableFlying" /> - </menu_item_check> - <menu_item_call - label="Stop flying" - name="Stop flying" - shortcut="HOME"> - <menu_item_call.on_click - function="Agent.toggleFlying" /> - <menu_item_call.on_enable - function="Agent.getFlying" /> - </menu_item_call> - <menu_item_check - label="Always Run" - name="Always Run" - shortcut="control|R"> - <menu_item_check.on_check - function="World.CheckAlwaysRun" /> - <menu_item_check.on_click - function="World.AlwaysRun" /> - </menu_item_check> - <menu_item_call - label="Stop Animating Me" - name="Stop Animating My Avatar"> - <menu_item_call.on_click - function="Tools.StopAllAnimations" /> - </menu_item_call> - <menu_item_call - label="Walk / run / fly..." - name="WalkRunFly"> - <menu_item_call.on_click - function="Floater.ToggleOrBringToFront" - parameter="moveview" /> - </menu_item_call> - </menu> - <menu - create_jump_keys="true" - label="Status" - name="Status" - tear_off="true"> - <menu_item_check - name="Away" - label="Away"> - <menu_item_check.on_check - function="View.Status.CheckAway" /> - <menu_item_check.on_click - function="World.SetAway" /> - </menu_item_check> - <menu_item_check - name="Do Not Disturb" - label="Do Not Disturb"> - <menu_item_check.on_check - function="View.Status.CheckDoNotDisturb" /> - <menu_item_check.on_click - function="World.SetDoNotDisturb"/> - </menu_item_check> - - </menu> + <menu_item_separator/> + <menu_item_check + name="Away" + label="Away"> + <menu_item_check.on_check + function="View.Status.CheckAway" /> + <menu_item_check.on_click + function="World.SetAway" /> + </menu_item_check> + <menu_item_check + name="Do Not Disturb" + label="Do Not Disturb"> + <menu_item_check.on_check + function="View.Status.CheckDoNotDisturb" /> + <menu_item_check.on_click + function="World.SetDoNotDisturb"/> + </menu_item_check> <menu_item_separator/> @@ -208,6 +107,15 @@ name="ManageMyAccount_url" parameter="WebLaunchJoinNow,http://secondlife.com/account/" /> </menu_item_call> + <menu_item_call + label="[Membership]" + name="Membership"> + <menu_item_call.on_click + function="Advanced.ShowURL" + parameter="https://secondlife.com/my/account/membership.php"/> + <menu_item_call.on_visible + function="Membership.UpdateLabel"/> + </menu_item_call> <menu_item_separator/> @@ -255,6 +163,334 @@ </menu> <menu create_jump_keys="true" + label="Avatar" + name="Avatar" + tear_off="true"> + <menu_item_call + label="Now wearing..." + name="NowWearing" + shortcut="control|O"> + <menu_item_call.on_click + function="NowWearing" /> + <menu_item_call.on_enable + function="Edit.EnableCustomizeAvatar" /> + </menu_item_call> + <menu_item_call + label="My outfits..." + name="ChangeOutfit"> + <menu_item_call.on_click + function="CustomizeAvatar" /> + <menu_item_call.on_enable + function="Edit.EnableCustomizeAvatar" /> + </menu_item_call> + <menu_item_call label="Hover height..." + layout="topleft" + shortcut="alt|control|H" + name="Hover Height"> + <menu_item_call.on_click + function="HoverHeight" /> + <menu_item_call.on_enable + function="Edit.EnableHoverHeight" /> + </menu_item_call> + <menu_item_call + label="Edit shape..." + layout="topleft" + name="Edit My Shape"> + <menu_item_call.on_click + function="EditShape" /> + <menu_item_call.on_enable + function="Edit.EnableEditShape" /> + </menu_item_call> + <menu_item_call + label="Edit outfit parts..." + layout="topleft" + name="Edit Outfit"> + <menu_item_call.on_click + function="EditOutfit" /> + <menu_item_call.on_enable + function="Edit.EnableCustomizeAvatar" /> + </menu_item_call> + <menu + label="Take off" + layout="topleft" + name="Take Off >"> + <menu + label="Clothes" + layout="topleft" + name="Clothes >"> + <menu_item_call + enabled="false" + label="Shirt" + layout="topleft" + name="Shirt"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="shirt" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="shirt" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Pants" + layout="topleft" + name="Pants"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="pants" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="pants" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Skirt" + layout="topleft" + name="Skirt"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="skirt" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="skirt" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Shoes" + layout="topleft" + name="Shoes"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="shoes" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="shoes" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Socks" + layout="topleft" + name="Socks"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="socks" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="socks" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Jacket" + layout="topleft" + name="Jacket"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="jacket" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="jacket" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Gloves" + layout="topleft" + name="Gloves"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="gloves" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="gloves" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Undershirt" + layout="topleft" + name="Self Undershirt"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="undershirt" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="undershirt" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Underpants" + layout="topleft" + name="Self Underpants"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="underpants" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="underpants" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Tattoo" + layout="topleft" + name="Self Tattoo"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="tattoo" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="tattoo" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Physics" + layout="topleft" + name="Self Physics"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="physics" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="physics" /> + </menu_item_call> + <menu_item_call + enabled="false" + label="Alpha" + layout="topleft" + name="Self Alpha"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="alpha" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="alpha" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="All Clothes" + layout="topleft" + name="All Clothes"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="all" /> + </menu_item_call> + </menu> + <menu + label="HUD" + layout="topleft" + name="Avatar Detach HUD" /> + <menu + label="Detach" + layout="topleft" + name="Avatar Detach" /> + <menu_item_call + label="Detach All" + layout="topleft" + name="Detach All"> + <menu_item_call.on_click + function="Self.RemoveAllAttachments" + parameter="" /> + <menu_item_call.on_enable + function="Self.EnableRemoveAllAttachments" /> + </menu_item_call> + </menu> + <menu_item_separator/> + <menu_item_call + label="Complete avatars..." + name="Avatar Picker"> + <menu_item_call.on_click + function="Floater.ToggleOrBringToFront" + parameter="avatar" /> + </menu_item_call> + <menu_item_separator/> + + <menu_item_call + label="Sit / stand" + layout="topleft" + shortcut="alt|shift|S" + name="Sit stand"> + <menu_item_call.on_click + function="Self.ToggleSitStand"/> + <menu_item_call.on_enable + function="Self.EnableSitStand" /> + </menu_item_call> + <menu_item_call + label="Fly / land" + name="Fly land" + shortcut="HOME"> + <menu_item_call.on_click + function="Agent.toggleFlying" /> + <menu_item_call.on_enable + function="Agent.enableFlyLand" /> + </menu_item_call> + <menu_item_call + label="Stop animations" + name="Stop Animating My Avatar"> + <menu_item_call.on_click + function="Tools.StopAllAnimations" /> + </menu_item_call> + <menu_item_check + label="Walk / run / fly..." + name="WalkRunFly"> + <menu_item_check.on_check + function="Floater.Visible" + parameter="moveview" /> + <menu_item_check.on_click + function="Floater.ToggleOrBringToFront" + parameter="moveview" /> + </menu_item_check> + <menu_item_check + label="Always run" + name="Always Run" + shortcut="control|R"> + <menu_item_check.on_check + function="World.CheckAlwaysRun" /> + <menu_item_check.on_click + function="World.AlwaysRun" /> + </menu_item_check> + <menu_item_separator/> + <menu_item_check + label="Gestures..." + name="Gestures" + shortcut="control|G"> + <menu_item_check.on_check + function="Floater.Visible" + parameter="gestures" /> + <menu_item_check.on_click + function="Floater.Toggle" + parameter="gestures" /> + </menu_item_check> + <menu_item_separator/> + <menu_item_call + label="Reset skeleton" + layout="topleft" + name="Reset Skeleton"> + <menu_item_call.on_click + function="Avatar.ResetSkeleton" /> + </menu_item_call> + <menu_item_call + label="Reset skeleton and animations" + layout="topleft" + name="Reset Skeleton And Animations"> + <menu_item_call.on_click + function="Avatar.ResetSkeletonAndAnimations" /> + </menu_item_call> + <menu_item_call + label="Attachment scripts..." + name="MyScripts"> + <menu_item_call.on_click + function="Floater.ToggleOrBringToFront" + parameter="my_scripts"/> + </menu_item_call> + <menu_item_separator/> + <menu_item_call + label="Help with avatars..." + name="Help with avatars"> + <menu_item_call.on_click + function="Advanced.ShowURL" + parameter="https://community.secondlife.com/search/?type=cms_records3&tags=avatar&nodes=30&search_and_or=or"/> + </menu_item_call> + </menu> + <menu + create_jump_keys="true" label="Communicate" name="Communicate" tear_off="true"> @@ -306,21 +542,6 @@ parameter="conversation" /> </menu_item_check> <menu_item_separator/> - <menu_item_call - label="Twitter..." - name="Twitter"> - <menu_item_call.on_click - function="Floater.Toggle" - parameter="twitter"/> - </menu_item_call> - <menu_item_call - label="Flickr..." - name="Flickr"> - <menu_item_call.on_click - function="Floater.Toggle" - parameter="flickr"/> - </menu_item_call> - <menu_item_separator/> <menu label="Voice morphing" name="VoiceMorphing" @@ -468,10 +689,11 @@ </menu_item_check> <menu_item_call label="Events" - name="Events"> + name="Events" + shortcut="control|E"> <menu_item_call.on_click function="Advanced.ShowURL" - parameter="http://events.secondlife.com"/> + parameter="https://secondlife.com/my/community/events"/> </menu_item_call> <menu_item_check label="Search..." @@ -534,12 +756,18 @@ parameter="region_info" /> </menu_item_call> <menu_item_call - label="My land holdings..." - name="My Land"> + label="My Linden Home..." + name="Linden Home"> + <menu_item_call.on_click + function="World.LindenHome"/> + </menu_item_call> + <menu_item_call + label="My land holdings..." + name="My Land"> <menu_item_call.on_click function="Floater.Show" parameter="land_holdings" /> - </menu_item_call> + </menu_item_call> <menu_item_call label="Buy this land" name="Buy Land"> @@ -616,8 +844,7 @@ <menu_item_separator /> <menu_item_check label="Advanced Menu" - name="Show Advanced Menu" - shortcut="control|alt|shift|D"> + name="Show Advanced Menu"> <on_check function="CheckControl" parameter="UseDebugMenus" /> @@ -652,12 +879,13 @@ <menu create_jump_keys="true" - label="Sun" - name="Sun" + label="Environment" + name="Environment" tear_off="true"> <menu_item_check label="Sunrise" - name="Sunrise"> + name="Sunrise" + shortcut="control|shift|O"> <menu_item_check.on_click function="World.EnvSettings" parameter="sunrise" /> @@ -689,7 +917,8 @@ </menu_item_check> <menu_item_check label="Midnight" - name="Midnight"> + name="Midnight" + shortcut="control|shift|Z"> <menu_item_check.on_click function="World.EnvSettings" parameter="midnight" /> @@ -697,10 +926,9 @@ function="World.EnableEnvSettings" parameter="midnight" /> </menu_item_check> - <menu_item_separator/> <menu_item_check - label="Use Region Settings" - name="Use Region Settings"> + label="Use Shared Environment" + name="Use Shared Environment"> <menu_item_check.on_click function="World.EnvSettings" parameter="region" /> @@ -708,113 +936,105 @@ function="World.EnableEnvSettings" parameter="region" /> </menu_item_check> - </menu> - - + <menu_item_separator/> + <menu_item_call + label="My Environments..." + name="my_environs"> + <menu_item_call.on_click + function="World.EnvSettings" + parameter="my_environs" /> + </menu_item_call> + +<menu_item_call + label="Personal Lighting..." + name="adjustment_tool"> + <menu_item_call.on_click + function="World.EnvSettings" + parameter="adjust_tool" /> + </menu_item_call> + <menu_item_separator/> + <menu_item_check + label="Pause Clouds" + name="pause_clouds"> + <menu_item_check.on_click + function="World.EnvSettings" + parameter="pause_clouds" /> + <menu_item_check.on_check + function="World.EnableEnvSettings" + parameter="pause_clouds" /> + </menu_item_check> + </menu> + +<!-- <menu create_jump_keys="true" label="Environment Editor" name="Environment Editor" tear_off="true"> - - <menu_item_call + <menu_item_call label="Environment Settings..." name="Environment Settings"> - <menu_item_call.on_click +<menu_item_call.on_click function="World.EnvSettings" parameter="editor"/> </menu_item_call> - - <menu_item_separator/> - - <menu + <menu_item_separator/> +<menu name="Water Presets" label="Water Presets"> - <menu_item_call - label="New preset..." +<menu_item_call +label="New preset..." name="new_water_preset"> - <menu_item_call.on_click - function="World.EnvPreset" +<menu_item_call.on_click +function="World.EnvPreset" parameter="new_water"/> - </menu_item_call> - <menu_item_call - label="Edit preset..." +</menu_item_call> +<menu_item_call +label="Edit preset..." name="edit_water_preset"> - <menu_item_call.on_click - function="World.EnvPreset" +<menu_item_call.on_click +function="World.EnvPreset" parameter="edit_water"/> - </menu_item_call> - <menu_item_call - label="Delete preset..." - name="delete_water_preset"> - <menu_item_call.on_click - function="World.EnvPreset" - parameter="delete_water"/> - <menu_item_call.on_enable - function="World.EnableEnvPreset" - parameter="delete_water"/> - </menu_item_call> - </menu> - - <menu - name="Sky Presets" +</menu_item_call> +</menu> + <menu +name="Sky Presets" label="Sky Presets"> - <menu_item_call - label="New preset..." +<menu_item_call +label="New preset..." name="new_sky_preset"> - <menu_item_call.on_click - function="World.EnvPreset" +<menu_item_call.on_click +function="World.EnvPreset" parameter="new_sky"/> - </menu_item_call> - <menu_item_call - label="Edit preset..." +</menu_item_call> +<menu_item_call +label="Edit preset..." name="edit_sky_preset"> - <menu_item_call.on_click - function="World.EnvPreset" +<menu_item_call.on_click +function="World.EnvPreset" parameter="edit_sky"/> - </menu_item_call> - <menu_item_call - label="Delete preset..." - name="delete_sky_preset"> - <menu_item_call.on_click - function="World.EnvPreset" - parameter="delete_sky"/> - <menu_item_call.on_enable - function="World.EnableEnvPreset" - parameter="delete_sky"/> - </menu_item_call> - </menu> - - <menu - name="Day Presets" +</menu_item_call> +</menu> +<menu +name="Day Presets" label="Day Presets"> - <menu_item_call - label="New preset..." +<menu_item_call +label="New preset..." name="new_day_preset"> - <menu_item_call.on_click - function="World.EnvPreset" +<menu_item_call.on_click +function="World.EnvPreset" parameter="new_day_cycle"/> - </menu_item_call> - <menu_item_call - label="Edit preset..." +</menu_item_call> +<menu_item_call +label="Edit preset..." name="edit_day_preset"> - <menu_item_call.on_click - function="World.EnvPreset" +<menu_item_call.on_click +function="World.EnvPreset" parameter="edit_day_cycle"/> - </menu_item_call> - <menu_item_call - label="Delete preset..." - name="delete_day_preset"> - <menu_item_call.on_click - function="World.EnvPreset" - parameter="delete_day_cycle"/> - <menu_item_call.on_enable - function="World.EnableEnvPreset" - parameter="delete_day_cycle"/> - </menu_item_call> - </menu> - </menu> - +</menu_item_call> +</menu> +</menu> +--> </menu> <menu @@ -1044,8 +1264,7 @@ shortcut="control|D"> <menu_item_call.on_click function="Object.Duplicate" /> - - </menu_item_call> + </menu_item_call> </menu> <menu create_jump_keys="true" @@ -1306,7 +1525,7 @@ function="File.EnableUpload" /> <menu_item_call.on_visible function="Upload.CalculateCosts" - parameter="Upload Image" /> + parameter="Upload Image,texture" /> </menu_item_call> <menu_item_call label="Sound (L$[COST])..." @@ -1319,7 +1538,7 @@ function="File.EnableUpload" /> <menu_item_call.on_visible function="Upload.CalculateCosts" - parameter="Upload Sound" /> + parameter="Upload Sound,sound" /> </menu_item_call> <menu_item_call label="Animation (L$[COST])..." @@ -1332,12 +1551,13 @@ function="File.EnableUpload" /> <menu_item_call.on_visible function="Upload.CalculateCosts" - parameter="Upload Animation" /> + parameter="Upload Animation,animation" /> </menu_item_call> <menu_item_call label="Model..." layout="topleft" - name="Upload Model"> + name="Upload Model" + shortcut="alt|control|U"> <menu_item_call.on_click function="File.UploadModel" parameter="" /> @@ -1347,9 +1567,12 @@ function="File.VisibleUploadModel"/> </menu_item_call> <menu_item_call - label="Bulk (L$[COST] per file)..." + label="Bulk..." layout="topleft" name="Bulk Upload"> + <menu_item_call.on_visible + function="Upload.CalculateCosts" + parameter="Bulk Upload,texture" /> <menu_item_call.on_click function="File.UploadBulk" parameter="" /> @@ -1387,20 +1610,13 @@ name="Help" tear_off="true"> <menu_item_call - label="How to..." + label="Guidebook" name="How To" shortcut="F1"> <menu_item_call.on_click function="Help.ToggleHowTo" parameter="" /> </menu_item_call> - <menu_item_call - label="Quickstart" - name="Quickstart"> - <menu_item_call.on_click - function="Advanced.ShowURL" - parameter="http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Quickstart/ta-p/1087919"/> - </menu_item_call> <!-- <menu_item_call label="Tutorial" name="Tutorial"> @@ -1750,6 +1966,16 @@ parameter="character" /> </menu_item_check> <menu_item_check + label="Animeshes" + name="Rendering Type Control Avatar"> + <menu_item_check.on_check + function="Advanced.CheckRenderType" + parameter="controlAV" /> + <menu_item_check.on_click + function="Advanced.ToggleRenderType" + parameter="controlAV" /> + </menu_item_check> + <menu_item_check label="Surface Patch" name="Rendering Type Surface Patch" shortcut="control|alt|shift|5"> @@ -1989,20 +2215,6 @@ name="Shortcuts" tear_off="true" visible="false"> - <!-- This second, alternative shortcut for Show Advanced Menu is for backward compatibility. The main shortcut has been changed so it's Linux-friendly, where the old shortcut is typically eaten by the window manager. --> - <menu_item_check - label="Show Advanced Menu - legacy shortcut" - name="Show Advanced Menu - legacy shortcut" - shortcut="control|alt|D"> - <on_check - function="CheckControl" - parameter="UseDebugMenus" /> - <on_click - function="ToggleControl" - parameter="UseDebugMenus" /> - </menu_item_check> - - <menu_item_separator/> <menu_item_call label="Close Window" @@ -2445,6 +2657,18 @@ function="Advanced.ForceErrorSoftwareException" /> </menu_item_call> <menu_item_call + label="Force a Crash in a Coroutine" + name="Force a Crash in a Coroutine"> + <menu_item_call.on_click + function="Advanced.ForceErrorCoroutineCrash" /> + </menu_item_call> + <menu_item_call + label="Force a Crash in a Thread" + name="Force a Crash in a Thread"> + <menu_item_call.on_click + function="Advanced.ForceErrorThreadCrash" /> + </menu_item_call> + <menu_item_call label="Force Disconnect Viewer" name="Force Disconnect Viewer"> <menu_item_call.on_click @@ -2949,6 +3173,36 @@ parameter="TextureDisable" /> </menu_item_check> <menu_item_check + label="Disable Ambient" + name="Disable Ambient"> + <menu_item_check.on_check + function="CheckControl" + parameter="AmbientDisable" /> + <menu_item_check.on_click + function="ToggleShaderControl" + parameter="AmbientDisable" /> + </menu_item_check> + <menu_item_check + label="Disable Sunlight" + name="Disable Sunlight"> + <menu_item_check.on_check + function="CheckControl" + parameter="SunlightDisable" /> + <menu_item_check.on_click + function="ToggleShaderControl" + parameter="SunlightDisable" /> + </menu_item_check> + <menu_item_check + label="Disable Local Lights" + name="Disable Local Lights"> + <menu_item_check.on_check + function="CheckControl" + parameter="LocalLightDisable" /> + <menu_item_check.on_click + function="ToggleShaderControl" + parameter="LocalLightDisable" /> + </menu_item_check> + <menu_item_check label="Full Res Textures" name="Rull Res Textures"> <menu_item_check.on_check @@ -3610,7 +3864,7 @@ <menu_item_call label="Debug Avatar Textures" name="Debug Avatar Textures" - shortcut="control|alt|shift|A"> + shortcut="control|alt|shift|K"> <menu_item_call.on_click function="Advanced.DebugAvatarTextures" /> </menu_item_call> diff --git a/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml index aa56b4ba63..20c81c983b 100644 --- a/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml +++ b/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml @@ -4,6 +4,7 @@ <menu_item_call label="Replace" layout="topleft" + visible="false" name="wear_replace"> <on_click function="Wearable.Wear" /> @@ -11,6 +12,7 @@ <menu_item_call label="Wear" layout="topleft" + visible="false" name="wear_wear"> <on_click function="Wearable.Wear" /> @@ -18,13 +20,29 @@ <menu_item_call label="Add" layout="topleft" + visible="false" name="wear_add"> <on_click function="Wearable.Add" /> </menu_item_call> <menu_item_call + label="Touch" + layout="topleft" + name="touch" + visible="false" + on_click.function="Attachment.Touch" + /> + <menu_item_call + label="Edit" + layout="topleft" + name="edit" + visible="false" + on_click.function="Wearable.Edit" + /> + <menu_item_call label="Take Off / Detach" layout="topleft" + visible="false" name="take_off_or_detach"> <on_click function="Wearable.TakeOffDetach" /> @@ -32,6 +50,7 @@ <menu_item_call label="Detach" layout="topleft" + visible="false" name="detach"> <on_click function="Attachment.Detach" /> @@ -47,20 +66,15 @@ <menu_item_call label="Take Off" layout="topleft" + visible="false" name="take_off"> <on_click function="Clothing.TakeOff" /> </menu_item_call> <menu_item_call - label="Edit" - layout="topleft" - name="edit"> - <on_click - function="Wearable.Edit" /> - </menu_item_call> - <menu_item_call label="Item Profile" layout="topleft" + visible="false" name="object_profile"> <on_click function="Attachment.Profile" /> @@ -68,6 +82,7 @@ <menu_item_call label="Show Original" layout="topleft" + visible="false" name="show_original"> <on_click function="Wearable.ShowOriginal" /> @@ -75,6 +90,7 @@ <menu_item_call label="Create New" layout="topleft" + visible="false" name="create_new" translate="false"> <on_click @@ -83,6 +99,7 @@ <menu_item_call label="--no options--" layout="topleft" + visible="false" name="--no options--" translate="false"> </menu_item_call> diff --git a/indra/newview/skins/default/xui/en/menu_wearing_gear.xml b/indra/newview/skins/default/xui/en/menu_wearing_gear.xml index 0e858ccf10..57b20dfda9 100644 --- a/indra/newview/skins/default/xui/en/menu_wearing_gear.xml +++ b/indra/newview/skins/default/xui/en/menu_wearing_gear.xml @@ -4,11 +4,24 @@ visible="false" name="Gear Wearing"> <menu_item_call - label="Edit Outfit" + label="Touch" + layout="topleft" + name="touch"> + <on_click + function="Gear.TouchAttach" /> + <on_enable + function="Gear.OnEnable" + parameter="touch_attach" /> + </menu_item_call> + <menu_item_call + label="Edit" layout="topleft" - name="edit"> + name="edit_item"> <on_click - function="Gear.Edit" /> + function="Gear.EditItem" /> + <on_enable + function="Gear.OnEnable" + parameter="edit_item" /> </menu_item_call> <menu_item_call label="Take Off" @@ -20,6 +33,14 @@ function="Gear.OnEnable" parameter="take_off" /> </menu_item_call> + <menu_item_separator /> + <menu_item_call + label="Edit Outfit" + layout="topleft" + name="edit_outfit"> + <on_click + function="Gear.EditOutfit" /> + </menu_item_call> <menu_item_call label="Copy outfit list to clipboard" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/menu_wearing_tab.xml b/indra/newview/skins/default/xui/en/menu_wearing_tab.xml index 75c1de24aa..b8e2b44884 100644 --- a/indra/newview/skins/default/xui/en/menu_wearing_tab.xml +++ b/indra/newview/skins/default/xui/en/menu_wearing_tab.xml @@ -3,6 +3,20 @@ layout="topleft" name="Wearing"> <menu_item_call + label="Touch" + layout="topleft" + name="touch_attach"> + <on_click + function="Wearing.TouchAttach" /> + </menu_item_call> + <menu_item_call + label="Edit" + layout="topleft" + name="edit_item"> + <on_click + function="Wearing.EditItem" /> + </menu_item_call> + <menu_item_call label="Take Off" layout="topleft" name="take_off"> @@ -23,16 +37,9 @@ <menu_item_call label="Edit Outfit" layout="topleft" - name="edit"> + name="edit_outfit"> <on_click - function="Wearing.Edit" /> - </menu_item_call> - <menu_item_call - label="Edit" - layout="topleft" - name="edit_item"> - <on_click - function="Wearing.EditItem" /> + function="Wearing.EditOutfit" /> </menu_item_call> <menu_item_call label="Show Original" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index f72767cceb..d4f71fb370 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -686,6 +686,18 @@ Do you want to revoke modify rights for the selected Residents? <notification icon="alertmodal.tga" + name="GroupNameLengthWarning" + type="alertmodal"> +A group name must be between [MIN_LEN] and [MAX_LEN] characters. + <tag>group</tag> + <tag>fail</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" name="UnableToCreateGroup" type="alertmodal"> Unable to create group. @@ -920,7 +932,7 @@ You do not have enough L$ to join this group. icon="alertmodal.tga" name="CreateGroupCost" type="alertmodal"> -Creating this group will cost L$100. +Creating this group will cost L$[COST]. Groups need more than one member, or they are deleted forever. Please invite members within 48 hours. <tag>group</tag> @@ -929,7 +941,7 @@ Please invite members within 48 hours. canceltext="Cancel" name="okcancelbuttons" notext="Cancel" - yestext="Create group for L$100"/> + yestext="Create group for L$[COST]"/> </notification> <notification @@ -1012,18 +1024,6 @@ The group no longer has open enrollment. <notification icon="alertmodal.tga" - name="JoinGroupSuccess" - type="alertmodal"> -You have been added to the group - <tag>group_id</tag> - <tag>success</tag> - <usetemplate - name="okbutton" - yestext="OK"/> - </notification> - - <notification - icon="alertmodal.tga" name="JoinGroupInsufficientFunds" type="alertmodal"> Unable to transfer the required L$ [membership_fee] membership fee. @@ -1291,6 +1291,14 @@ Error encoding snapshot. <notification icon="alertmodal.tga" + name="ErrorCannotAffordUpload" + type="alertmodal"> + You need L$[COST] to upload this item. + <tag>fail</tag> + </notification> + + <notification + icon="alertmodal.tga" name="ErrorTextureCannotAfford" type="alertmodal"> You need L$[COST] to save a texture to your inventory. You may either buy L$ or save the photo to your computer instead. @@ -1323,6 +1331,18 @@ You must agree to the Second Life Terms and Conditions, Privacy Policy, and Term <notification icon="alertmodal.tga" + name="CouldNotBuyCurrency" + type="alertmodal"> +[TITLE] +[MESSAGE] + <tag>fail</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" name="CouldNotPutOnOutfit" type="alertmodal"> Could not put on outfit. @@ -1493,7 +1513,7 @@ Go to the [SECOND_LIFE] events web page? <tag>confirm</tag> <url option="0" name="url"> - http://secondlife.com/events/ + https://secondlife.com/my/community/events </url> <usetemplate name="okcancelbuttons" @@ -2180,7 +2200,7 @@ Wrong chunk size in WAV file: icon="alertmodal.tga" name="SoundFileInvalidTooLong" type="alertmodal"> -Audio file is too long (10 second maximum): +Audio file is too long (30 second maximum): [FILE] <tag>fail</tag> </notification> @@ -2259,6 +2279,7 @@ Unable to create output file: [FILE] icon="alertmodal.tga" name="DoNotSupportBulkAnimationUpload" type="alertmodal"> + <unique/> [APP_NAME] does not currently support bulk upload of BVH format animation files. <tag>fail</tag> </notification> @@ -2299,6 +2320,29 @@ You cannot create a landmark here because the owner of the land doesn't all </notification> <notification + icon="alertmodal.tga" + label="Create folder" + name="CreateLandmarkFolder" + type="alertmodal"> + <unique/> + Choose a name for the folder: + <tag>confirm</tag> + <form name="form"> + <input name="message" type="text"> + </input> + <button + default="true" + index="0" + name="OK" + text="OK"/> + <button + index="1" + name="Cancel" + text="Cancel"/> + </form> + </notification> + + <notification icon="alertmodal.tga" name="CannotRecompileSelectObjectsNoScripts" type="alertmodal"> @@ -2410,9 +2454,8 @@ Teleport failed. icon="alertmodal.tga" name="invalid_tport" type="alertmodal"> -Problem encountered processing your teleport request. You may need to log back in before you can teleport. -If you continue to get this message, please check the [SUPPORT_SITE]. - <tag>fail</tag> +Teleport attempts are limited to 6 per minute. If you are having trouble, wait one minute and try teleporting again. If the problem persists, log out and log in again. + <tag>fail</tag> </notification> <notification icon="alertmodal.tga" @@ -2480,6 +2523,13 @@ Sorry, but the system was unable to complete your region crossing in a timely fa </notification> <notification icon="alertmodal.tga" + name="preexisting_tport" + type="alertmodal"> + <tag>fail</tag> +Sorry, but the system was unable to start your teleport. Please try again in a few minutes. + </notification> + <notification + icon="alertmodal.tga" name="no_host" type="alertmodal"> <tag>fail</tag> @@ -3093,6 +3143,52 @@ See https://wiki.secondlife.com/wiki/Adding_Spelling_Dictionaries <notification icon="alertmodal.tga" + label="Rename Gesture" + name="RenameGesture" + type="alertmodal"> + New gesture name: + <tag>confirm</tag> + <form name="form"> + <input name="new_name" type="text" width="300"> + [NAME] + </input> + <button + default="true" + index="0" + name="OK" + text="OK"/> + <button + index="1" + name="Cancel" + text="Cancel"/> + </form> + </notification> + + <notification + icon="alertmodal.tga" + label="Rename Landmark" + name="RenameLandmark" + type="alertmodal"> + Choose a new name for [NAME] + <tag>confirm</tag> + <form name="form"> + <input name="new_name" type="text" width="300"> + [NAME] + </input> + <button + default="true" + index="0" + name="OK" + text="OK"/> + <button + index="1" + name="Cancel" + text="Cancel"/> + </form> + </notification> + + <notification + icon="alertmodal.tga" name="RemoveFromFriends" type="alertmodal"> <tag>friendship</tag> @@ -3123,7 +3219,7 @@ Do you want to remove multiple friends from your Friends list? type="alertmodal"> Are you sure you want to delete all scripted objects owned by ** [AVATAR_NAME] ** -on all others land in this sim? +on all others land in this region? <tag>confirm</tag> <usetemplate name="okcancelbuttons" @@ -3137,7 +3233,7 @@ on all others land in this sim? type="alertmodal"> Are you sure you want to DELETE ALL scripted objects owned by ** [AVATAR_NAME] ** -on ALL LAND in this sim? +on ALL LAND in this region? <tag>confirm</tag> <usetemplate name="okcancelbuttons" @@ -3151,7 +3247,7 @@ on ALL LAND in this sim? type="alertmodal"> Are you sure you want to DELETE ALL objects (scripted or not) owned by ** [AVATAR_NAME] ** -on ALL LAND in this sim? +on ALL LAND in this region? <tag>confirm</tag> <usetemplate name="okcancelbuttons" @@ -3410,6 +3506,9 @@ Display settings have been set to recommended levels because of a change to the icon="alertmodal.tga" name="ErrorMessage" type="alertmodal"> + <unique> + <context>ERROR_MESSAGE</context> + </unique> [ERROR_MESSAGE] <tag>fail</tag> <usetemplate @@ -3518,6 +3617,26 @@ If this is your first time using [SECOND_LIFE], you will need to create an accou <notification icon="alertmodal.tga" + name="LoginCantRemoveUsername" + type="alertmodal"> + <tag>fail</tag> +Already remembered user can be forgotten from Me > Preferences > Advanced > Remembered Usernames. + </notification> + + <notification + icon="alertmodal.tga" + name="LoginCantRemoveCurUsername" + type="alertmodal"> + <tag>confirm</tag> +Forgetting the logged-in user requires you to log out. + <usetemplate + name="okcancelbuttons" + notext="Cancel" + yestext="Confirm and log out"/> + </notification> + + <notification + icon="alertmodal.tga" name="LoginPacketNeverReceived" type="alertmodal"> <tag>fail</tag> @@ -3547,6 +3666,42 @@ You can either check your Internet connection and try again in a few minutes, cl <notification icon="alertmodal.tga" + name="LoginPacketNeverReceivedNoTP" + type="alertmodal"> + <tag>fail</tag> +We're having trouble connecting. There may be a problem with your Internet connection or the [SECOND_LIFE_GRID]. + +You can either check your Internet connection and try again in a few minutes or click Help to view the [SUPPORT_SITE]. + <url option="1" name="url"> + http://secondlife.com/support/ + </url> + <form name="form"> + <button + default="true" + index="0" + name="OK" + text="OK"/> + <button + index="1" + name="Help" + text="Help"/> + </form> + </notification> + + <notification + icon="alertmodal.tga" + name="LoginRemoveMultiGridUserData" + type="alertmodal"> + <tag>confirm</tag> +Local Data you are deleting is shared between multiple grids, are you sure you want to delete it? + <usetemplate + name="okcancelbuttons" + notext="Cancel" + yestext="Confirm"/> + </notification> + + <notification + icon="alertmodal.tga" name="WelcomeChooseSex" type="alertmodal"> Your character will appear in a moment. @@ -3570,6 +3725,17 @@ Could not teleport to [SLURL] as it's on a different grid ([GRID]) than the curr </notification> <notification icon="alertmodal.tga" + name="GeneralCertificateErrorShort" + type="alertmodal"> +Could not connect to the server. +[REASON] + <tag>fail</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification icon="alertmodal.tga" name="GeneralCertificateError" type="alertmodal"> Could not connect to the server. @@ -3906,6 +4072,8 @@ Finished download of raw terrain file to: [DOWNLOAD_PATH]. </notification> + <!-- RequiredUpdate does not display release notes URL because we don't get + that from login.cgi's login failure message. --> <notification icon="alertmodal.tga" name="RequiredUpdate" @@ -3923,6 +4091,8 @@ Please download from https://secondlife.com/support/downloads/ name="PauseForUpdate" type="alertmodal"> Version [VERSION] is required for login. +Release notes: [URL] + Click OK to download and install. <tag>confirm</tag> <usetemplate @@ -3935,6 +4105,8 @@ Click OK to download and install. name="OptionalUpdateReady" type="alertmodal"> Version [VERSION] has been downloaded and is ready to install. +Release notes: [URL] + Click OK to install. <tag>confirm</tag> <usetemplate @@ -3947,6 +4119,8 @@ Click OK to install. name="PromptOptionalUpdate" type="alertmodal"> Version [VERSION] has been downloaded and is ready to install. +Release notes: [URL] + Proceed? <tag>confirm</tag> <usetemplate @@ -4116,13 +4290,6 @@ Leave Group? yestext="OK"/> </notification> - <notification - icon="notify.tga" - name="GroupDepart" - type="notify"> -You have left the group '<nolink>[group_name]</nolink>'. - <tag>group</tag> - </notification> <notification icon="alertmodal.tga" @@ -4268,11 +4435,21 @@ You have reached your maximum number of groups. Please leave some group before j icon="alert.tga" name="GroupLimitInfo" type="alert"> -The group limit for base accounts is [MAX_BASIC], and for [https://secondlife.com/premium/ premium] -accounts is [MAX_PREMIUM]. -If you downgraded your account, you will need to get below [MAX_BASIC] group limit before you can join more. +Residents with Basic memberships may join up to [MAX_BASIC] groups. +Premium memberships allow up to [MAX_PREMIUM]. [https://secondlife.com/my/account/membership.php? Learn more or upgrade] + <tag>group</tag> + <usetemplate + name="okbutton" + yestext="Close"/> + </notification> -[https://secondlife.com/my/account/membership.php Upgrade today!] + <notification + icon="alert.tga" + name="GroupLimitInfoPlus" + type="alert"> +Residents with Basic memberships may join up to [MAX_BASIC] groups. +Premium memberships allow up to [MAX_PREMIUM]. Premium Plus +memberships allow up to [MAX_PREMIUM_PLUS]. [https://secondlife.com/my/account/membership.php? Learn more or upgrade] <tag>group</tag> <usetemplate name="okbutton" @@ -4898,10 +5075,26 @@ Unchecking this option may remove restrictions that parcel owners have added to <notification icon="alertmodal.tga" + name="EstateParcelEnvironmentOverride" + type="alertmodal"> +(Estate-wide change: [ESTATENAME]) Unchecking this option will remove any custom environments that parcel owners have added to their parcels. Please discuss with your parcel owners as needed. +Do you wish to proceed? + <tag>confirm</tag> + <usetemplate + name="okcancelbuttons" + notext="Cancel" + yestext="OK"/> + </notification> + + + <notification + icon="alertmodal.tga" name="RegionEntryAccessBlocked" type="alertmodal"> <tag>fail</tag> - The region you're trying to visit contains content exceeding your current preferences. You can change your preferences using Me > Preferences > General. + The region you’re trying to visit has a maturity rating exceeding your maximum maturity preference. Change this preference using Me menu > Preferences > General. + +Complete information on maturity ratings can be found [https://community.secondlife.com/knowledgebase/english/maturity-ratings-r52/ here]. <usetemplate name="okbutton" yestext="OK"/> @@ -4988,7 +5181,9 @@ The region you're trying to visit contains [REGIONMATURITY] content, but your cu name="TeleportEntryAccessBlocked" type="alertmodal"> <tag>fail</tag> - The region you're trying to visit contains content exceeding your current preferences. You can change your preferences using Me > Preferences > General. + The region you’re trying to visit has a maturity rating exceeding your maximum maturity preference. Change this preference using Me menu > Preferences > General. + +Complete information on maturity ratings can be found [https://community.secondlife.com/knowledgebase/english/maturity-ratings-r52/ here]. <usetemplate name="okbutton" yestext="OK"/> @@ -5137,6 +5332,8 @@ You won't receive any more notifications that you're about to visit a region wit name="LandClaimAccessBlocked" type="alertmodal"> The land you're trying to claim has a maturity rating exceeding your current preferences. You can change your preferences using Me > Preferences > General. + +Complete information on maturity ratings can be found [https://community.secondlife.com/knowledgebase/english/maturity-ratings-r52/ here]. <tag>fail</tag> <usetemplate name="okbutton" @@ -5206,6 +5403,8 @@ You won't receive any more notifications that you're about to visit a region wit name="LandBuyAccessBlocked" type="alertmodal"> The land you're trying to buy has a maturity rating exceeding your current preferences. You can change your preferences using Me > Preferences > General. + +Complete information on maturity ratings can be found [https://community.secondlife.com/knowledgebase/english/maturity-ratings-r52/ here]. <tag>fail</tag> <usetemplate name="okbutton" @@ -5999,6 +6198,34 @@ Would you like to turn off Do Not Disturb before completing this transaction? </notification> <notification + icon="notify.tga" + label="Parcel is Playing Media" + name="ParcelPlayingMedia" + persist="false" + type="notify"> +This location plays media: +[URL] +Would you like to play it? + <tag>confirm</tag> + <form name="form"> + <ignore name="ignore" + checkbox_only="true" + text="Always choose this option for this land."/> + <button + ignore="Play Media" + index="1" + name="Yes" + text="Play"/> + <button + default="true" + ignore="Ignore Media" + index="0" + name="No" + text="Don't play"/> + </form> + </notification> + + <notification icon="alertmodal.tga" name="ConfirmDeleteProtectedCategory" type="alertmodal"> @@ -6110,6 +6337,20 @@ Are you sure you want to permanently delete the contents of your Lost And Found? <notification icon="alertmodal.tga" + name="ConfirmReplaceLink" + type="alertmodal"> +You're about to replace '[TYPE]' body part link with the item which doesn't match the type. +Are you sure you want to proceed? + <tag>confirm</tag> + <usetemplate + ignoretext="Confirm before I replace link" + name="okcancelignore" + notext="No" + yestext="Yes"/> + </notification> + + <notification + icon="alertmodal.tga" name="CopySLURL" type="alertmodal"> The following SLurl has been copied to your clipboard: @@ -6155,7 +6396,23 @@ This day cycle file references a missing sky file: [SKY]. icon="alertmodal.tga" name="WLRegionApplyFail" type="alertmodal"> -Sorry, the settings couldn't be applied to the region. Leaving the region and then returning may help rectify the problem. The reason given was: [FAIL_REASON] +Sorry, the settings couldn't be applied to the region. Reason: [FAIL_REASON] + </notification> + + <notification + icon="alertmodal.tga" + name="WLLocalTextureDayBlock" + type="alertmodal"> +A Local texture is in use on track [TRACK], frame #[FRAMENO] ([FRAME]%) in field [FIELD]. +Settings may not be saved using local textures. + </notification> + + <notification + icon="alertmodal.tga" + name="WLLocalTextureFixedBlock" + type="alertmodal"> +A local texture is in use in field [FIELD]. +Settings may not be saved using local textures. </notification> <notification @@ -6711,20 +6968,6 @@ Please select at least one type of content to search (General, Moderate, or Adul <notification icon="notify.tga" - name="FlickrConnect" - type="notifytip"> - [MESSAGE] - </notification> - - <notification - icon="notify.tga" - name="TwitterConnect" - type="notifytip"> - [MESSAGE] - </notification> - - <notification - icon="notify.tga" name="PaymentReceived" log_to_im="true" persist="true" @@ -7026,12 +7269,16 @@ You can only claim public land in the Region you're in. </notification> <notification - icon="notify.tga" + icon="alertmodal.tga" name="RegionTPAccessBlocked" - persist="false" - type="notify"> + type="alertmodal"> <tag>fail</tag> - The region you're trying to visit contains content exceeding your current preferences. You can change your preferences using Me > Preferences > General. + The region you’re trying to visit has a maturity rating exceeding your maximum maturity preference. Change this preference using Me menu > Preferences > General. + +Complete information on maturity ratings can be found [https://community.secondlife.com/knowledgebase/english/maturity-ratings-r52/ here]. + <usetemplate + name="okbutton" + yestext="OK"/> </notification> <notification @@ -8356,6 +8603,18 @@ Can not overwrite default preset. </notification> <notification + icon="alertmodal.tga" + name="PresetAlreadyExists" + type="alertmodal"> +'[NAME]' is in use. You may replace +this preset or choose another name. + <tag>fail</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification icon="notifytip.tga" name="PresetNotDeleted" type="notifytip"> @@ -8402,9 +8661,50 @@ Your voice has been muted by moderator. name="okbutton" yestext="OK"/> </notification> + + <notification + icon="alertmodal.tga" + name="FailedToGetBenefits" + type="alertmodal"> + Unfortunately, we were unable to get benefits information for this session. This should not happen in a normal production environment. Please contact support. This session will not work normally and we recommend that you restart. + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="BulkUploadCostConfirmation" + type="alertmodal"> +This will upload [COUNT] items at a total cost of L$[COST]. Do you wish to continue with the upload? + <usetemplate + name="okcancelbuttons" + notext="Cancel" + yestext="Upload"/> + </notification> <notification icon="alertmodal.tga" + name="BulkUploadNoCompatibleFiles" + type="alertmodal"> +Selected files can not be bulk-uploaded. + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="BulkUploadIncompatibleFiles" + type="alertmodal"> +Some of the selected files can not be bulk-uploaded. + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" name="UploadCostConfirmation" type="alertmodal"> This upload will cost L$[PRICE], do you wish to continue with the upload? @@ -8418,7 +8718,7 @@ This upload will cost L$[PRICE], do you wish to continue with the upload? icon="alertmodal.tga" name="ConfirmClearTeleportHistory" type="alertmodal"> -Are you sure you want to delete your teleport history? +This will delete the entire list of places you have visited, and cannot be undone. Continue? <tag>confirm</tag> <usetemplate name="okcancelbuttons" @@ -9312,12 +9612,24 @@ Do you wish to continue? yestext="OK"/> </notification> + <global name="UnsupportedShaderRequirements"> +You do not appear to meet the hardware requirements for [APP_NAME]. [APP_NAME] requires OpenGL 2.0 or later shader support. If this is the case, you may want to make sure that you have the latest drivers for your graphics card, and service packs and patches for your operating system. + +If you continue to have problems, please visit the [SUPPORT_SITE]. + </global> + <global name="UnsupportedGLRequirements"> You do not appear to have the proper hardware requirements for [APP_NAME]. [APP_NAME] requires an OpenGL graphics card that has multitexture support. If this is the case, you may want to make sure that you have the latest drivers for your graphics card, and service packs and patches for your operating system. If you continue to have problems, please visit the [SUPPORT_SITE]. </global> + <global name="UnsupportedIntelDriver"> +The installed Intel graphics driver for [GPUNAME], version [VERSION], is significantly out of date and is known to cause excessive rates of program crashes. You are strongly advised to update to a current Intel driver + +Do you want to check the Intel driver website? + </global> + <global name="UnsupportedCPUAmount"> 796 </global> @@ -9333,6 +9645,10 @@ If you continue to have problems, please visit the [SUPPORT_SITE]. <global name="UnsupportedRAM"> - Your system memory does not meet the minimum requirements. </global> + + <global name="LLLeapUpdaterFailure"> +Failed to launch updater service [UPDATER_APP]. Please verify the viewer is installed correctly and has the necessary permissions to run. If you continue to experience issues, please visit the [SUPPORT_SITE]. + </global> <!-- these are alert strings from server. the name needs to match entire the server string, and needs to be changed whenever the server string changes --> @@ -9739,6 +10055,15 @@ Removal of the object <nolink>'[OBJ_NAME]'</nolink> from the simulat Cannot save your selection because you do not have permission to modify the object <nolink>'[OBJ_NAME]'</nolink>. </notification> + + <notification + icon="alertmodal.tga" + name="NoTransNoSaveToContents" + type="notify"> + <tag>fail</tag> + Cannot save <nolink>'[OBJ_NAME]'</nolink> to object contents because you do not have permission to transfer the object's ownership. + </notification> + <notification icon="alertmodal.tga" name="NoCopyNoSaveSelection" @@ -10034,7 +10359,7 @@ Unable to add script! name="AssetServerTimeoutObjReturn" type="notify"> <tag>fail</tag> -Asset server didn't respond in a timely fashion. Object returned to sim. +Asset server didn't respond in a timely fashion. Object returned to the region. </notification> <notification @@ -11175,6 +11500,19 @@ Cannot create large prims that intersect other residents. Please re-try when ot notext="Cancel" yestext="OK"/> </notification> + + <notification + icon="alertmodal.tga" + name="PreferenceControlsDefaults" + type="alertmodal"> + Do you want to restore default values for controls? + <tag>confirm</tag> + <usetemplate + canceltext="Cancel" + name="yesnocancelbuttons" + notext="Current mode" + yestext="All modes"/> + </notification> <notification icon="alertmodal.tga" @@ -11220,7 +11558,28 @@ Cannot create large prims that intersect other residents. Please re-try when ot name="okbutton" yestext="OK"/> </notification> - + + <notification + icon="alertmodal.tga" + name="AddPaymentMethod" + type="alertmodal"> +On the following page, choose a L$ amount +and click a place Order button. You will be +able to add a payment method at checkout. + <tag>confirm</tag> + <form name="form"> + <button + default="true" + index="0" + width="120" + name="Continue" + text="Continue"/> + <button + index="1" + name="Cancel" + text="Cancel"/> + </form> + </notification> <notification icon="alert.tga" @@ -11233,4 +11592,190 @@ Cannot create large prims that intersect other residents. Please re-try when ot yestext="OK"/> </notification> + <notification + icon="notify.tga" + name="FailedToFindSettings" + persist="true" + type="alertmodal"> +Could not load the settings for [NAME] from the database. + <tag>fail</tag> + </notification> + + <notification + icon="notify.tga" + name="FailedToLoadSettingsApply" + persist="true" + type="alertmodal"> +Unable to apply those settings to the environment. + <tag>fail</tag> + </notification> + + <notification + icon="notify.tga" + name="FailedToBuildSettingsDay" + persist="true" + type="alertmodal"> +Unable to apply those settings to the environment. + <tag>fail</tag> + </notification> + + <notification + icon="notify.tga" + name="NoEnvironmentSettings" + persist="true" + type="alertmodal"> +This Region does not support environmental settings. + <tag>fail</tag> + </notification> + + <notification + icon="alertmodal.tga" + label="Save Outfit" + name="SaveSettingAs" + type="alertmodal"> + <unique/> + Save current environmental settings as: + <tag>confirm</tag> + <form name="form"> + <input name="message" type="text"> + [DESC] (new) + </input> + <button + default="true" + index="0" + name="OK" + text="OK"/> + <button + index="1" + name="Cancel" + text="Cancel"/> + </form> + </notification> + + <notification + icon="notify.tga" + name="WLImportFail" + persist="true" + type="alertmodal"> +Unable to import legacy Windlight settings [NAME] from +[FILE]. + +[REASONS] + <tag>fail</tag> + </notification> + + <notification + icon="notify.tga" + name="WLParcelApplyFail" + persist="true" + type="alertmodal"> +Unable to set the environment for this parcel. +Please enter or select a parcel that you have rights to modify. + <tag>fail</tag> + </notification> + + <notification + icon="notify.tga" + name="SettingsUnsuported" + persist="true" + type="alertmodal"> +Settings are not supported on this region. +Please move to a settings enabled region and retry your action. + <tag>fail</tag> + </notification> + + <notification + icon="alertmodal.tga" + name="SettingsConfirmLoss" + type="alertmodal"> +You are about to lose the changes you have made to this [TYPE] named "[NAME]". +Are you sure you want to continue? + <tag>confirm</tag> + <usetemplate + ignoretext="Are you sure you want to lose changes?" + name="okcancelignore" + notext="No" + yestext="Yes"/> + </notification> + + <notification + icon="alertmodal.tga" + name="SettingsConfirmReset" + type="alertmodal"> +You are about to remove all applied settings. +Are you sure you want to continue? + <tag>confirm</tag> + <usetemplate + name="okcancelbuttons" + notext="No" + yestext="Yes"/> + </notification> + + <notification + icon="alertmodal.tga" + name="PersonalSettingsConfirmReset" + type="alertmodal"> +You are about to remove all applied Personal lighting settings. +Are you sure you want to continue? + <tag>confirm</tag> + <usetemplate + name="okcancelbuttons" + notext="No" + yestext="Yes"/> + </notification> + + <notification + icon="alertmodal.tga" + name="SettingsMakeNoTrans" + type="alertmodal"> +You are about to import non-transferable settings into this daycycle. Continuing will cause the settings you are editing to become non-transferable also. + +This change can not be undone. + +Are you sure you want to continue? + <tag>confirm</tag> + <usetemplate + ignoretext="Are you sure you want to make settings non-transferable?" + name="okcancelignore" + notext="No" + yestext="Yes"/> + </notification> + + <notification + icon="notify.tga" + name="NoEditFromLibrary" + persist="true" + type="alertmodal"> +You may not edit settings directly from the libary. +Please copy to your own inventory and try again. + <tag>fail</tag> + </notification> + + <notification + icon="notify.tga" + name="EnvironmentApplyFailed" + persist="true" + type="alertmodal"> +We have encountered an issue with these settings. They can not be saved or applied at this time. + <tag>fail</tag> + </notification> + + <notification + icon="notify.tga" + name="TrackLoadFailed" + persist="true" + type="alertmodal"> +Unable to load the track into [TRACK]. + <tag>fail</tag> + </notification> + + <notification + icon="notify.tga" + name="TrackLoadMismatch" + persist="true" + type="alertmodal"> +Unable to load the track from [TRACK1] into [TRACK2]. + <tag>fail</tag> + </notification> + </notifications> diff --git a/indra/newview/skins/default/xui/en/panel_camera_preset_item.xml b/indra/newview/skins/default/xui/en/panel_camera_preset_item.xml new file mode 100644 index 0000000000..9417ab4ac2 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_camera_preset_item.xml @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + follows="top|right|left" + height="20" + layout="topleft" + left="0" + name="camera_preset_item" + top="0" + width="280"> + <icon + follows="top|right|left" + height="20" + image_name="ListItem_Over" + layout="topleft" + left="0" + name="hovered_icon" + top="0" + visible="false" + width="380" /> + <icon + height="20" + follows="top|right|left" + image_name="ListItem_Select" + layout="topleft" + left="0" + name="selected_icon" + top="0" + visible="false" + width="380" /> + <text + follows="left" + height="20" + layout="topleft" + left="10" + parse_urls="false" + use_ellipses="true" + name="preset_name" + text_color="White" + top="2" + value="Default" + width="159" /> + <button + follows="right" + image_selected="TrashItem_Off" + image_pressed="TrashItem_Off" + image_unselected="TrashItem_Off" + is_toggle="true" + layout="topleft" + left_pad="5" + right="-10" + name="delete_btn" + tool_tip="Delete preset" + top="3" + height="18" + width="18" > + <button.commit_callback + function="CameraPresets.Delete"/> + </button> + <button + follows="right" + image_selected="Refresh_Off" + image_pressed="Refresh_Off" + image_unselected="Refresh_Off" + is_toggle="true" + layout="topleft" + left_pad="5" + right="-10" + name="reset_btn" + tool_tip="Reset preset to default" + top="2" + height="20" + width="20" > + <button.commit_callback + function="CameraPresets.Reset"/> + </button> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_classifieds_list_item.xml b/indra/newview/skins/default/xui/en/panel_classifieds_list_item.xml index 27c653bc35..d1175a9fe1 100644 --- a/indra/newview/skins/default/xui/en/panel_classifieds_list_item.xml +++ b/indra/newview/skins/default/xui/en/panel_classifieds_list_item.xml @@ -32,7 +32,6 @@ width="308"/> <texture_picker allow_no_texture="true" - border_enabled="true" fallback_image="default_land_picture.j2c" enabled="false" follows="left|top" diff --git a/indra/newview/skins/default/xui/en/panel_edit_classified.xml b/indra/newview/skins/default/xui/en/panel_edit_classified.xml index 3509eaa285..e846edf1d4 100644 --- a/indra/newview/skins/default/xui/en/panel_edit_classified.xml +++ b/indra/newview/skins/default/xui/en/panel_edit_classified.xml @@ -144,7 +144,6 @@ follows="left|top|right" height="100" width="273" - hide_scrollbar="false" layout="topleft" left="10" top_pad="2" diff --git a/indra/newview/skins/default/xui/en/panel_edit_pick.xml b/indra/newview/skins/default/xui/en/panel_edit_pick.xml index 553c112e6f..357a5559bf 100644 --- a/indra/newview/skins/default/xui/en/panel_edit_pick.xml +++ b/indra/newview/skins/default/xui/en/panel_edit_pick.xml @@ -26,7 +26,7 @@ name="back_btn" left="10" tab_stop="false" - top="2" + top="4" width="30" use_draw_context_alpha="false" /> <text @@ -39,17 +39,17 @@ left_pad="4" name="title" text_color="LtGray" - top="2" + top="4" width="250"> Edit Pick </text> <scroll_container color="DkGray2" follows="all" - height="502" + height="501" layout="topleft" left="8" - top_pad="10" + top_pad="9" name="profile_scroll" opaque="true" width="312"> diff --git a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml index dc1553e6a3..85d73ece48 100644 --- a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml +++ b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml @@ -13,7 +13,7 @@ width="333"> <string name="edit_shape_title"> - Editing Shape + Shape </string> <string name="edit_skin_title"> diff --git a/indra/newview/skins/default/xui/en/panel_favorites.xml b/indra/newview/skins/default/xui/en/panel_favorites.xml new file mode 100644 index 0000000000..1e8ea34ad2 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_favorites.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + name="Favorites" + layout="topleft" + left="0" + border="false" + background_visible="true" + bg_alpha_color="DkGray" + follows="all"> + <places_inventory_panel + allow_multi_select="true" + border="false" + top="1" + left="3" + bottom="0" + follows="all" + right="-3" + mouse_opaque="true" + name="favorites_list" + folder_view.use_ellipses="true" + start_folder.name="Favorites"/> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_flickr_account.xml b/indra/newview/skins/default/xui/en/panel_flickr_account.xml deleted file mode 100644 index 5c2f335780..0000000000 --- a/indra/newview/skins/default/xui/en/panel_flickr_account.xml +++ /dev/null @@ -1,79 +0,0 @@ -<panel - height="540" - width="272" - layout="topleft" - name="panel_flickr_account"> - <string - name="flickr_connected" - value="You are connected to Flickr as:" /> - <string - name="flickr_disconnected" - value="Not connected to Flickr" /> - <text - layout="topleft" - length="1" - follows="top|left" - font="SansSerif" - height="16" - left="10" - name="account_caption_label" - top="5" - type="string"> - Not connected to Flickr. - </text> - <text - layout="topleft" - top_pad="2" - length="1" - follows="top|left" - font="SansSerif" - height="16" - left="10" - name="account_name_label" - parse_urls="true" - type="string"/> - <panel - layout="topleft" - name="panel_buttons" - height="345" - left="0"> - <button - layout="topleft" - follows="left|top|right" - top_pad="9" - visible="true" - left="10" - right="-10" - height="23" - label="Connect..." - name="connect_btn" - width="210"> - <commit_callback function="SocialSharing.Connect"/> - </button> - - <button - layout="topleft" - follows="left|top|right" - top_delta="0" - left="10" - right="-10" - height="23" - label="Disconnect" - name="disconnect_btn" - width="210" - visible="false"> - <commit_callback function="SocialSharing.Disconnect"/> - </button> - <text - layout="topleft" - length="1" - follows="top|left" - height="16" - left="10" - name="account_learn_more_label" - top_pad="5" - type="string"> - [http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Share-Flickr/ta-p/2435609 Learn about posting to Flickr] - </text> - </panel> -</panel> diff --git a/indra/newview/skins/default/xui/en/panel_flickr_photo.xml b/indra/newview/skins/default/xui/en/panel_flickr_photo.xml deleted file mode 100644 index 7fb2291423..0000000000 --- a/indra/newview/skins/default/xui/en/panel_flickr_photo.xml +++ /dev/null @@ -1,259 +0,0 @@ - <panel - height="540" - width="272" - follows="all" - layout="topleft" - name="panel_flickr_photo"> - <combo_box - control_name="FlickrPhotoResolution" - follows="left|top" - layout="topleft" - top="7" - left="10" - name="resolution_combobox" - tool_tip="Image resolution" - height="21" - width="124"> - <combo_box.item - label="Current Window" - name="CurrentWindow" - value="[i0,i0]" /> - <combo_box.item - label="640x480" - name="640x480" - value="[i640,i480]" /> - <combo_box.item - label="800x600" - name="800x600" - value="[i800,i600]" /> - <combo_box.item - label="1024x768" - name="1024x768" - value="[i1024,i768]" /> - </combo_box> - <combo_box - control_name="FlickrPhotoFilters" - follows="left|top" - layout="topleft" - name="filters_combobox" - tool_tip="Image filters" - top_delta="0" - left_pad="4" - height="21" - width="124"> - <combo_box.item - label="No Filter" - name="NoFilter" - value="NoFilter" /> - </combo_box> - <panel - height="150" - width="250" - visible="true" - name="thumbnail_placeholder" - top_pad="5" - follows="left|top|right" - layout="topleft" - right="-10" - left="10"> - </panel> - <text - follows="left|top" - layout="topleft" - font="SansSerif" - text_color="EmphasisColor" - height="14" - top_pad="2" - left="10" - length="1" - halign="center" - name="working_lbl" - translate="false" - type="string" - visible="true" - width="251"> - Refreshing... - </text> - <view_border - bevel_style="in" - follows="left|top" - layout="topleft" - height="1" - left="10" - name="refresh_border" - width="250" - top_pad="0"/> - <button - follows="left|top" - layout="topleft" - height="23" - label="Refresh" - left="10" - top_pad="5" - name="new_snapshot_btn" - tool_tip="Click to refresh" - visible="true" - width="100" > - <button.commit_callback - function="SocialSharing.RefreshPhoto" /> - </button> - <button - follows="right|top" - layout="topleft" - height="23" - label="Preview" - right="-10" - top_delta="0" - name="big_preview_btn" - tool_tip="Click to toggle preview" - is_toggle="true" - visible="true" - width="100" > - <button.commit_callback - function="SocialSharing.BigPreview" /> - </button> - <text - length="1" - follows="top|left|right" - layout="topleft" - font="SansSerif" - height="16" - left="10" - name="title_label" - top_pad="10" - type="string"> - Title: - </text> - <line_editor - follows="left|top" - layout="topleft" - height="20" - width="250" - left="10" - length="1" - max_length="256" - name="photo_title" - type="string"> - </line_editor> - <text - length="1" - follows="top|left|right" - layout="topleft" - font="SansSerif" - height="16" - left="10" - right="-10" - name="description_label" - top_pad="10" - width="25" - type="string"> - Description: - </text> - <text_editor - follows="left|top" - layout="topleft" - height="50" - width="249" - left="10" - length="1" - max_length="700" - name="photo_description" - spellcheck="true" - type="string" - word_wrap="true"> - </text_editor> - <check_box - follows="left|top" - layout="topleft" - initial_value="true" - label="Include SL location at end of description" - name="add_location_cb" - left="9" - height="16" - top_pad="8"/> - <text - length="1" - follows="top|left" - layout="topleft" - font="SansSerif" - height="16" - left="10" - name="tags_label" - top_pad="6" - type="string"> - Tags: - </text> - <text - length="1" - follows="top|left" - layout="topleft" - font="SansSerifSmall" - text_color="White_50" - height="30" - name="tags_help_label" - left="51" - top_pad="-16" - type="string"> -Separate tags with spaces -Use "" for multi-word tags - </text> - <text_editor - follows="left|top" - layout="topleft" - height="50" - width="249" - left="10" - length="1" - max_length="700" - name="photo_tags" - type="string" - word_wrap="true"> - </text_editor> - <combo_box - control_name="FlickrPhotoRating" - follows="left|top" - layout="topleft" - top_pad="7" - left="10" - name="rating_combobox" - tool_tip="Flickr content rating" - height="21" - width="250"> - <combo_box.item - label="Safe Flickr rating" - name="SafeRating" - value="1" /> - <combo_box.item - label="Moderate Flickr rating" - name="ModerateRating" - value="2" /> - <combo_box.item - label="Restricted Flickr rating" - name="RestrictedRating" - value="3" /> - </combo_box> - <button - follows="left|top" - layout="topleft" - top_pad="7" - left="10" - height="23" - label="Share" - name="post_photo_btn" - width="100"> - <button.commit_callback - function="SocialSharing.SendPhoto" /> - </button> - <button - follows="right|top" - layout="topleft" - height="23" - label="Cancel" - name="cancel_photo_btn" - right="-10" - top_delta="0" - width="100"> - <button.commit_callback - function="SocialSharing.Cancel" /> - </button> - </panel> diff --git a/indra/newview/skins/default/xui/en/panel_group_creation_sidetray.xml b/indra/newview/skins/default/xui/en/panel_group_creation_sidetray.xml new file mode 100644 index 0000000000..c0265c2fa2 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_group_creation_sidetray.xml @@ -0,0 +1,314 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel +background_visible="true" + follows="all" + height="570" + label="Group Creation" + layout="topleft" + min_height="350" + left="0" + top="20" + name="GroupCreation" + width="313"> + <panel.string + name="current_membership"> +(your membership) + </panel.string> + <panel + name="group_info_top" + follows="top|left" + top="0" + left="0" + height="29" + width="313" + layout="topleft"> + <line_editor + follows="left|top" + font="SansSerif" + label="Type your new group name here" + layout="topleft" + max_length_bytes="35" + name="group_name_editor" + left="12" + top="5" + width="270" + height="20" + visible="true" /> + </panel> + <layout_stack + name="layout" + orientation="vertical" + follows="all" + left="8" + top_pad="0" + height="538" + width="300" + border_size="0"> + <layout_panel + bg_alpha_color="DkGray2" + bg_opaque_color="DkGray2" + background_visible="true" + background_opaque="true" + name="group_info" + follows="all" + layout="topleft" + auto_resize="false" + user_resize="false" + height="206" + width="313"> + <panel + name="group_info_top" + follows="top|left|right" + top="0" + left="0" + height="99" + width="312" + layout="topleft"> + <texture_picker + default_image_name="Generic_Group_Large" + follows="left|top" + name="insignia" + label="" + no_commit_on_selection="true" + tool_tip="Click to choose a picture" + layout="topleft" + height="110" + left="5" + top="5" + width="100" /> + <text_editor + follows="left|top|right" + layout="topleft" + type="string" + name="charter" + left_pad="3" + height="86" + max_length="511" + top="6" + right="-4" + bg_readonly_color="DkGray2" + text_readonly_color="White" + word_wrap="true"> + Group Charter + </text_editor> + </panel> + <panel + layout="topleft" + follows="left|top|right" + background_visible="false" + bevel_style="none" + border="false" + bg_alpha_color="FloaterUnfocusBorderColor" + height="100" + width="313" + left="0" + name="preferences_container" + top_pad="5"> + <check_box + follows="right|top|left" + layout="topleft" + label="Anyone can join" + height="16" + left="10" + name="open_enrollement" + tool_tip="Sets whether this group allows new members to join without being invited." + width="90" /> + <check_box + label="Cost to join" + layout="topleft" + name="check_enrollment_fee" + tool_tip="Sets whether to require an enrollment fee to join the group" + top_pad="5" + left_delta="0" + height="16" + width="300" /> + <spinner + decimal_digits="0" + follows="left|top" + halign="left" + increment="1" + label_width="15" + label="L$" + layout="topleft" + max_val="99999" + height="23" + left="30" + name="spin_enrollment_fee" + tool_tip="New members must pay this fee to join the group when Enrollment Fee is checked." + width="170" /> + <combo_box + follows="left|top" + layout="topleft" + name="group_mature_check" + tool_tip="Maturity ratings designate the type of content and behavior allowed in a group" + height="23" + left="10" + top_pad="4" + width="190"> + <combo_item name="select_mature" value="Select"> + - Select maturity rating - + </combo_item> + <combo_box.item + label="Moderate Content" + name="mature" + value="Mature" /> + <combo_box.item + label="General Content" + name="pg" + value="Not Mature" /> + </combo_box> + </panel> + </layout_panel> + <layout_panel + background_visible="false" + background_opaque="true" + name="create_info" + follows="all" + layout="topleft" + auto_resize="false" + user_resize="false" + height="200" + width="313"> + <text + font="SansSerifSmall" + follows="top|left|right" + layout="topleft" + mouse_opaque="false" + type="string" + name="fee_information" + skip_link_underline="true" + height="26" + left="8" + right="-8" + top="5" + word_wrap="true"> + The fee to create a group is based on your membership level. [https://secondlife.com/my/account/membership.php More info] + </text> + <scroll_list + draw_border="false" + background_visible="false" + follows="left|top|bottom|right" + layout="topleft" + multi_select="true" + name="membership_list" + row_padding="4" + enabled="false" + height="150" + left="2" + top_pad="8" + width="290"> + <scroll_list.columns + dynamic_width="false" + name="clmn_name" + width="220"/> + <scroll_list.columns + dynamic_width="true" + name="clmn_price"/> + <scroll_list.rows + name="basic" + value="Basic (placeholder)"/> + <scroll_list.rows + name="plc2" + value="" /> + <scroll_list.rows + name="premium" + value="Premium (placeholder)" /> + </scroll_list> + </layout_panel> + <layout_panel + background_visible="false" + background_opaque="true" + name="create_actions" + follows="all" + layout="topleft" + auto_resize="true" + user_resize="true" + height="200" + width="313"> + </layout_panel> + <layout_panel + background_visible="false" + background_opaque="true" + name="create_actions" + follows="all" + layout="topleft" + auto_resize="false" + user_resize="false" + height="75" + width="313"> + + <layout_stack + follows="bottom|left|right" + layout="topleft" + name="button_row_ls" + left="1" + right="-1" + orientation="horizontal" + height="25" + top="1"> + <layout_panel + follows="bottom|left|right" + layout="bottomleft" + name="layout_crt" + auto_resize="true" + height="23" + width="91"> + <!-- placeholder to autoadjust buttons (since they are of different sizes)--> + </layout_panel> + <layout_panel + follows="bottom|left|right" + layout="bottomleft" + name="layout_crt" + auto_resize="false" + height="23" + width="245"> + <button + follows="bottom|left|right" + layout="topleft" + label="Create group for L$ [COST]" + name="btn_create" + visible="true" + tool_tip="Create a new Group" + height="23" + left="1" + top="0" + width="160" /> + <button + follows="bottom|left|right" + name="back" + label="Cancel" + layout="topleft" + tool_tip="Return to list of groups" + left_pad="13" + height="23" + top="0" + width="70" /> + </layout_panel> + <layout_panel + follows="bottom|left|right" + layout="bottomleft" + name="layout_crt" + auto_resize="true" + height="23" + width="91"> + <!-- placeholder to autoadjust buttons--> + </layout_panel> + </layout_stack> + <text + font="SansSerifSmall" + follows="top|left|right" + layout="topleft" + mouse_opaque="false" + type="string" + height="26" + left="6" + right="-6" + name="info_deletion" + top_pad="8" + word_wrap="true" + halign="center"> + Note: After 7 days, a group with no members (other than the creator) is deleted + </text> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml index 95312edfb9..05de249d22 100644 --- a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml +++ b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml @@ -280,17 +280,6 @@ background_visible="true" left="1" top="0" width="90" /> - <button - follows="bottom|left|right" - height="23" - layout="topleft" - left="1" - top="0" - label="Create Group" - name="btn_create" - visible="true" - tool_tip="Create a new Group" - width="90" /> </layout_panel> </layout_stack> diff --git a/indra/newview/skins/default/xui/en/panel_group_notices.xml b/indra/newview/skins/default/xui/en/panel_group_notices.xml index 47aceb2c2e..a5aca5c72b 100644 --- a/indra/newview/skins/default/xui/en/panel_group_notices.xml +++ b/indra/newview/skins/default/xui/en/panel_group_notices.xml @@ -59,7 +59,8 @@ Maximum 200 per group daily <scroll_list.columns label="Date" name="date" - width="60" /> + sort_column="sort" + width="100" /> <scroll_list.columns name="sort" width="-1" /> diff --git a/indra/newview/skins/default/xui/en/panel_landmark_info.xml b/indra/newview/skins/default/xui/en/panel_landmark_info.xml index 13986c4030..e82305ef17 100644 --- a/indra/newview/skins/default/xui/en/panel_landmark_info.xml +++ b/indra/newview/skins/default/xui/en/panel_landmark_info.xml @@ -41,7 +41,7 @@ </string> <string name="acquired_date"> - [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local] + [wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [year,datetime,slt] </string> <!-- Texture names for rating icons --> <string @@ -67,7 +67,7 @@ name="back_btn" tool_tip="Back" tab_stop="false" - top="4" + top="2" width="30" use_draw_context_alpha="false" /> <text @@ -78,24 +78,24 @@ left_pad="7" name="title" text_color="LtGray" - top="3" + top="2" use_ellipses="true" value="Place Profile" width="280" /> <scroll_container color="DkGray2" follows="all" - height="532" + height="534" layout="topleft" left="9" name="place_scroll" opaque="true" - top_pad="10" - width="310"> + top_pad="9" + width="324"> <panel bg_alpha_color="DkGray2" follows="left|top|right" - height="630" + height="654" layout="topleft" left="0" min_height="300" @@ -112,35 +112,56 @@ name="logo" top="10" width="290" /> + <!-- texture picker has an empty label section, compensate for it with negative top_pad--> <text follows="left|top|right" font="SansSerifLarge" height="14" layout="topleft" left="10" - name="region_title" + top_pad="-10" + width="280" + name="parcel_title" text_color="white" - top_pad="10" use_ellipses="true" - value="SampleRegion" - width="280" /> + value="SampleParcel, Name Long" /> <text follows="left|top|right" height="14" layout="topleft" left="10" - name="parcel_title" - top_pad="10" + top_pad="9" + width="280" + name="region_title" + use_ellipses="true"> + Region: [REGIONAMEPOS] + </text> + <text + follows="left|top" + height="15" + layout="topleft" + left="10" + name="parcel_owner_label" + top_pad="7" + value="Owner:" + width="80" /> + <text + follows="left|top|right" + height="15" + layout="topleft" + left_pad="0" + name="parcel_owner" + top_delta="0" use_ellipses="true" - value="SampleParcel, Name Long (145, 228, 26)" - width="280" /> + value="TempOwner" + width="215" /> <expandable_text follows="left|top|right" height="50" layout="topleft" left="10" name="description" - top_pad="10" + top_pad="7" value="Du waltz die spritz" width="280" /> <icon @@ -163,19 +184,38 @@ width="268" /> <panel follows="left|top|right" - height="55" + height="81" layout="topleft" left="10" name="landmark_info_panel" top_pad="10" width="290"> + <view_border + bevel_style="none" + follows="top|left" + height="0" + layout="topleft" + left="0" + name="lod_tab_border" + top_pad="5" + width="290" /> + <text + follows="left|top" + height="15" + layout="topleft" + left="0" + name="this_landmark" + top_pad="8" + width="90"> + This landmark: + </text> <text follows="left|top" height="15" layout="topleft" left="0" name="owner_label" - top_pad="10" + top_pad="8" value="Owner:" width="90" /> <text @@ -237,17 +277,30 @@ top_pad="10" value="Title:" width="290" /> - <text - parse_urls="false" - follows="left|top" + <line_editor + text_readonly_color="white" + enabled="false" + use_bg_color="true" + bg_color="DkGray0" + follows="left|top|right" height="22" layout="topleft" left="0" name="title_value" text_color="white" top_pad="5" - use_ellipses="true" - width="290" /> + width="200" /> + <button + follows="top|right" + height="24" + label="Edit" + layout="topleft" + left_pad="8" + mouse_opaque="false" + name="edit_btn" + tool_tip="Edit landmark information" + top_delta="-1" + width="83" /> <line_editor follows="left|top|right" height="22" @@ -257,8 +310,8 @@ name="title_editor" prevalidate_callback="ascii" text_readonly_color="white" - top_delta="0" - width="290" /> + top_delta="1" + width="290"/> <text follows="left|top" height="15" @@ -269,7 +322,7 @@ value="My notes:" width="290" /> <text_editor - bg_readonly_color="DkGray2" + bg_readonly_color="DkGray0" follows="all" height="75" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/panel_landmarks.xml b/indra/newview/skins/default/xui/en/panel_landmarks.xml index 67a09949ce..10b925ec93 100644 --- a/indra/newview/skins/default/xui/en/panel_landmarks.xml +++ b/indra/newview/skins/default/xui/en/panel_landmarks.xml @@ -1,198 +1,23 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <panel name="Landmarks" - top="0" - height="400" layout="topleft" left="0" - width="313" help_topic="panel_landmarks" border="false" background_visible="true" bg_alpha_color="DkGray" follows="all"> - <accordion - background_visible="true" - bg_alpha_color="DkGray2" - bg_opaque_color="DkGray2" - follows="all" - height="373" - layout="topleft" - left="3" - name="landmarks_accordion" - top="0" - width="307"> - <accordion_tab - layout="topleft" - name="tab_favorites" - title="Favorites bar"> - <places_inventory_panel - allow_multi_select="true" - border="false" - bottom="0" - follows="all" - height="126" - left="0" - mouse_opaque="true" - name="favorites_list" - scroll.hide_scrollbar="true" - folder_view.use_ellipses="true" - start_folder.name="Favorites" - width="307"/> - </accordion_tab> - <accordion_tab - layout="topleft" - name="tab_landmarks" - title="My Landmarks"> - <places_inventory_panel - allow_multi_select="true" - border="false" - bottom="0" - follows="all" - height="126" - left="0" - mouse_opaque="true" - name="landmarks_list" - scroll.hide_scrollbar="true" - folder_view.use_ellipses="true" - start_folder.name="Landmarks" - width="307"/> - </accordion_tab> - <accordion_tab - layout="topleft" - name="tab_inventory" - title="My Inventory"> - <places_inventory_panel - allow_multi_select="true" - border="false" - bottom="0" - follows="all" - height="126" - left="0" - mouse_opaque="true" - name="my_inventory_list" - scroll.hide_scrollbar="true" - folder_view.use_ellipses="true" - start_folder.name="My Inventory" - width="307"/> - </accordion_tab> - <accordion_tab - layout="topleft" - name="tab_library" - title="Library"> - <places_inventory_panel - allow_multi_select="true" - border="false" - bottom="0" - follows="all" - height="126" - left="0" - mouse_opaque="true" - name="library_list" - scroll.hide_scrollbar="true" - folder_view.use_ellipses="true" - start_folder.name="LIBRARY" - width="313"/> - </accordion_tab> - </accordion> - <panel - background_visible="true" - bevel_style="none" - bottom="0" - follows="left|right|bottom" - height="27" - layout="bottomleft" - left="3" - name="bottom_panel" - width="313"> - - <layout_stack - animate="false" - border_size="0" - follows="left|right|bottom" - height="25" - layout="topleft" - orientation="horizontal" - top_pad="1" - left="0" - name="bottom_panel" - width="307"> - <layout_panel - auto_resize="false" - height="25" - layout="topleft" - name="options_gear_btn_panel" - width="32"> - <menu_button - follows="bottom|left" - tool_tip="Show additional options" - height="25" - image_hover_unselected="Toolbar_Left_Over" - image_overlay="OptionsMenu_Off" - image_selected="Toolbar_Left_Selected" - image_unselected="Toolbar_Left_Off" - layout="topleft" - left="0" - name="options_gear_btn" - top="0" - width="31" /> - </layout_panel> - <layout_panel - auto_resize="false" - height="25" - layout="topleft" - name="add_btn_panel" - width="32"> - <button - follows="bottom|left" - height="25" - image_hover_unselected="Toolbar_Middle_Over" - image_overlay="AddItem_Off" - image_selected="Toolbar_Middle_Selected" - image_unselected="Toolbar_Middle_Off" - layout="topleft" - left="0" - name="add_btn" - tool_tip="Add new landmark" - top="0" - width="31" /> - </layout_panel> - <layout_panel - auto_resize="true" - height="25" - layout="topleft" - name="dummy_panel" - width="212"> - <icon - follows="bottom|left|right" - height="25" - image_name="Toolbar_Middle_Off" - layout="topleft" - left="0" - top="0" - name="dummy_icon" - width="211" /> - </layout_panel> - <layout_panel - auto_resize="false" - height="25" - layout="topleft" - name="trash_btn_panel" - width="31"> - <dnd_button - follows="bottom|left" - height="25" - image_hover_unselected="Toolbar_Right_Over" - image_overlay="TrashItem_Off" - image_selected="Toolbar_Right_Selected" - image_unselected="Toolbar_Right_Off" - left="0" - layout="topleft" - name="trash_btn" - tool_tip="Remove selected landmark" - top="0" - width="31"/> - </layout_panel> - </layout_stack> - </panel> + <places_inventory_panel + allow_multi_select="true" + border="false" + top="1" + follows="all" + left="3" + bottom="0" + right="-3" + mouse_opaque="true" + name="landmarks_list" + folder_view.use_ellipses="true" + start_folder.name="Landmarks"/> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index 7759d4fdb2..ade004f9d0 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -33,7 +33,7 @@ auto_resize="false" follows="left|right|top" name="ui_container" - width="1000" + width="1011" left="0" top="0" height="172"> @@ -57,19 +57,15 @@ combo_editor.prevalidate_callback="ascii" tool_tip="The username you chose when you registered, like bobsmith12 or Steller Sunshine" name="username_combo" - width="232"> + width="206"> <combo_box.combo_editor text_pad_left="8" bg_image_always_focused="true"/> - <combo_box.combo_button - visible="false" /> - <combo_box.drop_down_button - visible="false" /> </combo_box> <line_editor follows="left|top" height="32" - left_pad="-11" + left_pad="15" max_length_chars="16" text_pad_left="8" name="password_edit" @@ -119,36 +115,51 @@ width="120" height="32" left_pad="15" - bottom_delta="0" /> + bottom_delta="0" /> + <text + follows="left|top" + font="SansSerifLarge" + font.style="BOLD" + text_color="EmphasisColor" + height="34" + name="sign_up_text" + left_pad="10" + width="200" + valign="center"> + Sign up + </text> <check_box - control_name="RememberPassword" follows="left|top" font="SansSerifMedium" left="185" - bottom_delta="21" + bottom_delta="21" height="24" label="Remember me" + word_wrap="down" check_button.bottom="3" - name="remember_check" - width="145" /> - <text + name="remember_name" + tool_tip="Already remembered user can be forgotten from Me > Preferences > Advanced > Remembered Usernames." + width="198" /> + <check_box + control_name="RememberPassword" follows="left|top" font="SansSerifMedium" text_color="EmphasisColor" height="16" - name="forgot_password_text" - left="408" + left="408" bottom_delta="0" - width="200"> - Forgotten password - </text> + label="Remember password" + word_wrap="down" + check_button.bottom="3" + name="remember_password" + width="165" /> <combo_box allow_text_entry="false" font="SansSerifTiny" follows="left|top" height="26" left="588" - bottom_delta="10" + bottom_delta="8" max_chars="128" label="Select grid" layout="topleft" @@ -159,12 +170,13 @@ font="SansSerifMedium" text_color="EmphasisColor" height="16" - name="sign_up_text" + name="forgot_password_text" left="778" - bottom_delta="-10" - width="200"> - Sign up - </text> + bottom_delta="-8" + width="120" + halign="center"> + Password help + </text> </layout_panel> <layout_panel height="172" diff --git a/indra/newview/skins/default/xui/en/panel_login_first.xml b/indra/newview/skins/default/xui/en/panel_login_first.xml index 726e713595..5568ccb792 100644 --- a/indra/newview/skins/default/xui/en/panel_login_first.xml +++ b/indra/newview/skins/default/xui/en/panel_login_first.xml @@ -234,32 +234,6 @@ left_pad="32" name="image_right" top="0" /> - <text - follows="left|top" - font="SansSerifLarge" - text_color="White" - height="64" - name="image_caption_left" - left="0" - halign="center" - top="408" - word_wrap="true" - width="400"> - Your first step is Learning Island. Find the exit portal! - </text> - <text - follows="left|top" - font="SansSerifLarge" - text_color="White" - height="64" - name="image_caption_right" - left="432" - halign="center" - top="408" - word_wrap="true" - width="400"> - Then explore Social Island and meet other new residents! - </text> </layout_panel> <layout_panel height="100" diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml index d77fbdec0a..2ff58035ed 100644 --- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml @@ -32,30 +32,20 @@ left="12" name="ItemcountText" font="SansSerifMedium" - text_color="EmphasisColor" + text_color="InventoryItemLinkColor" use_ellipses="true" top_pad="0" width="300"> Items: </text> - <filter_editor - text_pad_left="10" - follows="left|top|right" + <combo_box height="23" - label="Enter search text" layout="topleft" left="10" - max_length_chars="300" - name="inventory search editor" top="18" - width="208" /> - <combo_box - height="23" - layout="topleft" - left_pad="4" name="search_type" - follows="top|right" - width="90"> + follows="top|left" + width="88"> <item label="Name" name="Name" @@ -72,7 +62,27 @@ label="UUID" name="UUID" value="search_by_UUID"/> - </combo_box> + </combo_box> + <menu_button + follows="top|left" + tool_tip="Show search visibility options" + height="23" + image_overlay="Inv_Toolbar_SearchVisibility" + layout="topleft" + left_pad="3" + name="options_visibility_btn" + width="31" /> + <filter_editor + text_pad_left="10" + follows="left|top|right" + height="23" + label="Enter search text" + layout="topleft" + left_pad="3" + max_length_chars="300" + highlight_text_field="true" + name="inventory search editor" + width="177" /> <tab_container follows="all" halign="center" diff --git a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml index c7edba21f8..1c9aa1eb83 100644 --- a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml @@ -151,30 +151,43 @@ layout="topleft" auto_resize="true" user_resize="true" - min_width="185" + min_width="342" name="favorites_layout_panel" - width="320"> + width="342"> <icon follows="top|left" height="25" image_name="ChatBarHandle" layout="topleft" - left="-323" + left="-345" name="resize_handle" top="4" width="5" /> - + <button + height="23" + width="32" + layout="topleft" + mouse_opaque="true" + follows="left|top" + name="landmarks_btn" + tool_tip="My Landmarks" + top_delta="1" + left_pad="8" + scale_image="false" + image_overlay="Landmarks_overlay" + image_hover_unselected="PushButton_Over"> + </button> <favorites_bar follows="left|right|top" font="SansSerifSmall" height="20" layout="topleft" - left="0" + left_pad="0" top="4" name="favorite" image_drag_indication="Accordion_ArrowOpened_Off" tool_tip="Drag Landmarks here for quick access to your favorite places in Second Life!" - width="320"> + width="310"> <label follows="left|top" height="13" @@ -185,8 +198,8 @@ tool_tip="Drag Landmarks here for quick access to your favorite places in Second Life!" top="13" valign="bottom" - width="102"> - Favorites Bar + width="290"> + Places you save to your favorites bar will appear here. </label> <!-- More button actually is a text box. --> <more_button diff --git a/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml b/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml deleted file mode 100644 index b2d8bb874b..0000000000 --- a/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<inventory_panel - name="inventory_outbox" - start_folder.name="Outbox" - show_empty_message="false" - start_folder.type="outbox" - follows="all" layout="topleft" - top="0" left="0" height="165" width="308" - top_pad="0" - bg_opaque_color="DkGray2" - bg_alpha_color="DkGray2" - background_visible="true" - border="false" - bevel_style="none" - show_item_link_overlays="true" - tool_tip="Drag and drop items here to prepare them for sale on your storefront" - scroll.reserve_scroll_corner="false"> - <folder folder_arrow_image="Folder_Arrow" - folder_indentation="8" - item_height="20" - item_top_pad="4" - selection_image="Rounded_Square" - left_pad="5" - icon_pad="2" - icon_width="16" - text_pad="1" - text_pad_right="4" - arrow_size="12" - max_folder_item_overlap="2"/> - <item allow_wear="false"/> -</inventory_panel> diff --git a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml index 3f13cea58e..d625f89f3b 100644 --- a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml +++ b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml @@ -1,556 +1,561 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <!-- Side tray Outfit Edit panel --> <panel - background_visible="true" - border="false" - height="600" - follows="all" - layout="topleft" - help_topic="edit_outfit" - left="0" - min_height="350" - name="outfit_edit" - top="0" - width="320"> - <string - name="No Outfit" - value="No Outfit"/> - <string - name="unsaved_changes" - value="Unsaved Changes"/> - <string - name="now_editing" - value="Now Editing"/> - <string - name="folder_view_off" - value="Hierarchy_View_Disabled" - translate="false"/> - <string - name="folder_view_on" - value="Hierarchy_View_On" - translate="false"/> - <string - name="list_view_off" - value="List_View_Disabled" - translate="false"/> - <string - name="list_view_on" - value="List_View_On" - translate="false"/> + background_visible="true" + border="false" + height="600" + follows="all" + layout="topleft" + help_topic="edit_outfit" + left="0" + min_height="350" + name="outfit_edit" + top="0" + width="320"> + <string + name="No Outfit" + value="No Outfit"/> + <string + name="unsaved_changes" + value="Unsaved Changes"/> + <string + name="now_editing" + value="Now Editing"/> + <string + name="folder_view_off" + value="Hierarchy_View_Disabled" + translate="false"/> + <string + name="folder_view_on" + value="Hierarchy_View_On" + translate="false"/> + <string + name="list_view_off" + value="List_View_Disabled" + translate="false"/> + <string + name="list_view_on" + value="List_View_On" + translate="false"/> - <panel.string - name="not_available"> - (N\A) - </panel.string> - <panel.string - name="unknown"> - (unknown) - </panel.string> + <panel.string + name="not_available"> + (N\A) + </panel.string> + <panel.string + name="unknown"> + (unknown) + </panel.string> - <!-- Wearables filtering strings --> - <string name="Filter.All" value="All"/> - <string name="Filter.Clothes/Body" value="Clothes/Body"/> - <string name="Filter.Objects" value="Objects"/> - <string name="Filter.Clothing" value="Clothing"/> - <string name="Filter.Bodyparts" value="Body parts"/> + <!-- Wearables filtering strings --> + <string name="Filter.All" value="All"/> + <string name="Filter.Clothes/Body" value="Clothes/Body"/> + <string name="Filter.Objects" value="Objects"/> + <string name="Filter.Clothing" value="Clothing"/> + <string name="Filter.Bodyparts" value="Body parts"/> - <string - name="replace_body_part" - value="Click to replace your existing shape"/> + <string + name="replace_body_part" + value="Click to replace your existing shape"/> - <button - follows="top|left" - height="24" - image_hover_unselected="BackButton_Over" - image_pressed="BackButton_Press" - image_unselected="BackButton_Off" - layout="topleft" - name="back_btn" - left="5" - tab_stop="false" - top="1" - width="30" - use_draw_context_alpha="false" /> - <text - follows="top|left|right" - font="SansSerifHugeBold" - height="26" - layout="topleft" - left_pad="10" - name="title" - text_color="LtGray" - top="0" - value="Edit Outfit" - use_ellipses="true" - width="275" /> + <button + follows="top|left" + height="24" + image_hover_unselected="BackButton_Over" + image_pressed="BackButton_Press" + image_unselected="BackButton_Off" + layout="topleft" + name="back_btn" + left="5" + tab_stop="false" + top="1" + width="30" + use_draw_context_alpha="false" /> + <text + follows="top|left|right" + font="SansSerifHugeBold" + height="26" + layout="topleft" + left_pad="10" + name="title" + text_color="LtGray" + top="0" + value="Edit outfit parts" + use_ellipses="true" + width="275" /> - <!-- "HEADER WITH ICON, STATUS TEXT AND OUTFIT NAME" --> - <panel - background_visible="true" - bg_alpha_color="DkGray2" - bevel_style="none" - follows="top|left|right" - height="40" - layout="topleft" - left="6" - name="header_panel" - top_pad="5" - width="311"> - <icon - follows="left|top" - height="31" - image_name="Shirt_Large" - left="2" - mouse_opaque="false" - name="outfit_icon" - top="2" - scale_image="true" - visible="true" - width="31" /> - <panel - bevel_style="none" - follows="top|left|right" - height="37" - layout="topleft" - left_pad="5" - name="outfit_name_and_status" - top="2" - width="270"> - <text - follows="top|left|right" - font="SansSerifSmallBold" - height="13" - layout="topleft" - name="status" - text_color="EmphasisColor" - top="2" - value="Now editing..." - use_ellipses="true" - width="245" /> - <text - follows="bottom|left|right" - font="SansSerifLargeBold" - height="18" - layout="topleft" - name="curr_outfit_name" - parse_urls="false" - text_color="LtGray" - top_pad="2" - value="[Current Outfit]" - use_ellipses="true" - width="245" /> - <loading_indicator - follows="right|top" - height="24" - layout="topleft" - right="-2" - name="edit_outfit_loading_indicator" - top="6" - width="24" /> - </panel> - </panel> + <!-- "HEADER WITH ICON, STATUS TEXT AND OUTFIT NAME" --> + <panel + background_visible="true" + bg_alpha_color="DkGray2" + bevel_style="none" + follows="top|left|right" + height="40" + layout="topleft" + left="6" + name="header_panel" + top_pad="5" + width="311"> + <icon + follows="left|top" + height="31" + image_name="Shirt_Large" + left="2" + mouse_opaque="false" + name="outfit_icon" + top="2" + scale_image="true" + visible="true" + width="31" /> + <panel + bevel_style="none" + follows="top|left|right" + height="37" + layout="topleft" + left_pad="5" + name="outfit_name_and_status" + top="2" + width="270"> + <text + follows="top|left|right" + font="SansSerifSmallBold" + height="13" + layout="topleft" + name="status" + text_color="EmphasisColor" + top="2" + value="Now editing..." + use_ellipses="true" + width="245" /> + <text + follows="bottom|left|right" + font="SansSerifLargeBold" + height="18" + layout="topleft" + name="curr_outfit_name" + parse_urls="false" + text_color="LtGray" + top_pad="2" + value="[Current Outfit]" + use_ellipses="true" + width="245" /> + <loading_indicator + follows="right|top" + height="24" + layout="topleft" + right="-2" + name="edit_outfit_loading_indicator" + top="6" + width="24" /> + </panel> + </panel> - <!-- LIST OF WEARABLES (CURRENT OUTFIT/ WEARABLES TO ADD) --> - <!-- *NOTE: border_size is used to calculate space between layout panels and also to calculate resize bar's height. + <!-- LIST OF WEARABLES (CURRENT OUTFIT/ WEARABLES TO ADD) --> + <!-- *NOTE: border_size is used to calculate space between layout panels and also to calculate resize bar's height. Required height for dragbar (icon in spec) is 10, so resizebar height should be 10 px. It is calculated as border_size + 2*UIResizeBarOverlap --> - <layout_stack - animate="true" - border_size="8" - clip="false" - default_tab_group="2" - follows="all" - height="465" - width="313" - layout="topleft" - orientation="vertical" - name="im_panels" - tab_group="1" - top_pad="5" - left="5"> - <layout_panel - layout="topleft" - height="187" - min_height="155" - name="outfit_wearables_panel" - width="313" - auto_resize="true" - user_resize="true"> + <layout_stack + animate="true" + border_size="8" + clip="false" + default_tab_group="2" + follows="all" + height="465" + width="313" + layout="topleft" + orientation="vertical" + name="im_panels" + tab_group="1" + top_pad="5" + left="5"> + <layout_panel + layout="topleft" + height="187" + min_height="155" + name="outfit_wearables_panel" + width="313" + auto_resize="true" + user_resize="true"> - <layout_stack - animate="true" - border_size="0" - follows="all" - height="185" - width="313" - orientation="vertical" - layout="topleft" - name="filter_panels" - top="0" - left="0"> - <layout_panel - auto_resize="true" - background_visible="false" - layout="topleft" - height="154" - name="add_button_and_combobox" - width="311" - visible="true"> + <layout_stack + animate="true" + border_size="0" + follows="all" + height="185" + width="313" + orientation="vertical" + layout="topleft" + name="filter_panels" + top="0" + left="0"> + <layout_panel + auto_resize="true" + background_visible="false" + layout="topleft" + height="154" + name="add_button_and_combobox" + width="311" + visible="true"> - <!-- List containing items from the COF and Base outfit --> - <panel - background_visible="false" - class="cof_wearables" - filename="panel_cof_wearables.xml" - follows="all" - height="129" - layout="topleft" - left="1" - name="cof_wearables_list" - top="0" - width="311" /> + <!-- List containing items from the COF and Base outfit --> + <panel + background_visible="false" + class="cof_wearables" + filename="panel_cof_wearables.xml" + follows="all" + height="129" + layout="topleft" + left="1" + name="cof_wearables_list" + top="0" + width="311" /> - <button - follows="left|bottom" - height="22" - image_pressed="PushButton_Press" - image_pressed_selected="PushButton_Selected_Press" - image_selected="PushButton_Selected_Press" - is_toggle="true" - label="Add More..." - layout="topleft" - left="2" - name="show_add_wearables_btn" - top_pad="2" - tool_tip="Open/Close" - width="125" /> + <button + follows="left|bottom" + height="22" + image_pressed="PushButton_Press" + image_pressed_selected="PushButton_Selected_Press" + image_selected="PushButton_Selected_Press" + is_toggle="true" + label="Add More..." + layout="topleft" + left="2" + name="show_add_wearables_btn" + top_pad="2" + tool_tip="Open/Close" + width="125" /> - <combo_box - follows="left|right|bottom" - height="22" - layout="topleft" - left_pad="5" - name="list_view_filter_combobox" - top_delta="0" - visible="false" - width="152"/> - <combo_box - follows="left|right|bottom" - height="22" - layout="topleft" - left_delta="0" - name="folder_view_filter_combobox" - top_delta="0" - visible="false" - width="152"/> + <combo_box + follows="left|right|bottom" + height="22" + layout="topleft" + left_pad="5" + name="list_view_filter_combobox" + top_delta="0" + visible="false" + width="152"/> + <combo_box + follows="left|right|bottom" + height="22" + layout="topleft" + left_delta="0" + name="folder_view_filter_combobox" + top_delta="0" + visible="false" + width="152"/> - <button - follows="bottom|right" - height="22" - image_overlay="Search_Icon" - image_pressed="PushButton_Press" - image_pressed_selected="PushButton_Selected_Press" - image_selected="PushButton_Selected_Press" - is_toggle="true" - layout="topleft" - name="filter_button" - right="-5" - top_delta="0" - visible="false" - width="20" /> - </layout_panel> + <button + follows="bottom|right" + height="22" + image_overlay="Search_Icon" + image_pressed="PushButton_Press" + image_pressed_selected="PushButton_Selected_Press" + image_selected="PushButton_Selected_Press" + is_toggle="true" + layout="topleft" + name="filter_button" + right="-5" + top_delta="0" + visible="false" + width="20" /> + </layout_panel> - <layout_panel - auto_resize="false" - background_visible="true" - bg_alpha_color="DkGray2" - height="30" - name="filter_panel" - width="311" - visible="false"> + <layout_panel + auto_resize="false" + background_visible="true" + bg_alpha_color="DkGray2" + height="30" + name="filter_panel" + width="311" + visible="false"> - <filter_editor - background_image="TextField_Search_Off" - enabled="true" - follows="left|right|top" - label="Filter Inventory Wearables" - layout="topleft" - left="5" - width="290" - height="25" - name="look_item_filter" - search_button_visible="true" - text_color="black" - visible="true"/> + <filter_editor + background_image="TextField_Search_Off" + enabled="true" + follows="left|right|top" + label="Filter Inventory Wearables" + layout="topleft" + left="5" + width="290" + height="25" + name="look_item_filter" + search_button_visible="true" + text_color="black" + visible="true"/> - </layout_panel> - </layout_stack> - </layout_panel> + </layout_panel> + </layout_stack> + </layout_panel> - <layout_panel background_visible="false" - bg_alpha_color="DkGray2" - auto_resize="true" - height="450" - min_height="80" - name="add_wearables_panel" - width="313" - tab_group="2" - user_resize="true" - visible="false"> + <layout_panel background_visible="false" + bg_alpha_color="DkGray2" + auto_resize="true" + height="450" + min_height="80" + name="add_wearables_panel" + width="313" + tab_group="2" + user_resize="true" + visible="false"> - <!-- this icon represent dragbar between layout panels. + <!-- this icon represent dragbar between layout panels. This is a workaround implemented in EXT-7255 becouse of an issue with layout stack (EXT-7471) --> - <icon follows="left|top|right" - height="10" - image_name="Dragbar" - left="0" - top_pad="-9" - width="313" /> - <inventory_panel allow_multi_select="true" - background_visible="false" - border="false" - follows="left|top|right|bottom" - height="418" - layout="topleft" - left="0" - mouse_opaque="false" - name="folder_view" - top_pad="0" - width="313" - visible="false"/> - <panel name="filtered_wearables_panel" - background_opaque="true" - background_visible="false" - layout="topleft" - follows="left|top|right|bottom" - border="false" - height="418" - left="0" - mouse_opaque="false" - width="310" - top_delta="0" - visible="true"> - <wearable_items_list color="0.107 0.107 0.107 1" - name="list_view" - allow_select="true" - layout="topleft" - follows="all" - multi_select="true" - width="313" - height="418" - left="0" - top="0"/> - </panel> - <button follows="bottom|left" - height="22" - left="2" - label="Wear Item" - layout="topleft" - name="plus_btn" - top_pad="5" - width="130" /> - </layout_panel> - </layout_stack> + <icon follows="left|top|right" + height="10" + image_name="Dragbar" + left="0" + top_pad="-9" + width="313" /> + <inventory_panel allow_multi_select="true" + background_visible="false" + border="false" + follows="left|top|right|bottom" + height="418" + layout="topleft" + left="0" + mouse_opaque="false" + name="folder_view" + top_pad="0" + width="313" + preinitialize_views="false" + visible="false"/> + <panel name="filtered_wearables_panel" + background_opaque="true" + background_visible="false" + layout="topleft" + follows="left|top|right|bottom" + border="false" + height="418" + left="0" + mouse_opaque="false" + width="310" + top_delta="0" + visible="true"> + <wearable_items_list color="0.107 0.107 0.107 1" + name="list_view" + allow_select="true" + layout="topleft" + follows="all" + multi_select="true" + width="313" + height="418" + left="0" + top="0"/> + </panel> + <button follows="bottom|left" + height="22" + left="2" + label="Wear Item" + layout="topleft" + name="plus_btn" + top_pad="5" + width="130" /> + </layout_panel> + </layout_stack> - <!-- BUTTON BAR --> - <panel - background_visible="true" - bevel_style="none" - follows="bottom|left|right" - height="27" - layout="topleft" - left="5" - name="no_add_wearables_button_bar" - top_pad="0" - width="313"> - <menu_button - follows="bottom|left" - height="25" - image_hover_unselected="Toolbar_Left_Over" - image_overlay="OptionsMenu_Off" - image_selected="Toolbar_Left_Selected" - image_unselected="Toolbar_Left_Off" - layout="topleft" - left="0" - name="gear_menu_btn" - top="1" - width="31" /> - <icon - follows="bottom|left|right" - height="25" - image_name="Toolbar_Middle_Off" - layout="topleft" - left_pad="1" - name="dummy_right_icon" - width="250" /> - <button - follows="bottom|right" - height="25" - image_hover_unselected="Toolbar_Right_Over" - image_overlay="Shop" - image_selected="Toolbar_Right_Selected" - image_unselected="Toolbar_Right_Off" - layout="topleft" - left_pad="1" - name="shop_btn_1" - top="1" - tool_tip="Visit the SL Marketplace. You can also select something you are wearing, then click here to see more things like it" - width="31" /> - </panel> + <!-- BUTTON BAR --> + <panel + background_visible="true" + bevel_style="none" + follows="bottom|left|right" + height="27" + layout="topleft" + left="5" + name="no_add_wearables_button_bar" + top_pad="0" + width="313"> + <menu_button + follows="bottom|left" + height="25" + image_hover_unselected="Toolbar_Left_Over" + image_overlay="OptionsMenu_Off" + image_selected="Toolbar_Left_Selected" + image_unselected="Toolbar_Left_Off" + layout="topleft" + left="0" + name="gear_menu_btn" + top="1" + width="31" /> + <icon + follows="bottom|left|right" + height="25" + image_name="Toolbar_Middle_Off" + layout="topleft" + left_pad="1" + name="dummy_right_icon" + width="250" /> + <button + follows="bottom|right" + height="25" + image_hover_unselected="Toolbar_Right_Over" + image_overlay="Shop" + image_selected="Toolbar_Right_Selected" + image_unselected="Toolbar_Right_Off" + layout="topleft" + left_pad="1" + name="shop_btn_1" + top="1" + tool_tip="Visit the SL Marketplace. You can also select something you are wearing, then click here to see more things like it" + width="31" /> + </panel> - <!-- BUTTON BAR - WEARABLES ADDING MODE --> - <panel - background_visible="true" - bevel_style="none" - follows="left|right|bottom" - height="27" - layout="topleft" - left="5" - name="add_wearables_button_bar" - top_delta="0" - visible="false" - width="313"> - <menu_button - follows="bottom|left" - height="25" - image_hover_unselected="Toolbar_Left_Over" - image_overlay="OptionsMenu_Off" - image_selected="Toolbar_Left_Selected" - image_unselected="Toolbar_Left_Off" - layout="topleft" - left="0" - name="wearables_gear_menu_btn" - top="1" - width="31" /> - <button - follows="bottom|left" - height="25" - image_hover_unselected="Toolbar_Middle_Over" - image_overlay="Hierarchy_View_Disabled" - image_selected="Toolbar_Middle_Selected" - image_unselected="Toolbar_Middle_Off" - is_toggle="true" - layout="topleft" - left_pad="1" - name="folder_view_btn" - top="1" - width="31" /> - <button - follows="bottom|left" - height="25" - image_hover_unselected="Toolbar_Middle_Over" - image_overlay="List_View_On" - image_selected="Toolbar_Middle_Selected" - image_unselected="Toolbar_Middle_Off" - is_toggle="true" - layout="topleft" - left_pad="1" - name="list_view_btn" - top="1" - width="31" /> - <icon - follows="bottom|left|right" - height="25" - image_name="Toolbar_Middle_Off" - layout="topleft" - left_pad="1" - name="dummy_right_icon" - width="186" > - </icon> - <button - follows="bottom|right" - height="25" - image_hover_unselected="Toolbar_Right_Over" - image_overlay="Shop" - image_selected="Toolbar_Right_Selected" - image_unselected="Toolbar_Right_Off" - layout="topleft" - left_pad="1" - name="shop_btn_2" - top="1" - tool_tip="Visit the SL Marketplace. You can also select something you are wearing, then click here to see more things like it" - width="31" /> - </panel> + <!-- BUTTON BAR - WEARABLES ADDING MODE --> + <panel + background_visible="true" + bevel_style="none" + follows="left|right|bottom" + height="27" + layout="topleft" + left="5" + name="add_wearables_button_bar" + top_delta="0" + visible="false" + width="313"> + <menu_button + follows="bottom|left" + height="25" + image_hover_unselected="Toolbar_Left_Over" + image_overlay="OptionsMenu_Off" + image_selected="Toolbar_Left_Selected" + image_unselected="Toolbar_Left_Off" + layout="topleft" + left="0" + name="wearables_gear_menu_btn" + top="1" + width="31" /> + <button + follows="bottom|left" + height="25" + image_hover_unselected="Toolbar_Middle_Over" + image_overlay="Hierarchy_View_Disabled" + image_selected="Toolbar_Middle_Selected" + image_unselected="Toolbar_Middle_Off" + is_toggle="true" + layout="topleft" + left_pad="1" + name="folder_view_btn" + top="1" + width="31" /> + <button + follows="bottom|left" + height="25" + image_hover_unselected="Toolbar_Middle_Over" + image_overlay="List_View_On" + image_selected="Toolbar_Middle_Selected" + image_unselected="Toolbar_Middle_Off" + is_toggle="true" + layout="topleft" + left_pad="1" + name="list_view_btn" + top="1" + width="31" /> + <icon + follows="bottom|left|right" + height="25" + image_name="Toolbar_Middle_Off" + layout="topleft" + left_pad="1" + name="dummy_right_icon" + width="186" > + </icon> + <button + follows="bottom|right" + height="25" + image_hover_unselected="Toolbar_Right_Over" + image_overlay="Shop" + image_selected="Toolbar_Right_Selected" + image_unselected="Toolbar_Right_Off" + layout="topleft" + left_pad="1" + name="shop_btn_2" + top="1" + tool_tip="Visit the SL Marketplace. You can also select something you are wearing, then click here to see more things like it" + width="31" /> + </panel> - <!-- SAVE AND REVERT BUTTONS --> - <panel - follows="left|right|bottom" - height="30" - layout="topleft" - left="4" - top_pad="2" - name="save_revert_button_bar" - width="300"> - <layout_stack - follows="bottom|left|right" - height="23" - layout="topleft" - mouse_opaque="false" - name="button_bar_ls" - left="0" - orientation="horizontal" - top="0" - width="313"> - <layout_panel - follows="bottom|left|right" - height="23" - layout="bottomleft" - left="0" - mouse_opaque="false" - name="save_btn_lp" - auto_resize="true" - width="156"> - <button - follows="bottom|left|right" - height="23" - label="Save" - left="1" - layout="topleft" - name="save_btn" - top="0" - width="155" /> - <button - follows="bottom|right" - height="23" - name="save_flyout_btn" - label="" - layout="topleft" - left_pad="-20" - tab_stop="false" - top="0" - image_selected="SegmentedBtn_Right_Selected_Press" - image_unselected="SegmentedBtn_Right_Off" - image_pressed="SegmentedBtn_Right_Press" - image_pressed_selected="SegmentedBtn_Right_Selected_Press" - image_overlay="Arrow_Small_Up" - width="20"/> - </layout_panel> - <layout_panel - follows="bottom|left|right" - height="23" - layout="bottomleft" - left_pad="3" - mouse_opaque="false" - name="revert_btn_lp" - auto_resize="true" - width="147"> - <button - follows="bottom|left|right" - height="23" - left="0" - label="Undo Changes" - layout="topleft" - name="revert_btn" - top="0" - tool_tip="Revert to last saved version" - width="147" /> - </layout_panel> - </layout_stack> - </panel> + <!-- SAVE AND REVERT BUTTONS --> + <panel + follows="left|right|bottom" + height="30" + layout="topleft" + left="4" + top_pad="2" + name="save_revert_button_bar" + width="300"> + <layout_stack + follows="bottom|left|right" + height="23" + layout="topleft" + mouse_opaque="false" + name="button_bar_ls" + left="0" + orientation="horizontal" + top="0" + width="313"> + <layout_panel + follows="bottom|left|right" + height="23" + layout="bottomleft" + left="0" + mouse_opaque="false" + name="save_btn_lp" + auto_resize="true" + width="156"> + <button + follows="bottom|left|right" + height="23" + label="Save changes" + left="1" + layout="topleft" + name="save_btn" + top="0" + width="155" /> + </layout_panel> + <layout_panel + follows="bottom|left|right" + height="23" + layout="bottomleft" + left_pad="3" + mouse_opaque="false" + name="save_as_btn_lp" + auto_resize="true" + width="156"> + <button + follows="bottom|left|right" + height="23" + label="Save as..." + layout="topleft" + name="save_as_btn" + top="0" + left="1" + width="155" /> + </layout_panel> + <layout_panel + follows="bottom|left|right" + height="23" + layout="bottomleft" + left_pad="3" + mouse_opaque="false" + name="revert_btn_lp" + auto_resize="true" + width="147"> + <button + follows="bottom|left|right" + height="23" + left="0" + label="Undo Changes" + layout="topleft" + name="revert_btn" + top="0" + tool_tip="Revert to last saved version" + width="147" /> + </layout_panel> + </layout_stack> + </panel> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_outfit_snapshot_inventory.xml b/indra/newview/skins/default/xui/en/panel_outfit_snapshot_inventory.xml index 800faabc2a..441cf97e87 100644 --- a/indra/newview/skins/default/xui/en/panel_outfit_snapshot_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_outfit_snapshot_inventory.xml @@ -41,7 +41,7 @@ <text follows="top|left" font="SansSerif" - height="56" + height="126" layout="topleft" left="10" length="1" @@ -50,7 +50,9 @@ width="200" type="string" word_wrap="true"> - Uploading an image to your inventory costs L$[UPLOAD_COST]. +Uploading an image to your inventory costs L$[UPLOAD_COST]. + +Fee is based on your subscription level. Higher levels are charged lower fees. </text> <button follows="right|bottom" @@ -67,7 +69,7 @@ <button follows="left|bottom" height="23" - label="UPLOAD L$10" + label="UPLOAD L$[UPLOAD_COST]" layout="topleft" left="10" name="save_btn" @@ -76,4 +78,4 @@ <button.commit_callback function="Inventory.SaveOutfitPhoto" /> </button> -</panel>
\ No newline at end of file +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml index eeb930485e..7b898dbd7f 100644 --- a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml @@ -30,7 +30,6 @@ tab_height="30" tab_position="top" halign="center" - hide_scroll_arrows="true" top="8" width="315"> <panel @@ -101,28 +100,33 @@ <button follows="bottom|left|right" height="23" - label="Save As" + label="Save changes" left="1" layout="topleft" name="save_btn" top="0" width="155" /> - <button - follows="bottom|right" - height="23" - name="save_flyout_btn" - label="" - layout="topleft" - left_pad="-20" - tab_stop="false" - image_selected="SegmentedBtn_Right_Selected_Press" - image_unselected="SegmentedBtn_Right_Off" - image_pressed="SegmentedBtn_Right_Press" - image_pressed_selected="SegmentedBtn_Right_Selected_Press" - image_overlay="Arrow_Small_Up" - width="20"/> - </layout_panel> - <layout_panel + </layout_panel> + <layout_panel + follows="bottom|left|right" + height="23" + layout="bottomleft" + left_pad="3" + mouse_opaque="false" + name="save_as_btn_lp" + auto_resize="true" + width="156"> + <button + follows="bottom|left|right" + height="23" + label="Save as..." + layout="topleft" + name="save_as_btn" + top="0" + left="1" + width="155" /> + </layout_panel> + <layout_panel follows="bottom|left|right" height="23" layout="bottomleft" diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index a47121ae99..50035fd0e3 100644 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -12,7 +12,7 @@ width="333"> <string name="no_recent_people" - value="No recent people. Looking for people to hang out with? Try [secondlife:///app/search/people Search] or the [secondlife:///app/worldmap World Map]." /> + value="No recent people." /> <string name="no_filtered_recent_people" value="Didn't find what you're looking for? Try [secondlife:///app/search/people/[SEARCH_TERM] Search]." /> @@ -30,8 +30,13 @@ value="No friends" /> <string name="no_friends_msg"> - Find friends using [secondlife:///app/search/people Search] or right-click on a Resident to add them as a friend. -Looking for people to hang out with? Try the [secondlife:///app/worldmap World Map]. + To add someone as a friend, right-click on their avatar or their name. + +Looking for places with more people? + +[secondlife:///app/floater/destinations Destination Guide] has locations chosen by Second Life staff. + +[secondlife:///app/search/ Search] lets you search all of Second Life for certain keywords. </string> <string name="no_filtered_friends_msg"> @@ -45,8 +50,11 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M name="no_filtered_groups_msg" value="Didn't find what you're looking for? Try [secondlife:///app/search/groups/[SEARCH_TERM] Search]." /> <string - name="no_groups_msg" - value="Looking for Groups to join? Try [secondlife:///app/search/groups Search]." /> + name="no_groups_msg"> +You are not a member of any groups. + +Learn about [https://community.secondlife.com/knowledgebase/joining-and-participating-in-groups-r51/ groups in Second Life.] + </string> <string name="MiniMapToolTipMsg" value="[REGION](Double-click to open Map, shift-drag to pan)"/> @@ -55,7 +63,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M value="[REGION](Double-click to teleport, shift-drag to pan)"/> <string name="GroupCountWithInfo" - value="You belong to [COUNT] groups, and can join [REMAINING] more. [secondlife:/// Want more?]"/> + value="You belong to [COUNT] groups, and can join [REMAINING] more. [secondlife:/// Raise your limit]"/> <tab_container bottom="-10" follows="all" @@ -493,6 +501,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M top_pad="4" left="3" use_ellipses="true" + skip_link_underline="true" name="groupcount"> You belong to [COUNT] groups, and can join [REMAINING] more. </text> diff --git a/indra/newview/skins/default/xui/en/panel_pick_info.xml b/indra/newview/skins/default/xui/en/panel_pick_info.xml index 79d190e1e0..99c47eb825 100644 --- a/indra/newview/skins/default/xui/en/panel_pick_info.xml +++ b/indra/newview/skins/default/xui/en/panel_pick_info.xml @@ -103,7 +103,6 @@ height="100" width="280" parse_urls="true" - hide_scrollbar="false" layout="topleft" left="10" top_pad="2" diff --git a/indra/newview/skins/default/xui/en/panel_pick_list_item.xml b/indra/newview/skins/default/xui/en/panel_pick_list_item.xml index 43d580844f..4c0cdd321e 100644 --- a/indra/newview/skins/default/xui/en/panel_pick_list_item.xml +++ b/indra/newview/skins/default/xui/en/panel_pick_list_item.xml @@ -32,7 +32,6 @@ width="308" /> <texture_picker allow_no_texture="true" - border_enabled="true" fallback_image="default_land_picture.j2c" enabled="false" follows="left|top" diff --git a/indra/newview/skins/default/xui/en/panel_place_profile.xml b/indra/newview/skins/default/xui/en/panel_place_profile.xml index 0dd75b1b55..bdde2cab20 100644 --- a/indra/newview/skins/default/xui/en/panel_place_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_place_profile.xml @@ -172,7 +172,7 @@ name="back_btn" tool_tip="Back" tab_stop="false" - top="4" + top="2" width="30" use_draw_context_alpha="false" /> <text @@ -183,24 +183,24 @@ left_pad="10" name="title" text_color="LtGray" - top="4" + top="2" use_ellipses="true" value="Place Profile" width="280" /> <scroll_container color="DkGray2" follows="all" - height="572" + height="575" layout="topleft" left="9" name="place_scroll" opaque="true" - top_pad="10" - width="310"> + top_pad="9" + width="324"> <panel bg_alpha_color="DkGray2" follows="left|top|right|bottom" - height="580" + height="597" layout="topleft" left="0" min_height="300" @@ -277,32 +277,25 @@ height="14" layout="topleft" left="10" - name="region_title" - text_color="white" top_pad="5" + width="290" + name="parcel_title" + text_color="white" use_ellipses="true" - value="SampleRegion" - width="290" /> + value="SampleParcel" /> <text parse_urls="false" follows="left|top|right" height="14" layout="topleft" left="10" - name="parcel_title" - top_pad="4" - use_ellipses="true" - value="SampleParcel, Name Long (145, 228, 26)" - width="285" /> - <expandable_text - follows="left|top" - height="50" - layout="topleft" - left="5" - name="description" - top_pad="10" - value="Du waltz die spritz" - width="285" /> + top_pad="5" + width="285" + name="region_title" + text_color="White" + use_ellipses="true"> + Region: [REGIONAMEPOS] + </text> <text follows="left|top" height="14" @@ -310,20 +303,28 @@ left="10" name="owner_label" text_color="White" - top_pad="0" + top_pad="2" value="Owner:" - width="90" /> - <!--TODO: HOOK THIS NAME UP WITH AN INSPECTOR --> + width="80" /> <text follows="left|top|right" height="14" layout="topleft" - left_pad="1" - name="owner_value" + left_pad="0" + name="parcel_owner" top_delta="0" value="Alex Superduperlongenamenton" use_ellipses="true" width="200" /> + <expandable_text + follows="left|top" + height="50" + layout="topleft" + left="5" + name="description" + top_pad="10" + value="Du waltz die spritz" + width="285" /> <icon follows="top|left" height="16" @@ -331,7 +332,7 @@ layout="topleft" left="10" name="maturity_icon" - top_delta="0" + top_pad="0" width="18" /> <text follows="left|top|right" diff --git a/indra/newview/skins/default/xui/en/panel_places.xml b/indra/newview/skins/default/xui/en/panel_places.xml index 7d171490e8..58be4d4c5e 100644 --- a/indra/newview/skins/default/xui/en/panel_places.xml +++ b/indra/newview/skins/default/xui/en/panel_places.xml @@ -11,30 +11,156 @@ background_visible="true" top="0" left="0" width="333"> - <string - name="landmarks_tab_title" - value="MY LANDMARKS" /> - <string - name="teleport_history_tab_title" - value="TELEPORT HISTORY" /> - <filter_editor - text_pad_left="10" - follows="left|top|right" - font="SansSerifSmall" - height="23" - layout="topleft" - left="10" - label="Filter My Places" - max_length_chars="300" - name="Filter" - tab_group="1" - top="3" - width="303" /> + <string + name="landmarks_tab_title" + value="LANDMARKS" /> + <string + name="teleport_history_tab_title" + value="VISITED" /> + <string + name="favorites_tab_title" + value="FAVORITES" /> + <string + name="tooltip_trash_items" + value="Remove selected landmark or folder" /> + <string + name="tooltip_trash_history" + value="Delete list of visited places" /> + <layout_stack + animate="false" + border_size="0" + follows="all" + height="564" + layout="topleft" + orientation="vertical" + top="1" + left="0" + name="places_layout_panel" + width="333"> + <layout_panel + auto_resize="true" + height="538" + layout="topleft" + name="main_panel" + width="333"> + <layout_stack + animate="false" + border_size="0" + follows="left|top|right" + height="27" + layout="topleft" + orientation="horizontal" + top="0" + left="0" + name="top_menu_panel" + width="320"> + <layout_panel + auto_resize="true" + layout="topleft" + name="filter_panel" + width="193"> + <filter_editor + text_pad_left="10" + follows="left|top|right" + font="SansSerifSmall" + height="23" + layout="topleft" + left="10" + label="Filter My Places" + max_length_chars="300" + name="Filter" + tab_group="1" + top="3" + width="181" /> + </layout_panel> + <layout_panel + auto_resize="false" + height="25" + layout="topleft" + name="options_gear_btn_panel" + width="32"> + <menu_button + follows="bottom|left" + tool_tip="Show options" + height="25" + image_hover_unselected="Toolbar_Middle_Over" + image_overlay="OptionsMenu_Off" + image_selected="Toolbar_Middle_Selected" + image_unselected="Toolbar_Middle_Off" + menu_position="bottomleft" + layout="topleft" + left="0" + name="options_gear_btn" + top="0" + width="31" /> + </layout_panel> + <layout_panel + auto_resize="false" + height="25" + layout="topleft" + name="options_sort_btn_panel" + width="32"> + <menu_button + follows="bottom|left" + tool_tip="Show sorting options" + height="25" + image_hover_unselected="Toolbar_Middle_Over" + image_overlay="Conv_toolbar_sort" + image_selected="Toolbar_Middle_Selected" + image_unselected="Toolbar_Middle_Off" + menu_position="bottomleft" + layout="topleft" + left="0" + name="sorting_menu_btn" + top="0" + width="31" /> + </layout_panel> + <layout_panel + auto_resize="false" + height="25" + layout="topleft" + name="add_btn_panel" + width="32"> + <menu_button + follows="bottom|left" + height="25" + image_hover_unselected="Toolbar_Middle_Over" + image_overlay="AddItem_Off" + image_selected="Toolbar_Middle_Selected" + image_unselected="Toolbar_Middle_Off" + menu_position="bottomleft" + layout="topleft" + left="0" + name="add_menu_btn" + tool_tip="Add new landmark or folder" + top="0" + width="31" /> + </layout_panel> + <layout_panel + auto_resize="false" + height="25" + layout="topleft" + name="trash_btn_panel" + width="31"> + <dnd_button + follows="bottom|left" + height="25" + image_hover_unselected="Toolbar_Right_Over" + image_overlay="TrashItem_Off" + image_selected="Toolbar_Right_Selected" + image_unselected="Toolbar_Right_Off" + left="0" + layout="topleft" + name="trash_btn" + top="0" + width="31"/> + </layout_panel> + </layout_stack> <tab_container follows="all" - halign="center" - height="503" layout="topleft" + halign="center" + height="504" left="6" name="Places Tabs" tab_min_width="80" @@ -42,46 +168,57 @@ background_visible="true" tab_height="30" tab_group="2" tab_position="top" - top_pad="10" - width="315" /> + top_pad="7" + width="318" + visible="true"/> <panel class="panel_place_profile" filename="panel_place_profile.xml" follows="all" - height="533" layout="topleft" + height="533" left="0" + top="4" help_topic="place_profile" name="panel_place_profile" - top="5" visible="false" - width="315" /> + width="318" /> <panel class="panel_landmark_info" filename="panel_landmark_info.xml" follows="all" - height="533" layout="topleft" + height="533" left="0" + top="4" help_topic="landmark" name="panel_landmark_info" - top="5" visible="false" - width="315" /> + width="318" /> + </layout_panel> + + <!--*********************** Button wrappers ***********************--> + <layout_panel + auto_resize="false" + layout="topleft" + height="25" + name="button_layout_panel"> <panel follows="bottom|left|right" height="23" layout="topleft" left="4" + top="2" name="button_panel" - width="315"> - + width="318"> + <layout_stack follows="bottom|left|right" height="23" layout="topleft" mouse_opaque="false" name="bottom_bar_ls0" + animate="false" left="4" orientation="horizontal" top="0" @@ -150,8 +287,32 @@ background_visible="true" width="85" /> </layout_panel> </layout_stack> - </layout_panel> - + </layout_panel> + <!--*********************** Options button ***********************--> + <layout_panel + follows="bottom|right" + height="23" + layout="bottomleft" + left_pad="0" + mouse_opaque="false" + visible="false" + name="lp_options" + auto_resize="false" + width="23"> + <menu_button + follows="bottom|right" + height="23" + image_disabled="ComboButton_UpOff" + image_unselected="ComboButton_UpOff" + image_selected="ComboButton_UpSelected" + layout="topleft" + mouse_opaque="false" + name="overflow_btn" + tool_tip="Show additional options" + top="0" + left="0" + width="23" /> + </layout_panel> <layout_panel follows="bottom|left|right" height="23" @@ -159,103 +320,8 @@ background_visible="true" left_pad="0" mouse_opaque="false" name="lp2" - auto_resize="true" + auto_resize="true" width="116"> - - <!--*********************** Edit, Options buttons ***********************--> - - <layout_stack - follows="bottom|left|right" - height="23" - layout="topleft" - mouse_opaque="false" - name="bottom_bar_ls3" - left="0" - orientation="horizontal" - top="0" - width="113"> - - <layout_panel - follows="bottom|left|right" - height="23" - layout="bottomleft" - left_pad="0" - mouse_opaque="false" - name="edit_btn_lp" - auto_resize="true" - width="84"> - <button - follows="bottom|left|right" - height="23" - label="Edit" - layout="topleft" - left="1" - mouse_opaque="false" - name="edit_btn" - tool_tip="Edit landmark information" - top="0" - width="83" /> - </layout_panel> - - <layout_panel - follows="bottom|right" - height="23" - layout="bottomleft" - left_pad="0" - mouse_opaque="false" - name="overflow_btn_lp" - auto_resize="true" - width="24"> - <menu_button - follows="bottom|right" - height="23" - image_disabled="ComboButton_UpOff" - image_unselected="ComboButton_UpOff" - image_selected="ComboButton_UpSelected" - layout="topleft" - mouse_opaque="false" - name="overflow_btn" - tool_tip="Show additional options" - top="0" - left="1" - width="23" /> - </layout_panel> - </layout_stack> - - <!--*********************** Profile button ***********************--> - - <layout_stack - follows="bottom|left|right" - height="23" - layout="topleft" - mouse_opaque="false" - name="bottom_bar_profile_ls" - left="0" - orientation="horizontal" - top="0" - width="110"> - <layout_panel - follows="bottom|left|right" - height="23" - layout="bottomleft" - left_pad="3" - mouse_opaque="false" - name="profile_btn_lp" - auto_resize="true" - width="102"> - <button - follows="bottom|left|right" - height="23" - label="Profile" - layout="topleft" - mouse_opaque="false" - name="profile_btn" - left="1" - tool_tip="Show place profile" - top="0" - width="101" /> - </layout_panel> - </layout_stack> <!--*********************** Close button ***********************--> @@ -300,6 +366,7 @@ background_visible="true" <layout_stack follows="bottom|left|right" + animate="false" height="23" layout="topleft" mouse_opaque="false" @@ -354,4 +421,6 @@ background_visible="true" </layout_panel> </layout_stack> </panel> + </layout_panel> + </layout_stack> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml index 4f0bb9d3b7..d0518aa245 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml @@ -143,6 +143,32 @@ name="ui_scale_slider" top_pad="-14" width="250" /> + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left="33" + name="HUD Size:" + top_pad="20" + width="100"> + HUD Scale: + </text> + <slider + control_name="HUDScaleFactor" + decimal_digits="2" + follows="left|top" + height="17" + increment="0.1" + initial_value="1" + layout="topleft" + left_pad="0" + max_val="2.0" + min_val="1.0" + name="ui_scale_slider" + top_pad="-14" + width="250" /> <check_box control_name="ShowScriptErrors" follows="left|top" @@ -222,14 +248,27 @@ top_pad="5" width="237"/> <button + follows="top|left" + layout="topleft" + label="Remembered Usernames" + name="remembered_usernames" height="20" - label="Default Creation Permissions" + left="30" + top_pad="16" + width="200"> + <button.commit_callback + function="Pref.RememberedUsernames" /> + </button> + <button + follows="top|left" layout="topleft" + label="Default Creation Permissions" name="default_creation_permissions" + height="20" left="30" - top_pad = "20" - width="250"> - <button.commit_callback - function="Pref.PermsDefault" /> + top_pad="16" + width="200"> + <button.commit_callback + function="Pref.PermsDefault" /> </button> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml index 9e7023d2f2..c023cb036e 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml @@ -52,7 +52,7 @@ </check_box> <check_box - control_name="VoiceCallsFriendsOnly" + enabled="false" height="16" label="Only friends and groups can call or IM me" layout="topleft" @@ -99,6 +99,7 @@ label="Bubble Chat" layout="topleft" top_pad="4" + left_delta="0" name="bubble_text_chat" width="330"> </check_box> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml new file mode 100644 index 0000000000..9dab7d34e6 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8"?> +<panel + border="true" + follows="all" + height="408" + label="Controls" + layout="topleft" + left="102" + name="controls" + top="1" + width="517"> + <combo_box + follows="top|left" + layout="topleft" + top="6" + left="10" + height="23" + width="232" + name="key_mode"> + <combo_box.item + label="When in third person" + name="third_person" + value="1"/> + <combo_box.item + label="When in first person mode (Mouselook)" + name="first_person" + value="0"/> + <combo_box.item + label="When editing avatar" + name="edit_avatar" + value="2"/> + <combo_box.item + label="When sitting" + name="sitting" + value="3"/> + </combo_box> + + <button + follows="top|left" + layout="topleft" + top="6" + right="-10" + height="23" + width="140" + label="Restore Defaults" + tool_tip="Restores default values for all control modes." + name="restore_defaults"/> + + <scroll_list + draw_heading="true" + follows="all" + layout="topleft" + column_padding="0" + selection_type="header" + top="31" + left="3" + bottom="-3" + right="-3" + can_sort="false" + multi_select="false" + name="controls_list" + fg_disable_color="ScrollUnselectedColor"/> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml index 4692a226d9..5aff7a5127 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml @@ -242,7 +242,7 @@ top_delta="24" width="280"> <check_box.commit_callback - function="Pref.VertexShaderEnable" /> + function="Pref.RenderOptionUpdate" /> </check_box> <check_box @@ -256,7 +256,7 @@ top_delta="24" width="256"> <check_box.commit_callback - function="Pref.VertexShaderEnable" /> + function="Pref.RenderOptionUpdate" /> </check_box> <slider @@ -293,6 +293,21 @@ width="65"> 0 </text> +<text +type="string" +length="1" +follows="left|top" +height="16" +layout="topleft" +left_delta="68" +name="IndirectMaxComplexityLink" +mouse_opaque="false" +top_delta="0" +width="120"> +[https://community.secondlife.com/t5/Featured-News/Why-are-all-these-people-made-of-colored-jelly/ba-p/3031255 What's this?] +</text> + + <check_box control_name="AlwaysRenderFriends" height="16" @@ -345,7 +360,6 @@ function="Pref.PrefLoad" parameter="graphic"/> </button> - min_val="0.125" <button follows="top|left" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index 6732f4ff1c..dff6f6e600 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -148,20 +148,6 @@ </radio_group> <check_box - top_delta="2" - enabled="true" - follows="left|top" - height="18" - initial_value="true" - control_name="BrowserPluginsEnabled" - label="Enable plugins" - left_delta="20" - mouse_opaque="true" - name="browser_plugins_enabled" - radio_style="false" - width="400" - top_pad="5"/> - <check_box top_delta="4" enabled="true" follows="left|top" @@ -241,24 +227,23 @@ height="10" layout="topleft" left="30" - name="Proxy Settings:" + name="Proxy Settings 1" + mouse_opaque="false" + top_pad="10" + width="300"> + Proxy Settings: + </text> + <text + type="string" + length="1" + follows="left|top" + height="10" + layout="topleft" + left="80" + name="Proxy Settings 2" mouse_opaque="false" top_pad="5" width="300"> - Proxy Settings: + Your system's existing proxy settings will be used </text> - <button - label="Adjust proxy settings" - follows="left|top" - height="23" - width="140" - label_selected="Browse" - layout="topleft" - left_delta="50" - name="set_proxy" - top_pad="5" - > - <button.commit_callback - function="Pref.Proxy" /> - </button> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml index 8f2e81b9f7..2ea20570b1 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml @@ -13,6 +13,14 @@ name="middle_mouse"> Middle Mouse </panel.string> + <panel.string + name="button4_mouse"> + Mouse Button 4 + </panel.string> + <panel.string + name="button5_mouse"> + Mouse Button 5 + </panel.string> <slider control_name="AudioLevelMaster" follows="left|top" @@ -314,17 +322,40 @@ name="enable_voice_check" width="110"/> <!-- --> - <check_box - name="media_auto_play_btn" - control_name="ParcelMediaAutoPlayEnable" - enabled_control="AudioStreamingMedia" - value="true" - follows="left|bottom|right" - height="15" - tool_tip="Check this to let media auto-play if it wants" - label="Allow Media to auto-play" - top_pad="1" - left="25"/> + <text + follows="left|top" + layout="topleft" + height="15" + left="0" + top_pad="3" + width="120" + halign="right" + name="media_autoplay_label"> + Media auto-play + </text> + <combo_box + control_name="ParcelMediaAutoPlayEnable" + enabled_control="AudioStreamingMedia" + follows="left|top" + layout="topleft" + height="23" + left_pad="7" + top_delta="-4" + name="media_auto_play_combo" + width="100"> + <item + label="No" + name="autoplay_disabled" + value="0"/> + <item + label="Yes" + name="autoplay_enabled" + value="1"/> + <item + label="Ask" + name="autoplay_ask" + value="2"/> + </combo_box> <check_box name="media_show_on_others_btn" control_name="MediaShowOnOthers" @@ -432,63 +463,24 @@ enabled_control="EnableVoiceChat" control_name="PushToTalkToggle" height="15" - label="Toggle speak on/off when I press:" + label="Toggle speak on/off when I press button in toolbar" layout="topleft" left="44" name="push_to_talk_toggle_check" width="237" tool_tip="When in toggle mode, press and release the trigger key ONCE to switch your microphone on or off. When not in toggle mode, the microphone broadcasts your voice only while the trigger is being held down." top_pad="3"/> - <line_editor - follows="top|left" - control_name="PushToTalkButton" - enabled="false" - enabled_control="EnableVoiceChat" - height="23" - left="80" - max_length_bytes="200" - name="modifier_combo" - label="Push-to-Speak trigger" - top_pad="3" - width="200" /> - <button - layout="topleft" - follows="top|left" - enabled_control="EnableVoiceChat" - height="23" - label="Set Key" - left_pad="5" - name="set_voice_hotkey_button" - width="100"> - <button.commit_callback - function="Pref.VoiceSetKey" /> - </button> - <button - enabled_control="EnableVoiceChat" - follows="top|left" - halign="center" - height="23" - image_overlay="Refresh_Off" - layout="topleft" - tool_tip="Reset to Middle Mouse Button" - mouse_opaque="true" - name="set_voice_middlemouse_button" - left_pad="5" - width="25"> - <button.commit_callback - function="Pref.VoiceSetMiddleMouse" /> - </button> <button control_name="ShowDeviceSettings" follows="left|top" height="23" is_toggle="true" - label="Input/Output devices" + label="Voice Input/Output devices" layout="topleft" left="20" top_pad="6" name="device_settings_btn" - width="190"> + width="230"> </button> <panel layout="topleft" diff --git a/indra/newview/skins/default/xui/en/panel_presets_camera_pulldown.xml b/indra/newview/skins/default/xui/en/panel_presets_camera_pulldown.xml new file mode 100644 index 0000000000..25d9c47449 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_presets_camera_pulldown.xml @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + background_opaque="true" + background_visible="true" + bg_opaque_image="Volume_Background" + bg_alpha_image="Volume_Background" + border_visible="false" + border="false" + chrome="true" + follows="bottom" + height="155" + layout="topleft" + name="presets_camera_pulldown" + width="225"> + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + top="4" + left_delta="5" + font.style="BOLD" + name="Camera Presets" + width="120"> + Camera Presets + </text> + <scroll_list + follows="left|top" + layout="topleft" + column_padding="0" + height="100" + width="215" + draw_heading="false" + draw_stripes="false" + bg_stripe_color="0.25 0.25 0.25 0.25" + top_delta="15" + left_delta="0" + name="preset_camera_list"> + <scroll_list.columns + name="icon" + width="16" /> + <scroll_list.columns + relative_width="1" + name="preset_name" /> + <scroll_list.commit_callback + function="PresetsCamera.RowClick" /> + </scroll_list> + <view_border + bevel_style="none" + follows="top|left" + height="0" + layout="topleft" + left="5" + name="horiz_separator" + top_delta="105" + width="215" /> + <button + name="open_prefs_btn" + label="Open Camera floater" + tool_tip = "Bring up Camera floater" + top_delta="5" + left="15" + height="20" + width="200"> + <button.commit_callback + function="Presets.toggleCameraFloater" /> + </button> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_progress.xml b/indra/newview/skins/default/xui/en/panel_progress.xml index 860caf2d21..e77d097d5f 100644 --- a/indra/newview/skins/default/xui/en/panel_progress.xml +++ b/indra/newview/skins/default/xui/en/panel_progress.xml @@ -44,68 +44,129 @@ width="670" /> <layout_panel auto_resize="false" - height="250" + height="275" layout="topleft" - min_height="250" + min_height="275" name="panel4" width="670"> <icon color="LoginProgressBoxCenterColor" follows="left|right|bottom|top" - height="250" + height="275" image_name="Rounded_Square" layout="topleft" left="0" top="0" width="670" /> - <text - follows="left|right|top" - font="SansSerifHuge" - font_shadow="none" - halign="left" - height="20" - layout="topleft" - left_delta="47" - name="title_text" - text_color="LoginProgressBoxTextColor" - top_delta="50" - right="-47"/> - <text - follows="left|right|top" - font="SansSerif" - font_shadow="none" - halign="left" - height="20" - layout="topleft" - left_delta="0" - name="progress_text" - text_color="LoginProgressBoxTextColor" - top_pad="5" - right="-47" - word_wrap="true"/> - <progress_bar - bottom="115" - color_bar="1 1 1 0.96" - follows="left|right|top" - height="16" - layout="topleft" - left="45" - name="login_progress_bar" - right="-45" /> - <text + <layout_stack follows="left|right|top|bottom" - font="SansSerifLarge" - font_shadow="none" - halign="left" - height="100" + height="275" layout="topleft" - left="45" - line_spacing.pixels="2" - name="message_text" - text_color="LoginProgressBoxTextColor" - top="145" - right="-90" - word_wrap="true"/> + left="0" + orientation="vertical" + name="vertical_centering" + animate="false" + top="0" + width="670"> + <layout_panel + auto_resize="false" + height="30" + layout="topleft" + min_height="30" + name="panel_top_spacer" + width="670"> + </layout_panel> + <layout_panel + auto_resize="false" + height="100" + layout="topleft" + min_height="100" + name="panel_login" + width="670"> + <text + follows="left|right|top" + layout="topleft" + font="SansSerifHuge" + font_shadow="none" + halign="left" + height="20" + left="47" + top="32" + right="-47" + name="title_text" + text_color="LoginProgressBoxTextColor"/> + <text + follows="left|right|top" + layout="topleft" + font="SansSerif" + font_shadow="none" + halign="left" + height="20" + top_pad="5" + right="-47" + left_delta="0" + name="progress_text" + text_color="LoginProgressBoxTextColor" + word_wrap="true"/> + <progress_bar + color_bar="0 0.67 0.9 0.96" + follows="left|right|top" + layout="topleft" + image_fill="ProgressBarSolid" + height="16" + left="45" + top_pad="5" + name="login_progress_bar" + right="-45" /> + </layout_panel> + <layout_panel + auto_resize="false" + height="110" + layout="topleft" + min_height="110" + name="panel_motd" + width="670"> + <text + follows="left|right|top|bottom" + font="SansSerifLarge" + font_shadow="none" + halign="left" + valign="center" + height="100" + layout="topleft" + left="45" + line_spacing.pixels="2" + name="message_text" + text_color="LoginProgressBoxTextColor" + top="7" + right="-90" + word_wrap="true"/> + </layout_panel> + <layout_panel + auto_resize="false" + height="40" + layout="topleft" + min_height="40" + name="panel_icons" + width="670"> + <!--Logos are tied to following label from code--> + <text + follows="left|right|top" + layout="topleft" + font="SansSerifLarge" + font_shadow="none" + halign="left" + height="16" + width="240" + left="47" + top="6" + line_spacing.pixels="2" + name="logos_lbl" + text_color="LoginProgressBoxTextColor"> + Second Life uses + </text> + </layout_panel> + </layout_stack> </layout_panel> <layout_panel height="200" diff --git a/indra/newview/skins/default/xui/en/panel_region_environment.xml b/indra/newview/skins/default/xui/en/panel_region_environment.xml index aa38c49fae..edf1e1efd4 100644 --- a/indra/newview/skins/default/xui/en/panel_region_environment.xml +++ b/indra/newview/skins/default/xui/en/panel_region_environment.xml @@ -1,149 +1,903 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <panel - border="true" - follows="top|left" - height="300" - label="Environment" - layout="topleft" - help_topic="panel_region_environment_tab" - name="panel_env_info" - width="530"> - <text - name="water_settings_title" - follows="top|left" - height="30" - layout="topleft" - left="50" - top_pad="20" - width="430" - wrap="true"> - Select the Water and Sky/Day Cycle Settings you would like all visitors to your region to see. More info - </text> - <view_border - bevel_style="none" - follows="top|left" - height="237" - layout="topleft" - left="50" - name="border" - top="60" - width="430"/> - <radio_group - follows="top|left" - height="45" - layout="topleft" - left_delta="10" - name="region_settings_radio_group" - top_delta="20" - width="200"> - <radio_item - label="Use Second Life default" - layout="topleft" - name="use_sl_default_settings"/> - <radio_item - label="Use the following settings" - layout="topleft" - name="use_my_settings" - top_pad="20"/> - </radio_group> - <panel - follows="top|left" - height="150" - layout="topleft" - left="50" - name="user_environment_settings" - top_pad="20" - width="430"> - <text - name="water_settings_title" - follows="top|left" - height="16" - layout="topleft" - left="50" - top_pad="0" - width="160"> - Water Setting - </text> - <combo_box - follows="top|left" - left_pad="2" - name="water_settings_preset_combo" - top_delta="-7" - width="200"> - <combo_box.item - label="-Select a preset-" - name="item0"/> - </combo_box> - <text - name="sky_dayc_settings_title" - follows="top|left" - height="16" - layout="topleft" - left="50" - top_pad="30" - width="100"> - Sky / Day Cycle - </text> - <radio_group - layout="topleft" - left_delta="50" - name="sky_dayc_settings_radio_group" - top_pad="10" - height="50" - width="110"> - <radio_item - layout="topleft" - label="Fixed sky" - name="my_sky_settings"/> - <radio_item - layout="topleft" - label="Day cycle" - name="my_dayc_settings" - top_pad="25"/> - </radio_group> - <combo_box - follows="top|left" - left_pad="2" - name="sky_settings_preset_combo" - top_delta="-7" - width="200"> - <combo_box.item - label="-Select a preset-" - name="item0"/> - </combo_box> - <combo_box - follows="top|left" - name="dayc_settings_preset_combo" - top_delta="36" - width="200"> - <combo_box.item - label="-Select a preset-" - name="item0"/> - </combo_box> - </panel> - <button - follows="left|top" - height="23" - label="Apply" - layout="topleft" - right="-160" - name="apply_btn" - top_pad="10" - width="100" /> - <button - follows="left|top" - height="23" - label="Cancel" - layout="topleft" - left_pad="10" - name="cancel_btn" - width="100" /> - <loading_indicator - height="23" - left="50" - name="progress_indicator" - top_delta="0" - visible="false" - width="23" /> + border="true" + follows="all" + height="375" + label="Environment" + layout="topleft" + help_topic="panel_region_environment_tab" + name="panel_env_info" + width="530"> + <string name="str_label_use_default">Use Default Settings</string> + <string name="str_label_use_region">Use Region Settings</string> + <string name="str_altitude_desription">Sky [INDEX]([ALTITUDE]m)</string> + <string name="str_no_parcel">No parcel is selected. Environmental settings are disabled.</string> + <string name="str_cross_region">Environmental settings are not available across region boundries.</string> + <string name="str_legacy">Environmental settings are not available on this region.</string> + <string name="str_disallowed">The estate manager does not allow changing parcel environments in this region.</string> + <string name="str_too_small">The parcel must be at least 128 square meters to support an environment.</string> + <string name="str_empty">(empty)</string> + <string name="str_region_env">(region environment)</string> + + <layout_stack + width="530" + height="400" + follows="all" + layout="topleft" + left="0" + animate="false" + orientation="vertical"> + <layout_panel + user_resize="false" + auto_resize="false" + height="20" + name="pnl_environment_region_msg" + top="0"> + <text follows="left|top" + font="SansSerif" + height="20" + layout="topleft" + left="10" + name="region_text_lbl" + top="6" + width="100"> + Region: + </text> + <text follows="left|top" + font="SansSerif" + height="20" + layout="topleft" + left_delta="50" + name="region_text" + top_delta="0" + width="400"> + unknown + </text> + </layout_panel> + <layout_panel + user_resize="false" + name="pnl_environment_disabled" + visible="false"> + <text follows="top|left|bottom|right" + halign="center" + valign="top" + top_pad="40" + name="txt_environment_disabled" + text_color="white"> + ... + </text> + </layout_panel> + <layout_panel + user_resize="false" + min_height="0" + top="0" + name="pnl_environment_config" + visible="true"> + <layout_stack + follows="all" + layout="topleft" + animate="false" + orientation="horizontal"> + <layout_panel + user_resize="false" + min_height="0" + top="0" + name="pnl_environment_config" + visible="true"> + <layout_stack + follows="all" + layout="topleft" + animate="false" + orientation="vertical"> + <layout_panel + min_height="140" + follows="all" + border="true" + bevel_style="in" + name="pnl_environment_current"> + <text follows="top|left" + font="SansSerif" + halign="left" + text_color="white" + left="5" + top="2">Select Environment</text> + <button + follows="top|left" + top_pad="20" + left_delta="10" + layout="topleft" + height="23" + label="[USEDEFAULT]" + width="120" + name="btn_usedefault"/> + <button + follows="top|left" + top_pad="5" + left_delta="0" + layout="topleft" + height="23" + label="Use Inventory" + width="120" + name="btn_select_inventory"/> + <button + follows="top|left" + top_pad="5" + left_delta="0" + layout="topleft" + height="23" + label="Customize" + width="120" + name="btn_edit"/> + <check_box + height="20" + label="Parcel Owners May Override Environment" + layout="topleft" + left_delta="0" + top_pad="10" + name="chk_allow_override" + width="200" /> + </layout_panel> + <layout_panel + min_height="130" + follows="all" + border="true" + bevel_style="in" + name="pnl_environment_length"> + <text + font="SansSerif" + follows="top|left|right" + halign="left" + text_color="white" + left="5" + top="2">Day Settings</text> + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="10" + top_pad="16" + width="200"> + Day Length (hours) + </text> + <slider + can_edit_text="true" + decimal_digits="1" + follows="top|left|right" + layout="topleft" + increment="0.5" + height="20" + width="237" + left="10" + top_pad="0" + right="-10" + initial_value="4" + name="sld_day_length" + min_val="4" + max_val="168" /> + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="0" + top_pad="5" + width="200"> + Day Offset (hours) + </text> + <slider + can_edit_text="true" + decimal_digits="1" + follows="top|left|right" + layout="topleft" + height="20" + width="237" + increment="0.5" + initial_value="-8" + left="10" + top_pad="0" + right="-10" + name="sld_day_offset" + min_val="-11.5" + max_val="12" /> + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="0" + top_pad="5" + width="200"> + Apparent Time of Day: + </text> + <text + name="lbl_apparent_time" + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="10" + top_pad="5" + width="200"> + [HH]:[MM][AP] ([PRC]%) + </text> + </layout_panel> + <layout_panel + follows="bottom" + border="true" + bevel_style="in" + name="pnl_environment_buttons"> +<!-- used to be buttons, but now spacer. +--> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel + user_resize="false" + min_height="0" + top="0" + name="pnl_environment_altitudes" + visible="true"> + <!-- Three movable panels first so that they will be 'below' slider--> + <panel + follows="top|left" + height="26" + width="360" + layout="topleft" + visible="true" + left="1" + top="30" + name="pnl_alt1"> + <text + type="string" + length="1" + follows="left|top" + layout="topleft" + height="24" + width="52" + left_delta="2" + top_pad="1" + halign="right" + name="txt_alt1"> + Sky [INDEX] + [ALTITUDE]m + </text> + <line_editor + follows="left|top" + enabled="false" + top_delta="3" + left_pad="21" + height="20" + layout="topleft" + name="edt_invname_alt1" + use_bg_color="true" + bg_color="TextBgReadOnlyColor" + width="155"> + Unknown + </line_editor> + <settings_drop_target + height="20" + top_delta="0" + left_delta="0" + follows="top|left" + layout="topleft" + name="sdt_alt1" + tool_tip="Drag a setting from Inventory onto this target box to select it as current sky." + width="155" /> + </panel> + <panel + follows="top|left" + height="26" + width="360" + layout="topleft" + visible="true" + left="1" + top="60" + name="pnl_alt2"> + <text + type="string" + length="1" + follows="left|top" + layout="topleft" + height="24" + width="52" + left_delta="2" + top_pad="1" + halign="right" + name="txt_alt2"> + Sky [INDEX] + [ALTITUDE]m + </text> + <line_editor + follows="left|top" + enabled="false" + top_delta="3" + left_pad="21" + height="20" + layout="topleft" + name="edt_invname_alt2" + use_bg_color="true" + bg_color="TextBgReadOnlyColor" + width="155"> + Unknown + </line_editor> + <settings_drop_target + height="20" + top_delta="0" + left_delta="0" + follows="top|left" + layout="topleft" + name="sdt_alt2" + tool_tip="Drag a setting from Inventory onto this target box to select it as current sky." + width="155" /> + </panel> + <panel + follows="top|left" + height="26" + width="360" + layout="topleft" + visible="true" + left="1" + top="90" + name="pnl_alt3"> + <text + type="string" + length="1" + follows="left|top" + layout="topleft" + height="25" + width="52" + left_delta="2" + top_pad="1" + halign="right" + name="txt_alt3"> + Sky [INDEX] + [ALTITUDE]m + </text> + <line_editor + follows="left|top" + enabled="false" + top_delta="3" + left_pad="21" + height="20" + layout="topleft" + name="edt_invname_alt3" + use_bg_color="true" + bg_color="TextBgReadOnlyColor" + width="155"> + Unknown + </line_editor> + <settings_drop_target + height="20" + top_delta="0" + left_delta="0" + follows="top|left" + layout="topleft" + name="sdt_alt3" + tool_tip="Drag a setting from Inventory onto this target box to select it as current sky." + width="155" /> + </panel> + <text follows="top|left" + font="SansSerif" + halign="left" + text_color="white" + left="5" + top="2">Sky Altitudes</text> + <!-- Divider icons also should be under slider to not interfer with clicks--> + <icon + color="LtGray" + height="2" + width="17" + image_name="Rounded_Square" + layout="topleft" + left="57" + top="89" + name="mark0"/> + <icon + color="LtGray" + height="2" + width="17" + image_name="Rounded_Square" + layout="topleft" + left_delta="0" + top_delta="69" + name="mark1"/> + <icon + color="LtGray" + height="2" + width="17" + image_name="Rounded_Square" + layout="topleft" + left_delta="0" + top_delta="69" + name="mark2"/> + <multi_slider + height="270" + follows="top|left" + orientation="vertical" + increment="25" + min_val="100" + max_val="4000" + thumb_image="Inv_SettingsSky" + thumb_width="17" + thumb_highlight_color="white" + decimal_digits="0" + draw_track="true" + overlap_threshold="100" + initial_value="0" + layout="topleft" + left="57" + max_sliders="3" + name="sld_altitudes" + show_text="false" + top="20" + use_triangle="false" + width="17"> + <slider name="sld1" + value="1000"/> + <slider name="sld2" + value="2000"/> + <slider name="sld3" + value="3000"/> + </multi_slider> + <panel + follows="top|left" + height="21" + width="360" + layout="topleft" + visible="true" + left="1" + top_pad="10" + name="pnl_ground"> + <text + type="string" + length="1" + follows="left|top" + layout="topleft" + height="12" + width="52" + left_delta="2" + top_pad="2" + halign="right" + name="txt_ground"> + Ground + </text> + <icon + follows="top|left" + height="17" + width="17" + image_name="Inv_SettingsSky" + layout="topleft" + name="icon_ground" + mouse_opaque="false" + visible="true" + top_delta="-3" + left_pad="2"/> + <line_editor + follows="left|top" + enabled="false" + top_delta="-1" + left_pad="2" + height="20" + layout="topleft" + name="edt_invname_ground" + use_bg_color="true" + bg_color="TextBgReadOnlyColor" + width="155"> + Unknown + </line_editor> + <settings_drop_target + height="20" + top_delta="0" + left_delta="0" + follows="top|left" + layout="topleft" + name="sdt_ground" + tool_tip="Drag a setting from Inventory onto this target box to select it as the ground level sky." + width="155" /> + </panel> + <panel + follows="top|left" + height="21" + width="360" + layout="topleft" + visible="true" + left="1" + top_pad="10" + name="pnl_water"> + <text + type="string" + length="1" + follows="left|top" + layout="topleft" + height="12" + width="52" + left_delta="2" + top_pad="2" + halign="right" + name="txt_water"> + Water + </text> + <icon + follows="left|top" + height="17" + width="17" + image_name="Inv_SettingsWater" + layout="topleft" + name="icon_water" + mouse_opaque="false" + visible="true" + top_delta="-3" + left_pad="2"/> + <line_editor + follows="left|top" + enabled="false" + top_delta="-1" + left_pad="2" + height="20" + layout="topleft" + name="edt_invname_water" + use_bg_color="true" + bg_color="TextBgReadOnlyColor" + width="155"> + Unknown + </line_editor> + <settings_drop_target + height="20" + top_delta="0" + left_delta="0" + follows="top|left" + layout="topleft" + name="sdt_water" + tool_tip="Drag a setting from Inventory onto this target box to select it as current water." + width="155" /> + </panel> + <button + follows="top|right" + layout="topleft" + height="23" + width="100" + label="Reset" + right="-10" + top_pad="4" + tool_tip="Reset to default altitudes" + name="btn_rst_altitudes" /> + </layout_panel> + </layout_stack> + </layout_panel> + <!-- + <layout_panel + user_resize="false" + height="155" + min_height="0" + name="pnl_environment_config" + visible="true"> + <layout_stack + left="5" + top="0" + right="-5" + bottom="-1" + layout="topleft" + follows="all" + animate="false" + orientation="horizontal"> + <layout_panel + background_visible="true" + border="true" + bevel_style="in" + user_resize="false" + width="260" + min_width="260" + name="pnl_environment_current"> + <text follows="top|left" + font="SansSerif" + halign="left" + text_color="white" + top="2">Current Environment</text> + <radio_group + height="90" + layout="topleft" + top_pad="8" + left_delta="10" + name="rdg_environment_select"> + <radio_item + label="[USEDEFAULT]" + layout="topleft" + name="rdo_use_xxx_setting" + height="20"/> + <radio_item + label="Settings From Inventory" + layout="topleft" + valign="top" + name="rdo_use_inv_setting" + height="20"/> + <radio_item + top_pad="25" + label="Custom Environment" + layout="topleft" + height="20" + name="rdo_use_custom_setting"/> + </radio_group> + <line_editor + follows="top|left" + enabled="false" + left_delta="20" + top_delta="50" + height="20" + layout="topleft" + name="edt_inventory_name" + width="200"> + Unknown + </line_editor> + <settings_drop_target + height="20" + top_pad="-20" + follows="top|left" + layout="topleft" + name="sdt_drop_target" + tool_tip="Drag a setting from Inventory onto this target box to select it as current evironment." + width="200" /> + <button + name="btn_select_inventory" + follows="top|left" + image_overlay="Command_Inventory_Icon" + layout="topleft" + height="20" + width="20" + left_delta="205" + top_delta="0"/> + <button + follows="top|left" + top_pad="25" + left_delta="-205" + layout="topleft" + height="23" + label="Edit Environment" + width="120" + name="btn_edit"/> + + </layout_panel> + <layout_panel + border="true" + bevel_style="in" + user_resize="false" + width="260" + min_width="260" + background_visible="true" + name="pnl_environment_length"> + <text + font="SansSerif" + follows="top|left|right" + halign="left" + text_color="white" + top="2">Day Settings</text> + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="10" + top_pad="14" + width="200"> + Day Length (hours) + </text> + <slider + can_edit_text="true" + decimal_digits="1" + follows="left|top" + height="20" + increment="0.5" + initial_value="4" + layout="topleft" + left_delta="0" + top_pad="6" + name="sld_day_length" + min_val="4" + max_val="168" + width="180" /> + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="0" + top_pad="10" + width="200"> + Day Offset (hours) + </text> + <slider + can_edit_text="true" + decimal_digits="1" + follows="left|top" + height="20" + increment="0.5" + initial_value="-8" + layout="topleft" + left_delta="0" + top_pad="6" + name="sld_day_offset" + min_val="-12" + max_val="12" + width="180" /> + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="0" + top_pad="10" + width="200"> + Apparent Time of Day: + </text> + <text + name="lbl_apparent_time" + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="10" + top_pad="5" + width="200"> + [HH]:[MM][AP] ([PRC]%) + </text> + + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel + user_resize="false" + height="155" + min_height="0" + name="pnl_environment_altitudes" + visible="true"> + <panel + left="5" + top="0" + bottom="-1" + width="260" + follows="left|top|bottom" + background_visible="true" + border="true" + bevel_style="in" + name="cnt_panel"> + <text follows="top|left" + font="SansSerif" + halign="left" + text_color="white" + top="2">Sky Altitudes</text> + <multi_slider + decimal_digits="0" + follows="bottom" + height="123" + width="17" + orientation="vertical" + increment="10" + overlap_threshold="100" + min_val="100" + max_val="4000" + layout="topleft" + left="15" + top="20" + max_sliders="20" + name="sld_altitudes" + show_text="false" + thumb_image="Inv_SettingsSky" + thumb_width="17" + thumb_highlight_color="white"> + <slider name="sld1" + value="200"/> + <slider name="sld2" + value="400"/> + <slider name="sld3" + value="600"/> + </multi_slider> + <icon + follows="left|top" + height="17" + width="17" + image_name="Inv_SettingsSky" + layout="topleft" + name="icon_ground" + mouse_opaque="false" + visible="true" + left_delta="0" + top_pad="-9"/> + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_pad="3" + top_delta="2" + width="200" + name="ground"> + Ground + </text> + <text + type="string" + length="1" + follows="left" + height="12" + layout="topleft" + left="35" + top="30" + width="200" + name="alt1"> + Sky [INDEX]([ALTITUDE]m) + </text> + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left="35" + top="40" + width="200" + name="alt2"> + Sky [INDEX]([ALTITUDE]m) + </text> + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left="35" + top="50" + width="200" + name="alt3"> + Sky [INDEX]([ALTITUDE]m) + </text> + </panel> + </layout_panel> + <layout_panel + user_resize="false" + height="0" + min_height="0" + name="pnl_auto_adjust" + visible="true"/> + <layout_panel + user_resize="false" + height="59" + min_height="59" + name="pnl_environment_buttons"> + <check_box + height="20" + label="Parcel Owners May Override Environment" + layout="topleft" + left="10" + top="0" + name="chk_allow_override" + width="200" /> + <button + follows="top|left" + height="23" + label="Apply" + top_pad="5" + name="btn_apply" + width="100" /> + <button + follows="top|left" + height="23" + label="Reset" + layout="topleft" + left_pad="10" + top_delta="0" + name="btn_cancel" + width="100" /> + + </layout_panel> +--> + </layout_stack> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_script_ed.xml b/indra/newview/skins/default/xui/en/panel_script_ed.xml index ed37e9e2cc..545c01935b 100644 --- a/indra/newview/skins/default/xui/en/panel_script_ed.xml +++ b/indra/newview/skins/default/xui/en/panel_script_ed.xml @@ -145,10 +145,6 @@ name="Help" width="112"> <menu_item_call - label="Help..." - layout="topleft" - name="Help..." /> - <menu_item_call label="Keyword Help..." layout="topleft" name="Keyword Help..." /> diff --git a/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml b/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml new file mode 100644 index 0000000000..6f82a0efa1 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml @@ -0,0 +1,322 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + border="true" + follows="all" + label="Atmosphere & Lighting" + layout="topleft" + left="0" + name="panel_settings_sky_atmos" + top="0"> + <layout_stack + follows="all" + layout="topleft" + left="5" + top="5" + right="-5" + bottom="-5" + orientation="vertical"> + <layout_panel + border="true" + bevel_style="in" + auto_resize="false" + user_resize="false" + visible="true" + height="75"> + + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="15" + top_pad="15" + width="80"> + Ambient Color: + </text> + <color_swatch + can_apply_immediately="true" + follows="left|top" + height="37" + label_height="0" + layout="topleft" + left_delta="0" + name="ambient_light" + top_pad="5" + width="60" /> + <text + follows="left" + height="10" + layout="topleft" + left_delta="90" + top_delta="-15" + width="80"> + Blue Horizon: + </text> + <color_swatch + can_apply_immediately="true" + follows="left|top" + height="37" + label_height="0" + layout="topleft" + left_delta="0" + name="blue_horizon" + top_pad="5" + width="60" /> + <text + follows="left" + height="10" + layout="topleft" + left_delta="90" + top_delta="-15" + width="80"> + Blue Density: + </text> + <color_swatch + can_apply_immediately="true" + follows="left|top" + height="37" + label_height="0" + layout="topleft" + left_delta="0" + name="blue_density" + top_pad="5" + width="60" /> + </layout_panel> + <layout_panel + border="true" + bevel_style="in" + auto_resize="true" + user_resize="false" + visible="true"> + <layout_stack name="atmosphere1" + left="5" + top="5" + right="-5" + bottom="-5" + follows="left|top|right|bottom" + orientation="hoizontal"> + <layout_panel + border="false" + bevel_style="in" + auto_resize="true" + user_resize="false" + visible="true" + min_width="225"> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="15" + top_pad="15" + width="80"> + Haze Horizon: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="5" + name="haze_horizon" + top_delta="20" + width="207" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="25" + width="80"> + Haze Density: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="5" + name="haze_density" + top_delta="20" + width="207" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="25" + width="80"> + Moisture Level: + </text> + <slider + decimal_digits="3" + follows="left|top" + height="14" + increment="0.001" + initial_value="0" + left_delta="5" + top_delta="20" + layout="topleft" + min_val="0" + max_val="1" + name="moisture_level" + width="207" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="25" + width="80"> + Droplet Radius: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="14" + increment="0.01" + initial_value="0" + left_delta="5" + top_delta="20" + layout="topleft" + min_val="5.0" + max_val="1000.0" + name="droplet_radius" + width="207" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="25" + width="80"> + Ice Level: + </text> + <slider + decimal_digits="3" + follows="left|top" + height="14" + increment="0.001" + initial_value="0" + left_delta="5" + top_delta="20" + layout="topleft" + min_val="0" + max_val="1" + name="ice_level" + width="207" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="25" + width="80"> + Scene Gamma: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + max_val="20" + name="scene_gamma" + top_delta="20" + width="207" + can_edit_text="true"/> + </layout_panel> + <layout_panel + border="false" + bevel_style="in" + auto_resize="true" + user_resize="false" + visible="true" + min_width="225"> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="15" + top_pad="15" + width="200"> + Density Multiplier: + </text> + <slider + decimal_digits="4" + follows="left|top" + height="16" + increment="0.0001" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0.0001" + max_val="2" + name="density_multip" + top_delta="20" + width="219" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="25" + width="200"> + Distance Multiplier: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0.8" + layout="topleft" + left_delta="5" + min_val="0.05" + max_val="1000" + name="distance_multip" + top_delta="20" + width="219" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="25" + width="200"> + Maximum Altitude: + </text> + <slider + decimal_digits="1" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="10000" + name="max_alt" + top_delta="20" + width="219" + can_edit_text="true"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_settings_sky_clouds.xml b/indra/newview/skins/default/xui/en/panel_settings_sky_clouds.xml new file mode 100644 index 0000000000..ac3b45d24c --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_settings_sky_clouds.xml @@ -0,0 +1,271 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + border="true" + follows="all" + label="Clouds" + layout="topleft" + left="0" + help_topic="land_general_tab" + name="panel_settings_sky_clouds" + top="0"> + <layout_stack + follows="all" + layout="topleft" + left="5" + top="5" + right="-5" + bottom="-5" + orientation="hoizontal"> + <layout_panel + border="true" + bevel_style="in" + auto_resize="true" + user_resize="false" + visible="true" + height="75"> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="15" + top_pad="15" + width="80"> + Cloud Color: + </text> + <color_swatch + can_apply_immediately="true" + follows="left|top" + height="37" + label_height="0" + layout="topleft" + left_delta="0" + name="cloud_color" + top_pad="5" + width="60" /> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="0" + top_delta="47" + width="200"> + Cloud Coverage: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="1" + name="cloud_coverage" + top_delta="20" + width="214" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="25" + width="200"> + Cloud Scale: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0.01" + max_val="3" + name="cloud_scale" + top_delta="20" + width="214" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="25" + width="200"> + Cloud Variance: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="1.0" + name="cloud_variance" + top_delta="20" + width="214" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="25" + width="200"> + Cloud Scroll: + </text> + <xy_vector + follows="left|top" + name="cloud_scroll_xy" + width="127" + height="145" + visible="true" + left_delta="0" + top_delta="21" + min_val_x="-30" + max_val_x="30" + min_val_y="-30" + max_val_y="30" + logarithmic="1"/> + + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="160" + top_delta="-20" + width="200"> + Cloud Image: + </text> + <texture_picker + height="123" + layout="topleft" + left_delta="5" + name="cloud_map" + top_pad="10" + width="100"/> + </layout_panel> + <layout_panel + border="true" + bevel_style="in" + auto_resize="true" + user_resize="false" + visible="true" + height="75"> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="15" + top_pad="15" + width="200"> + Cloud Density: + </text> + <slider + label="X" + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="1" + name="cloud_density_x" + top_delta="20" + width="200" + can_edit_text="true"/> + <slider + label="Y" + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="0" + min_val="0" + max_val="1" + name="cloud_density_y" + top_delta="20" + width="200" + can_edit_text="true"/> + <slider + label="D" + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="0" + min_val="0" + max_val="3" + name="cloud_density_d" + top_delta="20" + width="200" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="35" + width="200"> + Cloud Detail: + </text> + <slider + label="X" + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="1" + name="cloud_detail_x" + top_delta="20" + width="200" + can_edit_text="true"/> + <slider + label="Y" + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="0" + min_val="0" + max_val="1" + name="cloud_detail_y" + top_delta="20" + width="200" + can_edit_text="true"/> + <slider + label="D" + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="0" + min_val="0" + max_val="1" + name="cloud_detail_d" + top_delta="20" + width="200" + can_edit_text="true"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_settings_sky_density.xml b/indra/newview/skins/default/xui/en/panel_settings_sky_density.xml new file mode 100644 index 0000000000..b3a33961bc --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_settings_sky_density.xml @@ -0,0 +1,273 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + border="true" + follows="all" + label="Density" + layout="topleft" + left="0" + help_topic="sky_density" + name="panel_settings_sky_density" + top="0"> + <layout_stack + follows="all" + layout="topleft" + left="5" + top="5" + right="-5" + bottom="-5" + orientation="vertical"> + <layout_panel + border="true" + bevel_style="in" + auto_resize="true" + user_resize="false" + visible="true" + height="12"> + <slider + decimal_digits="6" + follows="left|top" + height="14" + increment="0.0000001" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="1" + name="rayleigh_exponential" + label="Rayleigh Exponential Term:" + top_pad="12" + width="400" + label_width="160" + can_edit_text="true"/> + <slider + decimal_digits="6" + follows="left|top" + height="14" + increment="0.000001" + initial_value="0" + layout="topleft" + min_val="-0.01" + max_val="0.01" + name="rayleigh_exponential_scale" + label="Rayleigh Exponential Scale:" + width="400" + label_width="160" + can_edit_text="true"/> + <slider + decimal_digits="6" + follows="left|top" + height="14" + increment="0.000001" + initial_value="0" + layout="topleft" + min_val="0" + max_val="0.00001" + name="rayleigh_linear" + label="Rayleigh Linear Term:" + width="400" + label_width="160" + can_edit_text="true"/> + <slider + decimal_digits="6" + follows="left|top" + height="14" + increment="0.0000001" + initial_value="0" + layout="topleft" + min_val="0" + max_val="1" + name="rayleigh_constant" + label="Rayleigh Constant Term:" + width="400" + label_width="160" + can_edit_text="true"/> + <slider + decimal_digits="1" + follows="left|top" + height="14" + initial_value="0" + layout="topleft" + min_val="1000" + max_val="40000" + name="rayleigh_max_altitude" + label="Rayleigh Max Altitude:" + width="400" + label_width="160" + can_edit_text="true"/> + </layout_panel> + <layout_panel + border="true" + bevel_style="in" + auto_resize="true" + user_resize="false" + visible="true" + height="14"> + <slider + decimal_digits="6" + follows="left|top" + height="14" + increment="0.0000001" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="3.0" + name="mie_exponential" + label="Mie Exponential Term:" + top_pad="12" + width="400" + label_width="160" + can_edit_text="true"/> + <slider + decimal_digits="6" + follows="left|top" + height="14" + increment="0.0000001" + initial_value="0" + layout="topleft" + min_val="-0.01" + max_val="0.01" + name="mie_exponential_scale" + label="Mie Exponential Scale:" + width="400" + label_width="160" + can_edit_text="true"/> + <slider + decimal_digits="6" + follows="left|top" + height="14" + increment="0.000001" + initial_value="0" + layout="topleft" + min_val="0" + max_val="0.000004" + name="mie_linear" + label="Mie Linear Term:" + width="400" + label_width="160" + can_edit_text="true"/> + <slider + decimal_digits="6" + follows="left|top" + height="14" + increment="0.0000001" + initial_value="0" + layout="topleft" + min_val="0" + max_val="1" + name="mie_constant" + label="Mie Constant Term:" + width="400" + label_width="160" + can_edit_text="true"/> + <slider + decimal_digits="2" + follows="left|top" + height="14" + increment="0.01" + initial_value="0" + layout="topleft" + min_val="0.2" + max_val="1.8" + name="mie_aniso_factor" + label="Mie Aniso Factor:" + width="400" + label_width="160" + can_edit_text="true"/> + <slider + decimal_digits="1" + follows="left|top" + height="14" + increment="0.1" + initial_value="0" + layout="topleft" + min_val="1000" + max_val="30000" + name="mie_max_altitude" + label="Mie Max Altitude:" + width="400" + label_width="160" + can_edit_text="true"/> + </layout_panel> + <layout_panel + border="true" + bevel_style="in" + auto_resize="true" + user_resize="false" + visible="true" + height="12"> + <slider + decimal_digits="6" + follows="left|top" + height="14" + increment="0.0000001" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="1" + name="absorption_exponential" + label="Absorption Exponential Term:" + top_pad="8" + width="400" + label_width="160" + can_edit_text="true"/> + <slider + decimal_digits="6" + follows="left|top" + height="14" + increment="0.0000001" + initial_value="0" + layout="topleft" + min_val="-1" + max_val="1" + name="absorption_exponential_scale" + label="Absorption Exponential Scale:" + width="400" + label_width="160" + can_edit_text="true"/> + <slider + decimal_digits="6" + follows="left|top" + height="14" + increment="0.0000001" + initial_value="0" + layout="topleft" + min_val="0" + max_val="1" + name="absorption_linear" + label="Absorption Linear Term:" + width="400" + label_width="160" + can_edit_text="true"/> + <slider + decimal_digits="6" + follows="left|top" + height="14" + increment="0.0000001" + initial_value="0" + layout="topleft" + min_val="0" + max_val="1" + name="absorption_constant" + label="Absorption Constant Term:" + width="400" + label_width="160" + can_edit_text="true"/> + <slider + decimal_digits="1" + follows="left|top" + height="14" + increment="0.1" + initial_value="0" + layout="topleft" + min_val="1000" + max_val="25000" + name="absorption_max_altitude" + label="Absorption Max Altitude:" + width="400" + label_width="160" + can_edit_text="true"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_settings_sky_sunmoon.xml b/indra/newview/skins/default/xui/en/panel_settings_sky_sunmoon.xml new file mode 100644 index 0000000000..1ad78dbb13 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_settings_sky_sunmoon.xml @@ -0,0 +1,411 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + border="true" + follows="all" + label="Sun & Moon" + layout="topleft" + left="0" + name="panel_settings_sky_hbodies" + top="0"> + <layout_stack + follows="all" + layout="topleft" + left="5" + top="5" + right="-5" + bottom="-5" + orientation="horizontal"> + <layout_panel + border="true" + bevel_style="in" + auto_resize="true" + user_resize="false" + visible="true" + name="sun_layout" + height="400"> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="15" + top_pad="15" + font="SansSerifBold" + width="120"> + Sun & Stars + </text> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="10" + top_delta="25" + width="100"> + Position: + </text> + <sun_moon_trackball + name="sun_rotation" + follows="left|top" + left_delta="0" + top_delta="20" + height="150" + width="150" + thumb_mode="sun" /> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="160" + top_delta="-20" + width="200"> + Image: + </text> + <texture_picker + height="123" + layout="topleft" + left_delta="5" + name="sun_image" + top_pad="10" + width="100"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="110" + width="80"> + Scale: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0.25" + max_val="20" + name="sun_scale" + top_delta="15" + width="130" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="65" + top_delta="20" + width="80"> + Color: + </text> + <color_swatch + can_apply_immediately="true" + follows="left|top" + height="37" + label_height="0" + layout="topleft" + left_delta="5" + name="sun_moon_color" + top_pad="5" + width="60" /> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-235" + top_delta="-3" + width="200"> + Azimuth: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="359.99" + name="sun_azimuth" + top_delta="13" + width="215" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="22" + width="200"> + Elevation: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="-90" + max_val="90" + name="sun_elevation" + top_delta="13" + width="215" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="22" + width="200"> + Glow Focus: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="-2" + max_val="2" + name="glow_focus" + top_delta="13" + width="215" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="22" + width="200"> + Glow Size: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="1.99" + name="glow_size" + top_delta="13" + width="215" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="22" + width="200"> + Star Brightness: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="500" + name="star_brightness" + top_delta="13" + width="215" + can_edit_text="true"/> + + <check_box + control_name="sunbeacon" + follows="left|top" + layout="topleft" + width="60" + height="16" + label="Show Beacon" + name="sunbeacon" + top_pad="5" + left_delta="-8"/> + + </layout_panel> + <layout_panel + border="false" + bevel_style="in" + auto_resize="true" + user_resize="false" + visible="true" + height="400"> + <layout_stack + left="5" + top="5" + right="-5" + bottom="-5" + follows="left|top|right|bottom" + orientation="vertical"> + <layout_panel + border="true" + bevel_style="in" + auto_resize="true" + user_resize="false" + visible="true" + name="moon_layout" + height="220"> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="15" + top_pad="15" + font="SansSerifBold" + width="80"> + Moon + </text> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="10" + top_delta="25" + width="100"> + Position: + </text> + <sun_moon_trackball + name="moon_rotation" + follows="left|top" + left_delta="0" + top_delta="20" + height="150" + width="150" + thumb_mode="moon" /> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="160" + top_delta="-20" + width="200"> + Image: + </text> + <texture_picker + height="123" + layout="topleft" + left_delta="5" + name="moon_image" + top_pad="10" + width="100"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="110" + width="80"> + Scale: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0.25" + max_val="20" + name="moon_scale" + top_delta="15" + width="130" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-170" + top_delta="32" + width="200"> + Azimuth: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="359.99" + name="moon_azimuth" + top_delta="13" + width="215" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="22" + width="200"> + Elevation: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="-90" + max_val="90" + name="moon_elevation" + top_delta="13" + width="215" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="22" + width="200"> + Brightness: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0.0" + max_val="1.0" + name="moon_brightness" + top_delta="13" + width="215" + can_edit_text="true"/> + <check_box + control_name="moonbeacon" + follows="left|top" + layout="topleft" + width="60" + height="16" + label="Show Beacon" + name="moonbeacon" + top_pad="5" + left_delta="-8"/> + + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_settings_water.xml b/indra/newview/skins/default/xui/en/panel_settings_water.xml new file mode 100644 index 0000000000..991ce25bec --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_settings_water.xml @@ -0,0 +1,374 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + border="true" + follows="all" + label="Water" + layout="topleft" + left="0" + help_topic="land_general_tab" + name="panel_settings_water" + top="0"> + <layout_stack name="water_stack1" + follows="all" + layout="topleft" + left="5" + top="5" + right="-5" + bottom="-5" + orientation="vertical"> + <layout_panel + border="true" + bevel_style="in" + auto_resize="false" + user_resize="false" + visible="true" + height="105"> + <text + follows="left|top" + height="20" + font="SansSerif" + layout="topleft" + left="5" + top="5" + width="215"> + Water Fog: + </text> + <text + follows="left|top" + height="10" + layout="left|top" + left_delta="15" + top_delta="0" + width="60"> + Color: + </text> + <color_swatch + can_apply_immediately="true" + follows="left|top" + height="37" + label_height="0" + layout="topleft" + left_delta="0" + name="water_fog_color" + top_pad="5" + width="60" /> + <text + follows="left|top" + height="10" + top_delta="-15" + left_delta="80" + width="150"> + Density Exponent: + </text> + <slider + decimal_digits="1" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="top" + left_delta="15" + min_val="-10" + max_val="10" + name="water_fog_density" + top_delta="5" + width="150" + can_edit_text="true"/> + <text + follows="left|top" + height="10" + top_delta="25" + left_delta="-15" + width="150"> + Underwater Modifier:</text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="top" + left_delta="15" + min_val="0.0" + max_val="20.0" + name="water_underwater_mod" + top_delta="20" + width="150" + can_edit_text="true"/> + + <text + follows="left|top|right" + height="10" + layout="topleft" + left_delta="165" + top_delta="-53" + width="150"> + Fresnel Scale: + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0.7" + layout="topleft" + left_delta="5" + name="water_fresnel_scale" + top_delta="15" + width="150" + can_edit_text="true"/> + <text + follows="left|top|right" + layout="topleft" + left_delta="-5" + name="FresnelOffsetText" + top_delta="25" + width="150"> + Fresnel Offset: + </text> + <slider + decimal_digits="2" + follows="left|top" + increment="0.01" + initial_value="0.7" + height="16" + layout="topleft" + left_delta="5" + name="water_fresnel_offset" + top_pad="5" + width="150" + can_edit_text="true"/> + + </layout_panel> + <layout_panel + auto_resize="true" + user_resize="false" + visible="true"> + <layout_stack name="water_stack2" + left="5" + top="5" + right="-5" + bottom="-5" + follows="left|top|right|bottom" + orientation="horizontal"> + <layout_panel + border="true" + bevel_style="in" + auto_resize="true" + user_resize="false" + visible="true" + min_width="460" + width="50"> + <text + follows="left|top|right" + height="16" + layout="topleft" + left="15" + top="5" + width="215"> + Normal Map + </text> + <texture_picker + height="84" + layout="topleft" + left_delta="0" + name="water_normal_map" + top_pad="5" + width="61"/> + + <text + follows="left|top" + height="16" + width="120" + layout="topleft" + top_delta="-20" + left_delta="175"> + Large Wave Speed + </text> + <xy_vector + follows="top|left" + name="water_wave1_xy" + width="120" + height="145" + visible="true" + left_delta="0" + top_delta="21" + min_val_x="-20" + max_val_x="20" + increment_x="0.01f" + min_val_y="-20" + max_val_y="20" + increment_y="0.01f" + arrow_color="white"/> + + <text + follows="left|top" + height="16" + layout="topleft" + top_delta="-20" + left_delta="140"> + Small Wave Speed + </text> + <xy_vector + follows="top|left" + name="water_wave2_xy" + width="120" + height="145" + visible="true" + left_delta="0" + top_delta="21" + min_val_x="-20" + max_val_x="20" + min_val_y="-20" + max_val_y="20" + increment_x="0.01f" + increment_y="0.01f" + arrow_color="white"/> + + <text + follows="left|top|right" + height="16" + layout="topleft" + left="10" + top="90" + width="215"> + Reflection Wavelet Scale + </text> + <slider + decimal_digits="1" + follows="left|top" + increment="0.01" + height="16" + initial_value="0.7" + layout="topleft" + label="X:" + left_delta="10" + max_val="10" + name="water_normal_scale_x" + top_pad="5" + width="150" + can_edit_text="true"/> + <slider + decimal_digits="1" + follows="left|top" + increment="0.01" + initial_value="0.7" + height="16" + layout="topleft" + max_val="10" + name="water_normal_scale_y" + top_pad="6" + label="Y:" + width="150" + can_edit_text="true"/> + <slider + decimal_digits="1" + follows="left|top" + increment="0.01" + initial_value="0.7" + height="16" + layout="topleft" + max_val="10" + name="water_normal_scale_z" + top_pad="6" + label="Z:" + width="150" + can_edit_text="true"/> + + </layout_panel> + <layout_panel + border="true" + bevel_style="in" + auto_resize="true" + user_resize="false" + width="50" + visible="true"> + <text + follows="left|top" + height="20" + font="SansSerif" + layout="topleft" + left="5" + top="5" + width="215"> + Refraction And Blur: + </text> + <text + follows="left|top|right" + height="16" + layout="topleft" + top_delta="25" + left_delta="5" + width="215"> + Refraction Scale (Above) + </text> + <slider + control_name="water_scale_above" + decimal_digits="2" + follows="left|top" + increment="0.01" + initial_value="0.1" + height="16" + layout="topleft" + left_delta="5" + min_val="0" + max_val="3" + name="water_scale_above" + top_pad="5" + width="200" + can_edit_text="true" /> + <text + type="string" + length="1" + follows="left|top|right" + height="16" + layout="topleft" + left_delta="-5" + top_pad="5" + width="215"> + Refraction Scale (Below) + </text> + <slider + control_name="water_scale_below" + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="3" + name="water_scale_below" + top_pad="5" + width="200" + can_edit_text="true"/> + <text + follows="left|top|right" + font="SansSerif" + height="16" + layout="topleft" + left_delta="-5" + top_pad="5" + width="215"> + Blur Multiplier + </text> + <slider + control_name="water_blur_multip" + follows="left|top" + height="16" + increment="0.001" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="-0.5" + max_val="0.5" + name="water_blur_multip" + top_pad="5" + width="200" + can_edit_text="true"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/en/panel_snapshot_inventory.xml index d019a0a310..8cc27d9eef 100644 --- a/indra/newview/skins/default/xui/en/panel_snapshot_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_snapshot_inventory.xml @@ -118,7 +118,7 @@ width="200" type="string" word_wrap="true"> - Saving an image to your inventory costs L$[UPLOAD_COST]. To save your image as a texture select one of the square formats. + To save your image as a texture select one of the square formats. </text> <button follows="right|bottom" diff --git a/indra/newview/skins/default/xui/en/panel_snapshot_options.xml b/indra/newview/skins/default/xui/en/panel_snapshot_options.xml index 981b9ab881..8fc5cd7e63 100644 --- a/indra/newview/skins/default/xui/en/panel_snapshot_options.xml +++ b/indra/newview/skins/default/xui/en/panel_snapshot_options.xml @@ -61,40 +61,6 @@ font="SansSerif" halign="left" height="22" - image_overlay="Command_Twitter_Icon" - image_overlay_alignment="left" - image_top_pad="0" - imgoverlay_label_space="10" - label="Share to Twitter" - layout="topleft" - left_delta="0" - name="send_to_twitter_btn" - top_pad="5"> - <button.commit_callback - function="Snapshot.SendToTwitter"/> - </button> - <button - follows="left|top" - font="SansSerif" - halign="left" - height="22" - image_overlay="Command_Flickr_Icon" - image_overlay_alignment="left" - image_top_pad="0" - imgoverlay_label_space="10" - label="Share to Flickr" - layout="topleft" - left_delta="0" - name="send_to_flickr_btn" - top_pad="5"> - <button.commit_callback - function="Snapshot.SendToFlickr"/> - </button> - <button - follows="left|top" - font="SansSerif" - halign="left" - height="22" image_overlay="Snapshot_Email" image_overlay_alignment="left" image_top_pad="0" @@ -107,4 +73,18 @@ <button.commit_callback function="Snapshot.SaveToEmail" /> </button> + <text + follows="top|left" + font="SansSerif" + height="56" + layout="topleft" + left="10" + length="1" + name="fee_hint_lbl" + top_pad="7" + width="200" + type="string" + word_wrap="true"> + Fee is based on your subscription level. Higher levels are charged lower fees. + </text> </panel>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml index 52bcce01f7..9023d68ea9 100644 --- a/indra/newview/skins/default/xui/en/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml @@ -35,7 +35,7 @@ </panel.string> <panel height="18" - left="-458" + left="-398" top="0" width="120" follows="right|top" @@ -75,7 +75,7 @@ </panel> <panel height="18" - left="-416" + left="-398" width="185" top="1" follows="right|top" @@ -142,17 +142,25 @@ left_pad="0" name="TimeText" tool_tip="Current time (Pacific)" - width="145"> + width="85"> 24:00 AM PST </text> <icon follows="right|top" height="16" - image_name="Presets_Icon" + image_name="Cam_FreeCam_Off" left_pad="8" top="2" - name="presets_icon" + name="presets_icon_camera" width="18" /> + <icon + follows="right|top" + height="13" + image_name="Presets_Icon" + left_pad="8" + top="4" + name="presets_icon_graphic" + width="16" /> <button follows="right|top" height="16" diff --git a/indra/newview/skins/default/xui/en/panel_teleport_history.xml b/indra/newview/skins/default/xui/en/panel_teleport_history.xml index 768efc2f3f..55c47c90a4 100644 --- a/indra/newview/skins/default/xui/en/panel_teleport_history.xml +++ b/indra/newview/skins/default/xui/en/panel_teleport_history.xml @@ -6,7 +6,7 @@ bg_alpha_color="DkGray"> <accordion follows="left|top|right|bottom" - height="373" + height="400" layout="topleft" left="3" top="0" @@ -147,37 +147,4 @@ </flat_list_view> </accordion_tab> </accordion> - <panel - background_visible="true" - bevel_style="none" - bottom="0" - follows="left|right|bottom" - height="27" - layout="bottomleft" - left="3" - name="bottom_panel" - width="313"> - <menu_button - follows="bottom|left" - tool_tip="Show additional options" - height="25" - image_hover_unselected="Toolbar_Left_Over" - image_overlay="OptionsMenu_Off" - image_selected="Toolbar_Left_Selected" - image_unselected="Toolbar_Left_Off" - layout="topleft" - left="0" - name="gear_btn" - top="1" - width="31" /> - <icon - follows="bottom|left|right" - height="25" - image_name="Toolbar_Right_Off" - layout="topleft" - left_pad="1" - name="dummy_icon" - width="273" - /> - </panel> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_twitter_account.xml b/indra/newview/skins/default/xui/en/panel_twitter_account.xml deleted file mode 100644 index b9049a0bba..0000000000 --- a/indra/newview/skins/default/xui/en/panel_twitter_account.xml +++ /dev/null @@ -1,81 +0,0 @@ -<panel - height="400" - width="272" - layout="topleft" - name="panel_twitter_account"> - <string - name="twitter_connected" - value="You are connected to Twitter as:" /> - <string - name="twitter_disconnected" - value="Not connected to Twitter" /> - <text - layout="topleft" - length="1" - follows="top|left" - font="SansSerif" - height="16" - left="10" - name="account_caption_label" - top="5" - type="string"> - Not connected to Twitter. - </text> - <text - layout="topleft" - top_pad="2" - length="1" - follows="top|left" - font="SansSerif" - height="16" - left="10" - name="account_name_label" - parse_urls="true" - type="string"/> - <panel - layout="topleft" - follows="top|left" - name="panel_buttons" - height="345" - top_pad="3" - left="0"> - <button - layout="topleft" - follows="left|top|right" - top_pad="9" - left="10" - right="-10" - visible="true" - height="23" - label="Connect..." - name="connect_btn" - width="210"> - <commit_callback function="SocialSharing.Connect"/> - </button> - - <button - layout="topleft" - follows="left|top|right" - top_delta="0" - left="10" - right="-10" - height="23" - label="Disconnect" - name="disconnect_btn" - width="210" - visible="false"> - <commit_callback function="SocialSharing.Disconnect"/> - </button> - <text - layout="topleft" - length="1" - follows="top|left" - height="16" - left="10" - name="account_learn_more_label" - top_pad="5" - type="string"> - [http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Share-Twitter/ta-p/2435453 Learn about posting to Twitter] - </text> - </panel> -</panel> diff --git a/indra/newview/skins/default/xui/en/panel_twitter_photo.xml b/indra/newview/skins/default/xui/en/panel_twitter_photo.xml deleted file mode 100644 index 8774d09a03..0000000000 --- a/indra/newview/skins/default/xui/en/panel_twitter_photo.xml +++ /dev/null @@ -1,196 +0,0 @@ - <panel - height="420" - width="304" - layout="topleft" - name="panel_twitter_photo"> - <text - length="1" - layout="topleft" - follows="top|left|right" - font="SansSerif" - height="16" - left="10" - name="status_label" - top="5" - type="string"> - What's happening? - </text> - <text - length="1" - follows="top|left" - layout="topleft" - font="SansSerif" - text_color="EmphasisColor" - halign="right" - height="16" - width="30" - left="227" - name="status_counter_label" - top="5" - type="string"> - 140 - </text> - <text_editor - follows="left|top" - layout="topleft" - height="87" - width="250" - left="10" - length="1" - max_length="140" - name="photo_status" - spellcheck="true" - type="string" - word_wrap="true"> - </text_editor> - <check_box - follows="left|top" - layout="topleft" - initial_value="true" - label="Include SL location" - name="add_location_cb" - left="10" - height="16" - top_pad="8"/> - <check_box - follows="left|top" - layout="topleft" - initial_value="true" - label="Include a photo" - name="add_photo_cb" - left="10" - height="16" - top_pad="1"/> - <combo_box - control_name="TwitterPhotoResolution" - follows="left|top" - layout="topleft" - top_pad="5" - left="10" - name="resolution_combobox" - tool_tip="Image resolution" - height="21" - width="124"> - <combo_box.item - label="Current Window" - name="CurrentWindow" - value="[i0,i0]" /> - <combo_box.item - label="640x480" - name="640x480" - value="[i640,i480]" /> - <combo_box.item - label="800x600" - name="800x600" - value="[i800,i600]" /> - <combo_box.item - label="1024x768" - name="1024x768" - value="[i1024,i768]" /> - </combo_box> - <combo_box - control_name="TwitterPhotoFilters" - follows="right|top" - layout="topleft" - name="filters_combobox" - tool_tip="Image filters" - top_delta="0" - right="-10" - height="21" - width="124"> - <combo_box.item - label="No Filter" - name="NoFilter" - value="NoFilter" /> - </combo_box> - <panel - layout="topleft" - height="150" - width="250" - visible="true" - name="thumbnail_placeholder" - top_pad="5" - right="-10" - follows="left|top|right" - left="10"> - </panel> - <text - follows="left|top" - layout="topleft" - font="SansSerif" - text_color="EmphasisColor" - height="14" - top_pad="2" - left="10" - length="1" - halign="center" - name="working_lbl" - translate="false" - type="string" - visible="true" - width="251"> - Refreshing... - </text> - <view_border - bevel_style="in" - follows="left|top" - layout="topleft" - height="1" - left="10" - name="refresh_border" - width="250" - top_pad="0"/> - <button - follows="left|top" - layout="topleft" - height="23" - label="Refresh" - left="10" - top_pad="5" - name="new_snapshot_btn" - tool_tip="Click to refresh" - visible="true" - width="100" > - <button.commit_callback - function="SocialSharing.RefreshPhoto" /> - </button> - <button - follows="right|top" - layout="topleft" - height="23" - label="Preview" - right="-10" - top_delta="0" - name="big_preview_btn" - tool_tip="Click to toggle preview" - is_toggle="true" - visible="true" - width="100" > - <button.commit_callback - function="SocialSharing.BigPreview" /> - </button> - <button - follows="left|top" - layout="topleft" - top_pad="3" - left="10" - height="23" - label="Tweet" - name="post_photo_btn" - width="100"> - <button.commit_callback - function="SocialSharing.SendPhoto" /> - </button> - <button - follows="right|top" - layout="topleft" - height="23" - label="Cancel" - name="cancel_photo_btn" - right="-10" - top_delta="0" - width="100"> - <button.commit_callback - function="SocialSharing.Cancel" /> - </button> - </panel> diff --git a/indra/newview/skins/default/xui/en/role_actions.xml b/indra/newview/skins/default/xui/en/role_actions.xml index f79d752fdb..bda08f3421 100644 --- a/indra/newview/skins/default/xui/en/role_actions.xml +++ b/indra/newview/skins/default/xui/en/role_actions.xml @@ -92,7 +92,10 @@ <action description="Toggle various About Land > Options settings" longdescription="Toggle 'Safe (no damage)', 'Fly', and allow other Residents to: 'Edit Terrain', 'Build', 'Create Landmarks', and 'Run Scripts' on group-owned land in About Land > Options tab." name="land options" value="22" /> - </action_set> + <action description="Modify environment settings and day cycle." + longdescription="Change the environment settings and day cycle from the About Land > Environment tab." + name="land change environment" value="46" /> + </action_set> <action_set description="These Abilities include powers which allow Members to bypass restrictions on group-owned parcels." name="Parcel Powers"> diff --git a/indra/newview/skins/default/xui/en/sidepanel_appearance.xml b/indra/newview/skins/default/xui/en/sidepanel_appearance.xml index 2a1eb425ed..1777a0db05 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_appearance.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_appearance.xml @@ -32,7 +32,7 @@ width="333"> top="5" follows="left|top|right" layout="topleft" - width="303" + width="307" height="33" name="panel_currentlook" > @@ -118,14 +118,14 @@ width="333"> name="Filter" search_button_visible="true" top_pad="10" - width="303" /> + width="307" /> <panel class="panel_outfits_inventory" filename="panel_outfits_inventory.xml" name="panel_outfits_inventory" height="493" min_height="410" - width="320" + width="325" visible="false" left="0" tab_group="1" diff --git a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml index acb6f5b42a..9a68479d05 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml @@ -33,7 +33,7 @@ </panel.string> <panel.string name="acquiredDate"> - [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local] + [wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [year,datetime,slt] </panel.string> <panel.string name="origin_inventory"> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 9eedc45aa9..d115e09d5b 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -28,7 +28,7 @@ <string name="BuildConfig">Build Configuration [BUILD_CONFIG]</string> <string name="AboutPosition"> -You are at [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1] in [REGION] located at <nolink>[HOSTNAME]</nolink> ([HOSTIP]) +You are at [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1] in [REGION] located at <nolink>[HOSTNAME]</nolink> SLURL: <nolink>[SLURL]</nolink> (global coordinates [POSITION_0,number,1], [POSITION_1,number,1], [POSITION_2,number,1]) [SERVER_VERSION] @@ -107,7 +107,9 @@ Voice Server Version: [VOICE_VERSION] <string name="CertExpired">The certificate returned by the Grid appears to be expired. Please check your system clock, or contact your Grid administrator.</string> <string name="CertKeyUsage">The certificate returned by the server could not be used for SSL. Please contact your Grid administrator.</string> <string name="CertBasicConstraints">Too many certificates were in the servers Certificate chain. Please contact your Grid administrator.</string> + <string name="CertInvalid">Could not load certificate. Please contact your Grid administrator.</string> <string name="CertInvalidSignature">The certificate signature returned by the Grid server could not be verified. Please contact your Grid administrator.</string> + <string name="CertAllocationFailure">Failed to allocate openssl memory for certificate.</string> <string name="LoginFailedNoNetwork">Network error: Could not establish connection, please check your network connection.</string> <string name="LoginFailed">Login failed.</string> @@ -201,21 +203,7 @@ Please try logging in again in a minute.</string> <string name="YouHaveBeenDisconnected">You have been disconnected from the region you were in.</string> <string name="SentToInvalidRegion">You were sent to an invalid region.</string> <string name="TestingDisconnect">Testing viewer disconnect</string> - - <!-- SLShare: Flickr and Twitter --> - <string name="SocialFlickrConnecting">Connecting to Flickr...</string> - <string name="SocialFlickrPosting">Posting...</string> - <string name="SocialFlickrDisconnecting">Disconnecting from Flickr...</string> - <string name="SocialFlickrErrorConnecting">Problem connecting to Flickr</string> - <string name="SocialFlickrErrorPosting">Problem posting to Flickr</string> - <string name="SocialFlickrErrorDisconnecting">Problem disconnecting from Flickr</string> - <string name="SocialTwitterConnecting">Connecting to Twitter...</string> - <string name="SocialTwitterPosting">Posting...</string> - <string name="SocialTwitterDisconnecting">Disconnecting from Twitter...</string> - <string name="SocialTwitterErrorConnecting">Problem connecting to Twitter</string> - <string name="SocialTwitterErrorPosting">Problem posting to Twitter</string> - <string name="SocialTwitterErrorDisconnecting">Problem disconnecting from Twitter</string> - + <!-- SLShare: User Friendly Filter Names Translation --> <string name="BlackAndWhite">Black & White</string> <string name="Colors1970">1970's Colors</string> @@ -314,6 +302,17 @@ Please try logging in again in a minute.</string> <string name="BUTTON_DOCK">Dock</string> <string name="BUTTON_HELP">Show Help</string> + <!-- ToolTips for notecards --> + <string name="TooltipNotecardNotAllowedTypeDrop"> +Items of this type can't be attached +to notecards on this region. + </string> + <string name="TooltipNotecardOwnerRestrictedDrop"> +Only items with unrestricted +'next owner' permissions +can be attached to notecards. + </string> + <!-- searching - generic --> <string name="Searching">Searching...</string> <string name="NoneFound">None found.</string> @@ -366,6 +365,11 @@ Error in upload request. Please visit http://secondlife.com/support for help fixing this problem. </string> + <!-- Settings errors --> + <string name="SettingValidationError">Validation failed for importing settings [NAME]</string> + <string name="SettingImportFileError">Could not open file [FILE]</string> + <string name="SettingParseFileError">Could not open file [FILE]</string> + <string name="SettingTranslateError">Could not translate legacy windlight [NAME]</string> <!-- Asset Type human readable names: these will replace variable [TYPE] in notification FailedToFindWearable* --> <!-- Will also replace [OBJECTTYPE] in notifications: UserGiveItem, ObjectGiveItem --> <string name="texture">texture</string> @@ -393,7 +397,8 @@ http://secondlife.com/support for help fixing this problem. <string name="favorite">favorite</string> <string name="symbolic link">link</string> <string name="symbolic folder link">folder link</string> - <string name="mesh">mesh</string> + <string name="settings blob">settings</string> + <string name="mesh">mesh</string> <!-- llvoavatar. Displayed in the avatar chat bubble --> <string name="AvatarEditingAppearance">(Editing Appearance)</string> @@ -518,6 +523,7 @@ http://secondlife.com/support for help fixing this problem. <string name="ManageEstateSilently">Manage your estates silently</string> <string name="ChangeYourDefaultAnimations">Change your default animations</string> <string name="ForceSitAvatar">Force your avatar to sit</string> + <string name="ChangeEnvSettings">Change your environment settings</string> <string name="NotConnected">Not Connected</string> <string name="AgentNameSubst">(You)</string> <!-- Substitution for agent name --> @@ -2290,9 +2296,10 @@ For AI Character: Get the closest navigable point to the point provided. <!-- inventory --> <string name="InventoryNoMatchingItems">Didn't find what you're looking for? Try [secondlife:///app/search/all/[SEARCH_TERM] Search].</string> - <string name="InventoryNoMatchingRecentItems">Didn't find what you're looking for? Try [secondlife:///app/inventory/filters Show filters].</string> - <string name="PlacesNoMatchingItems">Didn't find what you're looking for? Try [secondlife:///app/search/places/[SEARCH_TERM] Search].</string> - <string name="FavoritesNoMatchingItems">Drag a landmark here to add it to your favorites.</string> + <string name="InventoryNoMatchingRecentItems">Didn't find what you're looking for? Try [secondlife:///app/inventory/filters Show filters].</string> + <string name="PlacesNoMatchingItems">To add a place to your landmarks, click the star to the right of the location name.</string> + <string name="FavoritesNoMatchingItems">To add a place to your favorites, click the star to the right of the location name, then save the landmark to "Favorites bar".</string> + <string name="MarketplaceNoListing">You have no listings yet.</string> <string name="MarketplaceNoMatchingItems">No items found. Check the spelling of your search string and try again.</string> <string name="InventoryNoTexture">You do not have a copy of this texture in your inventory</string> <string name="InventoryInboxNoItems">Your Marketplace purchases will appear here. You may then drag them into your inventory to use them.</string> @@ -2365,6 +2372,8 @@ If you continue to receive this message, please contact Second Life support for <string name="MarketplaceNoStock">out of stock</string> <string name="MarketplaceUpdating">updating...</string> + <string name="UploadFeeInfo">Fee is based on your subscription level. Higher levels are charged lower fees. [https://secondlife.com/my/account/membership.php? Learn more]</string> + <string name="Open landmarks">Open landmarks</string> <string name="Unconstrained">Unconstrained</string> @@ -2409,6 +2418,7 @@ If you continue to receive this message, please contact Second Life support for <string name="Scripts" value=" Scripts," /> <string name="Sounds" value=" Sounds," /> <string name="Textures" value=" Textures," /> + <string name="Settings" value=" Settings," /> <string name="Snapshots" value=" Snapshots," /> <string name="No Filters" value="No " /> <string name="Since Logoff" value=" - Since Logoff" /> @@ -2637,6 +2647,7 @@ If you continue to receive this message, please contact Second Life support for <string name="Debits">Debits</string> <string name="Total">Total</string> <string name="NoGroupDataFound">No group data found for group </string> + <string name="AlreadyInGroup">You are already in this group </string> <!-- floater IM bonus_info: When a Linden with Admin/god status receives a new IM this displays the estate (Mainland vs. teen grid) of the source avatar. This is to help Lindens when answering questions. --> @@ -2778,6 +2789,14 @@ If you continue to receive this message, please contact Second Life support for <string name="LocalSettings">Local Settings</string> <string name="RegionSettings">Region Settings</string> + <string name="NoEnvironmentSettings">This Region does not support environmental settings.</string> + <string name="EnvironmentSun">Sun</string> + <string name="EnvironmentMoon">Moon</string> + <string name="EnvironmentBloom">Bloom</string> + <string name="EnvironmentCloudNoise">Cloud Noise</string> + <string name="EnvironmentNormalMap">Normal Map</string> + <string name="EnvironmentTransparent">Transparent</string> + <!-- panel classified --> <string name="ClassifiedClicksTxt">Clicks: [TELEPORT] teleport, [MAP] map, [PROFILE] profile</string> <string name="ClassifiedUpdateAfterPublish">(will update after publish)</string> @@ -2817,10 +2836,9 @@ If you continue to receive this message, please contact Second Life support for <string name="AcquiredItems">Acquired Items</string> <string name="Cancel">Cancel</string> <string name="UploadingCosts">Uploading [NAME] costs L$ [AMOUNT]</string> - <string name="BuyingCosts">Buying this costs L$ [AMOUNT]</string> <string name="UnknownFileExtension"> Unknown file extension .%s -Expected .wav, .tga, .bmp, .jpg, .jpeg, or .bvh +Expected .wav, .tga, .bmp, .jpg, .jpeg, or .anim </string> <string name="MuteObject2">Block</string> <string name="MuteAvatar">Block</string> @@ -3655,13 +3673,6 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. Drag items from inventory here </string> - <string name="flickr_post_success"> - You posted to Flickr. - </string> - <string name="twitter_post_success"> - You posted to Twitter. - </string> - <string name="no_session_message"> (IM Session Doesn't Exist) </string> @@ -3683,10 +3694,10 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. Also there are some other places where "generic" is used. So, let add string with name="generic" with the same value as "generic_request_error" --> <string name="generic"> - Error making request, please try again later. + Please close and reopen the conversation, or relog and try again. </string> <string name="generic_request_error"> - Error making request, please try again later. + Please close and reopen the conversation, or relog and try again. </string> <string name="insufficient_perms_error"> You do not have sufficient permissions. @@ -3748,6 +3759,9 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. <string name="unread_chat_multiple"> [SOURCES] have said something new </string> + <string name="teleport_preamble_compact_chat"> + You are now at + </string> <string name="session_initialization_timed_out_error"> The session initialization is timed out </string> @@ -3757,6 +3771,10 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. <string name="voice_morphing_url">https://secondlife.com/destination/voice-island</string> <string name="premium_voice_morphing_url">https://secondlife.com/destination/voice-morphing-premium</string> + <string name="lindenhomes_get_home_url">https://secondlife.com/land/lindenhomes/member.php</string> + <string name="lindenhomes_my_home_url">https://land.secondlife.com/en-Us/lindenhomes/my-home.php</string> + <string name="membership_url">https://secondlife.com/my/account/membership.php</string> + <!-- Financial operations strings --> <string name="paid_you_ldollars">[NAME] paid you L$[AMOUNT] [REASON].</string> <string name="paid_you_ldollars_gift">[NAME] paid you L$[AMOUNT]: [REASON]</string> @@ -3780,11 +3798,12 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. <string name="to upload">to upload</string> <string name="to publish a classified ad">to publish a classified ad</string> - <string name="giving">Giving L$ [AMOUNT]</string> <string name="uploading_costs">Uploading costs L$ [AMOUNT]</string> <string name="this_costs">This costs L$ [AMOUNT]</string> - <string name="buying_selected_land">Buying selected land for L$ [AMOUNT]</string> - <string name="this_object_costs">This object costs L$ [AMOUNT]</string> + + <string name="buying_selected_land">This land costs</string> + <string name="this_object_costs">This item costs</string> + <string name="giving">You want to give</string> <string name="group_role_everyone">Everyone</string> <string name="group_role_officers">Officers</string> @@ -3857,6 +3876,12 @@ Abuse Report</string> <string name="Female - Stick tougue out">Female - Stick tongue out</string> <string name="Female - Wow">Female - Wow</string> +<!-- settings --> + <string name="New Daycycle">New Daycycle</string> + <string name="New Water">New Water</string> + <string name="New Sky">New Sky</string> + + <string name="/bow">/bow</string> <string name="/clap">/clap</string> <string name="/count">/count</string> @@ -3934,6 +3959,15 @@ Please check http://status.secondlifegrid.net to see if there is a known problem <string name="Accounting">Accounting</string> <string name="Notices">Notices</string> <string name="Chat">Chat</string> + + <!-- SL Membership --> + <string name="BaseMembership">Base</string> + <string name="PremiumMembership">Premium</string> + <string name="Premium PlusMembership">Premium Plus</string> + <string name="InternalMembership">Internal</string> <!-- No need to translate --> + + <string name="MembershipUpgradeText">Upgrade to Premium</string> + <string name="MembershipPremiumText">My Premium membership</string> <!-- Question strings for delete items notifications --> <string name="DeleteItems">Delete selected items?</string> @@ -4068,6 +4102,15 @@ Try enclosing path to the editor with double quotes. <string name="Z">Z</string> <!-- Key names end --> + <!-- Mouse button names (short) begin --> + <string name="LMB">LMB</string> + <string name="MMB">MMB</string> + <string name="RMB">RMB</string> + <string name="MB4">MB4</string> + <string name="MB5">MB5</string> + <string name="Double LMB">Double LMB</string> + <!-- Mouse button names end --> + <!-- llviewerwindow --> <string name="BeaconParticle">Viewing particle beacons (blue)</string> <string name="BeaconPhysical">Viewing physical object beacons (green)</string> @@ -4075,29 +4118,30 @@ Try enclosing path to the editor with double quotes. <string name="BeaconScriptedTouch">Viewing scripted object with touch function beacons (red)</string> <string name="BeaconSound">Viewing sound beacons (yellow)</string> <string name="BeaconMedia">Viewing media beacons (white)</string> + <string name="BeaconSun">Viewing sun direction beacon (orange)</string> + <string name="BeaconMoon">Viewing moon direction beacon (purple)</string> <string name="ParticleHiding">Hiding Particles</string> <!-- commands --> <string name="Command_AboutLand_Label">About land</string> - <string name="Command_Appearance_Label">Appearance</string> - <string name="Command_Avatar_Label">Avatar</string> + <string name="Command_Appearance_Label">Outfits</string> + <string name="Command_Avatar_Label">Complete avatars</string> <string name="Command_Build_Label">Build</string> <string name="Command_Chat_Label">Chat</string> <string name="Command_Conversations_Label">Conversations</string> <string name="Command_Compass_Label">Compass</string> <string name="Command_Destinations_Label">Destinations</string> - <string name="Command_Flickr_Label">Flickr</string> + <string name="Command_Environments_Label">My Environments</string> <string name="Command_Gestures_Label">Gestures</string> <string name="Command_Grid_Status_Label">Grid status</string> - <string name="Command_HowTo_Label">How to</string> + <string name="Command_HowTo_Label">Guidebook</string> <string name="Command_Inventory_Label">Inventory</string> <string name="Command_Map_Label">Map</string> <string name="Command_Marketplace_Label">Marketplace</string> <string name="Command_MarketplaceListings_Label">Marketplace</string> <string name="Command_MiniMap_Label">Mini-map</string> <string name="Command_Move_Label">Walk / run / fly</string> - <string name="Command_Outbox_Label">Merchant outbox</string> <string name="Command_People_Label">People</string> <string name="Command_Picks_Label">Picks</string> <string name="Command_Places_Label">Places</string> @@ -4107,7 +4151,6 @@ Try enclosing path to the editor with double quotes. <string name="Command_Search_Label">Search</string> <string name="Command_Snapshot_Label">Snapshot</string> <string name="Command_Speak_Label">Speak</string> - <string name="Command_Twitter_Label">Twitter</string> <string name="Command_View_Label">Camera controls</string> <string name="Command_Voice_Label">Voice settings</string> @@ -4119,7 +4162,7 @@ Try enclosing path to the editor with double quotes. <string name="Command_Conversations_Tooltip">Converse with everyone</string> <string name="Command_Compass_Tooltip">Compass</string> <string name="Command_Destinations_Tooltip">Destinations of interest</string> - <string name="Command_Flickr_Tooltip">Upload to Flickr</string> + <string name="Command_Environments_Tooltip">My Environments</string> <string name="Command_Gestures_Tooltip">Gestures for your avatar</string> <string name="Command_Grid_Status_Tooltip">Show current Grid status</string> <string name="Command_HowTo_Tooltip">How to do common tasks</string> @@ -4129,7 +4172,6 @@ Try enclosing path to the editor with double quotes. <string name="Command_MarketplaceListings_Tooltip">Sell your creation</string> <string name="Command_MiniMap_Tooltip">Show nearby people</string> <string name="Command_Move_Tooltip">Moving your avatar</string> - <string name="Command_Outbox_Tooltip">Transfer items to your marketplace for sale</string> <string name="Command_People_Tooltip">Friends, groups, and nearby people</string> <string name="Command_Picks_Tooltip">Places to show as favorites in your profile</string> <string name="Command_Places_Tooltip">Places you've saved</string> @@ -4139,7 +4181,6 @@ Try enclosing path to the editor with double quotes. <string name="Command_Search_Tooltip">Find places, events, people</string> <string name="Command_Snapshot_Tooltip">Take a picture</string> <string name="Command_Speak_Tooltip">Speak with people nearby using your microphone</string> - <string name="Command_Twitter_Tooltip">Twitter</string> <string name="Command_View_Tooltip">Changing camera angle</string> <string name="Command_Voice_Tooltip">Volume controls for calls and people near you in world</string> @@ -4196,6 +4237,8 @@ Try enclosing path to the editor with double quotes. <string name="ExperiencePermission10">control your camera</string> <string name="ExperiencePermission11">teleport you</string> <string name="ExperiencePermission12">automatically accept experience permissions</string> + <string name="ExperiencePermission16">force your avatar to sit</string> + <string name="ExperiencePermission17">change your environment settings</string> <string name="ExperiencePermissionShortUnknown">perform an unknown operation: [Permission]</string> <string name="ExperiencePermissionShort1">Take Controls</string> <string name="ExperiencePermissionShort3">Trigger Animations</string> @@ -4204,6 +4247,8 @@ Try enclosing path to the editor with double quotes. <string name="ExperiencePermissionShort10">Control Camera</string> <string name="ExperiencePermissionShort11">Teleport</string> <string name="ExperiencePermissionShort12">Permission</string> + <string name="ExperiencePermissionShort16">Sit</string> + <string name="ExperiencePermissionShort17">Environment</string> <!-- Conversation log messages --> <string name="logging_calls_disabled_log_empty"> diff --git a/indra/newview/skins/default/xui/en/teleport_strings.xml b/indra/newview/skins/default/xui/en/teleport_strings.xml index 5a9a16d344..1456114b25 100644 --- a/indra/newview/skins/default/xui/en/teleport_strings.xml +++ b/indra/newview/skins/default/xui/en/teleport_strings.xml @@ -2,8 +2,7 @@ <teleport_messages> <message_set name="errors"> <message name="invalid_tport"> - Problem encountered processing your teleport request. You may need to log back in before you can teleport. -If you continue to get this message, please check the [SUPPORT_SITE]. + Teleport attempts are limited to 6 per minute. If you are having trouble, wait one minute and try teleporting again. If the problem persists, log out and log in again. </message> <message name="invalid_region_handoff"> Problem encountered processing your region crossing. You may need to log back in before you can cross regions. @@ -39,6 +38,9 @@ Go to 'Welcome Island Public' to repeat the tutorial. <message name="expired_region_handoff"> Sorry, but the system was unable to complete your region crossing in a timely fashion. Please try again in a few minutes. </message> + <message name="preexisting_tport"> + Sorry, but the system was unable to start your teleport. Please try again in a few minutes. + </message> <message name="no_host"> Unable to find teleport destination. The destination may be temporarily unavailable or no longer exists. Please try again in a few minutes. </message> diff --git a/indra/newview/skins/default/xui/en/widgets/density_ctrl.xml b/indra/newview/skins/default/xui/en/widgets/density_ctrl.xml new file mode 100644 index 0000000000..0f3f0159db --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/density_ctrl.xml @@ -0,0 +1,164 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<densityctrl + border="true" + follows="all" + label="Density" + name="density_ctrl" + layout="topleft" + left="0" + top="0" + width="320" + height="240"> + <text + follows="left|top" + height="11" + layout="topleft" + left="15" + top_pad="-5" + width="120"> +Exponential Term + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left="15" + min_val="0" + max_val="1" + name="level_exponential" + top_delta="15" + width="200" + can_edit_text="true"/> + + <view + left_pad="15" + top="15" + name="preview_image" + height="140" + width="140" + follows="left|top" + /> + <text + follows="left|top" + height="11" + layout="topleft" + left="15" + top_pad="-5" + width="120"> +Exponential Scale Factor + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left="15" + min_val="0" + max_val="1" + name="exponential_scale" + top_delta="15" + width="200" + can_edit_text="true"/> + + <text + follows="left|top" + height="11" + layout="topleft" + left="15" + top_pad="-5" + width="120"> +Linear Term + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left="15" + min_val="0" + max_val="1" + name="level_linear" + top_delta="15" + width="200" + can_edit_text="true"/> + + <text + follows="left|top" + height="11" + layout="topleft" + left="15" + top_pad="-5" + width="120"> +Constant Term + </text> + <slider + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left="15" + min_val="0" + max_val="1" + name="level_constant" + top_delta="15" + width="200" + can_edit_text="true"/> + + <text + follows="left|top" + height="11" + layout="topleft" + left="15" + top_pad="15" + width="80"> +Max Altitude + </text> + <slider + decimal_digits="0" + follows="left|top" + height="16" + increment="1" + initial_value="0" + layout="topleft" + left="15" + min_val="1000" + max_val="40000" + name="max_altitude" + top_delta="15" + width="200" + can_edit_text="true"/> + + <text + follows="left|top" + height="11" + layout="topleft" + name="aniso_factor_label" + left="15" + top_pad="15" + width="80"> +Anisotropy Factor + </text> + <slider + decimal_digits="0" + follows="left|top" + height="16" + increment="1" + initial_value="0" + layout="topleft" + left="15" + min_val="1000" + max_val="40000" + name="aniso_factor" + top_delta="15" + width="200" + can_edit_text="true"/> +</densityctrl> diff --git a/indra/newview/skins/default/xui/en/widgets/filter_editor.xml b/indra/newview/skins/default/xui/en/widgets/filter_editor.xml index 2cc4abdd30..1c4822b8d5 100644 --- a/indra/newview/skins/default/xui/en/widgets/filter_editor.xml +++ b/indra/newview/skins/default/xui/en/widgets/filter_editor.xml @@ -6,9 +6,11 @@ text_pad_left="7" select_on_focus="true" text_tentative_color="TextFgTentativeColor" + highlight_text_field="false" background_image="TextField_Search_Off" background_image_disabled="TextField_Search_Disabled" - background_image_focused="TextField_Search_Active"> + background_image_focused="TextField_Search_Active" + background_image_highlight="TextField_Search_Highlight"> <search_button label="" top_pad="4" left_pad="4" diff --git a/indra/newview/skins/default/xui/en/widgets/joystick_quat.xml b/indra/newview/skins/default/xui/en/widgets/joystick_quat.xml new file mode 100644 index 0000000000..a190da3909 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/joystick_quat.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<joystick_rotate + image_selected="Cam_Rotate_In" + image_unselected="Cam_Rotate_Out" + scale_image="false" + mouse_opaque="false" + held_down_delay.seconds="0"/> diff --git a/indra/newview/skins/default/xui/en/widgets/joystick_rotate.xml b/indra/newview/skins/default/xui/en/widgets/joystick_rotate.xml index a190da3909..cbf721b346 100644 --- a/indra/newview/skins/default/xui/en/widgets/joystick_rotate.xml +++ b/indra/newview/skins/default/xui/en/widgets/joystick_rotate.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<joystick_rotate +<joystick_quat image_selected="Cam_Rotate_In" image_unselected="Cam_Rotate_Out" - scale_image="false" + scale_image="true" mouse_opaque="false" held_down_delay.seconds="0"/> diff --git a/indra/newview/skins/default/xui/en/widgets/line_editor.xml b/indra/newview/skins/default/xui/en/widgets/line_editor.xml index a054960bf8..f39e086196 100644 --- a/indra/newview/skins/default/xui/en/widgets/line_editor.xml +++ b/indra/newview/skins/default/xui/en/widgets/line_editor.xml @@ -6,6 +6,7 @@ commit_on_focus_lost="true" ignore_tab="true" cursor_color="TextCursorColor" + bg_color="White" text_color="TextFgColor" text_pad_left="2" text_readonly_color="TextFgReadOnlyColor" diff --git a/indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml b/indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml index 98707b8495..564f695cd0 100644 --- a/indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml +++ b/indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml @@ -15,7 +15,7 @@ top="30" scale_image="true" visible="false" - width="212" /> + width="30" /> <panel_camera_item.icon_selected follows="top|left" height="30" @@ -27,7 +27,7 @@ top="30" scale_image="true" visible="false" - width="212" /> + width="30" /> <panel_camera_item.picture follows="top|left" height="30" diff --git a/indra/newview/skins/default/xui/en/widgets/search_editor.xml b/indra/newview/skins/default/xui/en/widgets/search_editor.xml index faa0404b35..dc5a07bf4f 100644 --- a/indra/newview/skins/default/xui/en/widgets/search_editor.xml +++ b/indra/newview/skins/default/xui/en/widgets/search_editor.xml @@ -7,9 +7,11 @@ text_pad_right="6" select_on_focus="true" text_tentative_color="TextFgTentativeColor" + highlight_text_field="false" background_image="TextField_Search_Off" background_image_disabled="TextField_Search_Disabled" - background_image_focused="TextField_Search_Active" > + background_image_focused="TextField_Search_Active" + background_image_highlight="TextField_Search_Highlight"> <search_button top_pad="4" left_pad="4" diff --git a/indra/newview/skins/default/xui/en/widgets/sun_moon_trackball.xml b/indra/newview/skins/default/xui/en/widgets/sun_moon_trackball.xml new file mode 100644 index 0000000000..9fa77855c0 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/sun_moon_trackball.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<sun_moon_trackball + name="virtualtrackball" + width="150" + height="150" + user_resize="false" + increment_angle_mouse="1.5f" + increment_angle_btn="1.0f" + image_sphere="VirtualTrackball_Sphere" + image_moon_back="VirtualTrackball_Moon_Back" + image_moon_front="VirtualTrackball_Moon_Front" + image_sun_back="VirtualTrackball_Sun_Back" + image_sun_front="VirtualTrackball_Sun_Front"> + + <sun_moon_trackball.border + visible="true"/> + + <sun_moon_trackball.labelN + font="SansSerif" + name="labelN" + valign="bottom" + halign="left" + label="N"/> + <sun_moon_trackball.labelS + font="SansSerif" + name="labelS" + valign="top" + halign="left" + label="S"/> + <sun_moon_trackball.labelW + font="SansSerif" + name="labelW" + valign="top" + halign="right" + label="W"/> + <sun_moon_trackball.labelE + font="SansSerif" + name="labelE" + valign="top" + halign="left" + label="E"/> + + <sun_moon_trackball.button_rotate_top + name="btn_rotate_top" + image_unselected="VirtualTrackball_Rotate_Top" + image_selected="VirtualTrackball_Rotate_Top_Active" + image_disabled="Blank" /> + + <sun_moon_trackball.button_rotate_bottom + name="btn_rotate_bottom" + image_unselected="VirtualTrackball_Rotate_Bottom" + image_selected="VirtualTrackball_Rotate_Bottom_Active" + image_disabled="Blank" /> + + <sun_moon_trackball.button_rotate_left + name="btn_rotate_left" + image_unselected="VirtualTrackball_Rotate_Left" + image_selected="VirtualTrackball_Rotate_Left_Active" + image_disabled="Blank" /> + + <sun_moon_trackball.button_rotate_right + name="btn_rotate_right" + image_unselected="VirtualTrackball_Rotate_Right" + image_selected="VirtualTrackball_Rotate_Right_Active" + image_disabled="Blank" /> + +</sun_moon_trackball> + diff --git a/indra/newview/skins/default/xui/en/widgets/xy_vector.xml b/indra/newview/skins/default/xui/en/widgets/xy_vector.xml new file mode 100644 index 0000000000..93ae26a6ad --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/xy_vector.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<xy_vector + name="xyvector" + width="120" + height="140" + decimal_digits="1" + label_width="16" + padding="4" + edit_bar_height="18" + user_resize="false"> + + <xy_vector.border + visible="true"/> + + <xy_vector.x_entry + name="XEntry" + tab_stop="true" + label="X:"/> + <xy_vector.y_entry + name="YEntry" + tab_stop="true" + label="Y:"/> + + <xy_vector.touch_area + name="TouchArea" + bevel_style="in" + border_visible="true"/> + +</xy_vector> diff --git a/indra/newview/skins/default/xui/es/floater_about_land.xml b/indra/newview/skins/default/xui/es/floater_about_land.xml index 998d2a8863..df0edd498f 100644 --- a/indra/newview/skins/default/xui/es/floater_about_land.xml +++ b/indra/newview/skins/default/xui/es/floater_about_land.xml @@ -362,7 +362,7 @@ Sólo las parcelas más grandes pueden listarse en la búsqueda. Foto: </text> <texture_picker label="" name="snapshot_ctrl" tool_tip="Pulse para elegir una imagen"/> - <text name="allow_see_label"> + <text name="allow_see_label" top="170"> Los avatares de otras parcelas pueden ver a los avatares de esta parcela y chatear con ellos </text> <check_box label="Ver los avatares" name="SeeAvatarsCheck" tool_tip="Permite que los avatares de otras parcelas vean a los avatares de ésta y chateen con ellos, y también que tú puedas verles y chatear con ellos." top="170"/> @@ -444,7 +444,7 @@ los media: <panel.string name="estate_override"> Una o más de esta opciones está configurada a nivel del estado </panel.string> - <check_box label="Cualquiera puede visitar (Si no seleccionas esta opción, se crearán lÃneas de prohibición)" name="public_access"/> + <check_box label="Cualquiera puede visitar" name="public_access" tool_tip="Si no seleccionas esta opción, se crearán lÃneas de prohibición"/> <check_box label="Debe ser mayor de 18 [ESTATE_AGE_LIMIT]" name="limit_age_verified" tool_tip="Para poder acceder a esta parcela los Residentes deben ser mayores de 18 años. Para más información, consulta [SUPPORT_SITE]."/> <check_box label="Debe haber información archivada sobre el pago [ESTATE_PAYMENT_LIMIT]" name="limit_payment" tool_tip="Para poder acceder a esta parcela los Residentes deben haber aportado información de pago en su cuenta. Para más información, ver [SUPPORT_SITE]."/> <check_box label="Permitir grupo [GROUP] sin restricciones" name="GroupCheck" tool_tip="Elija el grupo en la pestaña General."/> @@ -479,5 +479,6 @@ los media: </panel> </panel> <panel label="EXPERIENCIAS" name="land_experiences_panel"/> + <panel label="ENTORNO" name="land_environment_panel"/> </tab_container> </floater> diff --git a/indra/newview/skins/default/xui/es/floater_adjust_environment.xml b/indra/newview/skins/default/xui/es/floater_adjust_environment.xml new file mode 100644 index 0000000000..25b6fad165 --- /dev/null +++ b/indra/newview/skins/default/xui/es/floater_adjust_environment.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_adjust_snapshot" title="Iluminación personal"> + <layout_stack name="outer_stack"> + <layout_panel name="env_controls"> + <layout_stack name="settings_stack"> + <layout_panel> + <button label="Restablecer" name="btn_reset" tool_tip="Cerrar y restablecer Entorno compartido"/> + <text name="cloud_map_label"> + Imagen nube: + </text> + </layout_panel> + <layout_panel> + <text name="label"> + Sol: + </text> + <check_box label="Mostrar baliza" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <check_box label="Mostrar baliza" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/es/floater_beacons.xml b/indra/newview/skins/default/xui/es/floater_beacons.xml index 49f990c84d..0eabcc7c27 100644 --- a/indra/newview/skins/default/xui/es/floater_beacons.xml +++ b/indra/newview/skins/default/xui/es/floater_beacons.xml @@ -18,5 +18,7 @@ <check_box label="Origen de sonidos" name="sounds"/> <check_box label="Origen de partÃculas" name="particles"/> <check_box label="Fuentes de media" name="moapbeacon"/> + <check_box label="Sol" name="sun"/> + <check_box label="Luna" name="moon"/> </panel> </floater> diff --git a/indra/newview/skins/default/xui/es/floater_bulk_perms.xml b/indra/newview/skins/default/xui/es/floater_bulk_perms.xml index 75e324c7ef..5ab13d2b09 100644 --- a/indra/newview/skins/default/xui/es/floater_bulk_perms.xml +++ b/indra/newview/skins/default/xui/es/floater_bulk_perms.xml @@ -30,6 +30,7 @@ <icon name="icon_sound" tool_tip="Sonidos"/> <check_box label="Texturas" name="check_texture"/> <icon name="icon_texture" tool_tip="Texturas"/> + <icon name="icon_setting" tool_tip="Configuración de entorno"/> <button label="√ Todos" label_selected="Todo" name="check_all"/> <button label="Limpiar" label_selected="Ninguno" name="check_none"/> <text name="newperms"> diff --git a/indra/newview/skins/default/xui/es/floater_buy_currency.xml b/indra/newview/skins/default/xui/es/floater_buy_currency.xml index 2c8848265f..086150dd57 100644 --- a/indra/newview/skins/default/xui/es/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/es/floater_buy_currency.xml @@ -60,8 +60,7 @@ no el objeto. </text> <button label="Comprar ahora" name="buy_btn"/> <button label="Cancelar" name="cancel_btn"/> - <text left="5" name="info_cannot_buy" right="-5"> + <floater.string name="info_cannot_buy"> No se pudo hacer la compra - </text> - <button label="Ir a la web" name="error_web"/> + </floater.string> </floater> diff --git a/indra/newview/skins/default/xui/es/floater_delete_env_preset.xml b/indra/newview/skins/default/xui/es/floater_delete_env_preset.xml deleted file mode 100644 index bd0910e5d4..0000000000 --- a/indra/newview/skins/default/xui/es/floater_delete_env_preset.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<floater name="Delete Env Preset" title="ELIMINAR EL ENV PREDEFINIDO"> - <string name="title_water"> - Eliminar el agua predefinida - </string> - <string name="title_sky"> - Eliminar cielo predefinido - </string> - <string name="title_day_cycle"> - Eliminar ciclo del dÃa - </string> - <string name="label_water"> - Predefinido: - </string> - <string name="label_sky"> - Predefinido: - </string> - <string name="label_day_cycle"> - Ciclo del dÃa: - </string> - <string name="msg_confirm_deletion"> - ¿Estás seguro de que quieres eliminar el valor predefinido seleccionado? - </string> - <string name="msg_sky_is_referenced"> - No se puede quitar un valor predefinido al que se hace referencia en otro u otros ciclos del dÃa. - </string> - <string name="combo_label"> - -Selecciona un valor predefinido- - </string> - <text name="label"> - Predefinido: - </text> - <button label="Eliminar" name="delete"/> - <button label="Cancelar" name="cancel"/> -</floater> diff --git a/indra/newview/skins/default/xui/es/floater_edit_ext_day_cycle.xml b/indra/newview/skins/default/xui/es/floater_edit_ext_day_cycle.xml new file mode 100644 index 0000000000..c3273ea64e --- /dev/null +++ b/indra/newview/skins/default/xui/es/floater_edit_ext_day_cycle.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_edit_extdaycycle" title="Editar Ciclo del dÃa"> + <string name="title_new"> + Crear un Nuevo ciclo del dÃa + </string> + <string name="title_edit"> + Editar Ciclo del dÃa + </string> + <string name="hint_new"> + Asigna un nombre al ciclo del dÃa, ajusta los controles para crearlo y selecciona "Guardar". + </string> + <string name="hint_edit"> + Para editar el ciclo del dÃa, ajusta los controles siguientes y selecciona "Guardar". + </string> + <string name="time_label"> + ([HH]:[MM]) + </string> + <string name="sky_track_label"> + Cielo [ALT] + </string> + <string name="sky_label"> + Cielo + </string> + <string name="water_label"> + Agua + </string> + <string name="commit_parcel"> + Aplicar a la Parcela + </string> + <string name="commit_region"> + Aplicar a la Región + </string> + <layout_stack name="outer_stack"> + <layout_panel name="name_and_import"> + <text name="label"> + Nombre del Ciclo del dÃa: + </text> + <button label="Importar" name="btn_import" tool_tip="Importar configuración legado desde disco."/> + </layout_panel> + <layout_panel name="content"> + <layout_stack name="content_stack"> + <layout_panel name="timeline_track_selection"> + <panel name="timeline_layers"> + <button label="Cielo 4" name="sky4_track"/> + <button label="Cielo 3" name="sky3_track"/> + <button label="Cielo 2" name="sky2_track"/> + <button label="Nivel del terreno" name="sky1_track"/> + <button label="Agua" name="water_track"/> + </panel> + <panel name="timeline"> + <text name="p0" value="0 %[DSC]"/> + <text name="p1" value="25 %[DSC]"/> + <text name="p2" value="50 %[DSC]"/> + <text name="p3" value="75 %[DSC]"/> + <text name="p4" value="100 %[DSC]"/> + <multi_slider initial_value="0" name="WLTimeSlider"/> + <multi_slider initial_value="0" name="WLDayCycleFrames"/> + <text name="current_time" value="[PRCNT]%[DSC]"/> + <layout_stack> + <layout_panel> + <button label="Clonar ruta de" name="copy_track"/> + <button label="Cargar ruta de" name="load_track"/> + <button label="Borrar ruta" name="clear_track"/> + </layout_panel> + <layout_panel> + <layout_stack name="progress_control"> + <layout_panel name="skip_back"> + <button name="skip_back_btn" tool_tip="Ir hacia atrás"/> + </layout_panel> + <layout_panel name="skip_forward"> + <button name="skip_forward_btn" tool_tip="Ir hacia adelante"/> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel> + <button label="Añadir [FRAME]" name="add_frame"/> + <button label="Cargar [FRAME]" name="btn_load_frame"/> + <button label="Borrar [FRAME]" name="delete_frame"/> + </layout_panel> + </layout_stack> + </panel> + </layout_panel> + <layout_panel name="frame_edit_controls"> + <text name="icn_lock_edit"> + Seleccionar un marco clave de la lÃnea de tiempo indicada arriba para editar los parámetros. + </text> + </layout_panel> + <layout_panel name="frame_settings_water"> + <tab_container name="water_tabs"> + <panel label="Agua" name="water_panel"/> + </tab_container> + </layout_panel> + <layout_panel name="frame_settings_sky"> + <tab_container name="sky_tabs"> + <panel label="Atmósfera e Iluminación" name="atmosphere_panel"/> + <panel label="Nubes" name="clouds_panel"/> + <panel label="Sol y Luna" name="moon_panel"/> + </tab_container> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel name="buttons"> + <button label="Guardar" name="save_btn"/> + <button label="Cancelar" name="cancel_btn"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/es/floater_fixedenvironment.xml b/indra/newview/skins/default/xui/es/floater_fixedenvironment.xml new file mode 100644 index 0000000000..d17dcaad01 --- /dev/null +++ b/indra/newview/skins/default/xui/es/floater_fixedenvironment.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="Fixed Environment" title="Entorno fijo"> + <string name="edit_sky"> + Editar Cielo: + </string> + <string name="edit_water"> + Editar Agua: + </string> + <layout_stack name="floater_stack"> + <layout_panel name="info_panel"> + <button label="Cargar" name="btn_load" tool_tip="Cargar una configuración del inventario"/> + <button label="Importar" name="btn_import" tool_tip="Importar configuración legado desde disco."/> + </layout_panel> + <layout_panel name="button_panel"> + <layout_stack name="button_bar_ls"> + <layout_panel name="save_btn_lp"> + <button label="Guardar" name="btn_commit"/> + </layout_panel> + <layout_panel name="revert_btn_lp"> + <button label="Cancelar" name="btn_cancel" tool_tip="Volver a la última versión guardada"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/es/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/es/floater_inventory_view_finder.xml index 5698e39bee..4f3c177976 100644 --- a/indra/newview/skins/default/xui/es/floater_inventory_view_finder.xml +++ b/indra/newview/skins/default/xui/es/floater_inventory_view_finder.xml @@ -12,6 +12,7 @@ <check_box label="Sonidos" name="check_sound"/> <check_box label="Texturas" name="check_texture"/> <check_box label="Fotos" name="check_snapshot"/> + <check_box label="Opciones" name="check_settings"/> <button label="Todos" label_selected="Todo" name="All"/> <button label="Ninguno" label_selected="Nada" name="None"/> <check_box label="Mostrar siempre las carpetas" name="check_show_empty"/> diff --git a/indra/newview/skins/default/xui/es/floater_merchant_outbox.xml b/indra/newview/skins/default/xui/es/floater_merchant_outbox.xml deleted file mode 100644 index b74c5fca5c..0000000000 --- a/indra/newview/skins/default/xui/es/floater_merchant_outbox.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="floater_merchant_outbox" title="BUZÓN DE SALIDA DE COMERCIANTE"> - <string name="OutboxFolderCount1"> - 1 carpeta - </string> - <string name="OutboxFolderCountN"> - [NUM] carpetas - </string> - <string name="OutboxImporting"> - Enviando carpetas... - </string> - <string name="OutboxInitializing"> - Inicializando... - </string> - <panel label="" name="panel_1"> - <panel name="panel_2"> - <panel name="outbox_inventory_placeholder_panel"> - <text name="outbox_inventory_placeholder_title"> - Cargando... - </text> - </panel> - </panel> - <panel name="panel_3"> - <panel name="outbox_generic_drag_target"> - <text name="text_1"> - Arrastra aquà artÃculos para crear carpetas - </text> - </panel> - <button label="Enviar al Mercado" name="outbox_import_btn" tool_tip="Poner en el escaparate de Mi Mercado"/> - </panel> - </panel> -</floater> diff --git a/indra/newview/skins/default/xui/es/floater_my_environments.xml b/indra/newview/skins/default/xui/es/floater_my_environments.xml new file mode 100644 index 0000000000..8f636490ac --- /dev/null +++ b/indra/newview/skins/default/xui/es/floater_my_environments.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater label="Lugares" name="my_environments" title="MIS ENTORNOS"> + <layout_stack> + <layout_panel label="Filtros" name="filter_panel"> + <check_box label="DÃas" name="chk_days"/> + <check_box label="Cielos" name="chk_skies"/> + <check_box label="Agua" name="chk_water"/> + <filter_editor label="Filtrar entornos" name="flt_search"/> + </layout_panel> + <layout_panel label="Entornos" name="list_panel"> + <panel label="pnl_inv_wrap" name="pnl_inv_wrap"/> + </layout_panel> + <layout_panel> + <check_box initial_value="false" label="Mostrar todas las carpetas" name="chk_showfolders"/> + </layout_panel> + <layout_panel name="pnl_control"> + <panel label="bottom_panel" name="pnl_bottom"> + <menu_button name="btn_gear" tool_tip="Más opciones"/> + <menu_button name="btn_newsettings" tool_tip="Crear una opción nueva"/> + <button name="btn_del" tool_tip="Quitar el Ãtem seleccionado"/> + </panel> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/es/floater_perms_default.xml b/indra/newview/skins/default/xui/es/floater_perms_default.xml index 97e5390931..7238ee7716 100644 --- a/indra/newview/skins/default/xui/es/floater_perms_default.xml +++ b/indra/newview/skins/default/xui/es/floater_perms_default.xml @@ -37,6 +37,10 @@ <text name="label_12" tool_tip="Definir los permisos predeterminados para la creación de ropa o partes del cuerpo"> ArtÃculos de vestir </text> + <text name="label_13" tool_tip="Definir los permisos predeterminados para la creación de parámetros de entorno"> + Opciones + </text> + <check_box name="env_settings_c" value="true"/> </panel> <button label="OK" label_selected="OK" name="ok"/> <button label="Cancelar" label_selected="Cancelar" name="cancel"/> diff --git a/indra/newview/skins/default/xui/es/floater_pick_track.xml b/indra/newview/skins/default/xui/es/floater_pick_track.xml new file mode 100644 index 0000000000..44c24248a6 --- /dev/null +++ b/indra/newview/skins/default/xui/es/floater_pick_track.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="track picker" title="DESTACADO: RUTA"> + <layout_stack name="adjuster"> + <layout_panel name="pnl_desc"> + <text name="select_description"> + Seleccionar cielo fuente: + </text> + </layout_panel> + <layout_panel name="pnl_traks"> + <radio_group name="track_selection"> + <radio_item label="Cielo4 [ALT]" name="radio_sky4" value="4"/> + <radio_item label="Cielo3 [ALT]" name="radio_sky3" value="3"/> + <radio_item label="Cielo2 [ALT]" name="radio_sky2" value="2"/> + <radio_item label="Terreno" name="radio_sky1" value="1."/> + </radio_group> + </layout_panel> + <layout_panel name="pnl_ok_cancel"> + <button label="OK" label_selected="OK" name="btn_select"/> + <button label="Cancelar" label_selected="Cancelar" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/es/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/es/floater_preferences_graphics_advanced.xml index b8d5824fb7..2bcec020b2 100644 --- a/indra/newview/skins/default/xui/es/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/es/floater_preferences_graphics_advanced.xml @@ -82,7 +82,6 @@ <check_box initial_value="true" label="Agua transparente" name="TransparentWater"/> <check_box initial_value="true" label="Efecto de relieve y brillo" name="BumpShiny"/> <check_box initial_value="true" label="Puntos de luz locales" name="LocalLights"/> - <check_box initial_value="true" label="Shaders básicos" name="BasicShaders" tool_tip="Desactivar esta opción puede evitar que se bloqueen los controladores de algunas tarjetas gráficas"/> <slider label="Nivel de detalle del terreno:" name="TerrainDetail"/> <text name="TerrainDetailText"> Bajo diff --git a/indra/newview/skins/default/xui/es/floater_preview_texture.xml b/indra/newview/skins/default/xui/es/floater_preview_texture.xml index 4012191c78..b0afd44750 100644 --- a/indra/newview/skins/default/xui/es/floater_preview_texture.xml +++ b/indra/newview/skins/default/xui/es/floater_preview_texture.xml @@ -10,7 +10,7 @@ Descripción: </text> <text name="dimensions"> - [WIDTH] px x [HEIGHT] px + [WIDTH]px x [HEIGHT]px </text> <text name="aspect_ratio"> Previsualizar la ratio de las proporciones diff --git a/indra/newview/skins/default/xui/es/floater_settings_picker.xml b/indra/newview/skins/default/xui/es/floater_settings_picker.xml new file mode 100644 index 0000000000..73b8de30c3 --- /dev/null +++ b/indra/newview/skins/default/xui/es/floater_settings_picker.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="settings picker" title="DESTACADO: CONFIGURACIÓN"> + <floater.string name="pick title"> + Destacado: + </floater.string> + <floater.string name="pick_track"> + SELECCIONAR RUTA + </floater.string> + <floater.string name="pick_settings"> + SELECCIONAR CONFIGURACIÓN + </floater.string> + <floater.string name="track_water"> + Agua + </floater.string> + <floater.string name="track_ground"> + Terreno + </floater.string> + <floater.string name="track_sky"> + Cielo[NUM] + </floater.string> + <layout_stack name="test_stack"> + <layout_panel name="inv_list"> + <filter_editor label="Filtrar las texturas" name="flt_inventory_search"/> + </layout_panel> + <layout_panel name="temp"> + <button label="OK" label_selected="OK" name="btn_select"/> + <button label="Cancelar" label_selected="Cancelar" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/es/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/es/floater_texture_ctrl.xml index 01b024bc3e..a77dd99af0 100644 --- a/indra/newview/skins/default/xui/es/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/es/floater_texture_ctrl.xml @@ -9,18 +9,14 @@ <text name="Multiple"> Texturas múltiples </text> - <radio_group name="mode_selection"> - <radio_item label="Inventario" name="inventory" value="0"/> - <radio_item label="Local" name="local" value="1"/> - </radio_group> - <text name="unknown"> - Tamaño: [DIMENSIONS] - </text> + <combo_box name="mode_selection"> + <combo_box.item label="Inventario" name="inventory" value="0"/> + <combo_box.item label="Local" name="local" value="1"/> + </combo_box> <button label="Por defecto" label_selected="Por defecto" name="Default" width="84"/> <button label="Blanca" label_selected="Blanca" name="Blank"/> <button label="Ninguna" label_selected="Ninguna" left="90" name="None"/> <button label="" label_selected="" name="Pipette"/> - <check_box initial_value="true" label="Aplicarlo ahora" name="apply_immediate_check"/> <text name="preview_disabled" value="Vista previa inhabilitada"/> <filter_editor label="Filtrar las texturas" name="inventory search editor"/> <check_box initial_value="false" label="Ver las carpetas" name="show_folders_check"/> @@ -31,6 +27,22 @@ <column label="Nombre" name="unit_name"/> <column label="ID" name="unit_id_HIDDEN"/> </scroll_list> + <combo_box name="l_bake_use_texture_combo_box" tool_tip="Elegir la textura de horneado"> + <combo_box.item label="Ninguno" name="None"/> + <combo_box.item label="BAKED_HEAD" name="BAKED_HEAD"/> + <combo_box.item label="BAKED_UPPER" name="BAKED_UPPER"/> + <combo_box.item label="BAKED_LOWER" name="BAKED_LOWER"/> + <combo_box.item label="BAKED_EYES" name="BAKED_EYES"/> + <combo_box.item label="BAKED_SKIRT" name="BAKED_SKIRT"/> + <combo_box.item label="BAKED_HAIR" name="BAKED_HAIR"/> + <combo_box.item label="BAKED_LEFTARM" name="BAKED_LEFTARM"/> + <combo_box.item label="BAKED_LEFTLEG" name="BAKED_LEFTLEG"/> + <combo_box.item label="BAKED_AUX1" name="BAKED_AUX1"/> + <combo_box.item label="BAKED_AUX2" name="BAKED_AUX2"/> + <combo_box.item label="BAKED_AUX3" name="BAKED_AUX3"/> + </combo_box> + <check_box initial_value="false" label="Esconder Región Malla Base" name="hide_base_mesh_region"/> <button label="OK" label_selected="OK" name="Select"/> <button label="Cancelar" label_selected="Cancelar" name="Cancel"/> + <check_box initial_value="true" label="Aplicarlo ahora" name="apply_immediate_check"/> </floater> diff --git a/indra/newview/skins/default/xui/es/menu_cof_attachment.xml b/indra/newview/skins/default/xui/es/menu_cof_attachment.xml index 7541530601..65e31c0654 100644 --- a/indra/newview/skins/default/xui/es/menu_cof_attachment.xml +++ b/indra/newview/skins/default/xui/es/menu_cof_attachment.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="COF Attachment"> + <menu_item_call label="Tocar" name="touch_attach" /> + <menu_item_call label="Editar" name="edit_item" /> <menu_item_call label="Quitar" name="detach"/> </context_menu> diff --git a/indra/newview/skins/default/xui/es/menu_inventory.xml b/indra/newview/skins/default/xui/es/menu_inventory.xml index c5bc301608..d855d6f04f 100644 --- a/indra/newview/skins/default/xui/es/menu_inventory.xml +++ b/indra/newview/skins/default/xui/es/menu_inventory.xml @@ -10,7 +10,6 @@ <menu_item_call label="Activar" name="Marketplace Activate"/> <menu_item_call label="Desactivar" name="Marketplace Deactivate"/> <menu_item_call label="Compartir" name="Share"/> - <menu_item_call label="Comprar" name="Task Buy"/> <menu_item_call label="Abrir" name="Task Open"/> <menu_item_call label="Ejecutar" name="Task Play"/> <menu_item_call label="Propiedades" name="Task Properties"/> @@ -34,6 +33,7 @@ <menu_item_call label="Ropa interior nueva" name="New Underpants"/> <menu_item_call label="Nueva capa Alpha" name="New Alpha Mask"/> <menu_item_call label="Tatuaje nuevo" name="New Tattoo"/> + <menu_item_call label="Nuevo Universal" name="New Universal"/> <menu_item_call label="Nueva fÃsica" name="New Physics"/> </menu> <menu label="Nuevas partes del cuerpo" name="New Body Parts"> @@ -42,6 +42,11 @@ <menu_item_call label="Pelo nuevo" name="New Hair"/> <menu_item_call label="Ojos nuevos" name="New Eyes"/> </menu> + <menu label="Nueva Configuración" name="New Settings"> + <menu_item_call label="Nuevo Cielo" name="New Sky"/> + <menu_item_call label="Nueva Agua" name="New Water"/> + <menu_item_call label="Nuevo Ciclo del dÃa" name="New Day Cycle"/> + </menu> <menu label="Usar como valor predeterminado para" name="upload_def"> <menu_item_call label="Imágenes subidas" name="Image uploads"/> <menu_item_call label="Sonidos subidos" name="Sound uploads"/> @@ -99,9 +104,12 @@ <menu_item_call label="Ponerme" name="Wearable And Object Wear"/> <menu label="Anexar a" name="Attach To"/> <menu label="Anexar como HUD" name="Attach To HUD"/> + <menu_item_call label="Tocar" name="Attachment Touch" /> <menu_item_call label="Editar" name="Wearable Edit"/> <menu_item_call label="Añadir" name="Wearable Add"/> <menu_item_call label="Quitarse" name="Take Off"/> + <menu_item_call label="Aplicar sólo a Mi mismo" name="Settings Apply Local"/> + <menu_item_call label="Aplicar a la Parcela" name="Settings Apply Parcel"/> <menu_item_call label="Copiar en artÃculos del Mercado" name="Marketplace Copy"/> <menu_item_call label="Mover a artÃculos del Mercado" name="Marketplace Move"/> <menu_item_call label="--sin opciones--" name="--no options--"/> diff --git a/indra/newview/skins/default/xui/es/menu_inventory_add.xml b/indra/newview/skins/default/xui/es/menu_inventory_add.xml index f17cfe4ceb..f9a9f3a9fe 100644 --- a/indra/newview/skins/default/xui/es/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/es/menu_inventory_add.xml @@ -5,9 +5,7 @@ <menu_item_call label="Sonido ([COST] L$)..." name="Upload Sound"/> <menu_item_call label="Animación ([COST] L$)..." name="Upload Animation"/> <menu_item_call label="Modelo..." name="Upload Model"/> - <menu_item_call label="Asistente de modelo..." name="Upload Model Wizard"/> <menu_item_call label="Masivo ([COST] L$ por archivo)..." name="Bulk Upload"/> - <menu_item_call label="Configurar los permisos por defecto de subida" name="perm prefs"/> </menu> <menu_item_call label="Carpeta nueva" name="New Folder"/> <menu_item_call label="Script nuevo" name="New Script"/> @@ -25,6 +23,7 @@ <menu_item_call label="Ropa interior nueva" name="New Underpants"/> <menu_item_call label="Nueva Alfa" name="New Alpha"/> <menu_item_call label="Tatuaje nuevo" name="New Tattoo"/> + <menu_item_call label="Nuevo Universal" name="New Universal"/> <menu_item_call label="Nueva fÃsica" name="New Physics"/> </menu> <menu label="Nuevas partes del cuerpo" name="New Body Parts"> @@ -33,4 +32,9 @@ <menu_item_call label="Pelo nuevo" name="New Hair"/> <menu_item_call label="Ojos nuevos" name="New Eyes"/> </menu> + <menu label="Nueva Configuración" name="New Settings"> + <menu_item_call label="Nuevo Cielo" name="New Sky"/> + <menu_item_call label="Nueva Agua" name="New Water"/> + <menu_item_call label="Nuevo Ciclo del dÃa" name="New Day Cycle"/> + </menu> </menu> diff --git a/indra/newview/skins/default/xui/es/menu_outfit_gear.xml b/indra/newview/skins/default/xui/es/menu_outfit_gear.xml index b3f2b789d7..0cfab7ffc8 100644 --- a/indra/newview/skins/default/xui/es/menu_outfit_gear.xml +++ b/indra/newview/skins/default/xui/es/menu_outfit_gear.xml @@ -20,6 +20,7 @@ <menu_item_call label="Nueva Alfa" name="New Alpha"/> <menu_item_call label="Nueva fÃsica" name="New Physics"/> <menu_item_call label="Tatuaje nuevo" name="New Tattoo"/> + <menu_item_call label="Nuevo Universal" name="New Universal"/> </menu> <menu label="Nuevas partes del cuerpo" name="New Body Parts"> <menu_item_call label="AnatomÃa nueva" name="New Shape"/> diff --git a/indra/newview/skins/default/xui/es/menu_save_settings.xml b/indra/newview/skins/default/xui/es/menu_save_settings.xml new file mode 100644 index 0000000000..164763427d --- /dev/null +++ b/indra/newview/skins/default/xui/es/menu_save_settings.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="save_settings_menu"> + <menu_item_check label="Guardar" name="save_settings"/> + <menu_item_check label="Guardar como" name="save_as_new_settings"/> + <menu_item_check label="Asignar" name="commit_changes"/> + <menu_item_check label="Aplicar sólo a Mi mismo" name="apply_local"/> + <menu_item_check label="Aplicar a la Parcela" name="apply_parcel"/> + <menu_item_check label="Aplicar a la Región" name="apply_region"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/es/menu_settings_add.xml b/indra/newview/skins/default/xui/es/menu_settings_add.xml new file mode 100644 index 0000000000..82bd384ab5 --- /dev/null +++ b/indra/newview/skins/default/xui/es/menu_settings_add.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_add"> + <menu_item_call label="Nuevo Cielo" name="New Sky"/> + <menu_item_call label="Nueva Agua" name="New Water"/> + <menu_item_call label="Nuevo Ciclo del dÃa" name="New Day Cycle"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/es/menu_settings_gear.xml b/indra/newview/skins/default/xui/es/menu_settings_gear.xml new file mode 100644 index 0000000000..5d1b43933f --- /dev/null +++ b/indra/newview/skins/default/xui/es/menu_settings_gear.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_gear"> + <menu_item_call label="Editar" name="edit_settings"/> + <menu_item_call label="Aplicar sólo a Mi mismo" name="Settings Apply Local"/> + <menu_item_call label="Aplicar a la Parcela" name="Settings Apply Parcel"/> + <menu_item_call label="Aplicar a la Región" name="Settings Apply Region"/> + <menu_item_call label="Copiar" name="copy_settings"/> + <menu_item_call label="Pegar" name="paste_settings"/> + <menu_item_call label="Copiar la UUID" name="copy_uuid"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/es/menu_viewer.xml b/indra/newview/skins/default/xui/es/menu_viewer.xml index 7cc3c0320a..10955567ba 100644 --- a/indra/newview/skins/default/xui/es/menu_viewer.xml +++ b/indra/newview/skins/default/xui/es/menu_viewer.xml @@ -79,30 +79,15 @@ <menu_item_check label="Propiedades de la parcela" name="Parcel Properties"/> <menu_item_check label="Menú Avanzado" name="Show Advanced Menu"/> </menu> - <menu label="Dom" name="Sun"> + <menu label="Entorno" name="Environment"> <menu_item_check label="Amanecer" name="Sunrise"/> <menu_item_check label="MediodÃa" name="Noon"/> <menu_item_check label="Atardecer" name="Sunset"/> <menu_item_check label="Medianoche" name="Midnight"/> - <menu_item_check label="Usar Configuración de la Región" name="Use Region Settings"/> - </menu> - <menu label="Editor de entorno" name="Environment Editor"> - <menu_item_call label="Configuración del entorno..." name="Environment Settings"/> - <menu label="Agua predefinida" name="Water Presets"> - <menu_item_call label="Nuevo predefinido..." name="new_water_preset"/> - <menu_item_call label="Editar predefinido..." name="edit_water_preset"/> - <menu_item_call label="Eliminar predefinido..." name="delete_water_preset"/> - </menu> - <menu label="Cielos predefinidos" name="Sky Presets"> - <menu_item_call label="Nuevo predefinido..." name="new_sky_preset"/> - <menu_item_call label="Editar predefinido..." name="edit_sky_preset"/> - <menu_item_call label="Eliminar predefinido..." name="delete_sky_preset"/> - </menu> - <menu label="DÃas predefinidos" name="Day Presets"> - <menu_item_call label="Nuevo predefinido..." name="new_day_preset"/> - <menu_item_call label="Editar predefinido..." name="edit_day_preset"/> - <menu_item_call label="Eliminar predefinido..." name="delete_day_preset"/> - </menu> + <menu_item_check label="Usar entorno compartido" name="Use Shared Environment"/> + <menu_item_call label="Mis entornos..." name="my_environs"/> + <menu_item_call label="Iluminación personal..." name="adjustment_tool"/> + <menu_item_check label="Pausar Nubes" name="pause_clouds"/> </menu> </menu> <menu label="Construir" name="BuildTools"> @@ -323,6 +308,9 @@ <menu_item_check label="Capas alfa automáticas (no deferidas)" name="Automatic Alpha Masks (non-deferred)"/> <menu_item_check label="Animation Textures" name="Animation Textures"/> <menu_item_check label="Disable Textures" name="Disable Textures"/> + <menu_item_check label="Desactivar ambiente" name="Disable Ambient"/> + <menu_item_check label="Desactivar luz del sol" name="Disable Sunlight"/> + <menu_item_check label="Desactivar luces locales" name="Disable Local Lights"/> <menu_item_check label="Render Attached Lights" name="Render Attached Lights"/> <menu_item_check label="Render Attached Particles" name="Render Attached Particles"/> <menu_item_check label="Hover Glow Objects" name="Hover Glow Objects"/> @@ -406,6 +394,7 @@ </menu> <menu label="Admin" name="Deprecated"> <menu label="Take Off Clothing" name="Take Off Clothing"> + <menu_item_call label="Universal" name="Universal"/> <menu_item_call label="FÃsica" name="Physics"/> </menu> <menu label="Ayuda" name="DeprecatedHelp"> diff --git a/indra/newview/skins/default/xui/es/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/es/menu_wearable_list_item.xml index 4bffa689e7..cb68ad39a4 100644 --- a/indra/newview/skins/default/xui/es/menu_wearable_list_item.xml +++ b/indra/newview/skins/default/xui/es/menu_wearable_list_item.xml @@ -3,6 +3,7 @@ <menu_item_call label="Reemplazar" name="wear_replace"/> <menu_item_call label="Ponerme" name="wear_wear"/> <menu_item_call label="Añadir" name="wear_add"/> + <menu_item_call label="Tocar" name="touch" /> <menu_item_call label="Quitarme / Quitar" name="take_off_or_detach"/> <menu_item_call label="Quitar" name="detach"/> <context_menu label="Anexar a" name="wearable_attach_to"/> diff --git a/indra/newview/skins/default/xui/es/menu_wearing_gear.xml b/indra/newview/skins/default/xui/es/menu_wearing_gear.xml index ec13f99a01..01d1b16b58 100644 --- a/indra/newview/skins/default/xui/es/menu_wearing_gear.xml +++ b/indra/newview/skins/default/xui/es/menu_wearing_gear.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <toggleable_menu name="Gear Wearing"> - <menu_item_call label="Editar el vestuario" name="edit"/> + <menu_item_call label="Tocar" name="touch"/> + <menu_item_call label="Editar" name="edit_item"/> + <menu_item_call label="Editar el vestuario" name="edit_outfit"/> <menu_item_call label="Quitarme" name="takeoff"/> <menu_item_call label="Copiar la lista del vestuario al portapapeles" name="copy"/> </toggleable_menu> diff --git a/indra/newview/skins/default/xui/es/menu_wearing_tab.xml b/indra/newview/skins/default/xui/es/menu_wearing_tab.xml index 637a14cf5b..54a7d9b92c 100644 --- a/indra/newview/skins/default/xui/es/menu_wearing_tab.xml +++ b/indra/newview/skins/default/xui/es/menu_wearing_tab.xml @@ -1,8 +1,9 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="Wearing"> + <menu_item_call label="Tocar" name="touch_attach"/> <menu_item_call label="Quitarme" name="take_off"/> <menu_item_call label="Quitar" name="detach"/> - <menu_item_call label="Editar el vestuario" name="edit"/> + <menu_item_call label="Editar el vestuario" name="edit_outfit"/> <menu_item_call label="Editar" name="edit_item"/> <menu_item_call label="Mostrar original" name="show_original"/> </context_menu> diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml index 0a3576b799..c7750320d5 100644 --- a/indra/newview/skins/default/xui/es/notifications.xml +++ b/indra/newview/skins/default/xui/es/notifications.xml @@ -265,6 +265,10 @@ La inicialización del mercado ha fallado por un error del sistema o de la red. ¿Quieres revocar los derechos de modificación a los residentes seleccionados? <usetemplate name="okcancelbuttons" notext="No" yestext="SÃ"/> </notification> + <notification name="GroupNameLengthWarning"> + El nombre de un grupo debe contener entre [MIN_LEN] y [MAX_LEN] caracteres. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="UnableToCreateGroup"> No se ha podido crear el grupo. [MESSAGE] @@ -356,7 +360,7 @@ Si no quieres que este rol siga teniendo dichas capacidades, deshabilÃtalas inm No tienes dinero suficiente para entrar. </notification> <notification name="CreateGroupCost"> - Crear este grupo te costará 100 L$. + Crear este grupo costará L$[COST]. Los grupos necesitan más de un miembro. Si no, son borrados permanentemente. Por favor, invita a miembros en las próximas 48 horas. <usetemplate canceltext="Cancelar" name="okcancelbuttons" notext="Cancelar" yestext="Crear un grupo por 100 L$"/> @@ -498,6 +502,9 @@ debes estar dentro de ella. <notification name="ErrorEncodingSnapshot"> Error al codificar la foto. </notification> + <notification name="ErrorCannotAffordUpload"> + Necesitas L$[COST] para subir este objeto. + </notification> <notification name="ErrorPhotoCannotAfford"> Necesitas [COST] L$ para guardar una foto en el inventario. Puedes comprar L$ o bien guardar la foto en tu equipo. </notification> @@ -1745,11 +1752,14 @@ Haz clic en OK para instalar. <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="GroupLimitInfo"> - El lÃmite de grupos para las cuentas básicas es de [MAX_BASIC], y para -las cuentas [https://secondlife.com/premium/ Premium] es de [MAX_PREMIUM]. -Si has bajado la categorÃa de tu cuenta, tendrás que estar por debajo del lÃmite de [MAX_BASIC] grupos para poder apuntarte a más grupos. - -[https://secondlife.com/my/account/membership.php Cámbiate hoy a Premium] + Los residentes con membresÃas Básicas pueden unirse a hasta [MAX_BASIC] grupos. +Las membresÃas Premium permiten hasta [MAX_PREMIUM]. [https://secondlife.com/my/account/membership.php? Aprende más al respecto o mejora tu membresÃa] + <usetemplate name="okbutton" yestext="Cerrar"/> + </notification> + <notification name="GroupLimitInfoPlus"> + Los residentes con membresÃas Básicas pueden unirse a hasta [MAX_BASIC] cinco grupos. +Las membresÃas Premium permiten hasta [MAX_PREMIUM]. Las membresÃas Premium Plus permiten +hasta [MAX_PREMIUM_PLUS]. [https://secondlife.com/my/account/membership.php? Aprende más al respecto o mejora tu membresÃa] <usetemplate name="okbutton" yestext="Cerrar"/> </notification> <notification name="KickUser"> @@ -1968,6 +1978,11 @@ Se cambiarán miles de regiones, y se provocará un colapso en el espacio del se Si esta opción no está seleccionada, se anularán las restricciones establecidas por los dueños de parcelas para evitar provocaciones, mantener la privacidad o proteger a los residentes menores de material para adultos. Por favor, consulte con los dueños de parcelas según sea necesario. <usetemplate name="okbutton" yestext="Aceptar"/> </notification> + <notification name="EstateParcelEnvironmentOverride"> + Si esta opción no está seleccionada, se anularán los entornos personalizados añadidos por los dueños a sus parcelas. Por favor, consulta con los dueños de parcelas según sea necesario. +¿Quieres seguir? + <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="OK"/> + </notification> <notification name="RegionEntryAccessBlocked"> Tus preferencias de contenido actuales te impiden visitar la región que has seleccionado. Puedes cambiar las preferencias en Yo > Preferencias > General. <usetemplate name="okbutton" yestext="OK"/> @@ -2447,7 +2462,15 @@ PublÃcala en una página web para que otros puedan acceder fácilmente a esta p Este archivo del ciclo de un dÃa se refiere a un archivo perdido de cielo: [SKY]. </notification> <notification name="WLRegionApplyFail"> - No se pudo aplicar la configuración a la región. El problema podrÃa solucionarse saliendo de la región y regresando a ella. La razón especificada fue: [FAIL_REASON] + No se pudo aplicar la configuración a la región. Motivo: [FAIL_REASON] + </notification> + <notification name="WLLocalTextureDayBlock"> + Una textura local está en uso en la ruta, [TRACK], # cuadro [FRAMENO] ([FRAME]%) en el campo [FIELD]. +Los parámetros no pueden guardarse usando texturas locales. + </notification> + <notification name="WLLocalTextureFixedBlock"> + Una textura local está en uso en el campo [FIELD]. +Los parámetros no pueden guardarse usando texturas locales. </notification> <notification name="EnvCannotDeleteLastDayCycleKey"> No se puede eliminar la última clave de este ciclo del dÃa, ya que no puedes vaciar la caché del dÃa. En lugar de intentar eliminar la última clave restante y después intentar crear una nueva, debes modificarla. @@ -3291,6 +3314,22 @@ Por tu seguridad, serán bloqueadas durante unos segundos. Un moderador ha silenciado tu voz. <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FailedToGetBenefits"> + Desafortunadamente no fuimos capaces de obtener información sobre los beneficios para esta sesión. Esto no deberÃa suceder en un espacio de producción normal. Por favor contacte con soporte. Esta sesión no funcionara normalmente y recomendamos reiniciar. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="BulkUploadCostConfirmation"> + Esto subirá [COUNT] objetos por un costo total de L$[COST]. ¿Deseas continuar con la subida? + <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Subir"/> + </notification> + <notification name="BulkUploadNoCompatibleFiles"> + Los archivos seleccionados no pueden ser subidos en grupo. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="BulkUploadIncompatibleFiles"> + Algunos de los archivos seleccionados no pueden ser subidos en grupo. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="UploadCostConfirmation"> Esta carga te costará [PRECIO] L$. ¿Deseas continuar? <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Subir"/> @@ -4387,4 +4426,76 @@ Prueba a seleccionar un terreno más pequeño. [REASON] <usetemplate name="okbutton" yestext="Aceptar"/> </notification> + <notification name="FailedToFindSettings"> + No se pudo cargar la configuración para [NAME] a partir de la base de datos. + </notification> + <notification name="FailedToLoadSettingsApply"> + No se pudo aplicar esa configuración al entorno. + </notification> + <notification name="FailedToBuildSettingsDay"> + No se pudo aplicar esa configuración al entorno. + </notification> + <notification name="NoEnvironmentSettings"> + Esta región no es compatible con las opciones de entorno. + </notification> + <notification label="Guardar el vestuario" name="SaveSettingAs"> + Guardar parámetros de entorno actuales como: + <form name="form"> + <input name="message"> + [DESC] (nuevo) + </input> + <button name="OK" text="OK"/> + <button name="Cancel" text="Cancelar"/> + </form> + </notification> + <notification name="WLImportFail"> + No se pudo importar la configuración de Viento de luz legado [NAME] de +[FILE]. + +[REASONS] + </notification> + <notification name="WLParcelApplyFail"> + No se pudo configurar el entorno para esta parcela. +Por favor ingresa o selecciona una parcela cuyos derechos puedes modificar. + </notification> + <notification name="SettingsUnsuported"> + La configuración de entorno no está disponible en esta región. +Por favor accede a una región cuya configuración esté disponible y vuelve a intentar. + </notification> + <notification name="SettingsConfirmLoss"> + Estás a punto de perder los cambios que realizaste en este [TYPE] llamado "[NAME]". +¿Estás seguro de que deseas continuar? + <usetemplate ignoretext="¿Estás seguro de que quieres perder los cambios?" name="okcancelignore" notext="No" yestext="SÃ"/> + </notification> + <notification name="SettingsConfirmReset"> + Estás a punto de eliminar todos los parámetros aplicados. +¿Estás seguro de que deseas continuar? + <usetemplate name="okcancelbuttons" notext="No" yestext="SÃ"/> + </notification> + <notification name="PersonalSettingsConfirmReset"> + Estás a punto de eliminar todos los parámetros aplicados de iluminación personal. +¿Estás seguro de que deseas continuar? + <usetemplate name="okcancelbuttons" notext="No" yestext="SÃ"/> + </notification> + <notification name="SettingsMakeNoTrans"> + Estás a punto de importar parámetros no transferibles a este ciclo del dÃa. Si continúas, las opciones que estás editando pasarán a ser no transferibles también. + +Este cambio no se puede deshacer. + +¿Estás seguro de que deseas continuar? + <usetemplate ignoretext="¿Estás seguro de que quieres que esta opción sea no transferible?" name="okcancelignore" notext="No" yestext="SÃ"/> + </notification> + <notification name="NoEditFromLibrary"> + No puedes editar parámetros directamente en la librerÃa. +Por favor, copia a tu propio inventario y vuelve a intentarlo. + </notification> + <notification name="EnvironmentApplyFailed"> + Se produjo un error con estos parámetros. No pueden guardarse o aplicarse por el momento. + </notification> + <notification name="TrackLoadFailed"> + No se pudo cargar la ruta en [TRACK]. + </notification> + <notification name="TrackLoadMismatch"> + No se pudo cargar la ruta de [TRACK1] a [TRACK2]. + </notification> </notifications> diff --git a/indra/newview/skins/default/xui/es/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/es/panel_edit_tattoo.xml index 8776dd6c10..6f6ee41e54 100644 --- a/indra/newview/skins/default/xui/es/panel_edit_tattoo.xml +++ b/indra/newview/skins/default/xui/es/panel_edit_tattoo.xml @@ -1,9 +1,11 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_tattoo_panel"> - <panel name="avatar_tattoo_color_panel"> - <texture_picker label="Tatuaje de la cabeza" name="Head Tattoo" tool_tip="Pulsa para elegir una imagen"/> - <texture_picker label="Tatuaje superior" name="Upper Tattoo" tool_tip="Pulsa para elegir una imagen"/> - <texture_picker label="Tatuaje inferior" name="Lower Tattoo" tool_tip="Pulsa para elegir una imagen"/> - <color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/> - </panel> + <scroll_container name="avatar_tattoo_scroll"> + <panel name="avatar_tattoo_color_panel"> + <texture_picker label="Tatuaje en la cabeza" name="Head Tattoo" tool_tip="Pulsa para elegir una imagen"/> + <texture_picker label="Tatuaje superior" name="Upper Tattoo" tool_tip="Pulsa para elegir una imagen"/> + <texture_picker label="Tatuaje inferior" name="Lower Tattoo" tool_tip="Pulsa para elegir una imagen"/> + <color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/> + </panel> + </scroll_container> </panel> diff --git a/indra/newview/skins/default/xui/es/panel_edit_universal.xml b/indra/newview/skins/default/xui/es/panel_edit_universal.xml new file mode 100644 index 0000000000..5c825b5980 --- /dev/null +++ b/indra/newview/skins/default/xui/es/panel_edit_universal.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel name="edit_universal_panel"> + <scroll_container name="avatar_universal_scroll"> + <panel name="avatar_universal_color_panel"> + <texture_picker label="Tatuaje de la cabeza" name="Head Universal Tattoo" tool_tip="Pulsa para elegir una imagen"/> + <texture_picker label="Tatuaje superior" name="Upper Universal Tattoo" tool_tip="Pulsa para elegir una imagen"/> + <texture_picker label="Tatuaje inferior" name="Lower Universal Tattoo" tool_tip="Pulsa para elegir una imagen"/> + <texture_picker label="Tatuaje en falda" name="Skirt Tattoo" tool_tip="Pulsa para elegir una imagen"/> + <texture_picker label="Tatuaje en cabello" name="Hair Tattoo" tool_tip="Pulsa para elegir una imagen"/> + <texture_picker label="Tatuaje en ojos" name="Eyes Tattoo" tool_tip="Pulsa para elegir una imagen"/> + <texture_picker label="Tatuaje en brazo izquierdo" name="Left Arm Tattoo" tool_tip="Pulsa para elegir una imagen"/> + <texture_picker label="Tatuaje en pierna izquierda" name="Left Leg Tattoo" tool_tip="Pulsa para elegir una imagen"/> + <texture_picker label="Tatuaje Aux1" name="Aux1 Tattoo" tool_tip="Pulsa para elegir una imagen"/> + <texture_picker label="Tatuaje Aux2" name="Aux2 Tattoo" tool_tip="Pulsa para elegir una imagen"/> + <texture_picker label="Tatuaje Aux3" name="Aux3 Tattoo" tool_tip="Pulsa para elegir una imagen"/> + <color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/> + </panel> + </scroll_container> +</panel> diff --git a/indra/newview/skins/default/xui/es/panel_edit_wearable.xml b/indra/newview/skins/default/xui/es/panel_edit_wearable.xml index 799512968d..c1edf99f87 100644 --- a/indra/newview/skins/default/xui/es/panel_edit_wearable.xml +++ b/indra/newview/skins/default/xui/es/panel_edit_wearable.xml @@ -45,6 +45,9 @@ <string name="edit_tattoo_title"> Modificando los tatuajes </string> + <string name="edit_universal_title"> + Modificando Universal + </string> <string name="edit_physics_title"> Modificar la fÃsica </string> @@ -93,6 +96,9 @@ <string name="tattoo_desc_text"> Tatuaje: </string> + <string name="universal_desc_text"> + Universal: + </string> <string name="physics_desc_text"> FÃsica: </string> diff --git a/indra/newview/skins/default/xui/es/panel_outbox_inventory.xml b/indra/newview/skins/default/xui/es/panel_outbox_inventory.xml deleted file mode 100644 index 9e2f3c3adc..0000000000 --- a/indra/newview/skins/default/xui/es/panel_outbox_inventory.xml +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<outbox_inventory_panel name="inventory_outbox" tool_tip="Arrastra y coloca aquà los objetos que desees preparar para venderlos en tu tienda"/> diff --git a/indra/newview/skins/default/xui/es/panel_people.xml b/indra/newview/skins/default/xui/es/panel_people.xml index 909743c325..73b9af3665 100644 --- a/indra/newview/skins/default/xui/es/panel_people.xml +++ b/indra/newview/skins/default/xui/es/panel_people.xml @@ -18,7 +18,7 @@ <string name="no_groups_msg" value="¿Buscas grupos en que participar? Prueba la [secondlife:///app/search/groups Búsqueda]."/> <string name="MiniMapToolTipMsg" value="[REGION](Pulsa dos veces para abrir el mapa, pulsa mayús y arrastra para obtener una panorámica)"/> <string name="AltMiniMapToolTipMsg" value="[REGION](Pulsa dos veces para teleportarte, pulsa mayús y arrastra para obtener una panorámica)"/> - <string name="GroupCountWithInfo" value="Perteneces a [COUNT] grupos y puedes unirte a [REMAINING] más. [secondlife:/// ¿Quieres más?]"/> + <string name="GroupCountWithInfo" value="Perteneces a [COUNT] grupos y puedes unirte a [REMAINING] más. [secondlife:/// Incrementa tu lÃmite]"/> <tab_container name="tabs"> <panel label="CERCANA" name="nearby_panel"> <panel label="bottom_panel" name="nearby_buttons_panel"> @@ -51,7 +51,7 @@ <dnd_button name="minus_btn" tool_tip="Dejar el grupo seleccionado"/> </panel> <text name="groupcount"> - Formas parte de [COUNT] grupos y puedes unirte a [REMAINING] más. + Perteneces a [COUNT] grupos y puedes unirte a [REMAINING] más. </text> </panel> <panel label="RECIENTE" name="recent_panel"> diff --git a/indra/newview/skins/default/xui/es/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/es/panel_preferences_advanced.xml index 007101b8fe..0ba676898f 100644 --- a/indra/newview/skins/default/xui/es/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/es/panel_preferences_advanced.xml @@ -28,5 +28,5 @@ <check_box label="Mostrar la selección de cuadrÃcula al iniciar sesión" name="show_grid_selection_check"/> <check_box label="Mostrar el menú Avanzado" name="show_advanced_menu_check"/> <check_box label="Mostrar el menú Desarrollar" name="show_develop_menu_check"/> - <button label="Permisos de creación predeterminados" name="default_creation_permissions"/> + <button label="Permisos de creación predeterminados" name="default_creation_permissions" width="235"/> </panel> diff --git a/indra/newview/skins/default/xui/es/panel_preferences_chat.xml b/indra/newview/skins/default/xui/es/panel_preferences_chat.xml index f7e036efd7..388a5d84d2 100644 --- a/indra/newview/skins/default/xui/es/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/es/panel_preferences_chat.xml @@ -13,7 +13,7 @@ <item label="Medio" name="Medium" value="1"/> <item label="Grande" name="Large" value="2"/> </combo_box> - <check_box label="Bocadillos del chat" name="bubble_text_chat"/> + <check_box label="Bocadillos del chat" name="bubble_text_chat" left_delta="30"/> </panel> <panel name="im_notification_settings"> <text name="friend_ims"> diff --git a/indra/newview/skins/default/xui/es/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/es/panel_preferences_graphics1.xml index 816c698548..47815d0296 100644 --- a/indra/newview/skins/default/xui/es/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/es/panel_preferences_graphics1.xml @@ -32,10 +32,10 @@ </text> <check_box initial_value="true" label="Renderizar siempre los amigos" name="AlwaysRenderFriends"/> <button label="Excepciones..." name="RenderExceptionsButton"/> - <button label="Guardar configuración como valor predefinido..." name="PrefSaveButton"/> - <button label="Cargar predefinido..." name="PrefLoadButton"/> + <button label="Guardar configuración como valor predefinido" name="PrefSaveButton" width="260" left="5"/> + <button label="Cargar predefinido" name="PrefLoadButton" left_pad="7"/> min_val="0.125" - <button label="Eliminar predefinido..." name="PrefDeleteButton"/> - <button label="Restablecer la configuración recomendada" name="Defaults"/> + <button label="Eliminar predefinido" name="PrefDeleteButton" width="117" left_pad="7"/> + <button label="Restablecer la configuración recomendada" name="Defaults" width="248"/> <button label="Configuración avanzada..." name="AdvancedSettings"/> </panel> diff --git a/indra/newview/skins/default/xui/es/panel_preferences_setup.xml b/indra/newview/skins/default/xui/es/panel_preferences_setup.xml index 1b191d3e46..36888850c4 100644 --- a/indra/newview/skins/default/xui/es/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/es/panel_preferences_setup.xml @@ -30,7 +30,7 @@ <combo_box.item label="Preguntarme cuando una actualización opcional está disponible para instalar" name="Install_ask"/> <combo_box.item label="Instalar sólo actualizaciones obligatorias" name="Install_manual"/> </combo_box> - <check_box label="Admitir candidatos a la versión comercial a la hora de realizar actualizaciones" name="update_willing_to_test"/> + <check_box label="Admitir candidatos a la versión comercial a la hora de realizar actualizaciones" name="update_willing_to_test" left_delta="-20"/> <check_box label="Mostrar las notas de la versión después de la actualización" name="update_show_release_notes"/> <text name="Proxy Settings:"> Configuración de proxy: diff --git a/indra/newview/skins/default/xui/es/panel_region_environment.xml b/indra/newview/skins/default/xui/es/panel_region_environment.xml index a73f1deed4..3aa7e12089 100644 --- a/indra/newview/skins/default/xui/es/panel_region_environment.xml +++ b/indra/newview/skins/default/xui/es/panel_region_environment.xml @@ -1,33 +1,116 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Entorno" name="panel_env_info"> - <text name="water_settings_title"> - Selecciona la configuración de agua y cielo/ciclo del dÃa que deseas que vean todos los visitantes de tu región. Más información - </text> - <radio_group name="region_settings_radio_group"> - <radio_item label="Usar los valores predeterminados de Second Life" name="use_sl_default_settings"/> - <radio_item label="Usar la configuración siguiente" name="use_my_settings"/> - </radio_group> - <panel name="user_environment_settings"> - <text name="water_settings_title"> - Configuración de agua - </text> - <combo_box name="water_settings_preset_combo"> - <combo_box.item label="-Selecciona un valor predefinido-" name="item0"/> - </combo_box> - <text name="sky_dayc_settings_title"> - Cielo/Ciclo del dÃa - </text> - <radio_group name="sky_dayc_settings_radio_group"> - <radio_item label="Cielo invariable" name="my_sky_settings"/> - <radio_item label="Ciclo del dÃa" name="my_dayc_settings"/> - </radio_group> - <combo_box name="sky_settings_preset_combo"> - <combo_box.item label="-Selecciona un valor predefinido-" name="item0"/> - </combo_box> - <combo_box name="dayc_settings_preset_combo"> - <combo_box.item label="-Selecciona un valor predefinido-" name="item0"/> - </combo_box> - </panel> - <button label="Aplicar" name="apply_btn"/> - <button label="Cancelar" name="cancel_btn"/> + <string name="str_label_use_default"> + Usar la configuración predeterminada + </string> + <string name="str_label_use_region"> + Usar Configuración de la Región + </string> + <string name="str_altitude_desription"> + Cielo [INDEX]([ALTITUDE]m) + </string> + <string name="str_no_parcel"> + No se ha seleccionado ninguna parcela. Las opciones de entorno están desactivadas. + </string> + <string name="str_cross_region"> + Las opciones de entorno no están disponibles en las fronteras de regiones. + </string> + <string name="str_legacy"> + La configuración de entorno no está disponible en esta región. + </string> + <string name="str_disallowed"> + El administrador del estado no permite cambiar los entornos de parcela en esta región. + </string> + <string name="str_too_small"> + La parcela debe tener como mÃnimo 128 metros cuadrados para ser compatible con un entorno. + </string> + <string name="str_empty"> + (vacÃo) + </string> + <string name="str_region_env"> + (entorno de la región) + </string> + <layout_stack> + <layout_panel name="pnl_environment_disabled"> + <text name="txt_environment_disabled"> + ... + </text> + </layout_panel> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_current"> + <button label="[USEDEFAULT]" name="btn_usedefault"/> + <button label="Usar Inventario" name="btn_select_inventory"/> + <button label="Personalizar" name="btn_edit"/> + <check_box label="Los propietarios de parcelas pueden borrar el entorno" name="chk_allow_override"/> + </layout_panel> + <layout_panel name="pnl_environment_length"> + <text name="lbl_apparent_time"> + [HH]:[MM][AP] ([PRC]%) + </text> + </layout_panel> + <layout_panel name="pnl_environment_buttons"/> + </layout_stack> + </layout_panel> + <layout_panel name="pnl_environment_altitudes"> + <panel name="pnl_alt1"> + <text name="txt_alt1"> + Cielo [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt1"> + Desconocido + </line_editor> + <settings_drop_target name="sdt_alt1" tool_tip="Mover un parámetro desde el Inventario hasta este recuadro para seleccionarlo como cielo actual."/> + </panel> + <panel name="pnl_alt2"> + <text name="txt_alt2"> + Cielo [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt2"> + Desconocido + </line_editor> + <settings_drop_target name="sdt_alt2" tool_tip="Mover un parámetro desde el Inventario hasta este recuadro para seleccionarlo como cielo actual."/> + </panel> + <panel name="pnl_alt3"> + <text name="txt_alt3"> + Cielo [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt3"> + Desconocido + </line_editor> + <settings_drop_target name="sdt_alt3" tool_tip="Mover un parámetro desde el Inventario hasta este recuadro para seleccionarlo como cielo actual."/> + </panel> + <multi_slider initial_value="0" name="sld_altitudes"> + <slider name="sld1" value="1000"/> + <slider name="sld2" value="2000"/> + <slider name="sld3" value="3000"/> + </multi_slider> + <panel name="pnl_ground"> + <text name="txt_ground"> + Terreno + </text> + <line_editor name="edt_invname_ground"> + Desconocido + </line_editor> + <settings_drop_target name="sdt_ground" tool_tip="Mover un parámetro desde el Inventario hasta este recuadro para seleccionarlo como cielo a nivel del terreno."/> + </panel> + <panel name="pnl_water"> + <text name="txt_water"> + Agua + </text> + <line_editor name="edt_invname_water"> + Desconocido + </line_editor> + <settings_drop_target name="sdt_water" tool_tip="Mover un parámetro desde el Inventario hasta este recuadro para seleccionarlo como agua actual."/> + </panel> + <button label="Restablecer" name="btn_rst_altitudes" tool_tip="Restablecer altitudes predeterminadas"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> </panel> diff --git a/indra/newview/skins/default/xui/es/panel_region_estate.xml b/indra/newview/skins/default/xui/es/panel_region_estate.xml index b3ee34bbfd..4cfbffb887 100644 --- a/indra/newview/skins/default/xui/es/panel_region_estate.xml +++ b/indra/newview/skins/default/xui/es/panel_region_estate.xml @@ -26,17 +26,17 @@ <check_box label="Permitir el teleporte a cualquier punto" name="allow_direct_teleport"/> <button label="Aplicar" name="apply_btn"/> <text name="estate_manager_label"> - Administradores del estado: + Administradores de estado: </text> <text name="allow_resident_label"> - Siempre permitido: + Siempre autorizado: </text> <button label="Añadir..." name="add_estate_manager_btn"/> <button label="Quitar..." name="remove_estate_manager_btn"/> <button label="Añadir..." name="add_allowed_avatar_btn"/> <button label="Quitar..." name="remove_allowed_avatar_btn"/> <text name="allow_group_label"> - Grupos siempre permitidos: + Grupos siempre autorizados: </text> <text name="ban_resident_label"> Siempre prohibido: diff --git a/indra/newview/skins/default/xui/es/panel_settings_sky_atmos.xml b/indra/newview/skins/default/xui/es/panel_settings_sky_atmos.xml new file mode 100644 index 0000000000..bce312dc18 --- /dev/null +++ b/indra/newview/skins/default/xui/es/panel_settings_sky_atmos.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Atmósfera e Iluminación" name="panel_settings_sky_atmos"/> diff --git a/indra/newview/skins/default/xui/es/panel_settings_sky_clouds.xml b/indra/newview/skins/default/xui/es/panel_settings_sky_clouds.xml new file mode 100644 index 0000000000..0aa6f1e41a --- /dev/null +++ b/indra/newview/skins/default/xui/es/panel_settings_sky_clouds.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Nubes" name="panel_settings_sky_clouds"> + <layout_stack> + <layout_panel> + <slider label="X" name="cloud_density_x"/> + <slider label="Y" name="cloud_density_y"/> + <slider label="D" name="cloud_density_d"/> + <slider label="X" name="cloud_detail_x"/> + <slider label="Y" name="cloud_detail_y"/> + <slider label="D" name="cloud_detail_d"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/es/panel_settings_sky_density.xml b/indra/newview/skins/default/xui/es/panel_settings_sky_density.xml new file mode 100644 index 0000000000..743f901c7f --- /dev/null +++ b/indra/newview/skins/default/xui/es/panel_settings_sky_density.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Densidad" name="panel_settings_sky_density"> + <layout_stack> + <layout_panel> + <slider label="PerÃodo exponencial Rayleigh:" name="rayleigh_exponential"/> + <slider label="Escala exponencial Rayleigh:" name="rayleigh_exponential_scale"/> + <slider label="PerÃodo lineal Rayleigh:" name="rayleigh_linear"/> + <slider label="PerÃodo constante Rayleigh:" name="rayleigh_constant"/> + <slider label="Altitud máxima Rayleigh:" name="rayleigh_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="PerÃodo exponencial Mie:" name="mie_exponential"/> + <slider label="Escala exponencial Mie:" name="mie_exponential_scale"/> + <slider label="PerÃodo lineal Mie:" name="mie_linear"/> + <slider label="PerÃodo constante Mie:" name="mie_constant"/> + <slider label="Factor Aniso Mie:" name="mie_aniso_factor"/> + <slider label="Altitud máxima Mie:" name="mie_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="PerÃodo exponencial de Absorción:" name="absorption_exponential"/> + <slider label="Escala exponencial de Absorción:" name="absorption_exponential_scale"/> + <slider label="PerÃodo lineal de Absorción:" name="absorption_linear"/> + <slider label="PerÃodo constante de Absorción:" name="absorption_constant"/> + <slider label="Altitud máxima de Absorción:" name="absorption_max_altitude"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/es/panel_settings_sky_sunmoon.xml b/indra/newview/skins/default/xui/es/panel_settings_sky_sunmoon.xml new file mode 100644 index 0000000000..77db745755 --- /dev/null +++ b/indra/newview/skins/default/xui/es/panel_settings_sky_sunmoon.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Sol y Luna" name="panel_settings_sky_hbodies"> + <layout_stack> + <layout_panel name="sun_layout"> + <check_box label="Mostrar baliza" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <layout_stack> + <layout_panel name="moon_layout"> + <check_box label="Mostrar baliza" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/es/panel_settings_water.xml b/indra/newview/skins/default/xui/es/panel_settings_water.xml new file mode 100644 index 0000000000..c0d0cb5636 --- /dev/null +++ b/indra/newview/skins/default/xui/es/panel_settings_water.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Agua" name="panel_settings_water"> + <layout_stack name="water_stack1"> + <layout_panel> + <text name="FresnelOffsetText"> + Compensación Fresnel: + </text> + </layout_panel> + <layout_panel> + <layout_stack name="water_stack2"> + <layout_panel> + <slider label="X:" name="water_normal_scale_x"/> + <slider label="Y:" name="water_normal_scale_y"/> + <slider label="Z:" name="water_normal_scale_z"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/es/panel_tools_texture.xml b/indra/newview/skins/default/xui/es/panel_tools_texture.xml index 6ab95b9f5d..fb1aa50198 100644 --- a/indra/newview/skins/default/xui/es/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/es/panel_tools_texture.xml @@ -1,11 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Textura" name="Texture"> - <panel.string name="string repeats per meter"> - Repeticiones por metro - </panel.string> - <panel.string name="string repeats per face"> - Repeticiones por cara - </panel.string> <text name="color label"> Color </text> @@ -114,4 +108,5 @@ <spinner label="Desplazamiento horizontal" name="shinyOffsetU"/> <spinner label="Desplazamiento vertical" name="shinyOffsetV"/> <check_box initial_value="false" label="Alinear caras del plano" name="checkbox planar align" tool_tip="Alinear texturas en todas las caras seleccionadas con la última cara seleccionada. Requiere la representación de texturas en el plano."/> + <button label="Centrar" label_selected="Alinear capas de textura actuales" name="button align textures" tool_tip="Alinear capas de textura actuales"/> </panel> diff --git a/indra/newview/skins/default/xui/es/role_actions.xml b/indra/newview/skins/default/xui/es/role_actions.xml index 80379da064..cfa37432a8 100644 --- a/indra/newview/skins/default/xui/es/role_actions.xml +++ b/indra/newview/skins/default/xui/es/role_actions.xml @@ -33,6 +33,7 @@ <action description="Cambiar música y configuraciones de los media" longdescription="Cambiar la música en streaming y las configuraciones de vÃdeo en Acerca del terreno > pestaña Media." name="land change media" value="20"/> <action description="Activar/desactivar 'Editar el terreno'" longdescription="Activar/desactivar 'Editar el terreno'. *AVISO* Acerca del terreno > pestaña Opciones > Editar el terreno, permite a cualquiera alterar la forma de su terreno y sustituir y mover plantas Linden. Asegúrese de lo que está haciendo antes de otorgar esta capacidad. La edición del terreno se activada/desactiva en Acerca del terreno > pestaña Opciones." name="land edit" value="21"/> <action description="Activar/desactivar varios Ãtems de Acerca del terreno > Opciones" longdescription="Cambia 'Seguro (sin daño)', 'Volar', y el permitir a otros residentes en terrenos propiedad del grupo 'Modificar el terreno', 'Construir', 'Crear hitos' y 'Ejecutat scripts', como aparece en Acerca del terreno > pestaña Opciones." name="land options" value="22"/> + <action description="Modificar configuración del entorno y ciclo del dÃa" longdescription="Cambiar la configuración de entorno y el ciclo del dÃa desde la pestaña Acerca del terreno > Entorno" name="land change environment" value="46"/> </action_set> <action_set description="Estas capacidades incluyen poderes que permiten a los miembros rebasar las restricciones de parcelas pertenecientes al grupo." name="Parcel Powers"> <action description="Permitir siempre 'Editar el terreno'" longdescription="Quien tenga un rol con esta capacidad puede editar el terreno de una parcela perteneciente al grupo aunque eso esté desactivado en Acerca del terreno > pestaña Opciones." name="land allow edit land" value="23"/> diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml index c9bfbd6610..f5e7d0bf4e 100644 --- a/indra/newview/skins/default/xui/es/strings.xml +++ b/indra/newview/skins/default/xui/es/strings.xml @@ -630,6 +630,15 @@ Intenta iniciar sesión de nuevo en unos instantes. <string name="BUTTON_HELP"> Ver la Ayuda </string> + <string name="TooltipNotecardNotAllowedTypeDrop"> + Los objetos de este tipo no se pueden adjuntar +a las notas de esta región. + </string> + <string name="TooltipNotecardOwnerRestrictedDrop"> + Sólo los objetos con permisos +«próximo propietario» sin restricciones +pueden adjuntarse a las notas. + </string> <string name="Searching"> Buscando... </string> @@ -706,6 +715,18 @@ Intenta iniciar sesión de nuevo en unos instantes. Error en la solicitud de carga. Por favor, ingresa a http://secondlife.com/support para obtener ayuda sobre cómo solucionar este problema. </string> + <string name="SettingValidationError"> + Error en la validación para importar los parámetros [NAME] + </string> + <string name="SettingImportFileError"> + No se pudo abrir el archivo [FILE] + </string> + <string name="SettingParseFileError"> + No se pudo abrir el archivo [FILE] + </string> + <string name="SettingTranslateError"> + No se pudo traducir el Viento de luz legado [NAME] + </string> <string name="texture"> la textura </string> @@ -781,6 +802,9 @@ http://secondlife.com/support para obtener ayuda sobre cómo solucionar este pro <string name="symbolic folder link"> enlace de la carpeta </string> + <string name="settings blob"> + opciones + </string> <string name="mesh"> red </string> @@ -1108,6 +1132,9 @@ http://secondlife.com/support para obtener ayuda sobre cómo solucionar este pro <string name="ForceSitAvatar"> Forzar que el avatar se siente </string> + <string name="ChangeEnvSettings"> + Cambiar tu configuración del entorno + </string> <string name="AgentNameSubst"> (Tú) </string> @@ -1256,6 +1283,9 @@ http://secondlife.com/support para obtener ayuda sobre cómo solucionar este pro <string name="tattoo"> Tatuaje </string> + <string name="universal"> + Universal + </string> <string name="physics"> FÃsica </string> @@ -1298,6 +1328,9 @@ http://secondlife.com/support para obtener ayuda sobre cómo solucionar este pro <string name="tattoo_not_worn"> Tatuaje no puesto </string> + <string name="universal_not_worn"> + Universal no puesto + </string> <string name="physics_not_worn"> FÃsica no puesta </string> @@ -1349,6 +1382,9 @@ http://secondlife.com/support para obtener ayuda sobre cómo solucionar este pro <string name="create_new_tattoo"> Crear un tatuaje nuevo </string> + <string name="create_new_universal"> + Crear unos guantes nuevos + </string> <string name="create_new_physics"> Crear nueva fÃsica </string> @@ -1592,11 +1628,14 @@ Si sigues recibiendo el mismo mensaje, solicita ayuda al personal de asistencia <string name="MarketplaceUpdating"> actualizando... </string> + <string name="UploadFeeInfo"> + Las tasas se basan en tu nivel de suscripción. Niveles más altos tienen tasas más bajas. [https://secondlife.com/my/account/membership.php? Aprende más al respecto] + </string> <string name="Open landmarks"> - Abrir hitos + Abrir puntos destacados </string> <string name="Unconstrained"> - Sin restricciones + Sin Restricciones </string> <string name="no_transfer" value="(no transferible)"/> <string name="no_modify" value="(no modificable)"/> @@ -2484,6 +2523,27 @@ Si sigues recibiendo el mismo mensaje, solicita ayuda al personal de asistencia <string name="RegionSettings"> Configuración de la región </string> + <string name="NoEnvironmentSettings"> + Esta región no es compatible con las opciones de entorno. + </string> + <string name="EnvironmentSun"> + Sol + </string> + <string name="EnvironmentMoon"> + Luna + </string> + <string name="EnvironmentBloom"> + Florecimiento + </string> + <string name="EnvironmentCloudNoise"> + Ruido de nubes + </string> + <string name="EnvironmentNormalMap"> + Vista Normal + </string> + <string name="EnvironmentTransparent"> + Transparente + </string> <string name="ClassifiedClicksTxt"> Clics: [TELEPORT] teleportes, [MAP] mapa, [PROFILE] perfil </string> @@ -4640,6 +4700,9 @@ Denuncia de infracción <string name="New Tattoo"> Tatuaje nuevo </string> + <string name="New Universal"> + Nuevo Universal + </string> <string name="New Physics"> Nueva fÃsica </string> @@ -4766,6 +4829,15 @@ Denuncia de infracción <string name="Female - Wow"> Mujer - Admiración </string> + <string name="New Daycycle"> + Nuevo Ciclo del dÃa + </string> + <string name="New Water"> + Nueva Agua + </string> + <string name="New Sky"> + Nuevo Cielo + </string> <string name="/bow"> /reverencia </string> @@ -5294,6 +5366,12 @@ Inténtalo incluyendo la ruta de acceso al editor entre comillas <string name="BeaconMedia"> Viendo balizas de medios (blancas) </string> + <string name="BeaconSun"> + Visualización de la baliza de dirección del sol (naranja) + </string> + <string name="BeaconMoon"> + Visualización de la baliza de dirección de la luna (violeta) + </string> <string name="ParticleHiding"> Ocultando las partÃculas </string> @@ -5321,6 +5399,12 @@ Inténtalo incluyendo la ruta de acceso al editor entre comillas <string name="Command_Destinations_Label"> Destinos </string> + <string name="Command_Environments_Label"> + Mis entornos + </string> + <string name="Command_Facebook_Label"> + Facebook + </string> <string name="Command_Flickr_Label"> Flickr </string> @@ -5414,6 +5498,12 @@ Inténtalo incluyendo la ruta de acceso al editor entre comillas <string name="Command_Destinations_Tooltip"> Destinos de interés </string> + <string name="Command_Environments_Tooltip"> + Mis entornos + </string> + <string name="Command_Facebook_Tooltip"> + Publicar en Facebook + </string> <string name="Command_Flickr_Tooltip"> Subir a Flickr </string> @@ -5609,6 +5699,12 @@ Inténtalo incluyendo la ruta de acceso al editor entre comillas <string name="ExperiencePermission12"> aceptar automáticamente permisos de experiencias </string> + <string name="ExperiencePermission16"> + forzar que el avatar se siente + </string> + <string name="ExperiencePermission17"> + cambiar tu configuración del entorno + </string> <string name="ExperiencePermissionShortUnknown"> realizar una operación desconocida: [Permission] </string> @@ -5633,6 +5729,12 @@ Inténtalo incluyendo la ruta de acceso al editor entre comillas <string name="ExperiencePermissionShort12"> Otorgar permisos </string> + <string name="ExperiencePermissionShort16"> + Sentarte + </string> + <string name="ExperiencePermissionShort17"> + Entorno + </string> <string name="logging_calls_disabled_log_empty"> No se están registrando las conversaciones. Para empezar a grabar un registro, elige "Guardar: Solo registro" o "Guardar: Registro y transcripciones" en Preferencias > Chat. </string> diff --git a/indra/newview/skins/default/xui/fr/floater_about_land.xml b/indra/newview/skins/default/xui/fr/floater_about_land.xml index 219857eb99..fe863fc565 100644 --- a/indra/newview/skins/default/xui/fr/floater_about_land.xml +++ b/indra/newview/skins/default/xui/fr/floater_about_land.xml @@ -366,10 +366,10 @@ Seules les parcelles de grande taille peuvent apparaître dans la recherche. Photo : </text> <texture_picker label="" name="snapshot_ctrl" tool_tip="Cliquez pour sélectionner une image"/> - <text name="allow_see_label"> + <text name="allow_see_label" top="170"> Les avatars sur d'autres parcelles peuvent voir et chatter avec les avatars sur cette parcelle. </text> - <check_box label="Voir les avatars" name="SeeAvatarsCheck" tool_tip="Permettre aux avatars présents sur d'autres parcelles de voir et chatter avec les avatars présents sur cette parcelle et à vous de les voir et de chatter avec eux."/> + <check_box label="Voir les avatars" name="SeeAvatarsCheck" top="170" tool_tip="Permettre aux avatars présents sur d'autres parcelles de voir et chatter avec les avatars présents sur cette parcelle et à vous de les voir et de chatter avec eux."/> <text name="landing_point"> Lieu d'arrivée : [LANDING] </text> @@ -449,7 +449,7 @@ musique : <panel.string name="estate_override"> Au moins une de ces options est définie au niveau du domaine. </panel.string> - <check_box label="Tout le monde peut rendre visite (Des lignes d'interdiction seront créées si cette case n'est pas cochée)" name="public_access"/> + <check_box label="Tout le monde peut rendre visite" tool_tip="Des lignes d'interdiction seront créées si cette case n'est pas cochée" name="public_access"/> <check_box label="Doit avoir plus de 18 ans [ESTATE_AGE_LIMIT]" name="limit_age_verified" tool_tip="Pour accéder à cette parcelle, les résidents doivent avoir au moins 18 ans. Consultez le [SUPPORT_SITE] pour plus d'informations."/> <check_box label="Les infos de paiement doivent être enregistrées dans le dossier [ESTATE_PAYMENT_LIMIT]" name="limit_payment" tool_tip="Pour pouvoir accéder à cette parcelle, les résidents doivent avoir enregistré des informations de paiement. Consultez le [SUPPORT_SITE] pour plus d'informations."/> <check_box label="Autoriser le groupe [GROUP] sans restrictions" name="GroupCheck" tool_tip="Définir le groupe à l'onglet Général."/> @@ -484,5 +484,6 @@ musique : </panel> </panel> <panel label="EXPÉRIENCES" name="land_experiences_panel"/> + <panel label="ENVIRONNEMENT" name="land_environment_panel"/> </tab_container> </floater> diff --git a/indra/newview/skins/default/xui/fr/floater_adjust_environment.xml b/indra/newview/skins/default/xui/fr/floater_adjust_environment.xml new file mode 100644 index 0000000000..ca5b0ec948 --- /dev/null +++ b/indra/newview/skins/default/xui/fr/floater_adjust_environment.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_adjust_snapshot" title="Éclairage personnel"> + <layout_stack name="outer_stack"> + <layout_panel name="env_controls"> + <layout_stack name="settings_stack"> + <layout_panel> + <button label="Réinitialiser" name="btn_reset" tool_tip="Fermer et réinitialiser vers l'environnement partagé"/> + <text name="cloud_map_label"> + Image du nuage : + </text> + </layout_panel> + <layout_panel> + <text name="label"> + Soleil : + </text> + <check_box label="Afficher la balise" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <check_box label="Afficher la balise" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/fr/floater_beacons.xml b/indra/newview/skins/default/xui/fr/floater_beacons.xml index ebd4dab683..c6adf67bac 100644 --- a/indra/newview/skins/default/xui/fr/floater_beacons.xml +++ b/indra/newview/skins/default/xui/fr/floater_beacons.xml @@ -18,5 +18,7 @@ <check_box label="Sources sonores" name="sounds"/> <check_box label="Sources des particules" name="particles"/> <check_box label="Sources des médias" name="moapbeacon"/> + <check_box label="Soleil" name="sun"/> + <check_box label="Lune" name="moon"/> </panel> </floater> diff --git a/indra/newview/skins/default/xui/fr/floater_bulk_perms.xml b/indra/newview/skins/default/xui/fr/floater_bulk_perms.xml index 02b58f9b36..09186b6777 100644 --- a/indra/newview/skins/default/xui/fr/floater_bulk_perms.xml +++ b/indra/newview/skins/default/xui/fr/floater_bulk_perms.xml @@ -30,6 +30,7 @@ <icon name="icon_sound" tool_tip="Sons"/> <check_box label="Textures" name="check_texture"/> <icon name="icon_texture" tool_tip="Textures"/> + <icon name="icon_setting" tool_tip="Paramètres d'environnement"/> <button label="√ Tout" label_selected="Tout" name="check_all"/> <button label="Effacer" label_selected="Aucun" name="check_none"/> <text name="newperms"> diff --git a/indra/newview/skins/default/xui/fr/floater_buy_currency.xml b/indra/newview/skins/default/xui/fr/floater_buy_currency.xml index 148a5a35d2..55b0d1825a 100644 --- a/indra/newview/skins/default/xui/fr/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/fr/floater_buy_currency.xml @@ -60,8 +60,7 @@ le Lindex... </text> <button label="Acheter" name="buy_btn"/> <button label="Annuler" name="cancel_btn"/> - <text left="5" name="info_cannot_buy" right="-5" width="200"> + <floater.string name="info_cannot_buy" left="160" width="200"> Achat impossible - </text> - <button label="Accéder au Web" name="error_web"/> + </floater.string> </floater> diff --git a/indra/newview/skins/default/xui/fr/floater_delete_env_preset.xml b/indra/newview/skins/default/xui/fr/floater_delete_env_preset.xml deleted file mode 100644 index c666a25c10..0000000000 --- a/indra/newview/skins/default/xui/fr/floater_delete_env_preset.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<floater name="Delete Env Preset" title="SUPPRIMER PRÉRÉGLAGE ENV."> - <string name="title_water"> - Supprimer un préréglage de l'eau - </string> - <string name="title_sky"> - Supprimer un préréglage du ciel - </string> - <string name="title_day_cycle"> - Supprimer un cycle du jour - </string> - <string name="label_water"> - Préréglage : - </string> - <string name="label_sky"> - Préréglage : - </string> - <string name="label_day_cycle"> - Cycle du jour : - </string> - <string name="msg_confirm_deletion"> - Voulez-vous vraiment supprimer le préréglage sélectionné ? - </string> - <string name="msg_sky_is_referenced"> - Impossible de supprimer un préréglage référencé dans un ou plusieurs cycles du jour. - </string> - <string name="combo_label"> - -Sélectionner un préréglage- - </string> - <text name="label"> - Préréglage : - </text> - <button label="Supprimer" name="delete"/> - <button label="Annuler" name="cancel"/> -</floater> diff --git a/indra/newview/skins/default/xui/fr/floater_edit_ext_day_cycle.xml b/indra/newview/skins/default/xui/fr/floater_edit_ext_day_cycle.xml new file mode 100644 index 0000000000..7e8e76fd5a --- /dev/null +++ b/indra/newview/skins/default/xui/fr/floater_edit_ext_day_cycle.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_edit_extdaycycle" title="Modifier un cycle du jour"> + <string name="title_new"> + Créer un nouveau cycle du jour + </string> + <string name="title_edit"> + Modifier un cycle du jour + </string> + <string name="hint_new"> + Donner un nom au cycle du jour, ajuster les contrôles afin de le créer, puis cliquez sur « Enregistrer ». + </string> + <string name="hint_edit"> + Pour modifier le cycle du jour, ajustez les contrôles ci-dessous, puis cliquez sur « Enregistrer ». + </string> + <string name="time_label"> + ([HH]:[MM]) + </string> + <string name="sky_track_label"> + Ciel [ALT] + </string> + <string name="sky_label"> + Ciel + </string> + <string name="water_label"> + Eau + </string> + <string name="commit_parcel"> + Appliquer à la parcelle + </string> + <string name="commit_region"> + Appliquer à la région + </string> + <layout_stack name="outer_stack"> + <layout_panel name="name_and_import"> + <text name="label"> + Nom du cycle du jour : + </text> + <button label="Importer" name="btn_import" tool_tip="Importer les paramètres hérités du disque."/> + </layout_panel> + <layout_panel name="content"> + <layout_stack name="content_stack"> + <layout_panel name="timeline_track_selection"> + <panel name="timeline_layers"> + <button label="Ciel 4" name="sky4_track"/> + <button label="Ciel 3" name="sky3_track"/> + <button label="Ciel 2" name="sky2_track"/> + <button label="Niveau du sol" name="sky1_track"/> + <button label="Eau" name="water_track"/> + </panel> + <panel name="timeline"> + <text name="p0" value="0%[DSC]"/> + <text name="p1" value="25%[DSC]"/> + <text name="p2" value="50%[DSC]"/> + <text name="p3" value="75%[DSC]"/> + <text name="p4" value="100%[DSC]"/> + <multi_slider initial_value="0" name="WLTimeSlider"/> + <multi_slider initial_value="0" name="WLDayCycleFrames"/> + <text name="current_time" value="[PRCNT]%[DSC]"/> + <layout_stack> + <layout_panel> + <button label="Cloner la piste à partir" name="copy_track"/> + <button label="Charger la piste à partir" name="load_track"/> + <button label="Effacer la piste" name="clear_track"/> + </layout_panel> + <layout_panel> + <layout_stack name="progress_control"> + <layout_panel name="skip_back"> + <button name="skip_back_btn" tool_tip="Reculer"/> + </layout_panel> + <layout_panel name="skip_forward"> + <button name="skip_forward_btn" tool_tip="Avancer"/> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel> + <button label="Ajouter [FRAME]" name="add_frame"/> + <button label="Charger [FRAME]" name="btn_load_frame"/> + <button label="Annuler [FRAME]" name="delete_frame"/> + </layout_panel> + </layout_stack> + </panel> + </layout_panel> + <layout_panel name="frame_edit_controls"> + <text name="icn_lock_edit"> + Sélectionnez un cadre clé à partir du calendrier ci-dessus pour modifier les paramètres. + </text> + </layout_panel> + <layout_panel name="frame_settings_water"> + <tab_container name="water_tabs"> + <panel label="Eau" name="water_panel"/> + </tab_container> + </layout_panel> + <layout_panel name="frame_settings_sky"> + <tab_container name="sky_tabs"> + <panel label="Atmosphère et éclairage" name="atmosphere_panel"/> + <panel label="Nuages" name="clouds_panel"/> + <panel label="Soleil et lune" name="moon_panel"/> + </tab_container> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel name="buttons"> + <button label="Enregistrer" name="save_btn"/> + <button label="Annuler" name="cancel_btn"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/fr/floater_fixedenvironment.xml b/indra/newview/skins/default/xui/fr/floater_fixedenvironment.xml new file mode 100644 index 0000000000..515a1d2843 --- /dev/null +++ b/indra/newview/skins/default/xui/fr/floater_fixedenvironment.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="Fixed Environment" title="Environnement fixe"> + <string name="edit_sky"> + Modifier le ciel : + </string> + <string name="edit_water"> + Modifier l'eau + </string> + <layout_stack name="floater_stack"> + <layout_panel name="info_panel"> + <button label="Charger" name="btn_load" tool_tip="Charger des paramètres à partir de l'inventaire"/> + <button label="Importer" name="btn_import" tool_tip="Importer les paramètres hérités du disque."/> + </layout_panel> + <layout_panel name="button_panel"> + <layout_stack name="button_bar_ls"> + <layout_panel name="save_btn_lp"> + <button label="Enregistrer" name="btn_commit"/> + </layout_panel> + <layout_panel name="revert_btn_lp"> + <button label="Annuler" name="btn_cancel" tool_tip="Rétablir la dernière version enregistrée"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/fr/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/fr/floater_inventory_view_finder.xml index 471dddf448..4e20431cc4 100644 --- a/indra/newview/skins/default/xui/fr/floater_inventory_view_finder.xml +++ b/indra/newview/skins/default/xui/fr/floater_inventory_view_finder.xml @@ -12,6 +12,7 @@ <check_box label="Sons" name="check_sound"/> <check_box label="Textures" name="check_texture"/> <check_box label="Photos" name="check_snapshot"/> + <check_box label="Paramètres" name="check_settings"/> <button label="Tout" label_selected="Tout" name="All"/> <button bottom_delta="0" label="Aucun" label_selected="Aucun" name="None"/> <check_box label="Toujours montrer les dossiers" name="check_show_empty"/> diff --git a/indra/newview/skins/default/xui/fr/floater_merchant_outbox.xml b/indra/newview/skins/default/xui/fr/floater_merchant_outbox.xml deleted file mode 100644 index 0f657e9e5b..0000000000 --- a/indra/newview/skins/default/xui/fr/floater_merchant_outbox.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="floater_merchant_outbox" title="BOÃŽTE D'ENVOI VENDEUR"> - <string name="OutboxFolderCount1"> - 1 dossier - </string> - <string name="OutboxFolderCountN"> - [NUM] dossiers - </string> - <string name="OutboxImporting"> - Envoi de dossiers... - </string> - <string name="OutboxInitializing"> - Initialisation... - </string> - <panel label="" name="panel_1"> - <panel name="panel_2"> - <panel name="outbox_inventory_placeholder_panel"> - <text name="outbox_inventory_placeholder_title"> - Chargement... - </text> - </panel> - </panel> - <panel name="panel_3"> - <panel name="outbox_generic_drag_target"> - <text name="text_1"> - Faites glisser des éléments ici pour créer des dossiers - </text> - </panel> - <button label="Envoyer vers la Place du marché" name="outbox_import_btn" tool_tip="Vers ma vitrine de la Place du marché"/> - </panel> - </panel> -</floater> diff --git a/indra/newview/skins/default/xui/fr/floater_my_environments.xml b/indra/newview/skins/default/xui/fr/floater_my_environments.xml new file mode 100644 index 0000000000..5ee6e2d5fd --- /dev/null +++ b/indra/newview/skins/default/xui/fr/floater_my_environments.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater label="Endroits" name="my_environments" title="MES ENVIRONNEMENTS"> + <layout_stack> + <layout_panel label="Filtres" name="filter_panel"> + <check_box label="Jours" name="chk_days"/> + <check_box label="Ciels" name="chk_skies"/> + <check_box label="Eau" name="chk_water"/> + <filter_editor label="Filtrer les environnements" name="flt_search"/> + </layout_panel> + <layout_panel label="Environnements" name="list_panel"> + <panel label="pnl_inv_wrap" name="pnl_inv_wrap"/> + </layout_panel> + <layout_panel> + <check_box initial_value="false" label="Afficher tous les dossiers" name="chk_showfolders"/> + </layout_panel> + <layout_panel name="pnl_control"> + <panel label="bottom_panel" name="pnl_bottom"> + <menu_button name="btn_gear" tool_tip="Plus d'options"/> + <menu_button name="btn_newsettings" tool_tip="Créer un nouveau paramètre"/> + <button name="btn_del" tool_tip="Supprimer l'article sélectionné"/> + </panel> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/fr/floater_perms_default.xml b/indra/newview/skins/default/xui/fr/floater_perms_default.xml index 1cea8e55cc..ef56ce5663 100644 --- a/indra/newview/skins/default/xui/fr/floater_perms_default.xml +++ b/indra/newview/skins/default/xui/fr/floater_perms_default.xml @@ -37,6 +37,10 @@ <text name="label_12" tool_tip="Définir les droits par défaut pour la création d’habits ou de parties de corps"> Articles à porter </text> + <text name="label_13" tool_tip="Définir les autorisations par défaut pour la création des paramètres environnementaux"> + Paramètres + </text> + <check_box name="env_settings_c" value="true"/> </panel> <button label="OK" label_selected="OK" name="ok"/> <button label="Annuler" label_selected="Annuler" name="cancel"/> diff --git a/indra/newview/skins/default/xui/fr/floater_pick_track.xml b/indra/newview/skins/default/xui/fr/floater_pick_track.xml new file mode 100644 index 0000000000..46731bcec7 --- /dev/null +++ b/indra/newview/skins/default/xui/fr/floater_pick_track.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="track picker" title="CHOISIR : PISTE"> + <layout_stack name="adjuster"> + <layout_panel name="pnl_desc"> + <text name="select_description"> + Sélectionner la source du ciel : + </text> + </layout_panel> + <layout_panel name="pnl_traks"> + <radio_group name="track_selection"> + <radio_item label="Ciel4 [ALT]" name="radio_sky4" value="4"/> + <radio_item label="Ciel3 [ALT]" name="radio_sky3" value="3"/> + <radio_item label="Ciel2 [ALT]" name="radio_sky2" value="2"/> + <radio_item label="Sol" name="radio_sky1" value="1"/> + </radio_group> + </layout_panel> + <layout_panel name="pnl_ok_cancel"> + <button label="OK" label_selected="OK" name="btn_select"/> + <button label="Annuler" label_selected="Annuler" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/fr/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/fr/floater_preferences_graphics_advanced.xml index fd47254934..42af9c526d 100644 --- a/indra/newview/skins/default/xui/fr/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/fr/floater_preferences_graphics_advanced.xml @@ -82,7 +82,6 @@ <check_box initial_value="true" label="Eau transparente" name="TransparentWater"/> <check_box initial_value="true" label="Placage de relief et brillance" name="BumpShiny"/> <check_box initial_value="true" label="Lumières locales" name="LocalLights"/> - <check_box initial_value="true" label="Effets de base" name="BasicShaders" tool_tip="La désactivation de cette option peut éviter le plantage de certains pilotes de cartes graphiques"/> <slider label="Rendu du terrain :" name="TerrainDetail"/> <text name="TerrainDetailText"> Faible diff --git a/indra/newview/skins/default/xui/fr/floater_preview_texture.xml b/indra/newview/skins/default/xui/fr/floater_preview_texture.xml index 9fc9d14026..d63d9903ec 100644 --- a/indra/newview/skins/default/xui/fr/floater_preview_texture.xml +++ b/indra/newview/skins/default/xui/fr/floater_preview_texture.xml @@ -10,12 +10,12 @@ Description : </text> <text name="dimensions"> - [WIDTH] px x [HEIGHT] px + [WIDTH]px x [HEIGHT]px </text> <text name="aspect_ratio"> - Aperçu du rapport hauteur/largeur + Rapport d'aspect fixe </text> - <combo_box name="combo_aspect_ratio" tool_tip="Aperçu avec un rapport hauteur/largeur fixe"> + <combo_box name="combo_aspect_ratio" tool_tip="Prévisualiser avec un rapport d'aspect fixe"> <combo_item name="Unconstrained"> Sans contraintes </combo_item> diff --git a/indra/newview/skins/default/xui/fr/floater_settings_picker.xml b/indra/newview/skins/default/xui/fr/floater_settings_picker.xml new file mode 100644 index 0000000000..b75d8c6b8d --- /dev/null +++ b/indra/newview/skins/default/xui/fr/floater_settings_picker.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="settings picker" title="CHOISIR : PARAMÈTRES"> + <floater.string name="pick title"> + Choisir : + </floater.string> + <floater.string name="pick_track"> + SÉLECTIONNER UNE PISTE + </floater.string> + <floater.string name="pick_settings"> + SÉLECTIONNEZ LES PARAMÈTRES + </floater.string> + <floater.string name="track_water"> + Eau + </floater.string> + <floater.string name="track_ground"> + Sol + </floater.string> + <floater.string name="track_sky"> + Ciel[NUM] + </floater.string> + <layout_stack name="test_stack"> + <layout_panel name="inv_list"> + <filter_editor label="Filtrer les textures" name="flt_inventory_search"/> + </layout_panel> + <layout_panel name="temp"> + <button label="OK" label_selected="OK" name="btn_select"/> + <button label="Annuler" label_selected="Annuler" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/fr/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/fr/floater_texture_ctrl.xml index eace67026c..a4de7954c5 100644 --- a/indra/newview/skins/default/xui/fr/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/fr/floater_texture_ctrl.xml @@ -9,18 +9,14 @@ <text name="Multiple"> Textures multiples </text> - <radio_group name="mode_selection"> - <radio_item label="Inventaire" name="inventory" value="0"/> - <radio_item label="Local" name="local" value="1"/> - </radio_group> - <text name="unknown"> - Taille : [DIMENSIONS] - </text> + <combo_box name="mode_selection"> + <combo_box.item label="Inventaire" name="inventory" value="0"/> + <combo_box.item label="Local" name="local" value="1"/> + </combo_box> <button label="Défaut" label_selected="Défaut" name="Default" width="60"/> <button label="Vierge" label_selected="Vierge" name="Blank" width="60"/> <button label="Aucune" label_selected="Aucune" left="68" name="None" width="60"/> <button bottom="-240" label="" label_selected="" name="Pipette"/> - <check_box initial_value="true" label="Appliquer maintenant" name="apply_immediate_check"/> <text name="preview_disabled" value="Aperçu désactivé"/> <filter_editor label="Filtrer les textures" name="inventory search editor"/> <check_box initial_value="false" label="Afficher les dossiers" name="show_folders_check"/> @@ -31,6 +27,22 @@ <column label="Nom" name="unit_name"/> <column label="ID" name="unit_id_HIDDEN"/> </scroll_list> + <combo_box name="l_bake_use_texture_combo_box" tool_tip="Choisir la texture mixte"> + <combo_box.item label="Aucun" name="None"/> + <combo_box.item label="BAKED_HEAD" name="BAKED_HEAD"/> + <combo_box.item label="BAKED_UPPER" name="BAKED_UPPER"/> + <combo_box.item label="BAKED_LOWER" name="BAKED_LOWER"/> + <combo_box.item label="BAKED_EYES" name="BAKED_EYES"/> + <combo_box.item label="BAKED_SKIRT" name="BAKED_SKIRT"/> + <combo_box.item label="BAKED_HAIR" name="BAKED_HAIR"/> + <combo_box.item label="BAKED_LEFTARM" name="BAKED_LEFTARM"/> + <combo_box.item label="BAKED_LEFTLEG" name="BAKED_LEFTLEG"/> + <combo_box.item label="BAKED_AUX1" name="BAKED_AUX1"/> + <combo_box.item label="BAKED_AUX2" name="BAKED_AUX2"/> + <combo_box.item label="BAKED_AUX3" name="BAKED_AUX3"/> + </combo_box> + <check_box initial_value="false" label="Masquer la région maillée de base" name="hide_base_mesh_region"/> <button label="OK" label_selected="OK" name="Select"/> <button label="Annuler" label_selected="Annuler" name="Cancel"/> + <check_box initial_value="true" label="Appliquer maintenant" name="apply_immediate_check"/> </floater> diff --git a/indra/newview/skins/default/xui/fr/menu_cof_attachment.xml b/indra/newview/skins/default/xui/fr/menu_cof_attachment.xml index a4ead48b6b..32bc564d72 100644 --- a/indra/newview/skins/default/xui/fr/menu_cof_attachment.xml +++ b/indra/newview/skins/default/xui/fr/menu_cof_attachment.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="COF Attachment"> + <menu_item_call label="Toucher" name="touch_attach" /> + <menu_item_call label="Modifier" name="edit_item" /> <menu_item_call label="Détacher" name="detach"/> </context_menu> diff --git a/indra/newview/skins/default/xui/fr/menu_inventory.xml b/indra/newview/skins/default/xui/fr/menu_inventory.xml index c8bd7dc130..5d66d0998b 100644 --- a/indra/newview/skins/default/xui/fr/menu_inventory.xml +++ b/indra/newview/skins/default/xui/fr/menu_inventory.xml @@ -10,7 +10,6 @@ <menu_item_call label="Activer" name="Marketplace Activate"/> <menu_item_call label="Désactiver" name="Marketplace Deactivate"/> <menu_item_call label="Partager" name="Share"/> - <menu_item_call label="Acheter" name="Task Buy"/> <menu_item_call label="Ouvrir" name="Task Open"/> <menu_item_call label="Jouer" name="Task Play"/> <menu_item_call label="Propriétés" name="Task Properties"/> @@ -34,6 +33,7 @@ <menu_item_call label="Nouveau caleçon" name="New Underpants"/> <menu_item_call label="Nouveau masque alpha" name="New Alpha Mask"/> <menu_item_call label="Nouveau tatouage" name="New Tattoo"/> + <menu_item_call label="Nouvel environnement universel" name="New Universal"/> <menu_item_call label="Nouvelles propriétés physiques" name="New Physics"/> </menu> <menu label="Nouvelles parties du corps" name="New Body Parts"> @@ -42,6 +42,11 @@ <menu_item_call label="Nouveaux cheveux" name="New Hair"/> <menu_item_call label="Nouveaux yeux" name="New Eyes"/> </menu> + <menu label="Nouveaux paramètres" name="New Settings"> + <menu_item_call label="Nouveau ciel" name="New Sky"/> + <menu_item_call label="Nouvelle eau" name="New Water"/> + <menu_item_call label="Nouveau cycle du jour" name="New Day Cycle"/> + </menu> <menu label="Utiliser comme défaut pour" name="upload_def"> <menu_item_call label="Chargements d’images" name="Image uploads"/> <menu_item_call label="Chargements de sons" name="Sound uploads"/> @@ -100,9 +105,12 @@ <menu_item_call label="Porter" name="Wearable And Object Wear"/> <menu label="Attacher à " name="Attach To"/> <menu label="Attacher au HUD " name="Attach To HUD"/> + <menu_item_call label="Toucher" name="Attachment Touch" /> <menu_item_call label="Modifier" name="Wearable Edit"/> <menu_item_call label="Ajouter" name="Wearable Add"/> <menu_item_call label="Enlever" name="Take Off"/> + <menu_item_call label="Appliquer uniquement à moi-même" name="Settings Apply Local"/> + <menu_item_call label="Appliquer à la parcelle" name="Settings Apply Parcel"/> <menu_item_call label="Copier dans les annonces Place du marché" name="Marketplace Copy"/> <menu_item_call label="Déplacer dans les annonces Place du marché" name="Marketplace Move"/> <menu_item_call label="--aucune option--" name="--no options--"/> diff --git a/indra/newview/skins/default/xui/fr/menu_inventory_add.xml b/indra/newview/skins/default/xui/fr/menu_inventory_add.xml index 1076af44d9..de510eaeaa 100644 --- a/indra/newview/skins/default/xui/fr/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/fr/menu_inventory_add.xml @@ -5,9 +5,7 @@ <menu_item_call label="Son ([COST] L$)..." name="Upload Sound"/> <menu_item_call label="Animation ([COST] L$)..." name="Upload Animation"/> <menu_item_call label="Modèle..." name="Upload Model"/> - <menu_item_call label="Assistant Modèle..." name="Upload Model Wizard"/> <menu_item_call label="Lot ([COST] L$ par fichier)..." name="Bulk Upload"/> - <menu_item_call label="Définir les droits de chargement par défaut" name="perm prefs"/> </menu> <menu_item_call label="Nouveau dossier" name="New Folder"/> <menu_item_call label="Nouveau script" name="New Script"/> @@ -25,6 +23,7 @@ <menu_item_call label="Nouveau caleçon" name="New Underpants"/> <menu_item_call label="Nouvel alpha" name="New Alpha"/> <menu_item_call label="Nouveau tatouage" name="New Tattoo"/> + <menu_item_call label="Nouvel environnement universel" name="New Universal"/> <menu_item_call label="Nouvelles propriétés physiques" name="New Physics"/> </menu> <menu label="Nouvelles parties du corps" name="New Body Parts"> @@ -33,4 +32,9 @@ <menu_item_call label="Nouveaux cheveux" name="New Hair"/> <menu_item_call label="Nouveaux yeux" name="New Eyes"/> </menu> + <menu label="Nouveaux paramètres" name="New Settings"> + <menu_item_call label="Nouveau ciel" name="New Sky"/> + <menu_item_call label="Nouvelle eau" name="New Water"/> + <menu_item_call label="Nouveau cycle du jour" name="New Day Cycle"/> + </menu> </menu> diff --git a/indra/newview/skins/default/xui/fr/menu_outfit_gear.xml b/indra/newview/skins/default/xui/fr/menu_outfit_gear.xml index 28ae2f74ad..3fce2e9f33 100644 --- a/indra/newview/skins/default/xui/fr/menu_outfit_gear.xml +++ b/indra/newview/skins/default/xui/fr/menu_outfit_gear.xml @@ -20,6 +20,7 @@ <menu_item_call label="Nouvel alpha" name="New Alpha"/> <menu_item_call label="Nouvelles propriétés physiques" name="New Physics"/> <menu_item_call label="Nouveau tatouage" name="New Tattoo"/> + <menu_item_call label="Nouvel environnement universel" name="New Universal"/> </menu> <menu label="Nouvelles parties du corps" name="New Body Parts"> <menu_item_call label="Nouvelle silhouette" name="New Shape"/> diff --git a/indra/newview/skins/default/xui/fr/menu_save_settings.xml b/indra/newview/skins/default/xui/fr/menu_save_settings.xml new file mode 100644 index 0000000000..34a3f00925 --- /dev/null +++ b/indra/newview/skins/default/xui/fr/menu_save_settings.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="save_settings_menu"> + <menu_item_check label="Enregistrer" name="save_settings"/> + <menu_item_check label="Enregistrer sous" name="save_as_new_settings"/> + <menu_item_check label="Valider" name="commit_changes"/> + <menu_item_check label="Appliquer uniquement à moi-même" name="apply_local"/> + <menu_item_check label="Appliquer à la parcelle" name="apply_parcel"/> + <menu_item_check label="Appliquer à la région" name="apply_region"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/fr/menu_settings_add.xml b/indra/newview/skins/default/xui/fr/menu_settings_add.xml new file mode 100644 index 0000000000..cbd7cba494 --- /dev/null +++ b/indra/newview/skins/default/xui/fr/menu_settings_add.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_add"> + <menu_item_call label="Nouveau ciel" name="New Sky"/> + <menu_item_call label="Nouvelle eau" name="New Water"/> + <menu_item_call label="Nouveau cycle du jour" name="New Day Cycle"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/fr/menu_settings_gear.xml b/indra/newview/skins/default/xui/fr/menu_settings_gear.xml new file mode 100644 index 0000000000..a4e52d373b --- /dev/null +++ b/indra/newview/skins/default/xui/fr/menu_settings_gear.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_gear"> + <menu_item_call label="Modifier" name="edit_settings"/> + <menu_item_call label="Appliquer uniquement à moi-même" name="Settings Apply Local"/> + <menu_item_call label="Appliquer à la parcelle" name="Settings Apply Parcel"/> + <menu_item_call label="Appliquer à la région" name="Settings Apply Region"/> + <menu_item_call label="Copier" name="copy_settings"/> + <menu_item_call label="Coller" name="paste_settings"/> + <menu_item_call label="Copier l’UUID" name="copy_uuid"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/fr/menu_viewer.xml b/indra/newview/skins/default/xui/fr/menu_viewer.xml index 12c50464da..2594e9d0bb 100644 --- a/indra/newview/skins/default/xui/fr/menu_viewer.xml +++ b/indra/newview/skins/default/xui/fr/menu_viewer.xml @@ -79,30 +79,15 @@ <menu_item_check label="Propriétés de la parcelle" name="Parcel Properties"/> <menu_item_check label="Menu Avancé" name="Show Advanced Menu"/> </menu> - <menu label="Soleil" name="Sun"> + <menu label="Environnement" name="Environment"> <menu_item_check label="Aube" name="Sunrise"/> <menu_item_check label="Midi" name="Noon"/> <menu_item_check label="Coucher de soleil" name="Sunset"/> <menu_item_check label="Minuit" name="Midnight"/> - <menu_item_check label="Utiliser les réglages de la région" name="Use Region Settings"/> - </menu> - <menu label="Éditeur d'environnement" name="Environment Editor"> - <menu_item_call label="Paramètres d'environnement..." name="Environment Settings"/> - <menu label="Préréglages de l'eau" name="Water Presets"> - <menu_item_call label="Nouveau préréglage..." name="new_water_preset"/> - <menu_item_call label="Modifier un préréglage..." name="edit_water_preset"/> - <menu_item_call label="Supprimer un préréglage..." name="delete_water_preset"/> - </menu> - <menu label="Préréglages du ciel" name="Sky Presets"> - <menu_item_call label="Nouveau préréglage..." name="new_sky_preset"/> - <menu_item_call label="Modifier un préréglage..." name="edit_sky_preset"/> - <menu_item_call label="Supprimer un préréglage..." name="delete_sky_preset"/> - </menu> - <menu label="Préréglages du jour" name="Day Presets"> - <menu_item_call label="Nouveau préréglage..." name="new_day_preset"/> - <menu_item_call label="Modifier un préréglage..." name="edit_day_preset"/> - <menu_item_call label="Supprimer un préréglage..." name="delete_day_preset"/> - </menu> + <menu_item_check label="Utiliser l'environnement partagé" name="Use Shared Environment"/> + <menu_item_call label="Mes environnements..." name="my_environs"/> + <menu_item_call label="Éclairage personnel..." name="adjustment_tool"/> + <menu_item_check label="Pause des nuages" name="pause_clouds"/> </menu> </menu> <menu label="Construire" name="BuildTools"> @@ -346,6 +331,9 @@ <menu_item_check label="Masques alpha automatiques (non différés)" name="Automatic Alpha Masks (non-deferred)"/> <menu_item_check label="Textures d'animation" name="Animation Textures"/> <menu_item_check label="Désactiver les textures" name="Disable Textures"/> + <menu_item_check label="Désactiver l'ambiance" name="Disable Ambient"/> + <menu_item_check label="Désactiver la lumière du soleil" name="Disable Sunlight"/> + <menu_item_check label="Désactiver les lumières locales" name="Disable Local Lights"/> <menu_item_check label="Textures pleine résolution" name="Rull Res Textures"/> <menu_item_check label="Rendu des lumières jointes" name="Render Attached Lights"/> <menu_item_check label="Rendu des particules jointes" name="Render Attached Particles"/> @@ -483,6 +471,7 @@ <menu_item_call label="Jupe" name="Skirt"/> <menu_item_call label="Alpha" name="Alpha"/> <menu_item_call label="Tatouage" name="Tattoo"/> + <menu_item_call label="Universel" name="Universal"/> <menu_item_call label="Propriétés physiques" name="Physics"/> <menu_item_call label="Tous les habits" name="All Clothes"/> </menu> diff --git a/indra/newview/skins/default/xui/fr/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/fr/menu_wearable_list_item.xml index 187cb4bcd2..a222de298f 100644 --- a/indra/newview/skins/default/xui/fr/menu_wearable_list_item.xml +++ b/indra/newview/skins/default/xui/fr/menu_wearable_list_item.xml @@ -3,6 +3,7 @@ <menu_item_call label="Remplacer" name="wear_replace"/> <menu_item_call label="Porter" name="wear_wear"/> <menu_item_call label="Ajouter" name="wear_add"/> + <menu_item_call label="Toucher" name="touch" /> <menu_item_call label="Enlever / Détacher" name="take_off_or_detach"/> <menu_item_call label="Détacher" name="detach"/> <context_menu label="Attacher à " name="wearable_attach_to"/> diff --git a/indra/newview/skins/default/xui/fr/menu_wearing_gear.xml b/indra/newview/skins/default/xui/fr/menu_wearing_gear.xml index c3d9d908b0..90b5ece574 100644 --- a/indra/newview/skins/default/xui/fr/menu_wearing_gear.xml +++ b/indra/newview/skins/default/xui/fr/menu_wearing_gear.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <toggleable_menu name="Gear Wearing"> - <menu_item_call label="Modifier la tenue" name="edit"/> + <menu_item_call label="Toucher" name="touch"/> + <menu_item_call label="Modifier" name="edit_item"/> + <menu_item_call label="Modifier la tenue" name="edit_outfit"/> <menu_item_call label="Enlever" name="takeoff"/> <menu_item_call label="Copier la liste de la tenue dans le presse-papiers" name="copy"/> </toggleable_menu> diff --git a/indra/newview/skins/default/xui/fr/menu_wearing_tab.xml b/indra/newview/skins/default/xui/fr/menu_wearing_tab.xml index 5a7193a7cc..af115b956e 100644 --- a/indra/newview/skins/default/xui/fr/menu_wearing_tab.xml +++ b/indra/newview/skins/default/xui/fr/menu_wearing_tab.xml @@ -1,8 +1,9 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="Wearing"> + <menu_item_call label="Toucher" name="touch_attach"/> <menu_item_call label="Enlever" name="take_off"/> <menu_item_call label="Détacher" name="detach"/> - <menu_item_call label="Modifier la tenue" name="edit"/> + <menu_item_call label="Modifier la tenue" name="edit_outfit"/> <menu_item_call label="Modifier" name="edit_item"/> <menu_item_call label="Afficher l’original" name="show_original"/> </context_menu> diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml index 54f132f684..e84de375d8 100644 --- a/indra/newview/skins/default/xui/fr/notifications.xml +++ b/indra/newview/skins/default/xui/fr/notifications.xml @@ -266,6 +266,10 @@ Souhaitez-vous accorder des droits d'édition aux résidents sélectionnés Souhaitez-vous retirer les droits d'édition aux résidents selectionnés ? <usetemplate name="okcancelbuttons" notext="Non" yestext="Oui"/> </notification> + <notification name="GroupNameLengthWarning"> + Un nom de groupe doit être compris entre [MIN_LEN] et [MAX_LEN] caractères. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="UnableToCreateGroup"> Impossible de créer le groupe. [MESSAGE] @@ -359,7 +363,7 @@ Souhaitez-vous continuer ? Vous n'avez pas suffisamment de L$ pour rejoindre ce groupe. </notification> <notification name="CreateGroupCost"> - La création de ce groupe coûte 100 L$. + La création de ce groupe coûtera L$[COST]. Les groupes doivent comporter plus d'un membre, sinon ils sont supprimés. Veuillez inviter des membres d'ici 48 heures. <usetemplate canceltext="Annuler" name="okcancelbuttons" notext="Annuler" yestext="Créer un groupe pour 100 L$"/> @@ -500,6 +504,9 @@ Pour ne placer le média que sur une seule face, choisissez Sélectionner une fa <notification name="ErrorEncodingSnapshot"> Erreur d'encodage de la photo. </notification> + <notification name="ErrorCannotAffordUpload"> + Vous avez besoin de L$[COST] pour charger cet élément. + </notification> <notification name="ErrorPhotoCannotAfford"> Il vous faut [COST] L$ pour enregistrer une photo dans votre inventaire. Vous pouvez acheter des L$ ou enregistrer la photo sur votre ordinateur. </notification> @@ -1736,11 +1743,14 @@ Quitter le groupe ? <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="GroupLimitInfo"> - Le nombre de groupes maximum est [MAX_BASIC] pour les comptes basiques et -[MAX_PREMIUM] pour les comptes [https://secondlife.com/premium/ premium]. -Si vous avez rétrogradé votre compte, vous devez réduire votre nombre de groupes pour passer sous le nombre de groupes maximum ([MAX_BASIC]) avant de pouvoir en rejoindre d’autres. - -[https://secondlife.com/my/account/membership.php Mettez à niveau dès aujourd’hui !] + Les résidents ayant une adhésion de base peuvent s'inscrire à [MAX_BASIC] groupes maximum. +Les adhésions premium permettent jusqu'à [MAX_PREMIUM]. [https://secondlife.com/my/account/membership.php? En savoir plus ou actualiser] + <usetemplate name="okbutton" yestext="Fermer"/> + </notification> + <notification name="GroupLimitInfoPlus"> + Les résidents ayant une adhésion de base peuvent s'inscrire à [MAX_BASIC] groupes maximum. +Les adhésions premium permettent jusqu'à [MAX_PREMIUM]. Les adhésions à Premium Plus permettent +jusqu'à [MAX_PREMIUM_PLUS]. [https://secondlife.com/my/account/membership.php? En savoir plus ou actualiser] <usetemplate name="okbutton" yestext="Fermer"/> </notification> <notification name="KickUser"> @@ -1959,6 +1969,11 @@ Cette action modifiera des milliers de régions et sera difficile à digérer po Le fait de décocher cette option est susceptible de lever les restrictions que les propriétaires des parcelles ont ajouté pour éviter tout différend, maintenir la confidentialité ou protéger les jeunes résidents contre tout contenu réservé aux adultes. Veuillez discuter avec les propriétaires du terrain si nécessaire. <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="EstateParcelEnvironmentOverride"> + Si vous décochez cette option, tous les environnements personnalisés que les propriétaires de parcelles ont ajoutés à leurs parcelles seront supprimés. Veuillez discuter avec les propriétaires de votre parcelle si nécessaire. +Souhaitez-vous continuer ? + <usetemplate name="okcancelbuttons" notext="Annuler" yestext="OK"/> + </notification> <notification name="RegionEntryAccessBlocked"> La région que vous essayez de visiter comporte du contenu dont le niveau dépasse celui de vos préférences actuelles. Vous pouvez modifier vos préférences en accédant à Moi > Préférences > Général. <usetemplate name="okbutton" yestext="OK"/> @@ -2439,7 +2454,15 @@ Liez-la à partir d'une page web pour permettre aux autres résidents d&apo Une dossier semble manquer au Cycle du jour : [SKY]. </notification> <notification name="WLRegionApplyFail"> - Impossible d'appliquer les réglages à la région. Le problème est parfois résolu en quittant la région puis en y revenant. Motif fourni : [FAIL_REASON] + Impossible d'appliquer les réglages à la région. Raison : [FAIL_REASON] + </notification> + <notification name="WLLocalTextureDayBlock"> + Une texture locale est utilisée sur la piste [TRACK], le cadre n° [FRAMENO] ([FRAME]%) dans le champ [FIELD]. +Les paramètres ne seront peut-être pas enregistrés en utilisant les textures locales + </notification> + <notification name="WLLocalTextureFixedBlock"> + Une texture locale est utilisée dans le champ [FIELD]. +Les paramètres ne seront peut-être pas enregistrés en utilisant les textures locales </notification> <notification name="EnvCannotDeleteLastDayCycleKey"> Impossible de supprimer la dernière clé de ce cycle du jour car ce dernier ne peut pas être vide. Modifiez la dernière clé restante au lieu d'essayer de la supprimer puis d'en créer une nouvelle. @@ -3291,6 +3314,22 @@ Elles vont être bloquées pendant quelques secondes pour votre sécurité. Le modérateur ignore vos paroles. <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FailedToGetBenefits"> + Malheureusement, nous n'avons pas pu obtenir d'informations sur les avantages pour cette session. Cela ne devrait pas se produire dans un environnement de production normal. Veuillez contacter le service d'assistance. Cette session ne fonctionnera pas normalement et nous vous recommandons de recommencer. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="BulkUploadCostConfirmation"> + Ceci permettra de charger [COUNT] éléments pour un coût total de L$[COST]. Souhaitez-vous poursuivre le téléchargement ? + <usetemplate name="okcancelbuttons" notext="Annuler" yestext="Charger"/> + </notification> + <notification name="BulkUploadNoCompatibleFiles"> + Les fichiers sélectionnés ne peuvent pas être téléchargés en masse. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="BulkUploadIncompatibleFiles"> + Certains des fichiers sélectionnés ne peuvent pas être téléchargés en masse. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="UploadCostConfirmation"> Ce chargement coûtera [PRICE] L$. Continuer ? <usetemplate name="okcancelbuttons" notext="Annuler" yestext="Charger"/> @@ -4389,4 +4428,76 @@ Veuillez sélectionner un terrain plus petit. [REASON] <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FailedToFindSettings"> + Impossible de charger les paramètres de [NOM] à partir de la base de données. + </notification> + <notification name="FailedToLoadSettingsApply"> + Impossible d'appliquer ces paramètres à l'environnement. + </notification> + <notification name="FailedToBuildSettingsDay"> + Impossible d'appliquer ces paramètres à l'environnement. + </notification> + <notification name="NoEnvironmentSettings"> + Cette région ne prend pas en charge les paramètres environnementaux. + </notification> + <notification label="Enregistrer la tenue" name="SaveSettingAs"> + Enregistrer les paramètres environnementaux actuels sous : + <form name="form"> + <input name="message"> + [DESC] (nouv.) + </input> + <button name="OK" text="OK"/> + <button name="Cancel" text="Annuler"/> + </form> + </notification> + <notification name="WLImportFail"> + Impossible d'importer les paramètres Windlight [NAME] hérités de +[FILE]. + +[REASONS] + </notification> + <notification name="WLParcelApplyFail"> + Impossible de définir l'environnement pour cette parcelle. +Veuillez entrer ou sélectionner une parcelle que vous avez le droit de modifier. + </notification> + <notification name="SettingsUnsuported"> + Les paramètres ne sont pas pris en charge dans cette région. +Veuillez vous déplacer dans une région où les paramètres sont activés et relancer votre action. + </notification> + <notification name="SettingsConfirmLoss"> + Vous êtes sur le point de perdre les modifications que vous avez apportées à ce [TYPE] nommé "[NAME]". +Voulez-vous vraiment continuer ? + <usetemplate ignoretext="Voulez-vous vraiment perdre les modifications ?" name="okcancelignore" notext="Non" yestext="Oui"/> + </notification> + <notification name="SettingsConfirmReset"> + Vous êtes sur le point de supprimer tous les paramètres appliqués. +Voulez-vous vraiment continuer ? + <usetemplate name="okcancelbuttons" notext="Non" yestext="Oui"/> + </notification> + <notification name="PersonalSettingsConfirmReset"> + Vous êtes sur le point de supprimer tous les paramètres d'éclairage personnel appliqués. +Voulez-vous vraiment continuer ? + <usetemplate name="okcancelbuttons" notext="Non" yestext="Oui"/> + </notification> + <notification name="SettingsMakeNoTrans"> + Vous êtes sur le point d'importer des paramètres non transférables dans ce cycle de jour. Si vous continuez, les paramètres que vous modifiez deviennent également non transférables. + +Cette modification ne peut être être annulée. + +Voulez-vous vraiment continuer ? + <usetemplate ignoretext="Voulez-vous vraiment que ces paramètres soient non transférables ?" name="okcancelignore" notext="Non" yestext="Oui"/> + </notification> + <notification name="NoEditFromLibrary"> + Vous ne pouvez pas modifier les paramètres directement à partir de la bibliothèque. +Veuillez copier vers votre inventaire puis réessayer + </notification> + <notification name="EnvironmentApplyFailed"> + Nous avons rencontré un problème avec ces paramètres. Ils ne peuvent pas être enregistres ou appliqués pour l'instant. + </notification> + <notification name="TrackLoadFailed"> + Impossible de charger la piste dans [TRACK]. + </notification> + <notification name="TrackLoadMismatch"> + Impossible de charger la piste de [TRACK1] dans [TRACK2]. + </notification> </notifications> diff --git a/indra/newview/skins/default/xui/fr/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/fr/panel_edit_tattoo.xml index 086542dee2..24b4fc212a 100644 --- a/indra/newview/skins/default/xui/fr/panel_edit_tattoo.xml +++ b/indra/newview/skins/default/xui/fr/panel_edit_tattoo.xml @@ -1,9 +1,11 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_tattoo_panel"> - <panel name="avatar_tattoo_color_panel"> - <texture_picker label="Tatouage tête" name="Head Tattoo" tool_tip="Cliquez pour sélectionner une image"/> - <texture_picker label="Tatouage haut" name="Upper Tattoo" tool_tip="Cliquez pour sélectionner une image"/> - <texture_picker label="Tatouage bas" name="Lower Tattoo" tool_tip="Cliquez pour sélectionner une image"/> - <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs"/> - </panel> + <scroll_container name="avatar_tattoo_scroll"> + <panel name="avatar_tattoo_color_panel"> + <texture_picker label="Tatouage tête" name="Head Tattoo" tool_tip="Cliquer pour sélectionner une image."/> + <texture_picker label="Tatouage haut" name="Upper Tattoo" tool_tip="Cliquer pour sélectionner une image."/> + <texture_picker label="Tatouage bas" name="Lower Tattoo" tool_tip="Cliquer pour sélectionner une image."/> + <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs"/> + </panel> + </scroll_container> </panel> diff --git a/indra/newview/skins/default/xui/fr/panel_edit_universal.xml b/indra/newview/skins/default/xui/fr/panel_edit_universal.xml new file mode 100644 index 0000000000..a4626123f9 --- /dev/null +++ b/indra/newview/skins/default/xui/fr/panel_edit_universal.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel name="edit_universal_panel"> + <scroll_container name="avatar_universal_scroll"> + <panel name="avatar_universal_color_panel"> + <texture_picker label="Tatouage tête" name="Head Universal Tattoo" tool_tip="Cliquer pour sélectionner une image."/> + <texture_picker label="Tatouage haut" name="Upper Universal Tattoo" tool_tip="Cliquer pour sélectionner une image."/> + <texture_picker label="Tatouage bas" name="Lower Universal Tattoo" tool_tip="Cliquer pour sélectionner une image."/> + <texture_picker label="Tatouage jupe" name="Skirt Tattoo" tool_tip="Cliquer pour sélectionner une image."/> + <texture_picker label="Tatouage cheveux" name="Hair Tattoo" tool_tip="Cliquer pour sélectionner une image."/> + <texture_picker label="Tatouage yeux" name="Eyes Tattoo" tool_tip="Cliquer pour sélectionner une image."/> + <texture_picker label="Tatouage bras gauche" name="Left Arm Tattoo" tool_tip="Cliquer pour sélectionner une image."/> + <texture_picker label="Tatouage jambe gauche" name="Left Leg Tattoo" tool_tip="Cliquer pour sélectionner une image."/> + <texture_picker label="Aux1 Tattoo" name="Aux1 Tattoo" tool_tip="Cliquer pour sélectionner une image."/> + <texture_picker label="Aux2 Tattoo" name="Aux2 Tattoo" tool_tip="Cliquer pour sélectionner une image."/> + <texture_picker label="Aux3 Tattoo" name="Aux3 Tattoo" tool_tip="Cliquer pour sélectionner une image."/> + <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs"/> + </panel> + </scroll_container> +</panel> diff --git a/indra/newview/skins/default/xui/fr/panel_edit_wearable.xml b/indra/newview/skins/default/xui/fr/panel_edit_wearable.xml index def158cf68..d8851bb42c 100644 --- a/indra/newview/skins/default/xui/fr/panel_edit_wearable.xml +++ b/indra/newview/skins/default/xui/fr/panel_edit_wearable.xml @@ -45,6 +45,9 @@ <string name="edit_tattoo_title"> Modification du tatouage </string> + <string name="edit_universal_title"> + Modifier l'universel + </string> <string name="edit_physics_title"> Modification des propriétés physiques </string> @@ -93,6 +96,9 @@ <string name="tattoo_desc_text"> Tatouage : </string> + <string name="universal_desc_text"> + Universel : + </string> <string name="physics_desc_text"> Propriétés physiques : </string> diff --git a/indra/newview/skins/default/xui/fr/panel_outbox_inventory.xml b/indra/newview/skins/default/xui/fr/panel_outbox_inventory.xml deleted file mode 100644 index d947dbceb8..0000000000 --- a/indra/newview/skins/default/xui/fr/panel_outbox_inventory.xml +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<outbox_inventory_panel name="inventory_outbox" tool_tip="Glisser-déposer des articles ici afin de les préparer à la vente sur votre vitrine."/> diff --git a/indra/newview/skins/default/xui/fr/panel_people.xml b/indra/newview/skins/default/xui/fr/panel_people.xml index 95cd13eb94..3be6bae52a 100644 --- a/indra/newview/skins/default/xui/fr/panel_people.xml +++ b/indra/newview/skins/default/xui/fr/panel_people.xml @@ -18,7 +18,7 @@ Pour rechercher des résidents avec qui passer du temps, utilisez [secondlife:// <string name="no_groups_msg" value="Vous souhaitez trouver des groupes à rejoindre ? Utilisez [secondlife:///app/search/groups Rechercher]."/> <string name="MiniMapToolTipMsg" value="[REGION](Carte : double-clic ; Panoramique : Maj + faire glisser)"/> <string name="AltMiniMapToolTipMsg" value="[REGION](Téléportation : double-clic ; Panoramique : Maj + faire glisser)"/> - <string name="GroupCountWithInfo" value="Vous appartenez à [COUNT] groupes, et pouvez en rejoindre [REMAINING] autres. [secondlife:/// Vous en voulez plus ?]"/> + <string name="GroupCountWithInfo" value="Vous appartenez à [COUNT] groupes et pouvez rejoindre [REMAINING] autres groupes. [secondlife:/// Augmentez votre limite]"/> <tab_container name="tabs"> <panel label="PRÈS DE VOUS" name="nearby_panel"> <panel label="bottom_panel" name="nearby_buttons_panel"> @@ -51,7 +51,7 @@ Pour rechercher des résidents avec qui passer du temps, utilisez [secondlife:// <dnd_button name="minus_btn" tool_tip="Quitter le groupe sélectionné"/> </panel> <text name="groupcount"> - Vous appartenez à [COUNT] groupes, et pouvez en rejoindre [REMAINING] autres. + Vous appartenez à [COUNT] groupes et pouvez rejoindre [REMAINING] autres groupes. </text> </panel> <panel label="RÉCENT" name="recent_panel"> diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml b/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml index 422243445b..a0f2e0eba7 100644 --- a/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml @@ -13,7 +13,7 @@ <item label="Moyenne" name="Medium" value="1"/> <item label="Grande" name="Large" value="2"/> </combo_box> - <check_box label="Bulles de chat" name="bubble_text_chat"/> + <check_box label="Bulles de chat" name="bubble_text_chat" left_delta="45"/> </panel> <panel name="im_notification_settings"> <text name="friend_ims"> diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml index 7117ace7e1..46d6305290 100644 --- a/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml @@ -32,10 +32,10 @@ </text> <check_box initial_value="true" label="Toujours effectuer le rendu des amis" name="AlwaysRenderFriends"/> <button label="Exceptions..." name="RenderExceptionsButton"/> - <button label="Enregistrer les paramètres comme préréglage..." name="PrefSaveButton"/> - <button label="Charger un préréglage..." name="PrefLoadButton"/> + <button label="Enregistrer les paramètres comme préréglage" name="PrefSaveButton" width="260" /> + <button label="Charger un préréglage" name="PrefLoadButton" width="132"/> min_val="0,125" - <button label="Supprimer un préréglage..." name="PrefDeleteButton"/> - <button label="Réinitialiser les paramètres recommandés" name="Defaults"/> + <button label="Supprimer un préréglage" name="PrefDeleteButton" width="148" top_delta="30" left_pad="-220"/> + <button label="Réinitialiser les paramètres recommandés" name="Defaults" width="255" top_delta="35"/> <button label="Paramètres avancés" name="AdvancedSettings"/> </panel> diff --git a/indra/newview/skins/default/xui/fr/panel_region_environment.xml b/indra/newview/skins/default/xui/fr/panel_region_environment.xml index a5be812ee5..5212c3a9ce 100644 --- a/indra/newview/skins/default/xui/fr/panel_region_environment.xml +++ b/indra/newview/skins/default/xui/fr/panel_region_environment.xml @@ -1,33 +1,116 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Environnement" name="panel_env_info"> - <text name="water_settings_title"> - Sélectionnez les réglages d'eau et de ciel/cycle du jour que vous souhaitez afficher pour tous les résidents visitant votre région. En savoir plus - </text> - <radio_group name="region_settings_radio_group"> - <radio_item label="Utiliser les réglages par défaut de Second Life" name="use_sl_default_settings"/> - <radio_item label="Utiliser les réglages suivants" name="use_my_settings"/> - </radio_group> - <panel name="user_environment_settings"> - <text name="water_settings_title"> - Réglage de l'eau - </text> - <combo_box name="water_settings_preset_combo"> - <combo_box.item label="-Sélectionner un préréglage-" name="item0"/> - </combo_box> - <text name="sky_dayc_settings_title"> - Ciel / Cycle du jour - </text> - <radio_group name="sky_dayc_settings_radio_group"> - <radio_item label="Ciel fixe" name="my_sky_settings"/> - <radio_item label="Cycle du jour" name="my_dayc_settings"/> - </radio_group> - <combo_box name="sky_settings_preset_combo"> - <combo_box.item label="-Sélectionner un préréglage-" name="item0"/> - </combo_box> - <combo_box name="dayc_settings_preset_combo"> - <combo_box.item label="-Sélectionner un préréglage-" name="item0"/> - </combo_box> - </panel> - <button label="Appliquer" name="apply_btn"/> - <button label="Annuler" name="cancel_btn"/> + <string name="str_label_use_default"> + Utiliser les réglages par défaut + </string> + <string name="str_label_use_region"> + Utiliser les réglages de la région + </string> + <string name="str_altitude_desription"> + Ciel [INDEX]([ALTITUDE]m) + </string> + <string name="str_no_parcel"> + Aucune parcelle n'est sélectionnée. Les paramètres environnementaux sont désactivés.. + </string> + <string name="str_cross_region"> + Les paramètres environnementaux ne sont pas disponibles dans les limites des régions. + </string> + <string name="str_legacy"> + Les paramètres environnementaux ne sont pas disponibles dans cette région. + </string> + <string name="str_disallowed"> + Le gérant du domaine n'autorise pas la modification de l'environnement des parcelles dans cette région. + </string> + <string name="str_too_small"> + La parcelle doit faire au moins 128 mètres carrés pour supporter un environnement. + </string> + <string name="str_empty"> + (vide) + </string> + <string name="str_region_env"> + (environnement de la région) + </string> + <layout_stack> + <layout_panel name="pnl_environment_disabled"> + <text name="txt_environment_disabled"> + ... + </text> + </layout_panel> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_current"> + <button label="[USEDEFAULT]" name="btn_usedefault"/> + <button label="Utiliser l'inventaire" name="btn_select_inventory"/> + <button label="Personnaliser" name="btn_edit"/> + <check_box label="Les propriétaires de parcelle peuvent neutraliser l'environnement" name="chk_allow_override"/> + </layout_panel> + <layout_panel name="pnl_environment_length"> + <text name="lbl_apparent_time"> + [HH]:[MM][AP] ([PRC]%) + </text> + </layout_panel> + <layout_panel name="pnl_environment_buttons"/> + </layout_stack> + </layout_panel> + <layout_panel name="pnl_environment_altitudes"> + <panel name="pnl_alt1"> + <text name="txt_alt1"> + Ciel [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt1"> + Inconnu + </line_editor> + <settings_drop_target name="sdt_alt1" tool_tip="Faites glisser un paramètre de l'inventaire vers cette zone cible pour le sélectionner comme ciel actuel."/> + </panel> + <panel name="pnl_alt2"> + <text name="txt_alt2"> + Ciel [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt2"> + Inconnu + </line_editor> + <settings_drop_target name="sdt_alt2" tool_tip="Faites glisser un paramètre de l'inventaire vers cette zone cible pour le sélectionner comme ciel actuel."/> + </panel> + <panel name="pnl_alt3"> + <text name="txt_alt3"> + Ciel [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt3"> + Inconnu + </line_editor> + <settings_drop_target name="sdt_alt3" tool_tip="Faites glisser un paramètre de l'inventaire vers cette zone cible pour le sélectionner comme ciel actuel."/> + </panel> + <multi_slider initial_value="0" name="sld_altitudes"> + <slider name="sld1" value="1000"/> + <slider name="sld2" value="2000"/> + <slider name="sld3" value="3000"/> + </multi_slider> + <panel name="pnl_ground"> + <text name="txt_ground"> + Sol + </text> + <line_editor name="edt_invname_ground"> + Inconnu + </line_editor> + <settings_drop_target name="sdt_ground" tool_tip="Faites glisser un paramètre de l'inventaire vers cette zone cible pour le sélectionner comme ciel au niveau du sol."/> + </panel> + <panel name="pnl_water"> + <text name="txt_water"> + Eau + </text> + <line_editor name="edt_invname_water"> + Inconnu + </line_editor> + <settings_drop_target name="sdt_water" tool_tip="Faites glisser un paramètre de l'inventaire vers cette zone cible pour le sélectionner comme eau actuelle."/> + </panel> + <button label="Réinitialiser" name="btn_rst_altitudes" tool_tip="Rétablir les altitudes par défaut."/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> </panel> diff --git a/indra/newview/skins/default/xui/fr/panel_settings_sky_atmos.xml b/indra/newview/skins/default/xui/fr/panel_settings_sky_atmos.xml new file mode 100644 index 0000000000..1d6491c7e7 --- /dev/null +++ b/indra/newview/skins/default/xui/fr/panel_settings_sky_atmos.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Atmosphère et éclairage" name="panel_settings_sky_atmos"/> diff --git a/indra/newview/skins/default/xui/fr/panel_settings_sky_clouds.xml b/indra/newview/skins/default/xui/fr/panel_settings_sky_clouds.xml new file mode 100644 index 0000000000..180f09653e --- /dev/null +++ b/indra/newview/skins/default/xui/fr/panel_settings_sky_clouds.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Nuages" name="panel_settings_sky_clouds"> + <layout_stack> + <layout_panel> + <slider label="X" name="cloud_density_x"/> + <slider label="Y" name="cloud_density_y"/> + <slider label="D" name="cloud_density_d"/> + <slider label="X" name="cloud_detail_x"/> + <slider label="Y" name="cloud_detail_y"/> + <slider label="D" name="cloud_detail_d"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/fr/panel_settings_sky_density.xml b/indra/newview/skins/default/xui/fr/panel_settings_sky_density.xml new file mode 100644 index 0000000000..107858dc20 --- /dev/null +++ b/indra/newview/skins/default/xui/fr/panel_settings_sky_density.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Densité" name="panel_settings_sky_density"> + <layout_stack> + <layout_panel> + <slider label="Terme exponentiel de Rayleigh :" name="rayleigh_exponential"/> + <slider label="Échelle exponentielle de Rayleigh :" name="rayleigh_exponential_scale"/> + <slider label="Terme linéaire de Rayleigh :" name="rayleigh_linear"/> + <slider label="Terme constant de Rayleigh :" name="rayleigh_constant"/> + <slider label="Altitude maximum de Rayleigh :" name="rayleigh_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="Terme exponentiel de mie :" name="mie_exponential"/> + <slider label="Échelle exponentielle de mie :" name="mie_exponential_scale"/> + <slider label="Terme linéaire de mie :" name="mie_linear"/> + <slider label="Terme constant de mie :" name="mie_constant"/> + <slider label="Facteur aniso de mie :" name="mie_aniso_factor"/> + <slider label="Altitude maximum de mie :" name="mie_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="Terme exponentiel d'absorption :" name="absorption_exponential"/> + <slider label="Échelle exponentielle d'absorption :" name="absorption_exponential_scale"/> + <slider label="Terme linéaire d'absorption :" name="absorption_linear"/> + <slider label="Terme constant d'absorption :" name="absorption_constant"/> + <slider label="Altitude maximale d'absorption :" name="absorption_max_altitude"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/fr/panel_settings_sky_sunmoon.xml b/indra/newview/skins/default/xui/fr/panel_settings_sky_sunmoon.xml new file mode 100644 index 0000000000..39d87c9727 --- /dev/null +++ b/indra/newview/skins/default/xui/fr/panel_settings_sky_sunmoon.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Soleil et lune" name="panel_settings_sky_hbodies"> + <layout_stack> + <layout_panel name="sun_layout"> + <check_box label="Afficher la balise" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <layout_stack> + <layout_panel name="moon_layout"> + <check_box label="Afficher la balise" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/fr/panel_settings_water.xml b/indra/newview/skins/default/xui/fr/panel_settings_water.xml new file mode 100644 index 0000000000..203075f987 --- /dev/null +++ b/indra/newview/skins/default/xui/fr/panel_settings_water.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Eau" name="panel_settings_water"> + <layout_stack name="water_stack1"> + <layout_panel> + <text name="FresnelOffsetText"> + Décalage Fresnel : + </text> + </layout_panel> + <layout_panel> + <layout_stack name="water_stack2"> + <layout_panel> + <slider label="X :" name="water_normal_scale_x"/> + <slider label="Y :" name="water_normal_scale_y"/> + <slider label="Z :" name="water_normal_scale_z"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/fr/panel_tools_texture.xml b/indra/newview/skins/default/xui/fr/panel_tools_texture.xml index 72c456aa6d..d028336ac7 100644 --- a/indra/newview/skins/default/xui/fr/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/fr/panel_tools_texture.xml @@ -1,11 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Texture" name="Texture"> - <panel.string name="string repeats per meter"> - Répétitions au mètre - </panel.string> - <panel.string name="string repeats per face"> - Répétitions par face - </panel.string> <text name="color label"> Couleur </text> @@ -114,4 +108,5 @@ <spinner label="Décalage horizontal" name="shinyOffsetU"/> <spinner label="Décalage vertical" name="shinyOffsetV"/> <check_box initial_value="false" label="Aligner les faces Plan" name="checkbox planar align" tool_tip="Aligner les textures sur toutes les faces sélectionnées avec la dernière face sélectionnée. Application de la texture Plan requise."/> + <button label="Aligner" label_selected="Aligner les couches de texture actuelles" name="button align textures" tool_tip="Aligner les couches de texture actuelles"/> </panel> diff --git a/indra/newview/skins/default/xui/fr/role_actions.xml b/indra/newview/skins/default/xui/fr/role_actions.xml index d10de38437..95e4799ce4 100644 --- a/indra/newview/skins/default/xui/fr/role_actions.xml +++ b/indra/newview/skins/default/xui/fr/role_actions.xml @@ -33,6 +33,7 @@ <action description="Modifier la musique et les médias" longdescription="Changez la musique et les médias à partir du menu À propos du terrain > Médias." name="land change media" value="20"/> <action description="Changer l'option Modifier le terrain" longdescription="Changez l'option Modifier le terrain à partir du menu À propos du terrain > Options. Attention : ce pouvoir permet de terraformer votre terrain et de placer ou déplacer des plantes Linden. Assurez-vous de bien comprendre ce pouvoir avant de l'attribuer. " name="land edit" value="21"/> <action description="Changer diverses options du terrain" longdescription="Activez Sécurisé (pas de dégâts), Voler, et autorisez les autres résidents à : modifier le terrain, construire, créer des repères et exécuter des scripts sur les terrains appartenant au groupe dans l'onglet propos du terrain > Options." name="land options" value="22"/> + <action description="Modifier les paramètres environnementaux et le cycle du jour." longdescription="Charger les paramètres environnementaux et le cycle du jour à partir de l'onglet A propos du terrain > Environnement." name="land change environment" value="46"/> </action_set> <action_set description="Ces pouvoirs permettent aux membres d'outrepasser les restrictions sur les parcelles du groupe." name="Parcel Powers"> <action description="Toujours autoriser Modifier le terrain" longdescription="Vous pouvez modifier le relief d'une parcelle du groupe, même si l'option est désactivée à partir du menu À propos du terrain > Options." name="land allow edit land" value="23"/> diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml index 959494545a..f26eac545a 100644 --- a/indra/newview/skins/default/xui/fr/strings.xml +++ b/indra/newview/skins/default/xui/fr/strings.xml @@ -639,6 +639,15 @@ Veuillez réessayer de vous connecter dans une minute. <string name="BUTTON_HELP"> Afficher l'aide </string> + <string name="TooltipNotecardNotAllowedTypeDrop"> + Les éléments de ce type ne peuvent pas être attachés +aux notes de cette région. + </string> + <string name="TooltipNotecardOwnerRestrictedDrop"> + Seuls des éléments avec des autorisation +illimitées pour le 'prochain propriétaire' +peuvent être joints aux notes. + </string> <string name="Searching"> Recherche... </string> @@ -718,6 +727,18 @@ Veuillez réessayer de vous connecter dans une minute. Erreur dans la demande de chargement. Veuillez consulter le site : http://secondlife.com/support pour vous aider à résoudre ce problème. </string> + <string name="SettingValidationError"> + Échec de la validation pour l'importation des paramètres [NAME] + </string> + <string name="SettingImportFileError"> + Impossible d'ouvre le fichier [FILE] + </string> + <string name="SettingParseFileError"> + Impossible d'ouvre le fichier [FILE] + </string> + <string name="SettingTranslateError"> + Impossible de traduit les paramètres windlight hérités [NAME] + </string> <string name="texture"> texture </string> @@ -793,6 +814,9 @@ http://secondlife.com/support pour vous aider à résoudre ce problème. <string name="symbolic folder link"> lien du dossier </string> + <string name="settings blob"> + paramètres + </string> <string name="mesh"> maillage </string> @@ -1123,6 +1147,9 @@ http://secondlife.com/support pour vous aider à résoudre ce problème. <string name="ForceSitAvatar"> Forcez votre avatar à s’asseoir </string> + <string name="ChangeEnvSettings"> + Changer vos paramètres d'environnement + </string> <string name="NotConnected"> Pas connecté(e) </string> @@ -1274,6 +1301,9 @@ http://secondlife.com/support pour vous aider à résoudre ce problème. <string name="tattoo"> Tatouage </string> + <string name="universal"> + Universel + </string> <string name="physics"> Propriétés physiques </string> @@ -1316,6 +1346,9 @@ http://secondlife.com/support pour vous aider à résoudre ce problème. <string name="tattoo_not_worn"> Tatouage non porté </string> + <string name="universal_not_worn"> + Universel non porté + </string> <string name="physics_not_worn"> Propriétés physiques non portées </string> @@ -1367,6 +1400,9 @@ http://secondlife.com/support pour vous aider à résoudre ce problème. <string name="create_new_tattoo"> Créer un nouveau tatouage </string> + <string name="create_new_universal"> + Créer un nouvel environnement universel + </string> <string name="create_new_physics"> Créer de nouvelles propriétés physiques </string> @@ -1610,11 +1646,14 @@ Si vous continuez de recevoir ce message, contactez l’assistance Second Life à <string name="MarketplaceUpdating"> mise à jour... </string> + <string name="UploadFeeInfo"> + Les frais dépendent de votre niveau d'abonnement. Les niveaux supérieurs sont soumis à des frais moins élevés. [https://secondlife.com/my/account/membership.php? En savoir plus] + </string> <string name="Open landmarks"> - Ouvrir les repères + Points de repère ouverts </string> <string name="Unconstrained"> - Sans contraintes + Sans contrainte </string> <string name="no_transfer" value=" (pas de transfert)"/> <string name="no_modify" value=" (pas de modification)"/> @@ -2514,6 +2553,27 @@ Si vous continuez de recevoir ce message, contactez l’assistance Second Life à <string name="RegionSettings"> Réglages de la région </string> + <string name="NoEnvironmentSettings"> + Cette région ne prend pas en charge les paramètres environnementaux. + </string> + <string name="EnvironmentSun"> + Soleil + </string> + <string name="EnvironmentMoon"> + Lune + </string> + <string name="EnvironmentBloom"> + Éclat + </string> + <string name="EnvironmentCloudNoise"> + Bruit du nuage + </string> + <string name="EnvironmentNormalMap"> + Carte normale + </string> + <string name="EnvironmentTransparent"> + Transparent + </string> <string name="ClassifiedClicksTxt"> Clics : [TELEPORT] téléportation, [MAP] carte, [PROFILE] profil </string> @@ -4730,6 +4790,9 @@ du rapport d'infraction <string name="New Tattoo"> Nouveau tatouage </string> + <string name="New Universal"> + Nouvel environnement universel + </string> <string name="New Physics"> Nouvelles propriétés physiques </string> @@ -4856,6 +4919,15 @@ du rapport d'infraction <string name="Female - Wow"> Femme - Ouah ! </string> + <string name="New Daycycle"> + Nouveau cycle du jour + </string> + <string name="New Water"> + Nouvelle eau + </string> + <string name="New Sky"> + Nouveau ciel + </string> <string name="/bow"> /s'incliner </string> @@ -5028,6 +5100,15 @@ Veuillez vous reporter à http://status.secondlifegrid.net afin de déterminer s <string name="Chat" value=" Chat :"> Chat </string> + <string name="BaseMembership"> + Base + </string> + <string name="PremiumMembership"> + Premium + </string> + <string name="Premium PlusMembership"> + Premium Plus + </string> <string name="DeleteItems"> Supprimer les articles sélectionnés ? </string> @@ -5384,6 +5465,12 @@ Essayez avec le chemin d'accès à l'éditeur entre guillemets doubles <string name="BeaconMedia"> Affichage des balises de média (blanc) </string> + <string name="BeaconSun"> + Balise de visibilité du soleil (orange) + </string> + <string name="BeaconMoon"> + Observation de la balise de direction de la lune (violet) + </string> <string name="ParticleHiding"> Masquage des particules </string> @@ -5411,6 +5498,12 @@ Essayez avec le chemin d'accès à l'éditeur entre guillemets doubles <string name="Command_Destinations_Label"> Destinations </string> + <string name="Command_Environments_Label"> + Mes environnements + </string> + <string name="Command_Facebook_Label"> + Facebook + </string> <string name="Command_Flickr_Label"> Flickr </string> @@ -5504,6 +5597,12 @@ Essayez avec le chemin d'accès à l'éditeur entre guillemets doubles <string name="Command_Destinations_Tooltip"> Destinations intéressantes </string> + <string name="Command_Environments_Tooltip"> + Mes environnements + </string> + <string name="Command_Facebook_Tooltip"> + Publier sur Facebook + </string> <string name="Command_Flickr_Tooltip"> Charger sur Flickr </string> @@ -5699,6 +5798,12 @@ Essayez avec le chemin d'accès à l'éditeur entre guillemets doubles <string name="ExperiencePermission12"> accepter automatiquement les permissions d’expérience </string> + <string name="ExperiencePermission16"> + forcez votre avatar à s’asseoir + </string> + <string name="ExperiencePermission17"> + changer vos paramètres d'environnement + </string> <string name="ExperiencePermissionShortUnknown"> a effectué une opération inconnue : [Permission] </string> @@ -5723,6 +5828,12 @@ Essayez avec le chemin d'accès à l'éditeur entre guillemets doubles <string name="ExperiencePermissionShort12"> Permission </string> + <string name="ExperiencePermissionShort16"> + M'asseoir + </string> + <string name="ExperiencePermissionShort17"> + Environnement + </string> <string name="logging_calls_disabled_log_empty"> Les conversations ne sont pas archivées. Pour commencer à tenir un journal, choisissez Enregistrer : Journal seul ou Enregistrer : Journal et transcriptions sous Préférences > Chat. </string> diff --git a/indra/newview/skins/default/xui/it/floater_about_land.xml b/indra/newview/skins/default/xui/it/floater_about_land.xml index 0a7837e122..03e03095d6 100644 --- a/indra/newview/skins/default/xui/it/floater_about_land.xml +++ b/indra/newview/skins/default/xui/it/floater_about_land.xml @@ -367,11 +367,11 @@ Solamente terreni più grandi possono essere abilitati nella ricerca. Fotografia: </text> <texture_picker label="" name="snapshot_ctrl" tool_tip="Clicca per scegliere una immagine"/> - <text name="allow_see_label"> + <text name="allow_see_label" top="170"> Gli avatar di altri lotti possono vedere gli avatar che si trovano in questo lotto e chattare con loro </text> - <check_box label="Vedi avatar" name="SeeAvatarsCheck" tool_tip="Consente ad avatar in altri lotti di vedere e chattare con avatar in questo lotto e viceversa."/> - <text name="landing_point"> + <check_box label="Vedi avatar" top="170" name="SeeAvatarsCheck" tool_tip="Consente ad avatar in altri lotti di vedere e chattare con avatar in questo lotto e viceversa."/> + <text name="landing_point" width="225"> Punto di atterraggio: [LANDING] </text> <button label="Imposta" label_selected="Imposta" name="Set" tool_tip="Imposta il punto di atterraggio dove arrivano i visitatori. Impostalo nel punto dove si trova il tuo avatar in questo terreno." width="60"/> @@ -449,7 +449,7 @@ Media: <panel.string name="estate_override"> Una o più di queste impostazioni sono già impostate a livello regionale </panel.string> - <check_box label="Chiunque può visitare (Se si rimuove la selezione vengono create linee di espulsione)" name="public_access"/> + <check_box label="Chiunque può visitare" tool_tip="Se si rimuove la selezione vengono create linee di espulsione" name="public_access"/> <check_box label="È necessario avere più di 18 anni [ESTATE_AGE_LIMIT]" name="limit_age_verified" tool_tip="Per poter visitare questo lotto i Residenti devono avere almeno 18 anni. Vedi [SUPPORT_SITE] per maggiori informazioni."/> <check_box label="È necessario aver registrato le informazioni di pagamento [ESTATE_PAYMENT_LIMIT]" name="limit_payment" tool_tip="Per poter visitare questo lotto i Residenti devono aver fornito informazioni di pagamento a Linden Lab. Vedi [SUPPORT_SITE] per maggiori informazioni."/> <check_box label="Consenti gruppo [GRUPPO] senza restrizioni" name="GroupCheck" tool_tip="Imposta il gruppo nel pannello generale."/> @@ -484,5 +484,6 @@ Media: </panel> </panel> <panel label="ESPERIENZE" name="land_experiences_panel"/> + <panel label="AMBIENTE" name="land_environment_panel"/> </tab_container> </floater> diff --git a/indra/newview/skins/default/xui/it/floater_adjust_environment.xml b/indra/newview/skins/default/xui/it/floater_adjust_environment.xml new file mode 100644 index 0000000000..948e2d03aa --- /dev/null +++ b/indra/newview/skins/default/xui/it/floater_adjust_environment.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_adjust_snapshot" title="Illuminazione personale"> + <layout_stack name="outer_stack"> + <layout_panel name="env_controls"> + <layout_stack name="settings_stack"> + <layout_panel> + <button label="Reimposta" name="btn_reset" tool_tip="Chiudi e reimposta a Ambiente Condiviso"/> + <text name="cloud_map_label"> + Immagine nuvola: + </text> + </layout_panel> + <layout_panel> + <text name="label"> + Sole: + </text> + <check_box label="Mostra marcatore" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <check_box label="Mostra marcatore" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/it/floater_beacons.xml b/indra/newview/skins/default/xui/it/floater_beacons.xml index b7ab265cc2..303c2fdd6c 100644 --- a/indra/newview/skins/default/xui/it/floater_beacons.xml +++ b/indra/newview/skins/default/xui/it/floater_beacons.xml @@ -18,5 +18,7 @@ <check_box label="Fonti sonore" name="sounds"/> <check_box label="Fonti delle particelle" name="particles"/> <check_box label="Fonti multimedia" name="moapbeacon"/> + <check_box label="Sole" name="sun"/> + <check_box label="Luna" name="moon"/> </panel> </floater> diff --git a/indra/newview/skins/default/xui/it/floater_bulk_perms.xml b/indra/newview/skins/default/xui/it/floater_bulk_perms.xml index 10bbe933e3..b7572f1776 100644 --- a/indra/newview/skins/default/xui/it/floater_bulk_perms.xml +++ b/indra/newview/skins/default/xui/it/floater_bulk_perms.xml @@ -30,6 +30,7 @@ <icon name="icon_sound" tool_tip="Suoni"/> <check_box label="Texture" name="check_texture"/> <icon name="icon_texture" tool_tip="Texture"/> + <icon name="icon_setting" tool_tip="Impostazioni ambiente"/> <button label="√ Tutti" label_selected="Tutti" name="check_all"/> <button label="Cancella" label_selected="Nessuno" name="check_none"/> <text name="newperms"> diff --git a/indra/newview/skins/default/xui/it/floater_buy_currency.xml b/indra/newview/skins/default/xui/it/floater_buy_currency.xml index 743969f557..522d26373e 100644 --- a/indra/newview/skins/default/xui/it/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/it/floater_buy_currency.xml @@ -60,8 +60,7 @@ l'oggetto. </text> <button label="Acquista" name="buy_btn"/> <button label="Annulla" name="cancel_btn"/> - <text left="5" name="info_cannot_buy" right="-5"> + <floater.string name="info_cannot_buy" left="160" font="SansSerifBig"> Non in grado di acquistare - </text> - <button label="Continua sul Web" name="error_web"/> + </floater.string> </floater> diff --git a/indra/newview/skins/default/xui/it/floater_delete_env_preset.xml b/indra/newview/skins/default/xui/it/floater_delete_env_preset.xml deleted file mode 100644 index 31cf01fc7b..0000000000 --- a/indra/newview/skins/default/xui/it/floater_delete_env_preset.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<floater name="Delete Env Preset" title="CANCELLA VALORE PREDEFINITO AMB"> - <string name="title_water"> - Cancella valore predefinito acqua - </string> - <string name="title_sky"> - Cancella valore predefinito cielo - </string> - <string name="title_day_cycle"> - Cancella ciclo giornata - </string> - <string name="label_water"> - Valore predefinito: - </string> - <string name="label_sky"> - Valore predefinito: - </string> - <string name="label_day_cycle"> - Ciclo giornata: - </string> - <string name="msg_confirm_deletion"> - Sei sicuro di volere eliminare il valore predefinito selezionato? - </string> - <string name="msg_sky_is_referenced"> - Impossibile rimuovere un valore predefinito che viene utilizzato in uno o più cicli di giornata. - </string> - <string name="combo_label"> - -Seleziona un valore predefinito- - </string> - <text name="label"> - Valore predefinito: - </text> - <button label="Elimina" name="delete"/> - <button label="Annulla" name="cancel"/> -</floater> diff --git a/indra/newview/skins/default/xui/it/floater_edit_ext_day_cycle.xml b/indra/newview/skins/default/xui/it/floater_edit_ext_day_cycle.xml new file mode 100644 index 0000000000..12efdb81b5 --- /dev/null +++ b/indra/newview/skins/default/xui/it/floater_edit_ext_day_cycle.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_edit_extdaycycle" title="Modifica ciclo giornata"> + <string name="title_new"> + Crea un nuovo ciclo giornata + </string> + <string name="title_edit"> + Modifica ciclo giornata + </string> + <string name="hint_new"> + Dai un nome al ciclo della giornata, regola i comandi per crearlo e fai clic su "Salva". + </string> + <string name="hint_edit"> + Per modificare il ciclo della giornata, regola i comandi seguenti e fai clic su "Salva". + </string> + <string name="time_label"> + ([HH]:[MM]) + </string> + <string name="sky_track_label"> + Cielo [ALT] + </string> + <string name="sky_label"> + Cielo + </string> + <string name="water_label"> + Acqua + </string> + <string name="commit_parcel"> + Applica al lotto + </string> + <string name="commit_region"> + Applica alla regione + </string> + <layout_stack name="outer_stack"> + <layout_panel name="name_and_import"> + <text name="label"> + Nome ciclo giornata: + </text> + <button label="Importa" name="btn_import" tool_tip="Importa impostazioni legacy dal disco."/> + </layout_panel> + <layout_panel name="content"> + <layout_stack name="content_stack"> + <layout_panel name="timeline_track_selection"> + <panel name="timeline_layers"> + <button label="Cielo 4:" name="sky4_track"/> + <button label="Cielo 3:" name="sky3_track"/> + <button label="Cielo 2:" name="sky2_track"/> + <button label="Suolo" name="sky1_track"/> + <button label="Acqua" name="water_track"/> + </panel> + <panel name="timeline"> + <text name="p0" value="0%[DSC]"/> + <text name="p1" value="25%[DSC]"/> + <text name="p2" value="50%[DSC]"/> + <text name="p3" value="75%[DSC]"/> + <text name="p4" value="100%[DSC]"/> + <multi_slider initial_value="0" name="WLTimeSlider"/> + <multi_slider initial_value="0" name="WLDayCycleFrames"/> + <text name="current_time" value="[PRCNT]%[DSC]"/> + <layout_stack> + <layout_panel> + <button label="Clona Percorso Da" name="copy_track"/> + <button label="Carica Percorso Da" name="load_track"/> + <button label="Cancella Percorso" name="clear_track"/> + </layout_panel> + <layout_panel> + <layout_stack name="progress_control"> + <layout_panel name="skip_back"> + <button name="skip_back_btn" tool_tip="Passo indietro"/> + </layout_panel> + <layout_panel name="skip_forward"> + <button name="skip_forward_btn" tool_tip="Passo avanti"/> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel> + <button label="Aggiungi [FRAME]" name="add_frame"/> + <button label="Carica [FRAME]" name="btn_load_frame"/> + <button label="Elimina [FRAME]" name="delete_frame"/> + </layout_panel> + </layout_stack> + </panel> + </layout_panel> + <layout_panel name="frame_edit_controls"> + <text name="icn_lock_edit"> + Seleziona un fotogramma chiave dalla cronologia degli eventi qui sopra per modificare le impostazioni. + </text> + </layout_panel> + <layout_panel name="frame_settings_water"> + <tab_container name="water_tabs"> + <panel label="Acqua" name="water_panel"/> + </tab_container> + </layout_panel> + <layout_panel name="frame_settings_sky"> + <tab_container name="sky_tabs"> + <panel label="Atmosfera e illuminazione" name="atmosphere_panel"/> + <panel label="Nuvole" name="clouds_panel"/> + <panel label="Sole e Luna" name="moon_panel"/> + </tab_container> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel name="buttons"> + <button label="Salva" name="save_btn"/> + <button label="Annulla" name="cancel_btn"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/it/floater_fixedenvironment.xml b/indra/newview/skins/default/xui/it/floater_fixedenvironment.xml new file mode 100644 index 0000000000..4ca13a5891 --- /dev/null +++ b/indra/newview/skins/default/xui/it/floater_fixedenvironment.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="Fixed Environment" title="Ambiente stabilito"> + <string name="edit_sky"> + Modifica cielo: + </string> + <string name="edit_water"> + Modifica acqua: + </string> + <layout_stack name="floater_stack"> + <layout_panel name="info_panel"> + <button label="Carica" name="btn_load" tool_tip="Carica impostazioni dall’inventario"/> + <button label="Importa" name="btn_import" tool_tip="Importa impostazioni legacy dal disco."/> + </layout_panel> + <layout_panel name="button_panel"> + <layout_stack name="button_bar_ls"> + <layout_panel name="save_btn_lp"> + <button label="Salva" name="btn_commit"/> + </layout_panel> + <layout_panel name="revert_btn_lp"> + <button label="Annulla" name="btn_cancel" tool_tip="Ripristina l'ultima versione salvata"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/it/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/it/floater_inventory_view_finder.xml index fe41b8ca65..c12c031198 100644 --- a/indra/newview/skins/default/xui/it/floater_inventory_view_finder.xml +++ b/indra/newview/skins/default/xui/it/floater_inventory_view_finder.xml @@ -12,6 +12,7 @@ <check_box label="Suoni" name="check_sound"/> <check_box label="Texture" name="check_texture"/> <check_box label="Fotografie" name="check_snapshot"/> + <check_box label="Impostazioni" name="check_settings"/> <button label="Tutto" label_selected="Tutto" name="All"/> <button label="Nulla" label_selected="Nulla" name="None"/> <check_box label="Mostra sempre le cartelle" name="check_show_empty"/> diff --git a/indra/newview/skins/default/xui/it/floater_merchant_outbox.xml b/indra/newview/skins/default/xui/it/floater_merchant_outbox.xml deleted file mode 100644 index 7a1f7f0a0c..0000000000 --- a/indra/newview/skins/default/xui/it/floater_merchant_outbox.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="floater_merchant_outbox" title="CASELLA IN USCITA DEL RIVENDITORE"> - <string name="OutboxFolderCount1"> - 1 cartella - </string> - <string name="OutboxFolderCountN"> - [NUM] cartelle - </string> - <string name="OutboxImporting"> - Invio cartelle... - </string> - <string name="OutboxInitializing"> - Inizializzazione... - </string> - <panel label="" name="panel_1"> - <panel name="panel_2"> - <panel name="outbox_inventory_placeholder_panel"> - <text name="outbox_inventory_placeholder_title"> - Caricamento in corso... - </text> - </panel> - </panel> - <panel name="panel_3"> - <panel name="outbox_generic_drag_target"> - <text name="text_1"> - Trascina elementi qui per creare cartelle - </text> - </panel> - <button label="Invia a Marketplace" name="outbox_import_btn" tool_tip="Push su negozio Marketplace"/> - </panel> - </panel> -</floater> diff --git a/indra/newview/skins/default/xui/it/floater_my_environments.xml b/indra/newview/skins/default/xui/it/floater_my_environments.xml new file mode 100644 index 0000000000..bcbf4613f3 --- /dev/null +++ b/indra/newview/skins/default/xui/it/floater_my_environments.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater label="Luoghi" name="my_environments" title="I MIEI AMBIENTI"> + <layout_stack> + <layout_panel label="Filtri" name="filter_panel"> + <check_box label="Giorni" name="chk_days"/> + <check_box label="Cieli" name="chk_skies"/> + <check_box label="Acqua" name="chk_water"/> + <filter_editor label="Filtra Ambienti" name="flt_search"/> + </layout_panel> + <layout_panel label="Ambienti" name="list_panel"> + <panel label="pnl_inv_wrap" name="pnl_inv_wrap"/> + </layout_panel> + <layout_panel> + <check_box initial_value="false" label="Mostra tutte le cartelle" name="chk_showfolders"/> + </layout_panel> + <layout_panel name="pnl_control"> + <panel label="bottom_panel" name="pnl_bottom"> + <menu_button name="btn_gear" tool_tip="Altre opzioni"/> + <menu_button name="btn_newsettings" tool_tip="Crea nuova impostazione"/> + <button name="btn_del" tool_tip="Rimuovi l'articolo selezionato"/> + </panel> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/it/floater_perms_default.xml b/indra/newview/skins/default/xui/it/floater_perms_default.xml index 9a88f53d47..bdfea6d0ad 100644 --- a/indra/newview/skins/default/xui/it/floater_perms_default.xml +++ b/indra/newview/skins/default/xui/it/floater_perms_default.xml @@ -37,6 +37,10 @@ <text name="label_12" tool_tip="Imposta autorizzazioni predefinite per la creazione di vestiti o parti del corpo"> Indossabili </text> + <text name="label_13" tool_tip="Imposta autorizzazioni predefinite per la creazione delle impostazioni dell’Ambiente"> + Impostazioni + </text> + <check_box name="env_settings_c" value="true"/> </panel> <button label="OK" label_selected="OK" name="ok"/> <button label="Annulla" label_selected="Annulla" name="cancel"/> diff --git a/indra/newview/skins/default/xui/it/floater_pick_track.xml b/indra/newview/skins/default/xui/it/floater_pick_track.xml new file mode 100644 index 0000000000..8e1f3d7065 --- /dev/null +++ b/indra/newview/skins/default/xui/it/floater_pick_track.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="track picker" title="PREFERITO: PERCORSO"> + <layout_stack name="adjuster"> + <layout_panel name="pnl_desc"> + <text name="select_description"> + Seleziona fonte cielo: + </text> + </layout_panel> + <layout_panel name="pnl_traks"> + <radio_group name="track_selection"> + <radio_item label="Cielo4 [ALT]" name="radio_sky4" value="4"/> + <radio_item label="Cielo3 [ALT]" name="radio_sky3" value="3"/> + <radio_item label="Cielo2 [ALT]" name="radio_sky2" value="2"/> + <radio_item label="Suolo" name="radio_sky1" value="1"/> + </radio_group> + </layout_panel> + <layout_panel name="pnl_ok_cancel"> + <button label="OK" label_selected="OK" name="btn_select"/> + <button label="Annulla" label_selected="Annulla" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/it/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/it/floater_preferences_graphics_advanced.xml index 3773ef3711..53f9ebc6fd 100644 --- a/indra/newview/skins/default/xui/it/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/it/floater_preferences_graphics_advanced.xml @@ -82,7 +82,6 @@ <check_box initial_value="true" label="Acqua trasparente" name="TransparentWater"/> <check_box initial_value="true" label="Mappatura urti e brillantezza" name="BumpShiny"/> <check_box initial_value="true" label="Luci locali" name="LocalLights"/> - <check_box initial_value="true" label="Shader di base" name="BasicShaders" tool_tip="Se si disattiva questa opzione, si possono evitare interruzioni nei driver di alcune schede grafiche"/> <slider label="Dettagli terreno:" name="TerrainDetail"/> <text name="TerrainDetailText"> Basso diff --git a/indra/newview/skins/default/xui/it/floater_preview_texture.xml b/indra/newview/skins/default/xui/it/floater_preview_texture.xml index 5b4054514e..8e8d020067 100644 --- a/indra/newview/skins/default/xui/it/floater_preview_texture.xml +++ b/indra/newview/skins/default/xui/it/floater_preview_texture.xml @@ -10,7 +10,7 @@ Descrizione: </text> <text name="dimensions"> - [WIDTH] px x [HEIGHT] px + [WIDTH]px x [HEIGHT]px </text> <text name="aspect_ratio"> Antreprima rapporto di visualizzazione diff --git a/indra/newview/skins/default/xui/it/floater_settings_picker.xml b/indra/newview/skins/default/xui/it/floater_settings_picker.xml new file mode 100644 index 0000000000..31dfb6ef19 --- /dev/null +++ b/indra/newview/skins/default/xui/it/floater_settings_picker.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="settings picker" title="PREFERITO: IMPOSTAZIONI"> + <floater.string name="pick title"> + Preferito: + </floater.string> + <floater.string name="pick_track"> + SELEZIONA PERCORSO + </floater.string> + <floater.string name="pick_settings"> + SELEZIONA IMPOSTAZIONI + </floater.string> + <floater.string name="track_water"> + Acqua + </floater.string> + <floater.string name="track_ground"> + Suolo + </floater.string> + <floater.string name="track_sky"> + Cielo[NUM] + </floater.string> + <layout_stack name="test_stack"> + <layout_panel name="inv_list"> + <filter_editor label="Filtro texture" name="flt_inventory_search"/> + </layout_panel> + <layout_panel name="temp"> + <button label="OK" label_selected="OK" name="btn_select"/> + <button label="Annulla" label_selected="Annulla" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/it/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/it/floater_texture_ctrl.xml index 27a17868a7..f857bfe49f 100644 --- a/indra/newview/skins/default/xui/it/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/it/floater_texture_ctrl.xml @@ -9,17 +9,13 @@ <text name="Multiple"> Texture multiple </text> - <radio_group name="mode_selection"> - <radio_item label="Inventario" name="inventory" value="0"/> - <radio_item label="Locale" name="local" value="1"/> - </radio_group> - <text name="unknown"> - Dimensioni: [DIMENSIONS] - </text> + <combo_box name="mode_selection"> + <combo_box.item label="Inventario" name="inventory" value="0"/> + <combo_box.item label="Locale" name="local" value="1"/> + </combo_box> <button label="Default" label_selected="Default" name="Default"/> <button label="Vuoto" label_selected="Vuoto" name="Blank"/> <button label="Niente" label_selected="Niente" name="None"/> - <check_box initial_value="true" label="Applica adesso" name="apply_immediate_check"/> <text name="preview_disabled" value="Anteprima disattivata"/> <filter_editor label="Filtro texture" name="inventory search editor"/> <check_box initial_value="false" label="Mostra cartelle" name="show_folders_check"/> @@ -30,6 +26,22 @@ <column label="Nome" name="unit_name"/> <column label="ID" name="unit_id_HIDDEN"/> </scroll_list> + <combo_box name="l_bake_use_texture_combo_box" tool_tip="Scegli la bake della texture"> + <combo_box.item label="Nessuna" name="None"/> + <combo_box.item label="BAKED_HEAD" name="BAKED_HEAD"/> + <combo_box.item label="BAKED_UPPER" name="BAKED_UPPER"/> + <combo_box.item label="BAKED_LOWER" name="BAKED_LOWER"/> + <combo_box.item label="BAKED_EYES" name="BAKED_EYES"/> + <combo_box.item label="BAKED_SKIRT" name="BAKED_SKIRT"/> + <combo_box.item label="BAKED_HAIR" name="BAKED_HAIR"/> + <combo_box.item label="BAKED_LEFTARM" name="BAKED_LEFTARM"/> + <combo_box.item label="BAKED_LEFTLEG" name="BAKED_LEFTLEG"/> + <combo_box.item label="BAKED_AUX1" name="BAKED_AUX1"/> + <combo_box.item label="BAKED_AUX2" name="BAKED_AUX2"/> + <combo_box.item label="BAKED_AUX3" name="BAKED_AUX3"/> + </combo_box> + <check_box initial_value="false" label="Nascondi regione mesh base" name="hide_base_mesh_region"/> <button label="OK" label_selected="OK" name="Select"/> <button label="Annulla" label_selected="Annulla" name="Cancel"/> + <check_box initial_value="true" label="Applica adesso" name="apply_immediate_check"/> </floater> diff --git a/indra/newview/skins/default/xui/it/menu_cof_attachment.xml b/indra/newview/skins/default/xui/it/menu_cof_attachment.xml index 699490c8f1..8861cc726f 100644 --- a/indra/newview/skins/default/xui/it/menu_cof_attachment.xml +++ b/indra/newview/skins/default/xui/it/menu_cof_attachment.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="COF Attachment"> + <menu_item_call label="Tocca" name="touch_attach" /> + <menu_item_call label="Modifica" name="edit_item" /> <menu_item_call label="Stacca" name="detach"/> </context_menu> diff --git a/indra/newview/skins/default/xui/it/menu_inventory.xml b/indra/newview/skins/default/xui/it/menu_inventory.xml index de6855ca97..d2fbcafe97 100644 --- a/indra/newview/skins/default/xui/it/menu_inventory.xml +++ b/indra/newview/skins/default/xui/it/menu_inventory.xml @@ -10,7 +10,6 @@ <menu_item_call label="Attiva" name="Marketplace Activate"/> <menu_item_call label="Disattiva" name="Marketplace Deactivate"/> <menu_item_call label="Condividi" name="Share"/> - <menu_item_call label="Compra" name="Task Buy"/> <menu_item_call label="Apri" name="Task Open"/> <menu_item_call label="Esegui" name="Task Play"/> <menu_item_call label="Proprietà " name="Task Properties"/> @@ -34,6 +33,7 @@ <menu_item_call label="Nuove mutande" name="New Underpants"/> <menu_item_call label="Nuovo Alfa Mask" name="New Alpha Mask"/> <menu_item_call label="Nuovo tatuaggio" name="New Tattoo"/> + <menu_item_call label="Nuovo Universale" name="New Universal"/> <menu_item_call label="Nuova fisica" name="New Physics"/> </menu> <menu label="Nuove parti del corpo" name="New Body Parts"> @@ -42,6 +42,11 @@ <menu_item_call label="Nuovi capelli" name="New Hair"/> <menu_item_call label="Nuovi occhi" name="New Eyes"/> </menu> + <menu label="Nuove impostazioni" name="New Settings"> + <menu_item_call label="Nuovo cielo" name="New Sky"/> + <menu_item_call label="Nuova acqua" name="New Water"/> + <menu_item_call label="Nuovo ciclo giornata" name="New Day Cycle"/> + </menu> <menu label="Usa come impostazione predefinita per" name="upload_def"> <menu_item_call label="Caricamenti immagini" name="Image uploads"/> <menu_item_call label="Caricamenti suoni" name="Sound uploads"/> @@ -100,9 +105,12 @@ <menu_item_call label="Indossa" name="Wearable And Object Wear"/> <menu label="Attacca a" name="Attach To"/> <menu label="Attacca all'HUD" name="Attach To HUD"/> + <menu_item_call label="Tocca" name="Attachment Touch" /> <menu_item_call label="Modifica" name="Wearable Edit"/> <menu_item_call label="Aggiungi" name="Wearable Add"/> <menu_item_call label="Togli" name="Take Off"/> + <menu_item_call label="Applica solo a me stesso" name="Settings Apply Local"/> + <menu_item_call label="Applica al lotto" name="Settings Apply Parcel"/> <menu_item_call label="Copia negli annunci Marketplace" name="Marketplace Copy"/> <menu_item_call label="Sposta negli annunci Marketplace" name="Marketplace Move"/> <menu_item_call label="--nessuna opzione--" name="--no options--"/> diff --git a/indra/newview/skins/default/xui/it/menu_inventory_add.xml b/indra/newview/skins/default/xui/it/menu_inventory_add.xml index 62da61cd6b..6f9212f56b 100644 --- a/indra/newview/skins/default/xui/it/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/it/menu_inventory_add.xml @@ -5,9 +5,7 @@ <menu_item_call label="Suono ([COST]L$)..." name="Upload Sound"/> <menu_item_call label="Animazione ([COST]L$)..." name="Upload Animation"/> <menu_item_call label="Modella..." name="Upload Model"/> - <menu_item_call label="Procedura guidata modellazione..." name="Upload Model Wizard"/> - <menu_item_call label="In blocco ([COST]L$ per file)..." name="Bulk Upload"/> - <menu_item_call label="Definisci diritti di caricamento predefiniti" name="perm prefs"/> + <menu_item_call label="In blocco..." name="Bulk Upload"/> </menu> <menu_item_call label="Nuova cartella" name="New Folder"/> <menu_item_call label="Nuovo script" name="New Script"/> @@ -25,6 +23,7 @@ <menu_item_call label="Nuovi slip" name="New Underpants"/> <menu_item_call label="Nuovo Alfa (trasparenza)" name="New Alpha"/> <menu_item_call label="Nuovo tatuaggio" name="New Tattoo"/> + <menu_item_call label="Nuovo Universale" name="New Universal"/> <menu_item_call label="Nuova fisica" name="New Physics"/> </menu> <menu label="Nuove parti del corpo" name="New Body Parts"> @@ -33,4 +32,9 @@ <menu_item_call label="Nuovi capelli" name="New Hair"/> <menu_item_call label="Nuovi occhi" name="New Eyes"/> </menu> + <menu label="Nuove impostazioni" name="New Settings"> + <menu_item_call label="Nuovo cielo" name="New Sky"/> + <menu_item_call label="Nuova acqua" name="New Water"/> + <menu_item_call label="Nuovo ciclo giornata" name="New Day Cycle"/> + </menu> </menu> diff --git a/indra/newview/skins/default/xui/it/menu_outfit_gear.xml b/indra/newview/skins/default/xui/it/menu_outfit_gear.xml index 62c6d53e1c..cf45fec09e 100644 --- a/indra/newview/skins/default/xui/it/menu_outfit_gear.xml +++ b/indra/newview/skins/default/xui/it/menu_outfit_gear.xml @@ -20,6 +20,7 @@ <menu_item_call label="Nuovo Alpha (trasparenza)" name="New Alpha"/> <menu_item_call label="Nuova fisica" name="New Physics"/> <menu_item_call label="Nuovo tatuaggio" name="New Tattoo"/> + <menu_item_call label="Nuovo Universale" name="New Universal"/> </menu> <menu label="Nuove parti del corpo" name="New Body Parts"> <menu_item_call label="Nuova figura corporea" name="New Shape"/> diff --git a/indra/newview/skins/default/xui/it/menu_save_settings.xml b/indra/newview/skins/default/xui/it/menu_save_settings.xml new file mode 100644 index 0000000000..80c0ef90a6 --- /dev/null +++ b/indra/newview/skins/default/xui/it/menu_save_settings.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="save_settings_menu"> + <menu_item_check label="Salva" name="save_settings"/> + <menu_item_check label="Salva con nome" name="save_as_new_settings"/> + <menu_item_check label="Esegui" name="commit_changes"/> + <menu_item_check label="Applica solo a me stesso" name="apply_local"/> + <menu_item_check label="Applica al lotto" name="apply_parcel"/> + <menu_item_check label="Applica alla regione" name="apply_region"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/it/menu_settings_add.xml b/indra/newview/skins/default/xui/it/menu_settings_add.xml new file mode 100644 index 0000000000..69fcacc374 --- /dev/null +++ b/indra/newview/skins/default/xui/it/menu_settings_add.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_add"> + <menu_item_call label="Nuovo cielo" name="New Sky"/> + <menu_item_call label="Nuova acqua" name="New Water"/> + <menu_item_call label="Nuovo ciclo giornata" name="New Day Cycle"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/it/menu_settings_gear.xml b/indra/newview/skins/default/xui/it/menu_settings_gear.xml new file mode 100644 index 0000000000..6a879814fc --- /dev/null +++ b/indra/newview/skins/default/xui/it/menu_settings_gear.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_gear"> + <menu_item_call label="Modifica" name="edit_settings"/> + <menu_item_call label="Applica solo a me stesso" name="Settings Apply Local"/> + <menu_item_call label="Applica al lotto" name="Settings Apply Parcel"/> + <menu_item_call label="Applica alla regione" name="Settings Apply Region"/> + <menu_item_call label="Copia" name="copy_settings"/> + <menu_item_call label="Incolla" name="paste_settings"/> + <menu_item_call label="Copia UUID" name="copy_uuid"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/it/menu_viewer.xml b/indra/newview/skins/default/xui/it/menu_viewer.xml index ae82a89d28..c7a10df910 100644 --- a/indra/newview/skins/default/xui/it/menu_viewer.xml +++ b/indra/newview/skins/default/xui/it/menu_viewer.xml @@ -79,30 +79,15 @@ <menu_item_check label="Proprietà del lotto" name="Parcel Properties"/> <menu_item_check label="Menu Avanzato" name="Show Advanced Menu"/> </menu> - <menu label="Dom" name="Sun"> + <menu label="Ambiente" name="Environment"> <menu_item_check label="Alba" name="Sunrise"/> <menu_item_check label="Mezzogiorno" name="Noon"/> <menu_item_check label="Tramonto" name="Sunset"/> <menu_item_check label="Mezzanotte" name="Midnight"/> - <menu_item_check label="Usa impostazioni regione" name="Use Region Settings"/> - </menu> - <menu label="Editor ambiente" name="Environment Editor"> - <menu_item_call label="Impostazioni ambiente..." name="Environment Settings"/> - <menu label="Valori predefiniti acqua" name="Water Presets"> - <menu_item_call label="Nuovo valore predefinito..." name="new_water_preset"/> - <menu_item_call label="Modifica valore predefinito..." name="edit_water_preset"/> - <menu_item_call label="Elimina valore predefinito..." name="delete_water_preset"/> - </menu> - <menu label="Valori predefiniti cielo" name="Sky Presets"> - <menu_item_call label="Nuovo valore predefinito..." name="new_sky_preset"/> - <menu_item_call label="Modifica valore predefinito..." name="edit_sky_preset"/> - <menu_item_call label="Elimina valore predefinito..." name="delete_sky_preset"/> - </menu> - <menu label="Valori predefiniti giorno" name="Day Presets"> - <menu_item_call label="Nuovo valore predefinito..." name="new_day_preset"/> - <menu_item_call label="Modifica valore predefinito..." name="edit_day_preset"/> - <menu_item_call label="Elimina valore predefinito..." name="delete_day_preset"/> - </menu> + <menu_item_check label="Utilizza ambienti condivisi" name="Use Shared Environment"/> + <menu_item_call label="I miei ambienti..." name="my_environs"/> + <menu_item_call label="Illuminazione personale..." name="adjustment_tool"/> + <menu_item_check label="Ferma nuvole" name="pause_clouds"/> </menu> </menu> <menu label="Costruisci" name="BuildTools"> @@ -168,7 +153,7 @@ <menu_item_call label="Suono ([COST] L$)..." name="Upload Sound"/> <menu_item_call label="Animazione ([COST] L$)..." name="Upload Animation"/> <menu_item_call label="Modella..." name="Upload Model"/> - <menu_item_call label="In blocco ([COST] L$ per file)..." name="Bulk Upload"/> + <menu_item_call label="In blocco..." name="Bulk Upload"/> </menu> <menu_item_call label="Annulla" name="Undo"/> <menu_item_call label="Ripeti" name="Redo"/> @@ -323,6 +308,9 @@ <menu_item_check label="Maschera alfa automatica (non differita)" name="Automatic Alpha Masks (non-deferred)"/> <menu_item_check label="Texture delle animazioni" name="Animation Textures"/> <menu_item_check label="Disabilita texture" name="Disable Textures"/> + <menu_item_check label="Disattiva Ambiente" name="Disable Ambient"/> + <menu_item_check label="Disattiva luce del sole" name="Disable Sunlight"/> + <menu_item_check label="Disattiva Luci locali" name="Disable Local Lights"/> <menu_item_check label="Rendering delle luci unite" name="Render Attached Lights"/> <menu_item_check label="Rendering particelle unite" name="Render Attached Particles"/> <menu_item_check label="Gli oggetti brillano quando sono sotto il cursore" name="Hover Glow Objects"/> @@ -413,6 +401,7 @@ </menu> <menu label="Admin" name="Deprecated"> <menu label="Take Off Clothing" name="Take Off Clothing"> + <menu_item_call label="Universale" name="Universal"/> <menu_item_call label="Fisica" name="Physics"/> </menu> <menu label="Guida" name="DeprecatedHelp"> diff --git a/indra/newview/skins/default/xui/it/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/it/menu_wearable_list_item.xml index c9a02d8a86..23abdd7bf2 100644 --- a/indra/newview/skins/default/xui/it/menu_wearable_list_item.xml +++ b/indra/newview/skins/default/xui/it/menu_wearable_list_item.xml @@ -3,6 +3,7 @@ <menu_item_call label="Sostituisci" name="wear_replace"/> <menu_item_call label="Indossa" name="wear_wear"/> <menu_item_call label="Aggiungi" name="wear_add"/> + <menu_item_call label="Tocca" name="touch" /> <menu_item_call label="Togli / Stacca" name="take_off_or_detach"/> <menu_item_call label="Stacca" name="detach"/> <context_menu label="Attacca a" name="wearable_attach_to"/> diff --git a/indra/newview/skins/default/xui/it/menu_wearing_gear.xml b/indra/newview/skins/default/xui/it/menu_wearing_gear.xml index de25f88aca..2f3a2aea43 100644 --- a/indra/newview/skins/default/xui/it/menu_wearing_gear.xml +++ b/indra/newview/skins/default/xui/it/menu_wearing_gear.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <toggleable_menu name="Gear Wearing"> - <menu_item_call label="Modifica vestiario" name="edit"/> + <menu_item_call label="Tocca" name="touch"/> + <menu_item_call label="Modifica" name="edit_item"/> + <menu_item_call label="Modifica vestiario" name="edit_outfit"/> <menu_item_call label="Togli" name="takeoff"/> <menu_item_call label="Copia gruppo vestiti negli Appunti" name="copy"/> </toggleable_menu> diff --git a/indra/newview/skins/default/xui/it/menu_wearing_tab.xml b/indra/newview/skins/default/xui/it/menu_wearing_tab.xml index ec375e5240..08b56888a3 100644 --- a/indra/newview/skins/default/xui/it/menu_wearing_tab.xml +++ b/indra/newview/skins/default/xui/it/menu_wearing_tab.xml @@ -1,8 +1,9 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="Wearing"> + <menu_item_call label="Tocca" name="touch_attach"/> <menu_item_call label="Togli" name="take_off"/> <menu_item_call label="Stacca" name="detach"/> - <menu_item_call label="Modifica vestiario" name="edit"/> + <menu_item_call label="Modifica vestiario" name="edit_outfit"/> <menu_item_call label="Modifica" name="edit_item"/> <menu_item_call label="Mostra originale" name="show_original"/> </context_menu> diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml index d7be208c51..1c43013255 100644 --- a/indra/newview/skins/default/xui/it/notifications.xml +++ b/indra/newview/skins/default/xui/it/notifications.xml @@ -266,6 +266,10 @@ Vuoi concedere i diritti di modifica ai residenti selezionati? Vuoi revocare i permessi di modifica dati ai residenti selezionati? <usetemplate name="okcancelbuttons" notext="No" yestext="Si"/> </notification> + <notification name="GroupNameLengthWarning"> + Il nome di un gruppo deve essere compreso tra [MIN_LEN] e [MAX_LEN] caratteri. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="UnableToCreateGroup"> Non è possibile creare il gruppo. [MESSAGE] @@ -360,7 +364,7 @@ Vuoi continuare? Non hai abbastanza L$ per iscriverti a questo gruppo. </notification> <notification name="CreateGroupCost"> - La creazione di questo gruppo costerà L$ 100. + La creazione di questo gruppo ti costerà [COST]L$. I gruppi devono avere più di un partecipante, o saranno eliminati definitivamente. Invita altri partecipanti entro le prossime 48 ore. <usetemplate canceltext="Annulla" name="okcancelbuttons" notext="Annulla" yestext="Crea un gruppo per L$ 100"/> @@ -501,6 +505,9 @@ Per collocare il media su una sola faccia, scegli Seleziona faccia, clicca su un <notification name="ErrorEncodingSnapshot"> Errore nella codifica della fotografia. </notification> + <notification name="ErrorCannotAffordUpload"> + Ti serviranno [COST]L$ per caricare questo articolo. + </notification> <notification name="ErrorPhotoCannotAfford"> Hai bisogno di L$ [COST] per salvare una foto nel tuo inventario. Puoi acquistare L$ o salvare la foto sul tuo computer. </notification> @@ -1740,11 +1747,14 @@ Vuoi cancellare quell'elemento? <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="GroupLimitInfo"> - Il numero massimo di gruppi per gli account Basic è [MAX_BASIC] e -per gli account [https://secondlife.com/premium/ Premium] è [MAX_PREMIUM]. -Se hai ridotto il livello del tuo account, dovrai essere iscritto a meno di [MAX_BASIC] gruppi prima di poter iscriverti a un nuovo gruppo. - -[https://secondlife.com/my/account/membership.php Passa a un livello superiore oggi stesso!] + I residenti con un'iscrizione Base possono aderire fino a [MAX_BASIC] gruppi. +Le iscrizioni Premium consentono fino a [MAX_PREMIUM]. [https://secondlife.com/my/account/membership.php? Per saperne di più o per l'aggiornamento] + <usetemplate name="okbutton" yestext="Chiudi"/> + </notification> + <notification name="GroupLimitInfoPlus"> + I residenti con un'iscrizione Base possono aderire fino a [MAX_BASIC] gruppi. +Le iscrizioni Premium consentono fino a [MAX_PREMIUM]. Le iscrizioni Premium Plus +consentono fino a [MAX_PREMIUM_PLUS]. [https://secondlife.com/my/account/membership.php? Per saperne di più o per l'aggiornamento] <usetemplate name="okbutton" yestext="Chiudi"/> </notification> <notification name="KickUser"> @@ -1963,6 +1973,10 @@ Cambierà migliaia di regioni e produrrà seri problemi ai vari server. Togliendo la spunta a questa opzione potrebbero essere rimosse le restrizioni che i proprietari di lotti hanno aggiunto per tenere lontani disturbatori, mantenere la privacy, o evitare che minorenni abbiano accesso a materiale per adulti. Parla con i proprietari del tuo lotto se ce n’è bisogno. <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="EstateParcelEnvironmentOverride"> + Togliendo la spunta a questa opzione potrebbero essere rimossi gli ambienti personalizzati che i proprietari hanno aggiunto ai loro lotti. Parlane con i proprietari del tuo lotto se ce n’è bisogno. Vuoi continuare? + <usetemplate name="okcancelbuttons" notext="Annulla" yestext="OK"/> + </notification> <notification name="RegionEntryAccessBlocked"> La regione che cerchi di visitare include contenuti che non corripondono al livello selezionato nelle preferenze. Per cambiare le preferenze seleziona Io > Preferenze > Generale. <usetemplate name="okbutton" yestext="OK"/> @@ -2443,7 +2457,15 @@ Inseriscilo in una pagina web per dare ad altri un accesso facile a questa ubica Questo file di ciclo giornaliero fa riferimento ad un file di cielo mancante: [SKY]. </notification> <notification name="WLRegionApplyFail"> - Queste impostazioni non possono essere applicare alla regione. Uscendo dalla regione e ritornandoci potrebbe risolvere il problema. Il motivo fornito: [FAIL_REASON] + Siamo spiacenti, queste impostazioni non possono essere applicate alla regione. Motivo: [FAIL_REASON] + </notification> + <notification name="WLLocalTextureDayBlock"> + Una texture Locale è in uso nel percorso [TRACK], fotogramma #[FRAMENO] ([FRAME%]) nel campo [FIELD]. +Utilizzando texture locali potrebbero non venire salvate le impostazioni. + </notification> + <notification name="WLLocalTextureFixedBlock"> + Una texture Locale è in uso nel campo [FIELD]. +Utilizzando texture locali potrebbero non venire salvate le impostazioni. </notification> <notification name="EnvCannotDeleteLastDayCycleKey"> Impossibile cancellare l'ultima chiave in questo ciclo giornata. Il ciclo giornata non può essere vuoto. Invece di cancellare la chiave restante, modificala e quindi creane una nuova. @@ -3294,6 +3316,22 @@ Per sicurezza, verranno bloccati per alcuni secondi. La tua voce è stata interrotta dal moderatore. <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FailedToGetBenefits"> + Purtroppo non siamo stati in grado di ottenere informazioni utili per questa sessione. Questo non dovrebbe accadere in un normale ambiente di produzione. Si prega di contattare il supporto. Questa sessione non funzionerà correttamente, si consiglia di riavviare. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="BulkUploadCostConfirmation"> + Questo caricherà [COUNT] oggetti a un costo totale di [COST]L$. Vuoi continuare con il caricamento? + <usetemplate name="okcancelbuttons" notext="Annulla" yestext="Carica"/> + </notification> + <notification name="BulkUploadNoCompatibleFiles"> + I file selezionati non possono essere caricati. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="BulkUploadIncompatibleFiles"> + Alcuni dei file selezionati non possono essere caricati. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="UploadCostConfirmation"> Questo caricamento costerà L$[PRICE]. Continuare con il caricamento? <usetemplate name="okcancelbuttons" notext="Annulla" yestext="Carica"/> @@ -4388,4 +4426,75 @@ Prova a selezionare un pezzo di terreno più piccolo. [REASON] <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FailedToFindSettings"> + Non abbiamo potuto caricare le impostazioni per [NAME] dal database. + </notification> + <notification name="FailedToLoadSettingsApply"> + Impossibile applicare le impostazioni all’ambiente. + </notification> + <notification name="FailedToBuildSettingsDay"> + Impossibile applicare le impostazioni all’ambiente. + </notification> + <notification name="NoEnvironmentSettings"> + Questa regione non supporta le impostazioni per l’ambiente. + </notification> + <notification label="Salva Outfit" name="SaveSettingAs"> + Salva con nome le impostazioni attuali dell’ambiente: + <form name="form"> + <input name="message"> + [DESC] (nuovo) + </input> + <button name="OK" text="OK"/> + <button name="Cancel" text="Annulla"/> + </form> + </notification> + <notification name="WLImportFail"> + Impossibile importare le impostazioni legacy vento e luce [NAME] da +[FILE]. + +[REASONS] + </notification> + <notification name="WLParcelApplyFail"> + Impossibile impostare l’ambiente per questo lotto. +Inserisci o seleziona un lotto che hai il permesso di modificare. + </notification> + <notification name="SettingsUnsuported"> + Questa regione non supporta le impostazioni. +Spostati in una regione che abbia le impostazioni abilitate e riprova. + </notification> + <notification name="SettingsConfirmLoss"> + Stai per perdere le modifiche che hai fatto a questo [TYPE] chiamato "[NAME]". +Vuoi continuare? + <usetemplate ignoretext="Sei sicuro di voler perdere le modifiche apportate?" name="okcancelignore" notext="No" yestext="Sì"/> + </notification> + <notification name="SettingsConfirmReset"> + Stai per rimuovere tutte le impostazioni applicate. +Vuoi continuare? + <usetemplate name="okcancelbuttons" notext="No" yestext="Sì"/> + </notification> + <notification name="PersonalSettingsConfirmReset"> + Stai per rimuovere tutte le Impostazioni personali illuminazione. Vuoi continuare? + <usetemplate name="okcancelbuttons" notext="No" yestext="Sì"/> + </notification> + <notification name="SettingsMakeNoTrans"> + Stai per importare impostazioni non trasferibili in questo ciclo giornata. Continuando, anche le impostazioni che stai modificando diventeranno non trasferibili. + +Questo cambiamento non può essere annullato. + +Vuoi continuare? + <usetemplate ignoretext="Sei sicuro di voler rendere le impostazioni non trasferibili?" name="okcancelignore" notext="No" yestext="Sì"/> + </notification> + <notification name="NoEditFromLibrary"> + Non puoi modificare le impostazioni direttamente dalla raccolta. +Copia nell’inventario e prova ancora. + </notification> + <notification name="EnvironmentApplyFailed"> + Abbiamo riscontrato un problema con queste impostazioni. Non possono essere salvate o applicate in questo momento. + </notification> + <notification name="TrackLoadFailed"> + Impossibile caricare il percorso in [TRACK]. + </notification> + <notification name="TrackLoadMismatch"> + Impossibile caricare il percorso da [TRACK1] a [TRACK2]. + </notification> </notifications> diff --git a/indra/newview/skins/default/xui/it/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/it/panel_edit_tattoo.xml index d76fb62c53..79938b79dc 100644 --- a/indra/newview/skins/default/xui/it/panel_edit_tattoo.xml +++ b/indra/newview/skins/default/xui/it/panel_edit_tattoo.xml @@ -1,9 +1,11 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_tattoo_panel"> - <panel name="avatar_tattoo_color_panel"> - <texture_picker label="Tatuaggio della testa" name="Head Tattoo" tool_tip="Clicca per scegliere una fotografia"/> - <texture_picker label="Tatuaggio superiore" name="Upper Tattoo" tool_tip="Clicca per scegliere una fotografia"/> - <texture_picker label="Tattuaggio inferiore" name="Lower Tattoo" tool_tip="Clicca per scegliere una fotografia"/> - <color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/> - </panel> + <scroll_container name="avatar_tattoo_scroll"> + <panel name="avatar_tattoo_color_panel"> + <texture_picker label="Tatuaggio testa" name="Head Tattoo" tool_tip="Fai clic per scegliere un’immagine"/> + <texture_picker label="Tatuaggio parte alta" name="Upper Tattoo" tool_tip="Fai clic per scegliere un’immagine"/> + <texture_picker label="Tatuaggio parte bassa" name="Lower Tattoo" tool_tip="Fai clic per scegliere un’immagine"/> + <color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Fai clic per aprire il selettore dei colori"/> + </panel> + </scroll_container> </panel> diff --git a/indra/newview/skins/default/xui/it/panel_edit_universal.xml b/indra/newview/skins/default/xui/it/panel_edit_universal.xml new file mode 100644 index 0000000000..10fab0e8be --- /dev/null +++ b/indra/newview/skins/default/xui/it/panel_edit_universal.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel name="edit_universal_panel"> + <scroll_container name="avatar_universal_scroll"> + <panel name="avatar_universal_color_panel"> + <texture_picker label="Tatuaggio testa" name="Head Universal Tattoo" tool_tip="Fai clic per scegliere un’immagine"/> + <texture_picker label="Tatuaggio parte alta" name="Upper Universal Tattoo" tool_tip="Fai clic per scegliere un’immagine"/> + <texture_picker label="Tatuaggio parte bassa" name="Lower Universal Tattoo" tool_tip="Fai clic per scegliere un’immagine"/> + <texture_picker label="Tatuaggio gonna" name="Skirt Tattoo" tool_tip="Fai clic per scegliere un’immagine"/> + <texture_picker label="Tatuaggio capelli" name="Hair Tattoo" tool_tip="Fai clic per scegliere un’immagine"/> + <texture_picker label="Tatuaggio occhi" name="Eyes Tattoo" tool_tip="Fai clic per scegliere un’immagine"/> + <texture_picker label="Tatuaggio braccio sinistro" name="Left Arm Tattoo" tool_tip="Fai clic per scegliere un’immagine"/> + <texture_picker label="Tatuaggio gamba sinistra" name="Left Leg Tattoo" tool_tip="Fai clic per scegliere un’immagine"/> + <texture_picker label="Tatuaggio Aux1" name="Aux1 Tattoo" tool_tip="Fai clic per scegliere un’immagine"/> + <texture_picker label="Tatuaggio Aux2" name="Aux2 Tattoo" tool_tip="Fai clic per scegliere un’immagine"/> + <texture_picker label="Tatuaggio Aux3" name="Aux3 Tattoo" tool_tip="Fai clic per scegliere un’immagine"/> + <color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Fai clic per aprire il selettore dei colori"/> + </panel> + </scroll_container> +</panel> diff --git a/indra/newview/skins/default/xui/it/panel_edit_wearable.xml b/indra/newview/skins/default/xui/it/panel_edit_wearable.xml index e54dc26d05..83824591d6 100644 --- a/indra/newview/skins/default/xui/it/panel_edit_wearable.xml +++ b/indra/newview/skins/default/xui/it/panel_edit_wearable.xml @@ -45,6 +45,9 @@ <string name="edit_tattoo_title"> Modifica del tatuaggio </string> + <string name="edit_universal_title"> + Modifica Universale: + </string> <string name="edit_physics_title"> Modifica fisica </string> @@ -93,6 +96,9 @@ <string name="tattoo_desc_text"> Tatuaggio: </string> + <string name="universal_desc_text"> + Universale: + </string> <string name="physics_desc_text"> Fisica: </string> diff --git a/indra/newview/skins/default/xui/it/panel_outbox_inventory.xml b/indra/newview/skins/default/xui/it/panel_outbox_inventory.xml deleted file mode 100644 index af5e05336e..0000000000 --- a/indra/newview/skins/default/xui/it/panel_outbox_inventory.xml +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<outbox_inventory_panel name="inventory_outbox" tool_tip="Trascina gli oggetti qui per prepararli per la vendita nel tuo negozio"/> diff --git a/indra/newview/skins/default/xui/it/panel_people.xml b/indra/newview/skins/default/xui/it/panel_people.xml index 38a03fb4d2..3df2368ae0 100644 --- a/indra/newview/skins/default/xui/it/panel_people.xml +++ b/indra/newview/skins/default/xui/it/panel_people.xml @@ -18,7 +18,7 @@ Stai cercando persone da frequentare? Prova la [secondlife:///app/worldmap Mappa <string name="no_groups_msg" value="Stai cercando gruppi di cui far parte? Prova [secondlife:///app/search/groups Cerca]."/> <string name="MiniMapToolTipMsg" value="[REGION](Fai doppio clic per aprire la Mappa, premi il tasto Maiusc e trascina per la panoramica)"/> <string name="AltMiniMapToolTipMsg" value="[REGION](Fai doppio clic per teleportarti, premi il tasto Maiusc e trascina per la panoramica)"/> - <string name="GroupCountWithInfo" value="Fai parte di [COUNT] gruppi e puoi iscriverti a [REMAINING] altri. [secondlife:/// Ne vuoi altri?]"/> + <string name="GroupCountWithInfo" value="Fai parte di [COUNT] gruppi e puoi ancora unirti a [REMAINING] gruppi. [secondlife:/// Aumenta il tuo limite]"/> <tab_container name="tabs"> <panel label="NELLE VICINANZE" name="nearby_panel"> <panel label="bottom_panel" name="nearby_buttons_panel"> @@ -51,7 +51,7 @@ Stai cercando persone da frequentare? Prova la [secondlife:///app/worldmap Mappa <dnd_button name="minus_btn" tool_tip="Lascia il gruppo selezionato"/> </panel> <text name="groupcount"> - Fai parte di [COUNT] gruppi e puoi iscriverti a [REMAINING] altri. + Fai parte di [COUNT] gruppi e puoi ancora unirti a [REMAINING] gruppi. </text> </panel> <panel label="RECENTE" name="recent_panel"> diff --git a/indra/newview/skins/default/xui/it/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/it/panel_preferences_graphics1.xml index f3ca9fafb3..c7739b8472 100644 --- a/indra/newview/skins/default/xui/it/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/it/panel_preferences_graphics1.xml @@ -32,10 +32,10 @@ </text> <check_box initial_value="true" label="Esegui sempre il rendering degli amici" name="AlwaysRenderFriends"/> <button label="Eccezioni..." name="RenderExceptionsButton"/> - <button label="Salva impostazioni come valori predefiniti..." name="PrefSaveButton"/> - <button label="Carica valore predefinito..." name="PrefLoadButton"/> + <button label="Salva impostazioni come valori predefiniti" name="PrefSaveButton" width="240" left="4"/> + <button label="Carica valore predefinito" name="PrefLoadButton" width="145" left_pad="7"/> min_val="0.125" - <button label="Elimina valore predefinito..." name="PrefDeleteButton"/> + <button label="Elimina valore predefinito" name="PrefDeleteButton" width="148" left_pad="7"/> <button label="Ripristina impostazioni consigliate" name="Defaults"/> <button label="Impostazioni avanzate..." name="AdvancedSettings"/> </panel> diff --git a/indra/newview/skins/default/xui/it/panel_preferences_setup.xml b/indra/newview/skins/default/xui/it/panel_preferences_setup.xml index aa3ff53f4a..c9d90539e1 100644 --- a/indra/newview/skins/default/xui/it/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/it/panel_preferences_setup.xml @@ -35,5 +35,5 @@ <text name="Proxy Settings:"> Impostazioni proxy: </text> - <button label="Regola impostazioni proxy" label_selected="Sfoglia" name="set_proxy"/> + <button label="Regola impostazioni proxy" label_selected="Sfoglia" name="set_proxy" width="160"/> </panel> diff --git a/indra/newview/skins/default/xui/it/panel_region_environment.xml b/indra/newview/skins/default/xui/it/panel_region_environment.xml index d7d9658e26..467bcdb005 100644 --- a/indra/newview/skins/default/xui/it/panel_region_environment.xml +++ b/indra/newview/skins/default/xui/it/panel_region_environment.xml @@ -1,33 +1,116 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Ambiente" name="panel_env_info"> - <text name="water_settings_title"> - Seleziona le impostazioni del ciclo dell'acqua e del cielo/giornata che vuoi che vedano tutti coloro che visitano la tua regione. Maggiori informazioni - </text> - <radio_group name="region_settings_radio_group"> - <radio_item label="Usa valori predefiniti di Second Life" name="use_sl_default_settings"/> - <radio_item label="Usa le impostazioni seguenti" name="use_my_settings"/> - </radio_group> - <panel name="user_environment_settings"> - <text name="water_settings_title"> - Impostazione Acqua - </text> - <combo_box name="water_settings_preset_combo"> - <combo_box.item label="-Seleziona un valore predefinito-" name="item0"/> - </combo_box> - <text name="sky_dayc_settings_title"> - Ciclo cielo / giornata - </text> - <radio_group name="sky_dayc_settings_radio_group"> - <radio_item label="Cielo fisso" name="my_sky_settings"/> - <radio_item label="Ciclo giornata" name="my_dayc_settings"/> - </radio_group> - <combo_box name="sky_settings_preset_combo"> - <combo_box.item label="-Seleziona un valore predefinito-" name="item0"/> - </combo_box> - <combo_box name="dayc_settings_preset_combo"> - <combo_box.item label="-Seleziona un valore predefinito-" name="item0"/> - </combo_box> - </panel> - <button label="Applica" name="apply_btn"/> - <button label="Annulla" name="cancel_btn"/> + <string name="str_label_use_default"> + Usa impostazioni predefinite + </string> + <string name="str_label_use_region"> + Usa impostazioni regione + </string> + <string name="str_altitude_desription"> + Cielo [INDEX]([ALTITUDE]m) + </string> + <string name="str_no_parcel"> + Non è stato selezionato alcun lotto. Le impostazioni ambientali sono disabilitate. + </string> + <string name="str_cross_region"> + Le impostazioni ambientali non sono disponibili oltre i confini della regione. + </string> + <string name="str_legacy"> + Le impostazioni ambientali non sono disponibili per questa regione. + </string> + <string name="str_disallowed"> + Il gestore della proprietà immobiliare non permette di cambiare gli ambienti del lotto in questa regione. + </string> + <string name="str_too_small"> + Il lotto deve essere di almeno 128 metri quadri per supportare un ambiente. + </string> + <string name="str_empty"> + (vuoto) + </string> + <string name="str_region_env"> + (ambiente regione) + </string> + <layout_stack> + <layout_panel name="pnl_environment_disabled"> + <text name="txt_environment_disabled"> + ... + </text> + </layout_panel> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_current"> + <button label="[USEDEFAULT]" name="btn_usedefault"/> + <button label="Utilizza Inventario" name="btn_select_inventory"/> + <button label="Personalizza" name="btn_edit"/> + <check_box label="I proprietari del lotto possono ignorare l’ambiente" name="chk_allow_override"/> + </layout_panel> + <layout_panel name="pnl_environment_length"> + <text name="lbl_apparent_time"> + [HH]:[MM][AP] ([PRC]%) + </text> + </layout_panel> + <layout_panel name="pnl_environment_buttons"/> + </layout_stack> + </layout_panel> + <layout_panel name="pnl_environment_altitudes"> + <panel name="pnl_alt1"> + <text name="txt_alt1"> + Cielo [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt1"> + Sconosciuto + </line_editor> + <settings_drop_target name="sdt_alt1" tool_tip="Trascina un’impostazione dall’Inventario a questa casella per selezionarla come cielo corrente."/> + </panel> + <panel name="pnl_alt2"> + <text name="txt_alt2"> + Cielo [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt2"> + Sconosciuto + </line_editor> + <settings_drop_target name="sdt_alt2" tool_tip="Trascina un’impostazione dall’Inventario a questa casella per selezionarla come cielo corrente."/> + </panel> + <panel name="pnl_alt3"> + <text name="txt_alt3"> + Cielo [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt3"> + Sconosciuto + </line_editor> + <settings_drop_target name="sdt_alt3" tool_tip="Trascina un’impostazione dall’Inventario a questa casella per selezionarla come cielo corrente."/> + </panel> + <multi_slider initial_value="0" name="sld_altitudes"> + <slider name="sld1" value="1000"/> + <slider name="sld2" value="2000"/> + <slider name="sld3" value="3000"/> + </multi_slider> + <panel name="pnl_ground"> + <text name="txt_ground"> + Suolo + </text> + <line_editor name="edt_invname_ground"> + Sconosciuto + </line_editor> + <settings_drop_target name="sdt_ground" tool_tip="Trascina un’impostazione dall’Inventario a questa casella per selezionarla come suolo."/> + </panel> + <panel name="pnl_water"> + <text name="txt_water"> + Acqua + </text> + <line_editor name="edt_invname_water"> + Sconosciuto + </line_editor> + <settings_drop_target name="sdt_water" tool_tip="Trascina un’impostazione dall’Inventario a questa casella per selezionarla come acqua."/> + </panel> + <button label="Reimposta" name="btn_rst_altitudes" tool_tip="Reimposta alle altitudini predefinite"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> </panel> diff --git a/indra/newview/skins/default/xui/it/panel_settings_sky_atmos.xml b/indra/newview/skins/default/xui/it/panel_settings_sky_atmos.xml new file mode 100644 index 0000000000..b2d27b93fc --- /dev/null +++ b/indra/newview/skins/default/xui/it/panel_settings_sky_atmos.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Atmosfera e illuminazione" name="panel_settings_sky_atmos"/> diff --git a/indra/newview/skins/default/xui/it/panel_settings_sky_clouds.xml b/indra/newview/skins/default/xui/it/panel_settings_sky_clouds.xml new file mode 100644 index 0000000000..e4dd5e00c0 --- /dev/null +++ b/indra/newview/skins/default/xui/it/panel_settings_sky_clouds.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Nuvole" name="panel_settings_sky_clouds"> + <layout_stack> + <layout_panel> + <slider label="X" name="cloud_density_x"/> + <slider label="Y" name="cloud_density_y"/> + <slider label="D" name="cloud_density_d"/> + <slider label="X" name="cloud_detail_x"/> + <slider label="Y" name="cloud_detail_y"/> + <slider label="D" name="cloud_detail_d"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/it/panel_settings_sky_density.xml b/indra/newview/skins/default/xui/it/panel_settings_sky_density.xml new file mode 100644 index 0000000000..3142d1442a --- /dev/null +++ b/indra/newview/skins/default/xui/it/panel_settings_sky_density.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Densità " name="panel_settings_sky_density"> + <layout_stack> + <layout_panel> + <slider label="Termine esponenziale Rayleigh:" name="rayleigh_exponential"/> + <slider label="Scala esponenziale Rayleigh:" name="rayleigh_exponential_scale"/> + <slider label="Termine lineare Rayleigh:" name="rayleigh_linear"/> + <slider label="Termine costante Rayleigh:" name="rayleigh_constant"/> + <slider label="Altitudine massima Rayleigh:" name="rayleigh_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="Termine esponenziale Mie:" name="mie_exponential"/> + <slider label="Scala esponenziale Mie:" name="mie_exponential_scale"/> + <slider label="Termine lineare Mie:" name="mie_linear"/> + <slider label="Termine costante Mie:" name="mie_constant"/> + <slider label="Fattore diverso Mie:" name="mie_aniso_factor"/> + <slider label="Altitudine massima Mie:" name="mie_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="Termine esponenziale di assorbimento:" name="absorption_exponential"/> + <slider label="Scala esponenziale di assorbimento:" name="absorption_exponential_scale"/> + <slider label="Termine lineare di assorbimento:" name="absorption_linear"/> + <slider label="Termine costante di assorbimento:" name="absorption_constant"/> + <slider label="Altitudine massima di assorbimento:" name="absorption_max_altitude"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/it/panel_settings_sky_sunmoon.xml b/indra/newview/skins/default/xui/it/panel_settings_sky_sunmoon.xml new file mode 100644 index 0000000000..5a167b0aea --- /dev/null +++ b/indra/newview/skins/default/xui/it/panel_settings_sky_sunmoon.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Sole e Luna" name="panel_settings_sky_hbodies"> + <layout_stack> + <layout_panel name="sun_layout"> + <check_box label="Mostra marcatore" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <layout_stack> + <layout_panel name="moon_layout"> + <check_box label="Mostra marcatore" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/it/panel_settings_water.xml b/indra/newview/skins/default/xui/it/panel_settings_water.xml new file mode 100644 index 0000000000..0d123a6249 --- /dev/null +++ b/indra/newview/skins/default/xui/it/panel_settings_water.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Acqua" name="panel_settings_water"> + <layout_stack name="water_stack1"> + <layout_panel> + <text name="FresnelOffsetText"> + Spostamento Fresnel: + </text> + </layout_panel> + <layout_panel> + <layout_stack name="water_stack2"> + <layout_panel> + <slider label="X:" name="water_normal_scale_x"/> + <slider label="Y:" name="water_normal_scale_y"/> + <slider label="Z:" name="water_normal_scale_z"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/it/panel_tools_texture.xml b/indra/newview/skins/default/xui/it/panel_tools_texture.xml index 46e2717647..5b4cb5868f 100644 --- a/indra/newview/skins/default/xui/it/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/it/panel_tools_texture.xml @@ -1,11 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Texture" name="Texture"> - <panel.string name="string repeats per meter"> - Ripetizioni al metro - </panel.string> - <panel.string name="string repeats per face"> - Ripetizioni per faccia - </panel.string> <text name="color label"> Colore </text> @@ -114,4 +108,5 @@ <spinner label="Spostamento orizzontale" name="shinyOffsetU"/> <spinner label="Spostamento verticale" name="shinyOffsetV"/> <check_box initial_value="false" label="Allinea facce planari" name="checkbox planar align" tool_tip="Allinea le texture su tutte le facce selezionate con l’ultima faccia selezionata. È richiesta la mappatura planare delle texture."/> + <button label="Alllinea" label_selected="Alllinea livelli di texture attuali" name="button align textures" tool_tip="Alllinea livelli di texture attuali"/> </panel> diff --git a/indra/newview/skins/default/xui/it/role_actions.xml b/indra/newview/skins/default/xui/it/role_actions.xml index 2bfaea8963..0e00165227 100644 --- a/indra/newview/skins/default/xui/it/role_actions.xml +++ b/indra/newview/skins/default/xui/it/role_actions.xml @@ -33,6 +33,7 @@ <action description="Cambiare impostazioni musica e multimediali" longdescription="Cambia le impostazioni per lo streaming della musica e dei video in Informazioni sul terreno > Media." name="land change media" value="20"/> <action description="Attiva 'Modifica terreno'" longdescription="Attiva 'Modifica terreno'. *ATTENZIONE* Informazioni sul terreno > Opzioni > Modifica terreno consente a chiunque di modificare la forma del tuo terreno e di collocare e spostare le piante Linden. Pertanto sii sicuro della scelta prima di assegnare questa Abilità . La funzione di modifica del terreno è attivata in Informazioni sul terreno > Opzioni." name="land edit" value="21"/> <action description="Attivazione di parametri per Informazioni sul terreno > Opzioni" longdescription="Premi Sicuro (nessun danno), Vola e consenti agli altri residenti di: modificare il terreno, costruire, creare punti di riferimento ed eseguire script nel terreno appartenente ad un gruppo in Informazioni sul terreno > scheda Opzioni." name="land options" value="22"/> + <action description="Modifica le impostazioni dell’ambiente e del ciclo giornata." longdescription="Cambia le impostazioni dell’ambiente e del ciclo giornata dalla scheda Informazioni sul terreno > Ambiente." name="land change environment" value="46"/> </action_set> <action_set description="Queste abilità permettono ai membri di non avere restrizioni in un lotto appartenente ad un gruppo." name="Parcel Powers"> <action description="Consenti sempre la modifica del terreno" longdescription="I membri con questo ruolo e abilità possono modificare il terreno appartenente ad un gruppo, anche se la funzionalità è disattivata in Informazioni sul terreno > Opzioni." name="land allow edit land" value="23"/> diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml index 9265ce9ec6..f0466cea81 100644 --- a/indra/newview/skins/default/xui/it/strings.xml +++ b/indra/newview/skins/default/xui/it/strings.xml @@ -635,6 +635,15 @@ Prova ad accedere nuovamente tra un minuto. <string name="BUTTON_HELP"> Mostra Aiuto </string> + <string name="TooltipNotecardNotAllowedTypeDrop"> + Oggetti di questo tipo non possono essere allegati ai +biglietti in questa regione. + </string> + <string name="TooltipNotecardOwnerRestrictedDrop"> + Solamente gli oggetti con autorizzazioni +illimitate al “proprietario successivo†+possono essere allegati ai biglietti. + </string> <string name="Searching"> Ricerca in corso... </string> @@ -711,6 +720,18 @@ Prova ad accedere nuovamente tra un minuto. Errore nella richiesta di caricamento. Vai alla pagina http://secondlife.com/support per risolvere il problema. </string> + <string name="SettingValidationError"> + Impossibile convalidare le impostazioni importate [NAME] + </string> + <string name="SettingImportFileError"> + Impossibile aprire il file [FILE] + </string> + <string name="SettingParseFileError"> + Impossibile aprire il file [FILE] + </string> + <string name="SettingTranslateError"> + Impossibile tradurre la legacy vento e luce [NAME] + </string> <string name="texture"> texture </string> @@ -786,6 +807,9 @@ http://secondlife.com/support per risolvere il problema. <string name="symbolic folder link"> link alla cartella </string> + <string name="settings blob"> + impostazioni + </string> <string name="mesh"> reticolo </string> @@ -1116,6 +1140,9 @@ http://secondlife.com/support per risolvere il problema. <string name="ForceSitAvatar"> Forza l'avatar a sedersi </string> + <string name="ChangeEnvSettings"> + Cambia le impostazioni dell’ambiente + </string> <string name="AgentNameSubst"> (Tu) </string> @@ -1264,6 +1291,9 @@ http://secondlife.com/support per risolvere il problema. <string name="tattoo"> Tatuaggio </string> + <string name="universal"> + Universale + </string> <string name="physics"> Fisica </string> @@ -1306,6 +1336,9 @@ http://secondlife.com/support per risolvere il problema. <string name="tattoo_not_worn"> Tatuaggio non portato </string> + <string name="universal_not_worn"> + Universale non indossato + </string> <string name="physics_not_worn"> Fisica non indossata </string> @@ -1357,6 +1390,9 @@ http://secondlife.com/support per risolvere il problema. <string name="create_new_tattoo"> Crea un nuovo tatuaggio </string> + <string name="create_new_universal"> + Crea nuovo universale + </string> <string name="create_new_physics"> Crea nuova fisica </string> @@ -1600,11 +1636,14 @@ Se continui a ricevere questo messaggio, contatta l'assistenza Second Life <string name="MarketplaceUpdating"> in aggiornamento... </string> + <string name="UploadFeeInfo"> + Il costo si basa sul tuo livello di iscrizione. Più alto è il livello, più basso è il costo. [https://secondlife.com/my/account/membership.php? Scopri di più] + </string> <string name="Open landmarks"> - Apri luoghi di riferimento + Luoghi aperti </string> <string name="Unconstrained"> - Libero + Senza limitazioni </string> <string name="no_transfer" value="(nessun trasferimento)"/> <string name="no_modify" value="(nessuna modifica)"/> @@ -2492,6 +2531,27 @@ Se continui a ricevere questo messaggio, contatta l'assistenza Second Life <string name="RegionSettings"> Impostazioni regione </string> + <string name="NoEnvironmentSettings"> + Questa regione non supporta le impostazioni per l’ambiente. + </string> + <string name="EnvironmentSun"> + Sole + </string> + <string name="EnvironmentMoon"> + Luna + </string> + <string name="EnvironmentBloom"> + Fioritura + </string> + <string name="EnvironmentCloudNoise"> + Rumore nuvole + </string> + <string name="EnvironmentNormalMap"> + Mappa normale + </string> + <string name="EnvironmentTransparent"> + Transparent + </string> <string name="ClassifiedClicksTxt"> Clicca: [TELEPORT] teleport, [MAP] mappa, [PROFILE] profilo </string> @@ -4645,6 +4705,9 @@ Segnala abuso <string name="New Tattoo"> Nuovo tatuaggio </string> + <string name="New Universal"> + Nuovo Universale + </string> <string name="New Physics"> Nuova fisica </string> @@ -4771,6 +4834,15 @@ Segnala abuso <string name="Female - Wow"> Femmina - Accipicchia </string> + <string name="New Daycycle"> + Nuovo ciclo giornata + </string> + <string name="New Water"> + Nuova acqua + </string> + <string name="New Sky"> + Nuovo cielo + </string> <string name="/bow"> /inchino </string> @@ -4943,6 +5015,15 @@ Consulta la pagina http://status.secondlifegrid.net per determinare se il proble <string name="Chat" value="Chat :"> Chat </string> + <string name="BaseMembership"> + Base + </string> + <string name="PremiumMembership"> + Premium + </string> + <string name="Premium PlusMembership"> + Premium Plus + </string> <string name="DeleteItems"> Cancellare gli elementi selezionati? </string> @@ -5299,6 +5380,12 @@ Prova a racchiudere il percorso dell'editor in doppie virgolette. <string name="BeaconMedia"> Visualizzazione marcatori multimedia (bianco) </string> + <string name="BeaconSun"> + Marcatore visualizza direzione sole (arancione) + </string> + <string name="BeaconMoon"> + Marcatore visualizza direzione luna (viola) + </string> <string name="ParticleHiding"> Particelle nascoste </string> @@ -5326,6 +5413,12 @@ Prova a racchiudere il percorso dell'editor in doppie virgolette. <string name="Command_Destinations_Label"> Destinazioni </string> + <string name="Command_Environments_Label"> + I miei ambienti + </string> + <string name="Command_Facebook_Label"> + Facebook + </string> <string name="Command_Flickr_Label"> Flickr </string> @@ -5419,6 +5512,12 @@ Prova a racchiudere il percorso dell'editor in doppie virgolette. <string name="Command_Destinations_Tooltip"> Destinazioni interessanti </string> + <string name="Command_Environments_Tooltip"> + I miei ambienti + </string> + <string name="Command_Facebook_Tooltip"> + Pubblica su Facebook + </string> <string name="Command_Flickr_Tooltip"> Carica su Flickr </string> @@ -5614,6 +5713,12 @@ Prova a racchiudere il percorso dell'editor in doppie virgolette. <string name="ExperiencePermission12"> accettazione automatica delle autorizzazioni per le esperienze </string> + <string name="ExperiencePermission16"> + obbliga l'avatar a sedersi + </string> + <string name="ExperiencePermission17"> + cambia le impostazioni dell’ambiente + </string> <string name="ExperiencePermissionShortUnknown"> ha eseguito un'operazione sconosciuta: [Permission] </string> @@ -5638,6 +5743,12 @@ Prova a racchiudere il percorso dell'editor in doppie virgolette. <string name="ExperiencePermissionShort12"> Autorizzazione </string> + <string name="ExperiencePermissionShort16"> + Siediti + </string> + <string name="ExperiencePermissionShort17"> + Ambiente + </string> <string name="logging_calls_disabled_log_empty"> Le conversazioni non vengono registrate. Per iniziare a registrare, seleziona "Salva: Solo registro" oppure "Salva: Registri e trascrizioni" in Preferenze > Chat. </string> diff --git a/indra/newview/skins/default/xui/ja/floater_about_land.xml b/indra/newview/skins/default/xui/ja/floater_about_land.xml index d26a1b34d5..4703dfaa34 100644 --- a/indra/newview/skins/default/xui/ja/floater_about_land.xml +++ b/indra/newview/skins/default/xui/ja/floater_about_land.xml @@ -478,5 +478,6 @@ </panel> </panel> <panel label="体験" name="land_experiences_panel"/> + <panel label="環境" name="land_environment_panel"/> </tab_container> </floater> diff --git a/indra/newview/skins/default/xui/ja/floater_adjust_environment.xml b/indra/newview/skins/default/xui/ja/floater_adjust_environment.xml new file mode 100644 index 0000000000..6736dad336 --- /dev/null +++ b/indra/newview/skins/default/xui/ja/floater_adjust_environment.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_adjust_snapshot" title="個人的ãªç…§æ˜Ž"> + <layout_stack name="outer_stack"> + <layout_panel name="env_controls"> + <layout_stack name="settings_stack"> + <layout_panel> + <button label="リセット" name="btn_reset" tool_tip="é–‰ã˜ã¦å…±æœ‰ã•れãŸç’°å¢ƒã«ãƒªã‚»ãƒƒãƒˆã™ã‚‹"/> + <text name="cloud_map_label"> + 雲ã®ç”»åƒï¼š + </text> + </layout_panel> + <layout_panel> + <text name="label"> + 太陽: + </text> + <check_box label="ビーコンを表示" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <check_box label="ビーコンを表示" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/ja/floater_beacons.xml b/indra/newview/skins/default/xui/ja/floater_beacons.xml index a55698e3d0..cb3dae0644 100644 --- a/indra/newview/skins/default/xui/ja/floater_beacons.xml +++ b/indra/newview/skins/default/xui/ja/floater_beacons.xml @@ -18,5 +18,7 @@ <check_box label="音æº" name="sounds"/> <check_box label="パーティクルæº" name="particles"/> <check_box label="メディアæº" name="moapbeacon"/> + <check_box label="太陽" name="sun"/> + <check_box label="月" name="moon"/> </panel> </floater> diff --git a/indra/newview/skins/default/xui/ja/floater_bulk_perms.xml b/indra/newview/skins/default/xui/ja/floater_bulk_perms.xml index b34fd192a9..fc9b35a34d 100644 --- a/indra/newview/skins/default/xui/ja/floater_bulk_perms.xml +++ b/indra/newview/skins/default/xui/ja/floater_bulk_perms.xml @@ -30,6 +30,7 @@ <icon name="icon_sound" tool_tip="サウンド"/> <check_box label="テクスãƒãƒ£" name="check_texture"/> <icon name="icon_texture" tool_tip="テクスãƒãƒ£"/> + <icon name="icon_setting" tool_tip="自然環境ã®è¨å®š"/> <button label="ã™ã¹ã¦ã« √" label_selected="å…¨ã¦" name="check_all"/> <button label="クリア" label_selected="ãªã—" name="check_none"/> <text name="newperms"> diff --git a/indra/newview/skins/default/xui/ja/floater_buy_currency.xml b/indra/newview/skins/default/xui/ja/floater_buy_currency.xml index a472f163e3..ac2db917cc 100644 --- a/indra/newview/skins/default/xui/ja/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/ja/floater_buy_currency.xml @@ -59,8 +59,7 @@ </text> <button label="購入ã™ã‚‹" name="buy_btn"/> <button label="å–り消ã—" name="cancel_btn"/> - <text name="info_cannot_buy"> + <floater.string name="info_cannot_buy"> 購入ã§ãã¾ã›ã‚“ - </text> - <button label="Web サイトã«ç§»å‹•" name="error_web" width="140"/> + </floater.string> </floater> diff --git a/indra/newview/skins/default/xui/ja/floater_delete_env_preset.xml b/indra/newview/skins/default/xui/ja/floater_delete_env_preset.xml deleted file mode 100644 index 6467a69956..0000000000 --- a/indra/newview/skins/default/xui/ja/floater_delete_env_preset.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<floater name="Delete Env Preset" title="環境ã®äº‹å‰è¨å®šã‚’削除"> - <string name="title_water"> - æ°´ã®äº‹å‰è¨å®šã‚’削除 - </string> - <string name="title_sky"> - 空ã®äº‹å‰è¨å®šã‚’削除 - </string> - <string name="title_day_cycle"> - デイサイクルを削除 - </string> - <string name="label_water"> - 事å‰è¨å®šï¼š - </string> - <string name="label_sky"> - 事å‰è¨å®šï¼š - </string> - <string name="label_day_cycle"> - デイサイクル: - </string> - <string name="msg_confirm_deletion"> - é¸æŠžã•れãŸäº‹å‰è¨å®šã‚’削除ã—ã¾ã™ã‹ï¼Ÿ - </string> - <string name="msg_sky_is_referenced"> - デイサイクルã®å‚ç…§å…ˆã¨ã—ã¦ä½¿ã‚れã¦ã„る事å‰è¨å®šã¯å‰Šé™¤ã§ãã¾ã›ã‚“。 - </string> - <string name="combo_label"> - - 事å‰è¨å®šã‚’é¸æŠž - - </string> - <text name="label"> - 事å‰è¨å®šï¼š - </text> - <button label="削除" name="delete"/> - <button label="ã‚ャンセル" name="cancel"/> -</floater> diff --git a/indra/newview/skins/default/xui/ja/floater_edit_ext_day_cycle.xml b/indra/newview/skins/default/xui/ja/floater_edit_ext_day_cycle.xml new file mode 100644 index 0000000000..79c97472df --- /dev/null +++ b/indra/newview/skins/default/xui/ja/floater_edit_ext_day_cycle.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_edit_extdaycycle" title="デイサイクルを編集"> + <string name="title_new"> + æ–°ã—ã„ãƒ‡ã‚¤ã‚µã‚¤ã‚¯ãƒ«ã‚’ä½œæˆ + </string> + <string name="title_edit"> + デイサイクルを編集 + </string> + <string name="hint_new"> + æ–°ã—ã„デイサイクルã«åå‰ã‚’ã¤ã‘ã€å¸Œæœ›ã®è¨å®šã«èª¿ç¯€ã—ã¦ã€ã€Œä¿å˜ã€ã‚’クリックã—ã¾ã™ã€‚ + </string> + <string name="hint_edit"> + 自分ã§ä½œæˆã—ãŸãƒ‡ã‚¤ã‚µã‚¤ã‚¯ãƒ«ã‚’編集ã™ã‚‹ã«ã¯ã€å¸Œæœ›ã®è¨å®šã«èª¿ç¯€ã—ã¦ã€ã€Œä¿å˜ã€ã‚’クリックã—ã¾ã™ã€‚ + </string> + <string name="time_label"> + ([HH]:[MM]) + </string> + <string name="sky_track_label"> + 空 [ALT] + </string> + <string name="sky_label"> + 空 + </string> + <string name="water_label"> + æ°´ + </string> + <string name="commit_parcel"> + 区画ã«é©ç”¨ + </string> + <string name="commit_region"> + リージョンã«é©ç”¨ + </string> + <layout_stack name="outer_stack"> + <layout_panel name="name_and_import"> + <text name="label"> + デイサイクルå: + </text> + <button label="インãƒãƒ¼ãƒˆ" name="btn_import" tool_tip="ディスクã‹ã‚‰éŽåŽ»ã®è¨å®šã‚’インãƒãƒ¼ãƒˆã™ã‚‹ã€‚"/> + </layout_panel> + <layout_panel name="content"> + <layout_stack name="content_stack"> + <layout_panel name="timeline_track_selection"> + <panel name="timeline_layers"> + <button label="空 4" name="sky4_track"/> + <button label="空 3" name="sky3_track"/> + <button label="空 2" name="sky2_track"/> + <button label="地表レベル" name="sky1_track"/> + <button label="æ°´" name="water_track"/> + </panel> + <panel name="timeline"> + <text name="p0" value="0%[DSC]"/> + <text name="p1" value="25%[DSC]"/> + <text name="p2" value="50%[DSC]"/> + <text name="p3" value="75%[DSC]"/> + <text name="p4" value="100%[DSC]"/> + <multi_slider initial_value="0" name="WLTimeSlider"/> + <multi_slider initial_value="0" name="WLDayCycleFrames"/> + <text name="current_time" value="[PRCNT]%[DSC]"/> + <layout_stack> + <layout_panel> + <button label="トラックを以下ã‹ã‚‰ã‚¯ãƒãƒ¼ãƒ³" name="copy_track"/> + <button label="トラックを以下ã‹ã‚‰ãƒãƒ¼ãƒ‰" name="load_track"/> + <button label="トラックをクリア" name="clear_track"/> + </layout_panel> + <layout_panel> + <layout_stack name="progress_control"> + <layout_panel name="skip_back"> + <button name="skip_back_btn" tool_tip="後ã‚ã«ç§»å‹•"/> + </layout_panel> + <layout_panel name="skip_forward"> + <button name="skip_forward_btn" tool_tip="å‰ã«ç§»å‹•"/> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel> + <button label="[FRAME] ã‚’è¿½åŠ " name="add_frame"/> + <button label="[FRAME] ã‚’ãƒãƒ¼ãƒ‰" name="btn_load_frame"/> + <button label="[FRAME] を削除" name="delete_frame"/> + </layout_panel> + </layout_stack> + </panel> + </layout_panel> + <layout_panel name="frame_edit_controls"> + <text name="icn_lock_edit"> + 上部ã®ã‚¿ã‚¤ãƒ ラインã‹ã‚‰ã‚ãƒ¼ãƒ•ãƒ¬ãƒ¼ãƒ ã‚’é¸æŠžã—ã€è¨å®šã‚’編集ã—ã¾ã™ã€‚ + </text> + </layout_panel> + <layout_panel name="frame_settings_water"> + <tab_container name="water_tabs"> + <panel label="æ°´" name="water_panel"/> + </tab_container> + </layout_panel> + <layout_panel name="frame_settings_sky"> + <tab_container name="sky_tabs"> + <panel label="大気&光" name="atmosphere_panel"/> + <panel label="雲" name="clouds_panel"/> + <panel label="太陽&月" name="moon_panel"/> + </tab_container> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel name="buttons"> + <button label="ä¿å˜" name="save_btn"/> + <button label="ã‚ャンセル" name="cancel_btn"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/ja/floater_fixedenvironment.xml b/indra/newview/skins/default/xui/ja/floater_fixedenvironment.xml new file mode 100644 index 0000000000..a00b87b990 --- /dev/null +++ b/indra/newview/skins/default/xui/ja/floater_fixedenvironment.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="Fixed Environment" title="固定ã•れãŸç’°å¢ƒ"> + <string name="edit_sky"> + 空を編集: + </string> + <string name="edit_water"> + 水を編集: + </string> + <layout_stack name="floater_stack"> + <layout_panel name="info_panel"> + <button label="ãƒãƒ¼ãƒ‰" name="btn_load" tool_tip="æŒã¡ç‰©ã‹ã‚‰è¨å®šã‚’ãƒãƒ¼ãƒ‰ã™ã‚‹"/> + <button label="インãƒãƒ¼ãƒˆ" name="btn_import" tool_tip="ディスクã‹ã‚‰éŽåŽ»ã®è¨å®šã‚’インãƒãƒ¼ãƒˆã™ã‚‹ã€‚"/> + </layout_panel> + <layout_panel name="button_panel"> + <layout_stack name="button_bar_ls"> + <layout_panel name="save_btn_lp"> + <button label="ä¿å˜" name="btn_commit"/> + </layout_panel> + <layout_panel name="revert_btn_lp"> + <button label="ã‚ャンセル" name="btn_cancel" tool_tip="最後ã«ä¿å˜ã•れãŸçŠ¶æ…‹ã«æˆ»ã™"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/ja/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/ja/floater_inventory_view_finder.xml index da63b54eab..425cb7ad81 100644 --- a/indra/newview/skins/default/xui/ja/floater_inventory_view_finder.xml +++ b/indra/newview/skins/default/xui/ja/floater_inventory_view_finder.xml @@ -12,6 +12,7 @@ <check_box label="サウンド" name="check_sound"/> <check_box label="テクスãƒãƒ£" name="check_texture"/> <check_box label="スナップショット" name="check_snapshot"/> + <check_box label="è¨å®š" name="check_settings"/> <button label="ã™ã¹ã¦" label_selected="ã™ã¹ã¦" name="All"/> <button label="ãªã—" label_selected="ãªã—" name="None"/> <check_box label="常ã«ãƒ•ォルダを表示" name="check_show_empty"/> diff --git a/indra/newview/skins/default/xui/ja/floater_merchant_outbox.xml b/indra/newview/skins/default/xui/ja/floater_merchant_outbox.xml deleted file mode 100644 index 2edb3c624c..0000000000 --- a/indra/newview/skins/default/xui/ja/floater_merchant_outbox.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="floater_merchant_outbox" title="マーãƒãƒ£ãƒ³ãƒˆã‚¢ã‚¦ãƒˆãƒœãƒƒã‚¯ã‚¹"> - <string name="OutboxFolderCount1"> - 1 個ã®ãƒ•ォルダ - </string> - <string name="OutboxFolderCountN"> - [NUM] 個ã®ãƒ•ォルダ - </string> - <string name="OutboxImporting"> - フォルダをé€ä¿¡ä¸... - </string> - <string name="OutboxInitializing"> - åˆæœŸåŒ–ä¸... - </string> - <panel label="" name="panel_1"> - <panel name="panel_2"> - <panel name="outbox_inventory_placeholder_panel"> - <text name="outbox_inventory_placeholder_title"> - ãƒãƒ¼ãƒ‰ä¸... - </text> - </panel> - </panel> - <panel name="panel_3"> - <panel name="outbox_generic_drag_target"> - <text name="text_1"> - ã“ã“ã«ã‚¢ã‚¤ãƒ†ãƒ をドラッグã—ã¦ã€ãƒ•ォルダを作æˆã™ã‚‹ - </text> - </panel> - <button label="マーケットプレイスã«é€ä¿¡" name="outbox_import_btn" tool_tip="自分ã®ãƒžãƒ¼ã‚±ãƒƒãƒˆãƒ—レイス店é ã«ç§»å‹•"/> - </panel> - </panel> -</floater> diff --git a/indra/newview/skins/default/xui/ja/floater_my_environments.xml b/indra/newview/skins/default/xui/ja/floater_my_environments.xml new file mode 100644 index 0000000000..d697a9f321 --- /dev/null +++ b/indra/newview/skins/default/xui/ja/floater_my_environments.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater label="å ´æ‰€" name="my_environments" title="ç§ã®ç’°å¢ƒ"> + <layout_stack> + <layout_panel label="フィルター" name="filter_panel"> + <check_box label="日間" name="chk_days"/> + <check_box label="空" name="chk_skies"/> + <check_box label="æ°´" name="chk_water"/> + <filter_editor label="環境ã®çµžã‚Šè¾¼ã¿" name="flt_search"/> + </layout_panel> + <layout_panel label="環境" name="list_panel"> + <panel label="pnl_inv_wrap" name="pnl_inv_wrap"/> + </layout_panel> + <layout_panel> + <check_box initial_value="false" label="ã™ã¹ã¦ã®ãƒ•ォルダを表示" name="chk_showfolders"/> + </layout_panel> + <layout_panel name="pnl_control"> + <panel label="bottom_panel" name="pnl_bottom"> + <menu_button name="btn_gear" tool_tip="ãã®ä»–ã®ã‚ªãƒ—ションを表示"/> + <menu_button name="btn_newsettings" tool_tip="æ–°è¦è¨å®šã‚’作æˆ"/> + <button name="btn_del" tool_tip="é¸æŠžã—ãŸã‚¢ã‚¤ãƒ†ãƒ を削除"/> + </panel> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/ja/floater_perms_default.xml b/indra/newview/skins/default/xui/ja/floater_perms_default.xml index 0dfc75014e..33551a5706 100644 --- a/indra/newview/skins/default/xui/ja/floater_perms_default.xml +++ b/indra/newview/skins/default/xui/ja/floater_perms_default.xml @@ -37,6 +37,10 @@ <text name="label_12" tool_tip="è¡£æœã¾ãŸã¯ãƒœãƒ‡ã‚£ãƒ‘ーツを作æˆã™ã‚‹ã¨ãã«ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®æ¨©é™ã‚’è¨å®šã™ã‚‹"> ç€ç”¨ç‰© </text> + <text name="label_13" tool_tip="自然環境ã®è¨å®šã‚’作æˆã™ã‚‹ã¨ãã«ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®æ¨©é™ã‚’è¨å®šã™ã‚‹"> + è¨å®š + </text> + <check_box name="env_settings_c" value="true"/> </panel> <button label="OK" label_selected="OK" name="ok"/> <button label="å–り消ã—" label_selected="å–り消ã—" name="cancel"/> diff --git a/indra/newview/skins/default/xui/ja/floater_pick_track.xml b/indra/newview/skins/default/xui/ja/floater_pick_track.xml new file mode 100644 index 0000000000..e5773e1ec8 --- /dev/null +++ b/indra/newview/skins/default/xui/ja/floater_pick_track.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="track picker" title="é¸æŠžï¼šãƒˆãƒ©ãƒƒã‚¯"> + <layout_stack name="adjuster"> + <layout_panel name="pnl_desc"> + <text name="select_description"> + 空ã®ã‚½ãƒ¼ã‚¹ã‚’é¸æŠžï¼š + </text> + </layout_panel> + <layout_panel name="pnl_traks"> + <radio_group name="track_selection"> + <radio_item label="空 4 [ALT]" name="radio_sky4" value="4"/> + <radio_item label="空 3 [ALT]" name="radio_sky3" value="3"/> + <radio_item label="空 2 [ALT]" name="radio_sky2" value="2"/> + <radio_item label="地é¢" name="radio_sky1" value="1"/> + </radio_group> + </layout_panel> + <layout_panel name="pnl_ok_cancel"> + <button label="OK" label_selected="OK" name="btn_select"/> + <button label="ã‚ャンセル" label_selected="ã‚ャンセル" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/ja/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/ja/floater_preferences_graphics_advanced.xml index c28afa4c98..8ba537faa2 100644 --- a/indra/newview/skins/default/xui/ja/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/ja/floater_preferences_graphics_advanced.xml @@ -82,7 +82,6 @@ <check_box initial_value="true" label="逿˜Žãªæ°´" name="TransparentWater"/> <check_box initial_value="true" label="ãƒãƒ³ãƒ—マッピングã¨å…‰æ²¢" name="BumpShiny"/> <check_box initial_value="true" label="è¿‘ãã®å…‰" name="LocalLights"/> - <check_box initial_value="true" label="基本シェーダー" name="BasicShaders" tool_tip="ã“ã®ã‚ªãƒ—ションを無効ã«ã™ã‚‹ã¨ã€ã‚°ãƒ©ãƒ•ィックカードã®ãƒ‰ãƒ©ã‚¤ãƒã®ç¨®é¡žã«ã‚ˆã£ã¦ã¯ã€ã‚¯ãƒ©ãƒƒã‚·ãƒ¥ã™ã‚‹ã®ã‚’防ãŽã¾ã™ã€‚"/> <slider label="地形詳細:" name="TerrainDetail"/> <text name="TerrainDetailText"> 低 diff --git a/indra/newview/skins/default/xui/ja/floater_settings_picker.xml b/indra/newview/skins/default/xui/ja/floater_settings_picker.xml new file mode 100644 index 0000000000..b8b1699f03 --- /dev/null +++ b/indra/newview/skins/default/xui/ja/floater_settings_picker.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="settings picker" title="é¸æŠžï¼šè¨å®š"> + <floater.string name="pick title"> + é¸æŠžï¼š + </floater.string> + <floater.string name="pick_track"> + ãƒˆãƒ©ãƒƒã‚¯ã‚’é¸æŠž + </floater.string> + <floater.string name="pick_settings"> + è¨å®šã‚’é¸æŠž + </floater.string> + <floater.string name="track_water"> + æ°´ + </floater.string> + <floater.string name="track_ground"> + åœ°é¢ + </floater.string> + <floater.string name="track_sky"> + 空 [NUM] + </floater.string> + <layout_stack name="test_stack"> + <layout_panel name="inv_list"> + <filter_editor label="テクスãƒãƒ£ã‚’フィルター" name="flt_inventory_search"/> + </layout_panel> + <layout_panel name="temp"> + <button label="OK" label_selected="OK" name="btn_select"/> + <button label="ã‚ャンセル" label_selected="ã‚ャンセル" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/ja/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/ja/floater_texture_ctrl.xml index 37233d3e68..1221702e9b 100644 --- a/indra/newview/skins/default/xui/ja/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/ja/floater_texture_ctrl.xml @@ -9,18 +9,14 @@ <text name="Multiple"> 複数ã®ãƒ†ã‚¯ã‚¹ãƒãƒ£ </text> - <radio_group name="mode_selection"> - <radio_item label="インベントリ" name="inventory" value="0"/> - <radio_item label="ãƒãƒ¼ã‚«ãƒ«" name="local" value="1"/> - </radio_group> - <text name="unknown"> - サイズ: [DIMENSIONS] - </text> + <combo_box name="mode_selection"> + <combo_box.item label="インベントリ" name="inventory" value="0"/> + <combo_box.item label="ãƒãƒ¼ã‚«ãƒ«" name="local" value="1"/> + </combo_box> <button label="デフォルト" label_selected="デフォルト" name="Default"/> <button label="ブランク" label_selected="ブランク" name="Blank"/> <button label="ãªã—" label_selected="ãªã—" name="None"/> <button label="" label_selected="" name="Pipette"/> - <check_box initial_value="true" label="今ã™ãé©ç”¨" name="apply_immediate_check"/> <text name="preview_disabled" value="プレビュー無効"/> <filter_editor label="テクスãƒãƒ£ã‚’フィルター" name="inventory search editor"/> <check_box initial_value="false" label="フォルダを表示" name="show_folders_check"/> @@ -31,6 +27,22 @@ <column label="åå‰" name="unit_name"/> <column label="ID" name="unit_id_HIDDEN"/> </scroll_list> + <combo_box name="l_bake_use_texture_combo_box" tool_tip="構築(ベーク)ã™ã‚‹ãƒ†ã‚¯ã‚¹ãƒãƒ£ã‚’é¸æŠž"> + <combo_box.item label="ãªã—" name="None"/> + <combo_box.item label="BAKED_HEAD" name="BAKED_HEAD"/> + <combo_box.item label="BAKED_UPPER" name="BAKED_UPPER"/> + <combo_box.item label="BAKED_LOWER" name="BAKED_LOWER"/> + <combo_box.item label="BAKED_EYES" name="BAKED_EYES"/> + <combo_box.item label="BAKED_SKIRT" name="BAKED_SKIRT"/> + <combo_box.item label="BAKED_HAIR" name="BAKED_HAIR"/> + <combo_box.item label="BAKED_LEFTARM" name="BAKED_LEFTARM"/> + <combo_box.item label="BAKED_LEFTLEG" name="BAKED_LEFTLEG"/> + <combo_box.item label="BAKED_AUX1" name="BAKED_AUX1"/> + <combo_box.item label="BAKED_AUX2" name="BAKED_AUX2"/> + <combo_box.item label="BAKED_AUX3" name="BAKED_AUX3"/> + </combo_box> + <check_box initial_value="false" label="基本ã¨ãªã‚‹ãƒ¡ãƒƒã‚·ãƒ¥ãƒªãƒ¼ã‚¸ãƒ§ãƒ³ã‚’éš ã™" name="hide_base_mesh_region"/> <button label="OK" label_selected="OK" name="Select"/> <button label="å–り消ã—" label_selected="å–り消ã—" name="Cancel"/> + <check_box initial_value="true" label="今ã™ãé©ç”¨" name="apply_immediate_check"/> </floater> diff --git a/indra/newview/skins/default/xui/ja/menu_cof_attachment.xml b/indra/newview/skins/default/xui/ja/menu_cof_attachment.xml index e786d02e40..aa07b9476e 100644 --- a/indra/newview/skins/default/xui/ja/menu_cof_attachment.xml +++ b/indra/newview/skins/default/xui/ja/menu_cof_attachment.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="COF Attachment"> + <menu_item_call label="触る" name="touch_attach" /> + <menu_item_call label="編集" name="edit_item" /> <menu_item_call label="å–り外ã™" name="detach"/> </context_menu> diff --git a/indra/newview/skins/default/xui/ja/menu_inventory.xml b/indra/newview/skins/default/xui/ja/menu_inventory.xml index 0b06b77901..7f68c18e0b 100644 --- a/indra/newview/skins/default/xui/ja/menu_inventory.xml +++ b/indra/newview/skins/default/xui/ja/menu_inventory.xml @@ -10,7 +10,6 @@ <menu_item_call label="有効ã«ã™ã‚‹" name="Marketplace Activate"/> <menu_item_call label="無効ã«ã™ã‚‹" name="Marketplace Deactivate"/> <menu_item_call label="共有" name="Share"/> - <menu_item_call label="購入" name="Task Buy"/> <menu_item_call label="é–‹ã" name="Task Open"/> <menu_item_call label="å†ç”Ÿ" name="Task Play"/> <menu_item_call label="プãƒãƒ‘ティ" name="Task Properties"/> @@ -34,6 +33,7 @@ <menu_item_call label="æ–°ã—ã„パンツ" name="New Underpants"/> <menu_item_call label="æ–°ã—ã„アルファマスク" name="New Alpha Mask"/> <menu_item_call label="æ–°ã—ã„タトゥ" name="New Tattoo"/> + <menu_item_call label="æ–°ã—ã„ユニãƒãƒ¼ã‚µãƒ«" name="New Universal"/> <menu_item_call label="æ–°è¦ã®ç‰©ç†ä½œç”¨" name="New Physics"/> </menu> <menu label="æ–°ã—ã„身体部ä½" name="New Body Parts"> @@ -42,6 +42,11 @@ <menu_item_call label="æ–°ã—ã„髪" name="New Hair"/> <menu_item_call label="æ–°ã—ã„眼" name="New Eyes"/> </menu> + <menu label="æ–°ã—ã„è¨å®š" name="New Settings"> + <menu_item_call label="æ–°ã—ã„空" name="New Sky"/> + <menu_item_call label="æ–°ã—ã„æ°´" name="New Water"/> + <menu_item_call label="æ–°ã—ã„デイサイクル" name="New Day Cycle"/> + </menu> <menu label="次ã®ãƒ‡ãƒ•ォルトã¨ã—ã¦ä½¿ç”¨" name="upload_def"> <menu_item_call label="ç”»åƒã®ã‚¢ãƒƒãƒ—ãƒãƒ¼ãƒ‰" name="Image uploads"/> <menu_item_call label="サウンドã®ã‚¢ãƒƒãƒ—ãƒãƒ¼ãƒ‰" name="Sound uploads"/> @@ -100,9 +105,12 @@ <menu_item_call label="装ç€" name="Wearable And Object Wear"/> <menu label="装ç€å…ˆ" name="Attach To"/> <menu label="HUD 装ç€å…ˆ" name="Attach To HUD"/> + <menu_item_call label="触る" name="Attachment Touch" /> <menu_item_call label="編集" name="Wearable Edit"/> <menu_item_call label="è¿½åŠ " name="Wearable Add"/> <menu_item_call label="å–り外ã™" name="Take Off"/> + <menu_item_call label="自分ã«ã®ã¿é©ç”¨" name="Settings Apply Local"/> + <menu_item_call label="区画ã«é©ç”¨" name="Settings Apply Parcel"/> <menu_item_call label="マーケットプレイスã®ãƒªã‚¹ãƒˆã«ã‚³ãƒ”ー" name="Marketplace Copy"/> <menu_item_call label="マーケットプレイスã®ãƒªã‚¹ãƒˆã«ç§»å‹•" name="Marketplace Move"/> <menu_item_call label="ï¼ï¼ã‚ªãƒ—ションãªã—ï¼ï¼" name="--no options--"/> diff --git a/indra/newview/skins/default/xui/ja/menu_inventory_add.xml b/indra/newview/skins/default/xui/ja/menu_inventory_add.xml index ae5ddbb78f..eecf166a70 100644 --- a/indra/newview/skins/default/xui/ja/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/ja/menu_inventory_add.xml @@ -5,9 +5,7 @@ <menu_item_call label="サウンド (L$[COST] )..." name="Upload Sound"/> <menu_item_call label="アニメーション (L$ [COST] )..." name="Upload Animation"/> <menu_item_call label="モデル" name="Upload Model"/> - <menu_item_call label="モデルウィザード" name="Upload Model Wizard"/> <menu_item_call label="一括 (ファイルã«ã¤ã L$[COST] )..." name="Bulk Upload"/> - <menu_item_call label="デフォルトã®ã‚¢ãƒƒãƒ—ãƒãƒ¼ãƒ‰æ¨©é™ã‚’è¨å®š" name="perm prefs"/> </menu> <menu_item_call label="æ–°è¦ãƒ•ォルダ" name="New Folder"/> <menu_item_call label="æ–°è¦ã‚¹ã‚¯ãƒªãƒ—ト" name="New Script"/> @@ -25,6 +23,7 @@ <menu_item_call label="æ–°ã—ã„下ç€ï¼ˆä¸‹ï¼‰" name="New Underpants"/> <menu_item_call label="æ–°ã—ã„アルファ" name="New Alpha"/> <menu_item_call label="æ–°ã—ã„タトゥー" name="New Tattoo"/> + <menu_item_call label="æ–°ã—ã„ユニãƒãƒ¼ã‚µãƒ«" name="New Universal"/> <menu_item_call label="æ–°è¦ã®ç‰©ç†ä½œç”¨" name="New Physics"/> </menu> <menu label="æ–°ã—ã„身体部ä½" name="New Body Parts"> @@ -33,4 +32,9 @@ <menu_item_call label="æ–°ã—ã„髪" name="New Hair"/> <menu_item_call label="æ–°ã—ã„ç›®" name="New Eyes"/> </menu> + <menu label="æ–°ã—ã„è¨å®š" name="New Settings"> + <menu_item_call label="æ–°ã—ã„空" name="New Sky"/> + <menu_item_call label="æ–°ã—ã„æ°´" name="New Water"/> + <menu_item_call label="æ–°ã—ã„デイサイクル" name="New Day Cycle"/> + </menu> </menu> diff --git a/indra/newview/skins/default/xui/ja/menu_outfit_gear.xml b/indra/newview/skins/default/xui/ja/menu_outfit_gear.xml index 5e02fd3b8f..4946d58fd8 100644 --- a/indra/newview/skins/default/xui/ja/menu_outfit_gear.xml +++ b/indra/newview/skins/default/xui/ja/menu_outfit_gear.xml @@ -20,6 +20,7 @@ <menu_item_call label="アルファ" name="New Alpha"/> <menu_item_call label="æ–°è¦ã®ç‰©ç†ä½œç”¨" name="New Physics"/> <menu_item_call label="æ–°ã—ã„タトゥ" name="New Tattoo"/> + <menu_item_call label="æ–°ã—ã„ユニãƒãƒ¼ã‚µãƒ«" name="New Universal"/> </menu> <menu label="æ–°ã—ã„身体部ä½" name="New Body Parts"> <menu_item_call label="æ–°ã—ã„シェイプ" name="New Shape"/> diff --git a/indra/newview/skins/default/xui/ja/menu_save_settings.xml b/indra/newview/skins/default/xui/ja/menu_save_settings.xml new file mode 100644 index 0000000000..44fb1fb30b --- /dev/null +++ b/indra/newview/skins/default/xui/ja/menu_save_settings.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="save_settings_menu"> + <menu_item_check label="ä¿å˜" name="save_settings"/> + <menu_item_check label="別åã§ä¿å˜" name="save_as_new_settings"/> + <menu_item_check label="ç´„æŸã™ã‚‹" name="commit_changes"/> + <menu_item_check label="自分ã«ã®ã¿é©ç”¨" name="apply_local"/> + <menu_item_check label="区画ã«é©ç”¨" name="apply_parcel"/> + <menu_item_check label="リージョンã«é©ç”¨" name="apply_region"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/ja/menu_settings_add.xml b/indra/newview/skins/default/xui/ja/menu_settings_add.xml new file mode 100644 index 0000000000..814ad9c1a6 --- /dev/null +++ b/indra/newview/skins/default/xui/ja/menu_settings_add.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_add"> + <menu_item_call label="æ–°ã—ã„空" name="New Sky"/> + <menu_item_call label="æ–°ã—ã„æ°´" name="New Water"/> + <menu_item_call label="æ–°ã—ã„デイサイクル" name="New Day Cycle"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/ja/menu_settings_gear.xml b/indra/newview/skins/default/xui/ja/menu_settings_gear.xml new file mode 100644 index 0000000000..064eae95bf --- /dev/null +++ b/indra/newview/skins/default/xui/ja/menu_settings_gear.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_gear"> + <menu_item_call label="編集" name="edit_settings"/> + <menu_item_call label="自分ã«ã®ã¿é©ç”¨" name="Settings Apply Local"/> + <menu_item_call label="区画ã«é©ç”¨" name="Settings Apply Parcel"/> + <menu_item_call label="リージョンã«é©ç”¨" name="Settings Apply Region"/> + <menu_item_call label="コピー" name="copy_settings"/> + <menu_item_call label="貼り付ã‘" name="paste_settings"/> + <menu_item_call label="UUID をコピー" name="copy_uuid"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/ja/menu_viewer.xml b/indra/newview/skins/default/xui/ja/menu_viewer.xml index 7810094823..ba8d8e4955 100644 --- a/indra/newview/skins/default/xui/ja/menu_viewer.xml +++ b/indra/newview/skins/default/xui/ja/menu_viewer.xml @@ -79,30 +79,15 @@ <menu_item_check label="区画プãƒãƒ‘ティ" name="Parcel Properties"/> <menu_item_check label="アドãƒãƒ³ã‚¹ãƒ¡ãƒ‹ãƒ¥ãƒ¼" name="Show Advanced Menu"/> </menu> - <menu label="æ—¥" name="Sun"> + <menu label="環境" name="Environment"> <menu_item_check label="æ—¥ã®å‡º" name="Sunrise"/> <menu_item_check label="æ£åˆ" name="Noon"/> <menu_item_check label="日没" name="Sunset"/> <menu_item_check label="深夜" name="Midnight"/> - <menu_item_check label="リージョンã®è¨å®šã‚’使用" name="Use Region Settings"/> - </menu> - <menu label="自然環境エディター" name="Environment Editor"> - <menu_item_call label="自然環境ã®è¨å®š..." name="Environment Settings"/> - <menu label="æ°´ã®äº‹å‰è¨å®š" name="Water Presets"> - <menu_item_call label="æ–°ã—ã„事å‰è¨å®š..." name="new_water_preset"/> - <menu_item_call label="事å‰è¨å®šã‚’編集..." name="edit_water_preset"/> - <menu_item_call label="事å‰è¨å®šã‚’削除..." name="delete_water_preset"/> - </menu> - <menu label="空ã®äº‹å‰è¨å®š" name="Sky Presets"> - <menu_item_call label="æ–°ã—ã„事å‰è¨å®š..." name="new_sky_preset"/> - <menu_item_call label="事å‰è¨å®šã‚’編集..." name="edit_sky_preset"/> - <menu_item_call label="事å‰è¨å®šã‚’削除..." name="delete_sky_preset"/> - </menu> - <menu label="デイã®äº‹å‰è¨å®š" name="Day Presets"> - <menu_item_call label="æ–°ã—ã„事å‰è¨å®š..." name="new_day_preset"/> - <menu_item_call label="事å‰è¨å®šã‚’編集..." name="edit_day_preset"/> - <menu_item_call label="事å‰è¨å®šã‚’削除..." name="delete_day_preset"/> - </menu> + <menu_item_check label="共有ã•れãŸç’°å¢ƒã‚’使用" name="Use Shared Environment"/> + <menu_item_call label="ç§ã®ç’°å¢ƒâ€¦" name="my_environs"/> + <menu_item_call label="個人的ãªç…§æ˜Žâ€¦" name="adjustment_tool"/> + <menu_item_check label="é›²ã‚’ä¸€æ™‚åœæ¢" name="pause_clouds"/> </menu> </menu> <menu label="制作" name="BuildTools"> @@ -346,6 +331,9 @@ <menu_item_check label="自動アルファマスク(é…å»¶ãªã—)" name="Automatic Alpha Masks (non-deferred)"/> <menu_item_check label="アニメーションテクスãƒãƒ£" name="Animation Textures"/> <menu_item_check label="テクスãƒãƒ£ã‚’無効ã«ã™ã‚‹" name="Disable Textures"/> + <menu_item_check label="アンビエントを無効ã«ã™ã‚‹" name="Disable Ambient"/> + <menu_item_check label="æ—¥ã®å‡ºã‚’無効ã«ã™ã‚‹" name="Disable Sunlight"/> + <menu_item_check label="è¿‘ãã®å…‰ã‚’無効ã«ã™ã‚‹" name="Disable Local Lights"/> <menu_item_check label="フル解åƒåº¦ãƒ†ã‚¯ã‚¹ãƒãƒ£" name="Rull Res Textures"/> <menu_item_check label="装ç€ã•れãŸå…‰æºã‚’æç”»ã™ã‚‹" name="Render Attached Lights"/> <menu_item_check label="å–り付ã‘られãŸãƒ‘ーティクルをæç”»ã™ã‚‹" name="Render Attached Particles"/> @@ -483,6 +471,7 @@ <menu_item_call label="スカート" name="Skirt"/> <menu_item_call label="アルファ" name="Alpha"/> <menu_item_call label="タトゥ" name="Tattoo"/> + <menu_item_call label="ユニãƒãƒ¼ã‚µãƒ«" name="Universal"/> <menu_item_call label="物ç†ä½œç”¨" name="Physics"/> <menu_item_call label="ã™ã¹ã¦ã®è¡£é¡ž" name="All Clothes"/> </menu> diff --git a/indra/newview/skins/default/xui/ja/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/ja/menu_wearable_list_item.xml index c402fa0b6d..02029230ba 100644 --- a/indra/newview/skins/default/xui/ja/menu_wearable_list_item.xml +++ b/indra/newview/skins/default/xui/ja/menu_wearable_list_item.xml @@ -3,6 +3,7 @@ <menu_item_call label="交æ›" name="wear_replace"/> <menu_item_call label="装ç€" name="wear_wear"/> <menu_item_call label="è¿½åŠ " name="wear_add"/> + <menu_item_call label="触る" name="touch" /> <menu_item_call label="å–り外ã™" name="take_off_or_detach"/> <menu_item_call label="å–り外ã™" name="detach"/> <context_menu label="装ç€ï¼š" name="wearable_attach_to"/> diff --git a/indra/newview/skins/default/xui/ja/menu_wearing_gear.xml b/indra/newview/skins/default/xui/ja/menu_wearing_gear.xml index 5334042dc9..48aac2ed05 100644 --- a/indra/newview/skins/default/xui/ja/menu_wearing_gear.xml +++ b/indra/newview/skins/default/xui/ja/menu_wearing_gear.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <toggleable_menu name="Gear Wearing"> - <menu_item_call label="アウトフットã®ç·¨é›†" name="edit"/> + <menu_item_call label="触る" name="touch"/> + <menu_item_call label="編集" name="edit_item"/> + <menu_item_call label="アウトフットã®ç·¨é›†" name="edit_outfit"/> <menu_item_call label="å–り外ã™" name="takeoff"/> <menu_item_call label="アウトフィットã®ãƒªã‚¹ãƒˆã‚’クリップボードã«ã‚³ãƒ”ー" name="copy"/> </toggleable_menu> diff --git a/indra/newview/skins/default/xui/ja/menu_wearing_tab.xml b/indra/newview/skins/default/xui/ja/menu_wearing_tab.xml index bf8e72e457..8c331bc008 100644 --- a/indra/newview/skins/default/xui/ja/menu_wearing_tab.xml +++ b/indra/newview/skins/default/xui/ja/menu_wearing_tab.xml @@ -1,8 +1,9 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="Wearing"> + <menu_item_call label="触る" name="touch_attach"/> <menu_item_call label="å–り外ã™" name="take_off"/> <menu_item_call label="å–り外ã™" name="detach"/> - <menu_item_call label="アウトフットã®ç·¨é›†" name="edit"/> + <menu_item_call label="アウトフットã®ç·¨é›†" name="edit_outfit"/> <menu_item_call label="編集" name="edit_item"/> <menu_item_call label="オリジナルを表示" name="show_original"/> </context_menu> diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml index 16aeb4dcd7..a66552d3fe 100644 --- a/indra/newview/skins/default/xui/ja/notifications.xml +++ b/indra/newview/skins/default/xui/ja/notifications.xml @@ -266,6 +266,10 @@ é¸æŠžã—ãŸä½äººã‹ã‚‰å¤‰æ›´æ¨©é™ã‚’å–り下ã’ã¾ã™ã‹ï¼Ÿ <usetemplate name="okcancelbuttons" notext="ã„ã„ãˆ" yestext="ã¯ã„"/> </notification> + <notification name="GroupNameLengthWarning"> + グループå㯠[MIN_LEN] ~ [MAX_LEN] æ–‡å—ã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="UnableToCreateGroup"> グループを作æˆã§ãã¾ã›ã‚“。 [MESSAGE] @@ -367,7 +371,7 @@ L$ ãŒä¸è¶³ã—ã¦ã„ã‚‹ã®ã§ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã«å‚åŠ ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。 </notification> <notification name="CreateGroupCost"> - ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—を作るã«ã¯ L$ 100 ã‹ã‹ã‚Šã¾ã™ã€‚ + ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—作æˆã«ã‹ã‹ã‚‹è²»ç”¨ï¼šL$[COST] 一人ã§ã¯ã‚°ãƒ«ãƒ¼ãƒ—ã«ãªã‚‰ãªã„ã®ã§ã€æ°¸ä¹…ã«å‰Šé™¤ã•れã¦ã—ã¾ã„ã¾ã™ã€‚ 48 時間以内ã«ãƒ¡ãƒ³ãƒãƒ¼ã‚’勧誘ã—ã€å…¥ä¼šã—ã¦ã‚‚らã£ã¦ãã ã•ã„。 <usetemplate canceltext="ã‚ャンセル" name="okcancelbuttons" notext="ã‚ャンセル" yestext="L$100 ã§ã‚°ãƒ«ãƒ¼ãƒ—を作æˆ"/> @@ -518,6 +522,9 @@ L$ ãŒä¸è¶³ã—ã¦ã„ã‚‹ã®ã§ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã«å‚åŠ ã™ã‚‹ã“ã¨ãŒã§ãã <notification name="ErrorEncodingSnapshot"> スナップショットã®ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰åŒ–ã§ã‚¨ãƒ©ãƒ¼ãŒå‡ºã¾ã—ãŸï¼ </notification> + <notification name="ErrorCannotAffordUpload"> + ã“ã®ã‚¢ã‚¤ãƒ†ãƒ をアップãƒãƒ¼ãƒ‰ã™ã‚‹ãŸã‚ã«ã¯ L$[COST] ãŒå¿…è¦ã§ã™ã€‚ + </notification> <notification name="ErrorPhotoCannotAfford"> インベントリã«å†™çœŸã‚’ä¿å˜ã™ã‚‹ã«ã¯ L$[COST] ãŒå¿…è¦ã§ã™ã€‚L$ を購入ã™ã‚‹ã‹ã€ä»£ã‚りã«å†™çœŸã‚’ã£ã‚³ãƒ³ãƒ”ュータã«ä¿å˜ã§ãã¾ã™ã€‚ </notification> @@ -1773,11 +1780,14 @@ https://secondlife.com/support/downloads/ ã‹ã‚‰ãƒ€ã‚¦ãƒ³ãƒãƒ¼ãƒ‰ã—ã¦ãã ã <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="GroupLimitInfo"> - ベースアカウントã®ã‚°ãƒ«ãƒ¼ãƒ—制é™ã¯ [MAX_BASIC]ã€[https://secondlife.com/premium/ プレミアム] アカウント㮠-グループ制é™ã¯ [MAX_PREMIUM] ã§ã™ã€‚ -アカウントをダウングレードã—ãŸå ´åˆã€ã•らã«ã‚°ãƒ«ãƒ¼ãƒ—ã«å‚åŠ ã™ã‚‹å‰ã«ã€ä¸‹ã® [MAX_BASIC] グループ制é™ã‚’å–å¾—ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ - -[https://secondlife.com/my/account/membership.php 今ã™ãアップグレード!] + ベーシック会員ã®ä½æ°‘ã¯ã€æœ€å¤§ [MAX_BASIC] グループã¾ã§å‚åŠ ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ +プレミアム会員ã¯ã€æœ€å¤§ [MAX_PREMIUM] ã¾ã§å¯èƒ½ã§ã™ã€‚[https://secondlife.com/my/account/membership.php? 詳細ã€ã¾ãŸã¯ã‚¢ãƒƒãƒ—グレード] + <usetemplate name="okbutton" yestext="é–‰ã˜ã‚‹"/> + </notification> + <notification name="GroupLimitInfoPlus"> + ベーシック会員ã®ä½æ°‘ã¯ã€æœ€å¤§ [MAX_BASIC] グループã¾ã§å‚åŠ ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ +プレミアム会員ã¯ã€æœ€å¤§ [MAX_PREMIUM] ã¾ã§å¯èƒ½ã§ã™ã€‚プレミアムプラス会員ã¯ã€æœ€å¤§ [MAX_PREMIUM_PLUS] ã¾ã§å¯èƒ½ã§ã™ã€‚ +[https://secondlife.com/my/account/membership.php? 詳細ã€ã¾ãŸã¯ã‚¢ãƒƒãƒ—グレード] <usetemplate name="okbutton" yestext="é–‰ã˜ã‚‹"/> </notification> <notification name="KickUser"> @@ -1996,6 +2006,11 @@ http://wiki.secondlife.com/wiki/Setting_your_display_name ã‚’å‚ç…§ã—ã¦ãã ã ã“ã®ã‚ªãƒ—ションをオフã«ã™ã‚‹ã¨ã€å«ŒãŒã‚‰ã›ã®é˜²æ¢ã‚„プライãƒã‚·ãƒ¼ã®ç¶æŒã€18 æ‰ä»¥ä¸‹ã®ä½äººã‚’ Adult コンテンツã‹ã‚‰å®ˆã‚‹ãŸã‚ã«åŒºç”»æ‰€æœ‰è€…ãŒåŠ ãˆãŸåˆ¶é™ãŒè§£é™¤ã•れるå¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚å¿…è¦ã«å¿œã˜ã¦åŒºç”»æ‰€æœ‰è€…ã¨ç›¸è«‡ã—ã¦ãã ã•ã„。 <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="EstateParcelEnvironmentOverride"> + ã“ã®ã‚ªãƒ—ションをオフã«ã™ã‚‹ã¨ã€åŒºç”»æ‰€æœ‰è€…ãŒãã®åŒºç”»ã«åŠ ãˆãŸã‚«ã‚¹ã‚¿ãƒ 環境ãŒå‰Šé™¤ã•れã¾ã™ã€‚å¿…è¦ã«å¿œã˜ã¦åŒºç”»æ‰€æœ‰è€…ã¨ç›¸è«‡ã—ã¦ãã ã•ã„。 +ç¶šã‘ã¾ã™ã‹ï¼Ÿ + <usetemplate name="okcancelbuttons" notext="ã‚ャンセル" yestext="OK"/> + </notification> <notification name="RegionEntryAccessBlocked"> 訪å•ã—よã†ã¨ã—ã¦ã„る地域(リージョン)ã«ã¯ç¾åœ¨ã®ç’°å¢ƒè¨å®šã‚’è¶…ãˆã‚‹ã‚³ãƒ³ãƒ†ãƒ³ãƒ„ãŒå«ã¾ã‚Œã¦ã„ã¾ã™ã€‚「ミー〠> 「環境è¨å®šã€ > 「一般ã€ã‚’é¸æŠžã—ã¦ã€ç’°å¢ƒè¨å®šã‚’変更ã§ãã¾ã™ã€‚ <usetemplate name="okbutton" yestext="OK"/> @@ -2483,7 +2498,14 @@ Web ページã«ãƒªãƒ³ã‚¯ã™ã‚‹ã¨ã€ä»–人ãŒã“ã®å ´æ‰€ã«ç°¡å˜ã«ã‚¢ã‚¯ã‚»ã ã“ã®ãƒ‡ã‚¤ã‚µã‚¤ã‚¯ãƒ«ã®ãƒ•ã‚¡ã‚¤ãƒ«ã¯æ¬¡ã®å˜åœ¨ã—ãªã„「空ã€ãƒ•ァイルをå‚ç…§ã—ã¦ã„ã¾ã™ï¼š [SKY]。 </notification> <notification name="WLRegionApplyFail"> - 申ã—訳ã”ã–ã„ã¾ã›ã‚“ãŒã€è¨å®šã‚’リージョンã«é©ç”¨ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚一度リージョンを出ã¦ã‹ã‚‰æˆ»ã‚‹ã¨ã€å•題ãŒè§£æ±ºã•れるã‹ã‚‚ã—れã¾ã›ã‚“。å•題ã®ç™ºç”Ÿã—ãŸç†ç”±ï¼š[FAIL_REASON] + 申ã—訳ã”ã–ã„ã¾ã›ã‚“ãŒã€è¨å®šã‚’リージョンã«é©ç”¨ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ç†ç”±ï¼š [FAIL_REASON] + </notification> + <notification name="WLLocalTextureDayBlock"> + ãƒãƒ¼ã‚«ãƒ«ãƒ†ã‚¯ã‚¹ãƒãƒ£ã¯ã€ãƒ•ィールド [FIELD] 内ã®ãƒˆãƒ©ãƒƒã‚¯ [TRACK]ã€ãƒ•レーム#[FRAMENO] ([FRAME]%) ã§ä½¿ç”¨ã•れã¦ã„ã¾ã™ã€‚ãƒãƒ¼ã‚«ãƒ«ãƒ†ã‚¯ã‚¹ãƒãƒ£ã‚’使ã£ãŸè¨å®šã¯ä¿å˜ã•れãªã„å¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚ + </notification> + <notification name="WLLocalTextureFixedBlock"> + ãƒãƒ¼ã‚«ãƒ«ãƒ†ã‚¯ã‚¹ãƒãƒ£ã¯ã€ãƒ•ィールド [FIELD] ã§ä½¿ç”¨ã•れã¦ã„ã¾ã™ã€‚ +ãƒãƒ¼ã‚«ãƒ«ãƒ†ã‚¯ã‚¹ãƒãƒ£ã‚’使ã£ãŸè¨å®šã¯ä¿å˜ã•れãªã„å¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚ </notification> <notification name="EnvCannotDeleteLastDayCycleKey"> デイサイクルを空ã«ã¯ã§ããªã„ã®ã§ã€ã“ã®ãƒ‡ã‚¤ã‚µã‚¤ã‚¯ãƒ«ã®æœ€å¾Œã®ã‚ーを削除ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。最後ã®ã‚ーを削除ã—ã¦æ–°ã—ã„ã‚ーを作æˆã™ã‚‹ã®ã§ã¯ãªãã€æœ€å¾Œã®ã‚ーを変更ã—ã¦ãã ã•ã„。 @@ -3337,6 +3359,22 @@ M ã‚ーを押ã—ã¦å¤‰æ›´ã—ã¾ã™ã€‚ モデレーターãŒã‚ãªãŸã®ãƒœã‚¤ã‚¹ã‚’ミュートã—ã¾ã—ãŸã€‚ <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FailedToGetBenefits"> + 残念ãªãŒã‚‰ã€ã“ã®ã‚»ãƒƒã‚·ãƒ§ãƒ³ã®ãƒ™ãƒãƒ•ã‚£ãƒƒãƒˆæƒ…å ±ã‚’å¾—ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“ã§ã—ãŸã€‚通常ã®ãƒ—ãƒãƒ€ã‚¯ã‚·ãƒ§ãƒ³ç’°å¢ƒã§èµ·ã“ã‚‹ã“ã¨ã§ã¯ã‚りã¾ã›ã‚“。サãƒãƒ¼ãƒˆã¾ã§ã”連絡ãã ã•ã„。ã“ã®ã‚»ãƒƒã‚·ãƒ§ãƒ³ã¯é€šå¸¸é€šã‚Šã«ä½œå‹•ã—ã¾ã›ã‚“ã®ã§ã€å†ã‚¹ã‚¿ãƒ¼ãƒˆã‚’ãŠè–¦ã‚ã—ã¾ã™ + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="BulkUploadCostConfirmation"> + åˆè¨ˆ L$[COST] ã§ [COUNT] アイテムãŒã‚¢ãƒƒãƒ—ãƒãƒ¼ãƒ‰ã•れã¾ã™ã€‚ アップãƒãƒ¼ãƒ‰ã‚’ç¶šã‘ã¾ã™ã‹ï¼Ÿ + <usetemplate name="okcancelbuttons" notext="å–り消ã—" yestext="アップãƒãƒ¼ãƒ‰"/> + </notification> + <notification name="BulkUploadNoCompatibleFiles"> + é¸æŠžã—ãŸãƒ•ァイルã¯ã€ã¾ã¨ã‚ã¦ã‚¢ãƒƒãƒ—ãƒãƒ¼ãƒ‰ã§ãã¾ã›ã‚“。 + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="BulkUploadIncompatibleFiles"> + é¸æŠžã—ãŸãƒ•ァイルã®ã„ãã¤ã‹ã¯ã€ã¾ã¨ã‚ã¦ã‚¢ãƒƒãƒ—ãƒãƒ¼ãƒ‰ã§ãã¾ã›ã‚“。 + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="UploadCostConfirmation"> ã“ã®ã‚¢ãƒƒãƒ—ãƒãƒ¼ãƒ‰ã¯ L$[PRICE] ã®ã‚³ã‚¹ãƒˆãŒã‹ã‹ã‚Šã¾ã™ã€‚アップãƒãƒ¼ãƒ‰ã‚’ç¶šã‘ã¾ã™ã‹ï¼Ÿ <usetemplate name="okcancelbuttons" notext="å–り消ã—" yestext="アップãƒãƒ¼ãƒ‰"/> @@ -4429,4 +4467,75 @@ M ã‚ーを押ã—ã¦å¤‰æ›´ã—ã¾ã™ã€‚ [REASON] <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FailedToFindSettings"> + データベースã‹ã‚‰ [NAME] ã®è¨å®šã®èªã¿è¾¼ã¿ãŒã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ + </notification> + <notification name="FailedToLoadSettingsApply"> + 環境ã«ã“れらã®è¨å®šã‚’é©ç”¨ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。 + </notification> + <notification name="FailedToBuildSettingsDay"> + 環境ã«ã“れらã®è¨å®šã‚’é©ç”¨ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。 + </notification> + <notification name="NoEnvironmentSettings"> + ã“ã®ãƒªãƒ¼ã‚¸ãƒ§ãƒ³ã¯ç’°å¢ƒè¨å®šã‚’サãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã›ã‚“。 + </notification> + <notification label="アウトフィットをä¿å˜ã™ã‚‹" name="SaveSettingAs"> + ç¾åœ¨ã®ç’°å¢ƒè¨å®šã‚’次ã®å†…容ã§ä¿å˜ã™ã‚‹ï¼š + <form name="form"> + <input name="message"> + [DESC] (新) + </input> + <button name="OK" text="OK"/> + <button name="Cancel" text="ã‚ャンセル"/> + </form> + </notification> + <notification name="WLImportFail"> + [FILE] ã‹ã‚‰éŽåŽ»ã®ã‚¦ã‚¤ãƒ³ãƒ‰ãƒ©ã‚¤ãƒˆã®è¨å®š [NAME] をインãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“。 + +[REASONS] + </notification> + <notification name="WLParcelApplyFail"> + ã“ã®åŒºç”»ã§ç’°å¢ƒã‚’è¨å®šã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。 +変更ã™ã‚‹æ¨©é™ã®ã‚る区画を入力ã¾ãŸã¯é¸æŠžã—ã¦ãã ã•ã„。 + </notification> + <notification name="SettingsUnsuported"> + ã“ã®ãƒªãƒ¼ã‚¸ãƒ§ãƒ³ã§ã¯è¨å®šã‚’サãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã›ã‚“。 +è¨å®šã«å¯¾å¿œã—ã¦ã„るリージョンã«ç§»å‹•ã—ã€ã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã‚’å†è©¦è¡Œã—ã¦ãã ã•ã„。 + </notification> + <notification name="SettingsConfirmLoss"> + "[NAME]"ã¨å付ã‘られãŸã“ã® [TYPE] ã«åŠ ãˆã‚‰ã‚ŒãŸå¤‰æ›´ãŒå¤±ã‚れã¾ã™ã€‚ +ç¶šã‘ã¾ã™ã‹ï¼Ÿ + <usetemplate ignoretext="変更を失ã„ã¾ã™ãŒã‚ˆã‚ã—ã„ã§ã™ã‹ï¼Ÿ" name="okcancelignore" notext="ã„ã„ãˆ" yestext="ã¯ã„"/> + </notification> + <notification name="SettingsConfirmReset"> + é©ç”¨ã•れãŸã™ã¹ã¦ã®è¨å®šã‚’削除ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚ +ç¶šã‘ã¾ã™ã‹ï¼Ÿ + <usetemplate name="okcancelbuttons" notext="ã„ã„ãˆ" yestext="ã¯ã„"/> + </notification> + <notification name="PersonalSettingsConfirmReset"> + é©ç”¨ã•れãŸã™ã¹ã¦ã®å€‹äººçš„ãªç…§æ˜Žã®è¨å®šã‚’削除ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚ +ç¶šã‘ã¾ã™ã‹ï¼Ÿ + <usetemplate name="okcancelbuttons" notext="ã„ã„ãˆ" yestext="ã¯ã„"/> + </notification> + <notification name="SettingsMakeNoTrans"> + ã“ã®ãƒ‡ã‚¤ã‚µã‚¤ã‚¯ãƒ«ã«ç§»è¡Œä¸å¯ã®è¨å®šã‚’インãƒãƒ¼ãƒˆã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚ã“ã®ã¾ã¾ç¶šã‘ã‚‹ã¨ã€ç·¨é›†ä¸ã®è¨å®šã‚‚移行ä¸å¯ã«ãªã‚Šã¾ã™ã€‚ + +ã“ã®å¤‰æ›´ã¯å…ƒã«æˆ»ã™ã“ã¨ãŒã§ãã¾ã›ã‚“。 + +ç¶šã‘ã¾ã™ã‹ï¼Ÿ + <usetemplate ignoretext="è¨å®šã‚’移行ä¸å¯ã«ã—ã¾ã™ã‹ï¼Ÿ" name="okcancelignore" notext="ã„ã„ãˆ" yestext="ã¯ã„"/> + </notification> + <notification name="NoEditFromLibrary"> + ライブラリã‹ã‚‰ç›´æŽ¥è¨å®šã‚’変更ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。 +è‡ªåˆ†ã®æŒã¡ç‰©ã‹ã‚‰ã‚³ãƒ”ーã—ã¦ã‚„り直ã—ã¦ãã ã•ã„。 + </notification> + <notification name="EnvironmentApplyFailed"> + ã“ã®è¨å®šã§å•題ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã“ã®è¨å®šã¯ç¾åœ¨ä¿å˜ã¾ãŸã¯é©ç”¨ãŒã§ãã¾ã›ã‚“。 + </notification> + <notification name="TrackLoadFailed"> + トラックを [TRACK] ã«ãƒãƒ¼ãƒ‰ã§ãã¾ã›ã‚“。 + </notification> + <notification name="TrackLoadMismatch"> + トラックを [TRACK1] ã‹ã‚‰ [TRACK2] ã«ãƒãƒ¼ãƒ‰ã§ãã¾ã›ã‚“。 + </notification> </notifications> diff --git a/indra/newview/skins/default/xui/ja/panel_edit_classified.xml b/indra/newview/skins/default/xui/ja/panel_edit_classified.xml index b556b68e02..cf5f2489f1 100644 --- a/indra/newview/skins/default/xui/ja/panel_edit_classified.xml +++ b/indra/newview/skins/default/xui/ja/panel_edit_classified.xml @@ -47,7 +47,7 @@ <button label="[LABEL]" name="save_changes_btn"/> </layout_panel> <layout_panel name="show_on_map_btn_lp"> - <button label="å–り消ã—" name="cancel_btn"/> + <button label="ã‚ャンセル" name="cancel_btn"/> </layout_panel> </layout_stack> </panel> diff --git a/indra/newview/skins/default/xui/ja/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/ja/panel_edit_tattoo.xml index f4cfe6d83f..5729cb7552 100644 --- a/indra/newview/skins/default/xui/ja/panel_edit_tattoo.xml +++ b/indra/newview/skins/default/xui/ja/panel_edit_tattoo.xml @@ -1,9 +1,11 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_tattoo_panel"> - <panel name="avatar_tattoo_color_panel"> - <texture_picker label="é 部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Head Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠž"/> - <texture_picker label="上部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Upper Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠž"/> - <texture_picker label="下部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Lower Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠž"/> - <color_swatch label="色・色彩é…åˆ" name="Color/Tint" tool_tip="クリックã—ã¦ã‚«ãƒ©ãƒ¼ãƒ”ッカーを開ãã¾ã™"/> - </panel> + <scroll_container name="avatar_tattoo_scroll"> + <panel name="avatar_tattoo_color_panel"> + <texture_picker label="é 部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Head Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã™ã‚‹"/> + <texture_picker label="上部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Upper Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã™ã‚‹"/> + <texture_picker label="下部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Lower Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã™ã‚‹"/> + <color_swatch label="è‰²ï¼æ˜Žæš—" name="Color/Tint" tool_tip="クリックã—ã¦ã‚«ãƒ©ãƒ¼ãƒ”ッカーを開ãã¾ã™"/> + </panel> + </scroll_container> </panel> diff --git a/indra/newview/skins/default/xui/ja/panel_edit_universal.xml b/indra/newview/skins/default/xui/ja/panel_edit_universal.xml new file mode 100644 index 0000000000..614fd1059f --- /dev/null +++ b/indra/newview/skins/default/xui/ja/panel_edit_universal.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel name="edit_universal_panel"> + <scroll_container name="avatar_universal_scroll"> + <panel name="avatar_universal_color_panel"> + <texture_picker label="é 部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Head Universal Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã™ã‚‹"/> + <texture_picker label="上部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Upper Universal Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã™ã‚‹"/> + <texture_picker label="下部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Lower Universal Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã™ã‚‹"/> + <texture_picker label="スカートã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Skirt Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã™ã‚‹"/> + <texture_picker label="é«ªã®æ¯›ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Hair Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã™ã‚‹"/> + <texture_picker label="ç›®ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Eyes Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã™ã‚‹"/> + <texture_picker label="左腕ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Left Arm Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã™ã‚‹"/> + <texture_picker label="左脚ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Left Leg Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã™ã‚‹"/> + <texture_picker label="Aux1 ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Aux1 Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã™ã‚‹"/> + <texture_picker label="Aux2 ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Aux2 Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã™ã‚‹"/> + <texture_picker label="Aux3 ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Aux3 Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã™ã‚‹"/> + <color_swatch label="è‰²ï¼æ˜Žæš—" name="Color/Tint" tool_tip="クリックã—ã¦ã‚«ãƒ©ãƒ¼ãƒ”ッカーを開ãã¾ã™"/> + </panel> + </scroll_container> +</panel> diff --git a/indra/newview/skins/default/xui/ja/panel_edit_wearable.xml b/indra/newview/skins/default/xui/ja/panel_edit_wearable.xml index 000dac7b5b..9101920f1b 100644 --- a/indra/newview/skins/default/xui/ja/panel_edit_wearable.xml +++ b/indra/newview/skins/default/xui/ja/panel_edit_wearable.xml @@ -45,6 +45,9 @@ <string name="edit_tattoo_title"> ã‚¿ãƒˆã‚¥ãƒ¼ã‚’ç·¨é›†ä¸ </string> + <string name="edit_universal_title"> + ユニãƒãƒ¼ã‚µãƒ«ã‚’ç·¨é›†ä¸ + </string> <string name="edit_physics_title"> 物ç†ä½œç”¨ã®ç·¨é›†ä¸ </string> @@ -93,6 +96,9 @@ <string name="tattoo_desc_text"> タトゥ: </string> + <string name="universal_desc_text"> + ユニãƒãƒ¼ã‚µãƒ«ï¼š + </string> <string name="physics_desc_text"> 物ç†ä½œç”¨ï¼š </string> diff --git a/indra/newview/skins/default/xui/ja/panel_me.xml b/indra/newview/skins/default/xui/ja/panel_me.xml index 3df1ae8048..9b1cf1c8a4 100644 --- a/indra/newview/skins/default/xui/ja/panel_me.xml +++ b/indra/newview/skins/default/xui/ja/panel_me.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<panel label="マイ プãƒãƒ•ィール" name="panel_me"> - <panel label="マイ-ピック" name="panel_picks"/> +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="プãƒãƒ•ィール" name="panel_me"> + <panel label="マイ ピック" name="panel_picks"/> </panel> diff --git a/indra/newview/skins/default/xui/ja/panel_outbox_inventory.xml b/indra/newview/skins/default/xui/ja/panel_outbox_inventory.xml deleted file mode 100644 index 1a14283113..0000000000 --- a/indra/newview/skins/default/xui/ja/panel_outbox_inventory.xml +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<outbox_inventory_panel name="inventory_outbox" tool_tip="アイテムをã“ã“ã«ãƒ‰ãƒ©ãƒƒã‚°ã‚¢ãƒ³ãƒ‰ãƒ‰ãƒãƒƒãƒ—ã™ã‚‹ã¨ã€ã‚ãªãŸã®åº—é ã«ä¸¦ã³ã¾ã™"/> diff --git a/indra/newview/skins/default/xui/ja/panel_people.xml b/indra/newview/skins/default/xui/ja/panel_people.xml index 5fc4b57a08..0a295855d0 100644 --- a/indra/newview/skins/default/xui/ja/panel_people.xml +++ b/indra/newview/skins/default/xui/ja/panel_people.xml @@ -18,7 +18,7 @@ <string name="no_groups_msg" value="ã‚°ãƒ«ãƒ¼ãƒ—ã‚’ãŠæŽ¢ã—ã§ã™ã‹ï¼Ÿ [secondlife:///app/search/groups 検索] ã‚’ãŠè©¦ã—ãã ã•ã„。"/> <string name="MiniMapToolTipMsg" value="[地域](ダブルクリックã§åœ°å›³ã‚’é–‹ã。Shiftâ€ãƒ‰ãƒ©ãƒƒã‚°ã§æ°´å¹³ãƒ»åž‚直移動)"/> <string name="AltMiniMapToolTipMsg" value="[地域](ダブルクリックã§ãƒ†ãƒ¬ãƒãƒ¼ãƒˆã€‚Shiftâ€ãƒ‰ãƒ©ãƒƒã‚°ã§æ°´å¹³ãƒ»åž‚直移動)"/> - <string name="GroupCountWithInfo" value="ã‚ãªãŸã¯ [COUNT] グループã«å±žã—ã¦ã„ã‚‹ã®ã§ã€ã¾ã [REMAINING] å‚åŠ ã§ãã¾ã™ã€‚[secondlife:/// 詳細]"/> + <string name="GroupCountWithInfo" value="ã‚ãªãŸã¯ç¾åœ¨ã€[COUNT] グループã«å±žã—ã¦ã„ã¾ã™ã€‚ã‚㨠[REMAINING] グループã«å‚åŠ ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚[secondlife:/// 上é™ã‚’増やã™]"/> <tab_container name="tabs"> <panel label="è¿‘ã" name="nearby_panel"> <panel label="bottom_panel" name="nearby_buttons_panel"> @@ -51,7 +51,7 @@ <dnd_button name="minus_btn" tool_tip="é¸æŠžã—ãŸã‚°ãƒ«ãƒ¼ãƒ—ã‹ã‚‰è„±é€€"/> </panel> <text name="groupcount"> - ã‚ãªãŸã¯[COUNT]グループã«å±žã—ã¦ã„ã‚‹ã®ã§ã€ã¾ã [REMAINING]å‚åŠ ã§ãã¾ã™ã€‚ + ã‚ãªãŸã¯ç¾åœ¨ã€[COUNT] グループã«å±žã—ã¦ã„ã¾ã™ã€‚ã‚㨠[REMAINING] グループã«å‚åŠ ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ </text> </panel> <panel label="最新" name="recent_panel"> diff --git a/indra/newview/skins/default/xui/ja/panel_region_environment.xml b/indra/newview/skins/default/xui/ja/panel_region_environment.xml index a2981012dc..444f8bae91 100644 --- a/indra/newview/skins/default/xui/ja/panel_region_environment.xml +++ b/indra/newview/skins/default/xui/ja/panel_region_environment.xml @@ -1,33 +1,116 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="環境" name="panel_env_info"> - <text name="water_settings_title"> - ã‚ãªãŸã®ãƒªãƒ¼ã‚¸ãƒ§ãƒ³ã‚’訪れるユーザーã«è¦‹ã›ãŸã„ã€æ°´ã¨ç©º/デイサイクルã®è¨å®šã‚’é¸æŠžã—ã¾ã™ã€‚詳細 - </text> - <radio_group name="region_settings_radio_group"> - <radio_item label="Second Life ã®ãƒ‡ãƒ•ォルトè¨å®šã‚’使用" name="use_sl_default_settings"/> - <radio_item label="次ã®è¨å®šã‚’使用" name="use_my_settings"/> - </radio_group> - <panel name="user_environment_settings"> - <text name="water_settings_title"> - æ°´ã®è¨å®š - </text> - <combo_box name="water_settings_preset_combo"> - <combo_box.item label="- 事å‰è¨å®šã‚’é¸æŠž -" name="item0"/> - </combo_box> - <text name="sky_dayc_settings_title"> - 空 / デイサイクル - </text> - <radio_group name="sky_dayc_settings_radio_group"> - <radio_item label="空ã®å›ºå®š" name="my_sky_settings"/> - <radio_item label="デイサイクル" name="my_dayc_settings"/> - </radio_group> - <combo_box name="sky_settings_preset_combo"> - <combo_box.item label="- 事å‰è¨å®šã‚’é¸æŠž -" name="item0"/> - </combo_box> - <combo_box name="dayc_settings_preset_combo"> - <combo_box.item label="- 事å‰è¨å®šã‚’é¸æŠž -" name="item0"/> - </combo_box> - </panel> - <button label="é©ç”¨" name="apply_btn"/> - <button label="ã‚ャンセル" name="cancel_btn"/> + <string name="str_label_use_default"> + 既定ã®è¨å®šã‚’使用 + </string> + <string name="str_label_use_region"> + リージョンã®è¨å®šã‚’使用 + </string> + <string name="str_altitude_desription"> + 空 [INDEX]([ALTITUDE]m) + </string> + <string name="str_no_parcel"> + 区画ãŒé¸æŠžã•れã¦ã„ã¾ã›ã‚“。環境è¨å®šãŒç„¡åйã«ãªã£ã¦ã„ã¾ã™ã€‚ + </string> + <string name="str_cross_region"> + リージョンã®å¢ƒç•Œã§ã¯ç’°å¢ƒè¨å®šãŒã§ãã¾ã›ã‚“。 + </string> + <string name="str_legacy"> + ã“ã®ãƒªãƒ¼ã‚¸ãƒ§ãƒ³ã§ç’°å¢ƒè¨å®šã¯ã§ãã¾ã›ã‚“。 + </string> + <string name="str_disallowed"> + ä¸å‹•産マãƒãƒ¼ã‚¸ãƒ£ãƒ¼ãŒã€ã“ã®ãƒªãƒ¼ã‚¸ãƒ§ãƒ³ã§åŒºç”»ã®ç’°å¢ƒã‚’変更ã™ã‚‹ã“ã¨ã‚’許å¯ã—ã¦ã„ã¾ã›ã‚“。 + </string> + <string name="str_too_small"> + 環境をサãƒãƒ¼ãƒˆã™ã‚‹ã«ã¯ã€æœ€ä½Žã§ã‚‚ 128 平方メートルã®åŒºç”»ãŒå¿…è¦ã§ã™ã€‚ + </string> + <string name="str_empty"> + (空) + </string> + <string name="str_region_env"> + (リージョンã®ç’°å¢ƒï¼‰ + </string> + <layout_stack> + <layout_panel name="pnl_environment_disabled"> + <text name="txt_environment_disabled"> + ... + </text> + </layout_panel> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_current"> + <button label="[USEDEFAULT]" name="btn_usedefault"/> + <button label="æŒã¡ç‰©ã‚’使ã†" name="btn_select_inventory"/> + <button label="カスタマイズ" name="btn_edit"/> + <check_box label="区画所有者ãŒç’°å¢ƒã‚’上書ãã™ã‚‹ã“ã¨ãŒã‚りã¾ã™" name="chk_allow_override"/> + </layout_panel> + <layout_panel name="pnl_environment_length"> + <text name="lbl_apparent_time"> + [HH]:[MM][AP] ([PRC]%) + </text> + </layout_panel> + <layout_panel name="pnl_environment_buttons"/> + </layout_stack> + </layout_panel> + <layout_panel name="pnl_environment_altitudes"> + <panel name="pnl_alt1"> + <text name="txt_alt1"> + 空 [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt1"> + 䏿˜Ž + </line_editor> + <settings_drop_target name="sdt_alt1" tool_tip="æŒã¡ç‰©ã‹ã‚‰è¨å®šã‚’ã“ã®ã‚¿ãƒ¼ã‚²ãƒƒãƒˆãƒœãƒƒã‚¯ã‚¹ã«ãƒ‰ãƒ©ãƒƒã‚°ã—ã€ç¾åœ¨ã®ç©ºã¨ã—ã¦é¸æŠžã™ã‚‹"/> + </panel> + <panel name="pnl_alt2"> + <text name="txt_alt2"> + 空 [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt2"> + 䏿˜Ž + </line_editor> + <settings_drop_target name="sdt_alt2" tool_tip="æŒã¡ç‰©ã‹ã‚‰è¨å®šã‚’ã“ã®ã‚¿ãƒ¼ã‚²ãƒƒãƒˆãƒœãƒƒã‚¯ã‚¹ã«ãƒ‰ãƒ©ãƒƒã‚°ã—ã€ç¾åœ¨ã®ç©ºã¨ã—ã¦é¸æŠžã™ã‚‹"/> + </panel> + <panel name="pnl_alt3"> + <text name="txt_alt3"> + 空 [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt3"> + 䏿˜Ž + </line_editor> + <settings_drop_target name="sdt_alt3" tool_tip="æŒã¡ç‰©ã‹ã‚‰è¨å®šã‚’ã“ã®ã‚¿ãƒ¼ã‚²ãƒƒãƒˆãƒœãƒƒã‚¯ã‚¹ã«ãƒ‰ãƒ©ãƒƒã‚°ã—ã€ç¾åœ¨ã®ç©ºã¨ã—ã¦é¸æŠžã™ã‚‹"/> + </panel> + <multi_slider initial_value="0" name="sld_altitudes"> + <slider name="sld1" value="1000"/> + <slider name="sld2" value="2000"/> + <slider name="sld3" value="3000"/> + </multi_slider> + <panel name="pnl_ground"> + <text name="txt_ground"> + åœ°é¢ + </text> + <line_editor name="edt_invname_ground"> + 䏿˜Ž + </line_editor> + <settings_drop_target name="sdt_ground" tool_tip="æŒã¡ç‰©ã‹ã‚‰è¨å®šã‚’ã“ã®ã‚¿ãƒ¼ã‚²ãƒƒãƒˆãƒœãƒƒã‚¯ã‚¹ã«ãƒ‰ãƒ©ãƒƒã‚°ã—ã€åœ°è¡¨ãƒ¬ãƒ™ãƒ«ã®ç©ºã¨ã—ã¦é¸æŠžã—ã¾ã™ã€‚"/> + </panel> + <panel name="pnl_water"> + <text name="txt_water"> + æ°´ + </text> + <line_editor name="edt_invname_water"> + 䏿˜Ž + </line_editor> + <settings_drop_target name="sdt_water" tool_tip="æŒã¡ç‰©ã‹ã‚‰è¨å®šã‚’ã“ã®ã‚¿ãƒ¼ã‚²ãƒƒãƒˆãƒœãƒƒã‚¯ã‚¹ã«ãƒ‰ãƒ©ãƒƒã‚°ã—ã€ç¾åœ¨ã®æ°´ã¨ã—ã¦é¸æŠžã™ã‚‹"/> + </panel> + <button label="リセット" name="btn_rst_altitudes" tool_tip="デフォルトã®é«˜åº¦ã«ãƒªã‚»ãƒƒãƒˆ"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> </panel> diff --git a/indra/newview/skins/default/xui/ja/panel_settings_sky_atmos.xml b/indra/newview/skins/default/xui/ja/panel_settings_sky_atmos.xml new file mode 100644 index 0000000000..56fab14f7c --- /dev/null +++ b/indra/newview/skins/default/xui/ja/panel_settings_sky_atmos.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="大気&光" name="panel_settings_sky_atmos"/> diff --git a/indra/newview/skins/default/xui/ja/panel_settings_sky_clouds.xml b/indra/newview/skins/default/xui/ja/panel_settings_sky_clouds.xml new file mode 100644 index 0000000000..232530c5f8 --- /dev/null +++ b/indra/newview/skins/default/xui/ja/panel_settings_sky_clouds.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="雲" name="panel_settings_sky_clouds"> + <layout_stack> + <layout_panel> + <slider label="X" name="cloud_density_x"/> + <slider label="Y" name="cloud_density_y"/> + <slider label="D" name="cloud_density_d"/> + <slider label="X" name="cloud_detail_x"/> + <slider label="Y" name="cloud_detail_y"/> + <slider label="D" name="cloud_detail_d"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/ja/panel_settings_sky_density.xml b/indra/newview/skins/default/xui/ja/panel_settings_sky_density.xml new file mode 100644 index 0000000000..cb746d8792 --- /dev/null +++ b/indra/newview/skins/default/xui/ja/panel_settings_sky_density.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="密度" name="panel_settings_sky_density"> + <layout_stack> + <layout_panel> + <slider label="ãƒ¬ã‚¤ãƒªãƒ¼æŒ‡æ•°é …ï¼š" name="rayleigh_exponential"/> + <slider label="レイリー指数スケール:" name="rayleigh_exponential_scale"/> + <slider label="ãƒ¬ã‚¤ãƒªãƒ¼ç·šå½¢é …ï¼š" name="rayleigh_linear"/> + <slider label="ãƒ¬ã‚¤ãƒªãƒ¼å®šæ•°é …ï¼š" name="rayleigh_constant"/> + <slider label="レイリー最大高度:" name="rayleigh_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="ãƒ¬ã‚¤ãƒªãƒ¼æŒ‡æ•°é …ï¼š" name="mie_exponential"/> + <slider label="Mie 指数スケール:" name="mie_exponential_scale"/> + <slider label="Mie ç·šå½¢é …ï¼š" name="mie_linear"/> + <slider label="Mie å®šæ•°é …ï¼š" name="mie_constant"/> + <slider label="Mie ä¸ç‰è¦ç´ :" name="mie_aniso_factor"/> + <slider label="Mie 最大高度:" name="mie_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="å¸åŽæŒ‡æ•°é …:" name="absorption_exponential"/> + <slider label="å¸åŽæŒ‡æ•°ã‚¹ã‚±ãƒ¼ãƒ«ï¼š" name="absorption_exponential_scale"/> + <slider label="å¸åŽç·šå½¢é …:" name="absorption_linear"/> + <slider label="å¸åŽå®šæ•°é …:" name="absorption_constant"/> + <slider label="å¸åŽæœ€å¤§é«˜åº¦ï¼š" name="absorption_max_altitude"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/ja/panel_settings_sky_sunmoon.xml b/indra/newview/skins/default/xui/ja/panel_settings_sky_sunmoon.xml new file mode 100644 index 0000000000..e5026dc9fd --- /dev/null +++ b/indra/newview/skins/default/xui/ja/panel_settings_sky_sunmoon.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="太陽&月" name="panel_settings_sky_hbodies"> + <layout_stack> + <layout_panel name="sun_layout"> + <check_box label="ビーコンを表示" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <layout_stack> + <layout_panel name="moon_layout"> + <check_box label="ビーコンを表示" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/ja/panel_settings_water.xml b/indra/newview/skins/default/xui/ja/panel_settings_water.xml new file mode 100644 index 0000000000..20341fcb8d --- /dev/null +++ b/indra/newview/skins/default/xui/ja/panel_settings_water.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="æ°´" name="panel_settings_water"> + <layout_stack name="water_stack1"> + <layout_panel> + <text name="FresnelOffsetText"> + フレãƒãƒ«ãƒ»ã‚ªãƒ•セット: + </text> + </layout_panel> + <layout_panel> + <layout_stack name="water_stack2"> + <layout_panel> + <slider label="X:" name="water_normal_scale_x"/> + <slider label="Y:" name="water_normal_scale_y"/> + <slider label="Z:" name="water_normal_scale_z"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/ja/panel_tools_texture.xml b/indra/newview/skins/default/xui/ja/panel_tools_texture.xml index 1821a6fad6..75bc8eb86f 100644 --- a/indra/newview/skins/default/xui/ja/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/ja/panel_tools_texture.xml @@ -1,11 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="テクスãƒãƒ£" name="Texture"> - <panel.string name="string repeats per meter"> - メーターã”ã¨ã«ç¹°ã‚Šè¿”ã™ - </panel.string> - <panel.string name="string repeats per face"> - é¢ã”ã¨ã«ç¹°ã‚Šè¿”ã™ - </panel.string> <text name="color label"> 色 </text> @@ -114,4 +108,5 @@ <spinner label="水平オフセット" name="shinyOffsetU"/> <spinner label="垂直オフセット" name="shinyOffsetV"/> <check_box initial_value="false" label="å¹³é¢ã‚’æƒãˆã‚‹" name="checkbox planar align" tool_tip="é¸æŠžé¢å…¨ã¦ã®ãƒ†ã‚¯ã‚¹ãƒãƒ£ã‚’ã€æœ€å¾Œã«é¸æŠžã•れãŸé¢ã«æƒãˆã¾ã™ã€‚å¹³é¢ãƒ†ã‚¯ã‚¹ãƒãƒ£ã®ãƒžãƒƒãƒ”ングãŒå¿…è¦ã§ã™ã€‚"/> + <button label="æƒãˆã‚‹" label_selected="ç¾åœ¨ã®ãƒ†ã‚¯ã‚¹ãƒãƒ£ãƒ¬ã‚¤ãƒ¤ãƒ¼ã‚’æƒãˆã‚‹" name="button align textures" tool_tip="ç¾åœ¨ã®ãƒ†ã‚¯ã‚¹ãƒãƒ£ãƒ¬ã‚¤ãƒ¤ãƒ¼ã‚’æƒãˆã‚‹"/> </panel> diff --git a/indra/newview/skins/default/xui/ja/role_actions.xml b/indra/newview/skins/default/xui/ja/role_actions.xml index fe90da89c7..05eca2cca3 100644 --- a/indra/newview/skins/default/xui/ja/role_actions.xml +++ b/indra/newview/skins/default/xui/ja/role_actions.xml @@ -33,6 +33,7 @@ <action description="音楽ã¨ãƒ¡ãƒ‡ã‚£ã‚¢ã®è¨å®šã‚’変更" longdescription="ストリーミングミュージックã¨å‹•ç”»ã®è¨å®šã‚’変更ã™ã‚‹ã«ã¯ã€ã€ŒåœŸåœ°æƒ…å ±ã€ ï¼ž 「メディアã€ã‚¿ãƒ–を使ã„ã¾ã™ã€‚" name="land change media" value="20"/> <action description="「地形を編集ã€ã«åˆ‡ã‚Šæ›¿ãˆ" longdescription="「地形を編集ã€ã«åˆ‡ã‚Šæ›¿ãˆã¾ã™ã€‚ *è¦å‘Š* ã€ŒåœŸåœ°æƒ…å ±ã€ï¼žã€Œã‚ªãƒ—ションã€ï¼žã€Œåœ°å½¢ã‚’編集ã€ã®é †ã§é€²ã‚€ã¨ã€èª°ã§ã‚‚ã‚ãªãŸã®åœŸåœ°ã®å½¢ã®æ•´å‚™ã‚„ã€ãƒªãƒ³ãƒ‡ãƒ³è£½ã®æ¨¹æœ¨ã®è¨ç½®ã€ç§»å‹•ãŒã§ãã¾ã™ã€‚ ã“ã®èƒ½åŠ›ã‚’å‰²ã‚ŠæŒ¯ã‚‹å‰ã«ã€ã“ã®ã“ã¨ã‚’よãç†è§£ã—ã¦ãŠã„ã¦ãã ã•ã„。 ã€ŒåœŸåœ°æƒ…å ±ã€ï¼žã€Œã‚ªãƒ—ションã€ã‚¿ãƒ–ã‹ã‚‰ã€Œåœ°å½¢ã‚’編集ã€ã«åˆ‡ã‚Šæ›¿ãˆã‚‰ã‚Œã¾ã™ã€‚" name="land edit" value="21"/> <action description="ã€ŒåœŸåœ°æƒ…å ±ã€ï¼žã€Œã‚ªãƒ—ションã€ã‚¿ãƒ–内ã®ã•ã¾ã–ã¾ãªè¨å®šã‚’切り替ãˆ" longdescription="「安全(ダメージãªã—)ã€ã€ã€Œé£›è¡Œã€ã‚’切り替ãˆã€ä½äººã«ä»¥ä¸‹ã‚’許å¯ã—ã¾ã™ï¼š グループ所有地ã®ã€ŒåœŸåœ°æƒ…å ±ã€ > 「オプションã€ã‚¿ãƒ–内ã®ã€ã€Œåœ°å½¢ã‚’編集ã€ã€ã€Œåˆ¶ä½œã€ã€ã€Œãƒ©ãƒ³ãƒ‰ãƒžãƒ¼ã‚¯ã®ä½œæˆã€ã€ã€Œã‚¹ã‚¯ãƒªãƒ—トã®å®Ÿè¡Œã€ã€‚" name="land options" value="22"/> + <action description="自然環境ã®è¨å®šã¨ãƒ‡ã‚¤ã‚µã‚¤ã‚¯ãƒ«ã‚’ä¿®æ£ã™ã‚‹ã€‚" longdescription="「土地ã«ã¤ã„ã¦ã€ > 「環境ã€ã‚¿ãƒ–ã‹ã‚‰è‡ªç„¶ç’°å¢ƒã®è¨å®šã¨ãƒ‡ã‚¤ã‚µã‚¤ã‚¯ãƒ«ã‚’変更ã™ã‚‹ã€‚" name="land change environment" value="46"/> </action_set> <action_set description="ã“れらã®èƒ½åŠ›ã«ã¯ã€ã‚°ãƒ«ãƒ¼ãƒ—所有ã®åŒºç”»ã«é–¢ã™ã‚‹è¦åˆ¶ã‚’迂回ã™ã‚‹ã“ã¨ã‚’ã€ãƒ¡ãƒ³ãƒãƒ¼ã«è¨±å¯ã™ã‚‹æ¨©é™ãŒå«ã¾ã‚Œã¾ã™ã€‚" name="Parcel Powers"> <action description="常ã«ã€Œåœ°å½¢ã‚’編集ã€ã‚’許å¯" longdescription="ã“ã®èƒ½åŠ›ã‚’æŒã¤å½¹å‰²ã®ãƒ¡ãƒ³ãƒãƒ¼ã¯ã€ã‚°ãƒ«ãƒ¼ãƒ—所有ã®åŒºç”»ä¸Šã§åœ°å½¢ã‚’編集ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ãã®åŒºç”»ãŒã€ŒåœŸåœ°æƒ…å ±ã€ï¼žã€Œã‚ªãƒ—ションã€ã‚¿ãƒ–ã§ã‚ªãƒ•ã«ãªã£ã¦ã„ã¦ã‚‚ã€åœ°å½¢ã®ç·¨é›†ãŒå¯èƒ½ã§ã™ã€‚" name="land allow edit land" value="23"/> diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml index 1e123eb619..52d6fb0c2b 100644 --- a/indra/newview/skins/default/xui/ja/strings.xml +++ b/indra/newview/skins/default/xui/ja/strings.xml @@ -638,6 +638,15 @@ support@secondlife.com ã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。 <string name="BUTTON_HELP"> ヘルプを表示 </string> + <string name="TooltipNotecardNotAllowedTypeDrop"> + ã“ã®ã‚¿ã‚¤ãƒ—ã®ã‚¢ã‚¤ãƒ†ãƒ ã¯ã€ã“ã®ãƒªãƒ¼ã‚¸ãƒ§ãƒ³ã®ãƒŽãƒ¼ãƒˆã‚«ãƒ¼ãƒ‰ +ã«æ·»ä»˜ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。 + </string> + <string name="TooltipNotecardOwnerRestrictedDrop"> + 制é™ã®ãªã„ã€Œæ¬¡ã®æ‰€æœ‰è€…ã€ã® +許å¯ã®ã¿ãƒŽãƒ¼ãƒˆã‚«ãƒ¼ãƒ‰ã« +添付ã§ãã¾ã™ã€‚ + </string> <string name="Searching"> 検索ä¸... </string> @@ -717,6 +726,18 @@ support@secondlife.com ã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。 アップãƒãƒ¼ãƒ‰ãƒªã‚¯ã‚¨ã‚¹ãƒˆä¸ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚å•題を解決ã™ã‚‹ã«ã¯ã€ã‚µãƒãƒ¼ãƒˆ (http://secondlife.com/support)ã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。 </string> + <string name="SettingValidationError"> + インãƒãƒ¼ãƒˆã™ã‚‹è¨å®š [NAME] ã®æ¤œè¨¼ã«å¤±æ•—ã—ã¾ã—ãŸã€‚ + </string> + <string name="SettingImportFileError"> + ファイル [FILE] ã‚’é–‹ãã“ã¨ãŒã§ãã¾ã›ã‚“ + </string> + <string name="SettingParseFileError"> + ファイル [FILE] ã‚’é–‹ãã“ã¨ãŒã§ãã¾ã›ã‚“ + </string> + <string name="SettingTranslateError"> + éŽåŽ»ã®ã‚¦ã‚¤ãƒ³ãƒ‰ãƒ©ã‚¤ãƒˆ [NAME] を変æ›ã§ãã¾ã›ã‚“ + </string> <string name="texture"> テクスãƒãƒ£ </string> @@ -792,6 +813,9 @@ support@secondlife.com ã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。 <string name="symbolic folder link"> フォルダã®ãƒªãƒ³ã‚¯ </string> + <string name="settings blob"> + è¨å®š + </string> <string name="mesh"> メッシュ </string> @@ -1122,6 +1146,9 @@ support@secondlife.com ã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。 <string name="ForceSitAvatar"> ã‚¢ãƒã‚¿ãƒ¼ã‚’強制的ã«åº§ã‚‰ã›ã‚‹ </string> + <string name="ChangeEnvSettings"> + 自然環境ã®è¨å®šã‚’変更ã™ã‚‹ + </string> <string name="NotConnected"> 接続ã•れã¦ã„ã¾ã›ã‚“ </string> @@ -1273,6 +1300,9 @@ support@secondlife.com ã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。 <string name="tattoo"> タトゥ </string> + <string name="universal"> + ユニãƒãƒ¼ã‚µãƒ« + </string> <string name="physics"> 物ç†ä½œç”¨ </string> @@ -1315,6 +1345,9 @@ support@secondlife.com ã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。 <string name="tattoo_not_worn"> タトゥー未ç€ç”¨ </string> + <string name="universal_not_worn"> + ユニãƒãƒ¼ã‚µãƒ«ãªã— + </string> <string name="physics_not_worn"> 物ç†ä½œç”¨ãªã— </string> @@ -1366,6 +1399,9 @@ support@secondlife.com ã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。 <string name="create_new_tattoo"> æ–°ã—ã„ã‚¿ãƒˆã‚¥ã‚’ä½œæˆ </string> + <string name="create_new_universal"> + æ–°ã—ã„ユニãƒãƒ¼ã‚µãƒ«ã‚’ä½œæˆ + </string> <string name="create_new_physics"> æ–°ã—ã„物ç†ä½œç”¨ã‚’ä½œæˆ </string> @@ -1608,11 +1644,14 @@ support@secondlife.com ã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。 <string name="MarketplaceUpdating"> アップデートä¸... </string> + <string name="UploadFeeInfo"> + 料金ã¯ã‚µãƒ–スクリプションã®ãƒ¬ãƒ™ãƒ«ã«ã‚ˆã‚Šç•°ãªã‚Šã¾ã™ã€‚レベルãŒé«˜ã„ã»ã©ã€æ–™é‡‘ãŒä¸‹ãŒã‚Šã¾ã™ã€‚[https://secondlife.com/my/account/membership.php? 詳細] + </string> <string name="Open landmarks"> - ランドマークを開ã + オープン ランドマーク </string> <string name="Unconstrained"> - éžæ‹˜æŸ + アンコンストレインド(制約ãªã—) </string> <string name="no_transfer" value=" (å†è²©ãƒ»ãƒ—レゼントä¸å¯ï¼‰"/> <string name="no_modify" value=" (編集ä¸å¯ï¼‰"/> @@ -2512,6 +2551,27 @@ support@secondlife.com ã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。 <string name="RegionSettings"> リージョン(地域)ã®è¨å®š </string> + <string name="NoEnvironmentSettings"> + ã“ã®ãƒªãƒ¼ã‚¸ãƒ§ãƒ³ã¯ç’°å¢ƒè¨å®šã‚’サãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã›ã‚“。 + </string> + <string name="EnvironmentSun"> + 太陽 + </string> + <string name="EnvironmentMoon"> + 月 + </string> + <string name="EnvironmentBloom"> + 花 + </string> + <string name="EnvironmentCloudNoise"> + 雲ã®éŸ³ + </string> + <string name="EnvironmentNormalMap"> + ノーマル・マップ + </string> + <string name="EnvironmentTransparent"> + Transparent + </string> <string name="ClassifiedClicksTxt"> クリック数: [TELEPORT] テレãƒãƒ¼ãƒˆã€ [MAP] 地図〠[PROFILE] プãƒãƒ•ィール </string> @@ -4728,6 +4788,9 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンãƒãƒ¼ãƒ‰ã—ã¦ãã ã <string name="New Tattoo"> æ–°ã—ã„タトゥ </string> + <string name="New Universal"> + æ–°ã—ã„ユニãƒãƒ¼ã‚µãƒ« + </string> <string name="New Physics"> æ–°è¦ã®ç‰©ç†ä½œç”¨ </string> @@ -4854,6 +4917,15 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンãƒãƒ¼ãƒ‰ã—ã¦ãã ã <string name="Female - Wow"> 女性 - Wow </string> + <string name="New Daycycle"> + æ–°ã—ã„デイサイクル + </string> + <string name="New Water"> + æ–°ã—ã„æ°´ + </string> + <string name="New Sky"> + æ–°ã—ã„空 + </string> <string name="/bow"> /ãŠã˜ãŽã™ã‚‹ </string> @@ -5026,6 +5098,15 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンãƒãƒ¼ãƒ‰ã—ã¦ãã ã <string name="Chat" value=" ãƒãƒ£ãƒƒãƒˆï¼š"> ãƒãƒ£ãƒƒãƒˆ </string> + <string name="BaseMembership"> + ベース + </string> + <string name="PremiumMembership"> + プレミアム+ </string> + <string name="Premium PlusMembership"> + プレミアムプラス + </string> <string name="DeleteItems"> é¸æŠžã—ãŸã‚¢ã‚¤ãƒ†ãƒ を削除ã—ã¾ã™ã‹ </string> @@ -5382,6 +5463,12 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンãƒãƒ¼ãƒ‰ã—ã¦ãã ã <string name="BeaconMedia"> ãƒ¡ãƒ‡ã‚£ã‚¢ãƒ“ãƒ¼ã‚³ãƒ³ï¼ˆç™½ï¼‰ã‚’è¡¨ç¤ºä¸ </string> + <string name="BeaconSun"> + å¤ªé™½ã®æ–¹è§’ãƒ“ãƒ¼ã‚³ãƒ³ï¼ˆã‚ªãƒ¬ãƒ³ã‚¸ï¼‰ã‚’è¡¨ç¤ºä¸ + </string> + <string name="BeaconMoon"> + æœˆã®æ–¹è§’ãƒ“ãƒ¼ã‚³ãƒ³ï¼ˆç´«ï¼‰ã‚’è¡¨ç¤ºä¸ + </string> <string name="ParticleHiding"> パーティクルをéžè¡¨ç¤º </string> @@ -5409,6 +5496,12 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンãƒãƒ¼ãƒ‰ã—ã¦ãã ã <string name="Command_Destinations_Label"> 行ãå…ˆ </string> + <string name="Command_Environments_Label"> + ç§ã®ç’°å¢ƒ + </string> + <string name="Command_Facebook_Label"> + Facebook + </string> <string name="Command_Flickr_Label"> Flickr </string> @@ -5502,6 +5595,12 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンãƒãƒ¼ãƒ‰ã—ã¦ãã ã <string name="Command_Destinations_Tooltip"> 行ã£ã¦ã¿ãŸã„å ´æ‰€ </string> + <string name="Command_Environments_Tooltip"> + ç§ã®ç’°å¢ƒ + </string> + <string name="Command_Facebook_Tooltip"> + Facebook ã¸æŠ•ç¨¿ + </string> <string name="Command_Flickr_Tooltip"> Flickr ã«ã‚¢ãƒƒãƒ—ãƒãƒ¼ãƒ‰ </string> @@ -5697,6 +5796,12 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンãƒãƒ¼ãƒ‰ã—ã¦ãã ã <string name="ExperiencePermission12"> ä½“é¨“ã®æ¨©é™ã‚’è‡ªå‹•çš„ã«æ‰¿è«¾ </string> + <string name="ExperiencePermission16"> + ã‚ãªãŸã®ã‚¢ãƒã‚¿ãƒ¼ã‚’強制的ã«åº§ã‚‰ã›ã‚‹ + </string> + <string name="ExperiencePermission17"> + 自然環境ã®è¨å®šã‚’変更ã™ã‚‹ + </string> <string name="ExperiencePermissionShortUnknown"> ãŒä¸æ˜Žãªæ“作を実行ã—ã¾ã—ãŸï¼š [Permission] </string> @@ -5721,6 +5826,12 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンãƒãƒ¼ãƒ‰ã—ã¦ãã ã <string name="ExperiencePermissionShort12"> æ¨©é™ </string> + <string name="ExperiencePermissionShort16"> + Sit + </string> + <string name="ExperiencePermissionShort17"> + 環境 + </string> <string name="logging_calls_disabled_log_empty"> 会話ã¯ãƒã‚°ã«è¨˜éŒ²ã•れã¦ã„ã¾ã›ã‚“。ãƒã‚°ã®è¨˜éŒ²ã‚’é–‹å§‹ã™ã‚‹ã«ã¯ã€ã€Œç’°å¢ƒè¨å®šã€>「ãƒãƒ£ãƒƒãƒˆã€ã§ã€Œä¿å˜: ãƒã‚°ã®ã¿ã€ã¾ãŸã¯ã€Œä¿å˜: ãƒã‚°ã¨ä¼šè©±ã®ãƒ†ã‚ストã€ã‚’é¸æŠžã—ã¾ã™ã€‚ </string> diff --git a/indra/newview/skins/default/xui/pl/floater_buy_currency.xml b/indra/newview/skins/default/xui/pl/floater_buy_currency.xml index 72167e0d3c..a1d703a15a 100644 --- a/indra/newview/skins/default/xui/pl/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/pl/floater_buy_currency.xml @@ -50,8 +50,7 @@ </text> <button label="Kup teraz" name="buy_btn" /> <button label="Anuluj" name="cancel_btn" /> - <text name="info_cannot_buy"> + <floater.string name="info_cannot_buy"> Nie można kupić - </text> - <button label="Odwiedź stronÄ™ WWW" name="error_web" /> + </floater.string> </floater> diff --git a/indra/newview/skins/default/xui/pl/floater_delete_env_preset.xml b/indra/newview/skins/default/xui/pl/floater_delete_env_preset.xml deleted file mode 100644 index fc750715c6..0000000000 --- a/indra/newview/skins/default/xui/pl/floater_delete_env_preset.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<floater name="Delete Env Preset" title="USUŃ UST. OTOCZENIA"> - <string name="title_water"> - UsuÅ„ Ustawienie wody - </string> - <string name="title_sky"> - UsuÅ„ Ustawienie nieba - </string> - <string name="title_day_cycle"> - UsuÅ„ cykl dnia - </string> - <string name="label_water"> - Wybierz: - </string> - <string name="label_sky"> - Wybierz: - </string> - <string name="label_day_cycle"> - Cykl dnia: - </string> - <string name="msg_confirm_deletion"> - Masz absolutnÄ… pewność, że chcesz usunąć wybrane Ustawienie? - </string> - <string name="msg_sky_is_referenced"> - Nie można usunąć Ustawienia odwoÅ‚ujÄ…cego siÄ™ do jakiegoÅ› cyklu dnia. - </string> - <string name="combo_label"> - -Wybierz Ustawienie- - </string> - <text name="label"> - Wybierz: - </text> - <button label="UsuÅ„" name="delete" /> - <button label="Anuluj" name="cancel" /> -</floater> diff --git a/indra/newview/skins/default/xui/pl/floater_merchant_outbox.xml b/indra/newview/skins/default/xui/pl/floater_merchant_outbox.xml deleted file mode 100644 index 9cc88ba288..0000000000 --- a/indra/newview/skins/default/xui/pl/floater_merchant_outbox.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<floater name="floater_merchant_outbox" title="SKRZYNKA NADAWCZA KUPCA"> - <string name="OutboxFolderCountN"> - Folderów: [NUM] - </string> - <string name="OutboxImporting"> - WysyÅ‚anie folderów... - </string> - <string name="OutboxInitializing"> - Inicjalizacja... - </string> - <panel name="panel_1"> - <panel name="panel_2"> - <panel name="outbox_inventory_placeholder_panel"> - <text name="outbox_inventory_placeholder_title"> - Åadowanie... - </text> - </panel> - </panel> - <panel name="panel_3"> - <panel name="outbox_generic_drag_target"> - <text name="text_1"> - PrzeciÄ…gaj tu przedmioty by tworzyć foldery - </text> - </panel> - <button label="WyÅ›lij na Marketplace" tool_tip="WyÅ›lij na witrynÄ™ Marketplace" name="outbox_import_btn" /> - </panel> - </panel> -</floater> diff --git a/indra/newview/skins/default/xui/pl/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/pl/floater_texture_ctrl.xml index 8ac158b462..2425213160 100644 --- a/indra/newview/skins/default/xui/pl/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/pl/floater_texture_ctrl.xml @@ -9,13 +9,10 @@ <text name="Multiple"> Wiele tekstur </text> - <radio_group name="mode_selection"> - <radio_item label="Szafa" name="inventory" /> - <radio_item label="Lokalna" name="local" /> - </radio_group> - <text name="unknown"> - Rozm.: [DIMENSIONS] - </text> + <combo_box name="mode_selection"> + <combo_box.item label="Szafa" name="inventory" /> + <combo_box.item label="Lokalna" name="local" /> + </combo_box> <button label="DomyÅ›lna" label_selected="DomyÅ›lna" name="Default" /> <button label="Pusta" label_selected="Pusta" name="Blank" /> <button label="Przezrocz." label_selected="Przezrocz." name="None" /> diff --git a/indra/newview/skins/default/xui/pl/menu_cof_attachment.xml b/indra/newview/skins/default/xui/pl/menu_cof_attachment.xml index add2d59998..f5fbf5c0c1 100644 --- a/indra/newview/skins/default/xui/pl/menu_cof_attachment.xml +++ b/indra/newview/skins/default/xui/pl/menu_cof_attachment.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <context_menu name="COF Attachment"> + <menu_item_call label="Dotknij" name="touch_attach" /> + <menu_item_call label="Edytuj" name="edit_item" /> <menu_item_call label="Odłącz" name="detach" /> </context_menu> diff --git a/indra/newview/skins/default/xui/pl/menu_inventory.xml b/indra/newview/skins/default/xui/pl/menu_inventory.xml index 0edb680b16..1aeffc58b7 100644 --- a/indra/newview/skins/default/xui/pl/menu_inventory.xml +++ b/indra/newview/skins/default/xui/pl/menu_inventory.xml @@ -85,6 +85,7 @@ <menu_item_call label="Załóż" name="Wearable And Object Wear" /> <menu label="Dołącz do" name="Attach To" /> <menu label="Dołącz do HUD-a" name="Attach To HUD" /> + <menu_item_call label="Dotknij" name="Attachment Touch" /> <menu_item_call label="Edytuj" name="Wearable Edit" /> <menu_item_call label="Dodaj/dołącz" name="Wearable Add" /> <menu_item_call label="Zdejmij" name="Take Off" /> diff --git a/indra/newview/skins/default/xui/pl/menu_viewer.xml b/indra/newview/skins/default/xui/pl/menu_viewer.xml index e6ad1faee6..4d03e7c780 100644 --- a/indra/newview/skins/default/xui/pl/menu_viewer.xml +++ b/indra/newview/skins/default/xui/pl/menu_viewer.xml @@ -84,17 +84,14 @@ <menu name="Water Presets" label="Ustawienia wody"> <menu_item_call label="Nowe Ustawienie..." name="new_water_preset" /> <menu_item_call label="Edytuj Ustawienie..." name="edit_water_preset" /> - <menu_item_call label="UsuÅ„ Ustawienie..." name="delete_water_preset" /> </menu> <menu name="Sky Presets" label="Ustawienia nieba"> <menu_item_call label="Nowe Ustawienie..." name="new_sky_preset" /> <menu_item_call label="Edytuj Ustawienie..." name="edit_sky_preset" /> - <menu_item_call label="UsuÅ„ Ustawienie..." name="delete_sky_preset" /> </menu> <menu name="Day Presets" label="Ustawienia pory dnia"> <menu_item_call label="Nowe Ustawienie..." name="new_day_preset" /> <menu_item_call label="Edytuj Ustawienie..." name="edit_day_preset" /> - <menu_item_call label="UsuÅ„ Ustawienie..." name="delete_day_preset" /> </menu> </menu> </menu> @@ -159,7 +156,7 @@ <menu_item_call label="DźwiÄ™k ([COST]L$)..." name="Upload Sound" /> <menu_item_call label="AnimacjÄ™ ([COST]L$)..." name="Upload Animation" /> <menu_item_call label="Model meszowy..." name="Upload Model" /> - <menu_item_call label="Zbiór wielu plików ([COST]L$ per file)..." name="Bulk Upload" /> + <menu_item_call label="Zbiór wielu plików..." name="Bulk Upload" /> </menu> <menu_item_call label="Cofnij" name="Undo" /> <menu_item_call label="Ponów" name="Redo" /> diff --git a/indra/newview/skins/default/xui/pl/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/pl/menu_wearable_list_item.xml index 260b86cb07..b0ef8e4393 100644 --- a/indra/newview/skins/default/xui/pl/menu_wearable_list_item.xml +++ b/indra/newview/skins/default/xui/pl/menu_wearable_list_item.xml @@ -3,6 +3,7 @@ <menu_item_call label="ZastÄ…p" name="wear_replace" /> <menu_item_call label="Załóż" name="wear_wear" /> <menu_item_call label="Dodaj" name="wear_add" /> + <menu_item_call label="Dotknij" name="touch" /> <menu_item_call label="Zdejmij/Odłącz" name="take_off_or_detach" /> <menu_item_call label="Odłącz" name="detach" /> <context_menu label="Dołącz do" name="wearable_attach_to" /> diff --git a/indra/newview/skins/default/xui/pl/menu_wearing_gear.xml b/indra/newview/skins/default/xui/pl/menu_wearing_gear.xml index 73138b2cf7..c129448adc 100644 --- a/indra/newview/skins/default/xui/pl/menu_wearing_gear.xml +++ b/indra/newview/skins/default/xui/pl/menu_wearing_gear.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <toggleable_menu name="Gear Wearing"> - <menu_item_call label="Edytuj strój" name="edit" /> + <menu_item_call label="Dotknij" name="touch"/> + <menu_item_call label="Edytuj" name="edit_item"/> + <menu_item_call label="Edytuj strój" name="edit_outfit" /> <menu_item_call label="Zdejmij" name="takeoff" /> <menu_item_call label="Kopiuj listÄ™ przedmiotów stroju do schowka" name="copy" /> </toggleable_menu> diff --git a/indra/newview/skins/default/xui/pl/menu_wearing_tab.xml b/indra/newview/skins/default/xui/pl/menu_wearing_tab.xml index 09c82da427..188f77a3bb 100644 --- a/indra/newview/skins/default/xui/pl/menu_wearing_tab.xml +++ b/indra/newview/skins/default/xui/pl/menu_wearing_tab.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <context_menu name="Wearing"> + <menu_item_call label="Dotknij" name="touch_attach"/> + <menu_item_call label="Edytuj" name="edit_item"/> <menu_item_call label="Zdejmij" name="take_off" /> <menu_item_call label="Odłącz" name="detach" /> - <menu_item_call label="Edytuj strój" name="edit" /> + <menu_item_call label="Edytuj strój" name="edit_outfit" /> </context_menu> diff --git a/indra/newview/skins/default/xui/pl/panel_outbox_inventory.xml b/indra/newview/skins/default/xui/pl/panel_outbox_inventory.xml deleted file mode 100644 index 01d0455215..0000000000 --- a/indra/newview/skins/default/xui/pl/panel_outbox_inventory.xml +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<inventory_panel name="inventory_outbox" tool_tip="PrzeciÄ…gnij i upuść tutaj przedmioty, aby przygotować je do sprzedaży na Twojej witrynie Marketplace" /> diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/pl/panel_preferences_graphics1.xml index 738805d800..e8c400dbd1 100644 --- a/indra/newview/skins/default/xui/pl/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/pl/panel_preferences_graphics1.xml @@ -28,7 +28,6 @@ <check_box label="Przezroczysta woda" name="TransparentWater" /> <check_box label="Mapping wypukÅ‚oÅ›ci i poÅ‚ysk" name="BumpShiny" /> <check_box label="Lokalne Å›wiatÅ‚a" name="LocalLights" /> - <check_box label="Podstawowe shadery" name="BasicShaders" tool_tip="Wyłączenie tej opcji może naprawić błędy niektórych sterowników graficznych" /> <check_box label="Shadery atmosfery" name="WindLightUseAtmosShaders" /> <check_box label="Zaawansowane oÅ›wietlenie" name="UseLightShaders" /> <check_box label="Okluzja otoczenia" name="UseSSAO" /> diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml index 9aece1221d..91fea234d2 100644 --- a/indra/newview/skins/default/xui/pl/strings.xml +++ b/indra/newview/skins/default/xui/pl/strings.xml @@ -710,6 +710,9 @@ Spróbuj zalogować siÄ™ ponownie za minutÄ™. <string name="mesh"> mesz </string> + <string name="settings"> + ustawieÅ„ + </string> <string name="AvatarEditingAppearance"> (Edycja wyglÄ…du) </string> diff --git a/indra/newview/skins/default/xui/pt/floater_about_land.xml b/indra/newview/skins/default/xui/pt/floater_about_land.xml index ef71baa0b6..d7741fa902 100644 --- a/indra/newview/skins/default/xui/pt/floater_about_land.xml +++ b/indra/newview/skins/default/xui/pt/floater_about_land.xml @@ -362,11 +362,11 @@ Apenas lotes maiores podem ser listados na busca. Foto: </text> <texture_picker label="" name="snapshot_ctrl" tool_tip="Clique para escolher uma imagem"/> - <text name="allow_see_label"> + <text name="allow_see_label" top="170"> Avatares em outros lotes podem ver e conversar com avatares neste lote </text> - <check_box label="Ver avatares" name="SeeAvatarsCheck" tool_tip="Permite que os avatares em outros lotes vejam e batam papo com avatares neste lote. Você poderá vê-los e conversar com eles."/> - <text name="landing_point"> + <check_box label="Ver avatares" name="SeeAvatarsCheck" top="170" tool_tip="Permite que os avatares em outros lotes vejam e batam papo com avatares neste lote. Você poderá vê-los e conversar com eles."/> + <text name="landing_point" width="225"> Ponto de Aterrissagem: [LANDING] </text> <button label="Definir" label_selected="Definir" name="Set" tool_tip="Define o ponto de aterrissagem de visitantes. Define para o ponto em que seu avatar se encontra neste lote."/> @@ -479,5 +479,6 @@ MÃdia: </panel> </panel> <panel label="EXPERIÊNCIAS" name="land_experiences_panel"/> + <panel label="AMBIENTE" name="land_environment_panel"/> </tab_container> </floater> diff --git a/indra/newview/skins/default/xui/pt/floater_adjust_environment.xml b/indra/newview/skins/default/xui/pt/floater_adjust_environment.xml new file mode 100644 index 0000000000..4e2e96c54b --- /dev/null +++ b/indra/newview/skins/default/xui/pt/floater_adjust_environment.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_adjust_snapshot" title="Iluminação pessoal"> + <layout_stack name="outer_stack"> + <layout_panel name="env_controls"> + <layout_stack name="settings_stack"> + <layout_panel> + <button label="Redefinir" name="btn_reset" tool_tip="Feche e redefina e Compartilhe o Ambiente"/> + <text name="cloud_map_label"> + Imagem de nuvem: + </text> + </layout_panel> + <layout_panel> + <text name="label"> + Dom: + </text> + <check_box label="Exibir baliza" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <check_box label="Exibir baliza" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/pt/floater_beacons.xml b/indra/newview/skins/default/xui/pt/floater_beacons.xml index f8ae3cd2d8..bcd6ae0400 100644 --- a/indra/newview/skins/default/xui/pt/floater_beacons.xml +++ b/indra/newview/skins/default/xui/pt/floater_beacons.xml @@ -18,5 +18,7 @@ <check_box label="Fontes de som" name="sounds"/> <check_box label="Fontes de partÃculas" name="particles"/> <check_box label="Fontes de mÃdia" name="moapbeacon"/> + <check_box label="Dom" name="sun"/> + <check_box label="Lua" name="moon"/> </panel> </floater> diff --git a/indra/newview/skins/default/xui/pt/floater_bulk_perms.xml b/indra/newview/skins/default/xui/pt/floater_bulk_perms.xml index a31b049345..554865b3a6 100644 --- a/indra/newview/skins/default/xui/pt/floater_bulk_perms.xml +++ b/indra/newview/skins/default/xui/pt/floater_bulk_perms.xml @@ -30,6 +30,7 @@ <icon name="icon_sound" tool_tip="Sons"/> <check_box label="Texturas" name="check_texture"/> <icon name="icon_texture" tool_tip="Texturas"/> + <icon name="icon_setting" tool_tip="Configurações de ambiente"/> <button label="Tudo" label_selected="Todas" name="check_all"/> <button label="Limpar" label_selected="Nenhuma" name="check_none"/> <text name="newperms"> diff --git a/indra/newview/skins/default/xui/pt/floater_buy_currency.xml b/indra/newview/skins/default/xui/pt/floater_buy_currency.xml index 513400954b..c740b90472 100644 --- a/indra/newview/skins/default/xui/pt/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/pt/floater_buy_currency.xml @@ -59,8 +59,7 @@ </text> <button label="Comprar já!" name="buy_btn"/> <button label="Fechar" name="cancel_btn"/> - <text name="info_cannot_buy" font="SansSerifBig"> + <floater.string name="info_cannot_buy"> Transação incompleta - </text> - <button label="Prosseguir para a web" name="error_web"/> + </floater.string> </floater> diff --git a/indra/newview/skins/default/xui/pt/floater_delete_env_preset.xml b/indra/newview/skins/default/xui/pt/floater_delete_env_preset.xml deleted file mode 100644 index 2434f67d6c..0000000000 --- a/indra/newview/skins/default/xui/pt/floater_delete_env_preset.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<floater name="Delete Env Preset" title="EXCLUIR PREDEFINIÇÃO ENV"> - <string name="title_water"> - Excluir predefinição da água - </string> - <string name="title_sky"> - Excluir predefinição de céu - </string> - <string name="title_day_cycle"> - Excluir ciclo de dias - </string> - <string name="label_water"> - Predefinição: - </string> - <string name="label_sky"> - Predefinição: - </string> - <string name="label_day_cycle"> - Ciclos de dias: - </string> - <string name="msg_confirm_deletion"> - Tem certeza de que quer excluir a predefinição selecionada? - </string> - <string name="msg_sky_is_referenced"> - Não é possÃvel remover uma predefinição que está referenciada por algum(ns) ciclo(s) de dias. - </string> - <string name="combo_label"> - -Selecionar uma prefefinição- - </string> - <text name="label"> - Predefinição: - </text> - <button label="Excluir" name="delete"/> - <button label="Cancelar" name="cancel"/> -</floater> diff --git a/indra/newview/skins/default/xui/pt/floater_edit_ext_day_cycle.xml b/indra/newview/skins/default/xui/pt/floater_edit_ext_day_cycle.xml new file mode 100644 index 0000000000..f58af73e55 --- /dev/null +++ b/indra/newview/skins/default/xui/pt/floater_edit_ext_day_cycle.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_edit_extdaycycle" title="Editar ciclo de dias"> + <string name="title_new"> + Criar um ciclo de dias + </string> + <string name="title_edit"> + Editar ciclo de dia + </string> + <string name="hint_new"> + Nomeie o seu ciclo de dias, ajustar os controles para criá-lo e clique em “Salvarâ€. + </string> + <string name="hint_edit"> + Editar o seu ciclo de dias, ajustar os controles para criá-lo e clique em “Salvarâ€. + </string> + <string name="time_label"> + ([HH]:[MM]) + </string> + <string name="sky_track_label"> + Céu [ALT] + </string> + <string name="sky_label"> + Céu + </string> + <string name="water_label"> + Ãgua + </string> + <string name="commit_parcel"> + Aplicar ao lote + </string> + <string name="commit_region"> + Aplicar para a região + </string> + <layout_stack name="outer_stack"> + <layout_panel name="name_and_import"> + <text name="label"> + Nome do ciclo de dias: + </text> + <button label="Importar" name="btn_import" tool_tip="Importar configurações do legado do disco."/> + </layout_panel> + <layout_panel name="content"> + <layout_stack name="content_stack"> + <layout_panel name="timeline_track_selection"> + <panel name="timeline_layers"> + <button label="Céu 4" name="sky4_track"/> + <button label="Céu 3" name="sky3_track"/> + <button label="Céu 2" name="sky2_track"/> + <button label="A nÃvel do chão" name="sky1_track"/> + <button label="Ãgua" name="water_track"/> + </panel> + <panel name="timeline"> + <text name="p0" value="0%[DSC]"/> + <text name="p1" value="25%[DSC]"/> + <text name="p2" value="50%[DSC]"/> + <text name="p3" value="75%[DSC]"/> + <text name="p4" value="100%[DSC]"/> + <multi_slider initial_value="0" name="WLTimeSlider"/> + <multi_slider initial_value="0" name="WLDayCycleFrames"/> + <text name="current_time" value="[PRCNT]%[DSC]"/> + <layout_stack> + <layout_panel> + <button label="Clonar Rastreio de" name="copy_track"/> + <button label="Carregar rastreio de" name="load_track"/> + <button label="Limpar rastreio" name="clear_track"/> + </layout_panel> + <layout_panel> + <layout_stack name="progress_control"> + <layout_panel name="skip_back"> + <button name="skip_back_btn" tool_tip="Passo para trás"/> + </layout_panel> + <layout_panel name="skip_forward"> + <button name="skip_forward_btn" tool_tip="Passo para frente"/> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel> + <button label="Adicionar [FRAME]" name="add_frame"/> + <button label="Carregar [FRAME]" name="btn_load_frame"/> + <button label="Excluir [FRAME]" name="delete_frame"/> + </layout_panel> + </layout_stack> + </panel> + </layout_panel> + <layout_panel name="frame_edit_controls"> + <text name="icn_lock_edit"> + Selecionar uma estrutura chave da linha do tempo acima para editar as configurações. + </text> + </layout_panel> + <layout_panel name="frame_settings_water"> + <tab_container name="water_tabs"> + <panel label="Ãgua" name="water_panel"/> + </tab_container> + </layout_panel> + <layout_panel name="frame_settings_sky"> + <tab_container name="sky_tabs"> + <panel label="Atmosfera e Claridade" name="atmosphere_panel"/> + <panel label="Nuvens" name="clouds_panel"/> + <panel label="Sol e Lua" name="moon_panel"/> + </tab_container> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel name="buttons"> + <button label="Salvar" name="save_btn"/> + <button label="Cancelar" name="cancel_btn"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/pt/floater_fixedenvironment.xml b/indra/newview/skins/default/xui/pt/floater_fixedenvironment.xml new file mode 100644 index 0000000000..c969aac74e --- /dev/null +++ b/indra/newview/skins/default/xui/pt/floater_fixedenvironment.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="Fixed Environment" title="Ambiente consertado"> + <string name="edit_sky"> + Editar céu: + </string> + <string name="edit_water"> + Editar água: + </string> + <layout_stack name="floater_stack"> + <layout_panel name="info_panel"> + <button label="Carregar" name="btn_load" tool_tip="Carregar as configurações de inventário"/> + <button label="Importar" name="btn_import" tool_tip="Importar configurações do legado do disco."/> + </layout_panel> + <layout_panel name="button_panel"> + <layout_stack name="button_bar_ls"> + <layout_panel name="save_btn_lp"> + <button label="Salvar" name="btn_commit"/> + </layout_panel> + <layout_panel name="revert_btn_lp"> + <button label="Cancelar" name="btn_cancel" tool_tip="Voltar à última versão salva"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/pt/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/pt/floater_inventory_view_finder.xml index 3f66fd07b9..c50d7dcda0 100644 --- a/indra/newview/skins/default/xui/pt/floater_inventory_view_finder.xml +++ b/indra/newview/skins/default/xui/pt/floater_inventory_view_finder.xml @@ -12,6 +12,7 @@ <check_box label="Sons" name="check_sound"/> <check_box label="Texturas" name="check_texture"/> <check_box label="Fotos" name="check_snapshot"/> + <check_box label="Configurações" name="check_settings"/> <button label="Tudo" label_selected="Tudo" name="All"/> <button label="Nenhum" label_selected="Nenhum" name="None"/> <check_box label="Sempre mostrar as pastas" name="check_show_empty"/> diff --git a/indra/newview/skins/default/xui/pt/floater_merchant_outbox.xml b/indra/newview/skins/default/xui/pt/floater_merchant_outbox.xml deleted file mode 100644 index 3beada1fc0..0000000000 --- a/indra/newview/skins/default/xui/pt/floater_merchant_outbox.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="floater_merchant_outbox" title="CAIXA DE SAÃDA DO LOJISTA"> - <string name="OutboxFolderCount1"> - 1 pasta - </string> - <string name="OutboxFolderCountN"> - [NUM] pasta(s) - </string> - <string name="OutboxImporting"> - Enviando pastas... - </string> - <string name="OutboxInitializing"> - Iniciando... - </string> - <panel label="" name="panel_1"> - <panel name="panel_2"> - <panel name="outbox_inventory_placeholder_panel"> - <text name="outbox_inventory_placeholder_title"> - Carregando... - </text> - </panel> - </panel> - <panel name="panel_3"> - <panel name="outbox_generic_drag_target"> - <text name="text_1"> - Arraste itens para cá para criar pastas - </text> - </panel> - <button label="Enviar para Mercado" name="outbox_import_btn" tool_tip="Enviar para a frente da minha loja do mercado"/> - </panel> - </panel> -</floater> diff --git a/indra/newview/skins/default/xui/pt/floater_my_environments.xml b/indra/newview/skins/default/xui/pt/floater_my_environments.xml new file mode 100644 index 0000000000..71c1a33f58 --- /dev/null +++ b/indra/newview/skins/default/xui/pt/floater_my_environments.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater label="Lugares" name="my_environments" title="MEUS AMBIENTES"> + <layout_stack> + <layout_panel label="Filtros" name="filter_panel"> + <check_box label="Dias" name="chk_days"/> + <check_box label="Céus" name="chk_skies"/> + <check_box label="Ãgua" name="chk_water"/> + <filter_editor label="Filtrar Ambientes" name="flt_search"/> + </layout_panel> + <layout_panel label="Ambientes" name="list_panel"> + <panel label="pnl_inv_wrap" name="pnl_inv_wrap"/> + </layout_panel> + <layout_panel> + <check_box initial_value="false" label="Exibir todas as pastas" name="chk_showfolders"/> + </layout_panel> + <layout_panel name="pnl_control"> + <panel label="bottom_panel" name="pnl_bottom"> + <menu_button name="btn_gear" tool_tip="Mais opções"/> + <menu_button name="btn_newsettings" tool_tip="Criar nova configuração"/> + <button name="btn_del" tool_tip="Remover item selecionado"/> + </panel> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/pt/floater_perms_default.xml b/indra/newview/skins/default/xui/pt/floater_perms_default.xml index 40659a353a..0b8914b4dd 100644 --- a/indra/newview/skins/default/xui/pt/floater_perms_default.xml +++ b/indra/newview/skins/default/xui/pt/floater_perms_default.xml @@ -37,6 +37,10 @@ <text name="label_12" tool_tip="Definir permissões padrão para roupas ou partes do corpo criadas"> Itens de vestuário </text> + <text name="label_13" tool_tip="Definir permissões padrão para quando as configurações do Ambiente forem criadas"> + Configurações + </text> + <check_box name="env_settings_c" value="true"/> </panel> <button label="OK" label_selected="OK" name="ok"/> <button label="Cancelar" label_selected="Cancelar" name="cancel"/> diff --git a/indra/newview/skins/default/xui/pt/floater_pick_track.xml b/indra/newview/skins/default/xui/pt/floater_pick_track.xml new file mode 100644 index 0000000000..dc09f262c0 --- /dev/null +++ b/indra/newview/skins/default/xui/pt/floater_pick_track.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="track picker" title="ESCOLHER: RASTREAR"> + <layout_stack name="adjuster"> + <layout_panel name="pnl_desc"> + <text name="select_description"> + Selecionar o céu de origem: + </text> + </layout_panel> + <layout_panel name="pnl_traks"> + <radio_group name="track_selection"> + <radio_item label="Céu4 [ALT]" name="radio_sky4" value="4"/> + <radio_item label="Céu3 [ALT]" name="radio_sky3" value="3"/> + <radio_item label="Céu2 [ALT]" name="radio_sky2" value="2"/> + <radio_item label="Chão" name="radio_sky1" value="1"/> + </radio_group> + </layout_panel> + <layout_panel name="pnl_ok_cancel"> + <button label="OK" label_selected="OK" name="btn_select"/> + <button label="Cancelar" label_selected="Cancelar" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/pt/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/pt/floater_preferences_graphics_advanced.xml index c5039267ca..bbe36e3e03 100644 --- a/indra/newview/skins/default/xui/pt/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/pt/floater_preferences_graphics_advanced.xml @@ -82,7 +82,6 @@ <check_box initial_value="true" label="Ãgua transparente" name="TransparentWater"/> <check_box initial_value="true" label="Mapeamento de relevo e brilho" name="BumpShiny"/> <check_box initial_value="true" label="Luzes locais" name="LocalLights"/> - <check_box initial_value="true" label="Sombreamento simples" name="BasicShaders" tool_tip="Desativar essa opção pode evitar o travamento de alguns drivers de placas gráficas"/> <slider label="Detalhes do terreno:" name="TerrainDetail"/> <text name="TerrainDetailText"> Baixo diff --git a/indra/newview/skins/default/xui/pt/floater_settings_picker.xml b/indra/newview/skins/default/xui/pt/floater_settings_picker.xml new file mode 100644 index 0000000000..0dc80989be --- /dev/null +++ b/indra/newview/skins/default/xui/pt/floater_settings_picker.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="settings picker" title="ESCOLHER: CONFIGURAÇÕES"> + <floater.string name="pick title"> + Escolher: + </floater.string> + <floater.string name="pick_track"> + SELECIONE RASTREIO + </floater.string> + <floater.string name="pick_settings"> + SELECIONAR CONFIGURAÇÕES + </floater.string> + <floater.string name="track_water"> + Ãgua + </floater.string> + <floater.string name="track_ground"> + Chão + </floater.string> + <floater.string name="track_sky"> + Céu[NUM] + </floater.string> + <layout_stack name="test_stack"> + <layout_panel name="inv_list"> + <filter_editor label="Filtrar texturas" name="flt_inventory_search"/> + </layout_panel> + <layout_panel name="temp"> + <button label="OK" label_selected="OK" name="btn_select"/> + <button label="Cancelar" label_selected="Cancelar" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/pt/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/pt/floater_texture_ctrl.xml index ba4ef0afde..d3eec114e2 100644 --- a/indra/newview/skins/default/xui/pt/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/pt/floater_texture_ctrl.xml @@ -9,17 +9,13 @@ <text name="Multiple"> Multiplas texturas </text> - <radio_group name="mode_selection"> - <radio_item label="Inventário" name="inventory" value="0"/> - <radio_item label="Local" name="local" value="1"/> - </radio_group> - <text name="unknown"> - Tamanho: [DIMENSÕES] - </text> + <combo_box name="mode_selection"> + <combo_box.item label="Inventário" name="inventory" value="0"/> + <combo_box.item label="Local" name="local" value="1"/> + </combo_box> <button label="Padrão" label_selected="Padrão" name="Default"/> <button label="Branco" label_selected="Branco" name="Blank"/> <button label="Nenhum" label_selected="Nenhum" name="None"/> - <check_box initial_value="true" label="Inscrever-se agora" name="apply_immediate_check"/> <text name="preview_disabled" value="Visualização desativada"/> <filter_editor label="Filtrar texturas" name="inventory search editor"/> <check_box initial_value="false" label="Exibir pastas" name="show_folders_check"/> @@ -30,6 +26,22 @@ <column label="Nome" name="unit_name"/> <column label="ID" name="unit_id_HIDDEN"/> </scroll_list> + <combo_box name="l_bake_use_texture_combo_box" tool_tip="Escolha a textura de assar"> + <combo_box.item label="Nenhum" name="None"/> + <combo_box.item label="BAKED_HEAD" name="BAKED_HEAD"/> + <combo_box.item label="BAKED_UPPER" name="BAKED_UPPER"/> + <combo_box.item label="BAKED_LOWER" name="BAKED_LOWER"/> + <combo_box.item label="BAKED_EYES" name="BAKED_EYES"/> + <combo_box.item label="BAKED_SKIRT" name="BAKED_SKIRT"/> + <combo_box.item label="BAKED_HAIR" name="BAKED_HAIR"/> + <combo_box.item label="BAKED_LEFTARM" name="BAKED_LEFTARM"/> + <combo_box.item label="BAKED_LEFTLEG" name="BAKED_LEFTLEG"/> + <combo_box.item label="BAKED_AUX1" name="BAKED_AUX1"/> + <combo_box.item label="BAKED_AUX2" name="BAKED_AUX2"/> + <combo_box.item label="BAKED_AUX3" name="BAKED_AUX3"/> + </combo_box> + <check_box initial_value="false" label="Ocultar região da mesh de base" name="hide_base_mesh_region"/> <button label="OK" label_selected="OK" name="Select"/> <button label="Cancelar" label_selected="Cancelar" name="Cancel"/> + <check_box initial_value="true" label="Inscrever-se agora" name="apply_immediate_check"/> </floater> diff --git a/indra/newview/skins/default/xui/pt/menu_cof_attachment.xml b/indra/newview/skins/default/xui/pt/menu_cof_attachment.xml index 527e3af3c9..5072b54f06 100644 --- a/indra/newview/skins/default/xui/pt/menu_cof_attachment.xml +++ b/indra/newview/skins/default/xui/pt/menu_cof_attachment.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="COF Attachment"> + <menu_item_call label="Tocar" name="touch_attach" /> + <menu_item_call label="Editar" name="edit_item" /> <menu_item_call label="Separar" name="detach"/> </context_menu> diff --git a/indra/newview/skins/default/xui/pt/menu_inventory.xml b/indra/newview/skins/default/xui/pt/menu_inventory.xml index b99ddc67d2..363ed43986 100644 --- a/indra/newview/skins/default/xui/pt/menu_inventory.xml +++ b/indra/newview/skins/default/xui/pt/menu_inventory.xml @@ -10,7 +10,6 @@ <menu_item_call label="Ativar" name="Marketplace Activate"/> <menu_item_call label="Desativar" name="Marketplace Deactivate"/> <menu_item_call label="Compartilhar" name="Share"/> - <menu_item_call label="Comprar" name="Task Buy"/> <menu_item_call label="Abrir" name="Task Open"/> <menu_item_call label="Executar" name="Task Play"/> <menu_item_call label="Propriedades" name="Task Properties"/> @@ -34,6 +33,7 @@ <menu_item_call label="Nova roupa de baixo" name="New Underpants"/> <menu_item_call label="Nova máscara alfa" name="New Alpha Mask"/> <menu_item_call label="Nova tatuagem" name="New Tattoo"/> + <menu_item_call label="Novo universal" name="New Universal"/> <menu_item_call label="Novo fÃsico" name="New Physics"/> </menu> <menu label="Nova parte do corpo" name="New Body Parts"> @@ -42,6 +42,11 @@ <menu_item_call label="Novo cabelo" name="New Hair"/> <menu_item_call label="Novos olhos" name="New Eyes"/> </menu> + <menu label="Novas configurações" name="New Settings"> + <menu_item_call label="Novo céu" name="New Sky"/> + <menu_item_call label="Nova água" name="New Water"/> + <menu_item_call label="Novo ciclo de dias" name="New Day Cycle"/> + </menu> <menu label="Usar como padrão para" name="upload_def"> <menu_item_call label="Envios de imagem" name="Image uploads"/> <menu_item_call label="Envios de som" name="Sound uploads"/> @@ -100,9 +105,12 @@ <menu_item_call label="Vestir" name="Wearable And Object Wear"/> <menu label="Anexar a" name="Attach To"/> <menu label="Anexar ao HUD" name="Attach To HUD"/> + <menu_item_call label="Tocar" name="Attachment Touch" /> <menu_item_call label="Editar" name="Wearable Edit"/> <menu_item_call label="Adicionar" name="Wearable Add"/> <menu_item_call label="Tirar" name="Take Off"/> + <menu_item_call label="Aplicar somente a mim" name="Settings Apply Local"/> + <menu_item_call label="Aplicar ao lote" name="Settings Apply Parcel"/> <menu_item_call label="Copiar para Listagens do Marketplace" name="Marketplace Copy"/> <menu_item_call label="Mover para Listagens do Marketplace" name="Marketplace Move"/> <menu_item_call label="--Sem opções--" name="--no options--"/> diff --git a/indra/newview/skins/default/xui/pt/menu_inventory_add.xml b/indra/newview/skins/default/xui/pt/menu_inventory_add.xml index 7a7ebc50af..0eaf3c7c5f 100644 --- a/indra/newview/skins/default/xui/pt/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/pt/menu_inventory_add.xml @@ -5,9 +5,7 @@ <menu_item_call label="Som (L$[COST])..." name="Upload Sound"/> <menu_item_call label="Animação (L$[COST])..." name="Upload Animation"/> <menu_item_call label="Modelar..." name="Upload Model"/> - <menu_item_call label="Assistente de modelagem..." name="Upload Model Wizard"/> - <menu_item_call label="Volume (L$[COST] per file)..." name="Bulk Upload"/> - <menu_item_call label="Autorizações de upload padrão" name="perm prefs"/> + <menu_item_call label="Volume..." name="Bulk Upload"/> </menu> <menu_item_call label="Nova pasta" name="New Folder"/> <menu_item_call label="Novo script" name="New Script"/> @@ -25,6 +23,7 @@ <menu_item_call label="Novas roupa de baixo" name="New Underpants"/> <menu_item_call label="Novo alpha" name="New Alpha"/> <menu_item_call label="Nova tatuagem" name="New Tattoo"/> + <menu_item_call label="Novo universal" name="New Universal"/> <menu_item_call label="Novo fÃsico" name="New Physics"/> </menu> <menu label="Nova parte do corpo" name="New Body Parts"> @@ -33,4 +32,9 @@ <menu_item_call label="Novo cabelo" name="New Hair"/> <menu_item_call label="Novos olhos" name="New Eyes"/> </menu> + <menu label="Novas configurações" name="New Settings"> + <menu_item_call label="Novo céu" name="New Sky"/> + <menu_item_call label="Nova água" name="New Water"/> + <menu_item_call label="Novo ciclo de dias" name="New Day Cycle"/> + </menu> </menu> diff --git a/indra/newview/skins/default/xui/pt/menu_outfit_gear.xml b/indra/newview/skins/default/xui/pt/menu_outfit_gear.xml index ccf65ae566..1de8fd939b 100644 --- a/indra/newview/skins/default/xui/pt/menu_outfit_gear.xml +++ b/indra/newview/skins/default/xui/pt/menu_outfit_gear.xml @@ -20,6 +20,7 @@ <menu_item_call label="Novo alpha" name="New Alpha"/> <menu_item_call label="Novo fÃsico" name="New Physics"/> <menu_item_call label="Nova tatuagem" name="New Tattoo"/> + <menu_item_call label="Novo universal" name="New Universal"/> </menu> <menu label="Nova parte do corpo" name="New Body Parts"> <menu_item_call label="Nova silhueta" name="New Shape"/> diff --git a/indra/newview/skins/default/xui/pt/menu_save_settings.xml b/indra/newview/skins/default/xui/pt/menu_save_settings.xml new file mode 100644 index 0000000000..9af5d01629 --- /dev/null +++ b/indra/newview/skins/default/xui/pt/menu_save_settings.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="save_settings_menu"> + <menu_item_check label="Salvar" name="save_settings"/> + <menu_item_check label="Salvar como" name="save_as_new_settings"/> + <menu_item_check label="Enviar" name="commit_changes"/> + <menu_item_check label="Aplicar somente a mim" name="apply_local"/> + <menu_item_check label="Aplicar ao lote" name="apply_parcel"/> + <menu_item_check label="Aplicar para a região" name="apply_region"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/pt/menu_settings_add.xml b/indra/newview/skins/default/xui/pt/menu_settings_add.xml new file mode 100644 index 0000000000..3bd87e6c12 --- /dev/null +++ b/indra/newview/skins/default/xui/pt/menu_settings_add.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_add"> + <menu_item_call label="Novo céu" name="New Sky"/> + <menu_item_call label="Nova água" name="New Water"/> + <menu_item_call label="Novo ciclo de dias" name="New Day Cycle"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/pt/menu_settings_gear.xml b/indra/newview/skins/default/xui/pt/menu_settings_gear.xml new file mode 100644 index 0000000000..55817b22e0 --- /dev/null +++ b/indra/newview/skins/default/xui/pt/menu_settings_gear.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_gear"> + <menu_item_call label="Editar" name="edit_settings"/> + <menu_item_call label="Aplicar somente a mim" name="Settings Apply Local"/> + <menu_item_call label="Aplicar ao lote" name="Settings Apply Parcel"/> + <menu_item_call label="Aplicar para a região" name="Settings Apply Region"/> + <menu_item_call label="Copiar" name="copy_settings"/> + <menu_item_call label="Colar" name="paste_settings"/> + <menu_item_call label="Copiar UUID" name="copy_uuid"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/pt/menu_viewer.xml b/indra/newview/skins/default/xui/pt/menu_viewer.xml index e82b7bc62a..8b144390fa 100644 --- a/indra/newview/skins/default/xui/pt/menu_viewer.xml +++ b/indra/newview/skins/default/xui/pt/menu_viewer.xml @@ -79,30 +79,15 @@ <menu_item_check label="Propriedades do lote" name="Parcel Properties"/> <menu_item_check label="Menu avançado" name="Show Advanced Menu"/> </menu> - <menu label="Dom" name="Sun"> + <menu label="Ambiente" name="Environment"> <menu_item_check label="Nascer do sol" name="Sunrise"/> <menu_item_check label="Meio-dia" name="Noon"/> <menu_item_check label="Pôr do sol" name="Sunset"/> <menu_item_check label="Meia-noite" name="Midnight"/> - <menu_item_check label="Usar as configurações da região" name="Use Region Settings"/> - </menu> - <menu label="Editor de ambientes" name="Environment Editor"> - <menu_item_call label="Configurações do ambiente..." name="Environment Settings"/> - <menu label="Predefinições da água" name="Water Presets"> - <menu_item_call label="Nova predefinição..." name="new_water_preset"/> - <menu_item_call label="Editar predefinição..." name="edit_water_preset"/> - <menu_item_call label="Excluir predefinição..." name="delete_water_preset"/> - </menu> - <menu label="Predefinições de céu" name="Sky Presets"> - <menu_item_call label="Nova predefinição..." name="new_sky_preset"/> - <menu_item_call label="Editar predefinição..." name="edit_sky_preset"/> - <menu_item_call label="Excluir predefinição..." name="delete_sky_preset"/> - </menu> - <menu label="Predefinições do dia" name="Day Presets"> - <menu_item_call label="Nova predefinição..." name="new_day_preset"/> - <menu_item_call label="Editar predefinição..." name="edit_day_preset"/> - <menu_item_call label="Excluir predefinição..." name="delete_day_preset"/> - </menu> + <menu_item_check label="Use o ambiente compartilhado" name="Use Shared Environment"/> + <menu_item_call label="Meu ambiente..." name="my_environs"/> + <menu_item_call label="Iluminação pessoal..." name="adjustment_tool"/> + <menu_item_check label="Pausar as nuvens" name="pause_clouds"/> </menu> </menu> <menu label="Construir" name="BuildTools"> @@ -323,6 +308,9 @@ <menu_item_check label="Máscaras alpha automáticas (sem adiar)" name="Automatic Alpha Masks (non-deferred)"/> <menu_item_check label="Texturas de animação" name="Animation Textures"/> <menu_item_check label="Desativar texturas" name="Disable Textures"/> + <menu_item_check label="Desativar ambiente" name="Disable Ambient"/> + <menu_item_check label="Desabilitar a luz solar" name="Disable Sunlight"/> + <menu_item_check label="Desativar Luzes locais" name="Disable Local Lights"/> <menu_item_check label="Render Attached Lights" name="Render Attached Lights"/> <menu_item_check label="Render Attached Particles" name="Render Attached Particles"/> <menu_item_check label="Objetos iridescentes" name="Hover Glow Objects"/> @@ -413,6 +401,7 @@ </menu> <menu label="Admin" name="Deprecated"> <menu label="Take Off Clothing" name="Take Off Clothing"> + <menu_item_call label="Universal" name="Universal"/> <menu_item_call label="FÃsico" name="Physics"/> </menu> <menu label="Ajuda" name="DeprecatedHelp"> diff --git a/indra/newview/skins/default/xui/pt/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/pt/menu_wearable_list_item.xml index 2487f6779f..2d16736277 100644 --- a/indra/newview/skins/default/xui/pt/menu_wearable_list_item.xml +++ b/indra/newview/skins/default/xui/pt/menu_wearable_list_item.xml @@ -3,6 +3,7 @@ <menu_item_call label="Trocar" name="wear_replace"/> <menu_item_call label="Vestir" name="wear_wear"/> <menu_item_call label="Adicionar" name="wear_add"/> + <menu_item_call label="Tocar" name="touch" /> <menu_item_call label="Tirar / Separar" name="take_off_or_detach"/> <menu_item_call label="Separar" name="detach"/> <context_menu label="Colocar em" name="wearable_attach_to"/> diff --git a/indra/newview/skins/default/xui/pt/menu_wearing_gear.xml b/indra/newview/skins/default/xui/pt/menu_wearing_gear.xml index 75dca703cb..bc24ffcdd9 100644 --- a/indra/newview/skins/default/xui/pt/menu_wearing_gear.xml +++ b/indra/newview/skins/default/xui/pt/menu_wearing_gear.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <toggleable_menu name="Gear Wearing"> - <menu_item_call label="Editar look" name="edit"/> + <menu_item_call label="Tocar" name="touch"/> + <menu_item_call label="Editar" name="edit_item"/> + <menu_item_call label="Editar look" name="edit_outfit"/> <menu_item_call label="Tirar" name="takeoff"/> <menu_item_call label="Copiar lista do look para a área de transferência" name="copy"/> </toggleable_menu> diff --git a/indra/newview/skins/default/xui/pt/menu_wearing_tab.xml b/indra/newview/skins/default/xui/pt/menu_wearing_tab.xml index 42aa386215..d00fd9ae28 100644 --- a/indra/newview/skins/default/xui/pt/menu_wearing_tab.xml +++ b/indra/newview/skins/default/xui/pt/menu_wearing_tab.xml @@ -1,8 +1,9 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="Wearing"> + <menu_item_call label="Tocar" name="touch_attach"/> <menu_item_call label="Tirar" name="take_off"/> <menu_item_call label="Tirar" name="detach"/> - <menu_item_call label="Editar look" name="edit"/> + <menu_item_call label="Editar look" name="edit_outfit"/> <menu_item_call label="Editar" name="edit_item"/> <menu_item_call label="Mostrar original" name="show_original"/> </context_menu> diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml index 530a272dbb..bd1185bdd2 100644 --- a/indra/newview/skins/default/xui/pt/notifications.xml +++ b/indra/newview/skins/default/xui/pt/notifications.xml @@ -265,6 +265,10 @@ Deseja conceder direitos de modificação para os residentes selecionados? Você quer revogar os direitos de edição para os residentes selecionados? <usetemplate name="okcancelbuttons" notext="Não" yestext="Sim"/> </notification> + <notification name="GroupNameLengthWarning"> + O nome do grupo deve conter entre [MIN_LEN] e [MAX_LEN] caracteres. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="UnableToCreateGroup"> Não foi possÃvel criar um grupo. [MESSAGE] @@ -359,7 +363,7 @@ Deseja continuar? Você não tem L$ suficientes para associar-se a este grupo. </notification> <notification name="CreateGroupCost"> - Criar este grupo custa L$100. + Criar este grupo custará L$[COST]. Grupos ser formados por mais de um membro, caso contrário serão definitivamente excluÃdos. Convite outros membros dentro de 48 horas. <usetemplate canceltext="Cancelar" name="okcancelbuttons" notext="Cancelar" yestext="Criar grupo por L$100"/> @@ -498,6 +502,9 @@ Para colocar a mÃdia em só uma face, selecione Selecionar face e clique na fac <notification name="ErrorEncodingSnapshot"> Erro ao codificar a foto. </notification> + <notification name="ErrorCannotAffordUpload"> + Você precisa de L$[COST] para fazer o upload deste item. + </notification> <notification name="ErrorPhotoCannotAfford"> Você precisa de L$ [COST] para salvar uma foto em seu inventário. Você pode comprar L$ ou salvar a foto em seu computador. </notification> @@ -1729,13 +1736,16 @@ Deseja prosseguir? <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="GroupLimitInfo"> - O limite de grupos para as contas básicas é [MAX_BASIC] e para as contas [https://secondlife.com/premium/ premium], -é [MAX_PREMIUM]. -Se você fizer downgrade de sua conta, precisará ficar abaixo do limite de grupos [MAX_BASIC] antes de entrar em mais. - -[https://secondlife.com/my/account/membership.php Faça o upgrade hoje!] + Residentes com o plano Básico podem participar de até [MAX_BASIC] grupos. +O plano Premium permite até [MAX_PREMIUM]. [https://secondlife.com/my/account/membership.php? Saiba mais ou faça um upgrade] <usetemplate name="okbutton" yestext="Fechar"/> </notification> + <notification name="GroupLimitInfoPlus"> + Residentes com o plano Básico podem participar de até [MAX_BASIC] grupos. +O plano Premium permite até [MAX_PREMIUM]. O plano Premium Plus permite até [MAX_PREMIUM_PLUS]. +[https://secondlife.com/my/account/membership.php? Saiba mais ou faça um upgrade] + <usetemplate name="okbutton" yestext="Fechar"/> + </notification> <notification name="KickUser"> Chutar este residente com qual mensagem? <form name="form"> @@ -1951,6 +1961,11 @@ Isto mudará milhares de regiões e fará o spaceserver soluçar. Ao desselecionar esta opção, você pode remover as restrições que os proprietários dos terrenos adicionaram para evitar problemas, manter a privacidade ou proteger residentes menores de idade contra conteúdo adulto. Por favor, discuta com os seus proprietários de terreno conforme necessário. <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="EstateParcelEnvironmentOverride"> + Desmarcando esta opção pode remover quaisquer ambientes personalizados que os proprietários tenham adicionado aos seus lotes.. +Por favor, discuta com os seus proprietários de terreno conforme necessário. Deseja continuar? + <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="OK"/> + </notification> <notification name="RegionEntryAccessBlocked"> A região que você está tentando visitar tem conteúdo que excede suas preferências atuais. Você pode alterar suas preferências acessando Eu > Preferências > Geral. <usetemplate name="okbutton" yestext="OK"/> @@ -2431,7 +2446,15 @@ Inclua um link para facilitar o acesso para visitantes. Teste o link na barra de Este arquivo de ciclo de dia se refere a um arquivo de céu faltando: [SKY]. </notification> <notification name="WLRegionApplyFail"> - As configurações não podem ser aplicadas à região. Talvez sair e votlar à região resolva. Motivo: [FAIL_REASON] + As configurações não puderam ser aplicadas para a região. Motivo: [FAIL_REASON] + </notification> + <notification name="WLLocalTextureDayBlock"> + Uma textura local está em uso no rastreio [TRACK], moldura #[FRAMENO] ([FRAME]%) no campo [FIELD]. +As definições não puderam ser salvas usando as texturas locais. + </notification> + <notification name="WLLocalTextureFixedBlock"> + Uma textura local está em uso no campo [FIELD]. +As definições não puderam ser salvas usando as texturas locais. </notification> <notification name="EnvCannotDeleteLastDayCycleKey"> ImpossÃvel excluir a última chave do ciclo pois um ciclo não pode ficar vazio. Modifique a última chave em vez de tentar apagá-la, depois crie uma chave nova. @@ -3279,6 +3302,22 @@ Para sua segurança, os SLurls serão bloqueados por alguns instantes. Sua voz foi silenciada pelo moderador. <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FailedToGetBenefits"> + Infelizmente, não conseguimos obter as informações de benefÃcios para esta sessão. Isto não deveria ocorrer em um ambiente de produção normal. Por favor, contate o suporte. Esta sessão não funcionará normalmente e recomendamos que você reinicie. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="BulkUploadCostConfirmation"> + Será feito o upload de [COUNT] itens, com um custo total de L$[COST]. Você deseja prosseguir com o upload? + <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Carregar"/> + </notification> + <notification name="BulkUploadNoCompatibleFiles"> + Não é possÃvel fazer o upload dos arquivos selecionados de uma vez só. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="BulkUploadIncompatibleFiles"> + Não é possÃvel fazer o upload de alguns dos arquivos selecionados de uma vez só. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="UploadCostConfirmation"> O carregamento custa L$[PRICE]. Deseja prosseguir? <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Carregar"/> @@ -4376,4 +4415,76 @@ Tente selecionar uma quantidade menor de terreno. [REASON] <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FailedToFindSettings"> + Não pode carregar as configurações para [NAME] da base de dados. + </notification> + <notification name="FailedToLoadSettingsApply"> + Não foi possÃvel aplicar aquelas configurações para o ambiente. + </notification> + <notification name="FailedToBuildSettingsDay"> + Não foi possÃvel aplicar aquelas configurações para o ambiente. + </notification> + <notification name="NoEnvironmentSettings"> + Esta Região não suporta as configurações do ambiente. + </notification> + <notification label="Salvar visual" name="SaveSettingAs"> + Salve as configurações do ambiente atual como: + <form name="form"> + <input name="message"> + [DESC] (novo) + </input> + <button name="OK" text="OK"/> + <button name="Cancel" text="Cancelar"/> + </form> + </notification> + <notification name="WLImportFail"> + Não foi possÃvel imporar as configurações do vento antigo [NAME] de +[FILE]. + +[REASONS] + </notification> + <notification name="WLParcelApplyFail"> + Não é possÃvel definir o ambiente para este lote. +Inserir ou selecionar um lote que você tem direitos para modificar. + </notification> + <notification name="SettingsUnsuported"> + As configurações não são suportadas para esta região. +Mude para uma configuração permitida para a região ou tente novamente realizar a ação. + </notification> + <notification name="SettingsConfirmLoss"> + Você está prestes a perder as alterações que você fez para este [TYPE] com o nome "[NAME]". +Tem certeza de que deseja continuar? + <usetemplate ignoretext="Tem certeza de que deseja perder as alterações?" name="okcancelignore" notext="Não" yestext="Sim"/> + </notification> + <notification name="SettingsConfirmReset"> + Você está prestes a remover todas as configurações aplicadas. +Tem certeza de que deseja continuar? + <usetemplate name="okcancelbuttons" notext="Não" yestext="Sim"/> + </notification> + <notification name="PersonalSettingsConfirmReset"> + Você está prestes a remover todas as configurações de Iluminação pessoal aplicadas. +Tem certeza de que deseja continuar? + <usetemplate name="okcancelbuttons" notext="Não" yestext="Sim"/> + </notification> + <notification name="SettingsMakeNoTrans"> + Você está prestes a importar configurações não transferÃveis para este ciclo de dias. Caso continue, transformará as configurações que você está editando não transferÃvel também. + +Esta alteração não pode ser desfeita. + +Tem certeza de que deseja continuar? + <usetemplate ignoretext="Tem certeza de que deseja tornar as configurações não transferÃvel?" name="okcancelignore" notext="Não" yestext="Sim"/> + </notification> + <notification name="NoEditFromLibrary"> + Você não pode editar as configurações diretamente da biblioteca. +Copie para o seu próprio inventário e tente novamente. + </notification> + <notification name="EnvironmentApplyFailed"> + Encontramos problemas com essas configurações. Eles não podem ser salvos ou aplicados desta vez. + </notification> + <notification name="TrackLoadFailed"> + Não foi possÃvel carregar o rastreio para [TRACK]. + </notification> + <notification name="TrackLoadMismatch"> + Não foi possÃvel carregar rastreio de [TRACK1] em [TRACK2]. + </notification> </notifications> diff --git a/indra/newview/skins/default/xui/pt/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/pt/panel_edit_tattoo.xml index f85bb3c499..f5d513e2f6 100644 --- a/indra/newview/skins/default/xui/pt/panel_edit_tattoo.xml +++ b/indra/newview/skins/default/xui/pt/panel_edit_tattoo.xml @@ -1,9 +1,11 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_tattoo_panel"> - <panel name="avatar_tattoo_color_panel"> - <texture_picker label="Tatuagem de cabeça" name="Head Tattoo" tool_tip="Clique para escolher uma foto"/> - <texture_picker label="Tatuagem superior" name="Upper Tattoo" tool_tip="Selecione uma foto"/> - <texture_picker label="Tatuagem inferior" name="Lower Tattoo" tool_tip="Selecione uma foto"/> - <color_swatch label="Cor/Tonalidade" name="Color/Tint" tool_tip="Selecionar a cor"/> - </panel> + <scroll_container name="avatar_tattoo_scroll"> + <panel name="avatar_tattoo_color_panel"> + <texture_picker label="Tatuagem na cabeça" name="Head Tattoo" tool_tip="Clique para selecionar uma imagem"/> + <texture_picker label="Tatuagem parte de cima" name="Upper Tattoo" tool_tip="Clique para selecionar uma imagem"/> + <texture_picker label="Tatuagem de baixo" name="Lower Tattoo" tool_tip="Clique para selecionar uma imagem"/> + <color_swatch label="Cor/Tonalidade" name="Color/Tint" tool_tip="Selecionar a cor"/> + </panel> + </scroll_container> </panel> diff --git a/indra/newview/skins/default/xui/pt/panel_edit_universal.xml b/indra/newview/skins/default/xui/pt/panel_edit_universal.xml new file mode 100644 index 0000000000..0bcaa36f1d --- /dev/null +++ b/indra/newview/skins/default/xui/pt/panel_edit_universal.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel name="edit_universal_panel"> + <scroll_container name="avatar_universal_scroll"> + <panel name="avatar_universal_color_panel"> + <texture_picker label="Tatuagem na cabeça" name="Head Universal Tattoo" tool_tip="Clique para selecionar uma imagem"/> + <texture_picker label="Tatuagem parte de cima" name="Upper Universal Tattoo" tool_tip="Clique para selecionar uma imagem"/> + <texture_picker label="Tatuagem de baixo" name="Lower Universal Tattoo" tool_tip="Clique para selecionar uma imagem"/> + <texture_picker label="Tatuagem de saia" name="Skirt Tattoo" tool_tip="Clique para selecionar uma imagem"/> + <texture_picker label="Tatuagem de cabelo" name="Hair Tattoo" tool_tip="Clique para selecionar uma imagem"/> + <texture_picker label="Tatuagem de olhos" name="Eyes Tattoo" tool_tip="Clique para selecionar uma imagem"/> + <texture_picker label="Tatuagem no Braço esquerdo" name="Left Arm Tattoo" tool_tip="Clique para selecionar uma imagem"/> + <texture_picker label="Tatuagem na perna esquerdo" name="Left Leg Tattoo" tool_tip="Clique para selecionar uma imagem"/> + <texture_picker label="Aux1 Tatuagem" name="Aux1 Tattoo" tool_tip="Clique para selecionar uma imagem"/> + <texture_picker label="Aux2 Tatuagem" name="Aux2 Tattoo" tool_tip="Clique para selecionar uma imagem"/> + <texture_picker label="Aux3 Tatuagem" name="Aux3 Tattoo" tool_tip="Clique para selecionar uma imagem"/> + <color_swatch label="Cor/Tonalidade" name="Color/Tint" tool_tip="Selecionar a cor"/> + </panel> + </scroll_container> +</panel> diff --git a/indra/newview/skins/default/xui/pt/panel_edit_wearable.xml b/indra/newview/skins/default/xui/pt/panel_edit_wearable.xml index 2e3e3d6305..e8d9063206 100644 --- a/indra/newview/skins/default/xui/pt/panel_edit_wearable.xml +++ b/indra/newview/skins/default/xui/pt/panel_edit_wearable.xml @@ -45,6 +45,9 @@ <string name="edit_tattoo_title"> Editando tatuagem </string> + <string name="edit_universal_title"> + Edição Universal + </string> <string name="edit_physics_title"> Editando o fÃsico </string> @@ -93,6 +96,9 @@ <string name="tattoo_desc_text"> Tatuagem: </string> + <string name="universal_desc_text"> + Universal: + </string> <string name="physics_desc_text"> FÃsico: </string> diff --git a/indra/newview/skins/default/xui/pt/panel_outbox_inventory.xml b/indra/newview/skins/default/xui/pt/panel_outbox_inventory.xml deleted file mode 100644 index 442622035a..0000000000 --- a/indra/newview/skins/default/xui/pt/panel_outbox_inventory.xml +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<outbox_inventory_panel name="inventory_outbox" tool_tip="Arraste e solte os itens aqui para prepará-los para venda na frente da sua loja"/> diff --git a/indra/newview/skins/default/xui/pt/panel_people.xml b/indra/newview/skins/default/xui/pt/panel_people.xml index fce170110e..2ef01841c5 100644 --- a/indra/newview/skins/default/xui/pt/panel_people.xml +++ b/indra/newview/skins/default/xui/pt/panel_people.xml @@ -18,7 +18,7 @@ Em busca de alguém para conversar? Procure no [secondlife:///app/worldmap Mapa- <string name="no_groups_msg" value="À procura de grupos interessantes? Tente fazer uma [secondlife:///app/search/groups Busca]."/> <string name="MiniMapToolTipMsg" value="[REGION](Clique duas vezes para abrir o mapa, shift+arraste para a visão pan)"/> <string name="AltMiniMapToolTipMsg" value="[REGION](Clique duas vezes para teletransportar, shift+arraste para a visão pan)"/> - <string name="GroupCountWithInfo" value="Você pertence a [COUNT] grupos e pode entrar em mais [REMAINING]. [secondlife:/// Quer mais?]"/> + <string name="GroupCountWithInfo" value="Você faz parte de [COUNT] grupos e pode participar de mais [REMAINING]. [secondlife:/// Aumente o seu limite]"/> <tab_container name="tabs"> <panel label="PROXIMIDADE" name="nearby_panel"> <panel label="bottom_panel" name="nearby_buttons_panel"> @@ -51,7 +51,7 @@ Em busca de alguém para conversar? Procure no [secondlife:///app/worldmap Mapa- <dnd_button name="minus_btn" tool_tip="Sair do grupo selecionado"/> </panel> <text name="groupcount"> - Você pertence a [COUNT] grupos e pode entrar em mais [REMAINING]. + Você faz parte de [COUNT] grupos e pode participar de mais [REMAINING]. </text> </panel> <panel label="RECENTE" name="recent_panel"> diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/pt/panel_preferences_graphics1.xml index a0f4ea4ed5..d387c4c869 100644 --- a/indra/newview/skins/default/xui/pt/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/pt/panel_preferences_graphics1.xml @@ -33,10 +33,10 @@ rápido </text> <check_box initial_value="true" label="Sempre renderizar amigos" name="AlwaysRenderFriends"/> <button label="Exceções..." name="RenderExceptionsButton"/> - <button label="Salvar configurações como predefinição..." name="PrefSaveButton"/> - <button label="Carregar predefinição..." name="PrefLoadButton"/> + <button label="Salvar configurações como predefinição" name="PrefSaveButton" width="235" left="5"/> + <button label="Carregar predefinição" name="PrefLoadButton" width="130" left_pad="8"/> min_val="0.125" - <button label="Excluir predefinição..." name="PrefDeleteButton"/> - <button label="Redefinir para configurações recomendadas" left="110" name="Defaults"/> + <button label="Excluir predefinição" name="PrefDeleteButton" width="122" left_pad="8"/> + <button label="Redefinir para configurações recomendadas" name="Defaults" width="255"/> <button label="Configurações avançadas..." name="AdvancedSettings"/> </panel> diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_setup.xml b/indra/newview/skins/default/xui/pt/panel_preferences_setup.xml index 03536f28c3..56fc225bc0 100644 --- a/indra/newview/skins/default/xui/pt/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/pt/panel_preferences_setup.xml @@ -35,5 +35,5 @@ <text name="Proxy Settings:"> Configurações de proxy: </text> - <button label="Ajustar configurações de proxy" label_selected="Procurar" name="set_proxy"/> + <button label="Ajustar configurações de proxy" label_selected="Procurar" name="set_proxy" width="180"/> </panel> diff --git a/indra/newview/skins/default/xui/pt/panel_region_environment.xml b/indra/newview/skins/default/xui/pt/panel_region_environment.xml index 7593c50941..f99a75d699 100644 --- a/indra/newview/skins/default/xui/pt/panel_region_environment.xml +++ b/indra/newview/skins/default/xui/pt/panel_region_environment.xml @@ -1,33 +1,116 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Ambiente" name="panel_env_info"> - <text name="water_settings_title"> - Selecionar a Ãgua e o Céu/Configurações de Ciclo de Dias que você gostaria que todos os visitantes da sua região visse. Mais informações - </text> - <radio_group name="region_settings_radio_group"> - <radio_item label="Use o padrão Second Life" name="use_sl_default_settings"/> - <radio_item label="Use as seguintes configurações" name="use_my_settings"/> - </radio_group> - <panel name="user_environment_settings"> - <text name="water_settings_title"> - Configurações da água - </text> - <combo_box name="water_settings_preset_combo"> - <combo_box.item label="-Selecionar uma prefefinição-" name="item0"/> - </combo_box> - <text name="sky_dayc_settings_title"> - Céu / Ciclo de dias - </text> - <radio_group name="sky_dayc_settings_radio_group"> - <radio_item label="Céu fixo" name="my_sky_settings"/> - <radio_item label="Ciclos de dias" name="my_dayc_settings"/> - </radio_group> - <combo_box name="sky_settings_preset_combo"> - <combo_box.item label="-Selecionar uma prefefinição-" name="item0"/> - </combo_box> - <combo_box name="dayc_settings_preset_combo"> - <combo_box.item label="-Selecionar uma prefefinição-" name="item0"/> - </combo_box> - </panel> - <button label="Aplicar" name="apply_btn"/> - <button label="Cancelar" name="cancel_btn"/> + <string name="str_label_use_default"> + Usar as configurações padrões + </string> + <string name="str_label_use_region"> + Usar as configurações da região + </string> + <string name="str_altitude_desription"> + Céu [INDEX]([ALTITUDE]m) + </string> + <string name="str_no_parcel"> + Nenhum lote está selecionado. As configurações do ambiente estão desativadas. + </string> + <string name="str_cross_region"> + As configurações do ambiente não estão disponÃveis além das fronteiras da região. + </string> + <string name="str_legacy"> + As configurações do ambiente não estão disponÃveis nesta região. + </string> + <string name="str_disallowed"> + O gerente do estado não permite alteração dos ambientes dos lotes nesta região. + </string> + <string name="str_too_small"> + O lote deve ter no mÃnimo 128 metros quadrados para suportar um ambiente. + </string> + <string name="str_empty"> + (vazio) + </string> + <string name="str_region_env"> + (região ambiente) + </string> + <layout_stack> + <layout_panel name="pnl_environment_disabled"> + <text name="txt_environment_disabled"> + ... + </text> + </layout_panel> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_current"> + <button label="[USEDEFAULT]" name="btn_usedefault"/> + <button label="Usar inventário" name="btn_select_inventory"/> + <button label="Customizar" name="btn_edit"/> + <check_box label="Os proprietários do lote podem desconsiderar o ambiente" name="chk_allow_override"/> + </layout_panel> + <layout_panel name="pnl_environment_length"> + <text name="lbl_apparent_time"> + [HH]:[MM][AP] ([PRC]%) + </text> + </layout_panel> + <layout_panel name="pnl_environment_buttons"/> + </layout_stack> + </layout_panel> + <layout_panel name="pnl_environment_altitudes"> + <panel name="pnl_alt1"> + <text name="txt_alt1"> + Céu [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt1"> + Desconhecido + </line_editor> + <settings_drop_target name="sdt_alt1" tool_tip="Arraste uma configuração do Inventário para a caixa alvo para selecionar como o céu atual."/> + </panel> + <panel name="pnl_alt2"> + <text name="txt_alt2"> + Céu [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt2"> + Desconhecido + </line_editor> + <settings_drop_target name="sdt_alt2" tool_tip="Arraste uma configuração do Inventário para a caixa alvo para selecionar como o céu atual."/> + </panel> + <panel name="pnl_alt3"> + <text name="txt_alt3"> + Céu [INDEX] + [ALTITUDE]m + </text> + <line_editor name="edt_invname_alt3"> + Desconhecido + </line_editor> + <settings_drop_target name="sdt_alt3" tool_tip="Arraste uma configuração do Inventário para a caixa alvo para selecionar como o céu atual."/> + </panel> + <multi_slider initial_value="0" name="sld_altitudes"> + <slider name="sld1" value="1000"/> + <slider name="sld2" value="2000"/> + <slider name="sld3" value="3000"/> + </multi_slider> + <panel name="pnl_ground"> + <text name="txt_ground"> + Chão + </text> + <line_editor name="edt_invname_ground"> + Desconhecido + </line_editor> + <settings_drop_target name="sdt_ground" tool_tip="Arraste uma configuração do Inventário para a caixa alvo para selecionar como o nÃvel do chão do céu."/> + </panel> + <panel name="pnl_water"> + <text name="txt_water"> + Ãgua + </text> + <line_editor name="edt_invname_water"> + Desconhecido + </line_editor> + <settings_drop_target name="sdt_water" tool_tip="Arraste uma configuração do Inventário para a caixa alvo para selecionar como a água atual."/> + </panel> + <button label="Redefinir" name="btn_rst_altitudes" tool_tip="Redefinir para padrão de altitudes"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> </panel> diff --git a/indra/newview/skins/default/xui/pt/panel_settings_sky_atmos.xml b/indra/newview/skins/default/xui/pt/panel_settings_sky_atmos.xml new file mode 100644 index 0000000000..25c27cd6e6 --- /dev/null +++ b/indra/newview/skins/default/xui/pt/panel_settings_sky_atmos.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Atmosfera e Claridade" name="panel_settings_sky_atmos"/> diff --git a/indra/newview/skins/default/xui/pt/panel_settings_sky_clouds.xml b/indra/newview/skins/default/xui/pt/panel_settings_sky_clouds.xml new file mode 100644 index 0000000000..70f814138a --- /dev/null +++ b/indra/newview/skins/default/xui/pt/panel_settings_sky_clouds.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Nuvens" name="panel_settings_sky_clouds"> + <layout_stack> + <layout_panel> + <slider label="X" name="cloud_density_x"/> + <slider label="Y" name="cloud_density_y"/> + <slider label="D" name="cloud_density_d"/> + <slider label="X" name="cloud_detail_x"/> + <slider label="Y" name="cloud_detail_y"/> + <slider label="D" name="cloud_detail_d"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/pt/panel_settings_sky_density.xml b/indra/newview/skins/default/xui/pt/panel_settings_sky_density.xml new file mode 100644 index 0000000000..14143a928a --- /dev/null +++ b/indra/newview/skins/default/xui/pt/panel_settings_sky_density.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Densidade" name="panel_settings_sky_density"> + <layout_stack> + <layout_panel> + <slider label="Espelhar termo exponencial:" name="rayleigh_exponential"/> + <slider label="Espelhar escala exponencial:" name="rayleigh_exponential_scale"/> + <slider label="Espelhar termo linear:" name="rayleigh_linear"/> + <slider label="Espelhar termo constante:" name="rayleigh_constant"/> + <slider label="Espelhar altitude máxima:" name="rayleigh_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="Mie termo exponencial:" name="mie_exponential"/> + <slider label="Mie escala exponencial:" name="mie_exponential_scale"/> + <slider label="Mie termo linear:" name="mie_linear"/> + <slider label="Mie termo constante:" name="mie_constant"/> + <slider label="Mie fator aniso:" name="mie_aniso_factor"/> + <slider label="Mie altitude máxima:" name="mie_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="Absorção termo exponencial:" name="absorption_exponential"/> + <slider label="Absorção escala exponencial:" name="absorption_exponential_scale"/> + <slider label="Absorção termo linear:" name="absorption_linear"/> + <slider label="Absorção termo constante:" name="absorption_constant"/> + <slider label="Absorção altitude máxima:" name="absorption_max_altitude"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/pt/panel_settings_sky_sunmoon.xml b/indra/newview/skins/default/xui/pt/panel_settings_sky_sunmoon.xml new file mode 100644 index 0000000000..fe6672b261 --- /dev/null +++ b/indra/newview/skins/default/xui/pt/panel_settings_sky_sunmoon.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Sol e Lua" name="panel_settings_sky_hbodies"> + <layout_stack> + <layout_panel name="sun_layout"> + <check_box label="Exibir baliza" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <layout_stack> + <layout_panel name="moon_layout"> + <check_box label="Exibir baliza" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/pt/panel_settings_water.xml b/indra/newview/skins/default/xui/pt/panel_settings_water.xml new file mode 100644 index 0000000000..9a6e6462bd --- /dev/null +++ b/indra/newview/skins/default/xui/pt/panel_settings_water.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Ãgua" name="panel_settings_water"> + <layout_stack name="water_stack1"> + <layout_panel> + <text name="FresnelOffsetText"> + Offset fresnel: + </text> + </layout_panel> + <layout_panel> + <layout_stack name="water_stack2"> + <layout_panel> + <slider label="X" name="water_normal_scale_x"/> + <slider label="Y:" name="water_normal_scale_y"/> + <slider label="Z:" name="water_normal_scale_z"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/pt/panel_tools_texture.xml b/indra/newview/skins/default/xui/pt/panel_tools_texture.xml index 5e97eca605..4f484c5fce 100644 --- a/indra/newview/skins/default/xui/pt/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/pt/panel_tools_texture.xml @@ -1,11 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Textura" name="Texture"> - <panel.string name="string repeats per meter"> - Repetições por metro - </panel.string> - <panel.string name="string repeats per face"> - Repetições por face - </panel.string> <text name="color label"> Cor </text> @@ -114,4 +108,5 @@ <spinner label="Offset horizontal" name="shinyOffsetU"/> <spinner label="Offset vertical" name="shinyOffsetV"/> <check_box initial_value="false" label="Alinhar planos planares" name="checkbox planar align" tool_tip="Alinhar texturas de todos os planos selecionados com o plano selecionado por último. Requer mapeamento de textura planar."/> + <button label="Alinhar" label_selected="Alinhar camadas de textura atual" name="button align textures" tool_tip="Alinhar camadas de textura atual"/> </panel> diff --git a/indra/newview/skins/default/xui/pt/role_actions.xml b/indra/newview/skins/default/xui/pt/role_actions.xml index 67ecfa0be3..e09476a83e 100644 --- a/indra/newview/skins/default/xui/pt/role_actions.xml +++ b/indra/newview/skins/default/xui/pt/role_actions.xml @@ -33,6 +33,7 @@ <action description="Mudar música & configurações de mÃdia" longdescription="Mude streaming de música e configurações de vÃdeo em Sobre o terreno > aba MÃdia." name="land change media" value="20"/> <action description="Ativar/desativar 'Editar terreno'" longdescription="Ative/desative 'Editar terreno'. *AVISO* Sobre o terreno > aba Opções > Editar terreno permite a qualquer um alterar as formas de seu terreno, substituir e mover plantas Linden. Certifique-se de saber o que está fazendo antes de desginar esta habilidade. A edição de terreno é ativada/desativada em Sobre o terreno > aba Opções." name="land edit" value="21"/> <action description="Ativar/desativar variados Sobre o Terreno > Opções de configuração" longdescription="Alterna as opções 'Seguro (zero danos)', 'Voar' e autorizar outros residentes a: 'Editar terreno', 'Contruir', 'Criar marcos' e 'Executar scripts' nos terrenos do grupo. Clique em Sobre o terreno > guia Opções." name="land options" value="22"/> + <action description="Modificar configurações do ambiente e ciclos de dia." longdescription="Mude as configurações de ambiente e ciclos de dia em Sobre terrenos > Aba Ambiente." name="land change environment" value="46"/> </action_set> <action_set description="Estas habilidades incluem poderes que permitem a membros ultrapassar restrições em parcelas pertencentes ao grupo." name="Parcel Powers"> <action description="Sempre permitir 'Editar terreno'" longdescription="Membros em uma função com esta habilidade podem editar terreno em uma parcela pertencente ao grupo, mesmo se estiver desativada em Sobre o terreno > aba Opções." name="land allow edit land" value="23"/> diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml index cccc70a92a..ee982b5b22 100644 --- a/indra/newview/skins/default/xui/pt/strings.xml +++ b/indra/newview/skins/default/xui/pt/strings.xml @@ -595,6 +595,15 @@ Aguarde um minuto antes que tentar logar-se novamente. <string name="BUTTON_HELP"> Mostrar ajuda </string> + <string name="TooltipNotecardNotAllowedTypeDrop"> + Os itens deste tipo não podem ser anexados +à s anotações desta região. + </string> + <string name="TooltipNotecardOwnerRestrictedDrop"> + Somente itens com permissões irrestritas +do 'próximo proprietário’ pode +ser anexado à s anotações. + </string> <string name="Searching"> Buscando... </string> @@ -671,6 +680,18 @@ Aguarde um minuto antes que tentar logar-se novamente. Erro na solicitação de upload. Acesso http://secondlife.com/support para ajuda ao resolver este problema. </string> + <string name="SettingValidationError"> + Falha na validação para importação das configurações [NAME] + </string> + <string name="SettingImportFileError"> + Não foi possÃvel abrir o arquivo [FILE] + </string> + <string name="SettingParseFileError"> + Não foi possÃvel abrir o arquivo [FILE] + </string> + <string name="SettingTranslateError"> + Não foi possÃvel traduzir o vento antigo [NAME] + </string> <string name="texture"> textura </string> @@ -746,6 +767,9 @@ http://secondlife.com/support para ajuda ao resolver este problema. <string name="symbolic folder link"> link da pasta </string> + <string name="settings blob"> + configurações + </string> <string name="mesh"> mesh </string> @@ -1076,6 +1100,9 @@ http://secondlife.com/support para ajuda ao resolver este problema. <string name="ForceSitAvatar"> Forçar o avatar a sentar </string> + <string name="ChangeEnvSettings"> + Alterar sua configurações de ambiente + </string> <string name="AgentNameSubst"> (Você) </string> @@ -1224,6 +1251,9 @@ http://secondlife.com/support para ajuda ao resolver este problema. <string name="tattoo"> Tatuagem </string> + <string name="universal"> + Universal + </string> <string name="physics"> FÃsico </string> @@ -1266,6 +1296,9 @@ http://secondlife.com/support para ajuda ao resolver este problema. <string name="tattoo_not_worn"> Tatuagem não usada </string> + <string name="universal_not_worn"> + Universal não usado + </string> <string name="physics_not_worn"> FÃsico não usado </string> @@ -1317,6 +1350,9 @@ http://secondlife.com/support para ajuda ao resolver este problema. <string name="create_new_tattoo"> Criar nova tatuagem </string> + <string name="create_new_universal"> + Criar um novo universal + </string> <string name="create_new_physics"> Criar novo fÃsico </string> @@ -1560,11 +1596,14 @@ Se você continuar a receber essa mensagem, entre em contato com o suporte do Se <string name="MarketplaceUpdating"> atualizando... </string> + <string name="UploadFeeInfo"> + A taxa é baseada em seu nÃvel de inscrição. NÃveis mais altos possuem taxas mais baixas. [https://secondlife.com/my/account/membership.php? Saiba mais] + </string> <string name="Open landmarks"> - Marcos abertos + Marcos em aberto </string> <string name="Unconstrained"> - Sem limites + Ilimitado </string> <string name="no_transfer" value="(não transferÃvel)"/> <string name="no_modify" value="(não modificável)"/> @@ -2452,6 +2491,27 @@ Se você continuar a receber essa mensagem, entre em contato com o suporte do Se <string name="RegionSettings"> Configurações da região </string> + <string name="NoEnvironmentSettings"> + Esta Região não suporta as configurações do ambiente. + </string> + <string name="EnvironmentSun"> + Dom + </string> + <string name="EnvironmentMoon"> + Lua + </string> + <string name="EnvironmentBloom"> + Florescer + </string> + <string name="EnvironmentCloudNoise"> + RuÃdo na nuvem + </string> + <string name="EnvironmentNormalMap"> + Mapa normal + </string> + <string name="EnvironmentTransparent"> + Transparente + </string> <string name="ClassifiedClicksTxt"> Cliques: [TELEPORT] teletransporte, [MAP] mapa, [PROFILE] perfil </string> @@ -4604,6 +4664,9 @@ Denunciar abuso <string name="New Tattoo"> Nova tatuagem </string> + <string name="New Universal"> + Novo universal + </string> <string name="New Physics"> Novo fÃsico </string> @@ -4730,6 +4793,15 @@ Denunciar abuso <string name="Female - Wow"> Wow - feminino </string> + <string name="New Daycycle"> + Novo ciclo de dias + </string> + <string name="New Water"> + Nova água + </string> + <string name="New Sky"> + Novo céu + </string> <string name="/bow"> /reverência </string> @@ -4902,6 +4974,9 @@ Visite http://status.secondlifegrid.net para saber se foi detectado um problema <string name="Chat" value="Bate papo"> Bate-papo </string> + <string name="BaseMembership"> + Básico + </string> <string name="DeleteItems"> Excluir itens selecionados? </string> @@ -5258,6 +5333,12 @@ Tente colocar o caminho do editor entre aspas. <string name="BeaconMedia"> Vendo balizas de mÃdia (branco) </string> + <string name="BeaconSun"> + Visualizando farol de direção do sol (alaranjado) + </string> + <string name="BeaconMoon"> + Visualizando farol de direção da lua (roxo) + </string> <string name="ParticleHiding"> Ocultar partÃculas </string> @@ -5285,6 +5366,12 @@ Tente colocar o caminho do editor entre aspas. <string name="Command_Destinations_Label"> Destinos </string> + <string name="Command_Environments_Label"> + Meus ambientes + </string> + <string name="Command_Facebook_Label"> + Facebook + </string> <string name="Command_Flickr_Label"> Flickr </string> @@ -5378,6 +5465,12 @@ Tente colocar o caminho do editor entre aspas. <string name="Command_Destinations_Tooltip"> Destinos de interesse </string> + <string name="Command_Environments_Tooltip"> + Meus ambientes + </string> + <string name="Command_Facebook_Tooltip"> + Publicar no Facebook + </string> <string name="Command_Flickr_Tooltip"> Carregar no Flickr </string> @@ -5573,6 +5666,12 @@ Tente colocar o caminho do editor entre aspas. <string name="ExperiencePermission12"> aceitar automaticamente permissões de experiência </string> + <string name="ExperiencePermission16"> + forçar o avatar a sentar + </string> + <string name="ExperiencePermission17"> + alterar sua configurações de ambiente + </string> <string name="ExperiencePermissionShortUnknown"> realizar uma operação desconhecida: [Permission] </string> @@ -5597,6 +5696,12 @@ Tente colocar o caminho do editor entre aspas. <string name="ExperiencePermissionShort12"> Autorização </string> + <string name="ExperiencePermissionShort16"> + Sentar + </string> + <string name="ExperiencePermissionShort17"> + Ambiente + </string> <string name="logging_calls_disabled_log_empty"> As conversas não estão sendo registradas. Para começar a manter um registro, selecione "Salvar: apenas registro" ou "Salvar: registro e transcrições" em Preferências> Bate-papo. </string> diff --git a/indra/newview/skins/default/xui/ru/floater_about_land.xml b/indra/newview/skins/default/xui/ru/floater_about_land.xml index 1ae6df76d9..4848f2f7e7 100644 --- a/indra/newview/skins/default/xui/ru/floater_about_land.xml +++ b/indra/newview/skins/default/xui/ru/floater_about_land.xml @@ -338,7 +338,7 @@ <check_box label="Ð’Ñе" name="check other scripts" tool_tip="ЕÑли уÑтановлен флажок, то жители могут выполнÑть Ñкрипты на вашем учаÑтке, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ."/> <check_box label="Группа" name="check group scripts" tool_tip="ЕÑли уÑтановлен флажок, то члены группы могут выполнÑть Ñкрипты на вашем учаÑтке, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ."/> <check_box label="БезопаÑно (нет повреждений)" name="check safe" tool_tip="ЕÑли отмечено, то Ð·ÐµÐ¼Ð»Ñ ÑчитаетÑÑ Ð±ÐµÐ·Ð¾Ð¿Ð°Ñной, отключены боевые повреждениÑ. ЕÑли не отмечено, то боевые Ð¿Ð¾Ð²Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ñ‹."/> - <check_box label="Ðе толкать" name="PushRestrictCheck" tool_tip="Запрещает Ñкриптам функцию толканиÑ. Ðтот параметр может оказатьÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ñ‹Ð¼ Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð½ÐµÐ¶ÐµÐ»Ð°Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð³Ð¾ Ð¿Ð¾Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð½Ð° вашей земле."/> + <check_box label="Ðе толкать" name="PushRestrictCheck" left_pad="44" tool_tip="Запрещает Ñкриптам функцию толканиÑ. Ðтот параметр может оказатьÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ñ‹Ð¼ Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð½ÐµÐ¶ÐµÐ»Ð°Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð³Ð¾ Ð¿Ð¾Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð½Ð° вашей земле."/> <check_box label="Показать меÑто в поиÑке (L$30/неделÑ)" name="ShowDirectoryCheck" tool_tip="Позволить людÑм видеть учаÑток в результатах поиÑка"/> <combo_box name="land category"> <combo_box.item label="Ð›ÑŽÐ±Ð°Ñ ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ð¸Ñ" name="item0"/> @@ -360,11 +360,11 @@ Снимок: </text> <texture_picker name="snapshot_ctrl" tool_tip="Щелкните Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° изображениÑ"/> - <text name="allow_see_label"> + <text name="allow_see_label" left="283"> Ðватары Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… учаÑтков могут видеть аватары на Ñтом учаÑтке и общатьÑÑ Ñ Ð½Ð¸Ð¼Ð¸ </text> - <check_box label="Видны аватары" name="SeeAvatarsCheck" tool_tip="Ðватары Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… учаÑтков Ñмогут видеть аватары на Ñтом учаÑтке и общатьÑÑ Ñ Ð½Ð¸Ð¼Ð¸ в чате, а вы также Ñможете видеть их и общатьÑÑ Ñ Ð½Ð¸Ð¼Ð¸."/> - <text name="landing_point"> + <check_box label="Видны аватары" left="262" name="SeeAvatarsCheck" tool_tip="Ðватары Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… учаÑтков Ñмогут видеть аватары на Ñтом учаÑтке и общатьÑÑ Ñ Ð½Ð¸Ð¼Ð¸ в чате, а вы также Ñможете видеть их и общатьÑÑ Ñ Ð½Ð¸Ð¼Ð¸."/> + <text name="landing_point" width="225"> Ð’ точку телепортации: [LANDING] </text> <button label="Задать" label_selected="Задать" name="Set" tool_tip="УÑтановить точку телепортации, в которую будут прибывать поÑетители, СтавитÑÑ Ð² меÑте вашего аватара на Ñтом учаÑтке."/> @@ -372,7 +372,7 @@ <text name="Teleport Routing: "> Вариант телепортации: </text> - <combo_box name="landing type" tool_tip="Вариант телепортации – выберите, каким образом будет производитьÑÑ Ñ‚ÐµÐ»ÐµÐ¿Ð¾Ñ€Ñ‚Ð°Ñ†Ð¸Ñ Ð½Ð° вашу землю"> + <combo_box name="landing type" width="150" tool_tip="Вариант телепортации – выберите, каким образом будет производитьÑÑ Ñ‚ÐµÐ»ÐµÐ¿Ð¾Ñ€Ñ‚Ð°Ñ†Ð¸Ñ Ð½Ð° вашу землю"> <combo_box.item label="Ð’ черном ÑпиÑке" name="Blocked"/> <combo_box.item label="Ð’ точку телепортации" name="LandingPoint"/> <combo_box.item label="Ð’ любое меÑто" name="Anywhere"/> @@ -439,7 +439,7 @@ <panel.string name="estate_override"> ЧаÑть Ñтих параметров уÑтановлена на уровне Ð·ÐµÐ¼Ð»ÐµÐ²Ð»Ð°Ð´ÐµÐ½Ð¸Ñ </panel.string> - <check_box label="ДоÑтуп открыт Ð´Ð»Ñ Ð²Ñех (При ÑнÑÑ‚Ð¸Ñ Ð²Ñ‹Ð´ÐµÐ»ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÐµÑ‚ Ñоздана запиÑÑŒ в Ñтроке запрета)" name="public_access"/> + <check_box label="ДоÑтуп открыт Ð´Ð»Ñ Ð²Ñех" tool_tip="При ÑнÑÑ‚Ð¸Ñ Ð²Ñ‹Ð´ÐµÐ»ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÐµÑ‚ Ñоздана запиÑÑŒ в Ñтроке запрета" name="public_access"/> <check_box label="Должен быть 18 и Ñтарше [ESTATE_AGE_LIMIT]" name="limit_age_verified" tool_tip="ДоÑтуп к Ñтому учаÑтку имеют только жители 18 лет и Ñтарше. Более Ð¿Ð¾Ð´Ñ€Ð¾Ð±Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð½Ð°Ñ…Ð¾Ð´Ð¸Ñ‚ÑÑ Ð·Ð´ÐµÑÑŒ: [SUPPORT_SITE]."/> <check_box label="Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ платежах должна быть в файле [ESTATE_PAYMENT_LIMIT]" name="limit_payment" tool_tip="Ð”Ð»Ñ Ð´Ð¾Ñтупа к Ñтому учаÑтку у Ð¶Ð¸Ñ‚ÐµÐ»Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° быть зарегиÑтрирована Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾Ð± оплате. Более Ð¿Ð¾Ð´Ñ€Ð¾Ð±Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð½Ð°Ñ…Ð¾Ð´Ð¸Ñ‚ÑÑ Ð·Ð´ÐµÑÑŒ: [SUPPORT_SITE]."/> <check_box label="Разрешить группе [GROUP] без вÑÑких ограничений" name="GroupCheck" tool_tip="Группа уÑтанавливаетÑÑ Ð½Ð° оÑновной вкладке."/> @@ -474,5 +474,6 @@ </panel> </panel> <panel label="ПРИКЛЮЧЕÐИЯ" name="land_experiences_panel"/> + <panel label="ОКРУЖÐЮЩÐЯ СРЕДÐ" name="land_environment_panel"/> </tab_container> </floater> diff --git a/indra/newview/skins/default/xui/ru/floater_adjust_environment.xml b/indra/newview/skins/default/xui/ru/floater_adjust_environment.xml new file mode 100644 index 0000000000..85809966e4 --- /dev/null +++ b/indra/newview/skins/default/xui/ru/floater_adjust_environment.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_adjust_snapshot" title="Личное оÑвещение"> + <layout_stack name="outer_stack"> + <layout_panel name="env_controls"> + <layout_stack name="settings_stack"> + <layout_panel> + <button label="СброÑ" name="btn_reset" tool_tip="Закрыть и ÑброÑить в общую Ñреду"/> + <text name="cloud_map_label"> + Изображение облака: + </text> + </layout_panel> + <layout_panel> + <text name="label"> + Солнце: + </text> + <check_box label="Показать метку" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <check_box label="Показать метку" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/ru/floater_beacons.xml b/indra/newview/skins/default/xui/ru/floater_beacons.xml index 38d257ff81..9d706a7c5d 100644 --- a/indra/newview/skins/default/xui/ru/floater_beacons.xml +++ b/indra/newview/skins/default/xui/ru/floater_beacons.xml @@ -18,5 +18,7 @@ <check_box label="ИÑточники звука" name="sounds"/> <check_box label="ИÑточники чаÑтиц" name="particles"/> <check_box label="ИÑточники медиа" name="moapbeacon"/> + <check_box label="Солнце" name="sun"/> + <check_box label="Луна" name="moon"/> </panel> </floater> diff --git a/indra/newview/skins/default/xui/ru/floater_bulk_perms.xml b/indra/newview/skins/default/xui/ru/floater_bulk_perms.xml index 55b0e0c3bd..f5115a161d 100644 --- a/indra/newview/skins/default/xui/ru/floater_bulk_perms.xml +++ b/indra/newview/skins/default/xui/ru/floater_bulk_perms.xml @@ -21,6 +21,7 @@ <icon name="icon_script" tool_tip="Скрипты"/> <icon name="icon_sound" tool_tip="Звуки"/> <icon name="icon_texture" tool_tip="ТекÑтуры"/> + <icon name="icon_setting" tool_tip="ÐаÑтройки окружающей Ñреды"/> <button label="√ Ð’Ñе" name="check_all"/> <button label="ОчиÑтить" label_selected="Ðет" name="check_none"/> <text name="newperms"> diff --git a/indra/newview/skins/default/xui/ru/floater_buy_currency.xml b/indra/newview/skins/default/xui/ru/floater_buy_currency.xml index 87e8bd524e..ef55ce58d4 100644 --- a/indra/newview/skins/default/xui/ru/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/ru/floater_buy_currency.xml @@ -59,8 +59,7 @@ </text> <button label="ПриобреÑти" name="buy_btn"/> <button label="Отмена" name="cancel_btn"/> - <text name="info_cannot_buy"> + <floater.string name="info_cannot_buy"> ÐÐµÐ»ÑŒÐ·Ñ ÐºÑƒÐ¿Ð¸Ñ‚ÑŒ - </text> - <button label="Продолжить в Интернете" name="error_web"/> + </floater.string> </floater> diff --git a/indra/newview/skins/default/xui/ru/floater_delete_env_preset.xml b/indra/newview/skins/default/xui/ru/floater_delete_env_preset.xml deleted file mode 100644 index 1ae278f03b..0000000000 --- a/indra/newview/skins/default/xui/ru/floater_delete_env_preset.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<floater name="Delete Env Preset" title="УДÐЛЕÐИЕ ÐÐСТРОЙКИ СРЕДЫ"> - <string name="title_water"> - Удалить наÑтройку воды - </string> - <string name="title_sky"> - Удалить наÑтройку неба - </string> - <string name="title_day_cycle"> - Удалить Ñуточный цикл - </string> - <string name="label_water"> - ÐаÑтройка: - </string> - <string name="label_sky"> - ÐаÑтройка: - </string> - <string name="label_day_cycle"> - Суточный цикл: - </string> - <string name="msg_confirm_deletion"> - ДейÑтвительно удалить выбранную наÑтройку? - </string> - <string name="msg_sky_is_referenced"> - ÐÐµÐ»ÑŒÐ·Ñ ÑƒÐ´Ð°Ð»Ð¸Ñ‚ÑŒ наÑтройку, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¸ÑпользуетÑÑ Ð² некоторых Ñуточных циклах. - </string> - <string name="combo_label"> - -Выбор наÑтройки- - </string> - <text name="label"> - ÐаÑтройка: - </text> - <button label="Удалить" name="delete"/> - <button label="Отмена" name="cancel"/> -</floater> diff --git a/indra/newview/skins/default/xui/ru/floater_edit_ext_day_cycle.xml b/indra/newview/skins/default/xui/ru/floater_edit_ext_day_cycle.xml new file mode 100644 index 0000000000..ba01b13a82 --- /dev/null +++ b/indra/newview/skins/default/xui/ru/floater_edit_ext_day_cycle.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_edit_extdaycycle" title="Изменить Ñуточный цикл"> + <string name="title_new"> + Создать новый Ñуточный цикл + </string> + <string name="title_edit"> + Изменить Ñуточный цикл + </string> + <string name="hint_new"> + Введите Ð¸Ð¼Ñ Ñуточного цикла, задайте его параметры Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Ñлементов ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¸ нажмите кнопку «Сохранить». + </string> + <string name="hint_edit"> + Чтобы изменить Ñуточный цикл, задайте его параметры Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Ñлементов ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð½Ð¸Ð¶Ðµ и нажмите кнопку «Сохранить». + </string> + <string name="time_label"> + ([HH]:[MM]) + </string> + <string name="sky_track_label"> + Ðебо [ALT] + </string> + <string name="sky_label"> + Ðебо + </string> + <string name="water_label"> + Вода + </string> + <string name="commit_parcel"> + Применить к учаÑтку + </string> + <string name="commit_region"> + Применить к региону + </string> + <layout_stack name="outer_stack"> + <layout_panel name="name_and_import"> + <text name="label"> + Ðазвание Ñуточного цикла: + </text> + <button label="Импортировать" name="btn_import" tool_tip="Импортировать уÑтаревшие наÑтройки Ñ Ð´Ð¸Ñка."/> + </layout_panel> + <layout_panel name="content"> + <layout_stack name="content_stack"> + <layout_panel name="timeline_track_selection"> + <panel name="timeline_layers"> + <button label="Ðебо 4" name="sky4_track"/> + <button label="Ðебо 3" name="sky3_track"/> + <button label="Ðебо 2" name="sky2_track"/> + <button label="Уровень земли" name="sky1_track"/> + <button label="Вода" name="water_track"/> + </panel> + <panel name="timeline"> + <text name="p0" value="0%[DSC]"/> + <text name="p1" value="25%[DSC]"/> + <text name="p2" value="50%[DSC]"/> + <text name="p3" value="75%[DSC]"/> + <text name="p4" value="100%[DSC]"/> + <multi_slider initial_value="0" name="WLTimeSlider"/> + <multi_slider initial_value="0" name="WLDayCycleFrames"/> + <text name="current_time" value="[PRCNT]%[DSC]"/> + <layout_stack> + <layout_panel> + <button label="Клонировать режим Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸Ð·" name="copy_track"/> + <button label="Загрузить режим Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸Ð·" name="load_track"/> + <button label="ОчиÑтить режим редактированиÑ" name="clear_track"/> + </layout_panel> + <layout_panel> + <layout_stack name="progress_control"> + <layout_panel name="skip_back"> + <button name="skip_back_btn" tool_tip="Шаг назад"/> + </layout_panel> + <layout_panel name="skip_forward"> + <button name="skip_forward_btn" tool_tip="Шаг вперед"/> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel> + <button label="Добавить [FRAME]" name="add_frame"/> + <button label="Загрузить [FRAME]" name="btn_load_frame"/> + <button label="Удалить [FRAME]" name="delete_frame"/> + </layout_panel> + </layout_stack> + </panel> + </layout_panel> + <layout_panel name="frame_edit_controls"> + <text name="icn_lock_edit"> + Выбрать ключевой фрейм на временной шкале выше Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð½Ð°Ñтроек. + </text> + </layout_panel> + <layout_panel name="frame_settings_water"> + <tab_container name="water_tabs"> + <panel label="Вода" name="water_panel"/> + </tab_container> + </layout_panel> + <layout_panel name="frame_settings_sky"> + <tab_container name="sky_tabs"> + <panel label="ÐтмоÑфера и оÑвещение" name="atmosphere_panel"/> + <panel label="Облака" name="clouds_panel"/> + <panel label="Солнце и луна" name="moon_panel"/> + </tab_container> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel name="buttons"> + <button label="Сохранить" name="save_btn"/> + <button label="Отмена" name="cancel_btn"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/ru/floater_fixedenvironment.xml b/indra/newview/skins/default/xui/ru/floater_fixedenvironment.xml new file mode 100644 index 0000000000..b5f1a1ced2 --- /dev/null +++ b/indra/newview/skins/default/xui/ru/floater_fixedenvironment.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="Fixed Environment" title="ФикÑÐ¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ñреда"> + <string name="edit_sky"> + Редактировать наÑтройки неба: + </string> + <string name="edit_water"> + Редактировать наÑтройки воды: + </string> + <layout_stack name="floater_stack"> + <layout_panel name="info_panel"> + <button label="Загрузить" name="btn_load" tool_tip="Загрузить наÑтройки из инвентарного ÑпиÑка"/> + <button label="Импортировать" name="btn_import" tool_tip="Импортировать уÑтаревшие наÑтройки Ñ Ð´Ð¸Ñка."/> + </layout_panel> + <layout_panel name="button_panel"> + <layout_stack name="button_bar_ls"> + <layout_panel name="save_btn_lp"> + <button label="Сохранить" name="btn_commit"/> + </layout_panel> + <layout_panel name="revert_btn_lp"> + <button label="Отмена" name="btn_cancel" tool_tip="ВернутьÑÑ Ðº поÑледней Ñохраненной верÑии"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/ru/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/ru/floater_inventory_view_finder.xml index ce6b89cb82..7c1d3b52c5 100644 --- a/indra/newview/skins/default/xui/ru/floater_inventory_view_finder.xml +++ b/indra/newview/skins/default/xui/ru/floater_inventory_view_finder.xml @@ -12,6 +12,7 @@ <check_box label="Звуки" name="check_sound"/> <check_box label="ТекÑтуры" name="check_texture"/> <check_box label="Снимки" name="check_snapshot"/> + <check_box label="ÐаÑтройки" name="check_settings"/> <button label="Ð’Ñе" label_selected="Ð’Ñе" name="All"/> <button label="Ðет" label_selected="Ðет" name="None"/> <check_box label="Ð’Ñегда показывать папки" name="check_show_empty"/> diff --git a/indra/newview/skins/default/xui/ru/floater_merchant_outbox.xml b/indra/newview/skins/default/xui/ru/floater_merchant_outbox.xml deleted file mode 100644 index 1d3ff3f5ed..0000000000 --- a/indra/newview/skins/default/xui/ru/floater_merchant_outbox.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="floater_merchant_outbox" title="ТОРГОВЫЕ ИСХОДЯЩИЕ"> - <string name="OutboxFolderCount1"> - 1 папка - </string> - <string name="OutboxFolderCountN"> - [NUM] папки - </string> - <string name="OutboxImporting"> - Отправка папок.... - </string> - <string name="OutboxInitializing"> - ИнициализациÑ... - </string> - <panel label="" name="panel_1"> - <panel name="panel_2"> - <panel name="outbox_inventory_placeholder_panel"> - <text name="outbox_inventory_placeholder_title"> - Загрузка... - </text> - </panel> - </panel> - <panel name="panel_3"> - <panel name="outbox_generic_drag_target"> - <text name="text_1"> - ПеретаÑкивайте предметы Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¿Ð°Ð¿Ð¾Ðº - </text> - </panel> - <button label="Отправить в торговый центр" name="outbox_import_btn" tool_tip="Ð’Ñ‹Ñтавить на витрину моего магазина"/> - </panel> - </panel> -</floater> diff --git a/indra/newview/skins/default/xui/ru/floater_my_environments.xml b/indra/newview/skins/default/xui/ru/floater_my_environments.xml new file mode 100644 index 0000000000..ba31600df7 --- /dev/null +++ b/indra/newview/skins/default/xui/ru/floater_my_environments.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater label="МеÑта" name="my_environments" title="МОЯ ОКРУЖÐЮЩÐЯ СРЕДÐ"> + <layout_stack> + <layout_panel label="Фильтры" name="filter_panel"> + <check_box label="Дни" name="chk_days"/> + <check_box label="ÐебеÑа" name="chk_skies"/> + <check_box label="Вода" name="chk_water"/> + <filter_editor label="Фильтр окружающей Ñреды" name="flt_search"/> + </layout_panel> + <layout_panel label="ÐžÐºÑ€ÑƒÐ¶Ð°ÑŽÑ‰Ð°Ñ Ñреда" name="list_panel"> + <panel label="pnl_inv_wrap" name="pnl_inv_wrap"/> + </layout_panel> + <layout_panel> + <check_box initial_value="false" label="Показать вÑе папки" name="chk_showfolders"/> + </layout_panel> + <layout_panel name="pnl_control"> + <panel label="bottom_panel" name="pnl_bottom"> + <menu_button name="btn_gear" tool_tip="Дополнительные параметры"/> + <menu_button name="btn_newsettings" tool_tip="Создать новую наÑтройку"/> + <button name="btn_del" tool_tip="Удалить выбранную вещь"/> + </panel> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/ru/floater_perms_default.xml b/indra/newview/skins/default/xui/ru/floater_perms_default.xml index a33c6b40b6..2a239c07c4 100644 --- a/indra/newview/skins/default/xui/ru/floater_perms_default.xml +++ b/indra/newview/skins/default/xui/ru/floater_perms_default.xml @@ -37,6 +37,10 @@ <text name="label_12" tool_tip="Задайте Ñтандартные Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¾Ð´ÐµÐ¶Ð´Ñ‹ или чаÑтей тела"> ÐоÑимые вещи </text> + <text name="label_13" tool_tip="Задать Ñтандартные разрешениÑ, когда будут Ñозданы наÑтройки Ñреды"> + ÐаÑтройки + </text> + <check_box name="env_settings_c" value="true"/> </panel> <button label="OK" label_selected="OK" name="ok"/> <button label="Отмена" label_selected="Отмена" name="cancel"/> diff --git a/indra/newview/skins/default/xui/ru/floater_pick_track.xml b/indra/newview/skins/default/xui/ru/floater_pick_track.xml new file mode 100644 index 0000000000..7588e1759c --- /dev/null +++ b/indra/newview/skins/default/xui/ru/floater_pick_track.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="track picker" title="ВЫБРÐТЬ: РЕЖИМ РЕДÐКТИРОВÐÐИЯ"> + <layout_stack name="adjuster"> + <layout_panel name="pnl_desc"> + <text name="select_description"> + Выбрать иÑточник неба: + </text> + </layout_panel> + <layout_panel name="pnl_traks"> + <radio_group name="track_selection"> + <radio_item label="Ðебо4 [ALT]" name="radio_sky4" value="4"/> + <radio_item label="Ðебо3 [ALT]" name="radio_sky3" value="3"/> + <radio_item label="Ðебо2 [ALT]" name="radio_sky2" value="2"/> + <radio_item label="ЗемлÑ" name="radio_sky1" value="1"/> + </radio_group> + </layout_panel> + <layout_panel name="pnl_ok_cancel"> + <button label="OK" label_selected="OK" name="btn_select"/> + <button label="Отмена" label_selected="Отмена" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/ru/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/ru/floater_preferences_graphics_advanced.xml index fc6b6a173e..84e1ff15a0 100644 --- a/indra/newview/skins/default/xui/ru/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/ru/floater_preferences_graphics_advanced.xml @@ -82,7 +82,6 @@ <check_box initial_value="true" label="ПрозрачноÑть воды" name="TransparentWater"/> <check_box initial_value="true" label="РельефноÑть и ÑиÑние" name="BumpShiny"/> <check_box initial_value="true" label="Локальный Ñвет" name="LocalLights"/> - <check_box initial_value="true" label="Базовые шейдеры" name="BasicShaders" tool_tip="Отключение Ñтого параметра может предотвратить завиÑание некоторых видеокарт"/> <slider label="Ландшафт:" name="TerrainDetail"/> <text name="TerrainDetailText"> ÐÐ¸Ð·ÐºÐ°Ñ diff --git a/indra/newview/skins/default/xui/ru/floater_preview_texture.xml b/indra/newview/skins/default/xui/ru/floater_preview_texture.xml index c9cb87282a..46d2a37503 100644 --- a/indra/newview/skins/default/xui/ru/floater_preview_texture.xml +++ b/indra/newview/skins/default/xui/ru/floater_preview_texture.xml @@ -10,12 +10,12 @@ ОпиÑание: </text> <text name="dimensions"> - [WIDTH]x[HEIGHT] пикÑелей + [WIDTH]пикÑелей x [HEIGHT]пикÑелей </text> <text name="aspect_ratio"> - Соотношение Ñторон + ПроÑмотр Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ñ Ñоотношением Ñторон </text> - <combo_box name="combo_aspect_ratio" tool_tip="ПроÑмотр Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼ Ñоотношением Ñторон"> + <combo_box name="combo_aspect_ratio" tool_tip="ПроÑмотр Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ñ Ñ„Ð¸ÐºÑированным Ñоотношением Ñторон"> <combo_item name="Unconstrained"> Без Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ </combo_item> @@ -42,6 +42,6 @@ </combo_item> </combo_box> <button label="OK" name="Keep"/> - <button label="Удалить" name="Discard"/> + <button label="Отменить" name="Discard"/> <button label="Сохранить как" name="save_tex_btn"/> </floater> diff --git a/indra/newview/skins/default/xui/ru/floater_settings_picker.xml b/indra/newview/skins/default/xui/ru/floater_settings_picker.xml new file mode 100644 index 0000000000..84f0e303fc --- /dev/null +++ b/indra/newview/skins/default/xui/ru/floater_settings_picker.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="settings picker" title="ВЫБРÐТЬ: ÐÐСТРОЙКИ"> + <floater.string name="pick title"> + Выбрать: + </floater.string> + <floater.string name="pick_track"> + ВЫБРÐТЬ РЕЖИМ РЕДÐКТИРОВÐÐИЯ + </floater.string> + <floater.string name="pick_settings"> + ВЫБРÐТЬ ÐÐСТРОЙКИ + </floater.string> + <floater.string name="track_water"> + Вода + </floater.string> + <floater.string name="track_ground"> + Ð—ÐµÐ¼Ð»Ñ + </floater.string> + <floater.string name="track_sky"> + Ðебо[NUM] + </floater.string> + <layout_stack name="test_stack"> + <layout_panel name="inv_list"> + <filter_editor label="Фильтровать текÑтуры" name="flt_inventory_search"/> + </layout_panel> + <layout_panel name="temp"> + <button label="OK" label_selected="OK" name="btn_select"/> + <button label="Отмена" label_selected="Отмена" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/ru/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/ru/floater_texture_ctrl.xml index c9e117362f..d4323e5c34 100644 --- a/indra/newview/skins/default/xui/ru/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/ru/floater_texture_ctrl.xml @@ -9,17 +9,13 @@ <text name="Multiple"> ÐеÑколько текÑтур </text> - <radio_group name="mode_selection"> - <radio_item label="Инвентарь" name="inventory" value="0"/> - <radio_item label="Локально" name="local" value="1"/> - </radio_group> - <text name="unknown"> - Размер: [DIMENSIONS] - </text> + <combo_box name="mode_selection"> + <combo_box.item label="Инвентарь" name="inventory" value="0"/> + <combo_box.item label="Локально" name="local" value="1"/> + </combo_box> <button label="По умолчанию" label_selected="По умолчанию" name="Default"/> <button label="ОчиÑтить" label_selected="ОчиÑтить" name="Blank"/> <button label="Ðет" label_selected="Ðет" name="None"/> - <check_box initial_value="true" label="Применить ÑейчаÑ" name="apply_immediate_check"/> <text name="preview_disabled" value="ПроÑмотр отключен"/> <filter_editor label="Фильтровать текÑтуры" name="inventory search editor"/> <check_box initial_value="false" label="Показывать папки" name="show_folders_check"/> @@ -30,6 +26,22 @@ <column label="ИмÑ" name="unit_name"/> <column label="ID" name="unit_id_HIDDEN"/> </scroll_list> + <combo_box name="l_bake_use_texture_combo_box" tool_tip="Выбрать фикÑированную текÑтуру"> + <combo_box.item label="Ðикакой" name="None"/> + <combo_box.item label="BAKED_HEAD" name="BAKED_HEAD"/> + <combo_box.item label="BAKED_UPPER" name="BAKED_UPPER"/> + <combo_box.item label="BAKED_LOWER" name="BAKED_LOWER"/> + <combo_box.item label="BAKED_EYES" name="BAKED_EYES"/> + <combo_box.item label="BAKED_SKIRT" name="BAKED_SKIRT"/> + <combo_box.item label="BAKED_HAIR" name="BAKED_HAIR"/> + <combo_box.item label="BAKED_LEFTARM" name="BAKED_LEFTARM"/> + <combo_box.item label="BAKED_LEFTLEG" name="BAKED_LEFTLEG"/> + <combo_box.item label="BAKED_AUX1" name="BAKED_AUX1"/> + <combo_box.item label="BAKED_AUX2" name="BAKED_AUX2"/> + <combo_box.item label="BAKED_AUX3" name="BAKED_AUX3"/> + </combo_box> + <check_box initial_value="false" label="Скрыть регион базовой Ñетки" name="hide_base_mesh_region"/> <button label="ОК" label_selected="ОК" name="Select"/> <button label="Отмена" label_selected="Отмена" name="Cancel"/> + <check_box initial_value="true" label="Применить ÑейчаÑ" name="apply_immediate_check"/> </floater> diff --git a/indra/newview/skins/default/xui/ru/menu_cof_attachment.xml b/indra/newview/skins/default/xui/ru/menu_cof_attachment.xml index 72d1bc52b5..bc60188e2d 100644 --- a/indra/newview/skins/default/xui/ru/menu_cof_attachment.xml +++ b/indra/newview/skins/default/xui/ru/menu_cof_attachment.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="COF Attachment"> + <menu_item_call label="КоÑнутьÑÑ" name="touch_attach" /> + <menu_item_call label="Изменить" name="edit_item" /> <menu_item_call label="ОтÑоединить" name="detach"/> </context_menu> diff --git a/indra/newview/skins/default/xui/ru/menu_inventory.xml b/indra/newview/skins/default/xui/ru/menu_inventory.xml index 3404ae29a3..0f63324e90 100644 --- a/indra/newview/skins/default/xui/ru/menu_inventory.xml +++ b/indra/newview/skins/default/xui/ru/menu_inventory.xml @@ -10,7 +10,6 @@ <menu_item_call label="Ðктивировать" name="Marketplace Activate"/> <menu_item_call label="Деактивировать" name="Marketplace Deactivate"/> <menu_item_call label="ПоделитьÑÑ" name="Share"/> - <menu_item_call label="Купить" name="Task Buy"/> <menu_item_call label="Открыть" name="Task Open"/> <menu_item_call label="ВоÑпроизвеÑти" name="Task Play"/> <menu_item_call label="СвойÑтва" name="Task Properties"/> @@ -34,6 +33,7 @@ <menu_item_call label="Ðовые труÑÑ‹" name="New Underpants"/> <menu_item_call label="ÐÐ¾Ð²Ð°Ñ Ð°Ð»ÑŒÑ„Ð°-маÑка" name="New Alpha Mask"/> <menu_item_call label="Ðовое тату" name="New Tattoo"/> + <menu_item_call label="Ðовые универÑальные" name="New Universal"/> <menu_item_call label="ÐÐ¾Ð²Ð°Ñ Ñ„Ð¸Ð·Ð¸ÐºÐ°" name="New Physics"/> </menu> <menu label="Ðовые чаÑти тела" name="New Body Parts"> @@ -42,6 +42,11 @@ <menu_item_call label="Ðовые волоÑÑ‹" name="New Hair"/> <menu_item_call label="Ðовые глаза" name="New Eyes"/> </menu> + <menu label="Ðовые наÑтройки" name="New Settings"> + <menu_item_call label="Ðовое небо" name="New Sky"/> + <menu_item_call label="ÐÐ¾Ð²Ð°Ñ Ð²Ð¾Ð´Ð°" name="New Water"/> + <menu_item_call label="Ðовый Ñуточный цикл" name="New Day Cycle"/> + </menu> <menu label="ИÑпользовать по умолчанию длÑ" name="upload_def"> <menu_item_call label="Переданные изображениÑ" name="Image uploads"/> <menu_item_call label="Переданные звуки" name="Sound uploads"/> @@ -100,9 +105,12 @@ <menu_item_call label="Ðадеть" name="Wearable And Object Wear"/> <menu label="ПриÑоединить к" name="Attach To"/> <menu label="ПриÑоединить к данным в игре" name="Attach To HUD"/> + <menu_item_call label="КоÑнутьÑÑ" name="Attachment Touch" /> <menu_item_call label="Изменить" name="Wearable Edit"/> <menu_item_call label="Добавить" name="Wearable Add"/> <menu_item_call label="СнÑть" name="Take Off"/> + <menu_item_call label="Применить только к Ñебе" name="Settings Apply Local"/> + <menu_item_call label="Применить к учаÑтку" name="Settings Apply Parcel"/> <menu_item_call label="Копировать в ÑпиÑки товаров торгового центра" name="Marketplace Copy"/> <menu_item_call label="ПеремеÑтить в ÑпиÑки товаров торгового центра" name="Marketplace Move"/> <menu_item_call label="- нет дейÑтвий -" name="--no options--"/> diff --git a/indra/newview/skins/default/xui/ru/menu_inventory_add.xml b/indra/newview/skins/default/xui/ru/menu_inventory_add.xml index 9a240c653e..94ec61af90 100644 --- a/indra/newview/skins/default/xui/ru/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/ru/menu_inventory_add.xml @@ -5,9 +5,7 @@ <menu_item_call label="Звук (L$[COST])..." name="Upload Sound"/> <menu_item_call label="ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ (L$[COST])..." name="Upload Animation"/> <menu_item_call label="Модель..." name="Upload Model"/> - <menu_item_call label="МаÑтер моделированиÑ..." name="Upload Model Wizard"/> <menu_item_call label="Ð’Ñе Ñразу (L$[COST] за файл)..." name="Bulk Upload"/> - <menu_item_call label="УÑтановить Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð° передачу по умолчанию" name="perm prefs"/> </menu> <menu_item_call label="ÐÐ¾Ð²Ð°Ñ Ð¿Ð°Ð¿ÐºÐ°" name="New Folder"/> <menu_item_call label="Ðовый Ñкрипт" name="New Script"/> @@ -25,6 +23,7 @@ <menu_item_call label="Ðовые труÑÑ‹" name="New Underpants"/> <menu_item_call label="ÐÐ¾Ð²Ð°Ñ Ð°Ð»ÑŒÑ„Ð°-маÑка" name="New Alpha"/> <menu_item_call label="Ðовое тату" name="New Tattoo"/> + <menu_item_call label="Ðовые универÑальные" name="New Universal"/> <menu_item_call label="ÐÐ¾Ð²Ð°Ñ Ñ„Ð¸Ð·Ð¸ÐºÐ°" name="New Physics"/> </menu> <menu label="Ðовые чаÑти тела" name="New Body Parts"> @@ -33,4 +32,9 @@ <menu_item_call label="Ðовые волоÑÑ‹" name="New Hair"/> <menu_item_call label="Ðовые глаза" name="New Eyes"/> </menu> + <menu label="Ðовые наÑтройки" name="New Settings"> + <menu_item_call label="Ðовое небо" name="New Sky"/> + <menu_item_call label="ÐÐ¾Ð²Ð°Ñ Ð²Ð¾Ð´Ð°" name="New Water"/> + <menu_item_call label="Ðовый Ñуточный цикл" name="New Day Cycle"/> + </menu> </menu> diff --git a/indra/newview/skins/default/xui/ru/menu_outfit_gear.xml b/indra/newview/skins/default/xui/ru/menu_outfit_gear.xml index 24d780ba1c..1d883220e8 100644 --- a/indra/newview/skins/default/xui/ru/menu_outfit_gear.xml +++ b/indra/newview/skins/default/xui/ru/menu_outfit_gear.xml @@ -20,6 +20,7 @@ <menu_item_call label="ÐÐ¾Ð²Ð°Ñ Ð°Ð»ÑŒÑ„Ð°-маÑка" name="New Alpha"/> <menu_item_call label="ÐÐ¾Ð²Ð°Ñ Ñ„Ð¸Ð·Ð¸ÐºÐ°" name="New Physics"/> <menu_item_call label="Ðовое тату" name="New Tattoo"/> + <menu_item_call label="Ðовые универÑальные" name="New Universal"/> </menu> <menu label="Ðовые чаÑти тела" name="New Body Parts"> <menu_item_call label="ÐÐ¾Ð²Ð°Ñ Ñ„Ð¸Ð³ÑƒÑ€Ð°" name="New Shape"/> diff --git a/indra/newview/skins/default/xui/ru/menu_save_settings.xml b/indra/newview/skins/default/xui/ru/menu_save_settings.xml new file mode 100644 index 0000000000..9a9c796cf6 --- /dev/null +++ b/indra/newview/skins/default/xui/ru/menu_save_settings.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="save_settings_menu"> + <menu_item_check label="Сохранить" name="save_settings"/> + <menu_item_check label="Сохранить как" name="save_as_new_settings"/> + <menu_item_check label="Подтвердить" name="commit_changes"/> + <menu_item_check label="Применить только к Ñебе" name="apply_local"/> + <menu_item_check label="Применить к учаÑтку" name="apply_parcel"/> + <menu_item_check label="Применить к региону" name="apply_region"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/ru/menu_settings_add.xml b/indra/newview/skins/default/xui/ru/menu_settings_add.xml new file mode 100644 index 0000000000..a3ef976424 --- /dev/null +++ b/indra/newview/skins/default/xui/ru/menu_settings_add.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_add"> + <menu_item_call label="Ðовое небо" name="New Sky"/> + <menu_item_call label="ÐÐ¾Ð²Ð°Ñ Ð²Ð¾Ð´Ð°" name="New Water"/> + <menu_item_call label="Ðовый Ñуточный цикл" name="New Day Cycle"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/ru/menu_settings_gear.xml b/indra/newview/skins/default/xui/ru/menu_settings_gear.xml new file mode 100644 index 0000000000..9d17424b85 --- /dev/null +++ b/indra/newview/skins/default/xui/ru/menu_settings_gear.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_gear"> + <menu_item_call label="Редактировать" name="edit_settings"/> + <menu_item_call label="Применить только к Ñебе" name="Settings Apply Local"/> + <menu_item_call label="Применить к учаÑтку" name="Settings Apply Parcel"/> + <menu_item_call label="Применить к региону" name="Settings Apply Region"/> + <menu_item_call label="Копировать" name="copy_settings"/> + <menu_item_call label="Ð’Ñтавить" name="paste_settings"/> + <menu_item_call label="Копировать UUID" name="copy_uuid"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/ru/menu_viewer.xml b/indra/newview/skins/default/xui/ru/menu_viewer.xml index 876972ba24..8361464f4c 100644 --- a/indra/newview/skins/default/xui/ru/menu_viewer.xml +++ b/indra/newview/skins/default/xui/ru/menu_viewer.xml @@ -77,30 +77,15 @@ <menu_item_check label="СвойÑтва учаÑтка" name="Parcel Properties"/> <menu_item_check label="Меню «Дополнительно»" name="Show Advanced Menu"/> </menu> - <menu label="Солнце" name="Sun"> + <menu label="ÐžÐºÑ€ÑƒÐ¶Ð°ÑŽÑ‰Ð°Ñ Ñреда" name="Environment"> <menu_item_check label="ВоÑход" name="Sunrise"/> <menu_item_check label="Полдень" name="Noon"/> <menu_item_check label="Закат" name="Sunset"/> <menu_item_check label="Полночь" name="Midnight"/> - <menu_item_check label="ИÑпользовать наÑтройки региона" name="Use Region Settings"/> - </menu> - <menu label="Редактор Ñреды" name="Environment Editor"> - <menu_item_call label="ÐаÑтройки Ñреды..." name="Environment Settings"/> - <menu label="ÐаÑтройки воды" name="Water Presets"> - <menu_item_call label="ÐÐ¾Ð²Ð°Ñ Ð½Ð°Ñтройка..." name="new_water_preset"/> - <menu_item_call label="Изменить наÑтройку..." name="edit_water_preset"/> - <menu_item_call label="Удалить наÑтройку..." name="delete_water_preset"/> - </menu> - <menu label="ÐаÑтройки неба" name="Sky Presets"> - <menu_item_call label="ÐÐ¾Ð²Ð°Ñ Ð½Ð°Ñтройка..." name="new_sky_preset"/> - <menu_item_call label="Изменить наÑтройку..." name="edit_sky_preset"/> - <menu_item_call label="Удалить наÑтройку..." name="delete_sky_preset"/> - </menu> - <menu label="Суточные наÑтройки" name="Day Presets"> - <menu_item_call label="ÐÐ¾Ð²Ð°Ñ Ð½Ð°Ñтройка..." name="new_day_preset"/> - <menu_item_call label="Изменить наÑтройку..." name="edit_day_preset"/> - <menu_item_call label="Удалить наÑтройку..." name="delete_day_preset"/> - </menu> + <menu_item_check label="ИÑпользование окружающей Ñреды" name="Use Shared Environment"/> + <menu_item_call label="ÐœÐ¾Ñ Ñреда…" name="my_environs"/> + <menu_item_call label="Личное оÑвещение..." name="adjustment_tool"/> + <menu_item_check label="ПриоÑтановить движение облаков" name="pause_clouds"/> </menu> </menu> <menu label="СтроительÑтво" name="BuildTools"> @@ -343,6 +328,9 @@ <menu_item_check label="ÐвтоматичеÑкие альфа-маÑки (не отложенные)" name="Automatic Alpha Masks (non-deferred)"/> <menu_item_check label="ТекÑтуры анимаций" name="Animation Textures"/> <menu_item_check label="Отключить текÑтуры" name="Disable Textures"/> + <menu_item_check label="Отключить окружающую Ñреду" name="Disable Ambient"/> + <menu_item_check label="Отключить Ñолнечный Ñвет" name="Disable Sunlight"/> + <menu_item_check label="Отключить локальный Ñвет" name="Disable Local Lights"/> <menu_item_check label="ТекÑтуры в полном разрешении" name="Rull Res Textures"/> <menu_item_check label="Ð’Ð¸Ð·ÑƒÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¸Ñоединенных иÑточников Ñвета" name="Render Attached Lights"/> <menu_item_check label="Ð’Ð¸Ð·ÑƒÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¸Ñоединенных чаÑтиц" name="Render Attached Particles"/> @@ -480,6 +468,7 @@ <menu_item_call label="Юбка" name="Skirt"/> <menu_item_call label="Ðльфа" name="Alpha"/> <menu_item_call label="Тату" name="Tattoo"/> + <menu_item_call label="УниверÑальные" name="Universal"/> <menu_item_call label="Физика" name="Physics"/> <menu_item_call label="Ð’ÑÑ Ð¾Ð´ÐµÐ¶Ð´Ð°" name="All Clothes"/> </menu> diff --git a/indra/newview/skins/default/xui/ru/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/ru/menu_wearable_list_item.xml index 2832e17b7d..caef7db458 100644 --- a/indra/newview/skins/default/xui/ru/menu_wearable_list_item.xml +++ b/indra/newview/skins/default/xui/ru/menu_wearable_list_item.xml @@ -3,6 +3,7 @@ <menu_item_call label="Заменить" name="wear_replace"/> <menu_item_call label="Ðадеть" name="wear_wear"/> <menu_item_call label="Добавить" name="wear_add"/> + <menu_item_call label="КоÑнутьÑÑ" name="touch" /> <menu_item_call label="СнÑть / отÑоединить" name="take_off_or_detach"/> <menu_item_call label="ОтÑоединить" name="detach"/> <context_menu label="ПриÑоединить" name="wearable_attach_to"/> diff --git a/indra/newview/skins/default/xui/ru/menu_wearing_gear.xml b/indra/newview/skins/default/xui/ru/menu_wearing_gear.xml index c2351fbfff..01491b9694 100644 --- a/indra/newview/skins/default/xui/ru/menu_wearing_gear.xml +++ b/indra/newview/skins/default/xui/ru/menu_wearing_gear.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <toggleable_menu name="Gear Wearing"> - <menu_item_call label="Изменить коÑтюм" name="edit"/> + <menu_item_call label="КоÑнутьÑÑ" name="touch"/> + <menu_item_call label="Изменить" name="edit_item"/> + <menu_item_call label="Изменить коÑтюм" name="edit_outfit"/> <menu_item_call label="СнÑть" name="takeoff"/> <menu_item_call label="Копировать ÑпиÑок коÑтюмов в буфер обмена" name="copy"/> </toggleable_menu> diff --git a/indra/newview/skins/default/xui/ru/menu_wearing_tab.xml b/indra/newview/skins/default/xui/ru/menu_wearing_tab.xml index 1e32090c2a..e68b67bb33 100644 --- a/indra/newview/skins/default/xui/ru/menu_wearing_tab.xml +++ b/indra/newview/skins/default/xui/ru/menu_wearing_tab.xml @@ -1,8 +1,9 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="Wearing"> + <menu_item_call label="КоÑнутьÑÑ" name="touch_attach"/> <menu_item_call label="СнÑть" name="take_off"/> <menu_item_call label="ОтÑоединить" name="detach"/> - <menu_item_call label="Изменить коÑтюм" name="edit"/> + <menu_item_call label="Изменить коÑтюм" name="edit_outfit"/> <menu_item_call label="Изменить" name="edit_item"/> <menu_item_call label="Показать оригинал" name="show_original"/> </context_menu> diff --git a/indra/newview/skins/default/xui/ru/notifications.xml b/indra/newview/skins/default/xui/ru/notifications.xml index 08accc39fe..bfcda798be 100644 --- a/indra/newview/skins/default/xui/ru/notifications.xml +++ b/indra/newview/skins/default/xui/ru/notifications.xml @@ -266,6 +266,10 @@ Отобрать у выбранных жителей права на изменение? <usetemplate name="okcancelbuttons" notext="Ðет" yestext="Да"/> </notification> + <notification name="GroupNameLengthWarning"> + Ðазвание группы может Ñодержать от [MIN_LEN] до [MAX_LEN] Ñимволов. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="UnableToCreateGroup"> Ðевозможно Ñоздать группу. [MESSAGE] @@ -360,7 +364,7 @@ У Ð²Ð°Ñ Ð½Ðµ хватает L$ Ð´Ð»Ñ Ð²ÑтуплениÑ. </notification> <notification name="CreateGroupCost"> - Создание Ñтой группы Ñтоит L$100. + Создание Ñтой группы Ñтоит L$[COST]. Ð’ группе должно быть более одного учаÑтника, иначе она будет удалена. ПриглаÑите учаÑтников в ближайшие 48 чаÑов. <usetemplate canceltext="Отмена" name="okcancelbuttons" notext="Отмена" yestext="Создать группу за L$100"/> @@ -500,6 +504,9 @@ <notification name="ErrorEncodingSnapshot"> Ошибка при кодировке Ñнимка. </notification> + <notification name="ErrorCannotAffordUpload"> + Чтобы загрузить Ñтот предмет, вам нужно L$[COST]. + </notification> <notification name="ErrorPhotoCannotAfford"> ТребуетÑÑ L$[COST] Ð´Ð»Ñ ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ñ„Ð¾Ñ‚Ð¾ в вашем инвентаре. Купите L$ или Ñохраните фото на компьютере. </notification> @@ -1436,9 +1443,9 @@ <usetemplate name="okcancelbuttons" notext="Продолжить" yestext="Создать аккаунт..."/> </notification> <notification name="LoginPacketNeverReceived"> - Возникли неполадки при подключении. Возможно, проблема Ñ Ð²Ð°ÑˆÐ¸Ð¼ подключением к интернету или [SECOND_LIFE_GRID]. + Возникли неполадки при подключении. Возможно, проблема Ñ Ð²Ð°ÑˆÐ¸Ð¼ подключением к интернету или [SECOND_LIFE_GRID] временно недоÑтупна. -Варианты ваших дейÑтвий: проверьте подключение к интернету и повторите попытку через неÑколько минут, нажмите кнопку «Справка» Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° к [SUPPORT_SITE] или кнопку «ТелепортациÑ», чтобы телепортироватьÑÑ Ð´Ð¾Ð¼Ð¾Ð¹. +Ð’Ñ‹ можете проверить подключение к интернету, повторить попытку через неÑколько минут, нажать кнопку «Справка» Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° на [SUPPORT_SITE] или нажать кнопку «ТелепортациÑ», чтобы телепортироватьÑÑ Ð´Ð¾Ð¼Ð¾Ð¹. <url name="url"> http://secondlife.com/support/ </url> @@ -1612,22 +1619,22 @@ [DOWNLOAD_PATH]. </notification> <notification name="RequiredUpdate"> - Ð”Ð»Ñ Ð²Ñ…Ð¾Ð´Ð° необходима верÑÐ¸Ñ \[VERSION]. + Ð”Ð»Ñ Ð²Ñ…Ð¾Ð´Ð° необходима верÑÐ¸Ñ [VERSION]. Скачайте обновление Ñ Ð²ÐµÐ±-Ñайта https://secondlife.com/support/downloads/ <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="PauseForUpdate"> - Ð”Ð»Ñ Ð²Ñ…Ð¾Ð´Ð° необходима верÑÐ¸Ñ \[VERSION]. + Ð”Ð»Ñ Ð²Ñ…Ð¾Ð´Ð° необходима верÑÐ¸Ñ [VERSION]. Ðажмите OK Ð´Ð»Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ¸ и уÑтановки. <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="OptionalUpdateReady"> - ВерÑÐ¸Ñ \[VERSION] загружена и готова к уÑтановке. + ВерÑÐ¸Ñ [VERSION] загружена и готова к уÑтановке. Ðажмите OK Ð´Ð»Ñ ÑƒÑтановки. <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="PromptOptionalUpdate"> - ВерÑÐ¸Ñ \[VERSION] загружена и готова к уÑтановке. + ВерÑÐ¸Ñ [VERSION] загружена и готова к уÑтановке. Продолжить? <usetemplate canceltext="Ðе ÑейчаÑ" name="yesnocancelbuttons" notext="ПропуÑтить" yestext="УÑтановить"/> </notification> @@ -1738,11 +1745,14 @@ <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="GroupLimitInfo"> - МакÑимальное чиÑло групп Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð±Ð°Ð·Ð¾Ð²Ð¾Ð³Ð¾ аккаунта ÑоÑтавлÑет [MAX_BASIC], -а Ð´Ð»Ñ [https://secondlife.com/premium/ премиум]-аккаунта – [MAX_PREMIUM]. -Чтобы вÑтупать в новые группы поÑле возврата к базовому аккаунту, вам придетÑÑ Ð²Ñ‹Ð¹Ñ‚Ð¸ из чаÑти групп, чтобы их общее чиÑло было меньше [MAX_BASIC]. - -[https://secondlife.com/my/account/membership.php Перейдите на премиум-членÑтво!] + Резиденты Ñ Ð‘Ð°Ð·Ð¾Ð²Ñ‹Ð¼ аккаунтом могут приÑоединитьÑÑ Ðº [MAX_BASIC] группам. +Премиум аккаунт разрешает до [MAX_PREMIUM]. [https://secondlife.com/my/account/membership.php? Узнайте больше или раÑширьте Ñвой аккаунт] + <usetemplate name="okbutton" yestext="Закрыть"/> + </notification> + <notification name="GroupLimitInfoPlus"> + Резиденты Ñ Ð‘Ð°Ð·Ð¾Ð²Ñ‹Ð¼ аккаунтом могут приÑоединитьÑÑ Ðº [MAX_BASIC] группам. +Премиум аккаунт разрешает до [MAX_PREMIUM]. Премиум ÐŸÐ»ÑŽÑ Ð°ÐºÐºÐ°ÑƒÐ½Ñ‚ разрешает до [MAX_PREMIUM_PLUS]. +[https://secondlife.com/my/account/membership.php? Узнайте больше или раÑширьте Ñвой аккаунт] <usetemplate name="okbutton" yestext="Закрыть"/> </notification> <notification name="KickUser"> @@ -1959,6 +1969,11 @@ При ÑнÑтии Ñтой опции вы можете удалить ограничениÑ, которые владельцы учаÑтка добавили Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð²Ð¾ÐºÐ°Ñ†Ð¸Ð¾Ð½Ð½Ñ‹Ñ… Ñообщений, ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð´ÐµÐ½Ñ†Ð¸Ð°Ð»ÑŒÐ½Ð¾Ñти и защиты неÑовершеннолетных жителей от материала Ð´Ð»Ñ Ð²Ð·Ñ€Ð¾Ñлых. При необходимоÑти обÑудите Ñо Ñвоими владельцами учаÑтков. <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="EstateParcelEnvironmentOverride"> + При ÑнÑтии Ñтой опции вы можете удалить пользовательÑкую Ñреду, которую владельцы учаÑтка добавили Ð´Ð»Ñ Ñвоих учаÑтков. При необходимоÑти обÑудите Ñо Ñвоими владельцами учаÑтков. +Ð’Ñ‹ хотите продолжить? + <usetemplate name="okcancelbuttons" notext="Отмена" yestext="OK"/> + </notification> <notification name="RegionEntryAccessBlocked"> Ð’Ñ‹ пытаетеÑÑŒ поÑетить регион, контент в котором не ÑоответÑтвует вашим наÑтройкам. Попробуйте изменить наÑтройки в меню «Я > ÐаÑтройки > Общие». <usetemplate name="okbutton" yestext="OK"/> @@ -2438,7 +2453,15 @@ Ðтот файл Ñуточного цикла ÑÑылаетÑÑ Ð½Ð° отÑутÑтвующий файл неба: [SKY]. </notification> <notification name="WLRegionApplyFail"> - Ðе удалоÑÑŒ применить наÑтройки к региону. Попробуйте покинуть регион, а затем вернутьÑÑ Ð² него. Причина неполадки: [FAIL_REASON] + К Ñожалению наÑтройки не применимы к Ñтому региону. Причина: [FAIL_REASON] + </notification> + <notification name="WLLocalTextureDayBlock"> + МеÑÑ‚Ð½Ð°Ñ Ñ‚ÐµÐºÑтура иÑпользуетÑÑ Ð² режиме Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ [TRACK], â„– фрейма [FRAMENO] ([FRAMENO]%) на поле [FIELD]. +ÐаÑтройки невозможно Ñохранить Ñ Ð¸Ñпользованием меÑтных текÑтур. + </notification> + <notification name="WLLocalTextureFixedBlock"> + МеÑÑ‚Ð½Ð°Ñ Ñ‚ÐµÐºÑтура иÑпользуетÑÑ Ð½Ð° поле [FIELD]. +ÐаÑтройки невозможно Ñохранить Ñ Ð¸Ñпользованием меÑтных текÑтур. </notification> <notification name="EnvCannotDeleteLastDayCycleKey"> Ðевозможно удалить поÑледний ключ в Ñтом Ñуточном цикле: пуÑтой Ñуточный цикл не разрешен. Следует изменить поÑледний оÑтавшийÑÑ ÐºÐ»ÑŽÑ‡, а не удалÑть его и Ñоздавать новый. @@ -3290,6 +3313,22 @@ Ваш Ð³Ð¾Ð»Ð¾Ñ Ð·Ð°Ð³Ð»ÑƒÑˆÐµÐ½ модератором. <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FailedToGetBenefits"> + К Ñожалению, в Ñтой ÑеÑÑии мы не Ñмогли получить информацию о преимущеÑтвах аккаунта. Такое не должно проиÑходить в нормально работающей Ñреде. ПожалуйÑта, ÑвÑжитеÑÑŒ Ñо Ñлужбой поддержки. Ðта ÑеÑÑÐ¸Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ð°ÐµÑ‚ некорректно, поÑтому мы рекомендуем вам перезапуÑтить программу. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="BulkUploadCostConfirmation"> + Ðтим дейÑтвием загружаетÑÑ [COUNT] предметов на общую ÑтоимоÑть L$[COST]. Ð’Ñ‹ хотите продолжить загрузку? + <usetemplate name="okcancelbuttons" notext="Отмена" yestext="Загрузить"/> + </notification> + <notification name="BulkUploadNoCompatibleFiles"> + Выбранные файлы не могут быть загружены группой. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="BulkUploadIncompatibleFiles"> + Ðекоторые из выбранных файлов не могут быть загружены группой. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="UploadCostConfirmation"> Ðта передача будет Ñтоить L$[PRICE]. Продолжить передачу? <usetemplate name="okcancelbuttons" notext="Отмена" yestext="Передать"/> @@ -4389,4 +4428,76 @@ [REASON] <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FailedToFindSettings"> + Ðе удалоÑÑŒ загрузить наÑтройки Ð´Ð»Ñ [NAME] из базы данных. + </notification> + <notification name="FailedToLoadSettingsApply"> + Ðевозможно применить Ñти наÑтройки Ð´Ð»Ñ Ñтой Ñреды. + </notification> + <notification name="FailedToBuildSettingsDay"> + Ðевозможно применить Ñти наÑтройки Ð´Ð»Ñ Ñтой Ñреды. + </notification> + <notification name="NoEnvironmentSettings"> + Ðтот регион не поддерживает наÑтройки окружающей Ñреды. + </notification> + <notification label="Сохранить коÑтюм" name="SaveSettingAs"> + Сохранить текущие наÑтройки как: + <form name="form"> + <input name="message"> + [DESC] (новый) + </input> + <button name="OK" text="OK"/> + <button name="Cancel" text="Отмена"/> + </form> + </notification> + <notification name="WLImportFail"> + Ðевозможно импортировать уÑтаревшие уÑтановки [NAME] Ð´Ð»Ñ Ñффекта Windlight из +[FILE]. + +[REASONS] + </notification> + <notification name="WLParcelApplyFail"> + Ðевозможно уÑтановить наÑтройки Ñреды Ð´Ð»Ñ Ñтого учаÑтка. +ВвеÑти или выбрать учаÑток, который вы можете модифицировать. + </notification> + <notification name="SettingsUnsuported"> + ÐаÑтройки окружающей Ñреды не поддерживаютÑÑ Ð² Ñтом регионе. +Перейдите в регион Ñ Ð¿Ð¾Ð´Ð´ÐµÑ€Ð¶Ð¸Ð²Ð°ÐµÐ¼Ñ‹Ð¼Ð¸ наÑтройками и повторите дейÑтвие. + </notification> + <notification name="SettingsConfirmLoss"> + Ð’Ñ‹ потерÑете изменениÑ, внеÑенные в Ñтот [TYPE] под именем "[NAME]". +Ð’Ñ‹ уверены, что хотите продолжить? + <usetemplate ignoretext="Ð’Ñ‹ уверены, что хотите Ñделать наÑтройки непереноÑимыми?" name="okcancelignore" notext="Ðет" yestext="Да"/> + </notification> + <notification name="SettingsConfirmReset"> + Ð’Ñ‹ ÑобираетеÑÑŒ удалить вÑе примененные наÑтройки. +Ð’Ñ‹ уверены, что хотите продолжить? + <usetemplate name="okcancelbuttons" notext="Ðет" yestext="Да"/> + </notification> + <notification name="PersonalSettingsConfirmReset"> + Ð’Ñ‹ ÑобираетеÑÑŒ удалить вÑе примененные наÑтройки Ð´Ð»Ñ Ð»Ð¸Ñ‡Ð½Ð¾Ð³Ð¾ оÑвещениÑ. +Ð’Ñ‹ уверены, что хотите продолжить? + <usetemplate name="okcancelbuttons" notext="Ðет" yestext="Да"/> + </notification> + <notification name="SettingsMakeNoTrans"> + Ð’Ñ‹ ÑобираетеÑÑŒ импортировать непереноÑимые наÑтройки в Ñтот Ñуточный цикл. Ð’ Ñлучае дальнейшего Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² Ñтих параметрах они также Ñтанут непереноÑимыми. + +Ðто изменение не подлежит отмене. + +Ð’Ñ‹ уверены, что хотите продолжить? + <usetemplate ignoretext="Ð’Ñ‹ уверены, что хотите Ñделать наÑтройки непереноÑимыми?" name="okcancelignore" notext="Ðет" yestext="Да"/> + </notification> + <notification name="NoEditFromLibrary"> + Ð’Ñ‹ не можете редактировать наÑтройки непоÑредÑтвенно из библиотеки. +Скопировать в Ñвой ÑобÑтвенный инвентарь и повторить попытку. + </notification> + <notification name="EnvironmentApplyFailed"> + Мы ÑтолкнулиÑÑŒ Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼Ð¾Ð¹ Ñ Ñтими наÑтройками. Их невозможно Ñохранить или применить в данный момент. + </notification> + <notification name="TrackLoadFailed"> + Ðевозможно загрузить режим Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² [TRACK]. + </notification> + <notification name="TrackLoadMismatch"> + Ðевозможно загрузить режим Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸Ð· [TRACK1] в [TRACK2]. + </notification> </notifications> diff --git a/indra/newview/skins/default/xui/ru/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/ru/panel_edit_tattoo.xml index 874d5f8bc4..ed5312b723 100644 --- a/indra/newview/skins/default/xui/ru/panel_edit_tattoo.xml +++ b/indra/newview/skins/default/xui/ru/panel_edit_tattoo.xml @@ -1,9 +1,11 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_tattoo_panel"> - <panel name="avatar_tattoo_color_panel"> - <texture_picker label="Тату на голове" name="Head Tattoo" tool_tip="Щелкните картинку, чтобы выбрать ее"/> - <texture_picker label="Тату вверху" name="Upper Tattoo" tool_tip="Щелкните картинку, чтобы выбрать ее"/> - <texture_picker label="Тату внизу" name="Lower Tattoo" tool_tip="Щелкните картинку, чтобы выбрать ее"/> - <color_swatch label="Цвет/оттенок" name="Color/Tint" tool_tip="Щелкните Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° цвета"/> - </panel> + <scroll_container name="avatar_tattoo_scroll"> + <panel name="avatar_tattoo_color_panel"> + <texture_picker label="Тату на голове" name="Head Tattoo" tool_tip="Щелкнуть Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° изображениÑ"/> + <texture_picker label="Тату на верхних чаÑÑ‚ÑÑ… тела" name="Upper Tattoo" tool_tip="Щелкнуть Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° изображениÑ"/> + <texture_picker label="Тату на нижних чаÑÑ‚ÑÑ… тела" name="Lower Tattoo" tool_tip="Щелкнуть Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° изображениÑ"/> + <color_swatch label="Цвет/оттенок" name="Color/Tint" tool_tip="Щелкнуть Ð´Ð»Ñ Ð¿Ð¾ÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð¿Ð°Ð»Ð¸Ñ‚Ñ€Ñ‹ цветов"/> + </panel> + </scroll_container> </panel> diff --git a/indra/newview/skins/default/xui/ru/panel_edit_universal.xml b/indra/newview/skins/default/xui/ru/panel_edit_universal.xml new file mode 100644 index 0000000000..647d1aa9e7 --- /dev/null +++ b/indra/newview/skins/default/xui/ru/panel_edit_universal.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel name="edit_universal_panel"> + <scroll_container name="avatar_universal_scroll"> + <panel name="avatar_universal_color_panel"> + <texture_picker label="Тату на голове" name="Head Universal Tattoo" tool_tip="Щелкнуть Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° изображениÑ"/> + <texture_picker label="Тату на верхних чаÑÑ‚ÑÑ… тела" name="Upper Universal Tattoo" tool_tip="Щелкнуть Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° изображениÑ"/> + <texture_picker label="Тату на нижних чаÑÑ‚ÑÑ… тела" name="Lower Universal Tattoo" tool_tip="Щелкнуть Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° изображениÑ"/> + <texture_picker label="Тату на юбке" name="Skirt Tattoo" tool_tip="Щелкнуть Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° изображениÑ"/> + <texture_picker label="Тату волоÑ" name="Hair Tattoo" tool_tip="Щелкнуть Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° изображениÑ"/> + <texture_picker label="Тату глаз" name="Eyes Tattoo" tool_tip="Щелкнуть Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° изображениÑ"/> + <texture_picker label="Тату на левой руке" name="Left Arm Tattoo" tool_tip="Щелкнуть Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° изображениÑ"/> + <texture_picker label="Тату на левой ноге" name="Left Leg Tattoo" tool_tip="Щелкнуть Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° изображениÑ"/> + <texture_picker label="Тату Aux1" name="Aux1 Tattoo" tool_tip="Щелкнуть Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° изображениÑ"/> + <texture_picker label="Тату Aux2" name="Aux2 Tattoo" tool_tip="Щелкнуть Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° изображениÑ"/> + <texture_picker label="Тату Aux3" name="Aux3 Tattoo" tool_tip="Щелкнуть Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° изображениÑ"/> + <color_swatch label="Цвет/оттенок" name="Color/Tint" tool_tip="Щелкнуть Ð´Ð»Ñ Ð¿Ð¾ÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð¿Ð°Ð»Ð¸Ñ‚Ñ€Ñ‹ цветов"/> + </panel> + </scroll_container> +</panel> diff --git a/indra/newview/skins/default/xui/ru/panel_edit_wearable.xml b/indra/newview/skins/default/xui/ru/panel_edit_wearable.xml index 79130a9c80..cede43f859 100644 --- a/indra/newview/skins/default/xui/ru/panel_edit_wearable.xml +++ b/indra/newview/skins/default/xui/ru/panel_edit_wearable.xml @@ -45,6 +45,9 @@ <string name="edit_tattoo_title"> Изменение тату </string> + <string name="edit_universal_title"> + Редактирование универÑальных + </string> <string name="edit_physics_title"> Изменение физики </string> @@ -93,6 +96,9 @@ <string name="tattoo_desc_text"> Тату: </string> + <string name="universal_desc_text"> + УниверÑальные: + </string> <string name="physics_desc_text"> Физика: </string> diff --git a/indra/newview/skins/default/xui/ru/panel_outbox_inventory.xml b/indra/newview/skins/default/xui/ru/panel_outbox_inventory.xml deleted file mode 100644 index 0095d48af9..0000000000 --- a/indra/newview/skins/default/xui/ru/panel_outbox_inventory.xml +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<outbox_inventory_panel name="inventory_outbox" tool_tip="Перетащите вещи Ñюда, чтобы подготовить их Ð´Ð»Ñ Ñ€Ð°Ð·Ð¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ð½Ð° витрине вашего магазина"/> diff --git a/indra/newview/skins/default/xui/ru/panel_people.xml b/indra/newview/skins/default/xui/ru/panel_people.xml index 0fdc06fb32..0812eb7433 100644 --- a/indra/newview/skins/default/xui/ru/panel_people.xml +++ b/indra/newview/skins/default/xui/ru/panel_people.xml @@ -18,7 +18,7 @@ <string name="no_groups_msg" value="Ищете группу, чтобы приÑоединитьÑÑ Ðº ней? ВоÑпользуйтеÑÑŒ [secondlife:///app/search/groups поиÑком]."/> <string name="MiniMapToolTipMsg" value="[REGION](Двойной щелчок открывает карту, shift+перетÑгивание – обзор)"/> <string name="AltMiniMapToolTipMsg" value="[REGION](Двойной щелчок – телепортациÑ, shift+перетÑгивание – обзор)"/> - <string name="GroupCountWithInfo" value="Ð’Ñ‹ входите в [COUNT] групп и можете приÑоединитьÑÑ ÐµÑ‰Ðµ к [REMAINING]. [secondlife:/// Хотите еще?]"/> + <string name="GroupCountWithInfo" value="Ð’Ñ‹ ÑоÑтоите в [COUNT] группах, и можете приÑоединитьÑÑ ÐµÑ‰Ðµ к [REMAINING]. [secondlife:/// РаÑширить Ñвои лимиты]"/> <tab_container name="tabs"> <panel label="РЯДОМ" name="nearby_panel"> <panel label="bottom_panel" name="nearby_buttons_panel"> @@ -51,7 +51,7 @@ <dnd_button name="minus_btn" tool_tip="Покинуть выбранную группу"/> </panel> <text name="groupcount"> - Ð’Ñ‹ входите в [COUNT] групп и можете приÑоединитьÑÑ ÐµÑ‰Ðµ к [REMAINING]. + Ð’Ñ‹ ÑоÑтоите в [COUNT] группах, и можете приÑоединитьÑÑ ÐµÑ‰Ðµ к [REMAINING]. </text> </panel> <panel label="ÐЕДÐÐ’ÐИЕ" name="recent_panel"> diff --git a/indra/newview/skins/default/xui/ru/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/ru/panel_preferences_advanced.xml index dd0cf8e172..79d5cb7960 100644 --- a/indra/newview/skins/default/xui/ru/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/ru/panel_preferences_advanced.xml @@ -28,5 +28,5 @@ <check_box label="Выбор Ñетки при входе" name="show_grid_selection_check"/> <check_box label="Показывать раÑширенное меню" name="show_advanced_menu_check"/> <check_box label="Показать меню разработчика" name="show_develop_menu_check"/> - <button label="Стандартные Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð° Ñоздание" name="default_creation_permissions"/> + <button label="Стандартные Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð° Ñоздание" name="default_creation_permissions" width="235"/> </panel> diff --git a/indra/newview/skins/default/xui/ru/panel_preferences_chat.xml b/indra/newview/skins/default/xui/ru/panel_preferences_chat.xml index c2fcac8840..03a714f266 100644 --- a/indra/newview/skins/default/xui/ru/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/ru/panel_preferences_chat.xml @@ -5,15 +5,15 @@ <check_box initial_value="true" label="ВоÑпроизводить анимацию ввода текÑта при общении" name="play_typing_animation"/> <check_box label="ОтправлÑть мне ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾ почте, когда Ð¼ÐµÐ½Ñ Ð½ÐµÑ‚ в Ñети" name="send_im_to_email"/> <check_box label="Только Ð´Ñ€ÑƒÐ·ÑŒÑ Ð¸ группы могут звонить мне и отправлÑть IM" name="voice_call_friends_only_check"/> - <text name="font_size"> + <text name="font_size" left="361"> Размер шрифта: </text> - <combo_box name="chat_font_size"> + <combo_box name="chat_font_size" left="361"> <item label="Мелкий" name="Small" value="0"/> <item label="Средний" name="Medium" value="1"/> <item label="Крупный" name="Large" value="2"/> </combo_box> - <check_box label="Чат в пузырьках" name="bubble_text_chat"/> + <check_box label="Чат в пузырьках" name="bubble_text_chat" left_delta="19"/> </panel> <panel name="im_notification_settings"> <text name="friend_ims"> diff --git a/indra/newview/skins/default/xui/ru/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/ru/panel_preferences_graphics1.xml index 4524fb4d43..f392a1f0b7 100644 --- a/indra/newview/skins/default/xui/ru/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/ru/panel_preferences_graphics1.xml @@ -32,7 +32,7 @@ </text> <check_box initial_value="true" label="Ð’Ñегда риÑовать друзей" name="AlwaysRenderFriends"/> <button label="ИÑключениÑ..." name="RenderExceptionsButton"/> - <button label="Сохранить наÑтройки как преÑет..." name="PrefSaveButton"/> + <button label="Сохранить наÑтройки как преÑет..." name="PrefSaveButton" width="210"/> <button label="Загрузить преÑет..." name="PrefLoadButton"/> min_val="0,125" <button label="Удалить преÑет..." name="PrefDeleteButton"/> diff --git a/indra/newview/skins/default/xui/ru/panel_preferences_setup.xml b/indra/newview/skins/default/xui/ru/panel_preferences_setup.xml index d4d0ef9e7c..137e047d97 100644 --- a/indra/newview/skins/default/xui/ru/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/ru/panel_preferences_setup.xml @@ -14,7 +14,7 @@ <text name="Web:"> Браузер: </text> - <radio_group name="preferred_browser_behavior"> + <radio_group name="preferred_browser_behavior" left_delta="30"> <radio_item label="ИÑпользуйте вÑтроенный браузер Ð´Ð»Ñ Ð²Ñех ÑÑылок" name="internal" tool_tip="Будет иÑпользоватьÑÑ Ð±Ñ€Ð°ÑƒÐ·ÐµÑ€, заданный в ÑиÑтеме по умолчанию. Ðе рекомендуетÑÑ, еÑли [APP_NAME] работает в полноÑкранном режиме." value="0"/> <radio_item label="Ð”Ð»Ñ ÑÑылок Second Life Ñледует иÑпользовать только вÑтроенный браузер" name="external" tool_tip="ИÑпользуйте вÑтроенный браузер Ð´Ð»Ñ Ñправки, веб-ÑÑылок и Ñ‚.д. Ð”Ð»Ñ ÑÑылок LindenLab/Second Life Ñледует иÑпользовать только вÑтроенный браузер." value="1"/> <radio_item label="Ð”Ð»Ñ Ð²Ñех ÑÑылок Ñледует иÑпользовать вÑтроенный браузер" name="external_all" tool_tip="Ð”Ð»Ñ Ð¿Ñ€Ð¾Ñмотра Ñправки, ÑÑылок на веб-Ñтраницы и Ñ‚. д. будет иÑпользоватьÑÑ Ð²Ñтроенный браузер. Ðтот браузер открываетÑÑ ÐºÐ°Ðº новое окно в [APP_NAME]." value="2"/> diff --git a/indra/newview/skins/default/xui/ru/panel_region_environment.xml b/indra/newview/skins/default/xui/ru/panel_region_environment.xml index 8057176cfb..fcf1548ae5 100644 --- a/indra/newview/skins/default/xui/ru/panel_region_environment.xml +++ b/indra/newview/skins/default/xui/ru/panel_region_environment.xml @@ -1,33 +1,116 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Среда" name="panel_env_info"> - <text name="water_settings_title"> - ÐаÑтройки воды и неба/Ñуточного цикла определÑÑŽÑ‚, каким поÑетители увидÑÑ‚ ваш регион. Ð”Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ - </text> - <radio_group name="region_settings_radio_group"> - <radio_item label="ИÑпользовать наÑтройки Second Life по умолчанию" name="use_sl_default_settings"/> - <radio_item label="ИÑпользовать Ñледующие наÑтройки" name="use_my_settings"/> - </radio_group> - <panel name="user_environment_settings"> - <text name="water_settings_title"> - ÐаÑтройка воды - </text> - <combo_box name="water_settings_preset_combo"> - <combo_box.item label="-Выбор наÑтройки-" name="item0"/> - </combo_box> - <text name="sky_dayc_settings_title"> - Ðебо/Ñуточный цикл - </text> - <radio_group name="sky_dayc_settings_radio_group"> - <radio_item label="ЗафикÑированное небо" name="my_sky_settings"/> - <radio_item label="Суточный цикл" name="my_dayc_settings"/> - </radio_group> - <combo_box name="sky_settings_preset_combo"> - <combo_box.item label="-Выбор наÑтройки-" name="item0"/> - </combo_box> - <combo_box name="dayc_settings_preset_combo"> - <combo_box.item label="-Выбор наÑтройки-" name="item0"/> - </combo_box> - </panel> - <button label="Применить" name="apply_btn"/> - <button label="Отмена" name="cancel_btn"/> + <string name="str_label_use_default"> + ИÑпользовать наÑтройки по умолчанию + </string> + <string name="str_label_use_region"> + ИÑпользовать наÑтройки региона + </string> + <string name="str_altitude_desription"> + Ðебо [INDEX]([ALTITUDE]м) + </string> + <string name="str_no_parcel"> + Ðе выбрано ни одного учаÑтка. ÐаÑтройки Ñреды отключены. + </string> + <string name="str_cross_region"> + ÐаÑтройки окружающей Ñреды недоÑтупны в рамках Ñтого региона. + </string> + <string name="str_legacy"> + ÐаÑтройки Ñреды недоÑтупны Ð´Ð»Ñ Ñтого региона. + </string> + <string name="str_disallowed"> + УправлÑющий недвижимоÑтью не разрешает менÑть Ñреду вокруг учаÑтка в Ñтом регионе. + </string> + <string name="str_too_small"> + Чтобы поддерживать наÑтройки окружающей Ñреды учаÑток должен быть не менее 128 кв. метров. + </string> + <string name="str_empty"> + (пуÑто) + </string> + <string name="str_region_env"> + (Ñреда региона) + </string> + <layout_stack> + <layout_panel name="pnl_environment_disabled"> + <text name="txt_environment_disabled"> + ... + </text> + </layout_panel> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_current"> + <button label="[USEDEFAULT]" name="btn_usedefault"/> + <button label="ИÑпользовать инвентарь" name="btn_select_inventory"/> + <button label="ÐаÑтроить" name="btn_edit"/> + <check_box label="Владельцы учаÑтков могут менÑть окружающую Ñреду" name="chk_allow_override"/> + </layout_panel> + <layout_panel name="pnl_environment_length"> + <text name="lbl_apparent_time"> + [HH]:[MM][AP] ([PRC]%) + </text> + </layout_panel> + <layout_panel name="pnl_environment_buttons"/> + </layout_stack> + </layout_panel> + <layout_panel name="pnl_environment_altitudes"> + <panel name="pnl_alt1"> + <text name="txt_alt1"> + Ðебо [INDEX] + [ALTITUDE]м + </text> + <line_editor name="edt_invname_alt1"> + ÐеизвеÑтно + </line_editor> + <settings_drop_target name="sdt_alt1" tool_tip="Перетащить наÑтройки из Ð¸Ð½Ð²ÐµÐ½Ñ‚Ð°Ñ€Ñ Ð½Ð° Ñто целевое поле, чтобы выбрать его в качеÑтве неба на наÑтоÑщий момент."/> + </panel> + <panel name="pnl_alt2"> + <text name="txt_alt2"> + Ðебо [INDEX] + [ALTITUDE]м + </text> + <line_editor name="edt_invname_alt2"> + ÐеизвеÑтно + </line_editor> + <settings_drop_target name="sdt_alt2" tool_tip="Перетащить наÑтройки из Ð¸Ð½Ð²ÐµÐ½Ñ‚Ð°Ñ€Ñ Ð½Ð° Ñто целевое поле, чтобы выбрать его в качеÑтве неба на наÑтоÑщий момент."/> + </panel> + <panel name="pnl_alt3"> + <text name="txt_alt3"> + Ðебо [INDEX] + [ALTITUDE]м + </text> + <line_editor name="edt_invname_alt3"> + ÐеизвеÑтно + </line_editor> + <settings_drop_target name="sdt_alt3" tool_tip="Перетащить наÑтройки из Ð¸Ð½Ð²ÐµÐ½Ñ‚Ð°Ñ€Ñ Ð½Ð° Ñто целевое поле, чтобы выбрать его в качеÑтве неба на наÑтоÑщий момент."/> + </panel> + <multi_slider initial_value="0" name="sld_altitudes"> + <slider name="sld1" value="1000"/> + <slider name="sld2" value="2000"/> + <slider name="sld3" value="3000"/> + </multi_slider> + <panel name="pnl_ground"> + <text name="txt_ground"> + Ð—ÐµÐ¼Ð»Ñ + </text> + <line_editor name="edt_invname_ground"> + ÐеизвеÑтно + </line_editor> + <settings_drop_target name="sdt_ground" tool_tip="Перетащить наÑтройки из Ð¸Ð½Ð²ÐµÐ½Ñ‚Ð°Ñ€Ñ Ð½Ð° Ñто целевое поле Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° его в качеÑтве неба на уровне земли."/> + </panel> + <panel name="pnl_water"> + <text name="txt_water"> + Вода + </text> + <line_editor name="edt_invname_water"> + ÐеизвеÑтно + </line_editor> + <settings_drop_target name="sdt_water" tool_tip="Перетащить наÑтройки из Ð¸Ð½Ð²ÐµÐ½Ñ‚Ð°Ñ€Ñ Ð½Ð° Ñто целевое поле Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° его в качеÑтве воды на наÑтоÑщий момент."/> + </panel> + <button label="СброÑ" name="btn_rst_altitudes" tool_tip="СброÑить наÑтройки по умолчанию"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> </panel> diff --git a/indra/newview/skins/default/xui/ru/panel_settings_sky_atmos.xml b/indra/newview/skins/default/xui/ru/panel_settings_sky_atmos.xml new file mode 100644 index 0000000000..9c4c502694 --- /dev/null +++ b/indra/newview/skins/default/xui/ru/panel_settings_sky_atmos.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="ÐтмоÑфера и оÑвещение" name="panel_settings_sky_atmos"/> diff --git a/indra/newview/skins/default/xui/ru/panel_settings_sky_clouds.xml b/indra/newview/skins/default/xui/ru/panel_settings_sky_clouds.xml new file mode 100644 index 0000000000..46b4b10125 --- /dev/null +++ b/indra/newview/skins/default/xui/ru/panel_settings_sky_clouds.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Облака" name="panel_settings_sky_clouds"> + <layout_stack> + <layout_panel> + <slider label="X" name="cloud_density_x"/> + <slider label="Y" name="cloud_density_y"/> + <slider label="D" name="cloud_density_d"/> + <slider label="X" name="cloud_detail_x"/> + <slider label="Y" name="cloud_detail_y"/> + <slider label="D" name="cloud_detail_d"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/ru/panel_settings_sky_density.xml b/indra/newview/skins/default/xui/ru/panel_settings_sky_density.xml new file mode 100644 index 0000000000..8886ceb539 --- /dev/null +++ b/indra/newview/skins/default/xui/ru/panel_settings_sky_density.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="ПлотноÑть" name="panel_settings_sky_density"> + <layout_stack> + <layout_panel> + <slider label="ÐкÑпоненциальный член Ð ÑлеÑ:" name="rayleigh_exponential"/> + <slider label="ÐкÑÐ¿Ð¾Ð½ÐµÐ½Ñ†Ð¸Ð°Ð»ÑŒÐ½Ð°Ñ ÑˆÐºÐ°Ð»Ð° Ð ÑлеÑ:" name="rayleigh_exponential_scale"/> + <slider label="Линейный член Ð ÑлеÑ:" name="rayleigh_linear"/> + <slider label="ПоÑтоÑнный член Ð ÑлеÑ:" name="rayleigh_constant"/> + <slider label="МакÑÐ¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ð²Ñ‹Ñота Ð ÑлеÑ:" name="rayleigh_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="ÐкÑпоненциальный член Мие:" name="mie_exponential"/> + <slider label="ÐкÑÐ¿Ð¾Ð½ÐµÐ½Ñ†Ð¸Ð°Ð»ÑŒÐ½Ð°Ñ ÑˆÐºÐ°Ð»Ð° Мие:" name="mie_exponential_scale"/> + <slider label="Линейный член Мие:" name="mie_linear"/> + <slider label="ПоÑтоÑнный член Мие:" name="mie_constant"/> + <slider label="Ðнизо-фактор Мие:" name="mie_aniso_factor"/> + <slider label="МакÑÐ¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ð²Ñ‹Ñота Мие:" name="mie_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="ÐкÑпоненциальный член абÑорбции:" name="absorption_exponential"/> + <slider label="ÐкÑÐ¿Ð¾Ð½ÐµÐ½Ñ†Ð¸Ð°Ð»ÑŒÐ½Ð°Ñ ÑˆÐºÐ°Ð»Ð° абÑорбции:" name="absorption_exponential_scale"/> + <slider label="Линейный член абÑорбции:" name="absorption_linear"/> + <slider label="ПоÑтоÑнный член абÑорбции:" name="absorption_constant"/> + <slider label="МакÑÐ¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ð²Ñ‹Ñота абÑорбции:" name="absorption_max_altitude"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/ru/panel_settings_sky_sunmoon.xml b/indra/newview/skins/default/xui/ru/panel_settings_sky_sunmoon.xml new file mode 100644 index 0000000000..a494bbbe0e --- /dev/null +++ b/indra/newview/skins/default/xui/ru/panel_settings_sky_sunmoon.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Солнце и луна" name="panel_settings_sky_hbodies"> + <layout_stack> + <layout_panel name="sun_layout"> + <check_box label="Показать метку" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <layout_stack> + <layout_panel name="moon_layout"> + <check_box label="Показать метку" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/ru/panel_settings_water.xml b/indra/newview/skins/default/xui/ru/panel_settings_water.xml new file mode 100644 index 0000000000..de8b15ac19 --- /dev/null +++ b/indra/newview/skins/default/xui/ru/panel_settings_water.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Вода" name="panel_settings_water"> + <layout_stack name="water_stack1"> + <layout_panel> + <text name="FresnelOffsetText"> + Ð£Ð³Ð»Ð¾Ð²Ð°Ñ Ð·Ð°Ð²Ð¸ÑимоÑть: + </text> + </layout_panel> + <layout_panel> + <layout_stack name="water_stack2"> + <layout_panel> + <slider label="X:" name="water_normal_scale_x"/> + <slider label="Y:" name="water_normal_scale_y"/> + <slider label="Z:" name="water_normal_scale_z"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/ru/panel_tools_texture.xml b/indra/newview/skins/default/xui/ru/panel_tools_texture.xml index 707578cd07..5cd83c712f 100644 --- a/indra/newview/skins/default/xui/ru/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/ru/panel_tools_texture.xml @@ -1,11 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="ТекÑтура" name="Texture"> - <panel.string name="string repeats per meter"> - Повторений на метр - </panel.string> - <panel.string name="string repeats per face"> - Повторений на грань - </panel.string> <text name="color label"> Цвет </text> @@ -114,4 +108,5 @@ <spinner label="Смещение по горизонтали" name="shinyOffsetU"/> <spinner label="Смещение по вертикали" name="shinyOffsetV"/> <check_box initial_value="false" label="СоглаÑование" name="checkbox planar align" tool_tip="СоглаÑование текÑтур на вÑех выбранных гранÑÑ… по поÑледней выбранной грани. Должно быть выбрано наложение по плоÑкоÑÑ‚Ñм."/> + <button label="ВыровнÑть" label_selected="ВыровнÑть текущие Ñлои текÑтуры" name="button align textures" tool_tip="ВыровнÑть текущие Ñлои текÑтуры"/> </panel> diff --git a/indra/newview/skins/default/xui/ru/role_actions.xml b/indra/newview/skins/default/xui/ru/role_actions.xml index 1d526b90e4..314f6b9cb5 100644 --- a/indra/newview/skins/default/xui/ru/role_actions.xml +++ b/indra/newview/skins/default/xui/ru/role_actions.xml @@ -33,6 +33,7 @@ <action description="Изменение наÑтроек музыки и медиа" longdescription="Измените наÑтройки потоковой музыки и фильмов в окне «О земле» на вкладке «Медиа»." name="land change media" value="20"/> <action description="Включение-отключение Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð»Ð°Ð½Ð´ÑˆÐ°Ñ„Ñ‚Ð°" longdescription="Включение-отключение Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð»Ð°Ð½Ð´ÑˆÐ°Ñ„Ñ‚Ð°. *ПРЕДУПРЕЖДЕÐИЕ* Выбрав параметры «О земле» > вкладка «Параметры» > «Изменить ландшафт», любой пользователь может изменить форму земли, а также размещать или перемещать раÑÑ‚ÐµÐ½Ð¸Ñ Linden. Прежде чем назначить Ñту ÑпоÑобноÑть, убедитеÑÑŒ в целеÑообразноÑти Ñтого. Изменить ландшафт можно в окне «О земле» на вкладке «Параметры»." name="land edit" value="21"/> <action description="Включение-отключение различных наÑтроек «О земле > Параметры»" longdescription="Ð’ окне «О земле» на вкладке «Параметры» можно включить-отключить параметр «БезопаÑно (нет повреждений)», «Полет» и разрешить другим жителÑм изменÑть ландшафт, ÑтроительÑтво, Ñоздавать закладки и запуÑкать Ñкрипты Ð´Ð»Ñ Ð·ÐµÐ¼Ð»Ð¸ группы." name="land options" value="22"/> + <action description="Изменить уÑтановки окружающей Ñреды и Ñуточного цикла." longdescription="Изменить уÑтановки окружающей Ñреды и Ñуточного цикла от «О земле» > Вкладка окружающей Ñреды." name="land change environment" value="46"/> </action_set> <action_set description="К Ñтим ÑпоÑобноÑÑ‚Ñм отноÑитÑÑ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ðµ учаÑтникам обходить Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð½Ð° учаÑтках группы." name="Parcel Powers"> <action description="Ð’Ñегда разрешено изменение ландшафта" longdescription="УчаÑтники роли Ñ Ñтой ÑпоÑобноÑтью могут изменÑть ландшафт учаÑтка группы, даже еÑли Ñто отключено в окне «О земле» на вкладке «Параметры»." name="land allow edit land" value="23"/> diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml index 9c01de2f1b..e9592a0476 100644 --- a/indra/newview/skins/default/xui/ru/strings.xml +++ b/indra/newview/skins/default/xui/ru/strings.xml @@ -639,6 +639,15 @@ support@secondlife.com. <string name="BUTTON_HELP"> Показать Ñправку </string> + <string name="TooltipNotecardNotAllowedTypeDrop"> + Ðлементы Ñтого типа не могут быть занеÑены в +карточку Ð´Ð»Ñ ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñ‚Ð°Ñ€Ð¸ÐµÐ² в Ñтом регионе. + </string> + <string name="TooltipNotecardOwnerRestrictedDrop"> + Только Ñлементы Ñ Ð±ÐµÐ·ÑƒÑловным разрешением +‘Ñледующего владельца’ можно внеÑти +в карточки Ð´Ð»Ñ ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñ‚Ð°Ñ€Ð¸ÐµÐ². + </string> <string name="Searching"> ПоиÑк... </string> @@ -715,6 +724,18 @@ support@secondlife.com. Ошибка при запроÑе на передачу. Ð”Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰Ð¸ в решении Ñтой проблемы пройдите по ÑÑылке http://secondlife.com/support. </string> + <string name="SettingValidationError"> + Ðе удалоÑÑŒ выполнить проверку Ð´Ð»Ñ Ð¸Ð¼Ð¿Ð¾Ñ€Ñ‚Ð° наÑтроек [NAME] + </string> + <string name="SettingImportFileError"> + Ðе удалоÑÑŒ открыть файл [FILE] + </string> + <string name="SettingParseFileError"> + Ðе удалоÑÑŒ открыть файл [FILE] + </string> + <string name="SettingTranslateError"> + Ðе удалоÑÑŒ применить уÑтаревший Ñффект windlight \[NAME] + </string> <string name="texture"> текÑтуру </string> @@ -790,6 +811,9 @@ support@secondlife.com. <string name="symbolic folder link"> ÑÑылку на папку </string> + <string name="settings blob"> + наÑтройки + </string> <string name="mesh"> Ñетка </string> @@ -1120,6 +1144,9 @@ support@secondlife.com. <string name="ForceSitAvatar"> ЗаÑтавьте аватар ÑеÑть </string> + <string name="ChangeEnvSettings"> + Изменить Ñвои наÑтройки окружающей Ñреды + </string> <string name="NotConnected"> Ðет Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ </string> @@ -1271,6 +1298,9 @@ support@secondlife.com. <string name="tattoo"> Тату </string> + <string name="universal"> + УниверÑальные + </string> <string name="physics"> ФизичеÑкие данные </string> @@ -1313,6 +1343,9 @@ support@secondlife.com. <string name="tattoo_not_worn"> Тату не надето </string> + <string name="universal_not_worn"> + УниверÑальный нарÑд не надет + </string> <string name="physics_not_worn"> Физика не учитываетÑÑ </string> @@ -1364,6 +1397,9 @@ support@secondlife.com. <string name="create_new_tattoo"> Создать тату </string> + <string name="create_new_universal"> + Создать новые универÑальные + </string> <string name="create_new_physics"> Создать физику </string> @@ -1607,11 +1643,14 @@ support@secondlife.com. <string name="MarketplaceUpdating"> обновление... </string> + <string name="UploadFeeInfo"> + Тариф завиÑит от типа вашей подпиÑки. Тарифы Ð´Ð»Ñ Ð²Ð»Ð°Ð´ÐµÐ»ÑŒÑ†ÐµÐ² раÑширенных пакетов меньше. [https://secondlife.com/my/account/membership.php? Узнать больше] + </string> <string name="Open landmarks"> - Открыть закладки + Открыть Ñохраненные локации </string> <string name="Unconstrained"> - Без Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ + Без ограничений </string> <string name="no_transfer" value="(не передаетÑÑ)"/> <string name="no_modify" value="(не изменÑетÑÑ)"/> @@ -2511,6 +2550,27 @@ support@secondlife.com. <string name="RegionSettings"> Региональные наÑтройки </string> + <string name="NoEnvironmentSettings"> + Ðтот регион не поддерживает наÑтройки окружающей Ñреды. + </string> + <string name="EnvironmentSun"> + Солнце + </string> + <string name="EnvironmentMoon"> + Луна + </string> + <string name="EnvironmentBloom"> + Ореол + </string> + <string name="EnvironmentCloudNoise"> + Шум облака + </string> + <string name="EnvironmentNormalMap"> + Карта Ðормалей + </string> + <string name="EnvironmentTransparent"> + Прозрачный + </string> <string name="ClassifiedClicksTxt"> Щелчки: телепорт [TELEPORT], карта [MAP], профиль [PROFILE] </string> @@ -4724,6 +4784,9 @@ support@secondlife.com. <string name="New Tattoo"> Ðовое тату </string> + <string name="New Universal"> + Ðовые универÑальные + </string> <string name="New Physics"> ÐÐ¾Ð²Ð°Ñ Ñ„Ð¸Ð·Ð¸ÐºÐ° </string> @@ -4850,6 +4913,15 @@ support@secondlife.com. <string name="Female - Wow"> Женщина – ух ты! </string> + <string name="New Daycycle"> + Ðовый Ñуточный цикл + </string> + <string name="New Water"> + ÐÐ¾Ð²Ð°Ñ Ð²Ð¾Ð´Ð° + </string> + <string name="New Sky"> + Ðовое небо + </string> <string name="/bow"> /поклонитьÑÑ </string> @@ -5022,6 +5094,15 @@ support@secondlife.com. <string name="Chat"> Чат </string> + <string name="BaseMembership"> + Базовый + </string> + <string name="PremiumMembership"> + Премиум + </string> + <string name="Premium PlusMembership"> + Премиум ÐŸÐ»ÑŽÑ + </string> <string name="DeleteItems"> Удалить выбранные объекты? </string> @@ -5390,6 +5471,12 @@ support@secondlife.com. <string name="BeaconMedia"> ПроÑмотр медийных меток (белые) </string> + <string name="BeaconSun"> + ПроÑмотр метки Ð½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ñолнца (оранжевый) + </string> + <string name="BeaconMoon"> + ПроÑмотр метки Ð½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð»ÑƒÐ½Ñ‹ (багровый) + </string> <string name="ParticleHiding"> ЧаÑтицы Ñкрыты </string> @@ -5417,6 +5504,12 @@ support@secondlife.com. <string name="Command_Destinations_Label"> Пункты </string> + <string name="Command_Environments_Label"> + ÐœÐ¾Ñ Ð¾ÐºÑ€ÑƒÐ¶Ð°ÑŽÑ‰Ð°Ñ Ñреда + </string> + <string name="Command_Facebook_Label"> + Facebook + </string> <string name="Command_Flickr_Label"> Flickr </string> @@ -5510,6 +5603,12 @@ support@secondlife.com. <string name="Command_Destinations_Tooltip"> ИнтереÑные меÑта </string> + <string name="Command_Environments_Tooltip"> + ÐœÐ¾Ñ Ð¾ÐºÑ€ÑƒÐ¶Ð°ÑŽÑ‰Ð°Ñ Ñреда + </string> + <string name="Command_Facebook_Tooltip"> + Опубликовать в Facebook + </string> <string name="Command_Flickr_Tooltip"> Загрузить на Flickr </string> @@ -5705,6 +5804,12 @@ support@secondlife.com. <string name="ExperiencePermission12"> автоматичеÑки принимать Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð¿Ñ€Ð¸ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ </string> + <string name="ExperiencePermission16"> + поÑадить аватара + </string> + <string name="ExperiencePermission17"> + изменить Ñвои наÑтройки окружающей Ñреды + </string> <string name="ExperiencePermissionShortUnknown"> выполнил неизвеÑтную операцию: [Permission] </string> @@ -5729,6 +5834,12 @@ support@secondlife.com. <string name="ExperiencePermissionShort12"> Разрешение </string> + <string name="ExperiencePermissionShort16"> + СеÑть + </string> + <string name="ExperiencePermissionShort17"> + ÐžÐºÑ€ÑƒÐ¶Ð°ÑŽÑ‰Ð°Ñ Ñреда + </string> <string name="logging_calls_disabled_log_empty"> Разговоры не запиÑываютÑÑ. Чтобы начать запиÑÑŒ разговора, в меню «ÐаÑтройки > Чат» выберите «СохранÑть: только журнал» или «СохранÑть: журнал и запиÑи». </string> diff --git a/indra/newview/skins/default/xui/tr/floater_about_land.xml b/indra/newview/skins/default/xui/tr/floater_about_land.xml index 48b16e2fde..f9dbda0378 100644 --- a/indra/newview/skins/default/xui/tr/floater_about_land.xml +++ b/indra/newview/skins/default/xui/tr/floater_about_land.xml @@ -360,10 +360,10 @@ Sadece büyük parseller aramada görünür. Anlık Görüntü: </text> <texture_picker name="snapshot_ctrl" tool_tip="Bir resim seçmek için tıklayın"/> - <text name="allow_see_label"> + <text name="allow_see_label" top="170"> DiÄŸer parsellerdeki avatarlar bu parseldeki avatarları görebilir ve onlarla sohbet edebilir </text> - <check_box label="Avatarları Gör" name="SeeAvatarsCheck" tool_tip="DiÄŸer parsellerdeki avatarların bu parseldeki avatarları görmesine ve onlarla sohbet etmesine, sizin de onları görüp, onlarla sohbet etmenize imkan tanır."/> + <check_box label="Avatarları Gör" name="SeeAvatarsCheck" top="170" tool_tip="DiÄŸer parsellerdeki avatarların bu parseldeki avatarları görmesine ve onlarla sohbet etmesine, sizin de onları görüp, onlarla sohbet etmenize imkan tanır."/> <text name="landing_point"> İniÅŸ Noktası: [LANDING] </text> @@ -474,5 +474,6 @@ Sadece büyük parseller aramada görünür. </panel> </panel> <panel label="DENEYİMLER" name="land_experiences_panel"/> + <panel label="ORTAM" name="land_environment_panel"/> </tab_container> </floater> diff --git a/indra/newview/skins/default/xui/tr/floater_adjust_environment.xml b/indra/newview/skins/default/xui/tr/floater_adjust_environment.xml new file mode 100644 index 0000000000..763845c54d --- /dev/null +++ b/indra/newview/skins/default/xui/tr/floater_adjust_environment.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_adjust_snapshot" title="KiÅŸisel Aydınlatma"> + <layout_stack name="outer_stack"> + <layout_panel name="env_controls"> + <layout_stack name="settings_stack"> + <layout_panel> + <button label="Sıfırla" name="btn_reset" tool_tip="Kapat ve Ortak Ortama sıfırla"/> + <text name="cloud_map_label"> + Bulut Görüntüsü: + </text> + </layout_panel> + <layout_panel> + <text name="label"> + GüneÅŸ: + </text> + <check_box label="İşareti Göster" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <check_box label="İşareti Göster" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/tr/floater_beacons.xml b/indra/newview/skins/default/xui/tr/floater_beacons.xml index 08ebf36be5..e5b598ee61 100644 --- a/indra/newview/skins/default/xui/tr/floater_beacons.xml +++ b/indra/newview/skins/default/xui/tr/floater_beacons.xml @@ -18,5 +18,7 @@ <check_box label="Ses kaynakları" name="sounds"/> <check_box label="Parçacık kaynakları" name="particles"/> <check_box label="Ortam kaynakları" name="moapbeacon"/> + <check_box label="GüneÅŸ" name="sun"/> + <check_box label="Ay" name="moon"/> </panel> </floater> diff --git a/indra/newview/skins/default/xui/tr/floater_bulk_perms.xml b/indra/newview/skins/default/xui/tr/floater_bulk_perms.xml index a7708b5882..4eee1b81a2 100644 --- a/indra/newview/skins/default/xui/tr/floater_bulk_perms.xml +++ b/indra/newview/skins/default/xui/tr/floater_bulk_perms.xml @@ -21,6 +21,7 @@ <icon name="icon_script" tool_tip="Komut Dosyaları"/> <icon name="icon_sound" tool_tip="Sesler"/> <icon name="icon_texture" tool_tip="Dokular"/> + <icon name="icon_setting" tool_tip="Ortam ayarları"/> <button label="√ Tümü" name="check_all"/> <button label="Temizle" label_selected="Hiçbiri" name="check_none"/> <text name="newperms"> diff --git a/indra/newview/skins/default/xui/tr/floater_buy_currency.xml b/indra/newview/skins/default/xui/tr/floater_buy_currency.xml index d90985dcff..33c4b2287f 100644 --- a/indra/newview/skins/default/xui/tr/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/tr/floater_buy_currency.xml @@ -59,8 +59,7 @@ </text> <button label="Åžimdi Satın Al" name="buy_btn"/> <button label="İptal" name="cancel_btn"/> - <text name="info_cannot_buy"> + <floater.string name="info_cannot_buy"> Satın Alınamıyor - </text> - <button label="Web'e devam et" name="error_web"/> + </floater.string> </floater> diff --git a/indra/newview/skins/default/xui/tr/floater_delete_env_preset.xml b/indra/newview/skins/default/xui/tr/floater_delete_env_preset.xml deleted file mode 100644 index 7634bea642..0000000000 --- a/indra/newview/skins/default/xui/tr/floater_delete_env_preset.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<floater name="Delete Env Preset" title="ORTAM ÖN AYARINI SİL"> - <string name="title_water"> - Su Ön Ayarını Sil - </string> - <string name="title_sky"> - Gökyüzü Ön Ayarını Sil - </string> - <string name="title_day_cycle"> - Gün Döngüsünü Sil - </string> - <string name="label_water"> - Ön Ayar: - </string> - <string name="label_sky"> - Ön Ayar: - </string> - <string name="label_day_cycle"> - Gün döngüsü: - </string> - <string name="msg_confirm_deletion"> - Seçili ön ayarı silmek istediÄŸinizden emin misiniz? - </string> - <string name="msg_sky_is_referenced"> - Bazı gün döngüleri tarafından referans alınan bir ön ayar kaldırılamaz. - </string> - <string name="combo_label"> - -Bir ön ayar seçin- - </string> - <text name="label"> - Ön Ayar: - </text> - <button label="Sil" name="delete"/> - <button label="İptal Et" name="cancel"/> -</floater> diff --git a/indra/newview/skins/default/xui/tr/floater_edit_ext_day_cycle.xml b/indra/newview/skins/default/xui/tr/floater_edit_ext_day_cycle.xml new file mode 100644 index 0000000000..7ebbafa9bc --- /dev/null +++ b/indra/newview/skins/default/xui/tr/floater_edit_ext_day_cycle.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_edit_extdaycycle" title="Gün Döngüsünü Düzenle"> + <string name="title_new"> + Yeni bir Gün Döngüsü OluÅŸtur + </string> + <string name="title_edit"> + Gün Döngüsünü Düzenle + </string> + <string name="hint_new"> + Gün döngünüze ad verin, bunu oluÅŸturmak için denetimleri ayarlayın ve "Kaydet" düğmesine tıklayın. + </string> + <string name="hint_edit"> + Gün döngünüzü düzenlemek için, alttaki denetimleri ayarlayın ve "Kaydet" düğmesine tıklayın. + </string> + <string name="time_label"> + ([HH]:[MM]) + </string> + <string name="sky_track_label"> + Gökyüzü [ALT] + </string> + <string name="sky_label"> + Gökyüzü + </string> + <string name="water_label"> + Su + </string> + <string name="commit_parcel"> + Parsele Uygula + </string> + <string name="commit_region"> + Bölgeye Uygula + </string> + <layout_stack name="outer_stack"> + <layout_panel name="name_and_import"> + <text name="label"> + Gün Döngüsü Adı: + </text> + <button label="İçeri Aktar" name="btn_import" tool_tip="Eski ayarları diskten içeri aktarın."/> + </layout_panel> + <layout_panel name="content"> + <layout_stack name="content_stack"> + <layout_panel name="timeline_track_selection"> + <panel name="timeline_layers"> + <button label="Gökyüzü 4" name="sky4_track"/> + <button label="Gökyüzü 3" name="sky3_track"/> + <button label="Gökyüzü 2" name="sky2_track"/> + <button label="Zemin Seviyesi" name="sky1_track"/> + <button label="Su" name="water_track"/> + </panel> + <panel name="timeline"> + <text name="p0" value="%0 [DSC]"/> + <text name="p1" value="%25 [DSC]"/> + <text name="p2" value="%50 [DSC]"/> + <text name="p3" value="%75 [DSC]"/> + <text name="p4" value="%100 [DSC]"/> + <multi_slider initial_value="0" name="WLTimeSlider"/> + <multi_slider initial_value="0" name="WLDayCycleFrames"/> + <text name="current_time" value="%[PRCNT] [DSC]"/> + <layout_stack> + <layout_panel> + <button label="Buradan Rota Kopyala:" name="copy_track"/> + <button label="Buradan Rota Yükle:" name="load_track"/> + <button label="Rotayı Temizle" name="clear_track"/> + </layout_panel> + <layout_panel> + <layout_stack name="progress_control"> + <layout_panel name="skip_back"> + <button name="skip_back_btn" tool_tip="Geri çekil"/> + </layout_panel> + <layout_panel name="skip_forward"> + <button name="skip_forward_btn" tool_tip="İleri çık"/> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel> + <button label="[FRAME] Ekle" name="add_frame"/> + <button label="[FRAME] Yükle" name="btn_load_frame"/> + <button label="[FRAME] Sil" name="delete_frame"/> + </layout_panel> + </layout_stack> + </panel> + </layout_panel> + <layout_panel name="frame_edit_controls"> + <text name="icn_lock_edit"> + Ayarları düzenlemek için yukarıdaki zaman çizelgesinden bir anahtar çerçeve seçin. + </text> + </layout_panel> + <layout_panel name="frame_settings_water"> + <tab_container name="water_tabs"> + <panel label="Su" name="water_panel"/> + </tab_container> + </layout_panel> + <layout_panel name="frame_settings_sky"> + <tab_container name="sky_tabs"> + <panel label="Atmosfer ve Aydınlatma" name="atmosphere_panel"/> + <panel label="Bulutlar" name="clouds_panel"/> + <panel label="GüneÅŸ ve Ay" name="moon_panel"/> + </tab_container> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel name="buttons"> + <button label="Kaydet" name="save_btn"/> + <button label="İptal Et" name="cancel_btn"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/tr/floater_fixedenvironment.xml b/indra/newview/skins/default/xui/tr/floater_fixedenvironment.xml new file mode 100644 index 0000000000..8a8757c86c --- /dev/null +++ b/indra/newview/skins/default/xui/tr/floater_fixedenvironment.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="Fixed Environment" title="Sabit Ortam"> + <string name="edit_sky"> + Gökyüzünü Düzenle: + </string> + <string name="edit_water"> + Suyu Düzenle: + </string> + <layout_stack name="floater_stack"> + <layout_panel name="info_panel"> + <button label="Yükle" name="btn_load" tool_tip="Envanterden bir ayar yükle"/> + <button label="İçeri Aktar" name="btn_import" tool_tip="Eski ayarları diskten içeri aktarın."/> + </layout_panel> + <layout_panel name="button_panel"> + <layout_stack name="button_bar_ls"> + <layout_panel name="save_btn_lp"> + <button label="Kaydet" name="btn_commit"/> + </layout_panel> + <layout_panel name="revert_btn_lp"> + <button label="İptal Et" name="btn_cancel" tool_tip="Son kaydedilen sürüme dön"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/tr/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/tr/floater_inventory_view_finder.xml index 6c04b64275..accb1ed71c 100644 --- a/indra/newview/skins/default/xui/tr/floater_inventory_view_finder.xml +++ b/indra/newview/skins/default/xui/tr/floater_inventory_view_finder.xml @@ -12,6 +12,7 @@ <check_box label="Sesler" name="check_sound"/> <check_box label="Dokular" name="check_texture"/> <check_box label="Anlık Görüntüler" name="check_snapshot"/> + <check_box label="Ayarlar" name="check_settings"/> <button label="Tümü" label_selected="Tümü" name="All"/> <button label="Hiçbiri" label_selected="Hiçbiri" name="None"/> <check_box label="Klasörleri her zaman göster" name="check_show_empty"/> diff --git a/indra/newview/skins/default/xui/tr/floater_merchant_outbox.xml b/indra/newview/skins/default/xui/tr/floater_merchant_outbox.xml deleted file mode 100644 index e5643f3bf6..0000000000 --- a/indra/newview/skins/default/xui/tr/floater_merchant_outbox.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="floater_merchant_outbox" title="SATICI GİDEN KUTUSU"> - <string name="OutboxFolderCount1"> - 1 klasör - </string> - <string name="OutboxFolderCountN"> - [NUM] klasör - </string> - <string name="OutboxImporting"> - Klasörler gönderiliyor... - </string> - <string name="OutboxInitializing"> - BaÅŸlatılıyor... - </string> - <panel label="" name="panel_1"> - <panel name="panel_2"> - <panel name="outbox_inventory_placeholder_panel"> - <text name="outbox_inventory_placeholder_title"> - Yükleniyor... - </text> - </panel> - </panel> - <panel name="panel_3"> - <panel name="outbox_generic_drag_target"> - <text name="text_1"> - Klasör oluÅŸturmak için öğeleri buraya sürükleyin - </text> - </panel> - <button label="Pazaryerine Gönder" name="outbox_import_btn" tool_tip="Pazaryeri Vitrinime Gönder"/> - </panel> - </panel> -</floater> diff --git a/indra/newview/skins/default/xui/tr/floater_my_environments.xml b/indra/newview/skins/default/xui/tr/floater_my_environments.xml new file mode 100644 index 0000000000..b91f48c500 --- /dev/null +++ b/indra/newview/skins/default/xui/tr/floater_my_environments.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater label="Yerler" name="my_environments" title="ORTAMLARIM"> + <layout_stack> + <layout_panel label="Filtreler" name="filter_panel"> + <check_box label="Günler" name="chk_days"/> + <check_box label="Gökler" name="chk_skies"/> + <check_box label="Su" name="chk_water"/> + <filter_editor label="Ortamları Filtrele" name="flt_search"/> + </layout_panel> + <layout_panel label="Ortamlar" name="list_panel"> + <panel label="pnl_inv_wrap" name="pnl_inv_wrap"/> + </layout_panel> + <layout_panel> + <check_box initial_value="false" label="Tüm Klasörleri Göster" name="chk_showfolders"/> + </layout_panel> + <layout_panel name="pnl_control"> + <panel label="bottom_panel" name="pnl_bottom"> + <menu_button name="btn_gear" tool_tip="DiÄŸer seçenekler"/> + <menu_button name="btn_newsettings" tool_tip="Yeni ayar oluÅŸtur"/> + <button name="btn_del" tool_tip="Seçilen öğeyi kaldır"/> + </panel> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/tr/floater_perms_default.xml b/indra/newview/skins/default/xui/tr/floater_perms_default.xml index 9691b678f2..9263d4e1c6 100644 --- a/indra/newview/skins/default/xui/tr/floater_perms_default.xml +++ b/indra/newview/skins/default/xui/tr/floater_perms_default.xml @@ -37,6 +37,10 @@ <text name="label_12" tool_tip="Giysi ya da Vücut Parçaları oluÅŸturulduÄŸunda varsayılan izinleri ayarla"> Giyilebilir öğeler </text> + <text name="label_13" tool_tip="Ortam ayarları oluÅŸturulduÄŸunda varsayılan izinleri ayarla"> + Ayarlar + </text> + <check_box name="env_settings_c" value="true"/> </panel> <button label="Tamam" label_selected="Tamam" name="ok"/> <button label="İptal" label_selected="İptal" name="cancel"/> diff --git a/indra/newview/skins/default/xui/tr/floater_pick_track.xml b/indra/newview/skins/default/xui/tr/floater_pick_track.xml new file mode 100644 index 0000000000..83cfa8b652 --- /dev/null +++ b/indra/newview/skins/default/xui/tr/floater_pick_track.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="track picker" title="SEÇİM: ROTA"> + <layout_stack name="adjuster"> + <layout_panel name="pnl_desc"> + <text name="select_description"> + Kaynak gökyüzünü seç + </text> + </layout_panel> + <layout_panel name="pnl_traks"> + <radio_group name="track_selection"> + <radio_item label="Gökyüzü 4 [ALT]" name="radio_sky4" value="4"/> + <radio_item label="Gökyüzü 3 [ALT]" name="radio_sky3" value="3"/> + <radio_item label="Gökyüzü 2 [ALT]" name="radio_sky2" value="2"/> + <radio_item label="Zemin" name="radio_sky1" value="1"/> + </radio_group> + </layout_panel> + <layout_panel name="pnl_ok_cancel"> + <button label="Tamam" label_selected="Tamam" name="btn_select"/> + <button label="İptal Et" label_selected="İptal Et" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/tr/floater_picks.xml b/indra/newview/skins/default/xui/tr/floater_picks.xml index 513a2e319a..5aee6ae091 100644 --- a/indra/newview/skins/default/xui/tr/floater_picks.xml +++ b/indra/newview/skins/default/xui/tr/floater_picks.xml @@ -1,2 +1,2 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="floater_picks" title="Seçmeler"/> +<floater name="floater_picks" title="Seçimler"/> diff --git a/indra/newview/skins/default/xui/tr/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/tr/floater_preferences_graphics_advanced.xml index 01ada1354c..c5ca997336 100644 --- a/indra/newview/skins/default/xui/tr/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/tr/floater_preferences_graphics_advanced.xml @@ -82,7 +82,6 @@ <check_box initial_value="true" label="Saydam Su" name="TransparentWater"/> <check_box initial_value="true" label="Tümsek eÅŸleme ve parlaklık" name="BumpShiny"/> <check_box initial_value="true" label="Yerel Işıklar" name="LocalLights"/> - <check_box initial_value="true" label="Temel gölgeleyiciler" name="BasicShaders" tool_tip="Bu seçeneÄŸin devre dışı bırakılması bazı grafik kartlarının sürücülerinin kilitlenmesini önleyebilir"/> <slider label="Yüzey Ayrıntısı:" name="TerrainDetail"/> <text name="TerrainDetailText"> Düşük diff --git a/indra/newview/skins/default/xui/tr/floater_preview_texture.xml b/indra/newview/skins/default/xui/tr/floater_preview_texture.xml index 79e184130a..8302c62070 100644 --- a/indra/newview/skins/default/xui/tr/floater_preview_texture.xml +++ b/indra/newview/skins/default/xui/tr/floater_preview_texture.xml @@ -10,7 +10,7 @@ Açıklama: </text> <text name="dimensions"> - [WIDTH]px x [HEIGHT]px + [WIDTH] pks x [HEIGHT] pks </text> <text name="aspect_ratio"> En boy oranını önizle diff --git a/indra/newview/skins/default/xui/tr/floater_settings_picker.xml b/indra/newview/skins/default/xui/tr/floater_settings_picker.xml new file mode 100644 index 0000000000..0ef3aad5ee --- /dev/null +++ b/indra/newview/skins/default/xui/tr/floater_settings_picker.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="settings picker" title="SEÇİM: AYARLAR"> + <floater.string name="pick title"> + Seçim: + </floater.string> + <floater.string name="pick_track"> + ROTA SEÇ + </floater.string> + <floater.string name="pick_settings"> + AYARLARI SEÇ + </floater.string> + <floater.string name="track_water"> + Su + </floater.string> + <floater.string name="track_ground"> + Zemin + </floater.string> + <floater.string name="track_sky"> + Gökyüzü [NUM] + </floater.string> + <layout_stack name="test_stack"> + <layout_panel name="inv_list"> + <filter_editor label="Dokuları Filtrele" name="flt_inventory_search"/> + </layout_panel> + <layout_panel name="temp"> + <button label="Tamam" label_selected="Tamam" name="btn_select"/> + <button label="İptal Et" label_selected="İptal Et" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/tr/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/tr/floater_texture_ctrl.xml index 42483c09e1..0389cdcbe5 100644 --- a/indra/newview/skins/default/xui/tr/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/tr/floater_texture_ctrl.xml @@ -9,17 +9,13 @@ <text name="Multiple"> Birden çok doku </text> - <radio_group name="mode_selection"> - <radio_item label="Envanter" name="inventory" value="0"/> - <radio_item label="Yerel" name="local" value="1"/> - </radio_group> - <text name="unknown"> - Büyüklük: [DIMENSIONS] - </text> + <combo_box name="mode_selection"> + <combo_box.item label="Envanter" name="inventory" value="0"/> + <combo_box.item label="Yerel" name="local" value="1"/> + </combo_box> <button label="Varsayılan" label_selected="Varsayılan" name="Default"/> <button label="BoÅŸ" label_selected="BoÅŸ" name="Blank"/> <button label="Hiçbiri" label_selected="Hiçbiri" name="None"/> - <check_box initial_value="true" label="Åžimdi uygula" name="apply_immediate_check"/> <text name="preview_disabled" value="Önizleme Devre Dışı"/> <filter_editor label="Dokuları Filtrele" name="inventory search editor"/> <check_box initial_value="false" label="Klasörleri göster" name="show_folders_check"/> @@ -30,6 +26,22 @@ <column label="Ad" name="unit_name"/> <column label="Kimlik" name="unit_id_HIDDEN"/> </scroll_list> + <combo_box name="l_bake_use_texture_combo_box" tool_tip="Kurutma dokusunu seçin"> + <combo_box.item label="Yok" name="None"/> + <combo_box.item label="BAKED_HEAD" name="BAKED_HEAD"/> + <combo_box.item label="BAKED_UPPER" name="BAKED_UPPER"/> + <combo_box.item label="BAKED_LOWER" name="BAKED_LOWER"/> + <combo_box.item label="BAKED_EYES" name="BAKED_EYES"/> + <combo_box.item label="BAKED_SKIRT" name="BAKED_SKIRT"/> + <combo_box.item label="BAKED_HAIR" name="BAKED_HAIR"/> + <combo_box.item label="BAKED_LEFTARM" name="BAKED_LEFTARM"/> + <combo_box.item label="BAKED_LEFTLEG" name="BAKED_LEFTLEG"/> + <combo_box.item label="BAKED_AUX1" name="BAKED_AUX1"/> + <combo_box.item label="BAKED_AUX2" name="BAKED_AUX2"/> + <combo_box.item label="BAKED_AUX3" name="BAKED_AUX3"/> + </combo_box> + <check_box initial_value="false" label="Temel AÄŸ Bölgesini Gizle" name="hide_base_mesh_region"/> <button label="Tamam" label_selected="Tamam" name="Select"/> <button label="İptal" label_selected="İptal" name="Cancel"/> + <check_box initial_value="true" label="Åžimdi uygula" name="apply_immediate_check"/> </floater> diff --git a/indra/newview/skins/default/xui/tr/menu_cof_attachment.xml b/indra/newview/skins/default/xui/tr/menu_cof_attachment.xml index d57c43f6c1..82c9b286bb 100644 --- a/indra/newview/skins/default/xui/tr/menu_cof_attachment.xml +++ b/indra/newview/skins/default/xui/tr/menu_cof_attachment.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="COF Attachment"> + <menu_item_call label="Dokun" name="touch_attach" /> + <menu_item_call label="Düzenle" name="edit_item" /> <menu_item_call label="Ayır" name="detach"/> </context_menu> diff --git a/indra/newview/skins/default/xui/tr/menu_inventory.xml b/indra/newview/skins/default/xui/tr/menu_inventory.xml index 1e8dfc7d68..ce85c437cb 100644 --- a/indra/newview/skins/default/xui/tr/menu_inventory.xml +++ b/indra/newview/skins/default/xui/tr/menu_inventory.xml @@ -10,7 +10,6 @@ <menu_item_call label="EtkinleÅŸtir" name="Marketplace Activate"/> <menu_item_call label="Devre Dışı Bırak" name="Marketplace Deactivate"/> <menu_item_call label="PaylaÅŸ" name="Share"/> - <menu_item_call label="Satın Al" name="Task Buy"/> <menu_item_call label="Aç" name="Task Open"/> <menu_item_call label="Oyna" name="Task Play"/> <menu_item_call label="Özellikler" name="Task Properties"/> @@ -34,6 +33,7 @@ <menu_item_call label="Yeni Külot" name="New Underpants"/> <menu_item_call label="Yeni Alfa Maskesi" name="New Alpha Mask"/> <menu_item_call label="Yeni Dövme" name="New Tattoo"/> + <menu_item_call label="Yeni Evrensel" name="New Universal"/> <menu_item_call label="Yeni Fizik" name="New Physics"/> </menu> <menu label="Yeni Vücut Bölümleri" name="New Body Parts"> @@ -42,6 +42,11 @@ <menu_item_call label="Yeni Saç" name="New Hair"/> <menu_item_call label="Yeni Gözler" name="New Eyes"/> </menu> + <menu label="Yeni Ayarlar" name="New Settings"> + <menu_item_call label="Yeni Gökyüzü" name="New Sky"/> + <menu_item_call label="Yeni Su" name="New Water"/> + <menu_item_call label="Yeni Gün Döngüsü" name="New Day Cycle"/> + </menu> <menu label="Åžunun için varsayılan olarak kullan" name="upload_def"> <menu_item_call label="Karşıya yüklenen görüntüler" name="Image uploads"/> <menu_item_call label="Karşıya yüklenen sesler" name="Sound uploads"/> @@ -100,9 +105,12 @@ <menu_item_call label="Giy" name="Wearable And Object Wear"/> <menu label="Åžuna Ekle:" name="Attach To"/> <menu label="BÜG'e Ekle" name="Attach To HUD"/> + <menu_item_call label="Dokun" name="Attachment Touch" /> <menu_item_call label="Düzenle" name="Wearable Edit"/> <menu_item_call label="Ekle" name="Wearable Add"/> <menu_item_call label="Çıkar" name="Take Off"/> + <menu_item_call label="Sadece Kendime Uygula" name="Settings Apply Local"/> + <menu_item_call label="Parsele Uygula" name="Settings Apply Parcel"/> <menu_item_call label="Pazaryeri İlanlarına Kopyala" name="Marketplace Copy"/> <menu_item_call label="Pazaryeri İlanlarına Taşı" name="Marketplace Move"/> <menu_item_call label="--seçenek yok--" name="--no options--"/> diff --git a/indra/newview/skins/default/xui/tr/menu_inventory_add.xml b/indra/newview/skins/default/xui/tr/menu_inventory_add.xml index db2a9a2c8c..118081e3a3 100644 --- a/indra/newview/skins/default/xui/tr/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/tr/menu_inventory_add.xml @@ -5,9 +5,7 @@ <menu_item_call label="Ses (L$[COST])..." name="Upload Sound"/> <menu_item_call label="Animasyon (L$[COST])..." name="Upload Animation"/> <menu_item_call label="Model..." name="Upload Model"/> - <menu_item_call label="Model Sihirbazı..." name="Upload Model Wizard"/> <menu_item_call label="Toplu (dosya başına L$[COST])..." name="Bulk Upload"/> - <menu_item_call label="Varsayılan Karşıya Yükleme İzinlerini Ayarla" name="perm prefs"/> </menu> <menu_item_call label="Yeni Klasör" name="New Folder"/> <menu_item_call label="Yeni Komut Dosyası" name="New Script"/> @@ -25,6 +23,7 @@ <menu_item_call label="Yeni Külot" name="New Underpants"/> <menu_item_call label="Yeni Alfa" name="New Alpha"/> <menu_item_call label="Yeni Dövme" name="New Tattoo"/> + <menu_item_call label="Yeni Evrensel" name="New Universal"/> <menu_item_call label="Yeni Fizik" name="New Physics"/> </menu> <menu label="Yeni Vücut Bölümleri" name="New Body Parts"> @@ -33,4 +32,9 @@ <menu_item_call label="Yeni Saç" name="New Hair"/> <menu_item_call label="Yeni Gözler" name="New Eyes"/> </menu> + <menu label="Yeni Ayarlar" name="New Settings"> + <menu_item_call label="Yeni Gökyüzü" name="New Sky"/> + <menu_item_call label="Yeni Su" name="New Water"/> + <menu_item_call label="Yeni Gün Döngüsü" name="New Day Cycle"/> + </menu> </menu> diff --git a/indra/newview/skins/default/xui/tr/menu_outfit_gear.xml b/indra/newview/skins/default/xui/tr/menu_outfit_gear.xml index 1b73032a5d..7590ee28de 100644 --- a/indra/newview/skins/default/xui/tr/menu_outfit_gear.xml +++ b/indra/newview/skins/default/xui/tr/menu_outfit_gear.xml @@ -20,6 +20,7 @@ <menu_item_call label="Yeni Alfa" name="New Alpha"/> <menu_item_call label="Yeni Fizik" name="New Physics"/> <menu_item_call label="Yeni Dövme" name="New Tattoo"/> + <menu_item_call label="Yeni Evrensel" name="New Universal"/> </menu> <menu label="Yeni Vücut Bölümleri" name="New Body Parts"> <menu_item_call label="Yeni Åžekil" name="New Shape"/> diff --git a/indra/newview/skins/default/xui/tr/menu_save_settings.xml b/indra/newview/skins/default/xui/tr/menu_save_settings.xml new file mode 100644 index 0000000000..dad150a54b --- /dev/null +++ b/indra/newview/skins/default/xui/tr/menu_save_settings.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="save_settings_menu"> + <menu_item_check label="Kaydet" name="save_settings"/> + <menu_item_check label="Farklı Kaydet" name="save_as_new_settings"/> + <menu_item_check label="Yürüt" name="commit_changes"/> + <menu_item_check label="Sadece Kendime Uygula" name="apply_local"/> + <menu_item_check label="Parsele Uygula" name="apply_parcel"/> + <menu_item_check label="Bölgeye Uygula" name="apply_region"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/tr/menu_settings_add.xml b/indra/newview/skins/default/xui/tr/menu_settings_add.xml new file mode 100644 index 0000000000..0afd8a7893 --- /dev/null +++ b/indra/newview/skins/default/xui/tr/menu_settings_add.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_add"> + <menu_item_call label="Yeni Gökyüzü" name="New Sky"/> + <menu_item_call label="Yeni Su" name="New Water"/> + <menu_item_call label="Yeni Gün Döngüsü" name="New Day Cycle"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/tr/menu_settings_gear.xml b/indra/newview/skins/default/xui/tr/menu_settings_gear.xml new file mode 100644 index 0000000000..f0d04a9e68 --- /dev/null +++ b/indra/newview/skins/default/xui/tr/menu_settings_gear.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_gear"> + <menu_item_call label="Düzenle" name="edit_settings"/> + <menu_item_call label="Sadece Kendime Uygula" name="Settings Apply Local"/> + <menu_item_call label="Parsele Uygula" name="Settings Apply Parcel"/> + <menu_item_call label="Bölgeye Uygula" name="Settings Apply Region"/> + <menu_item_call label="Kopyala" name="copy_settings"/> + <menu_item_call label="Yapıştır" name="paste_settings"/> + <menu_item_call label="UUID'yi Kopyala" name="copy_uuid"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/tr/menu_viewer.xml b/indra/newview/skins/default/xui/tr/menu_viewer.xml index b83847a013..1c977ba5ce 100644 --- a/indra/newview/skins/default/xui/tr/menu_viewer.xml +++ b/indra/newview/skins/default/xui/tr/menu_viewer.xml @@ -77,30 +77,15 @@ <menu_item_check label="Parsel Özellikleri" name="Parcel Properties"/> <menu_item_check label="GeliÅŸmiÅŸ Menü" name="Show Advanced Menu"/> </menu> - <menu label="GüneÅŸ" name="Sun"> + <menu label="Ortam" name="Environment"> <menu_item_check label="Gün doÄŸumu" name="Sunrise"/> <menu_item_check label="Öğle" name="Noon"/> <menu_item_check label="Gün batımı" name="Sunset"/> <menu_item_check label="Gece yarısı" name="Midnight"/> - <menu_item_check label="Bölge Ayarlarını Kullan" name="Use Region Settings"/> - </menu> - <menu label="Ortam Düzenleyici" name="Environment Editor"> - <menu_item_call label="Ortam Ayarları..." name="Environment Settings"/> - <menu label="Su Ön Ayarları" name="Water Presets"> - <menu_item_call label="Yeni ön ayar..." name="new_water_preset"/> - <menu_item_call label="Ön ayarı düzenle..." name="edit_water_preset"/> - <menu_item_call label="Ön ayarı sil..." name="delete_water_preset"/> - </menu> - <menu label="Gökyüzü Ön Ayarları" name="Sky Presets"> - <menu_item_call label="Yeni ön ayar..." name="new_sky_preset"/> - <menu_item_call label="Ön ayarı düzenle..." name="edit_sky_preset"/> - <menu_item_call label="Ön ayarı sil..." name="delete_sky_preset"/> - </menu> - <menu label="Gün Ön Ayarları" name="Day Presets"> - <menu_item_call label="Yeni ön ayar..." name="new_day_preset"/> - <menu_item_call label="Ön ayarı düzenle..." name="edit_day_preset"/> - <menu_item_call label="Ön ayarı sil..." name="delete_day_preset"/> - </menu> + <menu_item_check label="Ortak Ortam Kullan" name="Use Shared Environment"/> + <menu_item_call label="Ortamlarım..." name="my_environs"/> + <menu_item_call label="KiÅŸisel Aydınlatma..." name="adjustment_tool"/> + <menu_item_check label="Bulutları Duraklat" name="pause_clouds"/> </menu> </menu> <menu label="İnÅŸa Et" name="BuildTools"> @@ -344,6 +329,9 @@ <menu_item_check label="Otomatik Alfa Maskeleri (ertelenmemiÅŸ)" name="Automatic Alpha Masks (non-deferred)"/> <menu_item_check label="Animasyon Dokuları" name="Animation Textures"/> <menu_item_check label="Dokuları Devre Dışı Bırak" name="Disable Textures"/> + <menu_item_check label="Ortamı Devre Dışı Bırak" name="Disable Ambient"/> + <menu_item_check label="GüneÅŸ Işığını Devre Dışı Bırak" name="Disable Sunlight"/> + <menu_item_check label="Yerel Işıkları Devre Dışı Bırak" name="Disable Local Lights"/> <menu_item_check label="Tam Çöz. Dokular" name="Rull Res Textures"/> <menu_item_check label="EklenmiÅŸ Işıkları İşle" name="Render Attached Lights"/> <menu_item_check label="EklenmiÅŸ Parçacıkları İşle" name="Render Attached Particles"/> @@ -481,6 +469,7 @@ <menu_item_call label="Etek" name="Skirt"/> <menu_item_call label="Alfa" name="Alpha"/> <menu_item_call label="Dövme" name="Tattoo"/> + <menu_item_call label="Evrensel" name="Universal"/> <menu_item_call label="Fizik" name="Physics"/> <menu_item_call label="Tüm Giysiler" name="All Clothes"/> </menu> diff --git a/indra/newview/skins/default/xui/tr/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/tr/menu_wearable_list_item.xml index 448202df87..486f76a29a 100644 --- a/indra/newview/skins/default/xui/tr/menu_wearable_list_item.xml +++ b/indra/newview/skins/default/xui/tr/menu_wearable_list_item.xml @@ -3,6 +3,7 @@ <menu_item_call label="DeÄŸiÅŸtir" name="wear_replace"/> <menu_item_call label="Giy" name="wear_wear"/> <menu_item_call label="Ekle" name="wear_add"/> + <menu_item_call label="Dokun" name="touch" /> <menu_item_call label="Çıkar / Ayır" name="take_off_or_detach"/> <menu_item_call label="Ayır" name="detach"/> <context_menu label="Åžuna ekle" name="wearable_attach_to"/> diff --git a/indra/newview/skins/default/xui/tr/menu_wearing_gear.xml b/indra/newview/skins/default/xui/tr/menu_wearing_gear.xml index 438e580cd3..1594cf3afb 100644 --- a/indra/newview/skins/default/xui/tr/menu_wearing_gear.xml +++ b/indra/newview/skins/default/xui/tr/menu_wearing_gear.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <toggleable_menu name="Gear Wearing"> - <menu_item_call label="Dış Görünümü Düzenle" name="edit"/> + <menu_item_call label="Dokun" name="touch"/> + <menu_item_call label="Düzenle" name="edit_item"/> + <menu_item_call label="Dış Görünümü Düzenle" name="edit_outfit"/> <menu_item_call label="Çıkar" name="takeoff"/> <menu_item_call label="Dış görünüm listesini panoya kopyala" name="copy"/> </toggleable_menu> diff --git a/indra/newview/skins/default/xui/tr/menu_wearing_tab.xml b/indra/newview/skins/default/xui/tr/menu_wearing_tab.xml index 1db95c17e1..56397c8628 100644 --- a/indra/newview/skins/default/xui/tr/menu_wearing_tab.xml +++ b/indra/newview/skins/default/xui/tr/menu_wearing_tab.xml @@ -1,8 +1,9 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="Wearing"> + <menu_item_call label="Dokun" name="touch_attach"/> <menu_item_call label="Çıkar" name="take_off"/> <menu_item_call label="Ayır" name="detach"/> - <menu_item_call label="Dış Görünümü Düzenle" name="edit"/> + <menu_item_call label="Dış Görünümü Düzenle" name="edit_outfit"/> <menu_item_call label="Düzenle" name="edit_item"/> <menu_item_call label="Orijinali Göster" name="show_original"/> </context_menu> diff --git a/indra/newview/skins/default/xui/tr/notifications.xml b/indra/newview/skins/default/xui/tr/notifications.xml index 13867cf5b8..5403a78f22 100644 --- a/indra/newview/skins/default/xui/tr/notifications.xml +++ b/indra/newview/skins/default/xui/tr/notifications.xml @@ -266,6 +266,10 @@ Seçili Sakinlere deÄŸiÅŸiklik yapma hakkı vermek istiyor musunuz? Seçili Sakinlerin deÄŸiÅŸiklik yapma hakkını iptal etmek istiyor musunuz? <usetemplate name="okcancelbuttons" notext="Hayır" yestext="Evet"/> </notification> + <notification name="GroupNameLengthWarning"> + Bir grup adı [MIN_LEN] ile [MAX_LEN] karakter olmalıdır. + <usetemplate name="okbutton" yestext="Tamam"/> + </notification> <notification name="UnableToCreateGroup"> Grup oluÅŸturulamıyor. [MESSAGE] @@ -360,7 +364,7 @@ Devam etmek istiyor musunuz? Bu gruba katılmak için yeterli L$'na sahip deÄŸilsiniz. </notification> <notification name="CreateGroupCost"> - Bu grubu oluÅŸturmanın maliyeti: L$ 100. + Bu grubu oluÅŸturmak L$[COST]'dır. Grupların birden fazla üyeye sahip olması gereklidir, aksi takdirde grup kalıcı olarak silinir. Lütfen 48 saat içinde diÄŸer üyeleri davet edin. <usetemplate canceltext="İptal" name="okcancelbuttons" notext="İptal" yestext="L$ 100 ödeyerek grubu oluÅŸtur"/> @@ -501,6 +505,9 @@ Ortamı sadece bir yüze yerleÅŸtirmek için, Yüz Seç'i seçin ve ardınd <notification name="ErrorEncodingSnapshot"> Anlık görüntü kodlanırken hata oluÅŸtu. </notification> + <notification name="ErrorCannotAffordUpload"> + Bu nesneyi yüklemek için L$[COST] ' a ihtiyacınız var. + </notification> <notification name="ErrorPhotoCannotAfford"> Envanterinize bir fotoÄŸraf kaydedebilmek için [COST] L$ paraya ihtiyacınız var. L$ satın alabilir veya bunun yerine fotoÄŸrafı bilgisayarınıza kaydedebilirsiniz. </notification> @@ -1739,11 +1746,14 @@ Gruptan ayrılmak istiyor musunuz? <usetemplate name="okbutton" yestext="Tamam"/> </notification> <notification name="GroupLimitInfo"> - Temel hesaplar için grup limiti [MAX_BASIC], [https://secondlife.com/premium/ özel] hesaplar -içinse [MAX_PREMIUM] olarak belirlenmiÅŸtir. -Hesabınızı indirgediyseniz, daha fazla gruba katılmak için önce grup sayınızı [MAX_BASIC] grubun altına düşürmelisiniz. - -[https://secondlife.com/my/account/membership.php Åžimdi yükselt!] + Temel üyelikler [MAX_BASIC]'a kadar katılım saÄŸlayabilir. +Premium üyelikler [MAX_PREMIUM] 'a kadar izinlidir. [https://secondlife.com/my/account/membership.php? Daha fazla bilgi alın ya da üyeiliÄŸinizi yükseltin] + <usetemplate name="okbutton" yestext="Kapat"/> + </notification> + <notification name="GroupLimitInfoPlus"> + Temel üyelik sahibi yerleÅŸimciler [MAX_BASIC]'a kadar olan gruplara katılabilir. +Premium üyeler [MAX_PREMIUM] 'a kadar izinlidir. Premium Plus üyeler [MAX_PREMIUM_PLUS] 'a kadar izinlidir. +[https://secondlife.com/my/account/membership.php? Daha fazla bilgi alın ya da üyeiliÄŸinizi yükseltin] <usetemplate name="okbutton" yestext="Kapat"/> </notification> <notification name="KickUser"> @@ -1960,6 +1970,11 @@ Binlerce bölgeyi deÄŸiÅŸtirecek ve alan sunucusunu kesintiye uÄŸratacaktır. Bu seçeneÄŸin onay iÅŸaretini kaldırmak, parsel sahiplerinin rahatsızlık veren oyuncuları bunu yapmasını engellemek, gizliliÄŸi sürdürmek ve yaşı tutmayan sakinleri yetiÅŸkin içeriklerden korumak için ekledikleri kısıtlamaları kaldırabilir. Lütfen gerekli olduÄŸunda parsel sahiplerinizle tartışın. <usetemplate name="okbutton" yestext="Tamam"/> </notification> + <notification name="EstateParcelEnvironmentOverride"> + Bu seçeneÄŸin onay iÅŸaretinin kaldırılması, parsel sahiplerinin kendi parsellerine eklemiÅŸ oldukları tüm özel ortamları kaldırır. Lütfen gerektiÄŸinde parsel sahiplerinizle görüşün. +Devam etmek istiyor musunuz? + <usetemplate name="okcancelbuttons" notext="İptal Et" yestext="Tamam"/> + </notification> <notification name="RegionEntryAccessBlocked"> Ziyaret etmeye çalıştığınız bölge, mevcut tercihlerinizi aÅŸan içeriÄŸe sahip. Ben > Tercihler > Genel sekmesini kullanarak tercihlerinizi deÄŸiÅŸtirebilirsiniz. <usetemplate name="okbutton" yestext="Tamam"/> @@ -2438,7 +2453,15 @@ DiÄŸer kiÅŸilerin bu konuma kolayca eriÅŸmesini saÄŸlamak için bu adrese bir we Bu gün döngüsü dosyası kayıp bir gökyüzü dosyasına baÅŸvuruda bulunuyor: [SKY]. </notification> <notification name="WLRegionApplyFail"> - Üzgünüz, bu ayarlar bölgeye uygulanamadı. Bölgeden ayrılmak ve sonra geri dönmek sorunu çözebilir. Gösterilen neden ÅŸuydu: [FAIL_REASON] + Üzgünüz, ayarlar bölgeye uygulanamadı. Neden: [FAIL_REASON] + </notification> + <notification name="WLLocalTextureDayBlock"> + Bir Yerel doku [FIELD] alanındaki [TRACK] rotasında, #[FRAMENO] ([FRAME]%) çerçevesinde kullanılıyor. +Ayarlar yerel dokular kullanılarak kaydedilemez. + </notification> + <notification name="WLLocalTextureFixedBlock"> + Bir yerel doku [FIELD] alanında kullanılıyor. +Ayarlar yerel dokular kullanılarak kaydedilemez. </notification> <notification name="EnvCannotDeleteLastDayCycleKey"> Bu gün döngüsündeki son anahtar silinemedi çünkü boÅŸ bir gün döngünüz olamaz. Son kalan anahtarı silmek ve yenisini oluÅŸturmaya kalkışmak yerine bunu deÄŸiÅŸtirmelisiniz. @@ -3290,6 +3313,22 @@ GüvenliÄŸiniz için birkaç saniye engellenecek. Sesli sohbetiniz moderatör tarafından engellendi. <usetemplate name="okbutton" yestext="Tamam"/> </notification> + <notification name="FailedToGetBenefits"> + Maalesef, bu oturumun avantajlarıyla ilgili bilgilere ulaÅŸamıyoruz. Normal prodüksiyon ortamında yaÅŸanmaması gereken bir durumdur. Lütfen destek ekibiyle iletiÅŸime geçin. Bu oturum normal bir ÅŸekilde çalışmayacaktır, yeniden baÅŸlatmanızı öneririz. + <usetemplate name="okbutton" yestext="Tamam"/> + </notification> + <notification name="BulkUploadCostConfirmation"> + Bu, toplam tutarı L$[COST] olan [COUNT] nesne yükleyecektir. Bu yüklemeye devam etmek istiyor musunuz? + <usetemplate name="okcancelbuttons" notext="İptal" yestext="Karşıya Yükle"/> + </notification> + <notification name="BulkUploadNoCompatibleFiles"> + Seçili dosyalar aynı anda yüklenemez. + <usetemplate name="okbutton" yestext="Tamam"/> + </notification> + <notification name="BulkUploadIncompatibleFiles"> + Seçili bazı dosyalar aynı anda yüklenemez. + <usetemplate name="okbutton" yestext="Tamam"/> + </notification> <notification name="UploadCostConfirmation"> Bu karşıya yükleme iÅŸleminin maliyeti L$[PRICE] olacak, karşıya yüklemeye devam etmek istiyor musunuz? <usetemplate name="okcancelbuttons" notext="İptal" yestext="Karşıya Yükle"/> @@ -4382,4 +4421,75 @@ Daha küçük bir arazi parçası seçmeyi deneyin. [REASON] <usetemplate name="okbutton" yestext="Tamam"/> </notification> + <notification name="FailedToFindSettings"> + [NAME] ile ilgili ayarlar veritabanından yüklenemedi. + </notification> + <notification name="FailedToLoadSettingsApply"> + Bu deÄŸiÅŸiklikler ortama uygulanamıyor. + </notification> + <notification name="FailedToBuildSettingsDay"> + Bu deÄŸiÅŸiklikler ortama uygulanamıyor. + </notification> + <notification name="NoEnvironmentSettings"> + Bu Bölge ortam ayarlarını desteklemiyor. + </notification> + <notification label="Dış Görünümü Kaydet" name="SaveSettingAs"> + Geçerli ortam ayarlarını farklı kaydet: + <form name="form"> + <input name="message"> + [DESC] (yeni) + </input> + <button name="OK" text="Tamam"/> + <button name="Cancel" text="İptal Et"/> + </form> + </notification> + <notification name="WLImportFail"> + Eski Windlight ayarları [NAME], [FILE] kaynağından içeri aktarılamıyor. + +[REASONS] + </notification> + <notification name="WLParcelApplyFail"> + Bu parsele ait ortam ayarlanamıyor. +Lütfen deÄŸiÅŸiklik yapma hakkına sahip olduÄŸunuz bir parsel girin veya seçin. + </notification> + <notification name="SettingsUnsuported"> + Ayarlar bu bölgede desteklenmiyor. +Lütfen ayarların etkin olduÄŸu bir bölgeye gidin ve eyleminizi yeniden deneyin. + </notification> + <notification name="SettingsConfirmLoss"> + "[NAME]" adlı bu [TYPE] öğesinde yaptığınız deÄŸiÅŸiklikleri kaybetmek üzeresiniz. +Devam etmek istediÄŸinizden emin misiniz? + <usetemplate ignoretext="DeÄŸiÅŸiklikleri kaybetmek istediÄŸinizden emin misiniz?" name="okcancelignore" notext="Hayır" yestext="Evet"/> + </notification> + <notification name="SettingsConfirmReset"> + Uygulanan ayarlarınızın tümünü kaldırmak üzeresiniz. +Devam etmek istediÄŸinizden emin misiniz? + <usetemplate name="okcancelbuttons" notext="Hayır" yestext="Evet"/> + </notification> + <notification name="PersonalSettingsConfirmReset"> + Uygulanan KiÅŸisel aydınlatma ayarlarınızın tümünü kaldırmak üzeresiniz. +Devam etmek istediÄŸinizden emin misiniz? + <usetemplate name="okcancelbuttons" notext="Hayır" yestext="Evet"/> + </notification> + <notification name="SettingsMakeNoTrans"> + Aktarılamayan ayarları bu gün döngüsüne aktarmak üzeresiniz. Bu iÅŸleme devam etmeniz düzenlemekte olduÄŸunuz ayarların da aktarılamaz olmasına neden olacaktır. + +Bu deÄŸiÅŸiklik geri alınamaz. + +Devam etmek istediÄŸinizden emin misiniz? + <usetemplate ignoretext="Ayarları aktarılamaz hale getirmek istediÄŸinizden emin misiniz?" name="okcancelignore" notext="Hayır" yestext="Evet"/> + </notification> + <notification name="NoEditFromLibrary"> + Ayarları doÄŸrudan kütüphaneden düzenleyemezsiniz. +Lütfen kendi envanterinize kopyalayın ve yeniden deneyin. + </notification> + <notification name="EnvironmentApplyFailed"> + Bu ayarlarla ilgili bir sorunla karşılaÅŸtık. Bu ayarlar ÅŸu anda kaydedilemiyor veya uygulanamıyor. + </notification> + <notification name="TrackLoadFailed"> + Rota [TRACK] hedefine yüklenemiyor. + </notification> + <notification name="TrackLoadMismatch"> + Rota [TRACK1] kaynağından [TRACK2] hedefine yüklenemiyor. + </notification> </notifications> diff --git a/indra/newview/skins/default/xui/tr/panel_edit_classified.xml b/indra/newview/skins/default/xui/tr/panel_edit_classified.xml index 7584b754f1..fc444f21f6 100644 --- a/indra/newview/skins/default/xui/tr/panel_edit_classified.xml +++ b/indra/newview/skins/default/xui/tr/panel_edit_classified.xml @@ -47,7 +47,7 @@ <button label="[LABEL]" name="save_changes_btn"/> </layout_panel> <layout_panel name="show_on_map_btn_lp"> - <button label="İptal" name="cancel_btn"/> + <button label="İptal Et" name="cancel_btn"/> </layout_panel> </layout_stack> </panel> diff --git a/indra/newview/skins/default/xui/tr/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/tr/panel_edit_tattoo.xml index 7f5590a485..fb97f1e1ce 100644 --- a/indra/newview/skins/default/xui/tr/panel_edit_tattoo.xml +++ b/indra/newview/skins/default/xui/tr/panel_edit_tattoo.xml @@ -1,9 +1,11 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_tattoo_panel"> - <panel name="avatar_tattoo_color_panel"> - <texture_picker label="BaÅŸ Dövmesi" name="Head Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> - <texture_picker label="Üst Gövde Dövmesi" name="Upper Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> - <texture_picker label="Alt Gövde Dövmesi" name="Lower Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> - <color_swatch label="Renk/Ton" name="Color/Tint" tool_tip="Renk seçiciyi açmak için tıklayın"/> - </panel> + <scroll_container name="avatar_tattoo_scroll"> + <panel name="avatar_tattoo_color_panel"> + <texture_picker label="BaÅŸ Dövmesi" name="Head Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> + <texture_picker label="Üst Gövde Dövmesi" name="Upper Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> + <texture_picker label="Alt Gövde Dövmesi" name="Lower Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> + <color_swatch label="Renk/Ton" name="Color/Tint" tool_tip="Renk seçiciyi açmak için tıklayın"/> + </panel> + </scroll_container> </panel> diff --git a/indra/newview/skins/default/xui/tr/panel_edit_universal.xml b/indra/newview/skins/default/xui/tr/panel_edit_universal.xml new file mode 100644 index 0000000000..ef10307d11 --- /dev/null +++ b/indra/newview/skins/default/xui/tr/panel_edit_universal.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel name="edit_universal_panel"> + <scroll_container name="avatar_universal_scroll"> + <panel name="avatar_universal_color_panel"> + <texture_picker label="BaÅŸ Dövmesi" name="Head Universal Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> + <texture_picker label="Üst Gövde Dövmesi" name="Upper Universal Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> + <texture_picker label="Alt Gövde Dövmesi" name="Lower Universal Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> + <texture_picker label="Etek Dövmesi" name="Skirt Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> + <texture_picker label="Saç Dövmesi" name="Hair Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> + <texture_picker label="Göz Dövmesi" name="Eyes Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> + <texture_picker label="Sol Kol Dövmesi" name="Left Arm Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> + <texture_picker label="Sol Bacak Dövmesi" name="Left Leg Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> + <texture_picker label="Yedek 1 Dövme" name="Aux1 Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> + <texture_picker label="Yedek 2 Dövme" name="Aux2 Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> + <texture_picker label="Yedek 3 Dövme" name="Aux3 Tattoo" tool_tip="Bir resim seçmek için tıklayın"/> + <color_swatch label="Renk/Ton" name="Color/Tint" tool_tip="Renk seçiciyi açmak için tıklayın"/> + </panel> + </scroll_container> +</panel> diff --git a/indra/newview/skins/default/xui/tr/panel_edit_wearable.xml b/indra/newview/skins/default/xui/tr/panel_edit_wearable.xml index 7a4a09aaed..7880de8e7d 100644 --- a/indra/newview/skins/default/xui/tr/panel_edit_wearable.xml +++ b/indra/newview/skins/default/xui/tr/panel_edit_wearable.xml @@ -45,6 +45,9 @@ <string name="edit_tattoo_title"> Dövme Düzenleniyor </string> + <string name="edit_universal_title"> + Evrensel Düzenleniyor + </string> <string name="edit_physics_title"> Fizik Düzenleniyor </string> @@ -93,6 +96,9 @@ <string name="tattoo_desc_text"> Dövme: </string> + <string name="universal_desc_text"> + Evrensel: + </string> <string name="physics_desc_text"> Fizik: </string> diff --git a/indra/newview/skins/default/xui/tr/panel_me.xml b/indra/newview/skins/default/xui/tr/panel_me.xml index 4b911c9ce6..d9e79d171c 100644 --- a/indra/newview/skins/default/xui/tr/panel_me.xml +++ b/indra/newview/skins/default/xui/tr/panel_me.xml @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Profilim" name="panel_me"> - <panel label="SEÇMELERİM" name="panel_picks"/> + <panel label="SEÇTİKLERİM" name="panel_picks"/> </panel> diff --git a/indra/newview/skins/default/xui/tr/panel_outbox_inventory.xml b/indra/newview/skins/default/xui/tr/panel_outbox_inventory.xml deleted file mode 100644 index a947eee150..0000000000 --- a/indra/newview/skins/default/xui/tr/panel_outbox_inventory.xml +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<outbox_inventory_panel name="inventory_outbox" tool_tip="Öğeleri vitrininizde satışa hazırlamak için sürükleyip buraya bırakın"/> diff --git a/indra/newview/skins/default/xui/tr/panel_people.xml b/indra/newview/skins/default/xui/tr/panel_people.xml index 29ca4772fd..25d29fcbb5 100644 --- a/indra/newview/skins/default/xui/tr/panel_people.xml +++ b/indra/newview/skins/default/xui/tr/panel_people.xml @@ -18,7 +18,7 @@ Birlikte takılacak kiÅŸiler mi arıyorsunuz? [secondlife:///app/worldmap Dünya <string name="no_groups_msg" value="Katılacak Gruplar mı arıyorsunuz? [secondlife:///app/search/groups Ara] deneyin."/> <string name="MiniMapToolTipMsg" value="[REGION](Haritayı açmak için çift tıkla, yatay hareket için shift çek)"/> <string name="AltMiniMapToolTipMsg" value="[REGION](Işınlamak için çift tıkla, yatay hareket için shift çek)"/> - <string name="GroupCountWithInfo" value="[COUNT] gruba üyesiniz, daha [REMAINING] gruba üye olabilirsiniz. [secondlife:/// Daha fazlasını mı istiyorsunuz?]"/> + <string name="GroupCountWithInfo" value="[COUNT] gruba üyesin ve [REMAINING] daha gruba üye olabilirsin. [secondlife:/// Limitini arttır]"/> <tab_container name="tabs"> <panel label="YAKIN" name="nearby_panel"> <panel label="bottom_panel" name="nearby_buttons_panel"> @@ -51,7 +51,7 @@ Birlikte takılacak kiÅŸiler mi arıyorsunuz? [secondlife:///app/worldmap Dünya <dnd_button name="minus_btn" tool_tip="Seçilen gruptan ayrıl"/> </panel> <text name="groupcount"> - [COUNT] gruba üyesiniz, daha [REMAINING] gruba üye olabilirsiniz. + [COUNT] gruba üyesin ve [REMAINING] daha gruba üye olabilirsin. </text> </panel> <panel label="SON" name="recent_panel"> diff --git a/indra/newview/skins/default/xui/tr/panel_region_environment.xml b/indra/newview/skins/default/xui/tr/panel_region_environment.xml index b5f505f25f..d375203cf6 100644 --- a/indra/newview/skins/default/xui/tr/panel_region_environment.xml +++ b/indra/newview/skins/default/xui/tr/panel_region_environment.xml @@ -1,33 +1,116 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Ortam" name="panel_env_info"> - <text name="water_settings_title"> - Bölgenize gelen tüm ziyaretçilerin görmesini istediÄŸiniz Su ve Gökyüzü/Gündüz Döngüsü Ayarlarını seçin. Ek bilgi - </text> - <radio_group name="region_settings_radio_group"> - <radio_item label="Second Life varsayılanını kullan" name="use_sl_default_settings"/> - <radio_item label="AÅŸağıdaki ayarları kullan" name="use_my_settings"/> - </radio_group> - <panel name="user_environment_settings"> - <text name="water_settings_title"> - Su Ayarı - </text> - <combo_box name="water_settings_preset_combo"> - <combo_box.item label="-Bir ön ayar seçin-" name="item0"/> - </combo_box> - <text name="sky_dayc_settings_title"> - Gökyüzü / Gün Döngüsü - </text> - <radio_group name="sky_dayc_settings_radio_group"> - <radio_item label="Sabit gökyüzü" name="my_sky_settings"/> - <radio_item label="Gün döngüsü" name="my_dayc_settings"/> - </radio_group> - <combo_box name="sky_settings_preset_combo"> - <combo_box.item label="-Bir ön ayar seçin-" name="item0"/> - </combo_box> - <combo_box name="dayc_settings_preset_combo"> - <combo_box.item label="-Bir ön ayar seçin-" name="item0"/> - </combo_box> - </panel> - <button label="Uygula" name="apply_btn"/> - <button label="İptal Et" name="cancel_btn"/> + <string name="str_label_use_default"> + Varsayılan Ayarları Kullan + </string> + <string name="str_label_use_region"> + Bölge Ayarlarını Kullan + </string> + <string name="str_altitude_desription"> + Gökyüzü [INDEX]([ALTITUDE] m) + </string> + <string name="str_no_parcel"> + Parsel seçilmedi. Ortam ayarları devre dışı. + </string> + <string name="str_cross_region"> + Ortam ayarları bölge sınırları dahilinde kullanılamıyor. + </string> + <string name="str_legacy"> + Ortam ayarları bu bölgede kullanılamıyor. + </string> + <string name="str_disallowed"> + Gayrimenkul yöneticisi bu bölgede parsel ortamlarını deÄŸiÅŸtirmeye izin vermiyor. + </string> + <string name="str_too_small"> + Parselin bir ortamı desteklemesi için en az 128 metrekare olması gerekir. + </string> + <string name="str_empty"> + (boÅŸ) + </string> + <string name="str_region_env"> + (bölge ortamı) + </string> + <layout_stack> + <layout_panel name="pnl_environment_disabled"> + <text name="txt_environment_disabled"> + ... + </text> + </layout_panel> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_current"> + <button label="[USEDEFAULT]" name="btn_usedefault"/> + <button label="Envanteri Kullan" name="btn_select_inventory"/> + <button label="ÖzelleÅŸtir" name="btn_edit"/> + <check_box label="Parsel Sahipleri Ortamı Geçersiz Kılabilir" name="chk_allow_override"/> + </layout_panel> + <layout_panel name="pnl_environment_length"> + <text name="lbl_apparent_time"> + [HH]:[MM][AP] (% [PRC]) + </text> + </layout_panel> + <layout_panel name="pnl_environment_buttons"/> + </layout_stack> + </layout_panel> + <layout_panel name="pnl_environment_altitudes"> + <panel name="pnl_alt1"> + <text name="txt_alt1"> + Gökyüzü [INDEX] + [ALTITUDE] m + </text> + <line_editor name="edt_invname_alt1"> + Bilinmiyor + </line_editor> + <settings_drop_target name="sdt_alt1" tool_tip="Geçerli gökyüzü olarak seçmek için Envanterden bir ayarı bu hedef kutuya sürükleyin."/> + </panel> + <panel name="pnl_alt2"> + <text name="txt_alt2"> + Gökyüzü [INDEX] + [ALTITUDE] m + </text> + <line_editor name="edt_invname_alt2"> + Bilinmiyor + </line_editor> + <settings_drop_target name="sdt_alt2" tool_tip="Geçerli gökyüzü olarak seçmek için Envanterden bir ayarı bu hedef kutuya sürükleyin."/> + </panel> + <panel name="pnl_alt3"> + <text name="txt_alt3"> + Gökyüzü [INDEX] + [ALTITUDE] m + </text> + <line_editor name="edt_invname_alt3"> + Bilinmiyor + </line_editor> + <settings_drop_target name="sdt_alt3" tool_tip="Geçerli gökyüzü olarak seçmek için Envanterden bir ayarı bu hedef kutuya sürükleyin."/> + </panel> + <multi_slider initial_value="0" name="sld_altitudes"> + <slider name="sld1" value="1000"/> + <slider name="sld2" value="2000"/> + <slider name="sld3" value="3000"/> + </multi_slider> + <panel name="pnl_ground"> + <text name="txt_ground"> + Zemin + </text> + <line_editor name="edt_invname_ground"> + Bilinmiyor + </line_editor> + <settings_drop_target name="sdt_ground" tool_tip="Zemin seviyesinde gökyüzü olarak seçmek için Envanterden bir ayarı bu hedef kutuya sürükleyin."/> + </panel> + <panel name="pnl_water"> + <text name="txt_water"> + Su + </text> + <line_editor name="edt_invname_water"> + Bilinmiyor + </line_editor> + <settings_drop_target name="sdt_water" tool_tip="Geçerli su olarak seçmek için Envanterden bir ayarı bu hedef kutuya sürükleyin."/> + </panel> + <button label="Sıfırla" name="btn_rst_altitudes" tool_tip="Varsayılan irtifalara sıfırla"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> </panel> diff --git a/indra/newview/skins/default/xui/tr/panel_settings_sky_atmos.xml b/indra/newview/skins/default/xui/tr/panel_settings_sky_atmos.xml new file mode 100644 index 0000000000..9bc23a5507 --- /dev/null +++ b/indra/newview/skins/default/xui/tr/panel_settings_sky_atmos.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Atmosfer ve Aydınlatma" name="panel_settings_sky_atmos"/> diff --git a/indra/newview/skins/default/xui/tr/panel_settings_sky_clouds.xml b/indra/newview/skins/default/xui/tr/panel_settings_sky_clouds.xml new file mode 100644 index 0000000000..5dd31546cd --- /dev/null +++ b/indra/newview/skins/default/xui/tr/panel_settings_sky_clouds.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Bulutlar" name="panel_settings_sky_clouds"> + <layout_stack> + <layout_panel> + <slider label="X" name="cloud_density_x"/> + <slider label="Y" name="cloud_density_y"/> + <slider label="D" name="cloud_density_d"/> + <slider label="X" name="cloud_detail_x"/> + <slider label="Y" name="cloud_detail_y"/> + <slider label="D" name="cloud_detail_d"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/tr/panel_settings_sky_density.xml b/indra/newview/skins/default/xui/tr/panel_settings_sky_density.xml new file mode 100644 index 0000000000..1d2aa30921 --- /dev/null +++ b/indra/newview/skins/default/xui/tr/panel_settings_sky_density.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="YoÄŸunluk" name="panel_settings_sky_density"> + <layout_stack> + <layout_panel> + <slider label="Rayleigh Üstel Terim:" name="rayleigh_exponential"/> + <slider label="Rayleigh Üstel Skala:" name="rayleigh_exponential_scale"/> + <slider label="Rayleigh Lineer Terim:" name="rayleigh_linear"/> + <slider label="Rayleigh Sabit Terim:" name="rayleigh_constant"/> + <slider label="Rayleigh Maks. İrtifa:" name="rayleigh_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="Mie Üstel Terim:" name="mie_exponential"/> + <slider label="Mie Üstel Skala:" name="mie_exponential_scale"/> + <slider label="Mie Lineer Terim:" name="mie_linear"/> + <slider label="Mie Sabit Terim:" name="mie_constant"/> + <slider label="Mie Anizotropi Faktörü:" name="mie_aniso_factor"/> + <slider label="Mie Maks. İrtifa:" name="mie_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="Absorpsiyon Üstel Terim:" name="absorption_exponential"/> + <slider label="Absorpsiyon Üstel Skala:" name="absorption_exponential_scale"/> + <slider label="Absorpsiyon Lineer Terim:" name="absorption_linear"/> + <slider label="Absorpsiyon Sabit Terim:" name="absorption_constant"/> + <slider label="Absorpsiyon Maks. İrtifa:" name="absorption_max_altitude"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/tr/panel_settings_sky_sunmoon.xml b/indra/newview/skins/default/xui/tr/panel_settings_sky_sunmoon.xml new file mode 100644 index 0000000000..44fccb594d --- /dev/null +++ b/indra/newview/skins/default/xui/tr/panel_settings_sky_sunmoon.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="GüneÅŸ ve Ay" name="panel_settings_sky_hbodies"> + <layout_stack> + <layout_panel name="sun_layout"> + <check_box label="İşareti Göster" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <layout_stack> + <layout_panel name="moon_layout"> + <check_box label="İşareti Göster" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/tr/panel_settings_water.xml b/indra/newview/skins/default/xui/tr/panel_settings_water.xml new file mode 100644 index 0000000000..9537a2b494 --- /dev/null +++ b/indra/newview/skins/default/xui/tr/panel_settings_water.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Su" name="panel_settings_water"> + <layout_stack name="water_stack1"> + <layout_panel> + <text name="FresnelOffsetText"> + Fresnel Dengeleme: + </text> + </layout_panel> + <layout_panel> + <layout_stack name="water_stack2"> + <layout_panel> + <slider label="X:" name="water_normal_scale_x"/> + <slider label="Y:" name="water_normal_scale_y"/> + <slider label="Z:" name="water_normal_scale_z"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/tr/panel_tools_texture.xml b/indra/newview/skins/default/xui/tr/panel_tools_texture.xml index 1324e2cc36..baf53a7af4 100644 --- a/indra/newview/skins/default/xui/tr/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/tr/panel_tools_texture.xml @@ -1,11 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Doku" name="Texture"> - <panel.string name="string repeats per meter"> - Metrede Kaç Kez Tekrarlandığı - </panel.string> - <panel.string name="string repeats per face"> - Bir Yüzde Kaç Kez Tekrarlandığı - </panel.string> <text name="color label"> Renk </text> @@ -114,4 +108,5 @@ <spinner label="Yatay ofset" name="shinyOffsetU"/> <spinner label="Dikey ofset" name="shinyOffsetV"/> <check_box initial_value="false" label="Planar yüzleri hizala" name="checkbox planar align" tool_tip="Tüm seçili yüzeylerdeki dokuları son seçili yüzdekiyle hizalar. Planar doku eÅŸleÅŸtirmesi gerektirir."/> + <button label="Hizala" label_selected="Geçerli doku katmanlarına hizala" name="button align textures" tool_tip="Geçerli doku katmanlarına hizala"/> </panel> diff --git a/indra/newview/skins/default/xui/tr/role_actions.xml b/indra/newview/skins/default/xui/tr/role_actions.xml index 5e830bddd5..3ac4a7b19f 100644 --- a/indra/newview/skins/default/xui/tr/role_actions.xml +++ b/indra/newview/skins/default/xui/tr/role_actions.xml @@ -33,6 +33,7 @@ <action description="MüziÄŸi & ortam ayarlarını deÄŸiÅŸtir" longdescription="Akış müziÄŸini ve film ayarlarını Arazi Hakkında > Ortam sekmesinden deÄŸiÅŸtirin." name="land change media" value="20"/> <action description="'Yüzeyi Düzenle' seçeneÄŸini Aç/Kapa" longdescription="'Yüzeyi Düzenle' seçeneÄŸini açın/kapatın. *UYARI* Arazi Hakkında > Seçenekler sekmesi > Yüzeyi Düzenle seçeneÄŸi, herhangi bir kiÅŸinin arazinizin ÅŸeklini deÄŸiÅŸtirmesine, Linden bitkileri yerleÅŸtirmesine ve bu bitkilerin yerlerini deÄŸiÅŸtirmesine izin verir. Bu YeteneÄŸi atamadan önce ne yaptığınızı bildiÄŸinizden emin olun. Yüzey düzenleme seçeneÄŸi Arazi Hakkında > Seçenekler sekmesinden açılıp kapanır." name="land edit" value="21"/> <action description="Arazi Hakkında > Seçenekler sekmesindeki çeÅŸitli ayarları Aç/Kapa" longdescription="'Güvenli (hasar yok)', 'Uç' ve diÄŸer Second Life Sakinlerinin 'Yüzeyi Düzenle', 'İnÅŸa Et', 'Yer İmleri OluÅŸtur' ve 'Komut Dosyalarını Çalıştır' yeteneklerini grubun sahip olduÄŸu arazi üzerinde kullanmalarına izin verme tercihini Arazi Hakkında > Seçenekler sekmesinden açın/kapayın." name="land options" value="22"/> + <action description="Ortam ayarlarını ve gün döngüsünü deÄŸiÅŸtirin." longdescription="Arazi Hakkında > Ortam sekmesinden ortam ayarlarını ve gün döngüsünü deÄŸiÅŸtirin." name="land change environment" value="46"/> </action_set> <action_set description="Bu Yeteneklere Üyelerin grubun sahip olduÄŸu parseller üzerindeki kısıtlamaları geçmesine izin veren güçler de dahildir." name="Parcel Powers"> <action description="'Yüzeyi Düzenle' yeteneÄŸine her zaman izin ver" longdescription="Bu YeteneÄŸe sahip olan bir Roldeki Üyeler, Arazi Hakkında > Seçenekler sekmesinde kapalı olsa da grubun sahip olduÄŸu parsel üzerinde yüzey düzenleme yapabilir." name="land allow edit land" value="23"/> diff --git a/indra/newview/skins/default/xui/tr/strings.xml b/indra/newview/skins/default/xui/tr/strings.xml index 27f3c4d4d9..56fad978f5 100644 --- a/indra/newview/skins/default/xui/tr/strings.xml +++ b/indra/newview/skins/default/xui/tr/strings.xml @@ -639,6 +639,15 @@ Lütfen bir dakika içerisinde tekrar oturum açmayı deneyin. <string name="BUTTON_HELP"> Yardımı Göster </string> + <string name="TooltipNotecardNotAllowedTypeDrop"> + Bu türe ait öğeler bu bölgedeki +not kartlarına eklenemez. + </string> + <string name="TooltipNotecardOwnerRestrictedDrop"> + Sadece kısıtlamasız 'sonraki sahip' +izinlerini içeren öğeler not +kartlarına eklenebilir. + </string> <string name="Searching"> Arıyor... </string> @@ -715,6 +724,18 @@ Lütfen bir dakika içerisinde tekrar oturum açmayı deneyin. Karşıya yükleme talebinde hata. Bu sorunu çözmek için lütfen http://secondlife.com/support adresini ziyaret edin. </string> + <string name="SettingValidationError"> + [NAME] ayarlarının içeri aktarılması için doÄŸrulama baÅŸarısız oldu + </string> + <string name="SettingImportFileError"> + [FILE] dosyası açılamadı + </string> + <string name="SettingParseFileError"> + [FILE] dosyası açılamadı + </string> + <string name="SettingTranslateError"> + Eski Windlight [NAME] çevrilemedi + </string> <string name="texture"> doku </string> @@ -790,6 +811,9 @@ http://secondlife.com/support adresini ziyaret edin. <string name="symbolic folder link"> klasör baÄŸlantısı </string> + <string name="settings blob"> + ayarlar + </string> <string name="mesh"> örgü </string> @@ -1120,6 +1144,9 @@ http://secondlife.com/support adresini ziyaret edin. <string name="ForceSitAvatar"> Avatarınızı oturmaya zorlayın </string> + <string name="ChangeEnvSettings"> + Ortam ayarlarınızı deÄŸiÅŸtirin + </string> <string name="NotConnected"> BaÄŸlı DeÄŸil </string> @@ -1271,6 +1298,9 @@ http://secondlife.com/support adresini ziyaret edin. <string name="tattoo"> Dövme </string> + <string name="universal"> + Evrensel + </string> <string name="physics"> Fizik </string> @@ -1313,6 +1343,9 @@ http://secondlife.com/support adresini ziyaret edin. <string name="tattoo_not_worn"> GiyilmemiÅŸ dövme </string> + <string name="universal_not_worn"> + Evrensel giyilmiyor + </string> <string name="physics_not_worn"> GiyilmemiÅŸ fizik </string> @@ -1364,6 +1397,9 @@ http://secondlife.com/support adresini ziyaret edin. <string name="create_new_tattoo"> Yeni dövme oluÅŸtur </string> + <string name="create_new_universal"> + Yeni evrensel oluÅŸtur + </string> <string name="create_new_physics"> Yeni fizik oluÅŸtur </string> @@ -1607,11 +1643,14 @@ Bu mesaj size gelmeye devam ederse lütfen http://support.secondlife.com adresin <string name="MarketplaceUpdating"> güncelleniyor... </string> + <string name="UploadFeeInfo"> + Ücret, üyelik seviyene göre belirlenir. Yüksek seviyelere daha düşük ücretler uygulanır. [https://secondlife.com/my/account/membership.php? Daha fazla bilgi al] + </string> <string name="Open landmarks"> - Açık yer imleri + Açık alanlar </string> <string name="Unconstrained"> - Kısıtsız + Serbest </string> <string name="no_transfer" value="(aktarım yok)"/> <string name="no_modify" value="(deÄŸiÅŸtirme yok)"/> @@ -2511,6 +2550,27 @@ Bu mesaj size gelmeye devam ederse lütfen http://support.secondlife.com adresin <string name="RegionSettings"> Bölge Ayarları </string> + <string name="NoEnvironmentSettings"> + Bu Bölge ortam ayarlarını desteklemiyor. + </string> + <string name="EnvironmentSun"> + GüneÅŸ + </string> + <string name="EnvironmentMoon"> + Ay + </string> + <string name="EnvironmentBloom"> + Bahar + </string> + <string name="EnvironmentCloudNoise"> + Bulut Gürültüsü + </string> + <string name="EnvironmentNormalMap"> + Normal Harita + </string> + <string name="EnvironmentTransparent"> + Saydam + </string> <string name="ClassifiedClicksTxt"> Tıklamalar: [TELEPORT] ışınlama, [MAP] harita, [PROFILE] profil </string> @@ -4725,6 +4785,9 @@ Bu iletiyi almaya devam ederseniz, lütfen [SUPPORT_SITE] bölümüne baÅŸvurun. <string name="New Tattoo"> Yeni Dövme </string> + <string name="New Universal"> + Yeni Evrensel + </string> <string name="New Physics"> Yeni Fizik </string> @@ -4851,6 +4914,15 @@ Bu iletiyi almaya devam ederseniz, lütfen [SUPPORT_SITE] bölümüne baÅŸvurun. <string name="Female - Wow"> Kadın - Vay be </string> + <string name="New Daycycle"> + Yeni Gün döngüsü + </string> + <string name="New Water"> + Yeni Su + </string> + <string name="New Sky"> + Yeni Gökyüzü + </string> <string name="/bow"> /selamlama </string> @@ -5023,6 +5095,9 @@ Hizmetle iliÅŸkili bilinen bir sorun olup olmadığını görmek için lütfen h <string name="Chat"> Sohbet </string> + <string name="BaseMembership"> + Temel + </string> <string name="DeleteItems"> Seçili öğeler silinsin mi? </string> @@ -5391,6 +5466,12 @@ Düzenleyici yolunu çift tırnakla çevrelemeyi deneyin. <string name="BeaconMedia"> Ortam iÅŸaretleri gösteriliyor (beyaz) </string> + <string name="BeaconSun"> + GüneÅŸ yönü iÅŸareti (turuncu) görüntüleniyor + </string> + <string name="BeaconMoon"> + Ay yönü iÅŸareti (mor) görüntüleniyor + </string> <string name="ParticleHiding"> Parçacıklar Gizleniyor </string> @@ -5418,6 +5499,12 @@ Düzenleyici yolunu çift tırnakla çevrelemeyi deneyin. <string name="Command_Destinations_Label"> Hedef Konum </string> + <string name="Command_Environments_Label"> + Ortamlarım + </string> + <string name="Command_Facebook_Label"> + Facebook + </string> <string name="Command_Flickr_Label"> Flickr </string> @@ -5511,6 +5598,12 @@ Düzenleyici yolunu çift tırnakla çevrelemeyi deneyin. <string name="Command_Destinations_Tooltip"> İlgilendiÄŸiniz hedef konumlar </string> + <string name="Command_Environments_Tooltip"> + Ortamlarım + </string> + <string name="Command_Facebook_Tooltip"> + Facebook'ta Yayınla + </string> <string name="Command_Flickr_Tooltip"> Flickr'a yükle </string> @@ -5706,6 +5799,12 @@ Düzenleyici yolunu çift tırnakla çevrelemeyi deneyin. <string name="ExperiencePermission12"> deneyim izinlerini otomatik olarak kabul et </string> + <string name="ExperiencePermission16"> + avatarınızı oturmaya zorlayın + </string> + <string name="ExperiencePermission17"> + ortam ayarlarınızı deÄŸiÅŸtirin + </string> <string name="ExperiencePermissionShortUnknown"> bilinmeyen bir iÅŸlem gerçekleÅŸtirdi: [Permission] </string> @@ -5730,6 +5829,12 @@ Düzenleyici yolunu çift tırnakla çevrelemeyi deneyin. <string name="ExperiencePermissionShort12"> İzin </string> + <string name="ExperiencePermissionShort16"> + Otur + </string> + <string name="ExperiencePermissionShort17"> + Ortam + </string> <string name="logging_calls_disabled_log_empty"> Sohbetlerin günlüğü tutulmuyor. Bir günlük tutmaya baÅŸlamak için, Tercihler > Sohbet altında "Kaydet: Sadece günlük" veya "Kaydet: Günlük ve dökümler" seçimini yapın. </string> diff --git a/indra/newview/skins/default/xui/zh/floater_about_land.xml b/indra/newview/skins/default/xui/zh/floater_about_land.xml index 1164722abf..bb680f822e 100644 --- a/indra/newview/skins/default/xui/zh/floater_about_land.xml +++ b/indra/newview/skins/default/xui/zh/floater_about_land.xml @@ -474,5 +474,6 @@ </panel> </panel> <panel label="體驗" name="land_experiences_panel"/> + <panel label="環境" name="land_environment_panel"/> </tab_container> </floater> diff --git a/indra/newview/skins/default/xui/zh/floater_adjust_environment.xml b/indra/newview/skins/default/xui/zh/floater_adjust_environment.xml new file mode 100644 index 0000000000..192c429430 --- /dev/null +++ b/indra/newview/skins/default/xui/zh/floater_adjust_environment.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_adjust_snapshot" title="個人照明"> + <layout_stack name="outer_stack"> + <layout_panel name="env_controls"> + <layout_stack name="settings_stack"> + <layout_panel> + <button label="é‡è¨" name="btn_reset" tool_tip="關閉並é‡è¨çˆ²å…±äº«ç’°å¢ƒ"/> + <text name="cloud_map_label"> + 雲彩圖åƒï¼š + </text> + </layout_panel> + <layout_panel> + <text name="label"> + 太陽: + </text> + <check_box label="顯示指標" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <check_box label="顯示指標" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/zh/floater_beacons.xml b/indra/newview/skins/default/xui/zh/floater_beacons.xml index 83e10804d6..4df8c8f14b 100644 --- a/indra/newview/skins/default/xui/zh/floater_beacons.xml +++ b/indra/newview/skins/default/xui/zh/floater_beacons.xml @@ -18,5 +18,7 @@ <check_box label="è²éŸ³ä¾†æº" name="sounds"/> <check_box label="例å來æº" name="particles"/> <check_box label="媒體來æº" name="moapbeacon"/> + <check_box label="太陽" name="sun"/> + <check_box label="月亮" name="moon"/> </panel> </floater> diff --git a/indra/newview/skins/default/xui/zh/floater_bulk_perms.xml b/indra/newview/skins/default/xui/zh/floater_bulk_perms.xml index dbf4a21416..3729aa7620 100644 --- a/indra/newview/skins/default/xui/zh/floater_bulk_perms.xml +++ b/indra/newview/skins/default/xui/zh/floater_bulk_perms.xml @@ -21,6 +21,7 @@ <icon name="icon_script" tool_tip="腳本"/> <icon name="icon_sound" tool_tip="è²éŸ³"/> <icon name="icon_texture" tool_tip="æè³ª"/> + <icon name="icon_setting" tool_tip="環境è¨å®š"/> <button label="√ 全部" name="check_all"/> <button label="清除" label_selected="ç„¡" name="check_none"/> <text name="newperms"> diff --git a/indra/newview/skins/default/xui/zh/floater_buy_currency.xml b/indra/newview/skins/default/xui/zh/floater_buy_currency.xml index fcf2800728..41c8c26ccc 100644 --- a/indra/newview/skins/default/xui/zh/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/zh/floater_buy_currency.xml @@ -59,8 +59,7 @@ </text> <button label="ç«‹å³è³¼è²·" name="buy_btn"/> <button label="å–æ¶ˆ" name="cancel_btn"/> - <text name="info_cannot_buy"> + <floater.string name="info_cannot_buy"> 無法購買 - </text> - <button label="繼續到網é " name="error_web"/> + </floater.string> </floater> diff --git a/indra/newview/skins/default/xui/zh/floater_delete_env_preset.xml b/indra/newview/skins/default/xui/zh/floater_delete_env_preset.xml deleted file mode 100644 index 4aafb31952..0000000000 --- a/indra/newview/skins/default/xui/zh/floater_delete_env_preset.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<floater name="Delete Env Preset" title="刪除環境自訂é…ç½®"> - <string name="title_water"> - 刪除水的自訂é…ç½® - </string> - <string name="title_sky"> - 刪除天空自訂é…ç½® - </string> - <string name="title_day_cycle"> - 刪除日循環 - </string> - <string name="label_water"> - 自訂é…置: - </string> - <string name="label_sky"> - 自訂é…置: - </string> - <string name="label_day_cycle"> - 日循環: - </string> - <string name="msg_confirm_deletion"> - 確定è¦åˆªé™¤æ‰€é¸è‡ªè¨‚é…置? - </string> - <string name="msg_sky_is_referenced"> - 無法刪除日循環有所指涉的自訂é…置。 - </string> - <string name="combo_label"> - -鏿“‡ä¸€å€‹è‡ªè¨‚é…ç½®- - </string> - <text name="label"> - 自訂é…置: - </text> - <button label="刪除" name="delete"/> - <button label="å–æ¶ˆ" name="cancel"/> -</floater> diff --git a/indra/newview/skins/default/xui/zh/floater_edit_ext_day_cycle.xml b/indra/newview/skins/default/xui/zh/floater_edit_ext_day_cycle.xml new file mode 100644 index 0000000000..cdcf0a685e --- /dev/null +++ b/indra/newview/skins/default/xui/zh/floater_edit_ext_day_cycle.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="env_edit_extdaycycle" title="編輯日循環"> + <string name="title_new"> + 新建一個日循環 + </string> + <string name="title_edit"> + 編輯日循環 + </string> + <string name="hint_new"> + 為日循環定å,調整å„é …æŽ§åˆ¶ç¢ºå®šç´°ç¯€ï¼Œå†é»žæŒ‰ã€Œå„²å˜ã€ã€‚ + </string> + <string name="hint_edit"> + è‹¥è¦ç·¨è¼¯ä½ 的日循環,請調整下方å„é …æŽ§åˆ¶ï¼Œå†é»žæŒ‰ã€Œå„²å˜ã€ã€‚ + </string> + <string name="time_label"> + ([HH]:[MM]) + </string> + <string name="sky_track_label"> + 天空[ALT] + </string> + <string name="sky_label"> + 天空 + </string> + <string name="water_label"> + æ°´æ–‡ + </string> + <string name="commit_parcel"> + 套用到地段 + </string> + <string name="commit_region"> + å¥—ç”¨åˆ°åœ°å€ + </string> + <layout_stack name="outer_stack"> + <layout_panel name="name_and_import"> + <text name="label"> + 日循環å稱: + </text> + <button label="匯入" name="btn_import" tool_tip="從ç£ç¢ŸåŒ¯å…¥èˆŠè¨å®šã€‚"/> + </layout_panel> + <layout_panel name="content"> + <layout_stack name="content_stack"> + <layout_panel name="timeline_track_selection"> + <panel name="timeline_layers"> + <button label="天空 4" name="sky4_track"/> + <button label="天空 3" name="sky3_track"/> + <button label="天空 2" name="sky2_track"/> + <button label="åœ°é¢æ°´å¹³" name="sky1_track"/> + <button label="æ°´æ–‡" name="water_track"/> + </panel> + <panel name="timeline"> + <text name="p0" value="0%[DSC]"/> + <text name="p1" value="25%[DSC]"/> + <text name="p2" value="50%[DSC]"/> + <text name="p3" value="75%[DSC]"/> + <text name="p4" value="100%[DSC]"/> + <multi_slider initial_value="0" name="WLTimeSlider"/> + <multi_slider initial_value="0" name="WLDayCycleFrames"/> + <text name="current_time" value="[PRCNT]%[DSC]"/> + <layout_stack> + <layout_panel> + <button label="複製軌跡來æºï¼š" name="copy_track"/> + <button label="載入軌跡來æºï¼š" name="load_track"/> + <button label="清除軌跡" name="clear_track"/> + </layout_panel> + <layout_panel> + <layout_stack name="progress_control"> + <layout_panel name="skip_back"> + <button name="skip_back_btn" tool_tip="逿¥å¾Œé€€"/> + </layout_panel> + <layout_panel name="skip_forward"> + <button name="skip_forward_btn" tool_tip="逿¥å‰é€²"/> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel> + <button label="新增[FRAME]" name="add_frame"/> + <button label="載入[FRAME]" name="btn_load_frame"/> + <button label="刪除[FRAME]" name="delete_frame"/> + </layout_panel> + </layout_stack> + </panel> + </layout_panel> + <layout_panel name="frame_edit_controls"> + <text name="icn_lock_edit"> + å¾žä¸Šæ–¹çš„æ™‚é–“ç·šé¸æ“‡ä¸€å€‹é—œéµå¹€ä»¥ç·¨è¼¯è¨å®šã€‚ + </text> + </layout_panel> + <layout_panel name="frame_settings_water"> + <tab_container name="water_tabs"> + <panel label="æ°´æ–‡" name="water_panel"/> + </tab_container> + </layout_panel> + <layout_panel name="frame_settings_sky"> + <tab_container name="sky_tabs"> + <panel label="大氣與照明" name="atmosphere_panel"/> + <panel label="雲彩" name="clouds_panel"/> + <panel label="日與月" name="moon_panel"/> + </tab_container> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel name="buttons"> + <button label="儲å˜" name="save_btn"/> + <button label="å–æ¶ˆ" name="cancel_btn"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/zh/floater_fixedenvironment.xml b/indra/newview/skins/default/xui/zh/floater_fixedenvironment.xml new file mode 100644 index 0000000000..b47b893764 --- /dev/null +++ b/indra/newview/skins/default/xui/zh/floater_fixedenvironment.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="Fixed Environment" title="固定環境"> + <string name="edit_sky"> + 編輯天空: + </string> + <string name="edit_water"> + 編輯水文: + </string> + <layout_stack name="floater_stack"> + <layout_panel name="info_panel"> + <button label="載入" name="btn_load" tool_tip="從收ç´å€è¼‰å…¥ä¸€å€‹è¨å®š"/> + <button label="匯入" name="btn_import" tool_tip="從ç£ç¢ŸåŒ¯å…¥èˆŠè¨å®šã€‚"/> + </layout_panel> + <layout_panel name="button_panel"> + <layout_stack name="button_bar_ls"> + <layout_panel name="save_btn_lp"> + <button label="儲å˜" name="btn_commit"/> + </layout_panel> + <layout_panel name="revert_btn_lp"> + <button label="å–æ¶ˆ" name="btn_cancel" tool_tip="æ¢å¾©ä¸Šä¸€å€‹å·²å„²å˜ç‰ˆæœ¬"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/zh/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/zh/floater_inventory_view_finder.xml index 9001615d89..ae05396cc5 100644 --- a/indra/newview/skins/default/xui/zh/floater_inventory_view_finder.xml +++ b/indra/newview/skins/default/xui/zh/floater_inventory_view_finder.xml @@ -12,6 +12,7 @@ <check_box label="è²éŸ³" name="check_sound"/> <check_box label="æè³ª" name="check_texture"/> <check_box label="å¿«ç…§" name="check_snapshot"/> + <check_box label="è¨å®š" name="check_settings"/> <button label="全部" label_selected="全部" name="All"/> <button label="ç„¡" label_selected="ç„¡" name="None"/> <check_box label="固定顯示資料夾" name="check_show_empty"/> diff --git a/indra/newview/skins/default/xui/zh/floater_merchant_outbox.xml b/indra/newview/skins/default/xui/zh/floater_merchant_outbox.xml deleted file mode 100644 index e6a70a7724..0000000000 --- a/indra/newview/skins/default/xui/zh/floater_merchant_outbox.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="floater_merchant_outbox" title="商家發件匣"> - <string name="OutboxFolderCount1"> - 1 個資料夾 - </string> - <string name="OutboxFolderCountN"> - [NUM] 個資料夾 - </string> - <string name="OutboxImporting"> - æ£åœ¨å‚³é€è³‡æ–™å¤¾â€¦ - </string> - <string name="OutboxInitializing"> - æ£åœ¨åˆå§‹åŒ–… - </string> - <panel label="" name="panel_1"> - <panel name="panel_2"> - <panel name="outbox_inventory_placeholder_panel"> - <text name="outbox_inventory_placeholder_title"> - 載入ä¸â€¦ - </text> - </panel> - </panel> - <panel name="panel_3"> - <panel name="outbox_generic_drag_target"> - <text name="text_1"> - æŠŠç‰©é …æ‹–æ›³åˆ°é€™è£¡ï¼Œå¯å»ºç«‹è³‡æ–™å¤¾ - </text> - </panel> - <button label="é€å¾€ç¬¬äºŒäººç”Ÿè³¼ç‰©å¸‚集" name="outbox_import_btn" tool_tip="推到我第二人生購物市集的店é¢"/> - </panel> - </panel> -</floater> diff --git a/indra/newview/skins/default/xui/zh/floater_my_environments.xml b/indra/newview/skins/default/xui/zh/floater_my_environments.xml new file mode 100644 index 0000000000..2184455dc9 --- /dev/null +++ b/indra/newview/skins/default/xui/zh/floater_my_environments.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater label="地點" name="my_environments" title="我的環境"> + <layout_stack> + <layout_panel label="éŽæ¿¾å™¨" name="filter_panel"> + <check_box label="æ—¥" name="chk_days"/> + <check_box label="天空" name="chk_skies"/> + <check_box label="æ°´æ–‡" name="chk_water"/> + <filter_editor label="éŽæ¿¾ç’°å¢ƒ" name="flt_search"/> + </layout_panel> + <layout_panel label="環境" name="list_panel"> + <panel label="pnl_inv_wrap" name="pnl_inv_wrap"/> + </layout_panel> + <layout_panel> + <check_box initial_value="false" label="顯示所有資料夾" name="chk_showfolders"/> + </layout_panel> + <layout_panel name="pnl_control"> + <panel label="bottom_panel" name="pnl_bottom"> + <menu_button name="btn_gear" tool_tip="更多é¸é …"/> + <menu_button name="btn_newsettings" tool_tip="製作新的è¨å®š"/> + <button name="btn_del" tool_tip="ç§»é™¤æ‰€é¸æ“‡çš„物å“"/> + </panel> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/zh/floater_perms_default.xml b/indra/newview/skins/default/xui/zh/floater_perms_default.xml index d4706d8d87..eb432a8bcd 100644 --- a/indra/newview/skins/default/xui/zh/floater_perms_default.xml +++ b/indra/newview/skins/default/xui/zh/floater_perms_default.xml @@ -37,6 +37,10 @@ <text name="label_12" tool_tip="è¨å®šé è¨æ¬Šé™æ±ºå®šä½•時建立æœè£æˆ–身體部ä½"> å¯ç©¿è£æ‰® </text> + <text name="label_13" tool_tip="è¨å®šé è¨æ¬Šé™æ±ºå®šä½•時建立環境è¨å®š"> + è¨å®š + </text> + <check_box name="env_settings_c" value="true"/> </panel> <button label="確定" label_selected="確定" name="ok"/> <button label="å–æ¶ˆ" label_selected="å–æ¶ˆ" name="cancel"/> diff --git a/indra/newview/skins/default/xui/zh/floater_pick_track.xml b/indra/newview/skins/default/xui/zh/floater_pick_track.xml new file mode 100644 index 0000000000..f86132a423 --- /dev/null +++ b/indra/newview/skins/default/xui/zh/floater_pick_track.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="track picker" title="鏿“‡ï¼šè»Œè·¡"> + <layout_stack name="adjuster"> + <layout_panel name="pnl_desc"> + <text name="select_description"> + 鏿“‡ä¾†æºå¤©ç©ºï¼š + </text> + </layout_panel> + <layout_panel name="pnl_traks"> + <radio_group name="track_selection"> + <radio_item label="天空4[ALT]" name="radio_sky4" value="4"/> + <radio_item label="天空3[ALT]" name="radio_sky3" value="3"/> + <radio_item label="天空2[ALT]" name="radio_sky2" value="2"/> + <radio_item label="地é¢" name="radio_sky1" value="1"/> + </radio_group> + </layout_panel> + <layout_panel name="pnl_ok_cancel"> + <button label="確定" label_selected="確定" name="btn_select"/> + <button label="å–æ¶ˆ" label_selected="å–æ¶ˆ" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/zh/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/zh/floater_preferences_graphics_advanced.xml index 7b127acd71..58314efeed 100644 --- a/indra/newview/skins/default/xui/zh/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/zh/floater_preferences_graphics_advanced.xml @@ -82,7 +82,6 @@ <check_box initial_value="true" label="æ¸…æ¾ˆé€æ˜Žçš„æ°´" name="TransparentWater"/> <check_box initial_value="true" label="å‡¹å‡¸æ˜ å°„èˆ‡å…‰æ¾¤æ•ˆæžœ" name="BumpShiny"/> <check_box initial_value="true" label="本地光線" name="LocalLights"/> - <check_box initial_value="true" label="基本著色" name="BasicShaders" tool_tip="關閉æ¤ä¸€é¸é …å¯èƒ½é¿å…部分顯示å¡é©…å‹•ç¨‹å¼ææ¯€ç•¶æ©Ÿ"/> <slider label="地形細節:" name="TerrainDetail"/> <text name="TerrainDetailText"> 低 diff --git a/indra/newview/skins/default/xui/zh/floater_preview_texture.xml b/indra/newview/skins/default/xui/zh/floater_preview_texture.xml index c56b1c2987..2b6eac48b3 100644 --- a/indra/newview/skins/default/xui/zh/floater_preview_texture.xml +++ b/indra/newview/skins/default/xui/zh/floater_preview_texture.xml @@ -10,7 +10,7 @@ æè¿°ï¼š </text> <text name="dimensions"> - [WIDTH] åƒç´ X [HEIGHT] åƒç´ + [WIDTH]åƒç´ x [HEIGHT]åƒç´ </text> <text name="aspect_ratio"> é 覽長寬比 diff --git a/indra/newview/skins/default/xui/zh/floater_settings_picker.xml b/indra/newview/skins/default/xui/zh/floater_settings_picker.xml new file mode 100644 index 0000000000..36e32777fb --- /dev/null +++ b/indra/newview/skins/default/xui/zh/floater_settings_picker.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="settings picker" title="鏿“‡ï¼šè¨å®š"> + <floater.string name="pick title"> + ç²¾é¸åœ°é»žï¼š + </floater.string> + <floater.string name="pick_track"> + é¸å–軌跡 + </floater.string> + <floater.string name="pick_settings"> + é¸å–è¨å®š + </floater.string> + <floater.string name="track_water"> + æ°´æ–‡ + </floater.string> + <floater.string name="track_ground"> + åœ°é¢ + </floater.string> + <floater.string name="track_sky"> + 天空[NUM] + </floater.string> + <layout_stack name="test_stack"> + <layout_panel name="inv_list"> + <filter_editor label="æè³ªéŽæ¿¾å™¨" name="flt_inventory_search"/> + </layout_panel> + <layout_panel name="temp"> + <button label="確定" label_selected="確定" name="btn_select"/> + <button label="å–æ¶ˆ" label_selected="å–æ¶ˆ" name="btn_cancel"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/zh/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/zh/floater_texture_ctrl.xml index 02d06323d4..6fc3e1129b 100644 --- a/indra/newview/skins/default/xui/zh/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/zh/floater_texture_ctrl.xml @@ -9,17 +9,13 @@ <text name="Multiple"> å¤šé‡æè³ª </text> - <radio_group name="mode_selection"> - <radio_item label="æ”¶ç´å€" name="inventory" value="0"/> - <radio_item label="本地" name="local" value="1"/> - </radio_group> - <text name="unknown"> - 尺寸:[DIMENSIONS] - </text> + <combo_box name="mode_selection"> + <combo_box.item label="æ”¶ç´å€" name="inventory" value="0"/> + <combo_box.item label="本地" name="local" value="1"/> + </combo_box> <button label="é è¨" label_selected="é è¨" name="Default"/> <button label="空白" label_selected="空白" name="Blank"/> <button label="ç„¡" label_selected="ç„¡" name="None"/> - <check_box initial_value="true" label="ç«‹å³å¥—用" name="apply_immediate_check"/> <text name="preview_disabled" value="å·²åœç”¨é 覽"/> <filter_editor label="æè³ªéŽæ¿¾å™¨" name="inventory search editor"/> <check_box initial_value="false" label="顯示資料夾" name="show_folders_check"/> @@ -30,6 +26,22 @@ <column label="å稱" name="unit_name"/> <column label="ID" name="unit_id_HIDDEN"/> </scroll_list> + <combo_box name="l_bake_use_texture_combo_box" tool_tip="鏿“‡å®šè²Œæè³ª"> + <combo_box.item label="ç„¡" name="None"/> + <combo_box.item label="BAKED_HEAD" name="BAKED_HEAD"/> + <combo_box.item label="BAKED_UPPER" name="BAKED_UPPER"/> + <combo_box.item label="BAKED_LOWER" name="BAKED_LOWER"/> + <combo_box.item label="BAKED_EYES" name="BAKED_EYES"/> + <combo_box.item label="BAKED_SKIRT" name="BAKED_SKIRT"/> + <combo_box.item label="BAKED_HAIR" name="BAKED_HAIR"/> + <combo_box.item label="BAKED_LEFTARM" name="BAKED_LEFTARM"/> + <combo_box.item label="BAKED_LEFTLEG" name="BAKED_LEFTLEG"/> + <combo_box.item label="BAKED_AUX1" name="BAKED_AUX1"/> + <combo_box.item label="BAKED_AUX2" name="BAKED_AUX2"/> + <combo_box.item label="BAKED_AUX3" name="BAKED_AUX3"/> + </combo_box> + <check_box initial_value="false" label="éš±è—基底網é¢å€åŸŸ" name="hide_base_mesh_region"/> <button label="確定" label_selected="確定" name="Select"/> <button label="å–æ¶ˆ" label_selected="å–æ¶ˆ" name="Cancel"/> + <check_box initial_value="true" label="ç«‹å³å¥—用" name="apply_immediate_check"/> </floater> diff --git a/indra/newview/skins/default/xui/zh/menu_cof_attachment.xml b/indra/newview/skins/default/xui/zh/menu_cof_attachment.xml index 876fef16df..6ab2220ca7 100644 --- a/indra/newview/skins/default/xui/zh/menu_cof_attachment.xml +++ b/indra/newview/skins/default/xui/zh/menu_cof_attachment.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="COF Attachment"> + <menu_item_call label="觸碰" name="touch_attach" /> + <menu_item_call label="編輯" name="edit_item" /> <menu_item_call label="å¸ä¸‹" name="detach"/> </context_menu> diff --git a/indra/newview/skins/default/xui/zh/menu_inventory.xml b/indra/newview/skins/default/xui/zh/menu_inventory.xml index 2ed078841e..10b170d4a4 100644 --- a/indra/newview/skins/default/xui/zh/menu_inventory.xml +++ b/indra/newview/skins/default/xui/zh/menu_inventory.xml @@ -10,7 +10,6 @@ <menu_item_call label="啟用" name="Marketplace Activate"/> <menu_item_call label="åœç”¨" name="Marketplace Deactivate"/> <menu_item_call label="分享" name="Share"/> - <menu_item_call label="購買" name="Task Buy"/> <menu_item_call label="打開" name="Task Open"/> <menu_item_call label="æ’æ”¾" name="Task Play"/> <menu_item_call label="屬性" name="Task Properties"/> @@ -34,6 +33,7 @@ <menu_item_call label="新內褲" name="New Underpants"/> <menu_item_call label="æ–°åŠé€æ˜Žé®ç½©" name="New Alpha Mask"/> <menu_item_call label="新刺é’" name="New Tattoo"/> + <menu_item_call label="新通用值" name="New Universal"/> <menu_item_call label="新身體物ç†" name="New Physics"/> </menu> <menu label="新身體部ä½" name="New Body Parts"> @@ -42,6 +42,11 @@ <menu_item_call label="æ–°é é«®" name="New Hair"/> <menu_item_call label="新眼ç›" name="New Eyes"/> </menu> + <menu label="æ–°çš„è¨å®š" name="New Settings"> + <menu_item_call label="新的天空" name="New Sky"/> + <menu_item_call label="新的水文" name="New Water"/> + <menu_item_call label="新的日循環" name="New Day Cycle"/> + </menu> <menu label="作這一用途的é è¨å€¼ï¼š" name="upload_def"> <menu_item_call label="圖åƒä¸Šå‚³" name="Image uploads"/> <menu_item_call label="è²éŸ³ä¸Šå‚³" name="Sound uploads"/> @@ -100,9 +105,12 @@ <menu_item_call label="穿上" name="Wearable And Object Wear"/> <menu label="附著到..." name="Attach To"/> <menu label="附著到擡é 顯示" name="Attach To HUD"/> + <menu_item_call label="觸碰" name="Attachment Touch" /> <menu_item_call label="編輯" name="Wearable Edit"/> <menu_item_call label="æ·»åŠ " name="Wearable Add"/> <menu_item_call label="脫下" name="Take Off"/> + <menu_item_call label="僅套用到我自己" name="Settings Apply Local"/> + <menu_item_call label="套用到地段" name="Settings Apply Parcel"/> <menu_item_call label="複製到 Marketplace 刊登" name="Marketplace Copy"/> <menu_item_call label="移到 Marketplace 刊登" name="Marketplace Move"/> <menu_item_call label="-- ç„¡é¸é … --" name="--no options--"/> diff --git a/indra/newview/skins/default/xui/zh/menu_inventory_add.xml b/indra/newview/skins/default/xui/zh/menu_inventory_add.xml index 30bf5a7e75..c64b399630 100644 --- a/indra/newview/skins/default/xui/zh/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/zh/menu_inventory_add.xml @@ -5,9 +5,7 @@ <menu_item_call label="è²éŸ³ï¼ˆL$[COST])..." name="Upload Sound"/> <menu_item_call label="動作(L$[COST])..." name="Upload Animation"/> <menu_item_call label="模型…" name="Upload Model"/> - <menu_item_call label="模型精éˆâ€¦" name="Upload Model Wizard"/> <menu_item_call label="批é‡ï¼ˆæ¯æª”案 L$[COST] )..." name="Bulk Upload"/> - <menu_item_call label="è¨å®šé è¨ä¸Šå‚³æ¬Šé™" name="perm prefs"/> </menu> <menu_item_call label="新資料夾" name="New Folder"/> <menu_item_call label="新腳本" name="New Script"/> @@ -25,6 +23,7 @@ <menu_item_call label="新內褲" name="New Underpants"/> <menu_item_call label="æ–°åŠé€æ˜Ž" name="New Alpha"/> <menu_item_call label="新刺é’" name="New Tattoo"/> + <menu_item_call label="新通用值" name="New Universal"/> <menu_item_call label="新身體物ç†" name="New Physics"/> </menu> <menu label="新身體部ä½" name="New Body Parts"> @@ -33,4 +32,9 @@ <menu_item_call label="æ–°é é«®" name="New Hair"/> <menu_item_call label="新眼ç›" name="New Eyes"/> </menu> + <menu label="æ–°çš„è¨å®š" name="New Settings"> + <menu_item_call label="新的天空" name="New Sky"/> + <menu_item_call label="新的水文" name="New Water"/> + <menu_item_call label="新的日循環" name="New Day Cycle"/> + </menu> </menu> diff --git a/indra/newview/skins/default/xui/zh/menu_outfit_gear.xml b/indra/newview/skins/default/xui/zh/menu_outfit_gear.xml index 124598a098..460adf9918 100644 --- a/indra/newview/skins/default/xui/zh/menu_outfit_gear.xml +++ b/indra/newview/skins/default/xui/zh/menu_outfit_gear.xml @@ -20,6 +20,7 @@ <menu_item_call label="æ–°åŠé€æ˜Ž" name="New Alpha"/> <menu_item_call label="新身體物ç†" name="New Physics"/> <menu_item_call label="新刺é’" name="New Tattoo"/> + <menu_item_call label="新通用值" name="New Universal"/> </menu> <menu label="新身體部ä½" name="New Body Parts"> <menu_item_call label="新體形" name="New Shape"/> diff --git a/indra/newview/skins/default/xui/zh/menu_save_settings.xml b/indra/newview/skins/default/xui/zh/menu_save_settings.xml new file mode 100644 index 0000000000..05ec0d97e2 --- /dev/null +++ b/indra/newview/skins/default/xui/zh/menu_save_settings.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="save_settings_menu"> + <menu_item_check label="儲å˜" name="save_settings"/> + <menu_item_check label="å¦å˜ç‚º" name="save_as_new_settings"/> + <menu_item_check label="確定" name="commit_changes"/> + <menu_item_check label="僅套用到我自己" name="apply_local"/> + <menu_item_check label="套用到地段" name="apply_parcel"/> + <menu_item_check label="套用到地å€" name="apply_region"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/zh/menu_settings_add.xml b/indra/newview/skins/default/xui/zh/menu_settings_add.xml new file mode 100644 index 0000000000..4e11741241 --- /dev/null +++ b/indra/newview/skins/default/xui/zh/menu_settings_add.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_add"> + <menu_item_call label="新的天空" name="New Sky"/> + <menu_item_call label="新的水文" name="New Water"/> + <menu_item_call label="新的日循環" name="New Day Cycle"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/zh/menu_settings_gear.xml b/indra/newview/skins/default/xui/zh/menu_settings_gear.xml new file mode 100644 index 0000000000..342f9d50b4 --- /dev/null +++ b/indra/newview/skins/default/xui/zh/menu_settings_gear.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<toggleable_menu name="menu_settings_gear"> + <menu_item_call label="編輯" name="edit_settings"/> + <menu_item_call label="僅套用到我自己" name="Settings Apply Local"/> + <menu_item_call label="套用到地段" name="Settings Apply Parcel"/> + <menu_item_call label="套用到地å€" name="Settings Apply Region"/> + <menu_item_call label="複製" name="copy_settings"/> + <menu_item_call label="貼上" name="paste_settings"/> + <menu_item_call label="覆製 UUID" name="copy_uuid"/> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/zh/menu_viewer.xml b/indra/newview/skins/default/xui/zh/menu_viewer.xml index a5c9684973..972434dfc5 100644 --- a/indra/newview/skins/default/xui/zh/menu_viewer.xml +++ b/indra/newview/skins/default/xui/zh/menu_viewer.xml @@ -77,30 +77,15 @@ <menu_item_check label="地段屬性" name="Parcel Properties"/> <menu_item_check label="進階é¸å–®" name="Show Advanced Menu"/> </menu> - <menu label="太陽" name="Sun"> + <menu label="環境" name="Environment"> <menu_item_check label="日出" name="Sunrise"/> <menu_item_check label="ä¸åˆ" name="Noon"/> <menu_item_check label="æ—¥è½" name="Sunset"/> <menu_item_check label="åˆå¤œ" name="Midnight"/> - <menu_item_check label="使用地å€è¨å®š" name="Use Region Settings"/> - </menu> - <menu label="環境編輯器" name="Environment Editor"> - <menu_item_call label="環境è¨å®šâ€¦" name="Environment Settings"/> - <menu label="水的自訂é…ç½®" name="Water Presets"> - <menu_item_call label="新的自訂é…置…" name="new_water_preset"/> - <menu_item_call label="編輯自訂é…置…" name="edit_water_preset"/> - <menu_item_call label="刪除自訂é…置…" name="delete_water_preset"/> - </menu> - <menu label="天空自訂é…ç½®" name="Sky Presets"> - <menu_item_call label="新的自訂é…置…" name="new_sky_preset"/> - <menu_item_call label="編輯自訂é…置…" name="edit_sky_preset"/> - <menu_item_call label="刪除自訂é…置…" name="delete_sky_preset"/> - </menu> - <menu label="日的自訂é…ç½®" name="Day Presets"> - <menu_item_call label="新的自訂é…置…" name="new_day_preset"/> - <menu_item_call label="編輯自訂é…置…" name="edit_day_preset"/> - <menu_item_call label="刪除自訂é…置…" name="delete_day_preset"/> - </menu> + <menu_item_check label="使用共享環境" name="Use Shared Environment"/> + <menu_item_call label="我的環境…" name="my_environs"/> + <menu_item_call label="個人照明⋯" name="adjustment_tool"/> + <menu_item_check label="æš«åœé›²å½©" name="pause_clouds"/> </menu> </menu> <menu label="å»ºé€ " name="BuildTools"> @@ -344,6 +329,9 @@ <menu_item_check label="自動åŠé€æ˜Žé®ç½©ï¼ˆéžéžå»¶ï¼‰" name="Automatic Alpha Masks (non-deferred)"/> <menu_item_check label="動作æè³ª" name="Animation Textures"/> <menu_item_check label="關閉æè³ª" name="Disable Textures"/> + <menu_item_check label="åœç”¨ç’°å¢ƒå…‰" name="Disable Ambient"/> + <menu_item_check label="åœç”¨æ—¥å…‰" name="Disable Sunlight"/> + <menu_item_check label="åœç”¨æœ¬åœ°å…‰ç·š" name="Disable Local Lights"/> <menu_item_check label="全解æžåº¦æè³ª" name="Rull Res Textures"/> <menu_item_check label="使附著燈光呈åƒ" name="Render Attached Lights"/> <menu_item_check label="ä½¿é™„è‘—ä¾‹åæ•ˆæžœå‘ˆåƒ" name="Render Attached Particles"/> @@ -481,6 +469,7 @@ <menu_item_call label="裙å" name="Skirt"/> <menu_item_call label="åŠé€æ˜Ž" name="Alpha"/> <menu_item_call label="刺é’" name="Tattoo"/> + <menu_item_call label="通用值" name="Universal"/> <menu_item_call label="身體物ç†" name="Physics"/> <menu_item_call label="全部衣æœ" name="All Clothes"/> </menu> diff --git a/indra/newview/skins/default/xui/zh/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/zh/menu_wearable_list_item.xml index 576f7f3b73..0093eb68f1 100644 --- a/indra/newview/skins/default/xui/zh/menu_wearable_list_item.xml +++ b/indra/newview/skins/default/xui/zh/menu_wearable_list_item.xml @@ -3,6 +3,7 @@ <menu_item_call label="å–代" name="wear_replace"/> <menu_item_call label="穿上" name="wear_wear"/> <menu_item_call label="æ·»åŠ " name="wear_add"/> + <menu_item_call label="觸碰" name="touch" /> <menu_item_call label="è„«ä¸‹è£æ‰® / å¸é™¤é™„ä»¶" name="take_off_or_detach"/> <menu_item_call label="å¸ä¸‹" name="detach"/> <context_menu label="附著到..." name="wearable_attach_to"/> diff --git a/indra/newview/skins/default/xui/zh/menu_wearing_gear.xml b/indra/newview/skins/default/xui/zh/menu_wearing_gear.xml index 6184f956d1..f09d4cfba9 100644 --- a/indra/newview/skins/default/xui/zh/menu_wearing_gear.xml +++ b/indra/newview/skins/default/xui/zh/menu_wearing_gear.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <toggleable_menu name="Gear Wearing"> - <menu_item_call label="ç·¨è¼¯è£æ‰®" name="edit"/> + <menu_item_call label="觸碰" name="touch"/> + <menu_item_call label="編輯" name="edit_item"/> + <menu_item_call label="ç·¨è¼¯è£æ‰®" name="edit_outfit"/> <menu_item_call label="脫下" name="takeoff"/> <menu_item_call label="è¤‡è£½è£æ‰®æ¸…單到剪貼簿" name="copy"/> </toggleable_menu> diff --git a/indra/newview/skins/default/xui/zh/menu_wearing_tab.xml b/indra/newview/skins/default/xui/zh/menu_wearing_tab.xml index dc9adcbd25..945297885e 100644 --- a/indra/newview/skins/default/xui/zh/menu_wearing_tab.xml +++ b/indra/newview/skins/default/xui/zh/menu_wearing_tab.xml @@ -1,8 +1,9 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <context_menu name="Wearing"> + <menu_item_call label="觸碰" name="touch_attach"/> <menu_item_call label="脫下" name="take_off"/> <menu_item_call label="å¸ä¸‹" name="detach"/> - <menu_item_call label="ç·¨è¼¯è£æ‰®" name="edit"/> + <menu_item_call label="ç·¨è¼¯è£æ‰®" name="edit_outfit"/> <menu_item_call label="編輯" name="edit_item"/> <menu_item_call label="顯示原件" name="show_original"/> </context_menu> diff --git a/indra/newview/skins/default/xui/zh/notifications.xml b/indra/newview/skins/default/xui/zh/notifications.xml index d304e95b09..cfde824349 100644 --- a/indra/newview/skins/default/xui/zh/notifications.xml +++ b/indra/newview/skins/default/xui/zh/notifications.xml @@ -1954,6 +1954,11 @@ SHA1 指紋:[MD5_DIGEST] è‹¥ä¸å‹¾é¸é€™é¸é …,å¯èƒ½æœƒç§»é™¤åœ°æ®µæ‰€æœ‰äººç‚ºé˜²æ¢æƒ¡æ„騷擾åŠç‚ºç¶è·éš±ç§ã€ä¿è·å¹¼æœªæˆå¹´å±…æ°‘ä¸æŽ¥è§¸æˆå¹´é™åˆ¶ç´šå…§å®¹çš„é™åˆ¶æŽªæ–½ã€‚ 若有必è¦è«‹èˆ‡åœ°æ®µæ‰€æœ‰äººæºé€šã€‚ <usetemplate name="okbutton" yestext="確定"/> </notification> + <notification name="EstateParcelEnvironmentOverride"> + å–æ¶ˆå‹¾é¸é€™é¸é …æœƒç§»é™¤åœ°æ®µæ“æœ‰äººå¢žè¨æ–¼åœ°æ®µçš„任何自訂環境è¨å®šã€‚ 若有必è¦è«‹èˆ‡åœ°æ®µæ‰€æœ‰äººæºé€šã€‚ +ä½ ç¢ºå®šè¦ç¹¼çºŒå—Žï¼Ÿ + <usetemplate name="okcancelbuttons" notext="å–æ¶ˆ" yestext="確定"/> + </notification> <notification name="RegionEntryAccessBlocked"> ä½ æ‰€æ¬²å‰å¾€çš„地å€å«æœ‰è¶…éŽä½ ç›®å‰å好的分級的內容。 ä½ å¯ä»¥åˆ°ã€Œæˆ‘自己 > å好è¨å®š > 一般è¨å®šã€è®Šæ›´ä½ çš„å好è¨å®šã€‚ <usetemplate name="okbutton" yestext="確定"/> @@ -2433,7 +2438,15 @@ SHA1 指紋:[MD5_DIGEST] é€™å€‹ã€Œä¸€æ—¥å¾ªç’°ã€æª”案åƒè€ƒäº†ä¸€å€‹ä¸å˜åœ¨çš„天空檔案:[SKY]。 </notification> <notification name="WLRegionApplyFail"> - 抱æ‰ï¼Œè¨å®šç„¡æ³•套用到地å€ã€‚ 離開地å€å†è¿”回也許å¯ä»¥è§£æ±ºé€™å€‹å•題。 æ‰€å¾—çš„åŽŸå› ç‚ºï¼š[FAIL_REASON] + 抱æ‰ï¼Œè¨å®šç„¡æ³•套用到地å€ã€‚ åŽŸå› ï¼š[FAIL_REASON] + </notification> + <notification name="WLLocalTextureDayBlock"> + 一個本地æè³ªæ£åœ¨ä½¿ç”¨ä¸ï¼šè»Œè·¡[TRACK],幀#[FRAMENO]([FRAME]%),欄ä½[FIELD]。 +無法儲å˜ä½¿ç”¨æœ¬åœ°æè³ªçš„è¨å®šã€‚ + </notification> + <notification name="WLLocalTextureFixedBlock"> + 一個本地æè³ªæ£åœ¨æ¬„ä½[FIELD]使用ä¸ã€‚ +無法儲å˜ä½¿ç”¨æœ¬åœ°æè³ªçš„è¨å®šã€‚ </notification> <notification name="EnvCannotDeleteLastDayCycleKey"> ç„¡æ³•åˆªé™¤æ¤æ—¥å¾ªç’°çš„æœ€å¾Œä¸€çµ„è¨å®šï¼Œæ—¥å¾ªç’°ä¸å¾—為空白。 ä½ æ‡‰è©²ä¿®æ”¹æœ€å¾Œä¸€çµ„è³‡æ–™ï¼Œä¸è¦è©¦åœ–刪除,然後å†å»ºç«‹æ–°çš„。 @@ -4380,4 +4393,76 @@ SHA1 指紋:[MD5_DIGEST] [REASON] <usetemplate name="okbutton" yestext="確定"/> </notification> + <notification name="FailedToFindSettings"> + 無法從資料庫載入[NAME]çš„è¨å®šã€‚ + </notification> + <notification name="FailedToLoadSettingsApply"> + 無法將è¨å®šå¥—用到環境。 + </notification> + <notification name="FailedToBuildSettingsDay"> + 無法將è¨å®šå¥—用到環境。 + </notification> + <notification name="NoEnvironmentSettings"> + 這å€åŸŸä¸æ”¯æ´ç’°å¢ƒè¨å®šã€‚ + </notification> + <notification label="儲å˜è£æ‰®" name="SaveSettingAs"> + 把目å‰çš„環境è¨å®šå„²å˜ç‚ºï¼š + <form name="form"> + <input name="message"> + [DESC](新) + </input> + <button name="OK" text="確定"/> + <button name="Cancel" text="å–æ¶ˆ"/> + </form> + </notification> + <notification name="WLImportFail"> + 無法匯入舊的風光(Windlight)è¨å®š[NAME],來æºï¼š +[FILE]。 + +[REASONS] + </notification> + <notification name="WLParcelApplyFail"> + 無法è¨å®šæ¤åœ°æ®µçš„環境。 +è«‹è¼¸å…¥æˆ–é¸æ“‡ä¸€å€‹ä½ 有權修改的地段。 + </notification> + <notification name="SettingsUnsuported"> + 這地å€ä¸æ”¯æ´è¨å®šã€‚ +è«‹ç§»ä½åˆ°æ”¯æ´è¨å®šçš„地å€ï¼Œå†è©¦ä¸€æ¬¡ã€‚ + </notification> + <notification name="SettingsConfirmLoss"> + ä½ å³å°‡é‡å°å爲"[NAME]"çš„[TYPE]放棄變更。 +確定繼續? + <usetemplate ignoretext="確定放棄變更?" name="okcancelignore" notext="å–æ¶ˆ" yestext="確定"/> + </notification> + <notification name="SettingsConfirmReset"> + ä½ å³å°‡ç§»é™¤æ‰€æœ‰å·²ç”¨çš„è¨å®šã€‚ +確定繼續? + <usetemplate name="okcancelbuttons" notext="å–æ¶ˆ" yestext="確定"/> + </notification> + <notification name="PersonalSettingsConfirmReset"> + ä½ å³å°‡ç§»é™¤æ‰€æœ‰å·²ç”¨çš„個人照明è¨å®šã€‚ +確定繼續? + <usetemplate name="okcancelbuttons" notext="å–æ¶ˆ" yestext="確定"/> + </notification> + <notification name="SettingsMakeNoTrans"> + ä½ å³å°‡æŠŠç„¡æ³•轉移的è¨å®šåŒ¯å…¥é€™å€‹æ—¥å¾ªç’°ã€‚ å¦‚æžœç¹¼çºŒï¼Œå°‡ä½¿å¾—ä½ æ£åœ¨ç·¨è¼¯çš„è¨å®šä¹Ÿè®Šæˆç„¡æ³•轉移。 + +é€™å€‹æ”¹è®Šç„¡æ³•å–æ¶ˆå¾©åŽŸã€‚ + +確定繼續? + <usetemplate ignoretext="ç¢ºå®šè¦æŠŠè¨å®šè®Šæˆç„¡æ³•轉移?" name="okcancelignore" notext="å–æ¶ˆ" yestext="確定"/> + </notification> + <notification name="NoEditFromLibrary"> + ä½ ä¸å¾—直接從資æºåº«ç·¨è¼¯è¨å®šã€‚ +è«‹è¤‡è£½åˆ°ä½ è‡ªå·±çš„æ”¶ç´å€ï¼Œç„¶å¾Œå†è©¦ä¸€æ¬¡ã€‚ + </notification> + <notification name="EnvironmentApplyFailed"> + 這些è¨å®šç™¼ç”Ÿä¸€å€‹å•題。 å®ƒå€‘æ¤æ™‚ç„¡æ³•å„²å˜æˆ–套用。 + </notification> + <notification name="TrackLoadFailed"> + 無法把軌跡載入[TRACK]。 + </notification> + <notification name="TrackLoadMismatch"> + 無法把軌跡從[TRACK1]載入[TRACK2]。 + </notification> </notifications> diff --git a/indra/newview/skins/default/xui/zh/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/zh/panel_edit_tattoo.xml index f5111d629a..10ed653472 100644 --- a/indra/newview/skins/default/xui/zh/panel_edit_tattoo.xml +++ b/indra/newview/skins/default/xui/zh/panel_edit_tattoo.xml @@ -1,9 +1,11 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_tattoo_panel"> - <panel name="avatar_tattoo_color_panel"> - <texture_picker label="é 部刺é’" name="Head Tattoo" tool_tip="點按以挑é¸åœ–片"/> - <texture_picker label="上åŠèº«åˆºé’" name="Upper Tattoo" tool_tip="點按以挑é¸åœ–片"/> - <texture_picker label="下åŠèº«åˆºé’" name="Lower Tattoo" tool_tip="點按以挑é¸åœ–片"/> - <color_swatch label="é¡è‰²/色調" name="Color/Tint" tool_tip="點按以開啟é¡è‰²æŒ‘é¸å™¨"/> - </panel> + <scroll_container name="avatar_tattoo_scroll"> + <panel name="avatar_tattoo_color_panel"> + <texture_picker label="é 部刺é’" name="Head Tattoo" tool_tip="點按以挑é¸åœ–片"/> + <texture_picker label="上åŠèº«åˆºé’" name="Upper Tattoo" tool_tip="點按以挑é¸åœ–片"/> + <texture_picker label="下åŠèº«åˆºé’" name="Lower Tattoo" tool_tip="點按以挑é¸åœ–片"/> + <color_swatch label="é¡è‰²/色調" name="Color/Tint" tool_tip="點按以開啟é¡è‰²æŒ‘é¸å™¨"/> + </panel> + </scroll_container> </panel> diff --git a/indra/newview/skins/default/xui/zh/panel_edit_universal.xml b/indra/newview/skins/default/xui/zh/panel_edit_universal.xml new file mode 100644 index 0000000000..6974efcc89 --- /dev/null +++ b/indra/newview/skins/default/xui/zh/panel_edit_universal.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel name="edit_universal_panel"> + <scroll_container name="avatar_universal_scroll"> + <panel name="avatar_universal_color_panel"> + <texture_picker label="é 部刺é’" name="Head Universal Tattoo" tool_tip="點按以挑é¸åœ–片"/> + <texture_picker label="上åŠèº«åˆºé’" name="Upper Universal Tattoo" tool_tip="點按以挑é¸åœ–片"/> + <texture_picker label="下åŠèº«åˆºé’" name="Lower Universal Tattoo" tool_tip="點按以挑é¸åœ–片"/> + <texture_picker label="裙å刺é’" name="Skirt Tattoo" tool_tip="點按以挑é¸åœ–片"/> + <texture_picker label="é 髮刺é’" name="Hair Tattoo" tool_tip="點按以挑é¸åœ–片"/> + <texture_picker label="眼ç›åˆºé’" name="Eyes Tattoo" tool_tip="點按以挑é¸åœ–片"/> + <texture_picker label="左臂刺é’" name="Left Arm Tattoo" tool_tip="點按以挑é¸åœ–片"/> + <texture_picker label="左腿刺é’" name="Left Leg Tattoo" tool_tip="點按以挑é¸åœ–片"/> + <texture_picker label="Aux1刺é’" name="Aux1 Tattoo" tool_tip="點按以挑é¸åœ–片"/> + <texture_picker label="Aux2刺é’" name="Aux2 Tattoo" tool_tip="點按以挑é¸åœ–片"/> + <texture_picker label="Aux3刺é’" name="Aux3 Tattoo" tool_tip="點按以挑é¸åœ–片"/> + <color_swatch label="é¡è‰²/色調" name="Color/Tint" tool_tip="點按以開啟é¡è‰²æŒ‘é¸å™¨"/> + </panel> + </scroll_container> +</panel> diff --git a/indra/newview/skins/default/xui/zh/panel_edit_wearable.xml b/indra/newview/skins/default/xui/zh/panel_edit_wearable.xml index 4dd7ea6d93..d41785858a 100644 --- a/indra/newview/skins/default/xui/zh/panel_edit_wearable.xml +++ b/indra/newview/skins/default/xui/zh/panel_edit_wearable.xml @@ -45,6 +45,9 @@ <string name="edit_tattoo_title"> 刺é’ç·¨è¼¯ä¸ </string> + <string name="edit_universal_title"> + 編輯通用值 + </string> <string name="edit_physics_title"> 身體物ç†ç·¨è¼¯ä¸ </string> @@ -93,6 +96,9 @@ <string name="tattoo_desc_text"> 刺é’: </string> + <string name="universal_desc_text"> + 通用值: + </string> <string name="physics_desc_text"> 身體物ç†ï¼š </string> diff --git a/indra/newview/skins/default/xui/zh/panel_outbox_inventory.xml b/indra/newview/skins/default/xui/zh/panel_outbox_inventory.xml deleted file mode 100644 index 8de0bb0e4d..0000000000 --- a/indra/newview/skins/default/xui/zh/panel_outbox_inventory.xml +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<outbox_inventory_panel name="inventory_outbox" tool_tip="å°‡ç‰©é …æ‹–æ›³ä¸¦ç½®æ”¾åˆ°é€™è£¡ï¼Œæº–å‚™åœ¨ä½ çš„å•†åº—å‡ºå”®"/> diff --git a/indra/newview/skins/default/xui/zh/panel_region_environment.xml b/indra/newview/skins/default/xui/zh/panel_region_environment.xml index afea391dda..8caadf50ae 100644 --- a/indra/newview/skins/default/xui/zh/panel_region_environment.xml +++ b/indra/newview/skins/default/xui/zh/panel_region_environment.xml @@ -1,33 +1,116 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="環境" name="panel_env_info"> - <text name="water_settings_title"> - 鏿“‡ä½ å¸Œæœ›åˆ°ä½ åœ°å€çš„訪客所能看到的水和天空 / 日循環è¨å®šã€‚ 詳情 - </text> - <radio_group name="region_settings_radio_group"> - <radio_item label="使用第二人生é è¨å€¼" name="use_sl_default_settings"/> - <radio_item label="使用以下è¨å®š" name="use_my_settings"/> - </radio_group> - <panel name="user_environment_settings"> - <text name="water_settings_title"> - æ°´çš„è¨å®š - </text> - <combo_box name="water_settings_preset_combo"> - <combo_box.item label="-鏿“‡ä¸€å€‹è‡ªè¨‚é…ç½®-" name="item0"/> - </combo_box> - <text name="sky_dayc_settings_title"> - å¤©ç©ºï¼æ—¥å¾ªç’° - </text> - <radio_group name="sky_dayc_settings_radio_group"> - <radio_item label="固定天空" name="my_sky_settings"/> - <radio_item label="日循環" name="my_dayc_settings"/> - </radio_group> - <combo_box name="sky_settings_preset_combo"> - <combo_box.item label="-鏿“‡ä¸€å€‹è‡ªè¨‚é…ç½®-" name="item0"/> - </combo_box> - <combo_box name="dayc_settings_preset_combo"> - <combo_box.item label="-鏿“‡ä¸€å€‹è‡ªè¨‚é…ç½®-" name="item0"/> - </combo_box> - </panel> - <button label="套用" name="apply_btn"/> - <button label="å–æ¶ˆ" name="cancel_btn"/> + <string name="str_label_use_default"> + 使用é è¨è¨å®š + </string> + <string name="str_label_use_region"> + 使用地å€è¨å®š + </string> + <string name="str_altitude_desription"> + 天空 [INDEX]([ALTITUDE]m) + </string> + <string name="str_no_parcel"> + æœªé¸æ“‡åœ°æ®µã€‚ 環境è¨å®šå·²åœç”¨ã€‚ + </string> + <string name="str_cross_region"> + 跨越地å€ä¸æä¾›ç’°å¢ƒè¨å®šã€‚ + </string> + <string name="str_legacy"> + 這地å€ä¸æä¾›ç’°å¢ƒè¨å®šã€‚ + </string> + <string name="str_disallowed"> + é ˜åœ°ç®¡ç†äººä¸å…許改變æ¤å€åŸŸçš„地段環境。 + </string> + <string name="str_too_small"> + åœ°æ®µå¿…é ˆè‡³å°‘128平方公尺æ‰å¯æ”¯æ’環境。 + </string> + <string name="str_empty"> + (空白) + </string> + <string name="str_region_env"> + (地å€ç’°å¢ƒï¼‰ + </string> + <layout_stack> + <layout_panel name="pnl_environment_disabled"> + <text name="txt_environment_disabled"> + ... + </text> + </layout_panel> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_config"> + <layout_stack> + <layout_panel name="pnl_environment_current"> + <button label="[USEDEFAULT]" name="btn_usedefault"/> + <button label="使用收ç´å€" name="btn_select_inventory"/> + <button label="自訂" name="btn_edit"/> + <check_box label="地段所有人å¯å¼·åˆ¶è¨å®šç’°å¢ƒ" name="chk_allow_override"/> + </layout_panel> + <layout_panel name="pnl_environment_length"> + <text name="lbl_apparent_time"> + [HH]:[MM][AP] ([PRC]%) + </text> + </layout_panel> + <layout_panel name="pnl_environment_buttons"/> + </layout_stack> + </layout_panel> + <layout_panel name="pnl_environment_altitudes"> + <panel name="pnl_alt1"> + <text name="txt_alt1"> + 天空[INDEX] + [ALTITUDE]公尺 + </text> + <line_editor name="edt_invname_alt1"> + 未知 + </line_editor> + <settings_drop_target name="sdt_alt1" tool_tip="將一個è¨å®šå¾žæ”¶ç´å€æ‹–æ›³åˆ°é€™å€‹ç›®æ¨™ç®±æ¡†ï¼Œä¾¿å¯æŠŠå®ƒé¸å®šç‚ºç›®å‰çš„天空。"/> + </panel> + <panel name="pnl_alt2"> + <text name="txt_alt2"> + 天空[INDEX] + [ALTITUDE]公尺 + </text> + <line_editor name="edt_invname_alt2"> + 未知 + </line_editor> + <settings_drop_target name="sdt_alt2" tool_tip="將一個è¨å®šå¾žæ”¶ç´å€æ‹–æ›³åˆ°é€™å€‹ç›®æ¨™ç®±æ¡†ï¼Œä¾¿å¯æŠŠå®ƒé¸å®šç‚ºç›®å‰çš„天空。"/> + </panel> + <panel name="pnl_alt3"> + <text name="txt_alt3"> + 天空[INDEX] + [ALTITUDE]公尺 + </text> + <line_editor name="edt_invname_alt3"> + 未知 + </line_editor> + <settings_drop_target name="sdt_alt3" tool_tip="將一個è¨å®šå¾žæ”¶ç´å€æ‹–æ›³åˆ°é€™å€‹ç›®æ¨™ç®±æ¡†ï¼Œä¾¿å¯æŠŠå®ƒé¸å®šç‚ºç›®å‰çš„天空。"/> + </panel> + <multi_slider initial_value="0" name="sld_altitudes"> + <slider name="sld1" value="1000"/> + <slider name="sld2" value="2000"/> + <slider name="sld3" value="3000"/> + </multi_slider> + <panel name="pnl_ground"> + <text name="txt_ground"> + åœ°é¢ + </text> + <line_editor name="edt_invname_ground"> + 未知 + </line_editor> + <settings_drop_target name="sdt_ground" tool_tip="將一個è¨å®šå¾žæ”¶ç´å€æ‹–æ›³åˆ°é€™å€‹ç›®æ¨™ç®±æ¡†ï¼Œä¾¿å¯æŠŠå®ƒé¸å®šç‚ºåœ°é¢æ°´å¹³çš„天空。"/> + </panel> + <panel name="pnl_water"> + <text name="txt_water"> + æ°´æ–‡ + </text> + <line_editor name="edt_invname_water"> + 未知 + </line_editor> + <settings_drop_target name="sdt_water" tool_tip="將一個è¨å®šå¾žæ”¶ç´å€æ‹–æ›³åˆ°é€™å€‹ç›®æ¨™ç®±æ¡†ï¼Œä¾¿å¯æŠŠå®ƒé¸å®šç‚ºç›®å‰çš„æ°´æ–‡ã€‚"/> + </panel> + <button label="é‡è¨" name="btn_rst_altitudes" tool_tip="é‡è¨ç‚ºé è¨é«˜åº¦"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> </panel> diff --git a/indra/newview/skins/default/xui/zh/panel_settings_sky_atmos.xml b/indra/newview/skins/default/xui/zh/panel_settings_sky_atmos.xml new file mode 100644 index 0000000000..a352055d6d --- /dev/null +++ b/indra/newview/skins/default/xui/zh/panel_settings_sky_atmos.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="大氣與照明" name="panel_settings_sky_atmos"/> diff --git a/indra/newview/skins/default/xui/zh/panel_settings_sky_clouds.xml b/indra/newview/skins/default/xui/zh/panel_settings_sky_clouds.xml new file mode 100644 index 0000000000..e27e2278df --- /dev/null +++ b/indra/newview/skins/default/xui/zh/panel_settings_sky_clouds.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="雲彩" name="panel_settings_sky_clouds"> + <layout_stack> + <layout_panel> + <slider label="X" name="cloud_density_x"/> + <slider label="Y" name="cloud_density_y"/> + <slider label="D" name="cloud_density_d"/> + <slider label="X" name="cloud_detail_x"/> + <slider label="Y" name="cloud_detail_y"/> + <slider label="D" name="cloud_detail_d"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/zh/panel_settings_sky_density.xml b/indra/newview/skins/default/xui/zh/panel_settings_sky_density.xml new file mode 100644 index 0000000000..ddd5ecfe49 --- /dev/null +++ b/indra/newview/skins/default/xui/zh/panel_settings_sky_density.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="密度" name="panel_settings_sky_density"> + <layout_stack> + <layout_panel> + <slider label="RayleighæŒ‡æ•¸é …ï¼š" name="rayleigh_exponential"/> + <slider label="Rayleigh指數比例尺:" name="rayleigh_exponential_scale"/> + <slider label="Rayleighç·šæ€§é …ï¼š" name="rayleigh_linear"/> + <slider label="Rayleighå¸¸æ•¸é …ï¼š" name="rayleigh_constant"/> + <slider label="Rayleigh最大高度:" name="rayleigh_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="MieæŒ‡æ•¸é …ï¼š" name="mie_exponential"/> + <slider label="Mie指數比例尺:" name="mie_exponential_scale"/> + <slider label="Mieç·šæ€§é …ï¼š" name="mie_linear"/> + <slider label="Mieå¸¸æ•¸é …ï¼š" name="mie_constant"/> + <slider label="Mie Anisoå› æ•¸ï¼š" name="mie_aniso_factor"/> + <slider label="Mie最大高度:" name="mie_max_altitude"/> + </layout_panel> + <layout_panel> + <slider label="叿”¶æŒ‡æ•¸é …:" name="absorption_exponential"/> + <slider label="叿”¶æŒ‡æ•¸æ¯”例尺:" name="absorption_exponential_scale"/> + <slider label="叿”¶ç·šæ€§é …:" name="absorption_linear"/> + <slider label="叿”¶å¸¸æ•¸é …:" name="absorption_constant"/> + <slider label="叿”¶æœ€å¤§é«˜åº¦ï¼š" name="absorption_max_altitude"/> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/zh/panel_settings_sky_sunmoon.xml b/indra/newview/skins/default/xui/zh/panel_settings_sky_sunmoon.xml new file mode 100644 index 0000000000..7d1d433cbc --- /dev/null +++ b/indra/newview/skins/default/xui/zh/panel_settings_sky_sunmoon.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="日與月" name="panel_settings_sky_hbodies"> + <layout_stack> + <layout_panel name="sun_layout"> + <check_box label="顯示指標" name="sunbeacon"/> + </layout_panel> + <layout_panel> + <layout_stack> + <layout_panel name="moon_layout"> + <check_box label="顯示指標" name="moonbeacon"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/zh/panel_settings_water.xml b/indra/newview/skins/default/xui/zh/panel_settings_water.xml new file mode 100644 index 0000000000..59687c001b --- /dev/null +++ b/indra/newview/skins/default/xui/zh/panel_settings_water.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="æ°´æ–‡" name="panel_settings_water"> + <layout_stack name="water_stack1"> + <layout_panel> + <text name="FresnelOffsetText"> + è²æ¶…耳åè·ï¼š + </text> + </layout_panel> + <layout_panel> + <layout_stack name="water_stack2"> + <layout_panel> + <slider label="X:" name="water_normal_scale_x"/> + <slider label="Y:" name="water_normal_scale_y"/> + <slider label="Z:" name="water_normal_scale_z"/> + </layout_panel> + </layout_stack> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/zh/panel_tools_texture.xml b/indra/newview/skins/default/xui/zh/panel_tools_texture.xml index 9a4e2f68a8..f7868ff855 100644 --- a/indra/newview/skins/default/xui/zh/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/zh/panel_tools_texture.xml @@ -1,11 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="æè³ª" name="Texture"> - <panel.string name="string repeats per meter"> - æ¯å…¬å°ºé‡è¦†æ¬¡æ•¸ - </panel.string> - <panel.string name="string repeats per face"> - æ¯ä¸€é¢é‡è¦†æ¬¡æ•¸ - </panel.string> <text name="color label"> é¡è‰² </text> @@ -114,4 +108,5 @@ <spinner label="æ°´å¹³åè·" name="shinyOffsetU"/> <spinner label="垂直åè·" name="shinyOffsetV"/> <check_box initial_value="false" label="å°é½Šå¹³é¢" name="checkbox planar align" tool_tip="ä»¥æœ€å¾Œæ‰€é¸æ“‡çš„é¢ç‚ºåŸºæº–,å°é½Šå…¨éƒ¨æ‰€é¸æ“‡çš„é¢ä¸Šçš„æè³ªã€‚ é€™å¿…é ˆä½¿ç”¨å¹³é¢æè³ªæ˜ å°„æ–¹å¼ã€‚"/> + <button label="å°é½Š" label_selected="å°é½Šç›®å‰çš„æè³ªå±¤æ¬¡" name="button align textures" tool_tip="å°é½Šç›®å‰çš„æè³ªå±¤æ¬¡"/> </panel> diff --git a/indra/newview/skins/default/xui/zh/role_actions.xml b/indra/newview/skins/default/xui/zh/role_actions.xml index e3b0eb1261..e7865b6056 100644 --- a/indra/newview/skins/default/xui/zh/role_actions.xml +++ b/indra/newview/skins/default/xui/zh/role_actions.xml @@ -33,6 +33,7 @@ <action description="更改音樂和媒體è¨å®š" longdescription="在「土地資料ã€> 媒體é 籤更改串æµéŸ³æ¨‚和影片è¨å®šã€‚" name="land change media" value="20"/> <action description="切æ›ã€Œç·¨è¼¯åœ°å½¢ã€è¨å®š" longdescription="切æ›ã€Œç·¨è¼¯åœ°å½¢ã€è¨å®šã€‚ *è¦å‘Š* 「土地資料ã€> 「é¸é …ã€é 籤 >「編輯地形ã€å¯å…è¨±ä»»ä½•äººè®Šæ›´ä½ çš„åœŸåœ°å½¢ç‹€ï¼Œæ”¾ç½®æˆ–ç§»å‹• Linden æ¤ç‰©ã€‚ è³¦äºˆé€™é …èƒ½åŠ›ä¹‹å‰ï¼Œæ•¬è«‹æ…Žé‡è€ƒæ…®ã€‚ 編輯地形å¯åœ¨ã€ŒåœŸåœ°è³‡æ–™ã€> é¸é …é 籤åšåˆ‡æ›ã€‚" name="land edit" value="21"/> <action description="切æ›å„é …ã€ŒåœŸåœ°è³‡æ–™ã€> é¸é …è¨å®š" longdescription="在「土地資料ã€> é¸é …é 籤切æ›ã€Œå®‰å…¨ï¼ˆç„¡å‚·å®³ï¼‰ã€è¨å®šï¼Œä¸¦å…許其他居民在群組所有土地上「編輯地形ã€ã€ã€Œå»ºè£½ã€ã€ã€Œå»ºç«‹åœ°æ¨™ã€ã€ã€ŒåŸ·è¡Œè…³æœ¬ã€ã€‚" name="land options" value="22"/> + <action description="修改環境è¨å®šå’Œæ—¥å¾ªç’°ã€‚" longdescription="從「土地資料ã€>「環境é 籤ã€è®Šæ›´ç’°å¢ƒè¨å®šå’Œæ—¥å¾ªç’°ã€‚" name="land change environment" value="46"/> </action_set> <action_set description="這些能力包括å¯å…許æˆå“¡åœ¨ç¾¤çµ„所有地段上è¦é¿é™åˆ¶ã€‚" name="Parcel Powers"> <action description="固定å…許「編輯地形ã€" longdescription="èº«è² å…·æ¤èƒ½åŠ›çš„è§’è‰²çš„æˆå“¡å¯ä»¥åœ¨ç¾¤çµ„所有地段上編輯地形,無論這功能在「土地資料ã€> é¸é …é 籤裡是å¦è¢«ç¦æ¢ã€‚" name="land allow edit land" value="23"/> diff --git a/indra/newview/skins/default/xui/zh/strings.xml b/indra/newview/skins/default/xui/zh/strings.xml index bbbaf57501..e6c61a5d94 100644 --- a/indra/newview/skins/default/xui/zh/strings.xml +++ b/indra/newview/skins/default/xui/zh/strings.xml @@ -635,6 +635,15 @@ http://secondlife.com/viewer-access-faq <string name="BUTTON_HELP"> 顯示幫助 </string> + <string name="TooltipNotecardNotAllowedTypeDrop"> + é€™ç¨®é¡žåž‹çš„ç‰©é …ä¸èƒ½é™„è‘— +到這一å€åŸŸçš„記事å¡ã€‚ + </string> + <string name="TooltipNotecardOwnerRestrictedDrop"> + å”¯æœ‰ã€Œä¸‹ä¸€æ‰€æœ‰äººã€æ¬Šé™ +ä¸å—é™åˆ¶çš„ç‰©é …æ‰å¯ +附著到記事å¡ã€‚ + </string> <string name="Searching"> æœå°‹ä¸... </string> @@ -711,6 +720,18 @@ http://secondlife.com/viewer-access-faq ä¸Šå‚³è¦æ±‚發生錯誤。 è«‹åƒè¦‹ï¼š http://secondlife.com/support 求助解決å•題。 </string> + <string name="SettingValidationError"> + 匯入è¨å®š[NAME]時驗è‰å¤±æ•— + </string> + <string name="SettingImportFileError"> + 無法開啟檔案[FILE] + </string> + <string name="SettingParseFileError"> + 無法開啟檔案[FILE] + </string> + <string name="SettingTranslateError"> + 無法轉è¯èˆŠçš„風光(windlight)[NAME] + </string> <string name="texture"> æè³ª </string> @@ -786,6 +807,9 @@ http://secondlife.com/support 求助解決å•題。 <string name="symbolic folder link"> 資料夾è¯çµ </string> + <string name="settings blob"> + è¨å®š + </string> <string name="mesh"> ç¶²é¢ </string> @@ -1116,6 +1140,9 @@ http://secondlife.com/support 求助解決å•題。 <string name="ForceSitAvatar"> å¼·è¿«ä½ çš„åŒ–èº«å下 </string> + <string name="ChangeEnvSettings"> + æ”¹è®Šä½ çš„ç’°å¢ƒè¨å®š + </string> <string name="NotConnected"> æœªè¯æŽ¥ </string> @@ -1267,6 +1294,9 @@ http://secondlife.com/support 求助解決å•題。 <string name="tattoo"> åˆºé’ </string> + <string name="universal"> + 通用值 + </string> <string name="physics"> èº«é«”ç‰©ç† </string> @@ -1309,6 +1339,9 @@ http://secondlife.com/support 求助解決å•題。 <string name="tattoo_not_worn"> åˆºé’æœªç©¿ </string> + <string name="universal_not_worn"> + 未穿戴通用值 + </string> <string name="physics_not_worn"> èº«é«”ç‰©ç†æœªç©¿ </string> @@ -1360,6 +1393,9 @@ http://secondlife.com/support 求助解決å•題。 <string name="create_new_tattoo"> å‰µé€ æ–°åˆºé’ </string> + <string name="create_new_universal"> + 創立新的通用值 + </string> <string name="create_new_physics"> å‰µé€ æ–°èº«é«”ç‰©ç† </string> @@ -2507,6 +2543,27 @@ http://secondlife.com/support 求助解決å•題。 <string name="RegionSettings"> 地å€è¨å®š </string> + <string name="NoEnvironmentSettings"> + 這å€åŸŸä¸æ”¯æ´ç’°å¢ƒè¨å®šã€‚ + </string> + <string name="EnvironmentSun"> + 太陽 + </string> + <string name="EnvironmentMoon"> + 月亮 + </string> + <string name="EnvironmentBloom"> + 開花 + </string> + <string name="EnvironmentCloudNoise"> + 雲彩噪度 + </string> + <string name="EnvironmentNormalMap"> + æ£å¸¸åœ°åœ– + </string> + <string name="EnvironmentTransparent"> + 逿˜Ž + </string> <string name="ClassifiedClicksTxt"> 點按:[TELEPORT] 瞬間傳é€ï¼Œ[MAP] 地圖,[PROFILE] 檔案 </string> @@ -4723,6 +4780,9 @@ http://secondlife.com/support 求助解決å•題。 <string name="New Tattoo"> æ–°åˆºé’ </string> + <string name="New Universal"> + 新通用值 + </string> <string name="New Physics"> æ–°èº«é«”ç‰©ç† </string> @@ -4849,6 +4909,15 @@ http://secondlife.com/support 求助解決å•題。 <string name="Female - Wow"> 女性 - 哇塞 </string> + <string name="New Daycycle"> + 新的日循環 + </string> + <string name="New Water"> + 新的水文 + </string> + <string name="New Sky"> + 新的天空 + </string> <string name="/bow"> /彎腰點é </string> @@ -5389,6 +5458,12 @@ http://secondlife.com/support 求助解決å•題。 <string name="BeaconMedia"> 檢視媒體的導引(白色) </string> + <string name="BeaconSun"> + æª¢è¦–å¤ªé™½æ–¹å‘æŒ‡æ¨™ï¼ˆæ©˜è‰²ï¼‰ + </string> + <string name="BeaconMoon"> + æª¢è¦–æœˆäº®æ–¹å‘æŒ‡æ¨™ï¼ˆç´«è‰²ï¼‰ + </string> <string name="ParticleHiding"> éš±è—ç²’åæ•ˆæžœ </string> @@ -5416,6 +5491,12 @@ http://secondlife.com/support 求助解決å•題。 <string name="Command_Destinations_Label"> 目的地 </string> + <string name="Command_Environments_Label"> + 我的環境 + </string> + <string name="Command_Facebook_Label"> + 臉書 + </string> <string name="Command_Flickr_Label"> Flickr </string> @@ -5509,6 +5590,12 @@ http://secondlife.com/support 求助解決å•題。 <string name="Command_Destinations_Tooltip"> ä½ å¯èƒ½æ„Ÿèˆˆè¶£çš„目的地 </string> + <string name="Command_Environments_Tooltip"> + 我的環境 + </string> + <string name="Command_Facebook_Tooltip"> + 發佈到臉書 + </string> <string name="Command_Flickr_Tooltip"> 上傳到 Flickr </string> @@ -5704,6 +5791,12 @@ http://secondlife.com/support 求助解決å•題。 <string name="ExperiencePermission12"> 自動接å—å„ç¨®é«”é©—æ¬Šé™ </string> + <string name="ExperiencePermission16"> + å¼·è¿«ä½ çš„åŒ–èº«å下 + </string> + <string name="ExperiencePermission17"> + æ”¹è®Šä½ çš„ç’°å¢ƒè¨å®š + </string> <string name="ExperiencePermissionShortUnknown"> 進行了未知的æ“作:[Permission] </string> @@ -5728,6 +5821,12 @@ http://secondlife.com/support 求助解決å•題。 <string name="ExperiencePermissionShort12"> æ¬Šé™ </string> + <string name="ExperiencePermissionShort16"> + å下 + </string> + <string name="ExperiencePermissionShort17"> + 環境 + </string> <string name="logging_calls_disabled_log_empty"> 交談未留記錄。 若想開始留記錄,請到「å好è¨å®š > èŠå¤©ã€ï¼Œé¸æ“‡ã€Œå„²å˜ï¼šåªç•™æ·å²è¨˜éŒ„ã€æˆ–「儲å˜ï¼šæ·å²è¨˜éŒ„兼交談內容ã€ã€‚ </string> diff --git a/indra/newview/slplugin.entitlements b/indra/newview/slplugin.entitlements new file mode 100644 index 0000000000..a1c430a57a --- /dev/null +++ b/indra/newview/slplugin.entitlements @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>com.apple.security.cs.allow-unsigned-executable-memory</key> + <true/> +</dict> +</plist> diff --git a/indra/newview/tests/cppfeatures_test.cpp b/indra/newview/tests/cppfeatures_test.cpp new file mode 100644 index 0000000000..923bb1e1b2 --- /dev/null +++ b/indra/newview/tests/cppfeatures_test.cpp @@ -0,0 +1,386 @@ +/** + * @file cppfeatures_test + * @author Vir + * @date 2021-03 + * @brief cpp features + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +// Tests related to newer C++ features, for verifying support across compilers and platforms + +#include "linden_common.h" +#include "../test/lltut.h" + +namespace tut +{ + +struct cpp_features_test {}; +typedef test_group<cpp_features_test> cpp_features_test_t; +typedef cpp_features_test_t::object cpp_features_test_object_t; +tut::cpp_features_test_t tut_cpp_features_test("LLCPPFeatures"); + +// bracket initializers +// Can initialize containers or values using curly brackets +template<> template<> +void cpp_features_test_object_t::test<1>() +{ + S32 explicit_val{3}; + ensure(explicit_val==3); + + S32 default_val{}; + ensure(default_val==0); + + std::vector<S32> fibs{1,1,2,3,5}; + ensure(fibs[4]==5); +} + +// auto +// +// https://en.cppreference.com/w/cpp/language/auto +// +// Can use auto in place of a more complex type specification, if the compiler can infer the type +template<> template<> +void cpp_features_test_object_t::test<2>() +{ + std::vector<S32> numbers{3,6,9}; + + // auto element + auto& aval = numbers[1]; + ensure("auto element", aval==6); + + // auto iterator (non-const) + auto it = numbers.rbegin(); + *it += 1; + S32 val = *it; + ensure("auto iterator", val==10); +} + +// range for +// +// https://en.cppreference.com/w/cpp/language/range-for +// +// Can iterate over containers without explicit iterator +template<> template<> +void cpp_features_test_object_t::test<3>() +{ + + // Traditional iterator for with container + // + // Problems: + // * Have to create a new variable for the iterator, which is unrelated to the problem you're trying to solve. + // * Redundant and somewhat fragile. Have to make sure begin() and end() are both from the right container. + std::vector<S32> numbers{3,6,9}; + for (auto it = numbers.begin(); it != numbers.end(); ++it) + { + auto& n = *it; + n *= 2; + } + ensure("iterator for vector", numbers[2]==18); + + // Range for with container + // + // Under the hood, this is doing the same thing as the traditional + // for loop above. Still uses begin() and end() but you don't have + // to access them directly. + std::vector<S32> numbersb{3,6,9}; + for (auto& n: numbersb) + { + n *= 2; + } + ensure("range for vector", numbersb[2]==18); + + // Range for over a C-style array. + // + // This is handy because the language determines the range automatically. + // Getting this right manually is a little trickier. + S32 pows[] = {1,2,4,8,16}; + S32 sum{}; + for (const auto& v: pows) + { + sum += v; + } + ensure("for C-array", sum==31); +} + +// override specifier +// +// https://en.cppreference.com/w/cpp/language/override +// +// Specify that a particular class function is an override of a virtual function. +// Benefits: +// * Makes code somewhat easier to read by showing intent. +// * Prevents mistakes where you think something is an override but it doesn't actually match the declaration in the parent class. +// Drawbacks: +// * Some compilers require that any class using override must use it consistently for all functions. +// This makes switching a class to use override a lot more work. + +class Foo +{ +public: + virtual bool is_happy() const = 0; +}; + +class Bar: public Foo +{ +public: + bool is_happy() const override { return true; } + // Override would fail: non-const declaration doesn't match parent + // bool is_happy() override { return true; } + // Override would fail: wrong name + // bool is_happx() override { return true; } +}; + +template<> template<> +void cpp_features_test_object_t::test<4>() +{ + Bar b; + ensure("override", b.is_happy()); +} + +// final +// +// https://en.cppreference.com/w/cpp/language/final: "Specifies that a +// virtual function cannot be overridden in a derived class or that a +// class cannot be inherited from." + +class Vehicle +{ +public: + virtual bool has_wheels() const = 0; +}; + +class WheeledVehicle: public Vehicle +{ +public: + virtual bool has_wheels() const final override { return true; } +}; + +class Bicycle: public WheeledVehicle +{ +public: + // Error: can't override final version in WheeledVehicle + // virtual bool has_wheels() override const { return true; } +}; + +template<> template<> +void cpp_features_test_object_t::test<5>() +{ + Bicycle bi; + ensure("final", bi.has_wheels()); +} + +// deleted function declaration +// +// https://en.cppreference.com/w/cpp/language/function#Deleted_functions +// +// Typical case: copy constructor doesn't make sense for a particular class, so you want to make +// sure the no one tries to copy-construct an instance of the class, and that the +// compiler won't generate a copy constructor for you automatically. +// Traditional fix is to declare a +// copy constructor but never implement it, giving you a link-time error if anyone tries to use it. +// Now you can explicitly declare a function to be deleted, which has at least two advantages over +// the old way: +// * Makes the intention clear +// * Creates an error sooner, at compile time + +class DoNotCopy +{ +public: + DoNotCopy() {} + DoNotCopy(const DoNotCopy& ref) = delete; +}; + +template<> template<> +void cpp_features_test_object_t::test<6>() +{ + DoNotCopy nc; // OK, default constructor + //DoNotCopy nc2(nc); // No, can't copy + //DoNotCopy nc3 = nc; // No, this also calls copy constructor (even though it looks like an assignment) +} + +// defaulted function declaration +// +// https://en.cppreference.com/w/cpp/language/function#Function_definition +// +// What about the complementary case to the deleted function declaration, where you want a copy constructor +// and are happy with the default implementation the compiler will make (memberwise copy). +// Now you can explicitly declare that too. +// Usage: I guess it makes the intent clearer, but otherwise not obviously useful. +class DefaultCopyOK +{ +public: + DefaultCopyOK(): mVal(123) {} + DefaultCopyOK(const DefaultCopyOK&) = default; + S32 val() const { return mVal; } +private: + S32 mVal; +}; + +template<> template<> +void cpp_features_test_object_t::test<7>() +{ + DefaultCopyOK d; // OK + DefaultCopyOK d2(d); // OK + DefaultCopyOK d3 = d; // OK + ensure("default copy d", d.val()==123); + ensure("default copy d2", d.val()==d2.val()); + ensure("default copy d3", d.val()==d3.val()); +} + +// initialize class members inline +// +// https://en.cppreference.com/w/cpp/language/data_members#Member_initialization +// +// Default class member values can be set where they are declared, using either brackets or = + +// It is preferred to skip creating a constructor if all the work can be done by inline initialization: +// http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines.html#c45-dont-define-a-default-constructor-that-only-initializes-data-members-use-in-class-member-initializers-instead +// +class InitInline +{ +public: + S32 mFoo{10}; +}; + +class InitInlineWithConstructor +{ +public: + // Here mFoo is not specified, so you will get the default value of 10. + // mBar is specified, so 25 will override the default value. + InitInlineWithConstructor(): + mBar(25) + {} + + // Default values set using two different styles, same effect. + S32 mFoo{10}; + S32 mBar = 20; +}; + +template<> template<> +void cpp_features_test_object_t::test<8>() +{ + InitInline ii; + ensure("init member inline 1", ii.mFoo==10); + + InitInlineWithConstructor iici; + ensure("init member inline 2", iici.mFoo=10); + ensure("init member inline 3", iici.mBar==25); +} + +// constexpr +// +// https://en.cppreference.com/w/cpp/language/constexpr +// +// Various things can be computed at compile time, and flagged as constexpr. +constexpr S32 compute2() { return 2; } + +constexpr S32 ce_factorial(S32 n) +{ + if (n<=0) + { + return 1; + } + else + { + return n*ce_factorial(n-1); + } +} + +template<> template<> +void cpp_features_test_object_t::test<9>() +{ + S32 val = compute2(); + ensure("constexpr 1", val==2); + + // Compile-time factorial. You used to need complex templates to do something this useless. + S32 fac5 = ce_factorial(5); + ensure("constexpr 2", fac5==120); +} + +// static assert +// +// https://en.cppreference.com/w/cpp/language/static_assert +// +// You can add asserts to be checked at compile time. The thing to be checked must be a constexpr. +// There are two forms: +// * static_assert(expr); +// * static_assert(expr, message); +// +// Currently only the 2-parameter form works on windows. The 1-parameter form needs a flag we don't set. + +template<> template<> +void cpp_features_test_object_t::test<10>() +{ + // static_assert(ce_factorial(6)==720); No, needs a flag we don't currently set. + static_assert(ce_factorial(6)==720, "bad factorial"); // OK +} + +// type aliases +// +// https://en.cppreference.com/w/cpp/language/type_alias +// +// You can use the "using" statement to create simpler templates that +// are aliases for more complex ones. "Template typedef" + +// This makes stringmap<T> an alias for std::map<std::string, T> +template<typename T> +using stringmap = std::map<std::string, T>; + +template<> template<> +void cpp_features_test_object_t::test<11>() +{ + stringmap<S32> name_counts{ {"alice", 3}, {"bob", 2} }; + ensure("type alias", name_counts["bob"]==2); +} + +// Other possibilities: + +// nullptr + +// class enums + +// std::unique_ptr and make_unique + +// std::shared_ptr and make_shared + +// lambdas + +// perfect forwarding + +// variadic templates + +// std::thread + +// std::mutex + +// thread_local + +// rvalue reference && + +// move semantics + +// std::move + +// string_view + +} // namespace tut diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index 2edad30493..f9abc8b25d 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -41,6 +41,7 @@ #include "../test/lltut.h" #include "llevents.h" #include "llnotificationsutil.h" +#include "lltrans.h" #if defined(LL_WINDOWS) #pragma warning(disable: 4355) // using 'this' in base-class ctor initializer expr @@ -77,6 +78,11 @@ void LLViewerWindow::setShowProgress(BOOL show) {} LLProgressView * LLViewerWindow::getProgressView(void) const { return 0; } LLViewerWindow* gViewerWindow; + +std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args, bool def_string) +{ + return std::string("test_trans"); +} class LLLogin::Impl { @@ -202,8 +208,6 @@ void LLUIColorTable::saveUserSettings(void)const {} //----------------------------------------------------------------------------- #include "../llversioninfo.h" -const std::string &LLVersionInfo::getVersion() { return VIEWERLOGIN_VERSION; } -const std::string &LLVersionInfo::getChannel() { return VIEWERLOGIN_CHANNEL; } bool llHashedUniqueID(unsigned char* id) { diff --git a/indra/newview/tests/llsecapi_test.cpp b/indra/newview/tests/llsecapi_test.cpp index d7e87ed52e..37fbbb449b 100644 --- a/indra/newview/tests/llsecapi_test.cpp +++ b/indra/newview/tests/llsecapi_test.cpp @@ -57,15 +57,25 @@ void LLSecAPIBasicHandler::init() {} LLSecAPIBasicHandler::~LLSecAPIBasicHandler() {} LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(const std::string& pem_cert) { return NULL; } LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(X509* openssl_cert) { return NULL; } -LLPointer<LLCertificateChain> LLSecAPIBasicHandler::getCertificateChain(const X509_STORE_CTX* chain) { return NULL; } +LLPointer<LLCertificateChain> LLSecAPIBasicHandler::getCertificateChain(X509_STORE_CTX* chain) { return NULL; } LLPointer<LLCertificateStore> LLSecAPIBasicHandler::getCertificateStore(const std::string& store_id) { return NULL; } void LLSecAPIBasicHandler::setProtectedData(const std::string& data_type, const std::string& data_id, const LLSD& data) {} +void LLSecAPIBasicHandler::addToProtectedMap(const std::string& data_type, const std::string& data_id, const std::string& map_elem, const LLSD& data) {} +void LLSecAPIBasicHandler::removeFromProtectedMap(const std::string& data_type, const std::string& data_id, const std::string& map_elem) {} LLSD LLSecAPIBasicHandler::getProtectedData(const std::string& data_type, const std::string& data_id) { return LLSD(); } void LLSecAPIBasicHandler::deleteProtectedData(const std::string& data_type, const std::string& data_id) {} LLPointer<LLCredential> LLSecAPIBasicHandler::createCredential(const std::string& grid, const LLSD& identifier, const LLSD& authenticator) { return NULL; } LLPointer<LLCredential> LLSecAPIBasicHandler::loadCredential(const std::string& grid) { return NULL; } void LLSecAPIBasicHandler::saveCredential(LLPointer<LLCredential> cred, bool save_authenticator) {} void LLSecAPIBasicHandler::deleteCredential(LLPointer<LLCredential> cred) {} +bool LLSecAPIBasicHandler::hasCredentialMap(const std::string& storage, const std::string& grid) { return false; } +bool LLSecAPIBasicHandler::emptyCredentialMap(const std::string& storage, const std::string& grid) { return false; } +void LLSecAPIBasicHandler::loadCredentialMap(const std::string& storage, const std::string& grid, credential_map_t& credential_map) {} +LLPointer<LLCredential> LLSecAPIBasicHandler::loadFromCredentialMap(const std::string& storage, const std::string& grid, const std::string& userkey) { return NULL; } +void LLSecAPIBasicHandler::addToCredentialMap(const std::string& storage, LLPointer<LLCredential> cred, bool save_authenticator) {} +void LLSecAPIBasicHandler::removeFromCredentialMap(const std::string& storage, LLPointer<LLCredential> cred) {} +void LLSecAPIBasicHandler::removeFromCredentialMap(const std::string& storage, const std::string& grid, const std::string& userkey) {} +void LLSecAPIBasicHandler::removeCredentialMap(const std::string& storage, const std::string& grid) {} // ------------------------------------------------------------------------------------------- // TUT diff --git a/indra/newview/tests/llsechandler_basic_test.cpp b/indra/newview/tests/llsechandler_basic_test.cpp index 63967fae37..4c8d6c51b0 100644 --- a/indra/newview/tests/llsechandler_basic_test.cpp +++ b/indra/newview/tests/llsechandler_basic_test.cpp @@ -124,6 +124,14 @@ S32 LLMachineID::getUniqueID(unsigned char *unique_id, size_t len) S32 LLMachineID::init() { return 1; } +LLCertException::LLCertException(const LLSD& cert_data, const std::string& msg) + : LLException(msg), + mCertData(cert_data) +{ + LL_WARNS("SECAPI") << "Certificate Error: " << msg << LL_ENDL; +} + + // ------------------------------------------------------------------------------------------- // TUT // ------------------------------------------------------------------------------------------- @@ -1209,8 +1217,8 @@ namespace tut // Single cert in the chain. X509_STORE_CTX *test_store = X509_STORE_CTX_new(); - test_store->cert = mX509ChildCert; - test_store->untrusted = NULL; + X509_STORE_CTX_set_cert(test_store, mX509ChildCert); + X509_STORE_CTX_set0_untrusted(test_store, NULL); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); ensure_equals("two elements in store", test_chain->size(), 1); @@ -1221,9 +1229,9 @@ namespace tut // cert + CA test_store = X509_STORE_CTX_new(); - test_store->cert = mX509ChildCert; - test_store->untrusted = sk_X509_new_null(); - sk_X509_push(test_store->untrusted, mX509IntermediateCert); + X509_STORE_CTX_set_cert(test_store, mX509ChildCert); + X509_STORE_CTX_set0_untrusted(test_store, sk_X509_new_null()); + sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509IntermediateCert); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); ensure_equals("two elements in store", test_chain->size(), 2); @@ -1237,9 +1245,9 @@ namespace tut // cert + nonrelated test_store = X509_STORE_CTX_new(); - test_store->cert = mX509ChildCert; - test_store->untrusted = sk_X509_new_null(); - sk_X509_push(test_store->untrusted, mX509TestCert); + X509_STORE_CTX_set_cert(test_store, mX509ChildCert); + X509_STORE_CTX_set0_untrusted(test_store, sk_X509_new_null()); + sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509TestCert); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); ensure_equals("two elements in store", test_chain->size(), 1); @@ -1249,10 +1257,10 @@ namespace tut // cert + CA + nonrelated test_store = X509_STORE_CTX_new(); - test_store->cert = mX509ChildCert; - test_store->untrusted = sk_X509_new_null(); - sk_X509_push(test_store->untrusted, mX509IntermediateCert); - sk_X509_push(test_store->untrusted, mX509TestCert); + X509_STORE_CTX_set_cert(test_store, mX509ChildCert); + X509_STORE_CTX_set0_untrusted(test_store, sk_X509_new_null()); + sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509IntermediateCert); + sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509TestCert); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); ensure_equals("two elements in store", test_chain->size(), 2); @@ -1265,10 +1273,10 @@ namespace tut // cert + intermediate + CA test_store = X509_STORE_CTX_new(); - test_store->cert = mX509ChildCert; - test_store->untrusted = sk_X509_new_null(); - sk_X509_push(test_store->untrusted, mX509IntermediateCert); - sk_X509_push(test_store->untrusted, mX509RootCert); + X509_STORE_CTX_set_cert(test_store, mX509ChildCert); + X509_STORE_CTX_set0_untrusted(test_store, sk_X509_new_null()); + sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509IntermediateCert); + sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509RootCert); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); ensure_equals("three elements in store", test_chain->size(), 3); diff --git a/indra/newview/tests/llversioninfo_test.cpp b/indra/newview/tests/llversioninfo_test.cpp index 58f0469552..51a6f8f113 100644 --- a/indra/newview/tests/llversioninfo_test.cpp +++ b/indra/newview/tests/llversioninfo_test.cpp @@ -83,39 +83,39 @@ namespace tut void versioninfo_object_t::test<1>() { std::cout << "What we parsed from CMake: " << LL_VIEWER_VERSION_BUILD << std::endl; - std::cout << "What we get from llversioninfo: " << LLVersionInfo::getBuild() << std::endl; + std::cout << "What we get from llversioninfo: " << LLVersionInfo::instance().getBuild() << std::endl; ensure_equals("Major version", - LLVersionInfo::getMajor(), + LLVersionInfo::instance().getMajor(), LL_VIEWER_VERSION_MAJOR); ensure_equals("Minor version", - LLVersionInfo::getMinor(), + LLVersionInfo::instance().getMinor(), LL_VIEWER_VERSION_MINOR); ensure_equals("Patch version", - LLVersionInfo::getPatch(), + LLVersionInfo::instance().getPatch(), LL_VIEWER_VERSION_PATCH); ensure_equals("Build version", - LLVersionInfo::getBuild(), + LLVersionInfo::instance().getBuild(), LL_VIEWER_VERSION_BUILD); ensure_equals("Channel version", - LLVersionInfo::getChannel(), + LLVersionInfo::instance().getChannel(), ll_viewer_channel); ensure_equals("Version String", - LLVersionInfo::getVersion(), + LLVersionInfo::instance().getVersion(), mVersion); ensure_equals("Short Version String", - LLVersionInfo::getShortVersion(), + LLVersionInfo::instance().getShortVersion(), mShortVersion); ensure_equals("Version and channel String", - LLVersionInfo::getChannelAndVersion(), + LLVersionInfo::instance().getChannelAndVersion(), mVersionAndChannel); - LLVersionInfo::resetChannel(mResetChannel); + LLVersionInfo::instance().resetChannel(mResetChannel); ensure_equals("Reset channel version", - LLVersionInfo::getChannel(), + LLVersionInfo::instance().getChannel(), mResetChannel); ensure_equals("Reset Version and channel String", - LLVersionInfo::getChannelAndVersion(), + LLVersionInfo::instance().getChannelAndVersion(), mResetVersionAndChannel); } } diff --git a/indra/newview/tests/llviewernetwork_test.cpp b/indra/newview/tests/llviewernetwork_test.cpp index bb28abead3..fe81fd63ea 100644 --- a/indra/newview/tests/llviewernetwork_test.cpp +++ b/indra/newview/tests/llviewernetwork_test.cpp @@ -258,7 +258,7 @@ namespace tut std::string("https://login.aditi.lindenlab.com/cgi-bin/login.cgi")); ensure_equals("Aditi helper uri", LLGridManager::getInstance()->getHelperURI("util.aditi.lindenlab.com"), - std::string("https://secondlife.aditi.lindenlab.com/helpers/")); + std::string("https://secondlife.aditi.lindenlab.com/helpers/")); ensure_equals("Aditi login page", LLGridManager::getInstance()->getLoginPage("util.aditi.lindenlab.com"), std::string("https://viewer-splash.secondlife.com/")); @@ -330,7 +330,7 @@ namespace tut std::string("https://login.aditi.lindenlab.com/cgi-bin/login.cgi")); ensure_equals("Aditi helper uri", LLGridManager::getInstance()->getHelperURI("util.aditi.lindenlab.com"), - std::string("https://secondlife.aditi.lindenlab.com/helpers/")); + std::string("https://secondlife.aditi.lindenlab.com/helpers/")); ensure_equals("Aditi login page", LLGridManager::getInstance()->getLoginPage("util.aditi.lindenlab.com"), std::string("https://viewer-splash.secondlife.com/")); diff --git a/indra/newview/tests/llxmlrpclistener_test.cpp b/indra/newview/tests/llxmlrpclistener_test.cpp index 6e9756e7d5..dbaae7280c 100644 --- a/indra/newview/tests/llxmlrpclistener_test.cpp +++ b/indra/newview/tests/llxmlrpclistener_test.cpp @@ -88,15 +88,9 @@ namespace tut WrapLLErrs capture; LLSD request; request["uri"] = uri; - std::string threw; - try - { - pumps.obtain("LLXMLRPCTransaction").post(request); - } - catch (const WrapLLErrs::FatalException& e) - { - threw = e.what(); - } + std::string threw = capture.catch_llerrs([&pumps, &request](){ + pumps.obtain("LLXMLRPCTransaction").post(request); + }); ensure_contains("threw exception", threw, "missing params"); ensure_contains("identified missing", threw, "method"); ensure_contains("identified missing", threw, "reply"); @@ -113,15 +107,9 @@ namespace tut request["reply"] = "reply"; LLSD& params(request["params"]); params["who"]["specifically"] = "world"; // LLXMLRPCListener only handles scalar params - std::string threw; - try - { - pumps.obtain("LLXMLRPCTransaction").post(request); - } - catch (const WrapLLErrs::FatalException& e) - { - threw = e.what(); - } + std::string threw = capture.catch_llerrs([&pumps, &request](){ + pumps.obtain("LLXMLRPCTransaction").post(request); + }); ensure_contains("threw exception", threw, "unknown type"); } diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index d5526bf5fd..281777e492 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -46,7 +46,7 @@ viewer_dir = os.path.dirname(__file__) # Put it FIRST because some of our build hosts have an ancient install of # indra.util.llmanifest under their system Python! sys.path.insert(0, os.path.join(viewer_dir, os.pardir, "lib", "python")) -from indra.util.llmanifest import LLManifest, main, path_ancestors, CHANNEL_VENDOR_BASE, RELEASE_CHANNEL, ManifestError +from indra.util.llmanifest import LLManifest, main, path_ancestors, CHANNEL_VENDOR_BASE, RELEASE_CHANNEL, ManifestError, MissingError from llbase import llsd class ViewerManifest(LLManifest): @@ -78,6 +78,9 @@ class ViewerManifest(LLManifest): contributor_names = self.extract_names(contributions_path) self.put_in_file(contributor_names, "contributors.txt", src=contributions_path) + # ... and the default camera position settings + self.path("camera") + # ... and the entire windlight directory self.path("windlight") @@ -145,13 +148,10 @@ class ViewerManifest(LLManifest): with self.prefix(src_dst="skins"): # include the entire textures directory recursively with self.prefix(src_dst="*/textures"): - self.path("*/*.tga") - self.path("*/*.j2c") self.path("*/*.jpg") self.path("*/*.png") self.path("*.tga") self.path("*.j2c") - self.path("*.jpg") self.path("*.png") self.path("textures.xml") self.path("*/xui/*/*.xml") @@ -171,14 +171,6 @@ class ViewerManifest(LLManifest): self.path("*/*/*.gif") - # local_assets dir (for pre-cached textures) - with self.prefix(src_dst="local_assets"): - self.path("*.j2c") - self.path("*.tga") - - # File in the newview/ directory - self.path("gpu_table.txt") - #build_data.json. Standard with exception handling is fine. If we can't open a new file for writing, we have worse problems #platform is computed above with other arg parsing build_data_dict = {"Type":"viewer","Version":'.'.join(self.args['version']), @@ -268,6 +260,9 @@ class ViewerManifest(LLManifest): app_suffix=self.channel_variant() return CHANNEL_VENDOR_BASE + ' ' + app_suffix + def exec_name(self): + return "SecondLifeViewer" + def app_name_oneword(self): return ''.join(self.app_name().split()) @@ -427,10 +422,9 @@ class WindowsManifest(ViewerManifest): build_data_json_platform = 'win' def final_exe(self): - return self.app_name_oneword()+".exe" + return self.exec_name()+".exe" def finish_build_data_dict(self, build_data_dict): - #MAINT-7294: Windows exe names depend on channel name, so write that in also build_data_dict['Executable'] = self.final_exe() build_data_dict['AppName'] = self.app_name() return build_data_dict @@ -517,17 +511,6 @@ class WindowsManifest(ViewerManifest): with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'sharedlibs', self.args['configuration'])): - # Get llcommon and deps. If missing assume static linkage and continue. - try: - self.path('llcommon.dll') - self.path('libapr-1.dll') - self.path('libaprutil-1.dll') - self.path('libapriconv-1.dll') - - except RuntimeError as err: - print err.message - print "Skipping llcommon.dll (assuming llcommon was linked statically)" - # Mesh 3rd party libs needed for auto LOD and collada reading try: self.path("glod.dll") @@ -535,45 +518,48 @@ class WindowsManifest(ViewerManifest): print err.message print "Skipping GLOD library (assumming linked statically)" - # Get fmodex dll, continue if missing - try: - if(self.address_size == 64): - self.path("fmodex64.dll") + # Get fmodstudio dll if needed + if self.args['fmodstudio'] == 'ON': + if(self.args['configuration'].lower() == 'debug'): + self.path("fmodL.dll") else: - self.path("fmodex.dll") - except: - print "Skipping fmodex audio library(assuming other audio engine)" + self.path("fmod.dll") + + if self.args['openal'] == 'ON': + # Get openal dll + self.path("OpenAL32.dll") + self.path("alut.dll") # For textures self.path("openjpeg.dll") + # Uriparser + self.path("uriparser.dll") + # These need to be installed as a SxS assembly, currently a 'private' assembly. # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx - if self.args['configuration'].lower() == 'debug': - self.path("msvcr120d.dll") - self.path("msvcp120d.dll") - self.path("msvcr100d.dll") - self.path("msvcp100d.dll") - else: - self.path("msvcr120.dll") - self.path("msvcp120.dll") - self.path("msvcr100.dll") - self.path("msvcp100.dll") + self.path("msvcp140.dll") + self.path("vcruntime140.dll") - # Vivox runtimes - self.path("SLVoice.exe") + # SLVoice executable + with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')): + self.path("SLVoice.exe") + + # Vivox libraries if (self.address_size == 64): self.path("vivoxsdk_x64.dll") self.path("ortp_x64.dll") else: self.path("vivoxsdk.dll") self.path("ortp.dll") - self.path("libsndfile-1.dll") - self.path("vivoxoal.dll") - # Security - self.path("ssleay32.dll") - self.path("libeay32.dll") + # OpenSSL + if (self.address_size == 64): + self.path("libcrypto-1_1-x64.dll") + self.path("libssl-1_1-x64.dll") + else: + self.path("libcrypto-1_1.dll") + self.path("libssl-1_1.dll") # HTTP/2 self.path("nghttp2.dll") @@ -592,15 +578,6 @@ class WindowsManifest(ViewerManifest): self.path("BugSplat.dll") self.path("BugSplatRc.dll") - # For google-perftools tcmalloc allocator. - try: - if self.args['configuration'].lower() == 'debug': - self.path('libtcmalloc_minimal-debug.dll') - else: - self.path('libtcmalloc_minimal.dll') - except: - print "Skipping libtcmalloc_minimal.dll" - self.path(src="licenses-win32.txt", dst="licenses.txt") self.path("featuretable.txt") @@ -627,29 +604,25 @@ class WindowsManifest(ViewerManifest): config = 'debug' if self.args['configuration'].lower() == 'debug' else 'release' with self.prefix(src=os.path.join(pkgdir, 'bin', config)): self.path("chrome_elf.dll") - self.path("d3dcompiler_43.dll") self.path("d3dcompiler_47.dll") self.path("libcef.dll") self.path("libEGL.dll") self.path("libGLESv2.dll") self.path("dullahan_host.exe") - self.path("natives_blob.bin") self.path("snapshot_blob.bin") self.path("v8_context_snapshot.bin") # MSVC DLLs needed for CEF and have to be in same directory as plugin with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'sharedlibs', 'Release')): - self.path("msvcp120.dll") - self.path("msvcr120.dll") + self.path("msvcp140.dll") + self.path("vcruntime140.dll") # CEF files common to all configurations with self.prefix(src=os.path.join(pkgdir, 'resources')): - self.path("cef.pak") - self.path("cef_100_percent.pak") - self.path("cef_200_percent.pak") - self.path("cef_extensions.pak") - self.path("devtools_resources.pak") + self.path("chrome_100_percent.pak") + self.path("chrome_200_percent.pak") + self.path("resources.pak") self.path("icudtl.dat") with self.prefix(src=os.path.join(pkgdir, 'resources', 'locales'), dst='locales'): @@ -712,11 +685,6 @@ class WindowsManifest(ViewerManifest): self.path("libvlccore.dll") self.path("plugins/") - # pull in the crash logger from other projects - # tag:"crash-logger" here as a cue to the exporter - self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'], - dst="win_crash_logger.exe") - if not self.is_packaging_viewer(): self.package_file = "copied_deps" @@ -828,6 +796,7 @@ class WindowsManifest(ViewerManifest): for exe in ( self.final_exe(), "SLVersionChecker.exe", + "llplugin/dullahan_host.exe", ): self.sign(exe) @@ -861,13 +830,13 @@ class WindowsManifest(ViewerManifest): def sign(self, exe): sign_py = os.environ.get('SIGN', r'C:\buildscripts\code-signing\sign.py') - python = os.environ.get('PYTHON', 'python') + python = os.environ.get('PYTHON', sys.executable) if os.path.exists(sign_py): dst_path = self.dst_path_of(exe) print "about to run signing of: ", dst_path self.run_command([python, sign_py, dst_path]) else: - print "Skipping code signing of %s: %s not found" % (exe, sign_py) + print "Skipping code signing of %s %s: %s not found" % (self.dst_path_of(exe), exe, sign_py) def escape_slashes(self, path): return path.replace('\\', '\\\\\\\\') @@ -990,7 +959,7 @@ class DarwinManifest(ViewerManifest): with self.prefix(src=relpkgdir, dst=""): self.path("libndofdev.dylib") - self.path("libhunspell-1.3.0.dylib") + self.path("libhunspell-*.dylib") with self.prefix(src_dst="cursors_mac"): self.path("*.tif") @@ -1037,11 +1006,15 @@ class DarwinManifest(ViewerManifest): # (source, dest) pair to self.file_list for every expanded # file processed. Remember its size before the call. oldlen = len(self.file_list) - self.path(src, dst) - # The dest appended to self.file_list has been prepended - # with self.get_dst_prefix(). Strip it off again. - added = [os.path.relpath(d, self.get_dst_prefix()) - for s, d in self.file_list[oldlen:]] + try: + self.path(src, dst) + # The dest appended to self.file_list has been prepended + # with self.get_dst_prefix(). Strip it off again. + added = [os.path.relpath(d, self.get_dst_prefix()) + for s, d in self.file_list[oldlen:]] + except MissingError as err: + print >> sys.stderr, "Warning: "+err.msg + added = [] if not added: print "Skipping %s" % dst return added @@ -1051,57 +1024,48 @@ class DarwinManifest(ViewerManifest): # symlink from sub-app/Contents/Resources to the real .dylib. # Need to get the llcommon dll from any of the build directories as well. libfile_parent = self.get_dst_prefix() - libfile = "libllcommon.dylib" - dylibs = path_optional(self.find_existing_file(os.path.join(os.pardir, - "llcommon", - self.args['configuration'], - libfile), - os.path.join(relpkgdir, libfile)), - dst=libfile) - + dylibs=[] for libfile in ( "libapr-1.0.dylib", "libaprutil-1.0.dylib", - "libcollada14dom.dylib", "libexpat.1.dylib", - "libexception_handler.dylib", "libGLOD.dylib", # libnghttp2.dylib is a symlink to # libnghttp2.major.dylib, which is a symlink to # libnghttp2.version.dylib. Get all of them. "libnghttp2.*dylib", + "liburiparser.*dylib", ): dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) - # SLVoice and vivox lols, no symlinks needed + # SLVoice executable + with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')): + self.path("SLVoice") + + # Vivox libraries for libfile in ( 'libortp.dylib', - 'libsndfile.dylib', - 'libvivoxoal.dylib', 'libvivoxsdk.dylib', - 'libvivoxplatform.dylib', - 'SLVoice', ): self.path2basename(relpkgdir, libfile) - # dylibs that vary based on configuration - if self.args['configuration'].lower() == 'debug': - for libfile in ( - "libfmodexL.dylib", - ): - dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile) - else: - for libfile in ( - "libfmodex.dylib", - ): - dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) + # Fmod studio dylibs (vary based on configuration) + if self.args['fmodstudio'] == 'ON': + if self.args['configuration'].lower() == 'debug': + for libfile in ( + "libfmodL.dylib", + ): + dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile) + else: + for libfile in ( + "libfmod.dylib", + ): + dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) # our apps executable_path = {} - for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"), - # plugin launcher - (os.path.join("llplugin", "slplugin"), "SLPlugin.app"), - ): + embedded_apps = [ (os.path.join("llplugin", "slplugin"), "SLPlugin.app") ] + for app_bld_dir, app in embedded_apps: self.path2basename(os.path.join(os.pardir, app_bld_dir, self.args['configuration']), app) @@ -1141,46 +1105,55 @@ class DarwinManifest(ViewerManifest): # $viewer_app/Contents/Frameworks/Chromium Embedded Framework.framework SLPlugin_framework = self.relsymlinkf(CEF_framework, catch=False) - # copy DullahanHelper.app - self.path2basename(relpkgdir, 'DullahanHelper.app') - - # and fix that up with a Frameworks/CEF symlink too - with self.prefix(dst=os.path.join( - 'DullahanHelper.app', 'Contents', 'Frameworks')): - # from Dullahan Helper.app/Contents/Frameworks/Chromium Embedded - # Framework.framework back to - # SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework - # Since SLPlugin_framework is itself a - # symlink, don't let relsymlinkf() resolve -- - # explicitly call relpath(symlink=True) and - # create that symlink here. - DullahanHelper_framework = \ - self.symlinkf(self.relpath(SLPlugin_framework, symlink=True), - catch=False) - - # change_command includes install_name_tool, the - # -change subcommand and the old framework rpath - # stamped into the executable. To use it with - # run_command(), we must still append the new - # framework path and the pathname of the - # executable to change. - change_command = [ - 'install_name_tool', '-change', - '@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework'] - - with self.prefix(dst=os.path.join( - 'DullahanHelper.app', 'Contents', 'MacOS')): - # Now self.get_dst_prefix() is, at runtime, - # @executable_path. Locate the helper app - # framework (which is a symlink) from here. - newpath = os.path.join( - '@executable_path', - self.relpath(DullahanHelper_framework, symlink=True), - frameworkname) - # and restamp the DullahanHelper executable - self.run_command( - change_command + - [newpath, self.dst_path_of('DullahanHelper')]) + # for all the multiple CEF/Dullahan (as of CEF 76) helper app bundles we need: + for helper in ( + "DullahanHelper", + "DullahanHelper (GPU)", + "DullahanHelper (Renderer)", + "DullahanHelper (Plugin)", + ): + # app is the directory name of the app bundle, with app/Contents/MacOS/helper as the executable + app = helper + ".app" + + # copy DullahanHelper.app + self.path2basename(relpkgdir, app) + + # and fix that up with a Frameworks/CEF symlink too + with self.prefix(dst=os.path.join( + app, 'Contents', 'Frameworks')): + # from Dullahan Helper *.app/Contents/Frameworks/Chromium Embedded + # Framework.framework back to + # SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework + # Since SLPlugin_framework is itself a + # symlink, don't let relsymlinkf() resolve -- + # explicitly call relpath(symlink=True) and + # create that symlink here. + helper_framework = \ + self.symlinkf(self.relpath(SLPlugin_framework, symlink=True), catch=False) + + # change_command includes install_name_tool, the + # -change subcommand and the old framework rpath + # stamped into the executable. To use it with + # run_command(), we must still append the new + # framework path and the pathname of the + # executable to change. + change_command = [ + 'install_name_tool', '-change', + '@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework'] + + with self.prefix(dst=os.path.join( + app, 'Contents', 'MacOS')): + # Now self.get_dst_prefix() is, at runtime, + # @executable_path. Locate the helper app + # framework (which is a symlink) from here. + newpath = os.path.join( + '@executable_path', + self.relpath(helper_framework, symlink=True), + frameworkname) + # and restamp the Dullahan Helper executable itself + self.run_command( + change_command + + [newpath, self.dst_path_of(helper)]) # SLPlugin plugins with self.prefix(dst="llplugin"): @@ -1243,11 +1216,6 @@ class DarwinManifest(ViewerManifest): devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip() volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip() - if devfile != '/dev/disk1': - # adding more debugging info based upon nat's hunches to the - # logs to help track down 'SetFile -a V' failures -brad - print "WARNING: 'SetFile -a V' command below is probably gonna fail" - # Copy everything in to the mounted .dmg app_name = self.app_name() @@ -1275,21 +1243,6 @@ class DarwinManifest(ViewerManifest): # Hide the background image, DS_Store file, and volume icon file (set their "visible" bit) for f in ".VolumeIcon.icns", "background.jpg", ".DS_Store": pathname = os.path.join(volpath, f) - # We've observed mysterious "no such file" failures of the SetFile - # command, especially on the first file listed above -- yet - # subsequent inspection of the target directory confirms it's - # there. Timing problem with copy command? Try to handle. - for x in xrange(3): - if os.path.exists(pathname): - print "Confirmed existence: %r" % pathname - break - print "Waiting for %s copy command to complete (%s)..." % (f, x+1) - sys.stdout.flush() - time.sleep(1) - # If we fall out of the loop above without a successful break, oh - # well, possibly we've mistaken the nature of the problem. In any - # case, don't hang up the whole build looping indefinitely, let - # the original problem manifest by executing the desired command. self.run_command(['SetFile', '-a', 'V', pathname]) # Create the alias file (which is a resource file) from the .r @@ -1344,14 +1297,19 @@ class DarwinManifest(ViewerManifest): signed=False sign_attempts=3 sign_retry_wait=15 + libvlc_path = app_in_dmg + "/Contents/Resources/llplugin/media_plugin_libvlc.dylib" + cef_path = app_in_dmg + "/Contents/Resources/llplugin/media_plugin_cef.dylib" + slplugin_path = app_in_dmg + "/Contents/Resources/SLPlugin.app/Contents/MacOS/SLPlugin" + greenlet_path = app_in_dmg + "/Contents/Resources/updater/greenlet/_greenlet.so" while (not signed) and (sign_attempts > 0): try: - sign_attempts-=1; - self.run_command( - # Note: See blurb above about names of keychains - ['codesign', '--verbose', '--deep', '--force', - '--keychain', viewer_keychain, '--sign', identity, - app_in_dmg]) + sign_attempts-=1 + # Note: See blurb above about names of keychains + self.run_command(['codesign', '--force', '--timestamp','--keychain', viewer_keychain, '--sign', identity, libvlc_path]) + self.run_command(['codesign', '--force', '--timestamp', '--keychain', viewer_keychain, '--sign', identity, cef_path]) + self.run_command(['codesign', '--force', '--timestamp', '--keychain', viewer_keychain, '--sign', identity, greenlet_path]) + self.run_command(['codesign', '--verbose', '--deep', '--force', '--entitlements', self.src_path_of("slplugin.entitlements"), '--options', 'runtime', '--keychain', viewer_keychain, '--sign', identity, slplugin_path]) + self.run_command(['codesign', '--verbose', '--deep', '--force', '--options', 'runtime', '--keychain', viewer_keychain, '--sign', identity, app_in_dmg]) signed=True # if no exception was raised, the codesign worked except ManifestError as err: if sign_attempts: @@ -1362,6 +1320,7 @@ class DarwinManifest(ViewerManifest): print >> sys.stderr, "Maximum codesign attempts exceeded; giving up" raise self.run_command(['spctl', '-a', '-texec', '-vvvv', app_in_dmg]) + self.run_command([self.src_path_of("installers/darwin/apple-notarize.sh"), app_in_dmg]) finally: # Unmount the image even if exceptions from any of the above @@ -1370,7 +1329,6 @@ class DarwinManifest(ViewerManifest): print "Converting temp disk image to final disk image" self.run_command(['hdiutil', 'convert', sparsename, '-format', 'UDZO', '-imagekey', 'zlib-level=9', '-o', finalname]) - self.run_command(['hdiutil', 'internet-enable', '-yes', finalname]) # get rid of the temp file self.package_file = finalname self.remove(sparsename) @@ -1415,7 +1373,7 @@ class LinuxManifest(ViewerManifest): with self.prefix(dst="bin"): self.path("secondlife-bin","do-not-directly-run-secondlife-bin") self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin") - self.path2basename("../llplugin/slplugin", "SLPlugin") + self.path2basename("../llplugin/slplugin", "SLPlugin") #this copies over the python wrapper script, associated utilities and required libraries, see SL-321, SL-322 and SL-323 with self.prefix(src="../viewer_components/manager", dst=""): self.path("*.py") @@ -1558,14 +1516,15 @@ class Linux_i686_Manifest(LinuxManifest): print "tcmalloc files not found, skipping" pass - try: - self.path("libfmodex-*.so") - self.path("libfmodex.so") - pass - except: - print "Skipping libfmodex.so - not found" - pass - + if self.args['fmodstudio'] == 'ON': + try: + self.path("libfmod.so.11.7") + self.path("libfmod.so.11") + self.path("libfmod.so") + pass + except: + print "Skipping libfmod.so - not found" + pass # Vivox runtimes with self.prefix(src=relpkgdir, dst="bin"): @@ -1575,7 +1534,6 @@ class Linux_i686_Manifest(LinuxManifest): self.path("libsndfile.so.1") #self.path("libvivoxoal.so.1") # no - we'll re-use the viewer's own OpenAL lib self.path("libvivoxsdk.so") - self.path("libvivoxplatform.so") self.strip_binaries() @@ -1592,8 +1550,21 @@ class Linux_x86_64_Manifest(LinuxManifest): ################################################################ if __name__ == "__main__": + # Report our own command line so that, in case of trouble, a developer can + # manually rerun the same command. + print('%s \\\n%s' % + (sys.executable, + ' '.join((("'%s'" % arg) if ' ' in arg else arg) for arg in sys.argv))) + # fmodstudio and openal can be used simultaneously and controled by environment extra_arguments = [ dict(name='bugsplat', description="""BugSplat database to which to post crashes, if BugSplat crash reporting is desired""", default=''), + dict(name='fmodstudio', description="""Indication if fmod studio libraries are needed""", default='OFF'), + dict(name='openal', description="""Indication openal libraries are needed""", default='OFF'), ] - main(extra=extra_arguments) + try: + main(extra=extra_arguments) + except (ManifestError, MissingError) as err: + sys.exit("\nviewer_manifest.py failed: "+err.msg) + except: + raise diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt index 8344cead57..251100867f 100644 --- a/indra/test/CMakeLists.txt +++ b/indra/test/CMakeLists.txt @@ -13,7 +13,7 @@ include(LLXML) include(Linking) include(Tut) include(LLAddBuildTest) - +include(bugsplat) include(GoogleMock) include_directories( @@ -67,6 +67,7 @@ set(test_HEADER_FILES llpipeutil.h llsdtraits.h lltut.h + sync.h ) if (NOT WINDOWS) @@ -82,7 +83,12 @@ list(APPEND test_SOURCE_FILES ${test_HEADER_FILES}) add_executable(lltest ${test_SOURCE_FILES}) +if (USE_BUGSPLAT) + set_target_properties(lltest PROPERTIES COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}") +endif (USE_BUGSPLAT) + target_link_libraries(lltest + ${LEGACY_STDIO_LIBS} ${LLDATABASE_LIBRARIES} ${LLINVENTORY_LIBRARIES} ${LLMESSAGE_LIBRARIES} @@ -98,7 +104,7 @@ target_link_libraries(lltest ${WINDOWS_LIBRARIES} ${BOOST_PROGRAM_OPTIONS_LIBRARY} ${BOOST_REGEX_LIBRARY} - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY} ${DL_LIBRARY} diff --git a/indra/test/catch_and_store_what_in.h b/indra/test/catch_and_store_what_in.h index 59f8cc0085..5beba06024 100644 --- a/indra/test/catch_and_store_what_in.h +++ b/indra/test/catch_and_store_what_in.h @@ -2,7 +2,7 @@ * @file catch_and_store_what_in.h * @author Nat Goodspeed * @date 2012-02-15 - * @brief CATCH_AND_STORE_WHAT_IN() macro + * @brief catch_what() template function, CATCH_AND_STORE_WHAT_IN() macro * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. @@ -13,6 +13,30 @@ #define LL_CATCH_AND_STORE_WHAT_IN_H /** + * In the brave new world of lambdas, we can use a nicer C++ idiom for testing + * exceptions than CATCH_AND_STORE_WHAT_IN() below, e.g.: + * + * @code + * std::string threw = catch_what<std::runtime_error>( + * [](){ throw std::runtime_error("badness"); }); + * ensure_equals(threw, "badness"); + * @endcode + */ +template <typename EXCEPTION, typename FUNC> +std::string catch_what(FUNC func) +{ + try + { + func(); + return {}; + } + catch (const EXCEPTION& err) + { + return err.what(); + } +} + +/** * Idiom useful for test programs: catch an expected exception, store its * what() string in a specified std::string variable. From there the caller * can do things like: diff --git a/indra/test/chained_callback.h b/indra/test/chained_callback.h new file mode 100644 index 0000000000..05929e33ad --- /dev/null +++ b/indra/test/chained_callback.h @@ -0,0 +1,107 @@ +/** + * @file chained_callback.h + * @author Nat Goodspeed + * @date 2020-01-03 + * @brief Subclass of tut::callback used for chaining callbacks. + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Copyright (c) 2020, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_CHAINED_CALLBACK_H) +#define LL_CHAINED_CALLBACK_H + +#include "lltut.h" + +/** + * Derive your TUT callback from chained_callback instead of tut::callback to + * ensure that multiple such callbacks can coexist in a given test executable. + * The relevant callback method will be called for each callback instance in + * reverse order of the instance's link() methods being called: the most + * recently link()ed callback will be called first, then the previous, and so + * forth. + * + * Obviously, for this to work, all relevant callbacks must be derived from + * chained_callback instead of tut::callback. Given that, control should reach + * each of them regardless of their construction order. The chain is + * guaranteed to stop because the first link() call will link to test_runner's + * default_callback, which is simply an instance of the callback() base class. + * + * The rule for deriving from chained_callback is that you may override any of + * its virtual methods, but your override must at some point call the + * corresponding chained_callback method. + */ +class chained_callback: public tut::callback +{ +public: + /** + * Instead of calling tut::test_runner::set_callback(&your_callback), call + * your_callback.link(); + * This uses the canonical instance of tut::test_runner. + */ + void link() + { + link(tut::runner.get()); + } + + /** + * If for some reason you have a different instance of test_runner... + */ + void link(tut::test_runner& runner) + { + // Since test_runner's constructor sets a default callback, + // get_callback() will always return a reference to a valid callback + // instance. + mPrev = &runner.get_callback(); + runner.set_callback(this); + } + + /** + * Called when new test run started. + */ + virtual void run_started() + { + mPrev->run_started(); + } + + /** + * Called when a group started + * @param name Name of the group + */ + virtual void group_started(const std::string& name) + { + mPrev->group_started(name); + } + + /** + * Called when a test finished. + * @param tr Test results. + */ + virtual void test_completed(const tut::test_result& tr) + { + mPrev->test_completed(tr); + } + + /** + * Called when a group is completed + * @param name Name of the group + */ + virtual void group_completed(const std::string& name) + { + mPrev->group_completed(name); + } + + /** + * Called when all tests in run completed. + */ + virtual void run_completed() + { + mPrev->run_completed(); + } + +private: + tut::callback* mPrev; +}; + +#endif /* ! defined(LL_CHAINED_CALLBACK_H) */ diff --git a/indra/test/debug.h b/indra/test/debug.h index d61eba651b..76dbb973b2 100644 --- a/indra/test/debug.h +++ b/indra/test/debug.h @@ -29,42 +29,64 @@ #if ! defined(LL_DEBUG_H) #define LL_DEBUG_H -#include <iostream> +#include "print.h" /***************************************************************************** * Debugging stuff *****************************************************************************/ -// This class is intended to illuminate entry to a given block, exit from the -// same block and checkpoints along the way. It also provides a convenient -// place to turn std::cout output on and off. +/** + * This class is intended to illuminate entry to a given block, exit from the + * same block and checkpoints along the way. It also provides a convenient + * place to turn std::cerr output on and off. + * + * If the environment variable LOGTEST is non-empty, each Debug instance will + * announce its construction and destruction, presumably at entry and exit to + * the block in which it's declared. Moreover, any arguments passed to its + * operator()() will be streamed to std::cerr, prefixed by the block + * description. + * + * The variable LOGTEST is used because that's the environment variable + * checked by test.cpp, our TUT main() program, to turn on LLError logging. It + * is expected that Debug is solely for use in test programs. + */ class Debug { public: Debug(const std::string& block): - mBlock(block) + mBlock(block), + mLOGTEST(getenv("LOGTEST")), + // debug output enabled when LOGTEST is set AND non-empty + mEnabled(mLOGTEST && *mLOGTEST) { (*this)("entry"); } + // non-copyable + Debug(const Debug&) = delete; + ~Debug() { (*this)("exit"); } - void operator()(const std::string& status) + template <typename... ARGS> + void operator()(ARGS&&... args) { -#if defined(DEBUG_ON) - std::cout << mBlock << ' ' << status << std::endl; -#endif + if (mEnabled) + { + print(mBlock, ' ', std::forward<ARGS>(args)...); + } } private: const std::string mBlock; + const char* mLOGTEST; + bool mEnabled; }; // It's often convenient to use the name of the enclosing function as the name // of the Debug block. -#define DEBUG Debug debug(__FUNCTION__) +#define DEBUG Debug debug(LL_PRETTY_FUNCTION) // These BEGIN/END macros are specifically for debugging output -- please // don't assume you must use such for coroutines in general! They only help to diff --git a/indra/test/llevents_tut.cpp b/indra/test/llevents_tut.cpp index 16edab6282..17f64a4953 100644 --- a/indra/test/llevents_tut.cpp +++ b/indra/test/llevents_tut.cpp @@ -38,7 +38,6 @@ #define testable public #include "llevents.h" #undef testable -#include "lllistenerwrapper.h" // STL headers // std headers #include <iostream> @@ -92,9 +91,7 @@ template<> template<> void events_object::test<1>() { set_test_name("basic operations"); - // Now there's a static constructor in llevents.cpp that registers on - // the "mainloop" pump to call LLEventPumps::flush(). - // Actually -- having to modify this to track the statically- + // Having to modify this to track the statically- // constructed pumps in other TUT modules in this giant monolithic test // executable isn't such a hot idea. // ensure_equals("initial pump", pumps.mPumpMap.size(), 1); @@ -134,17 +131,15 @@ void events_object::test<1>() per_frame.post(4); check_listener("re-blocked", listener0, 3); } // unblock - std::string threw; - try - { - // NOTE: boost::bind() saves its arguments by VALUE! If you pass - // an object instance rather than a pointer, you'll end up binding - // to an internal copy of that instance! Use boost::ref() to - // capture a reference instead. - per_frame.listen(listener0.getName(), // note bug, dup name - boost::bind(&Listener::call, boost::ref(listener1), _1)); - } - CATCH_AND_STORE_WHAT_IN(threw, LLEventPump::DupListenerName) + std::string threw = catch_what<LLEventPump::DupListenerName>( + [&per_frame, this](){ + // NOTE: boost::bind() saves its arguments by VALUE! If you pass + // an object instance rather than a pointer, you'll end up binding + // to an internal copy of that instance! Use boost::ref() to + // capture a reference instead. + per_frame.listen(listener0.getName(), // note bug, dup name + boost::bind(&Listener::call, boost::ref(listener1), _1)); + }); ensure_equals(threw, std::string("DupListenerName: " "Attempt to register duplicate listener name '") + @@ -213,43 +208,6 @@ bool chainEvents(Listener& someListener, const LLSD& event) template<> template<> void events_object::test<3>() { - set_test_name("LLEventQueue delayed action"); - // This access is NOT legal usage: we can do it only because we're - // hacking private for test purposes. Normally we'd either compile in - // a particular name, or (later) edit a config file. - pumps.mQueueNames.insert("login"); - LLEventPump& login(pumps.obtain("login")); - // The "mainloop" pump is special: posting on that implicitly calls - // LLEventPumps::flush(), which in turn should flush our "login" - // LLEventQueue. - LLEventPump& mainloop(pumps.obtain("mainloop")); - ensure("LLEventQueue leaf class", dynamic_cast<LLEventQueue*> (&login)); - listener0.listenTo(login); - listener0.reset(0); - login.post(1); - check_listener("waiting for queued event", listener0, 0); - mainloop.post(LLSD()); - check_listener("got queued event", listener0, 1); - login.stopListening(listener0.getName()); - // Verify that when an event handler posts a new event on the same - // LLEventQueue, it doesn't get processed in the same flush() call -- - // it waits until the next flush() call. - listener0.reset(17); - login.listen("chainEvents", boost::bind(chainEvents, boost::ref(listener0), _1)); - login.post(1); - check_listener("chainEvents(1) not yet called", listener0, 17); - mainloop.post(LLSD()); - check_listener("chainEvents(1) called", listener0, 1); - mainloop.post(LLSD()); - check_listener("chainEvents(0) called", listener0, 0); - mainloop.post(LLSD()); - check_listener("chainEvents(-1) not called", listener0, 0); - login.stopListening("chainEvents"); -} - -template<> template<> -void events_object::test<4>() -{ set_test_name("explicitly-instantiated LLEventStream"); // Explicitly instantiate an LLEventStream, and verify that it // self-registers with LLEventPumps @@ -273,7 +231,7 @@ void events_object::test<4>() } template<> template<> -void events_object::test<5>() +void events_object::test<4>() { set_test_name("stopListening()"); LLEventPump& login(pumps.obtain("login")); @@ -287,7 +245,7 @@ void events_object::test<5>() } template<> template<> -void events_object::test<6>() +void events_object::test<5>() { set_test_name("chaining LLEventPump instances"); LLEventPump& upstream(pumps.obtain("upstream")); @@ -312,7 +270,7 @@ void events_object::test<6>() } template<> template<> -void events_object::test<7>() +void events_object::test<6>() { set_test_name("listener dependency order"); typedef LLEventPump::NameList NameList; @@ -341,15 +299,13 @@ void events_object::test<7>() ensure_equals(collector.result, make<StringVec>(list_of("Mary")("spot")("checked"))); collector.clear(); button.stopListening("spot"); - std::string threw; - try - { - button.listen("spot", - boost::bind(&Collect::add, boost::ref(collector), "spot", _1), - // after "Mary" and "checked" -- whoops! - make<NameList>(list_of("Mary")("checked"))); - } - CATCH_AND_STORE_WHAT_IN(threw, LLEventPump::Cycle) + std::string threw = catch_what<LLEventPump::Cycle>( + [&button, &collector](){ + button.listen("spot", + boost::bind(&Collect::add, boost::ref(collector), "spot", _1), + // after "Mary" and "checked" -- whoops! + make<NameList>(list_of("Mary")("checked"))); + }); // Obviously the specific wording of the exception text can // change; go ahead and change the test to match. // Establish that it contains: @@ -374,15 +330,13 @@ void events_object::test<7>() button.post(3); ensure_equals(collector.result, make<StringVec>(list_of("Mary")("checked")("yellow")("shoelaces"))); collector.clear(); - threw.clear(); - try - { - button.listen("of", - boost::bind(&Collect::add, boost::ref(collector), "of", _1), - make<NameList>(list_of("shoelaces")), - make<NameList>(list_of("yellow"))); - } - CATCH_AND_STORE_WHAT_IN(threw, LLEventPump::OrderChange) + threw = catch_what<LLEventPump::OrderChange>( + [&button, &collector](){ + button.listen("of", + boost::bind(&Collect::add, boost::ref(collector), "of", _1), + make<NameList>(list_of("shoelaces")), + make<NameList>(list_of("yellow"))); + }); // Same remarks about the specific wording of the exception. Just // ensure that it contains enough information to clarify the // problem and what must be done to resolve it. @@ -398,19 +352,17 @@ void events_object::test<7>() } template<> template<> -void events_object::test<8>() +void events_object::test<7>() { set_test_name("tweaked and untweaked LLEventPump instance names"); { // nested scope // Hand-instantiate an LLEventStream... LLEventStream bob("bob"); - std::string threw; - try - { - // then another with a duplicate name. - LLEventStream bob2("bob"); - } - CATCH_AND_STORE_WHAT_IN(threw, LLEventPump::DupPumpName) + std::string threw = catch_what<LLEventPump::DupPumpName>( + [](){ + // then another with a duplicate name. + LLEventStream bob2("bob"); + }); ensure("Caught DupPumpName", !threw.empty()); } // delete first 'bob' LLEventStream bob("bob"); // should work, previous one unregistered @@ -432,7 +384,7 @@ void eventSource(const LLListenerOrPumpName& listener) } template<> template<> -void events_object::test<9>() +void events_object::test<8>() { set_test_name("LLListenerOrPumpName"); // Passing a boost::bind() expression to LLListenerOrPumpName @@ -445,13 +397,11 @@ void events_object::test<9>() listener0.listenTo(random); eventSource("random"); check_listener("got by pump name", listener0, 17); - std::string threw; - try - { - LLListenerOrPumpName empty; - empty(17); - } - CATCH_AND_STORE_WHAT_IN(threw, LLListenerOrPumpName::Empty) + std::string threw = catch_what<LLListenerOrPumpName::Empty>( + [](){ + LLListenerOrPumpName empty; + empty(17); + }); ensure("threw Empty", !threw.empty()); } @@ -475,7 +425,7 @@ private: }; template<> template<> -void events_object::test<10>() +void events_object::test<9>() { set_test_name("listen(boost::bind(...TempListener...))"); // listen() can't do anything about a plain TempListener instance: @@ -503,223 +453,60 @@ void events_object::test<10>() heaptest.stopListening("temp"); } -template<> template<> -void events_object::test<11>() -{ - set_test_name("listen(boost::bind(...weak_ptr...))"); - // listen() detecting weak_ptr<TempListener> in boost::bind() object - bool live = false; - LLEventPump& heaptest(pumps.obtain("heaptest")); - LLBoundListener connection; - ensure("default state", !connection.connected()); - { - boost::shared_ptr<TempListener> newListener(new TempListener("heap", live)); - newListener->reset(); - ensure("TempListener constructed", live); - connection = heaptest.listen(newListener->getName(), - boost::bind(&Listener::call, - weaken(newListener), - _1)); - ensure("new connection", connection.connected()); - heaptest.post(1); - check_listener("received", *newListener, 1); - } // presumably this will make newListener go away? - // verify that - ensure("TempListener destroyed", !live); - ensure("implicit disconnect", !connection.connected()); - // now just make sure we don't blow up trying to access a freed object! - heaptest.post(2); -} - -template<> template<> -void events_object::test<12>() -{ - set_test_name("listen(boost::bind(...shared_ptr...))"); - /*==========================================================================*| - // DISABLED because I've made this case produce a compile error. - // Following the error leads the disappointed dev to a comment - // instructing her to use the weaken() function to bind a weak_ptr<T> - // instead of binding a shared_ptr<T>, and explaining why. I know of - // no way to use TUT to code a repeatable test in which the expected - // outcome is a compile error. The interested reader is invited to - // uncomment this block and build to see for herself. - - // listen() detecting shared_ptr<TempListener> in boost::bind() object - bool live = false; - LLEventPump& heaptest(pumps.obtain("heaptest")); - LLBoundListener connection; - std::string listenerName("heap"); - ensure("default state", !connection.connected()); - { - boost::shared_ptr<TempListener> newListener(new TempListener(listenerName, live)); - ensure_equals("use_count", newListener.use_count(), 1); - newListener->reset(); - ensure("TempListener constructed", live); - connection = heaptest.listen(newListener->getName(), - boost::bind(&Listener::call, newListener, _1)); - ensure("new connection", connection.connected()); - ensure_equals("use_count", newListener.use_count(), 2); - heaptest.post(1); - check_listener("received", *newListener, 1); - } // this should make newListener go away... - // Unfortunately, the fact that we've bound a shared_ptr by value into - // our LLEventPump means that copy will keep the referenced object alive. - ensure("TempListener still alive", live); - ensure("still connected", connection.connected()); - // disconnecting explicitly should delete the TempListener... - heaptest.stopListening(listenerName); -#if 0 // however, in my experience, it does not. I don't know why not. - // Ah: on 2009-02-19, Frank Mori Hess, author of the Boost.Signals2 - // library, stated on the boost-users mailing list: - // http://www.nabble.com/Re%3A--signals2--review--The-review-of-the-signals2-library-(formerly-thread_safe_signals)-begins-today%2C-Nov-1st-p22102367.html - // "It will get destroyed eventually. The signal cleans up its slot - // list little by little during connect/invoke. It doesn't immediately - // remove disconnected slots from the slot list since other threads - // might be using the same slot list concurrently. It might be - // possible to make it immediately reset the shared_ptr owning the - // slot though, leaving an empty shared_ptr in the slot list, since - // that wouldn't invalidate any iterators." - ensure("TempListener destroyed", ! live); - ensure("implicit disconnect", ! connection.connected()); -#endif // 0 - // now just make sure we don't blow up trying to access a freed object! - heaptest.post(2); -|*==========================================================================*/ -} - class TempTrackableListener: public TempListener, public LLEventTrackable { public: -TempTrackableListener(const std::string& name, bool& liveFlag): - TempListener(name, liveFlag) -{} + TempTrackableListener(const std::string& name, bool& liveFlag): + TempListener(name, liveFlag) + {} }; template<> template<> -void events_object::test<13>() -{ -set_test_name("listen(boost::bind(...TempTrackableListener ref...))"); -bool live = false; -LLEventPump& heaptest(pumps.obtain("heaptest")); -LLBoundListener connection; -{ - TempTrackableListener tempListener("temp", live); - ensure("TempTrackableListener constructed", live); - connection = heaptest.listen(tempListener.getName(), - boost::bind(&TempTrackableListener::call, - boost::ref(tempListener), _1)); - heaptest.post(1); - check_listener("received", tempListener, 1); -} // presumably this will make tempListener go away? -// verify that -ensure("TempTrackableListener destroyed", ! live); -ensure("implicit disconnect", ! connection.connected()); -// now just make sure we don't blow up trying to access a freed object! -heaptest.post(2); -} - -template<> template<> -void events_object::test<14>() -{ -set_test_name("listen(boost::bind(...TempTrackableListener pointer...))"); -bool live = false; -LLEventPump& heaptest(pumps.obtain("heaptest")); -LLBoundListener connection; +void events_object::test<10>() { - TempTrackableListener* newListener(new TempTrackableListener("temp", live)); - ensure("TempTrackableListener constructed", live); - connection = heaptest.listen(newListener->getName(), - boost::bind(&TempTrackableListener::call, - newListener, _1)); - heaptest.post(1); - check_listener("received", *newListener, 1); - // explicitly destroy newListener - delete newListener; -} -// verify that -ensure("TempTrackableListener destroyed", ! live); -ensure("implicit disconnect", ! connection.connected()); -// now just make sure we don't blow up trying to access a freed object! -heaptest.post(2); + set_test_name("listen(boost::bind(...TempTrackableListener ref...))"); + bool live = false; + LLEventPump& heaptest(pumps.obtain("heaptest")); + LLBoundListener connection; + { + TempTrackableListener tempListener("temp", live); + ensure("TempTrackableListener constructed", live); + connection = heaptest.listen(tempListener.getName(), + boost::bind(&TempTrackableListener::call, + boost::ref(tempListener), _1)); + heaptest.post(1); + check_listener("received", tempListener, 1); + } // presumably this will make tempListener go away? + // verify that + ensure("TempTrackableListener destroyed", ! live); + ensure("implicit disconnect", ! connection.connected()); + // now just make sure we don't blow up trying to access a freed object! + heaptest.post(2); } template<> template<> -void events_object::test<15>() -{ -// This test ensures that using an LLListenerWrapper subclass doesn't -// block Boost.Signals2 from recognizing a bound LLEventTrackable -// subclass. -set_test_name("listen(llwrap<LLLogListener>(boost::bind(...TempTrackableListener ref...)))"); -bool live = false; -LLEventPump& heaptest(pumps.obtain("heaptest")); -LLBoundListener connection; +void events_object::test<11>() { - TempTrackableListener tempListener("temp", live); - ensure("TempTrackableListener constructed", live); - connection = heaptest.listen(tempListener.getName(), - llwrap<LLLogListener>( - boost::bind(&TempTrackableListener::call, - boost::ref(tempListener), _1))); - heaptest.post(1); - check_listener("received", tempListener, 1); -} // presumably this will make tempListener go away? -// verify that -ensure("TempTrackableListener destroyed", ! live); -ensure("implicit disconnect", ! connection.connected()); -// now just make sure we don't blow up trying to access a freed object! -heaptest.post(2); + set_test_name("listen(boost::bind(...TempTrackableListener pointer...))"); + bool live = false; + LLEventPump& heaptest(pumps.obtain("heaptest")); + LLBoundListener connection; + { + TempTrackableListener* newListener(new TempTrackableListener("temp", live)); + ensure("TempTrackableListener constructed", live); + connection = heaptest.listen(newListener->getName(), + boost::bind(&TempTrackableListener::call, + newListener, _1)); + heaptest.post(1); + check_listener("received", *newListener, 1); + // explicitly destroy newListener + delete newListener; + } + // verify that + ensure("TempTrackableListener destroyed", ! live); + ensure("implicit disconnect", ! connection.connected()); + // now just make sure we don't blow up trying to access a freed object! + heaptest.post(2); } -class TempSharedListener: public TempListener, -public boost::enable_shared_from_this<TempSharedListener> -{ -public: -TempSharedListener(const std::string& name, bool& liveFlag): - TempListener(name, liveFlag) -{} -}; - -template<> template<> -void events_object::test<16>() -{ - set_test_name("listen(boost::bind(...TempSharedListener ref...))"); -#if 0 -bool live = false; -LLEventPump& heaptest(pumps.obtain("heaptest")); -LLBoundListener connection; -{ - // We MUST have at least one shared_ptr to an - // enable_shared_from_this subclass object before - // shared_from_this() can work. - boost::shared_ptr<TempSharedListener> - tempListener(new TempSharedListener("temp", live)); - ensure("TempSharedListener constructed", live); - // However, we're not passing either the shared_ptr or its - // corresponding weak_ptr -- instead, we're passing a reference to - // the TempSharedListener. -/*==========================================================================*| - std::cout << "Capturing const ref" << std::endl; - const boost::enable_shared_from_this<TempSharedListener>& cref(*tempListener); - std::cout << "Capturing const ptr" << std::endl; - const boost::enable_shared_from_this<TempSharedListener>* cp(&cref); - std::cout << "Capturing non-const ptr" << std::endl; - boost::enable_shared_from_this<TempSharedListener>* p(const_cast<boost::enable_shared_from_this<TempSharedListener>*>(cp)); - std::cout << "Capturing shared_from_this()" << std::endl; - boost::shared_ptr<TempSharedListener> sp(p->shared_from_this()); - std::cout << "Capturing weak_ptr" << std::endl; - boost::weak_ptr<TempSharedListener> wp(weaken(sp)); - std::cout << "Binding weak_ptr" << std::endl; -|*==========================================================================*/ - connection = heaptest.listen(tempListener->getName(), - boost::bind(&TempSharedListener::call, *tempListener, _1)); - heaptest.post(1); - check_listener("received", *tempListener, 1); -} // presumably this will make tempListener go away? -// verify that -ensure("TempSharedListener destroyed", ! live); -ensure("implicit disconnect", ! connection.connected()); -// now just make sure we don't blow up trying to access a freed object! -heaptest.post(2); -#endif // 0 -} } // namespace tut diff --git a/indra/test/llpermissions_tut.cpp b/indra/test/llpermissions_tut.cpp index fa4b085fd3..e6ccd5ecb7 100644 --- a/indra/test/llpermissions_tut.cpp +++ b/indra/test/llpermissions_tut.cpp @@ -406,43 +406,6 @@ namespace tut template<> template<> void permission_object_t::test<20>() { - LLFILE* fp = LLFile::fopen("linden_file.dat","w+"); - if(!fp) - { - LL_ERRS() << "file couldn't be opened\n" << LL_ENDL; - return; - } - LLPermissions perm,perm1; - LLUUID creator("abf0d56b-82e5-47a2-a8ad-74741bb2c29e"); - LLUUID owner("68edcf47-ccd7-45b8-9f90-1649d7f12806"); - LLUUID lastOwner("5e47a0dc-97bf-44e0-8b40-de06718cee9d"); - LLUUID group("9c8eca51-53d5-42a7-bb58-cef070395db8"); - perm.init(creator,owner,lastOwner,group); - - U32 base = PERM_TRANSFER | PERM_COPY; - U32 ownerp = PERM_TRANSFER; - U32 groupp = PERM_TRANSFER; - U32 everyone = PERM_TRANSFER; - U32 next = PERM_NONE; - - perm.initMasks(base, ownerp, everyone, groupp, next); - - ensure("Permissions export failed", perm.exportFile(fp)); - fclose(fp); - fp = LLFile::fopen("linden_file.dat","r+"); - if(!fp) - { - LL_ERRS() << "file couldn't be opened\n" << LL_ENDL; - return; - } - ensure("Permissions import failed", perm1.importFile(fp)); - fclose(fp); - ensure_equals("exportFile()/importFile():failed to export and import the data ", perm1, perm); -} - - template<> template<> - void permission_object_t::test<21>() - { LLPermissions perm,perm1; LLUUID creator("abf0d56b-82e5-47a2-a8ad-74741bb2c29e"); LLUUID owner("68edcf47-ccd7-45b8-9f90-1649d7f12806"); @@ -467,14 +430,7 @@ namespace tut } template<> template<> - void permission_object_t::test<22>() - { - // Deleted LLPermissions::exportFileXML() and LLPermissions::importXML() - // because I can't find any non-test code references to it. 2009-05-04 JC - } - - template<> template<> - void permission_object_t::test<23>() + void permission_object_t::test<21>() { LLPermissions perm,perm1; LLUUID creator("abf0d56b-82e5-47a2-a8ad-74741bb2c29e"); @@ -490,7 +446,7 @@ namespace tut } template<> template<> - void permission_object_t::test<24>() + void permission_object_t::test<22>() { LLPermissions perm,perm1; LLUUID creator("abf0d56b-82e5-47a2-a8ad-74741bb2c29e"); @@ -513,7 +469,7 @@ namespace tut } template<> template<> - void permission_object_t::test<25>() + void permission_object_t::test<23>() { LLAggregatePermissions AggrPermission; LLAggregatePermissions AggrPermission1; diff --git a/indra/test/llsaleinfo_tut.cpp b/indra/test/llsaleinfo_tut.cpp index 5f4d9186a8..b7b207610f 100644 --- a/indra/test/llsaleinfo_tut.cpp +++ b/indra/test/llsaleinfo_tut.cpp @@ -107,41 +107,6 @@ namespace tut template<> template<> void llsaleinfo_test_t::test<2>() { - - LLFILE* fp = LLFile::fopen("linden_file.dat","w+"); - if(!fp) - { - LL_ERRS() << "file could not be opened\n" << LL_ENDL; - return; - } - - S32 sale_price = 43500; - LLSaleInfo llsaleinfo(LLSaleInfo::FS_COPY, sale_price); - - llsaleinfo.exportFile(fp); - fclose(fp); - - LLSaleInfo llsaleinfo1; - U32 perm_mask; - BOOL has_perm_mask; - fp = LLFile::fopen("linden_file.dat","r"); - - if(!fp) - { - LL_ERRS() << "file coudnt be opened\n" << LL_ENDL; - return; - } - - llsaleinfo1.importFile(fp, has_perm_mask, perm_mask); - fclose(fp); - - ensure("importFile() fn failed ", llsaleinfo.getSaleType() == llsaleinfo1.getSaleType() && - llsaleinfo.getSalePrice() == llsaleinfo1.getSalePrice()); - } - - template<> template<> - void llsaleinfo_test_t::test<3>() - { S32 sale_price = 525452; LLSaleInfo llsaleinfo(LLSaleInfo::FS_ORIGINAL, sale_price); @@ -160,14 +125,7 @@ namespace tut } template<> template<> - void llsaleinfo_test_t::test<4>() - { - // Deleted LLSaleInfo::exportFileXML() and LLSaleInfo::importXML() - // because I can't find any non-test code references to it. 2009-05-04 JC - } - - template<> template<> - void llsaleinfo_test_t::test<5>() + void llsaleinfo_test_t::test<3>() { S32 sale_price = 99000; LLSaleInfo saleinfo(LLSaleInfo::FS_ORIGINAL, sale_price); @@ -186,7 +144,7 @@ namespace tut //static EForSale lookup(const char* name) fn test template<> template<> - void llsaleinfo_test_t::test<6>() + void llsaleinfo_test_t::test<4>() { S32 sale_price = 233223; LLSaleInfo::EForSale ret_type = LLSaleInfo::lookup("orig"); @@ -200,7 +158,7 @@ namespace tut //void LLSaleInfo::accumulate(const LLSaleInfo& sale_info) fn test template<> template<> - void llsaleinfo_test_t::test<7>() + void llsaleinfo_test_t::test<5>() { S32 sale_price = 20; LLSaleInfo saleinfo(LLSaleInfo::FS_COPY, sale_price); @@ -213,7 +171,7 @@ namespace tut // test cases of bool operator==(const LLSaleInfo &rhs) fn // test case of bool operator!=(const LLSaleInfo &rhs) fn template<> template<> - void llsaleinfo_test_t::test<8>() + void llsaleinfo_test_t::test<6>() { S32 sale_price = 55000; LLSaleInfo saleinfo(LLSaleInfo::FS_ORIGINAL, sale_price); @@ -225,7 +183,7 @@ namespace tut } template<> template<> - void llsaleinfo_test_t::test<9>() + void llsaleinfo_test_t::test<7>() { //TBD: void LLSaleInfo::packMessage(LLMessageSystem* msg) const diff --git a/indra/test/llsdmessagebuilder_tut.cpp b/indra/test/llsdmessagebuilder_tut.cpp index b7283f53a6..b65a3fefd5 100644 --- a/indra/test/llsdmessagebuilder_tut.cpp +++ b/indra/test/llsdmessagebuilder_tut.cpp @@ -272,7 +272,7 @@ namespace tut void LLSDMessageBuilderTestObject::test<14>() // Quaternion { - LLQuaternion outValue, inValue = LLQuaternion(1,2,3,4); + LLQuaternion outValue, inValue = LLQuaternion(1,LLVector3(2,3,4)); LLSDMessageBuilder builder = defaultBuilder(); builder.addQuat("var", inValue); LLSDMessageReader reader = setReader(builder); diff --git a/indra/test/llsdmessagereader_tut.cpp b/indra/test/llsdmessagereader_tut.cpp index 6dc5cf593e..3c402765d8 100644 --- a/indra/test/llsdmessagereader_tut.cpp +++ b/indra/test/llsdmessagereader_tut.cpp @@ -274,7 +274,7 @@ namespace tut void LLSDMessageReaderTestObject::test<17>() // Quaternion { - LLQuaternion outValue, inValue = LLQuaternion(1,2,3,4); + LLQuaternion outValue, inValue = LLQuaternion(1,LLVector3(2,3,4)); LLSD sdValue = ll_sd_from_quaternion(inValue); LLSDMessageReader msg = testType(sdValue); msg.getQuat("block", "var", outValue); diff --git a/indra/test/llsdutil_tut.cpp b/indra/test/llsdutil_tut.cpp index 140f4b832b..6fce53f335 100644 --- a/indra/test/llsdutil_tut.cpp +++ b/indra/test/llsdutil_tut.cpp @@ -386,4 +386,49 @@ namespace tut lmap["Seattle"] = 72; ensure("llsd_equals(superset left map)", ! llsd_equals(lmap, rmap)); } + + template<> template<> + void llsdutil_object::test<10>() + { + set_test_name("llsd_hashing"); + + { + LLSD data_s1 = LLSD::String("The quick brown aardvark jumped over the lazy lemming."); + LLSD data_s2 = LLSD::String("The quick brown aardvark jumped over the lazy lemming."); + + ensure("hash: Identical string hashes match.", boost::hash<LLSD>{}(data_s1) == boost::hash<LLSD>{}(data_s2)); + } + { + LLSD data_r1 = LLSD::Real(3.0f); + LLSD data_i1 = LLSD::Integer(3); + ensure("hash: equivalent values but different types do not match.", boost::hash<LLSD>{}(data_r1) != boost::hash<LLSD>{}(data_i1)); + } + { + LLSD data_a1 = LLSDArray("A")("B")("C"); + LLSD data_a2 = LLSDArray("A")("B")("C"); + + ensure("hash: identical arrays produce identical results", boost::hash<LLSD>{}(data_a1) == boost::hash<LLSD>{}(data_a2)); + + data_a2.append(LLSDArray(1)(2)); + + ensure("hash: changing the array changes the hash.", boost::hash<LLSD>{}(data_a1) != boost::hash<LLSD>{}(data_a2)); + + data_a1.append(LLSDArray(1)(2)); + ensure("hash: identical arrays produce identical results with nested arrays", boost::hash<LLSD>{}(data_a1) == boost::hash<LLSD>{}(data_a2)); + } + { + LLSD data_m1 = LLSDMap("key1", LLSD::Real(3.0))("key2", "value2")("key3", LLSDArray(1)(2)(3)); + LLSD data_m2 = LLSDMap("key1", LLSD::Real(3.0))("key2", "value2")("key3", LLSDArray(1)(2)(3)); + + ensure("hash: identical maps produce identical results", boost::hash<LLSD>{}(data_m1) == boost::hash<LLSD>{}(data_m2)); + + LLSD data_m3 = LLSDMap("key1", LLSD::Real(5.0))("key2", "value2")("key3", LLSDArray(1)(2)(3)); + ensure("hash: Different values in the map produce different hashes.", boost::hash<LLSD>{}(data_m1) != boost::hash<LLSD>{}(data_m3)); + + LLSD data_m4 = LLSDMap("keyA", LLSD::Real(3.0))("key2", "value2")("key3", LLSDArray(1)(2)(3)); + ensure("hash: Different keys in the map produce different hashes.", boost::hash<LLSD>{}(data_m1) != boost::hash<LLSD>{}(data_m4)); + + } + } + } diff --git a/indra/test/lltemplatemessagebuilder_tut.cpp b/indra/test/lltemplatemessagebuilder_tut.cpp index 7b4b6a8b70..10564ad7b3 100644 --- a/indra/test/lltemplatemessagebuilder_tut.cpp +++ b/indra/test/lltemplatemessagebuilder_tut.cpp @@ -319,7 +319,8 @@ namespace tut { LLMessageTemplate messageTemplate = defaultTemplate(); messageTemplate.addBlock(defaultBlock(MVT_LLQuaternion, 12)); - LLQuaternion outValue, inValue = LLQuaternion(0.3713907f, 0.5570861f, 0.7427813f,0.0f); + LLQuaternion outValue, inValue = LLQuaternion(0.0f, LLVector3(0.3713907f, 0.5570861f, 0.7427813f)); + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); builder->addQuat(_PREHASH_Test0, inValue); LLTemplateMessageReader* reader = setReader(messageTemplate, builder); @@ -786,7 +787,7 @@ namespace tut { LLMessageTemplate messageTemplate = defaultTemplate(); messageTemplate.addBlock(defaultBlock(MVT_LLQuaternion, 12)); - LLQuaternion outValue, inValue = LLQuaternion(0.3713907f, 0.5570861f, 0.7427813f,0.0f); + LLQuaternion outValue, inValue = LLQuaternion(0.0f, LLVector3(0.3713907f, 0.5570861f, 0.7427813f)); LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); builder->addQuat(_PREHASH_Test0, inValue); LLTemplateMessageReader* reader = setReader( diff --git a/indra/test/lltestapp.h b/indra/test/lltestapp.h new file mode 100644 index 0000000000..382516cd2b --- /dev/null +++ b/indra/test/lltestapp.h @@ -0,0 +1,34 @@ +/** + * @file lltestapp.h + * @author Nat Goodspeed + * @date 2019-10-21 + * @brief LLApp subclass useful for testing. + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Copyright (c) 2019, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLTESTAPP_H) +#define LL_LLTESTAPP_H + +#include "llapp.h" + +/** + * LLTestApp is a dummy LLApp that simply sets LLApp::isRunning() for anyone + * who cares. + */ +class LLTestApp: public LLApp +{ +public: + LLTestApp() + { + setStatus(APP_STATUS_RUNNING); + } + + bool init() { return true; } + bool cleanup() { return true; } + bool frame() { return true; } +}; + +#endif /* ! defined(LL_LLTESTAPP_H) */ diff --git a/indra/test/print.h b/indra/test/print.h new file mode 100644 index 0000000000..08e36caddf --- /dev/null +++ b/indra/test/print.h @@ -0,0 +1,42 @@ +/** + * @file print.h + * @author Nat Goodspeed + * @date 2020-01-02 + * @brief print() function for debugging + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Copyright (c) 2020, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_PRINT_H) +#define LL_PRINT_H + +#include <iostream> + +// print(..., NONL); +// leaves the output dangling, suppressing the normally appended std::endl +struct NONL_t {}; +#define NONL (NONL_t()) + +// normal recursion end +inline +void print() +{ + std::cerr << std::endl; +} + +// print(NONL) is a no-op +inline +void print(NONL_t) +{ +} + +template <typename T, typename... ARGS> +void print(T&& first, ARGS&&... rest) +{ + std::cerr << first; + print(std::forward<ARGS>(rest)...); +} + +#endif /* ! defined(LL_PRINT_H) */ diff --git a/indra/test/setenv.h b/indra/test/setenv.h new file mode 100644 index 0000000000..ed2de9ccca --- /dev/null +++ b/indra/test/setenv.h @@ -0,0 +1,66 @@ +/** + * @file setenv.h + * @author Nat Goodspeed + * @date 2020-04-01 + * @brief Provide a way for a particular test program to alter the + * environment before entry to main(). + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Copyright (c) 2020, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_SETENV_H) +#define LL_SETENV_H + +#include <stdlib.h> // setenv() + +/** + * Our test.cpp main program responds to environment variables LOGTEST and + * LOGFAIL. But if you set (e.g.) LOGTEST=DEBUG before a viewer build, @em + * every test program in the build emits debug log output. This can be so + * voluminous as to slow down the build. + * + * With an integration test program, you can specifically build (e.g.) the + * INTEGRATION_TEST_llstring target, and set any environment variables you + * want for that. But with a unit test program, since executing the program is + * a side effect rather than an explicit target, specifically building (e.g.) + * PROJECT_lllogin_TEST_lllogin only builds the executable without running it. + * + * To set an environment variable for a particular test program, declare a + * static instance of SetEnv in its .cpp file. SetEnv's constructor takes + * pairs of strings, e.g. + * + * @code + * static SetEnv sLOGGING("LOGTEST", "INFO"); + * @endcode + * + * Declaring a static instance of SetEnv is important because that ensures + * that the environment variables are set before main() is entered, since it + * is main() that examines LOGTEST and LOGFAIL. + */ +struct SetEnv +{ + // degenerate constructor, terminate recursion + SetEnv() {} + + /** + * SetEnv() accepts an arbitrary number of pairs of strings: variable + * name, value, variable name, value ... Entering the constructor sets + * those variables in the process environment using Posix setenv(), + * overriding any previous value. If static SetEnv declarations in + * different translation units specify overlapping sets of variable names, + * it is indeterminate which instance will "win." + */ + template <typename VAR, typename VAL, typename... ARGS> + SetEnv(VAR&& var, VAL&& val, ARGS&&... rest): + // constructor forwarding handles the tail of the list + SetEnv(std::forward<ARGS>(rest)...) + { + // set just the first (variable, value) pair + // 1 means override previous value if any + setenv(std::forward<VAR>(var), std::forward<VAL>(val), 1); + } +}; + +#endif /* ! defined(LL_SETENV_H) */ diff --git a/indra/test/sync.h b/indra/test/sync.h new file mode 100644 index 0000000000..ca8b7262d6 --- /dev/null +++ b/indra/test/sync.h @@ -0,0 +1,116 @@ +/** + * @file sync.h + * @author Nat Goodspeed + * @date 2019-03-13 + * @brief Synchronize coroutines within a test program so we can observe side + * effects. Certain test programs test coroutine synchronization + * mechanisms. Such tests usually want to interleave coroutine + * executions in strictly stepwise fashion. This class supports that + * paradigm. + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Copyright (c) 2019, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_SYNC_H) +#define LL_SYNC_H + +#include "llcond.h" +#include "lltut.h" +#include "stringize.h" +#include "llerror.h" +#include "llcoros.h" + +/** + * Instantiate Sync in any test in which we need to suspend one coroutine + * until we're sure that another has had a chance to run. Simply calling + * llcoro::suspend() isn't necessarily enough; that provides a chance for the + * other to run, but doesn't guarantee that it has. If each coroutine is + * consistent about calling Sync::bump() every time it wakes from any + * suspension, Sync::yield() and yield_until() should at least ensure that + * somebody else has had a chance to run. + */ +class Sync +{ + LLScalarCond<int> mCond{0}; + F32Milliseconds mTimeout; + +public: + Sync(F32Milliseconds timeout=F32Milliseconds(10000.0f)): + mTimeout(timeout) + {} + + /** + * Bump mCond by n steps -- ideally, do this every time a participating + * coroutine wakes up from any suspension. The choice to bump() after + * resumption rather than just before suspending is worth calling out: + * this practice relies on the fact that condition_variable::notify_all() + * merely marks a suspended coroutine ready to run, rather than + * immediately resuming it. This way, though, even if a coroutine exits + * before reaching its next suspend point, the other coroutine isn't + * left waiting forever. + */ + void bump(int n=1) + { + // Calling mCond.set_all(mCond.get() + n) would be great for + // coroutines -- but not so good between kernel threads -- it would be + // racy. Make the increment atomic by calling update_all(), which runs + // the passed lambda within a mutex lock. + int updated; + mCond.update_all( + [&n, &updated](int& data) + { + data += n; + // Capture the new value for possible logging purposes. + updated = data; + }); + // In the multi-threaded case, this log message could be a bit + // misleading, as it will be emitted after waiting threads have + // already awakened. But emitting the log message within the lock + // would seem to hold the lock longer than we really ought. + LL_DEBUGS() << llcoro::logname() << " bump(" << n << ") -> " << updated << LL_ENDL; + } + + /** + * Set mCond to a specific n. Use of bump() and yield() is nicely + * maintainable, since you can insert or delete matching operations in a + * test function and have the rest of the Sync operations continue to + * line up as before. But sometimes you need to get very specific, which + * is where set() and yield_until() come in handy: less maintainable, + * more precise. + */ + void set(int n) + { + LL_DEBUGS() << llcoro::logname() << " set(" << n << ")" << LL_ENDL; + mCond.set_all(n); + } + + /// suspend until "somebody else" has bumped mCond by n steps + void yield(int n=1) + { + return yield_until(STRINGIZE("Sync::yield_for(" << n << ") timed out after " + << int(mTimeout.value()) << "ms"), + mCond.get() + n); + } + + /// suspend until "somebody else" has bumped mCond to a specific value + void yield_until(int until) + { + return yield_until(STRINGIZE("Sync::yield_until(" << until << ") timed out after " + << int(mTimeout.value()) << "ms"), + until); + } + +private: + void yield_until(const std::string& desc, int until) + { + std::string name(llcoro::logname()); + LL_DEBUGS() << name << " yield_until(" << until << ") suspending" << LL_ENDL; + tut::ensure(name + ' ' + desc, mCond.wait_for_equal(mTimeout, until)); + // each time we wake up, bump mCond + bump(); + } +}; + +#endif /* ! defined(LL_SYNC_H) */ diff --git a/indra/test/test.cpp b/indra/test/test.cpp index 861ec1d942..87c4a8d8a3 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -37,7 +37,7 @@ #include "linden_common.h" #include "llerrorcontrol.h" #include "lltut.h" -#include "tests/wrapllerrs.h" // RecorderProxy +#include "chained_callback.h" #include "stringize.h" #include "namedtempfile.h" #include "lltrace.h" @@ -72,7 +72,6 @@ #include <boost/shared_ptr.hpp> #include <boost/make_shared.hpp> #include <boost/foreach.hpp> -#include <boost/lambda/lambda.hpp> #include <fstream> @@ -173,8 +172,10 @@ private: LLError::RecorderPtr mRecorder; }; -class LLTestCallback : public tut::callback +class LLTestCallback : public chained_callback { + typedef chained_callback super; + public: LLTestCallback(bool verbose_mode, std::ostream *stream, boost::shared_ptr<LLReplayLog> replayer) : @@ -185,7 +186,7 @@ public: mSkippedTests(0), // By default, capture a shared_ptr to std::cout, with a no-op "deleter" // so that destroying the shared_ptr makes no attempt to delete std::cout. - mStream(boost::shared_ptr<std::ostream>(&std::cout, boost::lambda::_1)), + mStream(boost::shared_ptr<std::ostream>(&std::cout, [](std::ostream*){})), mReplayer(replayer) { if (stream) @@ -206,22 +207,25 @@ public: ~LLTestCallback() { - } + } virtual void run_started() { //std::cout << "run_started" << std::endl; LL_INFOS("TestRunner")<<"Test Started"<< LL_ENDL; + super::run_started(); } virtual void group_started(const std::string& name) { LL_INFOS("TestRunner")<<"Unit test group_started name=" << name << LL_ENDL; *mStream << "Unit test group_started name=" << name << std::endl; + super::group_started(name); } virtual void group_completed(const std::string& name) { LL_INFOS("TestRunner")<<"Unit test group_completed name=" << name << LL_ENDL; *mStream << "Unit test group_completed name=" << name << std::endl; + super::group_completed(name); } virtual void test_completed(const tut::test_result& tr) @@ -254,7 +258,7 @@ public: break; case tut::test_result::ex: ++mFailedTests; - out << "exception"; + out << "exception: " << tr.exception_typeid; break; case tut::test_result::warn: ++mFailedTests; @@ -265,7 +269,7 @@ public: out << "abnormal termination"; break; case tut::test_result::skip: - ++mSkippedTests; + ++mSkippedTests; out << "skipped known failure"; break; default: @@ -283,6 +287,7 @@ public: *mStream << std::endl; } LL_INFOS("TestRunner")<<out.str()<<LL_ENDL; + super::test_completed(tr); } virtual int getFailedTests() const { return mFailedTests; } @@ -310,6 +315,7 @@ public: *mStream << "Please report or fix the problem." << std::endl; *mStream << "*********************************" << std::endl; } + super::run_completed(); } protected: @@ -475,9 +481,8 @@ void stream_usage(std::ostream& s, const char* app) << "LOGTEST=level : for all tests, emit log messages at level 'level'\n" << "LOGFAIL=level : only for failed tests, emit log messages at level 'level'\n" << "where 'level' is one of ALL, DEBUG, INFO, WARN, ERROR, NONE.\n" - << "--debug is like LOGTEST=DEBUG, but --debug overrides LOGTEST.\n" - << "Setting LOGFAIL overrides both LOGTEST and --debug: the only log\n" - << "messages you will see will be for failed tests.\n\n"; + << "--debug is like LOGTEST=DEBUG, but --debug overrides LOGTEST,\n" + << "while LOGTEST overrides LOGFAIL.\n\n"; s << "Examples:" << std::endl; s << " " << app << " --verbose" << std::endl; @@ -521,35 +526,8 @@ int main(int argc, char **argv) #ifndef LL_WINDOWS ::testing::InitGoogleMock(&argc, argv); #endif - // LOGTEST overrides default, but can be overridden by --debug or LOGFAIL. - const char* LOGTEST = getenv("LOGTEST"); - if (LOGTEST) - { - LLError::initForApplication(".", ".", true /* log to stderr */); - LLError::setDefaultLevel(LLError::decodeLevel(LOGTEST)); - } - else - { - LLError::initForApplication(".", ".", false /* do not log to stderr */); - LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - } - LLError::setFatalFunction(wouldHaveCrashed); - std::string test_app_name(argv[0]); - std::string test_log = test_app_name + ".log"; - LLFile::remove(test_log); - LLError::logToFile(test_log); - -#ifdef CTYPE_WORKAROUND - ctype_workaround(); -#endif ll_init_apr(); - - if (!sMasterThreadRecorder) - { - sMasterThreadRecorder = new LLTrace::ThreadRecorder(); - LLTrace::set_master_thread_recorder(sMasterThreadRecorder); - } apr_getopt_t* os = NULL; if(APR_SUCCESS != apr_getopt_init(&os, gAPRPoolp, argc, argv)) { @@ -563,7 +541,10 @@ int main(int argc, char **argv) std::string test_group; std::string suite_name; - // values use for options parsing + // LOGTEST overrides default, but can be overridden by --debug. + const char* LOGTEST = getenv("LOGTEST"); + + // values used for options parsing apr_status_t apr_err; const char* opt_arg = NULL; int opt_id = 0; @@ -612,7 +593,7 @@ int main(int argc, char **argv) wait_at_exit = true; break; case 'd': - LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + LOGTEST = "DEBUG"; break; case 'x': suite_name.assign(opt_arg); @@ -624,22 +605,45 @@ int main(int argc, char **argv) } } - // run the tests - + // set up logging const char* LOGFAIL = getenv("LOGFAIL"); - boost::shared_ptr<LLReplayLog> replayer; - // As described in stream_usage(), LOGFAIL overrides both --debug and - // LOGTEST. - if (LOGFAIL) + boost::shared_ptr<LLReplayLog> replayer{boost::make_shared<LLReplayLog>()}; + + // Testing environment variables for both 'set' and 'not empty' allows a + // user to suppress a pre-existing environment variable by forcing empty. + if (LOGTEST && *LOGTEST) { - LLError::ELevel level = LLError::decodeLevel(LOGFAIL); - replayer.reset(new LLReplayLogReal(level, gAPRPoolp)); + LLError::initForApplication(".", ".", true /* log to stderr */); + LLError::setDefaultLevel(LLError::decodeLevel(LOGTEST)); } else { - replayer.reset(new LLReplayLog()); + LLError::initForApplication(".", ".", false /* do not log to stderr */); + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + if (LOGFAIL && *LOGFAIL) + { + LLError::ELevel level = LLError::decodeLevel(LOGFAIL); + replayer.reset(new LLReplayLogReal(level, gAPRPoolp)); + } + } + LLError::setFatalFunction(wouldHaveCrashed); + std::string test_app_name(argv[0]); + std::string test_log = test_app_name + ".log"; + LLFile::remove(test_log); + LLError::logToFile(test_log); + +#ifdef CTYPE_WORKAROUND + ctype_workaround(); +#endif + + if (!sMasterThreadRecorder) + { + sMasterThreadRecorder = new LLTrace::ThreadRecorder(); + LLTrace::set_master_thread_recorder(sMasterThreadRecorder); } + // run the tests + LLTestCallback* mycallback; if (getenv("TEAMCITY_PROJECT_NAME")) { @@ -650,7 +654,8 @@ int main(int argc, char **argv) mycallback = new LLTestCallback(verbose_mode, output.get(), replayer); } - tut::runner.get().set_callback(mycallback); + // a chained_callback subclass must be linked with previous + mycallback->link(); if(test_group.empty()) { diff --git a/indra/tools/vstool/VSTool.exe b/indra/tools/vstool/VSTool.exe Binary files differindex 854290b90a..751540413a 100755 --- a/indra/tools/vstool/VSTool.exe +++ b/indra/tools/vstool/VSTool.exe diff --git a/indra/tools/vstool/main.cs b/indra/tools/vstool/main.cs index ef2e582b90..1d6b2f14d1 100755 --- a/indra/tools/vstool/main.cs +++ b/indra/tools/vstool/main.cs @@ -556,7 +556,7 @@ namespace VSTool break;
case "12.00":
- version = "VC120";
+ version = "VC150";
break;
default:
@@ -603,6 +603,10 @@ namespace VSTool progid = "VisualStudio.DTE.12.0";
break;
+ case "VC150":
+ progid = "VisualStudio.DTE.15.0";
+ break;
+
default:
throw new ApplicationException("Can't handle VS version: " + version);
}
diff --git a/indra/viewer_components/login/CMakeLists.txt b/indra/viewer_components/login/CMakeLists.txt index 3bedeb7292..23518b791c 100644 --- a/indra/viewer_components/login/CMakeLists.txt +++ b/indra/viewer_components/login/CMakeLists.txt @@ -50,7 +50,7 @@ target_link_libraries(lllogin ${LLMATH_LIBRARIES} ${LLXML_LIBRARIES} ${BOOST_THREAD_LIBRARY} - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY} ) @@ -62,7 +62,7 @@ if(LL_TESTS) set_source_files_properties( lllogin.cpp PROPERTIES - LL_TEST_ADDITIONAL_LIBRARIES "${LLMESSAGE_LIBRARIES};${LLCOREHTTP_LIBRARIES};${LLCOMMON_LIBRARIES};${BOOST_COROUTINE_LIBRARY};${BOOST_CONTEXT_LIBRARY};${BOOST_THREAD_LIBRARY};${BOOST_SYSTEM_LIBRARY}" + LL_TEST_ADDITIONAL_LIBRARIES "${LLMESSAGE_LIBRARIES};${LLCOREHTTP_LIBRARIES};${LLCOMMON_LIBRARIES};${BOOST_FIBER_LIBRARY};${BOOST_CONTEXT_LIBRARY};${BOOST_THREAD_LIBRARY};${BOOST_SYSTEM_LIBRARY}" ) LL_ADD_PROJECT_UNIT_TESTS(lllogin "${lllogin_TEST_SOURCE_FILES}") diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp index 9193d32b49..d485203fa1 100644 --- a/indra/viewer_components/login/lllogin.cpp +++ b/indra/viewer_components/login/lllogin.cpp @@ -23,6 +23,7 @@ * $/LicenseInfo$ */ +#include "llwin32headers.h" #include "linden_common.h" #include "llsd.h" #include "llsdutil.h" @@ -147,167 +148,170 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params) } try { - LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName() - << " with uri '" << uri << "', parameters " << printable_params << LL_ENDL; + LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::getName() + << " with uri '" << uri << "', parameters " << printable_params << LL_ENDL; - LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction")); - // EXT-4193: use a DIFFERENT reply pump than for the SRV request. We used - // to share them -- but the EXT-3934 fix made it possible for an abandoned - // SRV response to arrive just as we were expecting the XMLRPC response. - LLEventStream loginReplyPump("loginreply", true); + LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction")); + // EXT-4193: use a DIFFERENT reply pump than for the SRV request. We used + // to share them -- but the EXT-3934 fix made it possible for an abandoned + // SRV response to arrive just as we were expecting the XMLRPC response. + LLEventStream loginReplyPump("loginreply", true); - LLSD::Integer attempts = 0; + LLSD::Integer attempts = 0; - LLSD request(login_params); - request["reply"] = loginReplyPump.getName(); - request["uri"] = uri; - std::string status; + LLSD request(login_params); + request["reply"] = loginReplyPump.getName(); + request["uri"] = uri; + std::string status; - // Loop back to here if login attempt redirects to a different - // request["uri"] - for (;;) - { - ++attempts; - LLSD progress_data; - progress_data["attempt"] = attempts; - progress_data["request"] = request; - if (progress_data["request"].has("params") - && progress_data["request"]["params"].has("passwd")) - { - progress_data["request"]["params"]["passwd"] = "*******"; - } - sendProgressEvent("offline", "authenticating", progress_data); - - // We expect zero or more "Downloading" status events, followed by - // exactly one event with some other status. Use postAndSuspend() the - // first time, because -- at least in unit-test land -- it's - // possible for the reply to arrive before the post() call - // returns. Subsequent responses, of course, must be awaited - // without posting again. - for (mAuthResponse = validateResponse(loginReplyPump.getName(), - llcoro::postAndSuspend(request, xmlrpcPump, loginReplyPump, "reply")); - mAuthResponse["status"].asString() == "Downloading"; - mAuthResponse = validateResponse(loginReplyPump.getName(), - llcoro::suspendUntilEventOn(loginReplyPump))) + // Loop back to here if login attempt redirects to a different + // request["uri"] + for (;;) { - // Still Downloading -- send progress update. - sendProgressEvent("offline", "downloading"); - } + ++attempts; + LLSD progress_data; + progress_data["attempt"] = attempts; + progress_data["request"] = request; + if (progress_data["request"].has("params") + && progress_data["request"]["params"].has("passwd")) + { + progress_data["request"]["params"]["passwd"] = "*******"; + } + sendProgressEvent("offline", "authenticating", progress_data); + + // We expect zero or more "Downloading" status events, followed by + // exactly one event with some other status. Use postAndSuspend() the + // first time, because -- at least in unit-test land -- it's + // possible for the reply to arrive before the post() call + // returns. Subsequent responses, of course, must be awaited + // without posting again. + for (mAuthResponse = validateResponse(loginReplyPump.getName(), + llcoro::postAndSuspend(request, xmlrpcPump, loginReplyPump, "reply")); + mAuthResponse["status"].asString() == "Downloading"; + mAuthResponse = validateResponse(loginReplyPump.getName(), + llcoro::suspendUntilEventOn(loginReplyPump))) + { + // Still Downloading -- send progress update. + sendProgressEvent("offline", "downloading"); + } - LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL; - status = mAuthResponse["status"].asString(); + LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL; + status = mAuthResponse["status"].asString(); - // Okay, we've received our final status event for this - // request. Unless we got a redirect response, break the retry - // loop for the current rewrittenURIs entry. - if (!(status == "Complete" && - mAuthResponse["responses"]["login"].asString() == "indeterminate")) - { - break; - } + // Okay, we've received our final status event for this + // request. Unless we got a redirect response, break the retry + // loop for the current rewrittenURIs entry. + if (!(status == "Complete" && + mAuthResponse["responses"]["login"].asString() == "indeterminate")) + { + break; + } - sendProgressEvent("offline", "indeterminate", mAuthResponse["responses"]); + sendProgressEvent("offline", "indeterminate", mAuthResponse["responses"]); - // Here the login service at the current URI is redirecting us - // to some other URI ("indeterminate" -- why not "redirect"?). - // The response should contain another uri to try, with its - // own auth method. - request["uri"] = mAuthResponse["responses"]["next_url"].asString(); - request["method"] = mAuthResponse["responses"]["next_method"].asString(); - } // loop back to try the redirected URI + // Here the login service at the current URI is redirecting us + // to some other URI ("indeterminate" -- why not "redirect"?). + // The response should contain another uri to try, with its + // own auth method. + request["uri"] = mAuthResponse["responses"]["next_url"].asString(); + request["method"] = mAuthResponse["responses"]["next_method"].asString(); + } // loop back to try the redirected URI - // Here we're done with redirects. - if (status == "Complete") - { - // StatusComplete does not imply auth success. Check the - // actual outcome of the request. We've already handled the - // "indeterminate" case in the loop above. - if (mAuthResponse["responses"]["login"].asString() == "true") - { - sendProgressEvent("online", "connect", mAuthResponse["responses"]); - } - else + // Here we're done with redirects. + if (status == "Complete") { - // Synchronize here with the updater. We synchronize here rather - // than in the fail.login handler, which actually examines the - // response from login.cgi, because here we are definitely in a - // coroutine and can definitely use suspendUntilBlah(). Whoever's - // listening for fail.login might not be. - - // If the reason for login failure is that we must install a - // required update, we definitely want to pass control to the - // updater to manage that for us. We'll handle any other login - // failure ourselves, as usual. We figure that no matter where you - // are in the world, or what kind of network you're on, we can - // reasonably expect the Viewer Version Manager to respond more or - // less as quickly as login.cgi. This synchronization is only - // intended to smooth out minor races between the two services. - // But what if the updater crashes? Use a timeout so that - // eventually we'll tire of waiting for it and carry on as usual. - // Given the above, it can be a fairly short timeout, at least - // from a human point of view. - - // Since sSyncPoint is an LLEventMailDrop, we DEFINITELY want to - // consume the posted event. - LLCoros::OverrideConsuming oc(true); - // Timeout should produce the isUndefined() object passed here. - LL_DEBUGS("LLLogin") << "Login failure, waiting for sync from updater" << LL_ENDL; - LLSD updater = llcoro::suspendUntilEventOnWithTimeout(sSyncPoint, 10, LLSD()); - if (updater.isUndefined()) + // StatusComplete does not imply auth success. Check the + // actual outcome of the request. We've already handled the + // "indeterminate" case in the loop above. + if (mAuthResponse["responses"]["login"].asString() == "true") { - LL_WARNS("LLLogin") << "Failed to hear from updater, proceeding with fail.login" - << LL_ENDL; + sendProgressEvent("online", "connect", mAuthResponse["responses"]); } else { - LL_DEBUGS("LLLogin") << "Got responses from updater and login.cgi" << LL_ENDL; + // Synchronize here with the updater. We synchronize here rather + // than in the fail.login handler, which actually examines the + // response from login.cgi, because here we are definitely in a + // coroutine and can definitely use suspendUntilBlah(). Whoever's + // listening for fail.login might not be. + + // If the reason for login failure is that we must install a + // required update, we definitely want to pass control to the + // updater to manage that for us. We'll handle any other login + // failure ourselves, as usual. We figure that no matter where you + // are in the world, or what kind of network you're on, we can + // reasonably expect the Viewer Version Manager to respond more or + // less as quickly as login.cgi. This synchronization is only + // intended to smooth out minor races between the two services. + // But what if the updater crashes? Use a timeout so that + // eventually we'll tire of waiting for it and carry on as usual. + // Given the above, it can be a fairly short timeout, at least + // from a human point of view. + + // Since sSyncPoint is an LLEventMailDrop, we DEFINITELY want to + // consume the posted event. + LLCoros::OverrideConsuming oc(true); + // Timeout should produce the isUndefined() object passed here. + LL_DEBUGS("LLLogin") << "Login failure, waiting for sync from updater" << LL_ENDL; + LLSD updater = llcoro::suspendUntilEventOnWithTimeout(sSyncPoint, 10, LLSD()); + if (updater.isUndefined()) + { + LL_WARNS("LLLogin") << "Failed to hear from updater, proceeding with fail.login" + << LL_ENDL; + } + else + { + LL_DEBUGS("LLLogin") << "Got responses from updater and login.cgi" << LL_ENDL; + } + // Let the fail.login handler deal with empty updater response. + LLSD responses(mAuthResponse["responses"]); + responses["updater"] = updater; + sendProgressEvent("offline", "fail.login", responses); } - // Let the fail.login handler deal with empty updater response. - LLSD responses(mAuthResponse["responses"]); - responses["updater"] = updater; - sendProgressEvent("offline", "fail.login", responses); + return; // Done! } - return; // Done! - } -// /* Sometimes we end with "Started" here. Slightly slow server? -// * Seems to be ok to just skip it. Otherwise we'd error out and crash in the if below. -// */ -// if( status == "Started") -// { -// LL_DEBUGS("LLLogin") << mAuthResponse << LL_ENDL; -// continue; -// } - - // If we don't recognize status at all, trouble - if (! (status == "CURLError" - || status == "XMLRPCError" - || status == "OtherError")) - { - LL_ERRS("LLLogin") << "Unexpected status from " << xmlrpcPump.getName() << " pump: " - << mAuthResponse << LL_ENDL; - return; - } +/*==========================================================================*| + // Sometimes we end with "Started" here. Slightly slow server? Seems + // to be ok to just skip it. Otherwise we'd error out and crash in the + // if below. + if( status == "Started") + { + LL_DEBUGS("LLLogin") << mAuthResponse << LL_ENDL; + continue; + } +|*==========================================================================*/ - // Here status IS one of the errors tested above. - // Tell caller this didn't work out so well. - - // *NOTE: The response from LLXMLRPCListener's Poller::poll method returns an - // llsd with no "responses" node. To make the output from an incomplete login symmetrical - // to success, add a data/message and data/reason fields. - LLSD error_response(LLSDMap - ("reason", mAuthResponse["status"]) - ("errorcode", mAuthResponse["errorcode"]) - ("message", mAuthResponse["error"])); - if(mAuthResponse.has("certificate")) - { - error_response["certificate"] = mAuthResponse["certificate"]; - } - sendProgressEvent("offline", "fail.login", error_response); + // If we don't recognize status at all, trouble + if (! (status == "CURLError" + || status == "XMLRPCError" + || status == "OtherError")) + { + LL_ERRS("LLLogin") << "Unexpected status from " << xmlrpcPump.getName() << " pump: " + << mAuthResponse << LL_ENDL; + return; + } + + // Here status IS one of the errors tested above. + // Tell caller this didn't work out so well. + + // *NOTE: The response from LLXMLRPCListener's Poller::poll method returns an + // llsd with no "responses" node. To make the output from an incomplete login symmetrical + // to success, add a data/message and data/reason fields. + LLSD error_response(LLSDMap + ("reason", mAuthResponse["status"]) + ("errorcode", mAuthResponse["errorcode"]) + ("message", mAuthResponse["error"])); + if(mAuthResponse.has("certificate")) + { + error_response["certificate"] = mAuthResponse["certificate"]; + } + sendProgressEvent("offline", "fail.login", error_response); } catch (...) { - CRASH_ON_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::instance().getName() - << "('" << uri << "', " << printable_params << ")")); + LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::getName() + << "('" << uri << "', " << printable_params << ")")); + throw; } } diff --git a/indra/viewer_components/login/tests/lllogin_test.cpp b/indra/viewer_components/login/tests/lllogin_test.cpp index e96c495446..f9267533ff 100644 --- a/indra/viewer_components/login/tests/lllogin_test.cpp +++ b/indra/viewer_components/login/tests/lllogin_test.cpp @@ -36,14 +36,16 @@ #include "../lllogin.h" // STL headers // std headers +#include <chrono> #include <iostream> // external library headers // other Linden headers -#include "llsd.h" -#include "../../../test/lltut.h" -//#define DEBUG_ON #include "../../../test/debug.h" +#include "../../../test/lltestapp.h" +#include "../../../test/lltut.h" #include "llevents.h" +#include "lleventcoro.h" +#include "llsd.h" #include "stringize.h" #if LL_WINDOWS @@ -66,29 +68,68 @@ // This is a listener to receive results from lllogin. class LoginListener: public LLEventTrackable { - std::string mName; - LLSD mLastEvent; + std::string mName; + LLSD mLastEvent; + size_t mCalls{ 0 }; Debug mDebug; public: - LoginListener(const std::string& name) : - mName(name), + LoginListener(const std::string& name) : + mName(name), mDebug(stringize(*this)) - {} + {} - bool call(const LLSD& event) - { - mDebug(STRINGIZE("LoginListener called!: " << event)); - - mLastEvent = event; - return false; - } + bool call(const LLSD& event) + { + mDebug(STRINGIZE("LoginListener called!: " << event)); + + mLastEvent = event; + ++mCalls; + return false; + } LLBoundListener listenTo(LLEventPump& pump) { return pump.listen(mName, boost::bind(&LoginListener::call, this, _1)); - } + } + + LLSD lastEvent() const { return mLastEvent; } - LLSD lastEvent() const { return mLastEvent; } + size_t getCalls() const { return mCalls; } + + // wait for arbitrary predicate to become true + template <typename PRED> + LLSD waitFor(const std::string& desc, PRED&& pred, double seconds=2.0) const + { + // remember when we started waiting + auto start = std::chrono::system_clock::now(); + // Break loop when the passed predicate returns true + while (! std::forward<PRED>(pred)()) + { + // but if we've been spinning here too long, test failed + // how long have we been here, anyway? + auto now = std::chrono::system_clock::now(); + // the default ratio for duration is seconds + std::chrono::duration<double> elapsed = (now - start); + if (elapsed.count() > seconds) + { + tut::fail(STRINGIZE("LoginListener::waitFor() took more than " + << seconds << " seconds waiting for " << desc)); + } + // haven't yet received the new call, nor have we timed out -- + // just wait + llcoro::suspend(); + } + // oh good, we've gotten at least one new call! Return its event. + return lastEvent(); + } + + // wait for any call() calls beyond prevcalls + LLSD waitFor(size_t prevcalls, double seconds) const + { + return waitFor(STRINGIZE("more than " << prevcalls << " calls"), + [this, prevcalls]()->bool{ return getCalls() > prevcalls; }, + seconds); + } friend std::ostream& operator<<(std::ostream& out, const LoginListener& listener) { @@ -163,11 +204,16 @@ namespace tut { struct llviewerlogin_data { - llviewerlogin_data() : + llviewerlogin_data() : pumps(LLEventPumps::instance()) - {} - LLEventPumps& pumps; - }; + {} + ~llviewerlogin_data() + { + pumps.clear(); + } + LLEventPumps& pumps; + LLTestApp testApp; + }; typedef test_group<llviewerlogin_data> llviewerlogin_group; typedef llviewerlogin_group::object llviewerlogin_object; @@ -186,12 +232,12 @@ namespace tut // Have dummy XMLRPC respond immediately. LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc", respond_immediately); - dummyXMLRPC.listenTo(xmlrpcPump); + LLTempBoundListener conn1 = dummyXMLRPC.listenTo(xmlrpcPump); LLLogin login; LoginListener listener("test_ear"); - listener.listenTo(login.getEventPump()); + LLTempBoundListener conn2 = listener.listenTo(login.getEventPump()); LLSD credentials; credentials["first"] = "foo"; @@ -199,8 +245,9 @@ namespace tut credentials["passwd"] = "secret"; login.connect("login.bar.com", credentials); - - ensure_equals("Online state", listener.lastEvent()["state"].asString(), "online"); + listener.waitFor( + "online state", + [&listener]()->bool{ return listener.lastEvent()["state"].asString() == "online"; }); } template<> template<> @@ -214,11 +261,11 @@ namespace tut LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc"); - dummyXMLRPC.listenTo(xmlrpcPump); + LLTempBoundListener conn1 = dummyXMLRPC.listenTo(xmlrpcPump); LLLogin login; LoginListener listener("test_ear"); - listener.listenTo(login.getEventPump()); + LLTempBoundListener conn2 = listener.listenTo(login.getEventPump()); LLSD credentials; credentials["first"] = "who"; @@ -226,9 +273,12 @@ namespace tut credentials["passwd"] = "badpasswd"; login.connect("login.bar.com", credentials); + llcoro::suspend(); ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating"); + auto prev = listener.getCalls(); + // Send the failed auth request reponse LLSD data; data["status"] = "Complete"; @@ -238,6 +288,10 @@ namespace tut data["responses"]["login"] = "false"; dummyXMLRPC.setResponse(data); dummyXMLRPC.sendReply(); + // we happen to know LLLogin uses a 10-second timeout to try to sync + // with SLVersionChecker -- allow at least that much time before + // giving up + listener.waitFor(prev, 11.0); ensure_equals("Failed to offline", listener.lastEvent()["state"].asString(), "offline"); } @@ -253,11 +307,11 @@ namespace tut LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc"); - dummyXMLRPC.listenTo(xmlrpcPump); + LLTempBoundListener conn1 = dummyXMLRPC.listenTo(xmlrpcPump); LLLogin login; LoginListener listener("test_ear"); - listener.listenTo(login.getEventPump()); + LLTempBoundListener conn2 = listener.listenTo(login.getEventPump()); LLSD credentials; credentials["first"] = "these"; @@ -265,9 +319,12 @@ namespace tut credentials["passwd"] = "matter"; login.connect("login.bar.com", credentials); + llcoro::suspend(); ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating"); + auto prev = listener.getCalls(); + // Send the failed auth request reponse LLSD data; data["status"] = "OtherError"; @@ -276,40 +333,11 @@ namespace tut data["transfer_rate"] = 0; dummyXMLRPC.setResponse(data); dummyXMLRPC.sendReply(); + // we happen to know LLLogin uses a 10-second timeout to try to sync + // with SLVersionChecker -- allow at least that much time before + // giving up + listener.waitFor(prev, 11.0); ensure_equals("Failed to offline", listener.lastEvent()["state"].asString(), "offline"); } - - template<> template<> - void llviewerlogin_object::test<4>() - { - DEBUG; - // Test SRV request timeout. - set_test_name("LLLogin SRV timeout testing"); - - // Testing normal login procedure. - - LLLogin login; - LoginListener listener("test_ear"); - listener.listenTo(login.getEventPump()); - - LLSD credentials; - credentials["first"] = "these"; - credentials["last"] = "don't"; - credentials["passwd"] = "matter"; - credentials["cfg_srv_timeout"] = 0.0f; - - login.connect("login.bar.com", credentials); - - // Get the mainloop eventpump, which needs a pinging in order to drive the - // SRV timeout. - LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); - LLSD frame_event; - mainloop.post(frame_event); - - ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating"); - ensure_equals("Attempt", listener.lastEvent()["data"]["attempt"].asInteger(), 1); - ensure_equals("URI", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.bar.com"); - - } } diff --git a/indra/win_crash_logger/CMakeLists.txt b/indra/win_crash_logger/CMakeLists.txt deleted file mode 100644 index d1de20a6a0..0000000000 --- a/indra/win_crash_logger/CMakeLists.txt +++ /dev/null @@ -1,107 +0,0 @@ -# -*- cmake -*- - -project(win_crash_logger) - -include(00-Common) -include(ICU4C) -include(LLCommon) -include(LLCoreHttp) -include(LLCrashLogger) -include(LLMath) -include(LLMessage) -include(LLVFS) -include(LLWindow) -include(LLXML) -include(Linking) -include(LLSharedLibs) -include(GoogleBreakpad) -include(Boost) - -include_directories( - ${LLCOREHTTP_INCLUDE_DIRS} - ${LLCOMMON_INCLUDE_DIRS} - ${LLCRASHLOGGER_INCLUDE_DIRS} - ${LLMATH_INCLUDE_DIRS} - ${LLWINDOW_INCLUDE_DIRS} - ${LLXML_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} - ${BREAKPAD_INCLUDE_DIRECTORIES} - ) -include_directories(SYSTEM - ${LLCOMMON_SYSTEM_INCLUDE_DIRS} - ${LLXML_SYSTEM_INCLUDE_DIRS} - ) - -set(win_crash_logger_SOURCE_FILES - win_crash_logger.cpp - llcrashloggerwindows.cpp - ) - -set(win_crash_logger_HEADER_FILES - CMakeLists.txt - - llcrashloggerwindows.h - resource.h - StdAfx.h - win_crash_logger.h - ) - -set_source_files_properties(${win_crash_logger_HEADER_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) - -set(win_crash_logger_RESOURCE_FILES - ll_icon.ico - ) - -set_source_files_properties(${win_crash_logger_RESOURCE_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) - -set(win_crash_logger_RESOURCE_FILES - win_crash_logger.rc - ${win_crash_logger_RESOURCE_FILES} - ) - -SOURCE_GROUP("Resource Files" FILES ${win_crash_logger_RESOURCE_FILES}) - -list(APPEND - win_crash_logger_SOURCE_FILES - ${win_crash_logger_HEADER_FILES} - ${win_crash_logger_RESOURCE_FILES} - ) - -find_library(DXGUID_LIBRARY dxguid ${DIRECTX_LIBRARY_DIR}) - -add_executable(windows-crash-logger WIN32 ${win_crash_logger_SOURCE_FILES}) - -target_link_libraries(windows-crash-logger - ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES} - ${ICU4C_LIBRARY} - ${LLCRASHLOGGER_LIBRARIES} - ${LLWINDOW_LIBRARIES} - ${LLVFS_LIBRARIES} - ${LLXML_LIBRARIES} - ${LLMESSAGE_LIBRARIES} - ${LLMATH_LIBRARIES} - ${LLCOREHTTP_LIBRARIES} - ${LLCOMMON_LIBRARIES} - ${BOOST_CONTEXT_LIBRARY} - ${BOOST_COROUTINE_LIBRARY} - ${WINDOWS_LIBRARIES} - ${DXGUID_LIBRARY} - ${GOOGLE_PERFTOOLS_LIBRARIES} - user32 - gdi32 - oleaut32 - wininet - Wldap32 - ) - -if (WINDOWS) - set_target_properties(windows-crash-logger - PROPERTIES - LINK_FLAGS "/NODEFAULTLIB:LIBCMT" - LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\"" - ) -endif (WINDOWS) - -ll_deploy_sharedlibs_command(windows-crash-logger) diff --git a/indra/win_crash_logger/README.txt b/indra/win_crash_logger/README.txt new file mode 100644 index 0000000000..6932a8d9c3 --- /dev/null +++ b/indra/win_crash_logger/README.txt @@ -0,0 +1,3 @@ +This component is no longer used in Linden Lab builds. +Change requests to support continued use by open source +builds are welcome. diff --git a/indra/win_crash_logger/StdAfx.h b/indra/win_crash_logger/StdAfx.h deleted file mode 100644 index 35976658ac..0000000000 --- a/indra/win_crash_logger/StdAfx.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @file StdAfx.h - * @brief standard system includes - * - * $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$ - */ - -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) -#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - -// Windows Header Files: -#include <windows.h> - -// C RunTime Header Files -#include <stdlib.h> -#include <malloc.h> -#include <memory.h> - -// Local Header Files - -// TODO: reference additional headers your program requires here - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) diff --git a/indra/win_crash_logger/ll_icon.ico b/indra/win_crash_logger/ll_icon.ico Binary files differdeleted file mode 100644 index 566346dfe3..0000000000 --- a/indra/win_crash_logger/ll_icon.ico +++ /dev/null diff --git a/indra/win_crash_logger/llcrashloggerwindows.cpp b/indra/win_crash_logger/llcrashloggerwindows.cpp deleted file mode 100644 index 267224a79b..0000000000 --- a/indra/win_crash_logger/llcrashloggerwindows.cpp +++ /dev/null @@ -1,536 +0,0 @@ -/** -* @file llcrashloggerwindows.cpp -* @brief Windows crash logger implementation -* -* $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 "linden_common.h" - -#include "stdafx.h" -#include "resource.h" -#include "llcrashloggerwindows.h" - -#include <sstream> - -#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 "lldxhardware.h" -#include "lldir.h" -#include "llsdserialize.h" -#include "llsdutil.h" -#include "stringize.h" - -#include <client/windows/crash_generation/crash_generation_server.h> -#include <client/windows/crash_generation/client_info.h> - -#define MAX_LOADSTRING 100 -#define MAX_STRING 2048 -const char* const SETTINGS_FILE_HEADER = "version"; -const S32 SETTINGS_FILE_VERSION = 101; - -// Windows Message Handlers - -// Global Variables: -HINSTANCE hInst= NULL; // current instance -TCHAR szTitle[MAX_LOADSTRING]; /* Flawfinder: ignore */ // The title bar text -TCHAR szWindowClass[MAX_LOADSTRING]; /* Flawfinder: ignore */ // The title bar text - -std::string gProductName; -HWND gHwndReport = NULL; // Send/Don't Send dialog -HWND gHwndProgress = NULL; // Progress window -HCURSOR gCursorArrow = NULL; -HCURSOR gCursorWait = NULL; -BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialog? -std::stringstream gDXInfo; -bool gSendLogs = false; - -LLCrashLoggerWindows* LLCrashLoggerWindows::sInstance = NULL; - -//Conversion from char* to wchar* -//Replacement for ATL macros, doesn't allocate memory -//For more info see: http://www.codeguru.com/forum/showthread.php?t=337247 -void ConvertLPCSTRToLPWSTR (const char* pCstring, WCHAR* outStr) -{ - if (pCstring != NULL) - { - int nInputStrLen = strlen (pCstring); - // Double NULL Termination - int nOutputStrLen = MultiByteToWideChar(CP_ACP, 0, pCstring, nInputStrLen, NULL, 0) + 2; - if (outStr) - { - memset (outStr, 0x00, sizeof (WCHAR)*nOutputStrLen); - MultiByteToWideChar (CP_ACP, 0, pCstring, nInputStrLen, outStr, nInputStrLen); - } - } -} - -void write_debug(const char *str) -{ - gDXInfo << str; /* Flawfinder: ignore */ -} - -void write_debug(std::string& str) -{ - write_debug(str.c_str()); -} - -void show_progress(const std::string& message) -{ - std::wstring msg = wstring_to_utf16str(utf8str_to_wstring(message)); - if (gHwndProgress) - { - SendDlgItemMessage(gHwndProgress, // handle to destination window - IDC_LOG, - WM_SETTEXT, // message to send - FALSE, // undo option - (LPARAM)msg.c_str()); - } -} - -void update_messages() -{ - MSG msg; - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - { - exit(0); - } - TranslateMessage(&msg); - DispatchMessage(&msg); - } -} - -void sleep_and_pump_messages( U32 seconds ) -{ - const U32 CYCLES_PER_SECOND = 10; - U32 cycles = seconds * CYCLES_PER_SECOND; - while( cycles-- ) - { - update_messages(); - ms_sleep(1000 / CYCLES_PER_SECOND); - } -} - -// Include product name in the window caption. -void LLCrashLoggerWindows::ProcessCaption(HWND hWnd) -{ - TCHAR templateText[MAX_STRING]; /* Flawfinder: ignore */ - TCHAR header[MAX_STRING]; - std::string final; - GetWindowText(hWnd, templateText, sizeof(templateText)); - final = llformat(ll_convert_wide_to_string(templateText, CP_ACP).c_str(), gProductName.c_str()); - ConvertLPCSTRToLPWSTR(final.c_str(), header); - SetWindowText(hWnd, header); -} - - -// Include product name in the diaog item text. -void LLCrashLoggerWindows::ProcessDlgItemText(HWND hWnd, int nIDDlgItem) -{ - TCHAR templateText[MAX_STRING]; /* Flawfinder: ignore */ - TCHAR header[MAX_STRING]; - std::string final; - GetDlgItemText(hWnd, nIDDlgItem, templateText, sizeof(templateText)); - final = llformat(ll_convert_wide_to_string(templateText, CP_ACP).c_str(), gProductName.c_str()); - ConvertLPCSTRToLPWSTR(final.c_str(), header); - SetDlgItemText(hWnd, nIDDlgItem, header); -} - -bool handle_button_click(WORD button_id) -{ - // Is this something other than Send or Don't Send? - if (button_id != IDOK - && button_id != IDCANCEL) - { - return false; - } - - // We're done with this dialog. - gFirstDialog = FALSE; - - // Send the crash report if requested - if (button_id == IDOK) - { - gSendLogs = TRUE; - WCHAR wbuffer[20000]; - GetDlgItemText(gHwndReport, // handle to dialog box - IDC_EDIT1, // control identifier - wbuffer, // pointer to buffer for text - 20000 // maximum size of string - ); - std::string user_text(ll_convert_wide_to_string(wbuffer, CP_ACP)); - // Activate and show the window. - ShowWindow(gHwndProgress, SW_SHOW); - // Try doing this second to make the progress window go frontmost. - ShowWindow(gHwndReport, SW_HIDE); - ((LLCrashLoggerWindows*)LLCrashLogger::instance())->setUserText(user_text); - ((LLCrashLoggerWindows*)LLCrashLogger::instance())->sendCrashLogs(); - } - // Quit the app - LLApp::setQuitting(); - return true; -} - - -LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) -{ - switch( message ) - { - case WM_CREATE: - return 0; - - case WM_COMMAND: - if( gFirstDialog ) - { - WORD button_id = LOWORD(wParam); - bool handled = handle_button_click(button_id); - if (handled) - { - return 0; - } - } - break; - - case WM_DESTROY: - // Closing the window cancels - LLApp::setQuitting(); - PostQuitMessage(0); - return 0; - } - - return DefWindowProc(hwnd, message, wParam, lParam); -} - - -LLCrashLoggerWindows::LLCrashLoggerWindows(void) -{ - if (LLCrashLoggerWindows::sInstance==NULL) - { - sInstance = this; - } -} - -LLCrashLoggerWindows::~LLCrashLoggerWindows(void) -{ - sInstance = NULL; -} - -bool LLCrashLoggerWindows::getMessageWithTimeout(MSG *msg, UINT to) -{ - bool res; - UINT_PTR timerID = SetTimer(NULL, NULL, to, NULL); - res = GetMessage(msg, NULL, 0, 0); - KillTimer(NULL, timerID); - if (!res) - return false; - if (msg->message == WM_TIMER && msg->hwnd == NULL && msg->wParam == 1) - return false; //TIMEOUT! You could call SetLastError() or something... - return true; -} - -int LLCrashLoggerWindows::processingLoop() { - const int millisecs=1000; - int retries = 0; - const int max_retries = 60; - - LL_DEBUGS("CRASHREPORT") << "Entering processing loop for OOP server" << LL_ENDL; - - LLSD options = getOptionData( LLApp::PRIORITY_COMMAND_LINE ); - - MSG msg; - - bool result; - - while (1) - { - result = getMessageWithTimeout(&msg, millisecs); - if ( result ) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - if ( retries < max_retries ) //Wait up to 1 minute for the viewer to say hello. - { - if (mClientsConnected == 0) - { - LL_DEBUGS("CRASHREPORT") << "Waiting for client to connect." << LL_ENDL; - ++retries; - } - else - { - LL_INFOS("CRASHREPORT") << "Client has connected!" << LL_ENDL; - retries = max_retries; - } - } - else - { - if (mClientsConnected == 0) - { - break; - } - if (!mKeyMaster.isProcessAlive(mPID, mProcName) ) - { - break; - } - } - } - - LL_INFOS() << "session ending.." << LL_ENDL; - - std::string per_run_dir = options["dumpdir"].asString(); - std::string per_run_file = per_run_dir + "\\SecondLife.log"; - std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log"); - - if (gDirUtilp->fileExists(per_run_dir)) - { - LL_INFOS ("CRASHREPORT") << "Copying " << log_file << " to " << per_run_file << LL_ENDL; - LLFile::copy(log_file, per_run_file); - } - return 0; -} - - -void LLCrashLoggerWindows::OnClientConnected(void* context, - const google_breakpad::ClientInfo* client_info) -{ - sInstance->mClientsConnected++; - LL_INFOS("CRASHREPORT") << "Client connected. pid = " << client_info->pid() << " total clients " << sInstance->mClientsConnected << LL_ENDL; -} - -void LLCrashLoggerWindows::OnClientExited(void* context, - const google_breakpad::ClientInfo* client_info) -{ - sInstance->mClientsConnected--; - LL_INFOS("CRASHREPORT") << "Client disconnected. pid = " << client_info->pid() << " total clients " << sInstance->mClientsConnected << LL_ENDL; -} - - -void LLCrashLoggerWindows::OnClientDumpRequest(void* context, - const google_breakpad::ClientInfo* client_info, - const std::wstring* file_path) -{ - if (!file_path) - { - LL_WARNS() << "dump with no file path" << LL_ENDL; - return; - } - if (!client_info) - { - LL_WARNS() << "dump with no client info" << LL_ENDL; - return; - } - - LLCrashLoggerWindows* self = static_cast<LLCrashLoggerWindows*>(context); - if (!self) - { - LL_WARNS() << "dump with no context" << LL_ENDL; - return; - } - - //DWORD pid = client_info->pid(); -} - - -bool LLCrashLoggerWindows::initCrashServer() -{ - //For Breakpad on Windows we need a full Out of Process service to get good data. - //This routine starts up the service on a named pipe that the viewer will then - //communicate with. - using namespace google_breakpad; - - LLSD options = getOptionData( LLApp::PRIORITY_COMMAND_LINE ); - std::string dump_path = options["dumpdir"].asString(); - mClientsConnected = 0; - mPID = options["pid"].asInteger(); - mProcName = options["procname"].asString(); - - //Generate a quasi-uniq name for the named pipe. For our purposes - //this is unique-enough with least hassle. Worst case for duplicate name - //is a second instance of the viewer will not do crash reporting. - std::wstring wpipe_name; - wpipe_name = mCrashReportPipeStr + std::wstring(wstringize(mPID)); - - std::wstring wdump_path(utf8str_to_utf16str(dump_path)); - - //Pipe naming conventions: http://msdn.microsoft.com/en-us/library/aa365783%28v=vs.85%29.aspx - mCrashHandler = new CrashGenerationServer( wpipe_name, - NULL, - &LLCrashLoggerWindows::OnClientConnected, this, - /*NULL, NULL, */ &LLCrashLoggerWindows::OnClientDumpRequest, this, - &LLCrashLoggerWindows::OnClientExited, this, - NULL, NULL, - true, &wdump_path); - - if (!mCrashHandler) { - //Failed to start the crash server. - LL_WARNS() << "Failed to init crash server." << LL_ENDL; - return false; - } - - // Start servicing clients. - if (!mCrashHandler->Start()) { - LL_WARNS() << "Failed to start crash server." << LL_ENDL; - return false; - } - - LL_INFOS("CRASHREPORT") << "Initialized OOP server with pipe named " << stringize(wpipe_name) << LL_ENDL; - return true; -} - -bool LLCrashLoggerWindows::init(void) -{ - bool ok = LLCrashLogger::init(); - if(!ok) return false; - - initCrashServer(); - - /* - mbstowcs( gProductName, mProductName.c_str(), LL_ARRAY_SIZE(gProductName) ); - gProductName[ LL_ARRY_SIZE(gProductName) - 1 ] = 0; - swprintf(gProductName, L"Second Life"); - */ - - LL_INFOS() << "Loading dialogs" << LL_ENDL; - - // Initialize global strings - LoadString(mhInst, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); - LoadString(mhInst, IDC_WIN_CRASH_LOGGER, szWindowClass, MAX_LOADSTRING); - - gCursorArrow = LoadCursor(NULL, IDC_ARROW); - gCursorWait = LoadCursor(NULL, IDC_WAIT); - - // Register a window class that will be used by our dialogs - WNDCLASS wndclass; - wndclass.style = CS_HREDRAW | CS_VREDRAW; - wndclass.lpfnWndProc = WndProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = DLGWINDOWEXTRA; // Required, since this is used for dialogs! - wndclass.hInstance = mhInst; - wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE( IDI_WIN_CRASH_LOGGER ) ); - wndclass.hCursor = gCursorArrow; - wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - wndclass.lpszMenuName = NULL; - wndclass.lpszClassName = szWindowClass; - RegisterClass( &wndclass ); - - return true; -} - -void LLCrashLoggerWindows::gatherPlatformSpecificFiles() -{ - updateApplication("Gathering hardware information. App may appear frozen."); - // DX hardware probe blocks, so we can't cancel during it - //Generate our dx_info.log file - SetCursor(gCursorWait); - // At this point we're responsive enough the user could click the close button - SetCursor(gCursorArrow); - //mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo(); //Not initialized. -} - -bool LLCrashLoggerWindows::frame() -{ - LL_INFOS() << "CrashSubmitBehavior is " << mCrashBehavior << LL_ENDL; - - // Note: parent hwnd is 0 (the desktop). No dlg proc. See Petzold (5th ed) HexCalc example, Chapter 11, p529 - // win_crash_logger.rc has been edited by hand. - // Dialogs defined with CLASS "WIN_CRASH_LOGGER" (must be same as szWindowClass) - gProductName = mProductName; - gHwndProgress = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROGRESS), 0, NULL); - ProcessCaption(gHwndProgress); - ShowWindow(gHwndProgress, SW_HIDE ); - - if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND) - { - LL_INFOS() << "Showing crash report submit progress window." << LL_ENDL; - //ShowWindow(gHwndProgress, SW_SHOW ); Maint-5707 - sendCrashLogs(); - } - else if (mCrashBehavior == CRASH_BEHAVIOR_ASK) - { - gHwndReport = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PREVREPORTBOX), 0, NULL); - // Ignore result - (void) SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_SETCHECK, 0, 0); - // Include the product name in the caption and various dialog items. - ProcessCaption(gHwndReport); - ProcessDlgItemText(gHwndReport, IDC_STATIC_MSG); - - // Update the header to include whether or not we crashed on the last run. - std::string headerStr; - TCHAR header[MAX_STRING]; - if (mCrashInPreviousExec) - { - headerStr = llformat("%s appears to have crashed or frozen the last time it ran.", mProductName.c_str()); - } - else - { - headerStr = llformat("%s appears to have crashed.", mProductName.c_str()); - } - ConvertLPCSTRToLPWSTR(headerStr.c_str(), header); - SetDlgItemText(gHwndReport, IDC_STATIC_HEADER, header); - ShowWindow(gHwndReport, SW_SHOW ); - - MSG msg; - memset(&msg, 0, sizeof(msg)); - while (!LLApp::isQuitting() && GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return true; // msg.wParam; - } - else - { - LL_WARNS() << "Unknown crash behavior " << mCrashBehavior << LL_ENDL; - return true; // 1; - } - return true; // 0; -} - -void LLCrashLoggerWindows::updateApplication(const std::string& message) -{ - LLCrashLogger::updateApplication(message); - if(!message.empty()) show_progress(message); - update_messages(); -} - -bool LLCrashLoggerWindows::cleanup() -{ - if(gSendLogs) - { - if(mSentCrashLogs) show_progress("Done"); - else show_progress("Could not connect to servers, logs not sent"); - sleep_and_pump_messages(3); - } - PostQuitMessage(0); - commonCleanup(); - mKeyMaster.releaseMaster(); - return true; -} - diff --git a/indra/win_crash_logger/llcrashloggerwindows.h b/indra/win_crash_logger/llcrashloggerwindows.h deleted file mode 100644 index f89b8708dc..0000000000 --- a/indra/win_crash_logger/llcrashloggerwindows.h +++ /dev/null @@ -1,86 +0,0 @@ -/** -* @file llcrashloggerwindows.h -* @brief Windows crash logger definition -* -* $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 LLCRASHLOGGERWINDOWS_H -#define LLCRASHLOGGERWINDOWS_H - -#include "llcrashlogger.h" -#include "windows.h" -#include "llstring.h" - -class LLSD; - -namespace google_breakpad { - class CrashGenerationServer; - class ClientInfo; -} - -class LLCrashLoggerWindows : public LLCrashLogger -{ -public: - LLCrashLoggerWindows(void); - ~LLCrashLoggerWindows(void); - static LLCrashLoggerWindows* sInstance; - - virtual bool init(); - virtual bool frame(); - virtual void updateApplication(const std::string& message = LLStringUtil::null); - virtual bool cleanup(); - virtual void gatherPlatformSpecificFiles(); - void setHandle(HINSTANCE hInst) { mhInst = hInst; } - int clients_connected() const { - return mClientsConnected; - } - bool getMessageWithTimeout(MSG *msg, UINT to); - - // Starts the processing loop. This function does not return unless the - // user is logging off or the user closes the crash service window. The - // return value is a good number to pass in ExitProcess(). - int processingLoop(); -private: - void ProcessDlgItemText(HWND hWnd, int nIDDlgItem); - void ProcessCaption(HWND hWnd); - bool initCrashServer(); - google_breakpad::CrashGenerationServer* mCrashHandler; - static void OnClientConnected(void* context, - const google_breakpad::ClientInfo* client_info); - - static void OnClientDumpRequest( - void* context, - const google_breakpad::ClientInfo* client_info, - const std::wstring* file_path); - - static void OnClientExited(void* context, - const google_breakpad::ClientInfo* client_info); - int mClientsConnected; - int mPID; - std::string mProcName; - - HINSTANCE mhInst; - -}; - -#endif diff --git a/indra/win_crash_logger/resource.h b/indra/win_crash_logger/resource.h deleted file mode 100644 index 37a387275e..0000000000 --- a/indra/win_crash_logger/resource.h +++ /dev/null @@ -1,63 +0,0 @@ -/** -* @file resource.h -* @brief Windows crash logger windows resources -* -* $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$ -*/ - -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by win_crash_logger.rc -// -#define IDC_MYICON 2 -#define IDD_REPORT 9 -#define IDD_WIN_CRASH_LOGGER_DIALOG 102 -#define IDD_ABOUTBOX 103 -#define IDS_APP_TITLE 103 -#define IDM_ABOUT 104 -#define IDM_EXIT 105 -#define IDS_HELLO 106 -#define IDI_WIN_CRASH_LOGGER 107 -#define IDI_SMALL 108 -#define IDC_WIN_CRASH_LOGGER 109 -#define IDR_MAINFRAME 128 -#define IDD_PROGRESS 129 -#define IDD_PREVREPORTBOX 130 -#define IDC_EDIT1 1000 -#define IDC_LOG 1004 -#define IDC_CHECK_AUTO 1006 -#define IDC_STATIC_HEADER 1007 -#define IDC_STATIC_WHATINFO 1008 -#define IDC_STATIC_MOTIVATION 1009 -#define IDC_STATIC_MSG 1010 -#define IDC_STATIC -1 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 131 -#define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 1011 -#define _APS_NEXT_SYMED_VALUE 110 -#endif -#endif diff --git a/indra/win_crash_logger/win_crash_logger.cpp b/indra/win_crash_logger/win_crash_logger.cpp deleted file mode 100644 index 58746eba02..0000000000 --- a/indra/win_crash_logger/win_crash_logger.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @file win_crash_logger.cpp - * @brief Windows crash logger implementation - * - * $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 "linden_common.h" -#include "stdafx.h" -#include <stdlib.h> -#include "llcrashloggerwindows.h" - -#ifdef _UNICODE -int APIENTRY wWinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPWSTR lpCmdLine, - int nCmdShow) -#else -int APIENTRY WinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow) -#endif //_UNICODE -{ - LL_INFOS() << "Starting crash reporter with args" << &lpCmdLine << LL_ENDL; - LLCrashLoggerWindows app; - app.setHandle(hInstance); -#ifdef _UNICODE - app.parseCommandOptions(__argc, __wargv); -#else - app.parseCommandOptions(__argc, __argv); -#endif //_UNICODE - - LLSD options = LLApp::instance()->getOptionData( - LLApp::PRIORITY_COMMAND_LINE); - if (!(options.has("pid") && options.has("dumpdir"))) - { - LL_WARNS() << "Insufficient parameters to crash report." << LL_ENDL; - } - if (! app.init()) - { - LL_WARNS() << "Unable to initialize application." << LL_ENDL; - return -1; - } - - app.processingLoop(); - app.frame(); - app.cleanup(); - LL_INFOS() << "Crash reporter finished normally." << LL_ENDL; - return 0; -} diff --git a/indra/win_crash_logger/win_crash_logger.ico b/indra/win_crash_logger/win_crash_logger.ico Binary files differdeleted file mode 100644 index 386883523b..0000000000 --- a/indra/win_crash_logger/win_crash_logger.ico +++ /dev/null diff --git a/indra/win_crash_logger/win_crash_logger.rc b/indra/win_crash_logger/win_crash_logger.rc deleted file mode 100755 index 2819722f63..0000000000 --- a/indra/win_crash_logger/win_crash_logger.rc +++ /dev/null @@ -1,188 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#define APSTUDIO_HIDDEN_SYMBOLS -#include "windows.h" -#undef APSTUDIO_HIDDEN_SYMBOLS -#include "resource.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 - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_WIN_CRASH_LOGGER ICON "ll_icon.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - -IDC_WIN_CRASH_LOGGER MENU -BEGIN - POPUP "&File" - BEGIN - MENUITEM "E&xit", IDM_EXIT - END - POPUP "&Help" - BEGIN - MENUITEM "&About ...", IDM_ABOUT - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_PROGRESS DIALOGEX 100, 100, 234, 33 -STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU -CAPTION "%s Crash Logger" -CLASS "WIN_CRASH_LOGGER" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - LTEXT "Static",IDC_LOG,7,7,220,8 -END - -IDD_REPORT DIALOGEX 100, 100, 297, 125 -STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU -CAPTION "%s Crash Logger" -CLASS "WIN_CRASH_LOGGER" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - DEFPUSHBUTTON "Send",IDOK,198,104,45,15,WS_GROUP - PUSHBUTTON "Don't Send",IDCANCEL,247,104,45,15,WS_GROUP - LTEXT "%s appears to have crashed.",IDC_STATIC_HEADER,4,4,288,14 - LTEXT "This crash reporter collects information about your computer's hardware, operating system, and some %s logs, which are used for debugging purposes only.",IDC_STATIC_WHATINFO,4,23,288,19,NOT WS_GROUP - CONTROL "Remember this choice",IDC_CHECK_AUTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,106,89,13 - LTEXT "Sending crash reports is the best way to help us improve the quality of %s.",IDC_STATIC_MOTIVATION,4,43,288,8 - LTEXT "If you continue to experience this problem, please try:",IDC_STATIC,4,57,251,8 - LTEXT "- Contacting support by visiting http://www.secondlife.com/support",IDC_STATIC,4,67,231,8 -END - -IDD_PREVREPORTBOX DIALOGEX 100, 100, 232, 213 -STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU -CAPTION "%s Crash Logger" -CLASS "WIN_CRASH_LOGGER" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - DEFPUSHBUTTON "Send Report",IDOK,131,193,45,15,WS_GROUP - EDITTEXT IDC_EDIT1,3,100,223,89,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL - PUSHBUTTON "Don't Send",IDCANCEL,181,193,45,15,WS_GROUP - LTEXT "%s appears to have crashed or frozen the last time it ran.",IDC_STATIC_HEADER,4,4,214,8 - LTEXT "This crash reporter collects information about your computer's",IDC_STATIC,4,17,201,8 - LTEXT "hardware configuration, operating system, and some %s",IDC_STATIC_MSG,4,25,212,8 - LTEXT "logs, all of which are used for debugging purposes only.",IDC_STATIC,4,33,210,8 - LTEXT "In the space below, please briefly describe what you were doing",IDC_STATIC,3,48,208,8 - LTEXT "or trying to do just prior to the crash.",IDC_STATIC,3,56,204,8 - LTEXT "If you don't wish to send Linden Lab a crash report, press Don't Send.",IDC_STATIC,3,90,223,8 - LTEXT "This report is NOT read by customer support. If you have billing or",IDC_STATIC,3,68,208,8 - LTEXT "other questions, please go to: www.secondlife.com/support",IDC_STATIC,3,76,206,8 - CONTROL "Remember this choice",IDC_CHECK_AUTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,193,89,13 -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -2 TEXTINCLUDE -BEGIN - "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" - "#include ""windows.h""\r\n" - "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" - "#include ""resource.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_PROGRESS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 227 - TOPMARGIN, 7 - BOTTOMMARGIN, 26 - END - - IDD_REPORT, DIALOG - BEGIN - RIGHTMARGIN, 292 - VERTGUIDE, 4 - BOTTOMMARGIN, 119 - HORZGUIDE, 4 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE -BEGIN - IDS_APP_TITLE "win_crash_logger" - IDS_HELLO "Hello World!" - IDC_WIN_CRASH_LOGGER "WIN_CRASH_LOGGER" -END - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/scripts/code_tools/modified-strings.sh b/scripts/code_tools/modified-strings.sh new file mode 100644 index 0000000000..435dda3f5d --- /dev/null +++ b/scripts/code_tools/modified-strings.sh @@ -0,0 +1,199 @@ +#!/usr/bin/env bash +# $LicenseInfo:firstyear=2014&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 +# +### +### Extract strings modified between some version and the current version +### + +Action=DEFAULT +Rev=master +DefaultXuiDir="indra/newview/skins/default/xui" +Verbose=false +ExitStatus=0 + +while [ $# -ne 0 ] +do + case ${1} in + ## + ## Show usage + ## + -h|--help) + Action=USAGE + ;; + + -v|--verbose) + Verbose=true + ;; + + ## + ## Select the revision to compare against + ## + -r) + if [ $# -lt 2 ] + then + echo "Must specify <revision> with ${1}" 1>&2 + Action=USAGE + ExitStatus=1 + break + else + Rev=${2} + shift # consume the switch ( for n values, consume n-1 ) + fi + ;; + + ## + ## handle an unknown switch + ## + -*) + Action=USAGE + ExitStatus=1 + break + ;; + + *) + if [ -z "${XuiDir}" ] + then + XuiDir=${1} + else + echo "Too many arguments supplied: $@" 1>&2 + Action=USAGE + ExitStatus=1 + break + fi + ;; + esac + + shift # always consume 1 +done + +progress() +{ + if $Verbose + then + echo $* 1>&2 + fi +} + +if [[ $ExitStatus -eq 0 && "${Action}" = "DEFAULT" ]] +then + if [[ ! -d "${XuiDir:=$DefaultXuiDir}" ]] + then + echo "No XUI directory found in '$XuiDir'" 1>&2 + Action=USAGE + ExitStatus=1 + fi +fi + +if [ "${Action}" = "USAGE" ] +then + cat <<USAGE + +Usage: + + modified-strings.sh [ { -v | --verbose } ] [-r <revision>] [<path-to-xui>] + + where + --verbose shows progress messages on stderr (the command takes a while, so this is reassuring) + + -r <revision> specifies a git revision (branch, tag, commit, or relative specifier) + defaults to 'master' so that comparison is against the HEAD of the released viewer branch + + <path-to-xui> is the path to the root directory for XUI files + defaults to '$DefaultXuiDir' + + Emits a tab-separated file with these columns: + filename + the path of a file that has a string change (columns 2 and 3 are empty for lines with a filename) + name + the name attribute of a string or label whose value changed + English value + the current value of the string or label whose value changed + for strings, newlines are changed to '\n' and tab characters are changed to '\t' + + There is also a column for each of the language directories following the English. + +USAGE + exit $ExitStatus +fi + +stringval() # reads stdin and prints the escaped value of a string for the requested tag +{ + local tag=$1 + xmllint --xpath "string(/strings/string[@name=\"$tag\"])" - | perl -p -e 'chomp; s/\n/\\n/g; s/\t/\\t/g;' +} + +columns="file\tname\tEN" +for lang in $(ls -1 ${XuiDir}) +do + if [[ "$lang" != "en" && -d "${XuiDir}" && -f "${XuiDir}/$lang/strings.xml" ]] + then + columns+="\t$lang" + fi +done +echo -e "$columns" + +EnglishStrings="${XuiDir}/en/strings.xml" +progress -n "scanning $EnglishStrings " +echo -e "$EnglishStrings" +# loop over all tags in the current version of the strings file +cat "$EnglishStrings" | xmllint --xpath '/strings/string/@name' - | sed 's/ name="//; s/"$//;' \ +| while read name +do + progress -n "." + # fetch the $Rev and current values for each tag + old_stringval=$(git show "$Rev:$EnglishStrings" 2> /dev/null | stringval "$name") + new_stringval=$(cat "$EnglishStrings" | stringval "$name") + + if [[ "$old_stringval" != "$new_stringval" ]] + then + # the value is different, so print the tag and it's current value separated by a tab + echo -e "\t$name\t$new_stringval" + fi +done +progress "" + +# loop over all XUI files other than strings.xml finding labels +grep -rlw 'label' "${XuiDir}/en" | grep -v '/strings.xml' \ +| while read xuipath +do + progress -n "scanning $xuipath " + listed_file=false + # loop over all elements for which there is a label attribute, getting the name attribute value + xmllint --xpath '//*[@label]/@name' "$xuipath" 2> /dev/null | sed 's/ name="//; s/"$//;' \ + | while read name + do + progress -n "." + # get the old and new label attribute values for each name + old_label=$(git show "$Rev:$xuipath" 2> /dev/null | xmllint --xpath "string(//*[@name=\"${name}\"]/@label)" - 2> /dev/null) + new_label=$(cat "$xuipath" | xmllint --xpath "string(//*[@name=\"${name}\"]/@label)" - 2> /dev/null) + if [[ "$old_label" != "$new_label" ]] + then + if ! $listed_file + then + echo -e "$xuipath" + listed_file=true + fi + echo -e "\t$name\t$new_label" + fi + done + progress "" +done + diff --git a/scripts/code_tools/modified_strings.py b/scripts/code_tools/modified_strings.py new file mode 100644 index 0000000000..6a763b6ec5 --- /dev/null +++ b/scripts/code_tools/modified_strings.py @@ -0,0 +1,403 @@ +#!/usr/bin/env python +"""\ + +This script scans the SL codebase for translation-related strings. + +$LicenseInfo:firstyear=2020&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2020, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" + +from __future__ import print_function + +import xml.etree.ElementTree as ET +import argparse +import os +import sys +from git import Repo, Git # requires the gitpython package +import pandas as pd +import re +from datetime import datetime + +usage_msg="""%(prog)s [options] + +Analyze the XUI configuration files to find text that may need to +be translated. Works by comparing two specified revisions, one +specified by --rev (default HEAD) and one specified by --rev_base +(default master). The script works by comparing xui contents of the +two revisions, and outputs a spreadsheet listing any areas of +difference. The target language must be specified using the --lang +option. Output is an excel file, which can be used as-is or imported +into google sheets. + +If the --rev revision already contains a translation for the text, it +will be included in the spreadsheet for reference. + +Normally you would want --rev_base to be the last revision to have +translations added, and --rev to be the tip of the current +project. You can find the last commit with translation work using "git log --grep INTL- | head" + +The --missing argument can be used to find all text with missing +translations, regardless of when it was added. If translations are being kept +reasonably current, you will normally not need this argument. +""" + +translate_attribs = [ + "title", + "short_title", + "value", + "label", + "label_selected", + "tool_tip", + "ignoretext", + "yestext", + "notext", + "canceltext", + "description", + "longdescription" +] + +def codify_for_print(val): + if isinstance(val, unicode): + return val.encode("utf-8") + else: + return unicode(val, 'utf-8').encode("utf-8") + +# Returns a dict of { name => xml_node } +def read_xml_elements(blob): + try: + contents = blob.data_stream.read() + except: + # default - pretend we read a file with no elements of interest. + # Parser will complain if it gets no elements at all. + contents = '<?xml version="1.0" encoding="utf-8" standalone="yes" ?><strings></strings>' + xml = ET.fromstring(contents) + elts = {} + for child in xml.iter(): + if "name" in child.attrib: + name = child.attrib['name'] + elts[name] = child + return elts + +def failure(*msg): + print(*msg) + sys.exit(1) + +# return True iff any element of lis is "in" thing +def has_any(thing,lis): + for l in lis: + if l in thing: + return True + return False + +def should_translate(filename, elt, field, val): + if val is None: + return False + # Should translate apply recursively? + if "translate" in elt.attrib and elt.attrib["translate"] == "false": + return False + if has_any(filename,["floater_test","floater_aaa","floater_ui_preview"]): + return False + if "TestString PleaseIgnore" in val: + return False + val = re.sub(r"\[.*?\]","",val) + if len(val) == 0: + return False + if val.isspace(): + return False + val = val.strip() + if val.isdigit(): + return False + if not re.search('\w+', val): + return False + if re.match(r"^\s*\d*\s*x\s*\d*\s*$", val): + #print(val, "matches resolution string, will ignore") + return False + # "value" attribute is a hairball, mostly used to encode non-display info but a few exceptions + if field == "value": + if elt.text is not None and len(elt.text) > 0: + #print("value has text, ignoring", ET.tostring(elt)) + return False + if has_any(elt.attrib,["label"]): + return False + if elt.tag in ["string","text"]: + return True + #print("including value attribute", val, "tag", elt.tag,"in", ET.tostring(elt)) + return True + return True + +def make_translation_table(mod_tree, base_tree, lang, args): + + xui_path = "{}/{}".format(xui_base, args.base_lang) + try: + mod_xui_tree = mod_tree[xui_path] + except: + failure("xui tree not found for base language", args.base_lang,"or target lang", lang) + + if args.rev == args.rev_base: + failure("Revs are the same, nothing to compare") + + + data = [] + # For all files to be checked for translations + all_en_strings = set() + for mod_blob in mod_xui_tree.traverse(): + filename = mod_blob.path + if mod_blob.type == "tree": # directory, skip + continue + + if args.verbose: + print(filename) + + try: + base_blob = base_tree[filename] + except: + if args.verbose: + print("No matching base file found for", filename) + base_blob = None + + try: + transl_filename = filename.replace("/xui/{}/".format(args.base_lang), "/xui/{}/".format(lang)) + transl_blob = mod_tree[transl_filename] + except: + if args.verbose: + print("No matching translation file found at", transl_filename) + transl_blob = None + + mod_dict = read_xml_elements(mod_blob) + base_dict = read_xml_elements(base_blob) + transl_dict = read_xml_elements(transl_blob) + + rows = 0 + for name in mod_dict.keys(): + if not name in base_dict or mod_dict[name].text != base_dict[name].text or (args.missing and not name in transl_dict): + elt = mod_dict[name] + val = elt.text + field = "text" + if should_translate(filename, elt, field, val): + transl_val = "--" + if name in transl_dict: + transl_val = transl_dict[name].text + if val in all_en_strings: + new_val = "(DUPLICATE)" + else: + new_val = "" + data.append([val, transl_val, new_val, "", "", filename, name, field]) + all_en_strings.add(val) + rows += 1 + for attr in translate_attribs: + if attr in mod_dict[name].attrib: + if name not in base_dict \ + or attr not in base_dict[name].attrib \ + or mod_dict[name].attrib[attr] != base_dict[name].attrib[attr] \ + or (args.missing and (not name in transl_dict or not attr in transl_dict[name].attrib)): + elt = mod_dict[name] + val = elt.attrib[attr] + if should_translate(filename, elt, attr, val): + transl_val = "--" + if name in transl_dict and attr in transl_dict[name].attrib: + transl_val = transl_dict[name].attrib[attr] + if val in all_en_strings: + new_val = "(DUPLICATE)" + else: + new_val = "" + #attr = attr + ":" + ET.tostring(elt) + data.append([val, transl_val, new_val, "", "", filename, name, attr]) + all_en_strings.add(val) + rows += 1 + + return data + +def find_deletions(mod_tree, base_tree, lang, args, f): + + transl_xui_path = "{}/{}".format(xui_base, lang) + try: + transl_xui_tree = mod_tree[transl_xui_path] + except: + failure("xui tree not found for base language", args.base_lang,"or target lang", lang) + + for transl_blob in transl_xui_tree.traverse(): + if transl_blob.type == "tree": # directory, skip + continue + transl_filename = transl_blob.path + mod_filename = transl_filename.replace("/xui/{}/".format(lang), "/xui/{}/".format(args.base_lang)) + #print("checking",transl_filename,"against",mod_filename) + try: + mod_blob = mod_tree[mod_filename] + except: + print(" delete file", transl_filename, file=f) + continue + mod_dict = read_xml_elements(mod_blob) + if len(mod_dict) == 0: + print(" delete file", transl_filename, file=f) + continue + transl_dict = read_xml_elements(transl_blob) + #print("mod vs transl", len(mod_dict), len(transl_dict)) + lines = 0 + for elt_key in transl_dict: + if not elt_key in mod_dict: + if lines == 0: + print(" in file", transl_filename, file=f) + lines += 1 + print(" delete element", elt_key, file=f) + else: + transl_elt = transl_dict[elt_key] + mod_elt = mod_dict[elt_key] + for a in transl_elt.attrib: + if not a in mod_elt.attrib: + if lines == 0: + print(" in file", transl_filename, file=f) + lines += 1 + print(" delete attribute", a, "from", elt_key, file=f) + if transl_elt.text and (not mod_elt.text): + if lines == 0: + print(" in file", transl_filename, file=f) + lines += 1 + print(" delete text from", elt_key, file=f) + +def save_translation_file(per_lang_data, aux_data, outfile): + + langs = sorted(per_lang_data.keys()) + print("Saving languages", ",".join(langs),"as",outfile) + + writer = pd.ExcelWriter(outfile, engine='xlsxwriter') + + workbook = writer.book + wrap_format = workbook.add_format({'text_wrap': True}) + bold_wrap_format = workbook.add_format({'text_wrap': True, 'bold': True}) + wrap_unlocked_format = workbook.add_format({'text_wrap': True, 'locked': False}) + + for lang in langs: + data = per_lang_data[lang] + num_translations = len(data) + cols = ["EN", "Previous Translation ({})".format(lang.upper()), "ENTER NEW TRANSLATION ({})".format(lang.upper()), "Translator Questions", "Notes", "File", "Element", "Field"] + df = pd.DataFrame(data, columns=cols) + df.to_excel(writer, index=False, sheet_name = lang.upper()) + + worksheet = writer.sheets[lang.upper()] + + # Translators primarily care about columns A-C, and should write + # only in column C. Hide the others. Set widths. + worksheet.protect() + worksheet.set_column('A:B', 60, wrap_format) + worksheet.set_column('C:C', 60, wrap_unlocked_format) + worksheet.set_column('D:E', 40, wrap_unlocked_format) + worksheet.set_column('F:F', 50, wrap_format, {'hidden': True}) + worksheet.set_column('G:H', 30, wrap_format, {'hidden': True}) + + # Lock the top row (column headers) in place while scrolling + worksheet.freeze_panes(1, 0) + print("Added", num_translations, "rows for language", lang) + + # Reference info, not for translation + for aux, data in aux_data.items(): + df = pd.DataFrame(data, columns = ["Key", "Value"]) + df.to_excel(writer, index=False, sheet_name=aux) + worksheet = writer.sheets[aux] + worksheet.set_column('A:A', 50, bold_wrap_format) + worksheet.set_column('B:B', 80, wrap_format) + + print("Writing", outfile) + writer.save() + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description="analyze viewer xui files for needed translations", usage=usage_msg) + parser.add_argument("-v","--verbose", action="store_true", help="verbose flag") + parser.add_argument("--missing", action="store_true", default = False, help="include all fields for which a translation does not exist") + parser.add_argument("--deleted", action="store_true", default = False, help="show all translated entities which don't exist in english") + parser.add_argument("--skip_spreadsheet", action="store_true", default = False, help="skip creating the translation spreadsheet") + parser.add_argument("--rev", help="revision with modified strings, default HEAD", default="HEAD") + parser.add_argument("--rev_base", help="previous revision to compare against, default master", default="master") + parser.add_argument("--base_lang", help="base language, default en (normally leave unchanged - other values are only useful for testing)", default="en") + parser.add_argument("--lang", help="target languages, or 'all_valid' or 'supported'; default is 'supported'", nargs="+", default = ["supported"]) + args = parser.parse_args() + + cwd = os.getcwd() + rootdir = Git(cwd).rev_parse("--show-toplevel") + repo = Repo(rootdir) + try: + mod_commit = repo.commit(args.rev) + except: + failure(args.rev,"is not a valid commit") + try: + base_commit = repo.commit(args.rev_base) + except: + failure(args.rev_base,"is not a valid commit") + + print("Will identify changes in", args.rev, "not present in", args.rev_base) + if args.missing: + print("Will also include any text for which no corresponding translation exists, regardless of when it was added") + sys.stdout.flush() + + mod_tree = mod_commit.tree + base_tree = base_commit.tree + + xui_base = "indra/newview/skins/default/xui" + xui_base_tree = mod_tree[xui_base] + + # Find target languages + # all languages present in the codebase + valid_langs = [tree.name.lower() for tree in xui_base_tree if tree.name.lower() != args.base_lang.lower()] + # offically supported languages + supported_langs = ["fr", "es", "it", "pt", "ja", "de"] + langs = [l.lower() for l in args.lang] + if "supported" in args.lang: + langs = supported_langs + if "all_valid" in args.lang: + langs = valid_langs + langs = sorted(langs) + for lang in langs: + if not lang in valid_langs: + failure("Unknown target language {}. Valid values are {}".format(lang,", ".join(sorted(valid_langs) + ["all_valid","supported"]))) + print("Target language(s) are", ",".join(sorted(langs))) + sys.stdout.flush() + + outfile = "SL_Translations.xlsx" + try: + f = open(outfile,"a+") + f.close() + except: + failure("Can't write to output file",outfile,". Is it already open?") + + aux_data = { "REFERENCE": [["Command", " ".join(sys.argv)], + ["Date", str(datetime.now())], + ["Mod Commit", mod_commit.hexsha], + ["Base Commit", base_commit.hexsha], + ] } + + if not args.skip_spreadsheet: + per_lang_data = {} + for lang in langs: + print("Creating spreadsheet for language", lang) + sys.stdout.flush() + + per_lang_data[lang] = make_translation_table(mod_tree, base_tree, lang, args) + + print("Saving output file", outfile) + save_translation_file(per_lang_data, aux_data, outfile) + + if args.deleted: + deletion_file = "Translate_deletions.txt" + print("Saving deletion info to", deletion_file) + with open(deletion_file,"w") as f: + for lang in langs: + find_deletions(mod_tree, base_tree, lang, args, f) + diff --git a/scripts/content_tools/arche_tool.py b/scripts/content_tools/arche_tool.py index 23c96fc64e..f99d7be39a 100644 --- a/scripts/content_tools/arche_tool.py +++ b/scripts/content_tools/arche_tool.py @@ -79,15 +79,32 @@ def compare_trees(file_trees): print "Summary:" print summary - +def dump_appearance_params(tree): + vals = [] + for e in tree.getroot().iter(): + if e.tag == "param": + g = int(e.get("group")) + if g in [0,3]: + vals.append("{" + e.get("id") + "," +e.get("u8") + "}") + #print e.get("id"), e.get("name"), e.get("group"), e.get("u8") + if len(vals)==253: + print ", ".join(vals) + + if __name__ == "__main__": parser = argparse.ArgumentParser(description="compare avatar XML archetype files") parser.add_argument("--verbose", help="verbose flag", action="store_true") + parser.add_argument("--compare", help="compare flag", action="store_true") + parser.add_argument("--appearance_params", help="compare flag", action="store_true") parser.add_argument("files", nargs="+", help="name of one or more archtype files") args = parser.parse_args() print "files",args.files file_trees = [etree.parse(filename) for filename in args.files] - compare_trees(file_trees) + print args + if args.compare: + compare_trees(file_trees) + if args.appearance_params: + dump_appearance_params(file_trees[0]) diff --git a/scripts/messages/message_template.msg b/scripts/messages/message_template.msg index 18264ee59c..635227ccf3 100755 --- a/scripts/messages/message_template.msg +++ b/scripts/messages/message_template.msg @@ -6,7 +6,7 @@ version 2.0 // numbers. Each message must be numbered relative to the // other messages of that type. The current highest number // for each type is listed below: -// Low: 423 +// Low: 430 // Medium: 18 // High: 30 // PLEASE UPDATE THIS WHEN YOU ADD A NEW MESSAGE! @@ -4502,6 +4502,11 @@ version 2.0 RegionAllowAccessBlock Single { RegionAllowAccessOverride BOOL } } + { + ParcelEnvironmentBlock Single + { ParcelEnvironmentVersion S32 } + { RegionAllowEnvironmentOverride BOOL } + } } // ParcelPropertiesUpdate @@ -5775,6 +5780,28 @@ version 2.0 } } +// LargeGenericMessage +// Similar to the above messages, but can handle larger payloads and serialized +// LLSD. Uses HTTP transport +{ + LargeGenericMessage Low 430 NotTrusted Unencoded UDPDeprecated + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { TransactionID LLUUID } + } + { + MethodData Single + { Method Variable 1 } + { Invoice LLUUID } + } + { + ParamList Variable + { Parameter Variable 2 } + } +} + // *************************************************************************** // Requests for possessions, acquisition, money, etc // *************************************************************************** diff --git a/scripts/messages/message_template.msg.sha1 b/scripts/messages/message_template.msg.sha1 index db87ad5e77..bf45b08f93 100755 --- a/scripts/messages/message_template.msg.sha1 +++ b/scripts/messages/message_template.msg.sha1 @@ -1 +1 @@ -55df2c7135733c5da64ef8f01859b83a433a3a09
\ No newline at end of file +be964beb7a2cd060a438c89fd5cb25e2f687d45e
\ No newline at end of file diff --git a/scripts/metrics/viewerstats.py b/scripts/metrics/viewerstats.py new file mode 100755 index 0000000000..f7be3d967e --- /dev/null +++ b/scripts/metrics/viewerstats.py @@ -0,0 +1,226 @@ +#!runpy.sh + +"""\ + +This module contains code for analyzing ViewerStats data as uploaded by the viewer. + +$LicenseInfo:firstyear=2021&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2021, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +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 argparse +import numpy as np +import pandas as pd +import json +from collections import Counter, defaultdict +from llbase import llsd +import io +import re +import os +import sys + +def show_stats_by_key(recs,indices,settings_sd = None): + result = () + cnt = Counter() + per_key_cnt = defaultdict(Counter) + for r in recs: + try: + d = r + for idx in indices: + d = d[idx] + for k,v in d.items(): + if isinstance(v,dict): + continue + cnt[k] += 1 + if isinstance(v,list): + v = tuple(v) + per_key_cnt[k][v] += 1 + except Exception as e: + print "err", e + print "d", d, "k", k, "v", v + raise + mc = cnt.most_common() + print "=========================" + keyprefix = "" + if len(indices)>0: + keyprefix = ".".join(indices) + "." + for i,m in enumerate(mc): + k = m[0] + bigc = m[1] + unset_cnt = len(recs) - bigc + kmc = per_key_cnt[k].most_common(5) + print i, keyprefix+str(k), bigc + if settings_sd is not None and k in settings_sd and "Value" in settings_sd[k]: + print " ", "default",settings_sd[k]["Value"],"count",unset_cnt + for v in kmc: + print " ", "value",v[0],"count",v[1] + if settings_sd is not None: + print "Total keys in settings", len(settings_sd.keys()) + unused_keys = list(set(settings_sd.keys()) - set(cnt.keys())) + unused_keys_non_str = [k for k in unused_keys if settings_sd[k]["Type"] != "String"] + unused_keys_str = [k for k in unused_keys if settings_sd[k]["Type"] == "String"] + + # Things that no one in the sample has set to a non-default value. Possible candidates for removal. + print "\nUnused_keys_non_str", len(unused_keys_non_str) + print "======================" + print "\n".join(sorted(unused_keys_non_str)) + + # Strings are not currently logged, so we have no info on usage. + print "\nString keys (usage unknown)", len(unused_keys_str) + print "======================" + print "\n".join(sorted(unused_keys_str)) + + # Things that someone has set but that aren't recognized settings. + unrec_keys = list(set(cnt.keys()) - set(settings_sd.keys())) + print "\nUnrecognized keys", len(unrec_keys) + print "======================" + print "\n".join(sorted(unrec_keys)) + + result = (settings_sd.keys(), unused_keys_str, unused_keys_non_str, unrec_keys) + return result + +def parse_settings_xml(fname): + # assume we're in scripts/metrics + fname = "../../indra/newview/app_settings/" + fname + with open(fname,"r") as f: + contents = f.read() + return llsd.parse_xml(contents) + +def read_raw_settings_xml(fname): + # assume we're in scripts/metrics + fname = "../../indra/newview/app_settings/" + fname + contents = None + with open(fname,"r") as f: + contents = f.read() + return contents + +def write_settings_xml(fname, contents): + # assume we're in scripts/metrics + fname = "../../indra/newview/app_settings/" + fname + with open(fname,"w") as f: + f.write(llsd.format_pretty_xml(contents)) + f.close() + +def write_raw_settings_xml(fname, string): + # assume we're in scripts/metrics + fname = "../../indra/newview/app_settings/" + fname + with io.open(fname,"w", newline='\n') as f: + f.write(string.decode('latin1')) + f.close() + +def remove_settings(string, to_remove): + for r in to_remove: + subs_str = r"<key>" + r + r"<.*?</map>\n" + string = re.sub(subs_str,"",string,flags=re.S|re.DOTALL) + return string + +def get_used_strings(root_dir): + used_str = set() + skipped_ext = set() + for dir_name, sub_dir_list, file_list in os.walk(root_dir): + for fname in file_list: + if fname in ["settings.xml", "settings.xml.edit", "settings_per_account.xml"]: + print "skip", fname + continue + (base,ext) = os.path.splitext(fname) + #if ext not in [".cpp", ".hpp", ".h", ".xml"]: + # skipped_ext.add(ext) + # continue + + full_name = os.path.join(dir_name,fname) + + with open(full_name,"r") as f: + #print full_name + lines = f.readlines() + for l in lines: + ms = re.findall(r'[>\"]([A-Za-z0-9_]+)[\"<]',l) + for m in ms: + #print "used_str",m + used_str.add(m) + print "skipped extensions", skipped_ext + print "got used_str", len(used_str) + return used_str + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description="process tab-separated table containing viewerstats logs") + parser.add_argument("--verbose", action="store_true",help="verbose flag") + parser.add_argument("--preferences", action="store_true", help="analyze preference info") + parser.add_argument("--remove_unused", action="store_true", help="remove unused preferences") + parser.add_argument("--column", help="name of column containing viewerstats info") + parser.add_argument("infiles", nargs="+", help="name of .tsv files to process") + args = parser.parse_args() + + for fname in args.infiles: + print "process", fname + df = pd.read_csv(fname,sep='\t') + #print "DF", df.describe() + jstrs = df['RAW_LOG:BODY'] + #print "JSTRS", jstrs.describe() + recs = [] + for i,jstr in enumerate(jstrs): + recs.append(json.loads(jstr)) + show_stats_by_key(recs,[]) + show_stats_by_key(recs,["agent"]) + if args.preferences: + print "\nSETTINGS.XML" + settings_sd = parse_settings_xml("settings.xml") + #for skey,svals in settings_sd.items(): + # print skey, "=>", svals + (all_str,_,_,_) = show_stats_by_key(recs,["preferences","settings"],settings_sd) + print + + #print "\nSETTINGS_PER_ACCOUNT.XML" + #settings_pa_sd = parse_settings_xml("settings_per_account.xml") + #show_stats_by_key(recs,["preferences","settings_per_account"],settings_pa_sd) + + if args.remove_unused: + # walk codebase looking for strings + all_str_set = set(all_str) + used_strings = get_used_strings("../../indra") + used_strings_set = set(used_strings) + unref_strings = all_str_set-used_strings_set + # Some settings names are generated by appending to a prefix. Need to look for this case. + prefix_used = set() + print "checking unref_strings", len(unref_strings) + for u in unref_strings: + for k in range(6,len(u)): + prefix = u[0:k] + if prefix in all_str_set and prefix in used_strings_set: + prefix_used.add(u) + #print "PREFIX_USED",u,prefix + print "PREFIX_USED", len(prefix_used), ",".join(list(prefix_used)) + print + unref_strings = unref_strings - prefix_used + + print "\nUNREF_IN_CODE " + str(len(unref_strings)) + "\n" + print "\n".join(list(unref_strings)) + settings_str = read_raw_settings_xml("settings.xml") + # Do this via direct string munging to generate minimal changeset + settings_edited = remove_settings(settings_str,unref_strings) + write_raw_settings_xml("settings.xml.edit",settings_edited) + + + + + + |