Pull and merge from ssh://hg@bitbucket.org/lindenlab/viewer-release.
commit
4feef5af63
|
|
@ -25,6 +25,7 @@ indra/lib/mono/indra/*.exe
|
|||
indra/lib/mono/indra/*.pdb
|
||||
indra/lib/python/eventlet/
|
||||
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
|
||||
|
|
|
|||
27
.hgtags
27
.hgtags
|
|
@ -264,6 +264,7 @@ c6175c955a19e9b9353d242889ec1779b5762522 3.2.5-release
|
|||
16f8e2915f3f2e4d732fb3125daf229cb0fd1875 DRTVWR-114_3.2.8-beta1
|
||||
37dd400ad721e2a89ee820ffc1e7e433c68f3ca2 3.2.9-start
|
||||
16f8e2915f3f2e4d732fb3125daf229cb0fd1875 3.2.8-beta1
|
||||
089e5c84b2dece68f2b016c842ef9b5de4786842 DRTVWR-161
|
||||
987425b1acf4752379b2e1eb20944b4b35d67a85 DRTVWR-115_3.2.8-beta2
|
||||
987425b1acf4752379b2e1eb20944b4b35d67a85 3.2.8-beta2
|
||||
51b2fd52e36aab8f670e0874e7e1472434ec4b4a DRTVWR-113_3.2.8-release
|
||||
|
|
@ -286,6 +287,9 @@ d5f263687f43f278107363365938f0a214920a4b 3.3.0-beta1
|
|||
28b95a6a28dca3338d9a1f4f204b96678df9f6a5 viewer-beta-candidate
|
||||
b43cd25be49e3984ff5361cefad020e069131d98 3.3.1-start
|
||||
3e2fca4ed1a0dc9fe6d8a6664e71098bb035a367 DRTVWR-125
|
||||
dffd0457ee0745de65bf95f0642a5c9e46b8e2f0 viewer-beta-candidate
|
||||
3e2fca4ed1a0dc9fe6d8a6664e71098bb035a367 viewer-beta-candidate
|
||||
3e2fca4ed1a0dc9fe6d8a6664e71098bb035a367 viewer-beta-candidate
|
||||
3e2fca4ed1a0dc9fe6d8a6664e71098bb035a367 3.3.1-start
|
||||
28b95a6a28dca3338d9a1f4f204b96678df9f6a5 3.3.1-beta1
|
||||
1dc545e44617975da2a4a32fe303386c687a6ca1 viewer-beta-candidate
|
||||
|
|
@ -300,7 +304,13 @@ c623bbc854b6f7ee1b33a3718f76715046aa2937 viewer-release-candidate
|
|||
675668bd24d3bea570814f71762a2a806f7e1b8d viewer-release-candidate
|
||||
675668bd24d3bea570814f71762a2a806f7e1b8d 3.3.2-release
|
||||
675668bd24d3bea570814f71762a2a806f7e1b8d viewer-release-candidate
|
||||
050e48759337249130f684b4a21080b683f61732 DRTVWR-168
|
||||
b9d0170b62eb1c7c3adaa37a0b13a833e5e659f9 DRTVWR-171
|
||||
c08e2ac17a99973b2a94477659220b99b8847ae2 DRTVWR-163
|
||||
600f3b3920d94de805ac6dc8bb6def9c069dd360 DRTVWR-162
|
||||
600f3b3920d94de805ac6dc8bb6def9c069dd360 DRTVWR-162
|
||||
9a78ac13f047056f788c4734dd91aebfe30970e3 DRTVWR-157
|
||||
a716684aa7c07c440b1de5815b8a1f3dd3fd8bfb DRTVWR-159
|
||||
24a7281bef42bd4430ceb25db8b195449c2c7de3 DRTVWR-153
|
||||
15e90b52dc0297921b022b90d10d797436b8a1bd viewer-release-candidate
|
||||
6414ecdabc5d89515b08d1f872cf923ed3a5523a DRTVWR-148
|
||||
|
|
@ -317,3 +327,20 @@ fdcc08a4f20ae9bb060f4693c8980d216534efdf 3.3.3-beta2
|
|||
af5f3e43e6e4424b1da19d9e16f6b853a7b822ed DRTVWR-169
|
||||
4b3c68199a86cabaa5d9466d7b0f7e141e901d7a 3.3.3-beta3
|
||||
6428242e124b523813bfaf4c45b3d422f0298c81 3.3.3-release
|
||||
57d221de3df94f90b55204313c2cef044a3c0ae2 DRTVWR-176
|
||||
09ef7fd1b0781f33b8a3a9af6236b7bcb4831910 DRTVWR-170
|
||||
f87bfbe0b62d26f451d02a47c80ebef6b9168fc2 3.3.4-beta1
|
||||
f87bfbe0b62d26f451d02a47c80ebef6b9168fc2 DRTVWR-158
|
||||
f87bfbe0b62d26f451d02a47c80ebef6b9168fc2 3.3.4-beta1
|
||||
cbea6356ce9cb0c313b6777f10c5c14783264fcc DRTVWR-174
|
||||
bce218b2b45b730b22cc51e4807aa8b571cadef3 DRTVWR-173
|
||||
f91d003091a61937a044652c4c674447f7dcbb7a 3.3.4-beta1
|
||||
82b5330bc8b17d0d4b598832e9c5a92e90075682 3.3.4-beta2
|
||||
eb539c65e6ee26eea2bf373af2d0f4b52dc91289 DRTVWR-177
|
||||
a8057e1b9a1246b434a27405be35e030f7d28b0c 3.3.4-beta3
|
||||
4281aa899fb2cedb7a9ca7ce91c5c29d4aa69594 DRTVWR-180
|
||||
9cd174d3a54d93d409a7c346a15b8bfb40fc58f4 DRTVWR-184
|
||||
5c08e1d8edd871807153603b690e3ee9dbb548aa DRTVWR-183
|
||||
6c75f220b103db1420919c8b635fe53e2177f318 3.3.4-beta4
|
||||
ab2ffc547c8a8950ff187c4f6c95e5334fab597b 3.3.4-beta5
|
||||
28e100d0379a2b0710c57647a28fc5239d3d7b99 3.3.4-release
|
||||
|
|
|
|||
61
BuildParams
61
BuildParams
|
|
@ -36,6 +36,26 @@ viewer-development.build_debug_release_separately = true
|
|||
# <username>_<reponame>.email = <email-address>
|
||||
|
||||
|
||||
# =================================================================
|
||||
# Canonical viewer integration builds - Oz Linden
|
||||
# =================================================================
|
||||
integration_viewer-development.viewer_channel = "Second Life Development"
|
||||
integration_viewer-development.login_channel = "Second Life Development"
|
||||
integration_viewer-development.build_viewer_update_version_manager = false
|
||||
integration_viewer-development.email = viewer-development-builds@lists.secondlife.com
|
||||
integration_viewer-development.build_enforce_coding_policy = true
|
||||
integration_viewer-development.codeticket_add_context = true
|
||||
|
||||
viewer-beta.viewer_channel = "Second Life Beta Viewer"
|
||||
viewer-beta.login_channel = "Second Life Beta Viewer"
|
||||
viewer-beta.build_debug_release_separately = true
|
||||
viewer-beta.build_viewer_update_version_manager = true
|
||||
|
||||
viewer-release.viewer_channel = "Second Life Release"
|
||||
viewer-release.login_channel = "Second Life Release"
|
||||
viewer-release.build_debug_release_separately = true
|
||||
viewer-release.build_viewer_update_version_manager = true
|
||||
|
||||
# ========================================
|
||||
# mesh-development
|
||||
# ========================================
|
||||
|
|
@ -92,6 +112,17 @@ viewer-mesh.login_channel = "Project Viewer - Mesh"
|
|||
viewer-mesh.viewer_grid = aditi
|
||||
viewer-mesh.email = shining@lists.lindenlab.com
|
||||
|
||||
# ========================================
|
||||
# viewer-adult-check
|
||||
# ========================================
|
||||
|
||||
viewer-adult-check.viewer_channel = "Project Viewer - AdultCheck"
|
||||
viewer-adult-check.login_channel = "Project Viewer - AdultCheck"
|
||||
viewer-adult-check.viewer_grid = agni
|
||||
viewer-adult-check.build_debug_release_separately = true
|
||||
viewer-adult-check.build_CYGWIN_Debug = false
|
||||
viewer-adult-check.build_viewer_update_version_manager = false
|
||||
|
||||
# ========================================
|
||||
# viewer-pathfinding
|
||||
# ========================================
|
||||
|
|
@ -103,6 +134,36 @@ viewer-pathfinding.build_debug_release_separately = true
|
|||
viewer-pathfinding.build_CYGWIN_Debug = false
|
||||
viewer-pathfinding.build_viewer_update_version_manager = false
|
||||
|
||||
# ================
|
||||
# oz
|
||||
# ================
|
||||
|
||||
Snowstorm_viewer-project-review.build_debug_release_separately = true
|
||||
Snowstorm_viewer-project-review.codeticket_add_context = true
|
||||
Snowstorm_viewer-project-review.viewer_channel = "Project Viewer - Snowstorm Team"
|
||||
Snowstorm_viewer-project-review.login_channel = "Project Viewer - Snowstorm Team"
|
||||
Snowstorm_viewer-project-review.codeticket_add_context = true
|
||||
|
||||
oz_viewer-devreview.build_debug_release_separately = true
|
||||
oz_viewer-devreview.codeticket_add_context = false
|
||||
oz_viewer-devreview.build_enforce_coding_policy = true
|
||||
oz_viewer-devreview.email = oz@lindenlab.com
|
||||
|
||||
oz_viewer-trial.build_debug_release_separately = true
|
||||
oz_viewer-trial.codeticket_add_context = false
|
||||
oz_viewer-trial.build_enforce_coding_policy = true
|
||||
oz_viewer-trial.email = oz@lindenlab.com
|
||||
|
||||
oz_viewer-beta-review.build_debug_release_separately = true
|
||||
oz_viewer-beta-review.codeticket_add_context = false
|
||||
oz_viewer-beta-review.viewer_channel = "Second Life Beta Viewer"
|
||||
oz_viewer-beta-review.login_channel = "Second Life Beta Viewer"
|
||||
oz_viewer-beta-review.email = oz@lindenlab.com
|
||||
|
||||
oz_project-7.build_debug_release_separately = true
|
||||
oz_project-7.codeticket_add_context = false
|
||||
oz_project-7.email = "sldev@catznip.com oz@lindenlab.com"
|
||||
|
||||
# =================================================================
|
||||
# asset delivery 2010 projects
|
||||
# =================================================================
|
||||
|
|
|
|||
104
autobuild.xml
104
autobuild.xml
|
|
@ -363,6 +363,54 @@
|
|||
</map>
|
||||
</map>
|
||||
</map>
|
||||
<key>dictionaries</key>
|
||||
<map>
|
||||
<key>license</key>
|
||||
<string>various open</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/dictionaries.txt</string>
|
||||
<key>name</key>
|
||||
<string>dictionaries</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>06a6c49eb1873e95623d3d2d07aee903</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-dictionaries/rev/259873/arch/Darwin/installer/dictionaries-1-darwin-20120616.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin</string>
|
||||
</map>
|
||||
<key>linux</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>4f0ca21d27e0cd0b002149062b0a4b25</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-dictionaries/rev/259873/arch/Linux/installer/dictionaries-1-linux-20120616.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux</string>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>7520d75f6af325328322201c888191d4</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-dictionaries/rev/259873/arch/CYGWIN/installer/dictionaries-1-windows-20120616.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
</map>
|
||||
</map>
|
||||
<key>elfio</key>
|
||||
<map>
|
||||
<key>license</key>
|
||||
|
|
@ -1047,6 +1095,54 @@
|
|||
</map>
|
||||
</map>
|
||||
</map>
|
||||
<key>libhunspell</key>
|
||||
<map>
|
||||
<key>license</key>
|
||||
<string>libhunspell</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/hunspell.txt</string>
|
||||
<key>name</key>
|
||||
<string>libhunspell</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>6f5db0ef258df6e5c93c843ec559db6d</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-hunspell/rev/259874/arch/Darwin/installer/libhunspell-1.3.2-darwin-20120616.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin</string>
|
||||
</map>
|
||||
<key>linux</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>0c432d2626aea2e91a56335879c92965</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-hunspell/rev/259874/arch/Linux/installer/libhunspell-1.3.2-linux-20120616.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux</string>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>6a140e5620826aa5e587b4157f57b389</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-hunspell/rev/259874/arch/CYGWIN/installer/libhunspell-1.3.2-windows-20120616.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
</map>
|
||||
</map>
|
||||
<key>libpng</key>
|
||||
<map>
|
||||
<key>license</key>
|
||||
|
|
@ -1818,8 +1914,12 @@
|
|||
</map>
|
||||
<key>package_description</key>
|
||||
<map>
|
||||
<key>description</key>
|
||||
<string>Spell checking dictionaries</string>
|
||||
<key>license</key>
|
||||
<string>various open</string>
|
||||
<key>name</key>
|
||||
<string>viewer_development</string>
|
||||
<string>dictionaries</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>common</key>
|
||||
|
|
@ -2529,6 +2629,8 @@
|
|||
<string>windows</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>1.0</string>
|
||||
</map>
|
||||
<key>type</key>
|
||||
<string>autobuild</string>
|
||||
|
|
|
|||
21
build.sh
21
build.sh
|
|
@ -15,6 +15,12 @@
|
|||
# * The basic convention is that the build name can be mapped onto a mercurial URL,
|
||||
# which is also used as the "branch" name.
|
||||
|
||||
check_for()
|
||||
{
|
||||
if [ -e "$2" ]; then found_dict='FOUND'; else found_dict='MISSING'; fi
|
||||
echo "$1 ${found_dict} '$2' " 1>&2
|
||||
}
|
||||
|
||||
build_dir_Darwin()
|
||||
{
|
||||
echo build-darwin-i386
|
||||
|
|
@ -59,6 +65,8 @@ pre_build()
|
|||
&& [ -r "$master_message_template_checkout/message_template.msg" ] \
|
||||
&& template_verifier_master_url="-DTEMPLATE_VERIFIER_MASTER_URL=file://$master_message_template_checkout/message_template.msg"
|
||||
|
||||
check_for "Before 'autobuild configure'" ${build_dir}/packages/dictionaries
|
||||
|
||||
"$AUTOBUILD" configure -c $variant -- \
|
||||
-DPACKAGE:BOOL=ON \
|
||||
-DRELEASE_CRASH_REPORTING:BOOL=ON \
|
||||
|
|
@ -67,7 +75,10 @@ pre_build()
|
|||
-DGRID:STRING="\"$viewer_grid\"" \
|
||||
-DLL_TESTS:BOOL="$run_tests" \
|
||||
-DTEMPLATE_VERIFIER_OPTIONS:STRING="$template_verifier_options" $template_verifier_master_url
|
||||
end_section "Pre$variant"
|
||||
|
||||
check_for "After 'autobuild configure'" ${build_dir}/packages/dictionaries
|
||||
|
||||
end_section "Pre$variant"
|
||||
}
|
||||
|
||||
build()
|
||||
|
|
@ -76,12 +87,17 @@ build()
|
|||
if $build_viewer
|
||||
then
|
||||
begin_section "Viewer$variant"
|
||||
|
||||
check_for "Before 'autobuild build'" ${build_dir}/packages/dictionaries
|
||||
|
||||
if "$AUTOBUILD" build --no-configure -c $variant
|
||||
then
|
||||
echo true >"$build_dir"/build_ok
|
||||
else
|
||||
echo false >"$build_dir"/build_ok
|
||||
fi
|
||||
check_for "After 'autobuild configure'" ${build_dir}/packages/dictionaries
|
||||
|
||||
end_section "Viewer$variant"
|
||||
fi
|
||||
}
|
||||
|
|
@ -172,7 +188,10 @@ eval "$("$AUTOBUILD" source_environment)"
|
|||
# dump environment variables for debugging
|
||||
env|sort
|
||||
|
||||
check_for "Before 'autobuild install'" ${build_dir}/packages/dictionaries
|
||||
|
||||
|
||||
check_for "After 'autobuild install'" ${build_dir}/packages/dictionaries
|
||||
# Now run the build
|
||||
succeeded=true
|
||||
build_processes=
|
||||
|
|
|
|||
|
|
@ -297,6 +297,8 @@ Cherry Cheevers
|
|||
ChickyBabes Zuzu
|
||||
Christopher Organiser
|
||||
Ciaran Laval
|
||||
Cinder Roxley
|
||||
STORM-1703
|
||||
Clara Young
|
||||
Coaldust Numbers
|
||||
VWR-1095
|
||||
|
|
@ -471,6 +473,7 @@ Hiro Sommambulist
|
|||
VWR-143
|
||||
Hitomi Tiponi
|
||||
STORM-1741
|
||||
STORM-1862
|
||||
Holger Gilruth
|
||||
Horatio Freund
|
||||
Hoze Menges
|
||||
|
|
@ -623,12 +626,22 @@ Jonathan Yap
|
|||
STORM-1799
|
||||
STORM-1796
|
||||
STORM-1807
|
||||
STORM-1812
|
||||
STORM-1820
|
||||
STORM-1839
|
||||
STORM-1842
|
||||
STORM-1808
|
||||
STORM-637
|
||||
STORM-1822
|
||||
STORM-1809
|
||||
STORM-1793
|
||||
STORM-1810
|
||||
STORM-1860
|
||||
STORM-1852
|
||||
STORM-1870
|
||||
STORM-1872
|
||||
STORM-1858
|
||||
STORM-1862
|
||||
Kadah Coba
|
||||
STORM-1060
|
||||
Jondan Lundquist
|
||||
|
|
@ -725,6 +738,8 @@ Marc2 Sands
|
|||
Marianne McCann
|
||||
Marine Kelley
|
||||
STORM-281
|
||||
MartinRJ Fayray
|
||||
STORM-1845
|
||||
Matthew Anthony
|
||||
Matthew Dowd
|
||||
VWR-1344
|
||||
|
|
@ -1052,6 +1067,8 @@ Simon Nolan
|
|||
Sini Nubalo
|
||||
Sitearm Madonna
|
||||
SLB Wirefly
|
||||
Slee Mayo
|
||||
SEC-1075
|
||||
snowy Sidran
|
||||
SpacedOut Frye
|
||||
VWR-34
|
||||
|
|
@ -1287,6 +1304,7 @@ Zi Ree
|
|||
VWR-24017
|
||||
VWR-25588
|
||||
STORM-1790
|
||||
STORM-1842
|
||||
Zipherius Turas
|
||||
VWR-76
|
||||
VWR-77
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ set(cmake_SOURCE_FILES
|
|||
GLOD.cmake
|
||||
GStreamer010Plugin.cmake
|
||||
GooglePerfTools.cmake
|
||||
Hunspell.cmake
|
||||
JPEG.cmake
|
||||
LLAddBuildTest.cmake
|
||||
LLAudio.cmake
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ if(WINDOWS)
|
|||
libeay32.dll
|
||||
libcollada14dom22-d.dll
|
||||
glod.dll
|
||||
libhunspell.dll
|
||||
)
|
||||
|
||||
set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
|
||||
|
|
@ -53,6 +54,7 @@ if(WINDOWS)
|
|||
libeay32.dll
|
||||
libcollada14dom22.dll
|
||||
glod.dll
|
||||
libhunspell.dll
|
||||
)
|
||||
|
||||
if(USE_GOOGLE_PERFTOOLS)
|
||||
|
|
@ -212,11 +214,12 @@ elseif(DARWIN)
|
|||
libexpat.1.5.2.dylib
|
||||
libexpat.dylib
|
||||
libGLOD.dylib
|
||||
libllqtwebkit.dylib
|
||||
libminizip.a
|
||||
libllqtwebkit.dylib
|
||||
libminizip.a
|
||||
libndofdev.dylib
|
||||
libhunspell-1.3.0.dylib
|
||||
libexception_handler.dylib
|
||||
libcollada14dom.dylib
|
||||
libcollada14dom.dylib
|
||||
)
|
||||
|
||||
# fmod is statically linked on darwin
|
||||
|
|
@ -257,14 +260,15 @@ elseif(LINUX)
|
|||
libdb-5.1.so
|
||||
libexpat.so
|
||||
libexpat.so.1
|
||||
libglod.so
|
||||
libglod.so
|
||||
libgmock_main.so
|
||||
libgmock.so.0
|
||||
libgmodule-2.0.so
|
||||
libgobject-2.0.so
|
||||
libgtest_main.so
|
||||
libgtest.so.0
|
||||
libminizip.so
|
||||
libhunspell-1.3.so.0.0.0
|
||||
libminizip.so
|
||||
libopenal.so
|
||||
libopenjpeg.so
|
||||
libssl.so
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
# -*- cmake -*-
|
||||
|
||||
# - Find HUNSPELL
|
||||
# This module defines
|
||||
# HUNSPELL_INCLUDE_DIR, where to find libhunspell.h, etc.
|
||||
# HUNSPELL_LIBRARY, the library needed to use HUNSPELL.
|
||||
# HUNSPELL_FOUND, If false, do not try to use HUNSPELL.
|
||||
|
||||
find_path(HUNSPELL_INCLUDE_DIR hunspell.h
|
||||
PATH_SUFFIXES hunspell
|
||||
)
|
||||
|
||||
set(HUNSPELL_NAMES ${HUNSPELL_NAMES} libhunspell-1.3.0 libhunspell)
|
||||
find_library(HUNSPELL_LIBRARY
|
||||
NAMES ${HUNSPELL_NAMES}
|
||||
)
|
||||
|
||||
if (HUNSPELL_LIBRARY AND HUNSPELL_INCLUDE_DIR)
|
||||
set(HUNSPELL_FOUND "YES")
|
||||
else (HUNSPELL_LIBRARY AND HUNSPELL_INCLUDE_DIR)
|
||||
set(HUNSPELL_FOUND "NO")
|
||||
endif (HUNSPELL_LIBRARY AND HUNSPELL_INCLUDE_DIR)
|
||||
|
||||
|
||||
if (HUNSPELL_FOUND)
|
||||
if (NOT HUNSPELL_FIND_QUIETLY)
|
||||
message(STATUS "Found Hunspell: Library in '${HUNSPELL_LIBRARY}' and header in '${HUNSPELL_INCLUDE_DIR}' ")
|
||||
endif (NOT HUNSPELL_FIND_QUIETLY)
|
||||
else (HUNSPELL_FOUND)
|
||||
if (HUNSPELL_FIND_REQUIRED)
|
||||
message(FATAL_ERROR " * * *\nCould not find HUNSPELL library! * * *")
|
||||
endif (HUNSPELL_FIND_REQUIRED)
|
||||
endif (HUNSPELL_FOUND)
|
||||
|
||||
mark_as_advanced(
|
||||
HUNSPELL_LIBRARY
|
||||
HUNSPELL_INCLUDE_DIR
|
||||
)
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
|
||||
set(HUNSPELL_FIND_QUIETLY ON)
|
||||
set(HUNSPELL_FIND_REQUIRED ON)
|
||||
|
||||
if (STANDALONE)
|
||||
include(FindHUNSPELL)
|
||||
else (STANDALONE)
|
||||
use_prebuilt_binary(libhunspell)
|
||||
if (WINDOWS)
|
||||
set(HUNSPELL_LIBRARY libhunspell)
|
||||
elseif(DARWIN)
|
||||
set(HUNSPELL_LIBRARY hunspell-1.3.0)
|
||||
elseif(LINUX)
|
||||
set(HUNSPELL_LIBRARY hunspell-1.3)
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid platform")
|
||||
endif()
|
||||
set(HUNSPELL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/hunspell)
|
||||
use_prebuilt_binary(dictionaries)
|
||||
endif (STANDALONE)
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
include(Prebuilt)
|
||||
|
||||
if (NOT STANDALONE)
|
||||
use_prebuilt_binary(libhunspell)
|
||||
use_prebuilt_binary(libuuid)
|
||||
use_prebuilt_binary(slvoice)
|
||||
use_prebuilt_binary(fontconfig)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ include(LLWindow)
|
|||
include(LLUI)
|
||||
include(LLVFS) # ugh, needed for LLDir
|
||||
include(LLXML)
|
||||
include(Hunspell)
|
||||
include(Linking)
|
||||
# include(Tut)
|
||||
|
||||
|
|
@ -31,6 +32,7 @@ include_directories(
|
|||
${LLVFS_INCLUDE_DIRS}
|
||||
${LLWINDOW_INCLUDE_DIRS}
|
||||
${LLXML_INCLUDE_DIRS}
|
||||
${LIBS_PREBUILD_DIR}/include/hunspell
|
||||
)
|
||||
|
||||
set(llui_libtest_SOURCE_FILES
|
||||
|
|
@ -78,6 +80,7 @@ target_link_libraries(llui_libtest
|
|||
${LLIMAGEJ2COJ_LIBRARIES}
|
||||
${OS_LIBRARIES}
|
||||
${GOOGLE_PERFTOOLS_LIBRARIES}
|
||||
${HUNSPELL_LIBRARY}
|
||||
)
|
||||
|
||||
if (WINDOWS)
|
||||
|
|
|
|||
|
|
@ -269,6 +269,7 @@ namespace
|
|||
virtual LLSD::UUID asUUID() const { return LLUUID(mValue); }
|
||||
virtual LLSD::Date asDate() const { return LLDate(mValue); }
|
||||
virtual LLSD::URI asURI() const { return LLURI(mValue); }
|
||||
virtual int size() const { return mValue.size(); }
|
||||
};
|
||||
|
||||
LLSD::Integer ImplString::asInteger() const
|
||||
|
|
|
|||
|
|
@ -44,6 +44,15 @@ public:
|
|||
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}
|
||||
void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));}
|
||||
|
||||
LLStrider<Object> operator+(const S32& index)
|
||||
{
|
||||
LLStrider<Object> ret;
|
||||
ret.mBytep = mBytep + mSkip*index;
|
||||
ret.mSkip = mSkip;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void skip(const U32 index) { mBytep += mSkip*index;}
|
||||
U32 getSkip() const { return mSkip; }
|
||||
Object* get() { return mObjectp; }
|
||||
|
|
@ -51,6 +60,7 @@ public:
|
|||
Object& operator *() { return *mObjectp; }
|
||||
Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; }
|
||||
Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; }
|
||||
|
||||
Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -183,6 +183,9 @@ public:
|
|||
static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; }
|
||||
static bool isPunct(llwchar a) { return iswpunct(a) != 0; }
|
||||
|
||||
static bool isAlpha(char a) { return isalpha((unsigned char)a) != 0; }
|
||||
static bool isAlpha(llwchar a) { return iswalpha(a) != 0; }
|
||||
|
||||
static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; }
|
||||
static bool isAlnum(llwchar a) { return iswalnum(a) != 0; }
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
const S32 LL_VERSION_MAJOR = 3;
|
||||
const S32 LL_VERSION_MINOR = 3;
|
||||
const S32 LL_VERSION_PATCH = 3;
|
||||
const S32 LL_VERSION_PATCH = 4;
|
||||
const S32 LL_VERSION_BUILD = 0;
|
||||
|
||||
const char * const LL_CHANNEL = "Second Life Developer";
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ const S32 PARCEL_UNIT_AREA = 16;
|
|||
const F32 PARCEL_HEIGHT = 50.f;
|
||||
|
||||
//Height above ground which parcel boundries exist for explicitly banned avatars
|
||||
const F32 BAN_HEIGHT = 768.f;
|
||||
const F32 BAN_HEIGHT = 5000.f;
|
||||
|
||||
// Maximum number of entries in an access list
|
||||
const S32 PARCEL_MAX_ACCESS_LIST = 300;
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ const F32 F_ALMOST_ONE = 1.0f - F_ALMOST_ZERO;
|
|||
const F32 FP_MAG_THRESHOLD = 0.0000001f;
|
||||
|
||||
// TODO: Replace with logic like is_approx_equal
|
||||
inline BOOL is_approx_zero( F32 f ) { return (-F_APPROXIMATELY_ZERO < f) && (f < F_APPROXIMATELY_ZERO); }
|
||||
inline bool is_approx_zero( F32 f ) { return (-F_APPROXIMATELY_ZERO < f) && (f < F_APPROXIMATELY_ZERO); }
|
||||
|
||||
// These functions work by interpreting sign+exp+mantissa as an unsigned
|
||||
// integer.
|
||||
|
|
@ -111,13 +111,13 @@ inline BOOL is_approx_zero( F32 f ) { return (-F_APPROXIMATELY_ZERO < f) && (f <
|
|||
// WARNING: Infinity is comparable with F32_MAX and negative
|
||||
// infinity is comparable with F32_MIN
|
||||
|
||||
inline BOOL is_approx_equal(F32 x, F32 y)
|
||||
inline bool is_approx_equal(F32 x, F32 y)
|
||||
{
|
||||
const S32 COMPARE_MANTISSA_UP_TO_BIT = 0x02;
|
||||
return (std::abs((S32) ((U32&)x - (U32&)y) ) < COMPARE_MANTISSA_UP_TO_BIT);
|
||||
}
|
||||
|
||||
inline BOOL is_approx_equal(F64 x, F64 y)
|
||||
inline bool is_approx_equal(F64 x, F64 y)
|
||||
{
|
||||
const S64 COMPARE_MANTISSA_UP_TO_BIT = 0x02;
|
||||
return (std::abs((S32) ((U64&)x - (U64&)y) ) < COMPARE_MANTISSA_UP_TO_BIT);
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ class LLVolumeTriangle;
|
|||
#include "llstrider.h"
|
||||
#include "v4coloru.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llpointer.h"
|
||||
#include "llfile.h"
|
||||
|
||||
//============================================================================
|
||||
|
|
@ -919,6 +920,10 @@ public:
|
|||
LLVector2* mTexCoords;
|
||||
U16* mIndices;
|
||||
|
||||
//vertex buffer filled in by LLFace to cache this volume face geometry in vram
|
||||
// (declared as a LLPointer to LLRefCount to avoid dependency on LLVertexBuffer)
|
||||
mutable LLPointer<LLRefCount> mVertexBuffer;
|
||||
|
||||
std::vector<S32> mEdge;
|
||||
|
||||
//list of skin weights for rigged volumes
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ S32 getElementSize(const LLSD& llsd)
|
|||
case LLSD::TypeReal:
|
||||
return sizeof(F64);
|
||||
case LLSD::TypeString:
|
||||
return llsd.asString().size();
|
||||
return llsd.size();
|
||||
case LLSD::TypeUUID:
|
||||
return sizeof(LLUUID);
|
||||
case LLSD::TypeDate:
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ void LLCubeMap::initGL()
|
|||
{
|
||||
U32 texname = 0;
|
||||
|
||||
LLImageGL::generateTextures(1, &texname);
|
||||
LLImageGL::generateTextures(LLTexUnit::TT_CUBE_MAP, GL_RGB8, 1, &texname);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -422,6 +422,16 @@ S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y
|
|||
}
|
||||
|
||||
// font metrics - override for LLFontFreetype that returns units of virtual pixels
|
||||
F32 LLFontGL::getAscenderHeight() const
|
||||
{
|
||||
return mFontFreetype->getAscenderHeight() / sScaleY;
|
||||
}
|
||||
|
||||
F32 LLFontGL::getDescenderHeight() const
|
||||
{
|
||||
return mFontFreetype->getDescenderHeight() / sScaleY;
|
||||
}
|
||||
|
||||
S32 LLFontGL::getLineHeight() const
|
||||
{
|
||||
return llceil(mFontFreetype->getAscenderHeight() / sScaleY) + llceil(mFontFreetype->getDescenderHeight() / sScaleY);
|
||||
|
|
|
|||
|
|
@ -115,6 +115,8 @@ public:
|
|||
S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const;
|
||||
|
||||
// font metrics - override for LLFontFreetype that returns units of virtual pixels
|
||||
F32 getAscenderHeight() const;
|
||||
F32 getDescenderHeight() const;
|
||||
S32 getLineHeight() const;
|
||||
|
||||
S32 getWidth(const std::string& utf8text) const;
|
||||
|
|
|
|||
|
|
@ -249,6 +249,12 @@ PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample = NULL;
|
|||
PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv = NULL;
|
||||
PFNGLSAMPLEMASKIPROC glSampleMaski = NULL;
|
||||
|
||||
//transform feedback (4.0 core)
|
||||
PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback = NULL;
|
||||
PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback = NULL;
|
||||
PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings = NULL;
|
||||
PFNGLBINDBUFFERRANGEPROC glBindBufferRange = NULL;
|
||||
|
||||
//GL_ARB_debug_output
|
||||
PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB = NULL;
|
||||
PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB = NULL;
|
||||
|
|
@ -421,6 +427,7 @@ LLGLManager::LLGLManager() :
|
|||
mHasDrawBuffers(FALSE),
|
||||
mHasTextureRectangle(FALSE),
|
||||
mHasTextureMultisample(FALSE),
|
||||
mHasTransformFeedback(FALSE),
|
||||
mMaxSampleMaskWords(0),
|
||||
mMaxColorTextureSamples(0),
|
||||
mMaxDepthTextureSamples(0),
|
||||
|
|
@ -558,7 +565,8 @@ bool LLGLManager::initGL()
|
|||
parse_gl_version( &mDriverVersionMajor,
|
||||
&mDriverVersionMinor,
|
||||
&mDriverVersionRelease,
|
||||
&mDriverVersionVendorString );
|
||||
&mDriverVersionVendorString,
|
||||
&mGLVersionString);
|
||||
|
||||
mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f;
|
||||
|
||||
|
|
@ -938,7 +946,6 @@ void LLGLManager::initExtensions()
|
|||
mHasMultitexture = glh_init_extensions("GL_ARB_multitexture");
|
||||
mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts);
|
||||
mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts);
|
||||
mHasMipMapGeneration = glh_init_extensions("GL_SGIS_generate_mipmap");
|
||||
mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color");
|
||||
mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic");
|
||||
glh_init_extensions("GL_ARB_texture_cube_map");
|
||||
|
|
@ -963,11 +970,14 @@ void LLGLManager::initExtensions()
|
|||
ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts);
|
||||
#endif
|
||||
|
||||
mHasMipMapGeneration = mHasFramebufferObject || mGLVersion >= 1.4f;
|
||||
|
||||
mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts);
|
||||
mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts);
|
||||
mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts);
|
||||
mHasTextureMultisample = ExtensionExists("GL_ARB_texture_multisample", gGLHExts.mSysExts);
|
||||
mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts);
|
||||
mHasTransformFeedback = mGLVersion >= 4.f ? TRUE : FALSE;
|
||||
#if !LL_DARWIN
|
||||
mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
|
||||
#endif
|
||||
|
|
@ -1207,7 +1217,14 @@ void LLGLManager::initExtensions()
|
|||
glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glTexImage3DMultisample");
|
||||
glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetMultisamplefv");
|
||||
glSampleMaski = (PFNGLSAMPLEMASKIPROC) GLH_EXT_GET_PROC_ADDRESS("glSampleMaski");
|
||||
}
|
||||
}
|
||||
if (mHasTransformFeedback)
|
||||
{
|
||||
glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glBeginTransformFeedback");
|
||||
glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glEndTransformFeedback");
|
||||
glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) GLH_EXT_GET_PROC_ADDRESS("glTransformFeedbackVaryings");
|
||||
glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glBindBufferRange");
|
||||
}
|
||||
if (mHasDebugOutput)
|
||||
{
|
||||
glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageControlARB");
|
||||
|
|
@ -1964,6 +1981,7 @@ LLGLState::LLGLState(LLGLenum state, S32 enabled) :
|
|||
case GL_COLOR_MATERIAL:
|
||||
case GL_FOG:
|
||||
case GL_LINE_STIPPLE:
|
||||
case GL_POLYGON_STIPPLE:
|
||||
mState = 0;
|
||||
break;
|
||||
}
|
||||
|
|
@ -2052,7 +2070,7 @@ void LLGLManager::initGLStates()
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific )
|
||||
void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string )
|
||||
{
|
||||
// GL_VERSION returns a null-terminated string with the format:
|
||||
// <major>.<minor>[.<release>] [<vendor specific>]
|
||||
|
|
@ -2068,6 +2086,8 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor
|
|||
return;
|
||||
}
|
||||
|
||||
version_string->assign(version);
|
||||
|
||||
std::string ver_copy( version );
|
||||
S32 len = (S32)strlen( version ); /* Flawfinder: ignore */
|
||||
S32 i = 0;
|
||||
|
|
@ -2429,3 +2449,65 @@ LLGLSquashToFarClip::~LLGLSquashToFarClip()
|
|||
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||
}
|
||||
|
||||
|
||||
|
||||
LLGLSyncFence::LLGLSyncFence()
|
||||
{
|
||||
#ifdef GL_ARB_sync
|
||||
mSync = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
LLGLSyncFence::~LLGLSyncFence()
|
||||
{
|
||||
#ifdef GL_ARB_sync
|
||||
if (mSync)
|
||||
{
|
||||
glDeleteSync(mSync);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LLGLSyncFence::placeFence()
|
||||
{
|
||||
#ifdef GL_ARB_sync
|
||||
if (mSync)
|
||||
{
|
||||
glDeleteSync(mSync);
|
||||
}
|
||||
mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool LLGLSyncFence::isCompleted()
|
||||
{
|
||||
bool ret = true;
|
||||
#ifdef GL_ARB_sync
|
||||
if (mSync)
|
||||
{
|
||||
GLenum status = glClientWaitSync(mSync, 0, 1);
|
||||
if (status == GL_TIMEOUT_EXPIRED)
|
||||
{
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LLGLSyncFence::wait()
|
||||
{
|
||||
#ifdef GL_ARB_sync
|
||||
if (mSync)
|
||||
{
|
||||
while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED)
|
||||
{ //track the number of times we've waited here
|
||||
static S32 waits = 0;
|
||||
waits++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ public:
|
|||
BOOL mHasDepthClamp;
|
||||
BOOL mHasTextureRectangle;
|
||||
BOOL mHasTextureMultisample;
|
||||
BOOL mHasTransformFeedback;
|
||||
S32 mMaxSampleMaskWords;
|
||||
S32 mMaxColorTextureSamples;
|
||||
S32 mMaxDepthTextureSamples;
|
||||
|
|
@ -141,6 +142,7 @@ public:
|
|||
S32 mGLSLVersionMajor;
|
||||
S32 mGLSLVersionMinor;
|
||||
std::string mDriverVersionVendorString;
|
||||
std::string mGLVersionString;
|
||||
|
||||
S32 mVRAM; // VRAM in MB
|
||||
S32 mGLMaxVertexRange;
|
||||
|
|
@ -417,13 +419,38 @@ public:
|
|||
virtual void updateGL() = 0;
|
||||
};
|
||||
|
||||
const U32 FENCE_WAIT_TIME_NANOSECONDS = 1000; //1 ms
|
||||
|
||||
class LLGLFence
|
||||
{
|
||||
public:
|
||||
virtual void placeFence() = 0;
|
||||
virtual bool isCompleted() = 0;
|
||||
virtual void wait() = 0;
|
||||
};
|
||||
|
||||
class LLGLSyncFence : public LLGLFence
|
||||
{
|
||||
public:
|
||||
#ifdef GL_ARB_sync
|
||||
GLsync mSync;
|
||||
#endif
|
||||
|
||||
LLGLSyncFence();
|
||||
virtual ~LLGLSyncFence();
|
||||
|
||||
void placeFence();
|
||||
bool isCompleted();
|
||||
void wait();
|
||||
};
|
||||
|
||||
extern LLMatrix4 gGLObliqueProjectionInverse;
|
||||
|
||||
#include "llglstates.h"
|
||||
|
||||
void init_glstates();
|
||||
|
||||
void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific );
|
||||
void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string );
|
||||
|
||||
extern BOOL gClothRipple;
|
||||
extern BOOL gHeadlessClient;
|
||||
|
|
|
|||
|
|
@ -528,6 +528,13 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
|
|||
extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
|
||||
extern PFNGLSAMPLEMASKIPROC glSampleMaski;
|
||||
|
||||
//transform feedback (4.0 core)
|
||||
extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback;
|
||||
extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback;
|
||||
extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings;
|
||||
extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
|
||||
|
||||
|
||||
#elif LL_WINDOWS
|
||||
//----------------------------------------------------------------------------
|
||||
// LL_WINDOWS
|
||||
|
|
@ -759,6 +766,12 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
|
|||
extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
|
||||
extern PFNGLSAMPLEMASKIPROC glSampleMaski;
|
||||
|
||||
//transform feedback (4.0 core)
|
||||
extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback;
|
||||
extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback;
|
||||
extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings;
|
||||
extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
|
||||
|
||||
//GL_ARB_debug_output
|
||||
extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB;
|
||||
extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB;
|
||||
|
|
|
|||
|
|
@ -129,7 +129,9 @@ void LLGLSLShader::unload()
|
|||
}
|
||||
|
||||
BOOL LLGLSLShader::createShader(vector<string> * attributes,
|
||||
vector<string> * uniforms)
|
||||
vector<string> * uniforms,
|
||||
U32 varying_count,
|
||||
const char** varyings)
|
||||
{
|
||||
//reloading, reset matrix hash values
|
||||
for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i)
|
||||
|
|
@ -172,6 +174,13 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
|
|||
mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
|
||||
}
|
||||
|
||||
#ifdef GL_INTERLEAVED_ATTRIBS
|
||||
if (varying_count > 0 && varyings)
|
||||
{
|
||||
glTransformFeedbackVaryings(mProgramObject, varying_count, varyings, GL_INTERLEAVED_ATTRIBS);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Map attributes and uniforms
|
||||
if (success)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -76,7 +76,9 @@ public:
|
|||
|
||||
void unload();
|
||||
BOOL createShader(std::vector<std::string> * attributes,
|
||||
std::vector<std::string> * uniforms);
|
||||
std::vector<std::string> * uniforms,
|
||||
U32 varying_count = 0,
|
||||
const char** varyings = NULL);
|
||||
BOOL attachObject(std::string object);
|
||||
void attachObject(GLhandleARB object);
|
||||
void attachObjects(GLhandleARB* objects = NULL, S32 count = 0);
|
||||
|
|
|
|||
|
|
@ -42,6 +42,10 @@
|
|||
//----------------------------------------------------------------------------
|
||||
const F32 MIN_TEXTURE_LIFETIME = 10.f;
|
||||
|
||||
//which power of 2 is i?
|
||||
//assumes i is a power of 2 > 0
|
||||
U32 wpo2(U32 i);
|
||||
|
||||
//statics
|
||||
|
||||
U32 LLImageGL::sUniqueCount = 0;
|
||||
|
|
@ -50,7 +54,8 @@ S32 LLImageGL::sGlobalTextureMemoryInBytes = 0;
|
|||
S32 LLImageGL::sBoundTextureMemoryInBytes = 0;
|
||||
S32 LLImageGL::sCurBoundTextureMemory = 0;
|
||||
S32 LLImageGL::sCount = 0;
|
||||
std::list<U32> LLImageGL::sDeadTextureList;
|
||||
LLImageGL::dead_texturelist_t LLImageGL::sDeadTextureList[LLTexUnit::TT_NONE];
|
||||
U32 LLImageGL::sCurTexName = 1;
|
||||
|
||||
BOOL LLImageGL::sGlobalUseAnisotropic = FALSE;
|
||||
F32 LLImageGL::sLastFrameTime = 0.f;
|
||||
|
|
@ -416,6 +421,7 @@ void LLImageGL::init(BOOL usemipmaps)
|
|||
mTarget = GL_TEXTURE_2D;
|
||||
mBindTarget = LLTexUnit::TT_TEXTURE;
|
||||
mHasMipMaps = false;
|
||||
mMipLevels = -1;
|
||||
|
||||
mIsResident = 0;
|
||||
|
||||
|
|
@ -606,8 +612,24 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
|
|||
is_compressed = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (mUseMipMaps)
|
||||
{
|
||||
//set has mip maps to true before binding image so tex parameters get set properly
|
||||
gGL.getTexUnit(0)->unbind(mBindTarget);
|
||||
mHasMipMaps = true;
|
||||
mTexOptionsDirty = true;
|
||||
setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
|
||||
}
|
||||
else
|
||||
{
|
||||
mHasMipMaps = false;
|
||||
}
|
||||
|
||||
llverify(gGL.getTexUnit(0)->bind(this));
|
||||
|
||||
|
||||
if (mUseMipMaps)
|
||||
{
|
||||
if (data_hasmips)
|
||||
|
|
@ -620,6 +642,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
|
|||
S32 w = getWidth(d);
|
||||
S32 h = getHeight(d);
|
||||
S32 gl_level = d-mCurrentDiscardLevel;
|
||||
|
||||
mMipLevels = llmax(mMipLevels, gl_level);
|
||||
|
||||
if (d > mCurrentDiscardLevel)
|
||||
{
|
||||
data_in -= dataFormatBytes(mFormatPrimary, w, h); // see above comment
|
||||
|
|
@ -662,10 +687,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
|
|||
{
|
||||
if (mAutoGenMips)
|
||||
{
|
||||
if (!gGLManager.mHasFramebufferObject)
|
||||
{
|
||||
glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE);
|
||||
}
|
||||
stop_glerror();
|
||||
{
|
||||
// LLFastTimer t2(FTM_TEMP4);
|
||||
|
|
@ -679,6 +700,11 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
|
|||
S32 w = getWidth(mCurrentDiscardLevel);
|
||||
S32 h = getHeight(mCurrentDiscardLevel);
|
||||
|
||||
mMipLevels = wpo2(llmax(w, h));
|
||||
|
||||
//use legacy mipmap generation mode
|
||||
glTexParameteri(mTarget, GL_GENERATE_MIPMAP, GL_TRUE);
|
||||
|
||||
LLImageGL::setManualImage(mTarget, 0, mFormatInternal,
|
||||
w, h,
|
||||
mFormatPrimary, mFormatType,
|
||||
|
|
@ -694,16 +720,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
|
|||
stop_glerror();
|
||||
}
|
||||
}
|
||||
|
||||
if (gGLManager.mHasFramebufferObject)
|
||||
{
|
||||
glGenerateMipmap(LLTexUnit::getInternalType(mBindTarget));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create mips by hand
|
||||
// about 30% faster than autogen on ATI 9800, 50% slower on nVidia 4800
|
||||
// ~4x faster than gluBuild2DMipmaps
|
||||
S32 width = getWidth(mCurrentDiscardLevel);
|
||||
S32 height = getHeight(mCurrentDiscardLevel);
|
||||
|
|
@ -713,6 +733,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
|
|||
const U8* cur_mip_data = 0;
|
||||
S32 prev_mip_size = 0;
|
||||
S32 cur_mip_size = 0;
|
||||
|
||||
mMipLevels = nummips;
|
||||
|
||||
for (int m=0; m<nummips; m++)
|
||||
{
|
||||
if (m==0)
|
||||
|
|
@ -777,10 +800,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
|
|||
{
|
||||
llerrs << "Compressed Image has mipmaps but data does not (can not auto generate compressed mips)" << llendl;
|
||||
}
|
||||
mHasMipMaps = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mMipLevels = 0;
|
||||
S32 w = getWidth();
|
||||
S32 h = getHeight();
|
||||
if (is_compressed)
|
||||
|
|
@ -812,7 +835,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
|
|||
}
|
||||
|
||||
}
|
||||
mHasMipMaps = false;
|
||||
}
|
||||
stop_glerror();
|
||||
mGLTextureCreated = true;
|
||||
|
|
@ -1025,23 +1047,65 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_
|
|||
}
|
||||
|
||||
// static
|
||||
void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
|
||||
void LLImageGL::generateTextures(LLTexUnit::eTextureType type, U32 format, S32 numTextures, U32 *textures)
|
||||
{
|
||||
glGenTextures(numTextures, (GLuint*)textures);
|
||||
bool empty = true;
|
||||
|
||||
dead_texturelist_t::iterator iter = sDeadTextureList[type].find(format);
|
||||
|
||||
if (iter != sDeadTextureList[type].end())
|
||||
{
|
||||
empty = iter->second.empty();
|
||||
}
|
||||
|
||||
for (S32 i = 0; i < numTextures; ++i)
|
||||
{
|
||||
if (!empty)
|
||||
{
|
||||
textures[i] = iter->second.front();
|
||||
iter->second.pop_front();
|
||||
empty = iter->second.empty();
|
||||
}
|
||||
else
|
||||
{
|
||||
textures[i] = sCurTexName++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLImageGL::deleteTextures(S32 numTextures, U32 *textures, bool immediate)
|
||||
void LLImageGL::deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip_levels, S32 numTextures, U32 *textures, bool immediate)
|
||||
{
|
||||
for (S32 i = 0; i < numTextures; i++)
|
||||
if (gGLManager.mInited)
|
||||
{
|
||||
sDeadTextureList.push_back(textures[i]);
|
||||
}
|
||||
if (format == 0 || type == LLTexUnit::TT_CUBE_MAP || mip_levels == -1)
|
||||
{ //unknown internal format or unknown number of mip levels, not safe to reuse
|
||||
glDeleteTextures(numTextures, textures);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (S32 i = 0; i < numTextures; ++i)
|
||||
{ //remove texture from VRAM by setting its size to zero
|
||||
for (S32 j = 0; j <= mip_levels; j++)
|
||||
{
|
||||
gGL.getTexUnit(0)->bindManual(type, textures[i]);
|
||||
|
||||
if (immediate)
|
||||
glTexImage2D(LLTexUnit::getInternalType(type), j, format, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
}
|
||||
|
||||
llassert(std::find(sDeadTextureList[type][format].begin(),
|
||||
sDeadTextureList[type][format].end(), textures[i]) ==
|
||||
sDeadTextureList[type][format].end());
|
||||
|
||||
sDeadTextureList[type][format].push_back(textures[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*if (immediate)
|
||||
{
|
||||
LLImageGL::deleteDeadTextures();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
@ -1166,10 +1230,11 @@ BOOL LLImageGL::createGLTexture()
|
|||
|
||||
if(mTexName)
|
||||
{
|
||||
glDeleteTextures(1, (reinterpret_cast<GLuint*>(&mTexName))) ;
|
||||
LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, (reinterpret_cast<GLuint*>(&mTexName))) ;
|
||||
}
|
||||
|
||||
glGenTextures(1, (GLuint*)&mTexName);
|
||||
|
||||
LLImageGL::generateTextures(mBindTarget, mFormatInternal, 1, &mTexName);
|
||||
stop_glerror();
|
||||
if (!mTexName)
|
||||
{
|
||||
|
|
@ -1282,7 +1347,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
|
|||
}
|
||||
else
|
||||
{
|
||||
LLImageGL::generateTextures(1, &mTexName);
|
||||
LLImageGL::generateTextures(mBindTarget, mFormatInternal, 1, &mTexName);
|
||||
stop_glerror();
|
||||
{
|
||||
llverify(gGL.getTexUnit(0)->bind(this));
|
||||
|
|
@ -1327,7 +1392,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
|
|||
{
|
||||
sGlobalTextureMemoryInBytes -= mTextureMemory;
|
||||
|
||||
LLImageGL::deleteTextures(1, &old_name);
|
||||
LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, &old_name);
|
||||
|
||||
stop_glerror();
|
||||
}
|
||||
|
|
@ -1456,7 +1521,7 @@ void LLImageGL::deleteDeadTextures()
|
|||
{
|
||||
bool reset = false;
|
||||
|
||||
while (!sDeadTextureList.empty())
|
||||
/*while (!sDeadTextureList.empty())
|
||||
{
|
||||
GLuint tex = sDeadTextureList.front();
|
||||
sDeadTextureList.pop_front();
|
||||
|
|
@ -1478,7 +1543,7 @@ void LLImageGL::deleteDeadTextures()
|
|||
|
||||
glDeleteTextures(1, &tex);
|
||||
stop_glerror();
|
||||
}
|
||||
}*/
|
||||
|
||||
if (reset)
|
||||
{
|
||||
|
|
@ -1496,7 +1561,7 @@ void LLImageGL::destroyGLTexture()
|
|||
mTextureMemory = 0;
|
||||
}
|
||||
|
||||
LLImageGL::deleteTextures(1, &mTexName);
|
||||
LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, &mTexName);
|
||||
mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.
|
||||
mTexName = 0;
|
||||
mGLTextureCreated = FALSE ;
|
||||
|
|
|
|||
|
|
@ -45,8 +45,16 @@ class LLImageGL : public LLRefCount
|
|||
{
|
||||
friend class LLTexUnit;
|
||||
public:
|
||||
static std::list<U32> sDeadTextureList;
|
||||
static U32 sCurTexName;
|
||||
|
||||
//previously used but now available texture names
|
||||
// sDeadTextureList[<usage>][<internal format>]
|
||||
typedef std::map<U32, std::list<U32> > dead_texturelist_t;
|
||||
static dead_texturelist_t sDeadTextureList[LLTexUnit::TT_NONE];
|
||||
|
||||
// These 2 functions replace glGenTextures() and glDeleteTextures()
|
||||
static void generateTextures(LLTexUnit::eTextureType type, U32 format, S32 numTextures, U32 *textures);
|
||||
static void deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip_levels, S32 numTextures, U32 *textures, bool immediate = false);
|
||||
static void deleteDeadTextures();
|
||||
|
||||
// Size calculation
|
||||
|
|
@ -96,10 +104,6 @@ public:
|
|||
void setComponents(S32 ncomponents) { mComponents = (S8)ncomponents ;}
|
||||
void setAllowCompression(bool allow) { mAllowCompression = allow; }
|
||||
|
||||
// These 3 functions currently wrap glGenTextures(), glDeleteTextures(), and glTexImage2D()
|
||||
// for tracking purposes and will be deprecated in the future
|
||||
static void generateTextures(S32 numTextures, U32 *textures);
|
||||
static void deleteTextures(S32 numTextures, U32 *textures, bool immediate = false);
|
||||
static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression = true);
|
||||
|
||||
BOOL createGLTexture() ;
|
||||
|
|
@ -217,7 +221,8 @@ protected:
|
|||
LLGLenum mTarget; // Normally GL_TEXTURE2D, sometimes something else (ex. cube maps)
|
||||
LLTexUnit::eTextureType mBindTarget; // Normally TT_TEXTURE, sometimes something else (ex. cube maps)
|
||||
bool mHasMipMaps;
|
||||
|
||||
S32 mMipLevels;
|
||||
|
||||
LLGLboolean mIsResident;
|
||||
|
||||
S8 mComponents;
|
||||
|
|
|
|||
|
|
@ -408,12 +408,14 @@ void LLTexUnit::unbind(eTextureType type)
|
|||
|
||||
if (mIndex < 0) return;
|
||||
|
||||
//always flush and activate for consistency
|
||||
// some code paths assume unbind always flushes and sets the active texture
|
||||
gGL.flush();
|
||||
activate();
|
||||
|
||||
// Disabled caching of binding state.
|
||||
if (mCurrTexType == type)
|
||||
{
|
||||
gGL.flush();
|
||||
|
||||
activate();
|
||||
mCurrTexture = 0;
|
||||
if (LLGLSLShader::sNoFixedFunction && type == LLTexUnit::TT_TEXTURE)
|
||||
{
|
||||
|
|
@ -464,11 +466,25 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
|
|||
}
|
||||
else if (option >= TFO_BILINEAR)
|
||||
{
|
||||
glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
if (mHasMipMaps)
|
||||
{
|
||||
glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
if (mHasMipMaps)
|
||||
{
|
||||
glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
}
|
||||
}
|
||||
|
||||
if (gGLManager.mHasAnisotropic)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ bool LLRenderTarget::sUseFBO = false;
|
|||
LLRenderTarget::LLRenderTarget() :
|
||||
mResX(0),
|
||||
mResY(0),
|
||||
mTex(0),
|
||||
mFBO(0),
|
||||
mDepth(0),
|
||||
mStencil(0),
|
||||
|
|
@ -135,7 +134,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt)
|
|||
}
|
||||
|
||||
U32 tex;
|
||||
LLImageGL::generateTextures(1, &tex);
|
||||
LLImageGL::generateTextures(mUsage, color_fmt, 1, &tex);
|
||||
gGL.getTexUnit(0)->bindManual(mUsage, tex);
|
||||
|
||||
stop_glerror();
|
||||
|
|
@ -193,6 +192,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt)
|
|||
}
|
||||
|
||||
mTex.push_back(tex);
|
||||
mInternalFormat.push_back(color_fmt);
|
||||
|
||||
if (gDebugGL)
|
||||
{ //bind and unbind to validate target
|
||||
|
|
@ -217,7 +217,7 @@ bool LLRenderTarget::allocateDepth()
|
|||
}
|
||||
else
|
||||
{
|
||||
LLImageGL::generateTextures(1, &mDepth);
|
||||
LLImageGL::generateTextures(mUsage, GL_DEPTH_COMPONENT24, 1, &mDepth);
|
||||
gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
|
||||
|
||||
U32 internal_type = LLTexUnit::getInternalType(mUsage);
|
||||
|
|
@ -294,7 +294,7 @@ void LLRenderTarget::release()
|
|||
}
|
||||
else
|
||||
{
|
||||
LLImageGL::deleteTextures(1, &mDepth, true);
|
||||
LLImageGL::deleteTextures(mUsage, 0, 0, 1, &mDepth, true);
|
||||
stop_glerror();
|
||||
}
|
||||
mDepth = 0;
|
||||
|
|
@ -326,8 +326,9 @@ void LLRenderTarget::release()
|
|||
if (mTex.size() > 0)
|
||||
{
|
||||
sBytesAllocated -= mResX*mResY*4*mTex.size();
|
||||
LLImageGL::deleteTextures(mTex.size(), &mTex[0], true);
|
||||
LLImageGL::deleteTextures(mUsage, mInternalFormat[0], 0, mTex.size(), &mTex[0], true);
|
||||
mTex.clear();
|
||||
mInternalFormat.clear();
|
||||
}
|
||||
|
||||
mResX = mResY = 0;
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ protected:
|
|||
U32 mResX;
|
||||
U32 mResY;
|
||||
std::vector<U32> mTex;
|
||||
std::vector<U32> mInternalFormat;
|
||||
U32 mFBO;
|
||||
U32 mDepth;
|
||||
bool mStencil;
|
||||
|
|
|
|||
|
|
@ -702,7 +702,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
|||
|
||||
if (texture_index_channels > 1)
|
||||
{
|
||||
text[count++] = strdup("VARYING_FLAT ivec4 vary_texture_index;\n");
|
||||
text[count++] = strdup("VARYING_FLAT int vary_texture_index;\n");
|
||||
}
|
||||
|
||||
text[count++] = strdup("vec4 diffuseLookup(vec2 texcoord)\n");
|
||||
|
|
@ -716,20 +716,33 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
|||
}
|
||||
else if (major_version > 1 || minor_version >= 30)
|
||||
{ //switches are supported in GLSL 1.30 and later
|
||||
text[count++] = strdup("\tvec4 ret = vec4(1,0,1,1);\n");
|
||||
text[count++] = strdup("\tswitch (vary_texture_index.r)\n");
|
||||
text[count++] = strdup("\t{\n");
|
||||
|
||||
//switch body
|
||||
for (S32 i = 0; i < texture_index_channels; ++i)
|
||||
{
|
||||
std::string case_str = llformat("\t\tcase %d: ret = texture2D(tex%d, texcoord); break;\n", i, i);
|
||||
text[count++] = strdup(case_str.c_str());
|
||||
if (gGLManager.mIsNVIDIA)
|
||||
{ //switches are unreliable on some NVIDIA drivers
|
||||
for (U32 i = 0; i < texture_index_channels; ++i)
|
||||
{
|
||||
std::string if_string = llformat("\t%sif (vary_texture_index == %d) { return texture2D(tex%d, texcoord); }\n", i > 0 ? "else " : "", i, i);
|
||||
text[count++] = strdup(if_string.c_str());
|
||||
}
|
||||
text[count++] = strdup("\treturn vec4(1,0,1,1);\n");
|
||||
text[count++] = strdup("}\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
text[count++] = strdup("\tvec4 ret = vec4(1,0,1,1);\n");
|
||||
text[count++] = strdup("\tswitch (vary_texture_index)\n");
|
||||
text[count++] = strdup("\t{\n");
|
||||
|
||||
//switch body
|
||||
for (S32 i = 0; i < texture_index_channels; ++i)
|
||||
{
|
||||
std::string case_str = llformat("\t\tcase %d: return texture2D(tex%d, texcoord);\n", i, i);
|
||||
text[count++] = strdup(case_str.c_str());
|
||||
}
|
||||
|
||||
text[count++] = strdup("\t}\n");
|
||||
text[count++] = strdup("\treturn ret;\n");
|
||||
text[count++] = strdup("}\n");
|
||||
text[count++] = strdup("\t}\n");
|
||||
text[count++] = strdup("\treturn ret;\n");
|
||||
text[count++] = strdup("}\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //should never get here. Indexed texture rendering requires GLSL 1.30 or later
|
||||
|
|
@ -1026,6 +1039,9 @@ void LLShaderMgr::initAttribsAndUniforms()
|
|||
mReservedUniforms.push_back("size");
|
||||
mReservedUniforms.push_back("falloff");
|
||||
|
||||
mReservedUniforms.push_back("box_center");
|
||||
mReservedUniforms.push_back("box_size");
|
||||
|
||||
|
||||
mReservedUniforms.push_back("minLuminance");
|
||||
mReservedUniforms.push_back("maxExtractAlpha");
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ public:
|
|||
LIGHT_CENTER,
|
||||
LIGHT_SIZE,
|
||||
LIGHT_FALLOFF,
|
||||
BOX_CENTER,
|
||||
BOX_SIZE,
|
||||
|
||||
GLOW_MIN_LUMINANCE,
|
||||
GLOW_MAX_EXTRACT_ALPHA,
|
||||
|
|
|
|||
|
|
@ -41,9 +41,7 @@
|
|||
#if LL_DARWIN
|
||||
#define LL_VBO_POOLING 1
|
||||
#else
|
||||
#define LL_VBO_POOLING 0
|
||||
#endif
|
||||
|
||||
//Next Highest Power Of Two
|
||||
//helper function, returns first number > v that is a power of 2, or v if v is already a power of 2
|
||||
U32 nhpo2(U32 v)
|
||||
|
|
@ -71,6 +69,7 @@ U32 wpo2(U32 i)
|
|||
|
||||
|
||||
const U32 LL_VBO_BLOCK_SIZE = 2048;
|
||||
const U32 LL_VBO_POOL_MAX_SEED_SIZE = 256*1024;
|
||||
|
||||
U32 vbo_block_size(U32 size)
|
||||
{ //what block size will fit size?
|
||||
|
|
@ -83,6 +82,7 @@ U32 vbo_block_index(U32 size)
|
|||
return vbo_block_size(size)/LL_VBO_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE);
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
|
@ -95,6 +95,11 @@ LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_
|
|||
|
||||
U32 LLVBOPool::sBytesPooled = 0;
|
||||
U32 LLVBOPool::sIndexBytesPooled = 0;
|
||||
U32 LLVBOPool::sCurGLName = 1;
|
||||
|
||||
std::list<U32> LLVertexBuffer::sAvailableVAOName;
|
||||
U32 LLVertexBuffer::sCurVAOName = 1;
|
||||
|
||||
U32 LLVertexBuffer::sAllocatedIndexBytes = 0;
|
||||
U32 LLVertexBuffer::sIndexCount = 0;
|
||||
|
||||
|
|
@ -119,69 +124,55 @@ bool LLVertexBuffer::sUseStreamDraw = true;
|
|||
bool LLVertexBuffer::sUseVAO = false;
|
||||
bool LLVertexBuffer::sPreferStreamDraw = false;
|
||||
|
||||
const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000; //1 ms
|
||||
|
||||
class LLGLSyncFence : public LLGLFence
|
||||
U32 LLVBOPool::genBuffer()
|
||||
{
|
||||
public:
|
||||
#ifdef GL_ARB_sync
|
||||
GLsync mSync;
|
||||
#endif
|
||||
|
||||
LLGLSyncFence()
|
||||
U32 ret = 0;
|
||||
|
||||
if (mGLNamePool.empty())
|
||||
{
|
||||
#ifdef GL_ARB_sync
|
||||
mSync = 0;
|
||||
#endif
|
||||
ret = sCurGLName++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = mGLNamePool.front();
|
||||
mGLNamePool.pop_front();
|
||||
}
|
||||
|
||||
virtual ~LLGLSyncFence()
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LLVBOPool::deleteBuffer(U32 name)
|
||||
{
|
||||
if (gGLManager.mInited)
|
||||
{
|
||||
#ifdef GL_ARB_sync
|
||||
if (mSync)
|
||||
{
|
||||
glDeleteSync(mSync);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void placeFence()
|
||||
{
|
||||
#ifdef GL_ARB_sync
|
||||
if (mSync)
|
||||
{
|
||||
glDeleteSync(mSync);
|
||||
}
|
||||
mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
#ifdef GL_ARB_sync
|
||||
if (mSync)
|
||||
{
|
||||
while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED)
|
||||
{ //track the number of times we've waited here
|
||||
static S32 waits = 0;
|
||||
waits++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
LLVertexBuffer::unbind();
|
||||
|
||||
glBindBufferARB(mType, name);
|
||||
glBufferDataARB(mType, 0, NULL, mUsage);
|
||||
|
||||
llassert(std::find(mGLNamePool.begin(), mGLNamePool.end(), name) == mGLNamePool.end());
|
||||
|
||||
mGLNamePool.push_back(name);
|
||||
|
||||
glBindBufferARB(mType, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType)
|
||||
: mUsage(vboUsage), mType(vboType)
|
||||
{
|
||||
mMissCount.resize(LL_VBO_POOL_SEED_COUNT);
|
||||
std::fill(mMissCount.begin(), mMissCount.end(), 0);
|
||||
}
|
||||
|
||||
|
||||
volatile U8* LLVBOPool::allocate(U32& name, U32 size)
|
||||
volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed)
|
||||
{
|
||||
llassert(vbo_block_size(size) == size);
|
||||
|
||||
volatile U8* ret = NULL;
|
||||
|
||||
#if LL_VBO_POOLING
|
||||
|
||||
U32 i = vbo_block_index(size);
|
||||
|
||||
if (mFreeList.size() <= i)
|
||||
|
|
@ -189,12 +180,18 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size)
|
|||
mFreeList.resize(i+1);
|
||||
}
|
||||
|
||||
if (mFreeList[i].empty())
|
||||
if (mFreeList[i].empty() || for_seed)
|
||||
{
|
||||
//make a new buffer
|
||||
glGenBuffersARB(1, &name);
|
||||
name = genBuffer();
|
||||
|
||||
glBindBufferARB(mType, name);
|
||||
|
||||
if (!for_seed && i < LL_VBO_POOL_SEED_COUNT)
|
||||
{ //record this miss
|
||||
mMissCount[i]++;
|
||||
}
|
||||
|
||||
if (mType == GL_ARRAY_BUFFER_ARB)
|
||||
{
|
||||
LLVertexBuffer::sAllocatedBytes += size;
|
||||
|
|
@ -215,6 +212,25 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size)
|
|||
}
|
||||
|
||||
glBindBufferARB(mType, 0);
|
||||
|
||||
if (for_seed)
|
||||
{ //put into pool for future use
|
||||
llassert(mFreeList.size() > i);
|
||||
|
||||
Record rec;
|
||||
rec.mGLName = name;
|
||||
rec.mClientData = ret;
|
||||
|
||||
if (mType == GL_ARRAY_BUFFER_ARB)
|
||||
{
|
||||
sBytesPooled += size;
|
||||
}
|
||||
else
|
||||
{
|
||||
sIndexBytesPooled += size;
|
||||
}
|
||||
mFreeList[i].push_back(rec);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -232,33 +248,6 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size)
|
|||
|
||||
mFreeList[i].pop_front();
|
||||
}
|
||||
#else //no pooling
|
||||
|
||||
glGenBuffersARB(1, &name);
|
||||
glBindBufferARB(mType, name);
|
||||
|
||||
if (mType == GL_ARRAY_BUFFER_ARB)
|
||||
{
|
||||
LLVertexBuffer::sAllocatedBytes += size;
|
||||
}
|
||||
else
|
||||
{
|
||||
LLVertexBuffer::sAllocatedIndexBytes += size;
|
||||
}
|
||||
|
||||
if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB)
|
||||
{
|
||||
glBufferDataARB(mType, size, 0, mUsage);
|
||||
ret = (U8*) ll_aligned_malloc_16(size);
|
||||
}
|
||||
else
|
||||
{ //always use a true hint of static draw when allocating non-client-backed buffers
|
||||
glBufferDataARB(mType, size, 0, GL_STATIC_DRAW_ARB);
|
||||
}
|
||||
|
||||
glBindBufferARB(mType, 0);
|
||||
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -267,34 +256,7 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
|
|||
{
|
||||
llassert(vbo_block_size(size) == size);
|
||||
|
||||
#if LL_VBO_POOLING
|
||||
|
||||
U32 i = vbo_block_index(size);
|
||||
|
||||
llassert(mFreeList.size() > i);
|
||||
|
||||
Record rec;
|
||||
rec.mGLName = name;
|
||||
rec.mClientData = buffer;
|
||||
|
||||
if (buffer == NULL)
|
||||
{
|
||||
glDeleteBuffersARB(1, &rec.mGLName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mType == GL_ARRAY_BUFFER_ARB)
|
||||
{
|
||||
sBytesPooled += size;
|
||||
}
|
||||
else
|
||||
{
|
||||
sIndexBytesPooled += size;
|
||||
}
|
||||
mFreeList[i].push_back(rec);
|
||||
}
|
||||
#else //no pooling
|
||||
glDeleteBuffersARB(1, &name);
|
||||
deleteBuffer(name);
|
||||
ll_aligned_free_16((U8*) buffer);
|
||||
|
||||
if (mType == GL_ARRAY_BUFFER_ARB)
|
||||
|
|
@ -305,12 +267,36 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
|
|||
{
|
||||
LLVertexBuffer::sAllocatedIndexBytes -= size;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LLVBOPool::seedPool()
|
||||
{
|
||||
U32 dummy_name = 0;
|
||||
|
||||
if (mFreeList.size() < LL_VBO_POOL_SEED_COUNT)
|
||||
{
|
||||
mFreeList.resize(LL_VBO_POOL_SEED_COUNT);
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < LL_VBO_POOL_SEED_COUNT; i++)
|
||||
{
|
||||
if (mMissCount[i] > mFreeList[i].size())
|
||||
{
|
||||
U32 size = i*LL_VBO_BLOCK_SIZE;
|
||||
|
||||
S32 count = mMissCount[i] - mFreeList[i].size();
|
||||
for (U32 j = 0; j < count; ++j)
|
||||
{
|
||||
allocate(dummy_name, size, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLVBOPool::cleanup()
|
||||
{
|
||||
U32 size = 1;
|
||||
U32 size = LL_VBO_BLOCK_SIZE;
|
||||
|
||||
for (U32 i = 0; i < mFreeList.size(); ++i)
|
||||
{
|
||||
|
|
@ -320,8 +306,8 @@ void LLVBOPool::cleanup()
|
|||
{
|
||||
Record& r = l.front();
|
||||
|
||||
glDeleteBuffersARB(1, &r.mGLName);
|
||||
|
||||
deleteBuffer(r.mGLName);
|
||||
|
||||
if (r.mClientData)
|
||||
{
|
||||
ll_aligned_free_16((void*) r.mClientData);
|
||||
|
|
@ -341,8 +327,11 @@ void LLVBOPool::cleanup()
|
|||
}
|
||||
}
|
||||
|
||||
size *= 2;
|
||||
size += LL_VBO_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
//reset miss counts
|
||||
std::fill(mMissCount.begin(), mMissCount.end(), 0);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -376,6 +365,41 @@ U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
|
|||
GL_LINE_LOOP,
|
||||
};
|
||||
|
||||
//static
|
||||
U32 LLVertexBuffer::getVAOName()
|
||||
{
|
||||
U32 ret = 0;
|
||||
|
||||
if (!sAvailableVAOName.empty())
|
||||
{
|
||||
ret = sAvailableVAOName.front();
|
||||
sAvailableVAOName.pop_front();
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef GL_ARB_vertex_array_object
|
||||
glGenVertexArrays(1, &ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLVertexBuffer::releaseVAOName(U32 name)
|
||||
{
|
||||
sAvailableVAOName.push_back(name);
|
||||
}
|
||||
|
||||
|
||||
//static
|
||||
void LLVertexBuffer::seedPools()
|
||||
{
|
||||
sStreamVBOPool.seedPool();
|
||||
sDynamicVBOPool.seedPool();
|
||||
sStreamIBOPool.seedPool();
|
||||
sDynamicIBOPool.seedPool();
|
||||
}
|
||||
|
||||
//static
|
||||
void LLVertexBuffer::setupClientArrays(U32 data_mask)
|
||||
|
|
@ -985,7 +1009,7 @@ LLVertexBuffer::~LLVertexBuffer()
|
|||
if (mGLArray)
|
||||
{
|
||||
#if GL_ARB_vertex_array_object
|
||||
glDeleteVertexArrays(1, &mGLArray);
|
||||
releaseVAOName(mGLArray);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -1211,10 +1235,10 @@ void LLVertexBuffer::updateNumVerts(S32 nverts)
|
|||
|
||||
llassert(nverts >= 0);
|
||||
|
||||
if (nverts >= 65535)
|
||||
if (nverts > 65536)
|
||||
{
|
||||
llwarns << "Vertex buffer overflow!" << llendl;
|
||||
nverts = 65535;
|
||||
nverts = 65536;
|
||||
}
|
||||
|
||||
U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts);
|
||||
|
|
@ -1270,7 +1294,7 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
|
|||
if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO))
|
||||
{
|
||||
#if GL_ARB_vertex_array_object
|
||||
glGenVertexArrays(1, &mGLArray);
|
||||
mGLArray = getVAOName();
|
||||
#endif
|
||||
setupVertexArray();
|
||||
}
|
||||
|
|
@ -1306,7 +1330,7 @@ void LLVertexBuffer::setupVertexArray()
|
|||
1, //TYPE_WEIGHT,
|
||||
4, //TYPE_WEIGHT4,
|
||||
4, //TYPE_CLOTHWEIGHT,
|
||||
4, //TYPE_TEXTURE_INDEX
|
||||
1, //TYPE_TEXTURE_INDEX
|
||||
};
|
||||
|
||||
U32 attrib_type[] =
|
||||
|
|
@ -1323,7 +1347,7 @@ void LLVertexBuffer::setupVertexArray()
|
|||
GL_FLOAT, //TYPE_WEIGHT,
|
||||
GL_FLOAT, //TYPE_WEIGHT4,
|
||||
GL_FLOAT, //TYPE_CLOTHWEIGHT,
|
||||
GL_UNSIGNED_BYTE, //TYPE_TEXTURE_INDEX
|
||||
GL_UNSIGNED_INT, //TYPE_TEXTURE_INDEX
|
||||
};
|
||||
|
||||
bool attrib_integer[] =
|
||||
|
|
@ -2140,6 +2164,16 @@ void LLVertexBuffer::flush()
|
|||
}
|
||||
}
|
||||
|
||||
// bind for transform feedback (quick 'n dirty)
|
||||
void LLVertexBuffer::bindForFeedback(U32 channel, U32 type, U32 index, U32 count)
|
||||
{
|
||||
#ifdef GL_TRANSFORM_FEEDBACK_BUFFER
|
||||
U32 offset = mOffsets[type] + sTypeSize[type]*index;
|
||||
U32 size= (sTypeSize[type]*count);
|
||||
glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, channel, mGLBuffer, offset, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set for rendering
|
||||
void LLVertexBuffer::setBuffer(U32 data_mask)
|
||||
{
|
||||
|
|
@ -2291,10 +2325,10 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
|
|||
stop_glerror();
|
||||
volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
|
||||
|
||||
/*if ((data_mask & mTypeMask) != data_mask)
|
||||
if (gDebugGL && ((data_mask & mTypeMask) != data_mask))
|
||||
{
|
||||
llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
|
||||
}*/
|
||||
}
|
||||
|
||||
if (LLGLSLShader::sNoFixedFunction)
|
||||
{
|
||||
|
|
@ -2370,7 +2404,7 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
|
|||
#if !LL_DARWIN
|
||||
S32 loc = TYPE_TEXTURE_INDEX;
|
||||
void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12);
|
||||
glVertexAttribIPointer(loc, 4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
|
||||
glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
|
||||
#endif
|
||||
}
|
||||
if (data_mask & MAP_VERTEX)
|
||||
|
|
|
|||
|
|
@ -57,23 +57,28 @@ public:
|
|||
static U32 sBytesPooled;
|
||||
static U32 sIndexBytesPooled;
|
||||
|
||||
LLVBOPool(U32 vboUsage, U32 vboType)
|
||||
: mUsage(vboUsage)
|
||||
, mType(vboType)
|
||||
{}
|
||||
static U32 sCurGLName;
|
||||
|
||||
LLVBOPool(U32 vboUsage, U32 vboType);
|
||||
|
||||
const U32 mUsage;
|
||||
const U32 mType;
|
||||
|
||||
//size MUST be a power of 2
|
||||
volatile U8* allocate(U32& name, U32 size);
|
||||
volatile U8* allocate(U32& name, U32 size, bool for_seed = false);
|
||||
|
||||
//size MUST be the size provided to allocate that returned the given name
|
||||
void release(U32 name, volatile U8* buffer, U32 size);
|
||||
|
||||
//batch allocate buffers to be provided to the application on demand
|
||||
void seedPool();
|
||||
|
||||
//destroy all records in mFreeList
|
||||
void cleanup();
|
||||
|
||||
U32 genBuffer();
|
||||
void deleteBuffer(U32 name);
|
||||
|
||||
class Record
|
||||
{
|
||||
public:
|
||||
|
|
@ -81,16 +86,14 @@ public:
|
|||
volatile U8* mClientData;
|
||||
};
|
||||
|
||||
std::list<U32> mGLNamePool;
|
||||
|
||||
typedef std::list<Record> record_list_t;
|
||||
std::vector<record_list_t> mFreeList;
|
||||
std::vector<U32> mMissCount;
|
||||
|
||||
};
|
||||
|
||||
class LLGLFence
|
||||
{
|
||||
public:
|
||||
virtual void placeFence() = 0;
|
||||
virtual void wait() = 0;
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
// base class
|
||||
|
|
@ -125,13 +128,22 @@ public:
|
|||
static LLVBOPool sStreamIBOPool;
|
||||
static LLVBOPool sDynamicIBOPool;
|
||||
|
||||
static std::list<U32> sAvailableVAOName;
|
||||
static U32 sCurVAOName;
|
||||
|
||||
static bool sUseStreamDraw;
|
||||
static bool sUseVAO;
|
||||
static bool sPreferStreamDraw;
|
||||
|
||||
static void seedPools();
|
||||
|
||||
static U32 getVAOName();
|
||||
static void releaseVAOName(U32 name);
|
||||
|
||||
static void initClass(bool use_vbo, bool no_vbo_mapping);
|
||||
static void cleanupClass();
|
||||
static void setupClientArrays(U32 data_mask);
|
||||
static void pushPositions(U32 mode, const LLVector4a* pos, U32 count);
|
||||
static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm);
|
||||
static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp);
|
||||
|
||||
|
|
@ -208,7 +220,6 @@ protected:
|
|||
void destroyGLIndices();
|
||||
void updateNumVerts(S32 nverts);
|
||||
void updateNumIndices(S32 nindices);
|
||||
bool useVBOs() const;
|
||||
void unmapBuffer();
|
||||
|
||||
public:
|
||||
|
|
@ -218,6 +229,8 @@ public:
|
|||
volatile U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range);
|
||||
volatile U8* mapIndexBuffer(S32 index, S32 count, bool map_range);
|
||||
|
||||
void bindForFeedback(U32 channel, U32 type, U32 index, U32 count);
|
||||
|
||||
// set for rendering
|
||||
virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0
|
||||
void flush(); //flush pending data to GL memory
|
||||
|
|
@ -240,12 +253,14 @@ public:
|
|||
bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getTextureIndexStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getWeightStrider(LLStrider<F32>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
|
||||
|
||||
bool useVBOs() const;
|
||||
bool isEmpty() const { return mEmpty; }
|
||||
bool isLocked() const { return mVertexLocked || mIndexLocked; }
|
||||
S32 getNumVerts() const { return mNumVerts; }
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ include_directories(
|
|||
${LLWINDOW_INCLUDE_DIRS}
|
||||
${LLVFS_INCLUDE_DIRS}
|
||||
${LLXML_INCLUDE_DIRS}
|
||||
${LIBS_PREBUILD_DIR}/include/hunspell
|
||||
)
|
||||
|
||||
set(llui_SOURCE_FILES
|
||||
|
|
@ -84,6 +85,7 @@ set(llui_SOURCE_FILES
|
|||
llsearcheditor.cpp
|
||||
llslider.cpp
|
||||
llsliderctrl.cpp
|
||||
llspellcheck.cpp
|
||||
llspinctrl.cpp
|
||||
llstatbar.cpp
|
||||
llstatgraph.cpp
|
||||
|
|
@ -191,6 +193,8 @@ set(llui_HEADER_FILES
|
|||
llscrolllistitem.h
|
||||
llsliderctrl.h
|
||||
llslider.h
|
||||
llspellcheck.h
|
||||
llspellcheckmenuhandler.h
|
||||
llspinctrl.h
|
||||
llstatbar.h
|
||||
llstatgraph.h
|
||||
|
|
@ -260,6 +264,7 @@ target_link_libraries(llui
|
|||
${LLXUIXML_LIBRARIES}
|
||||
${LLXML_LIBRARIES}
|
||||
${LLMATH_LIBRARIES}
|
||||
${HUNSPELL_LIBRARY}
|
||||
${LLCOMMON_LIBRARIES} # must be after llimage, llwindow, llrender
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
#include "llkeyboard.h"
|
||||
#include "llrect.h"
|
||||
#include "llresmgr.h"
|
||||
#include "llspellcheck.h"
|
||||
#include "llstring.h"
|
||||
#include "llwindow.h"
|
||||
#include "llui.h"
|
||||
|
|
@ -65,6 +66,7 @@ const S32 SCROLL_INCREMENT_ADD = 0; // make space for typing
|
|||
const S32 SCROLL_INCREMENT_DEL = 4; // make space for baskspacing
|
||||
const F32 AUTO_SCROLL_TIME = 0.05f;
|
||||
const F32 TRIPLE_CLICK_INTERVAL = 0.3f; // delay between double and triple click. *TODO: make this equal to the double click interval?
|
||||
const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on
|
||||
|
||||
const std::string PASSWORD_ASTERISK( "\xE2\x80\xA2" ); // U+2022 BULLET
|
||||
|
||||
|
|
@ -88,6 +90,7 @@ LLLineEditor::Params::Params()
|
|||
background_image_focused("background_image_focused"),
|
||||
select_on_focus("select_on_focus", false),
|
||||
revert_on_esc("revert_on_esc", true),
|
||||
spellcheck("spellcheck", false),
|
||||
commit_on_focus_lost("commit_on_focus_lost", true),
|
||||
ignore_tab("ignore_tab", true),
|
||||
is_password("is_password", false),
|
||||
|
|
@ -134,6 +137,9 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
|
|||
mIgnoreArrowKeys( FALSE ),
|
||||
mIgnoreTab( p.ignore_tab ),
|
||||
mDrawAsterixes( p.is_password ),
|
||||
mSpellCheck( p.spellcheck ),
|
||||
mSpellCheckStart(-1),
|
||||
mSpellCheckEnd(-1),
|
||||
mSelectAllonFocusReceived( p.select_on_focus ),
|
||||
mSelectAllonCommit( TRUE ),
|
||||
mPassDelete(FALSE),
|
||||
|
|
@ -151,7 +157,8 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
|
|||
mHighlightColor(p.highlight_color()),
|
||||
mPreeditBgColor(p.preedit_bg_color()),
|
||||
mGLFont(p.font),
|
||||
mContextMenuHandle()
|
||||
mContextMenuHandle(),
|
||||
mAutoreplaceCallback()
|
||||
{
|
||||
llassert( mMaxLengthBytes > 0 );
|
||||
|
||||
|
|
@ -177,6 +184,12 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
|
|||
updateTextPadding();
|
||||
setCursor(mText.length());
|
||||
|
||||
if (mSpellCheck)
|
||||
{
|
||||
LLSpellChecker::setSettingsChangeCallback(boost::bind(&LLLineEditor::onSpellCheckSettingsChange, this));
|
||||
}
|
||||
mSpellCheckTimer.reset();
|
||||
|
||||
setPrevalidateInput(p.prevalidate_input_callback());
|
||||
setPrevalidate(p.prevalidate_callback());
|
||||
|
||||
|
|
@ -195,7 +208,6 @@ LLLineEditor::~LLLineEditor()
|
|||
gFocusMgr.releaseFocusIfNeeded( this );
|
||||
}
|
||||
|
||||
|
||||
void LLLineEditor::onFocusReceived()
|
||||
{
|
||||
gEditMenuHandler = this;
|
||||
|
|
@ -519,6 +531,99 @@ void LLLineEditor::selectAll()
|
|||
updatePrimary();
|
||||
}
|
||||
|
||||
bool LLLineEditor::getSpellCheck() const
|
||||
{
|
||||
return (LLSpellChecker::getUseSpellCheck()) && (!mReadOnly) && (mSpellCheck);
|
||||
}
|
||||
|
||||
const std::string& LLLineEditor::getSuggestion(U32 index) const
|
||||
{
|
||||
return (index < mSuggestionList.size()) ? mSuggestionList[index] : LLStringUtil::null;
|
||||
}
|
||||
|
||||
U32 LLLineEditor::getSuggestionCount() const
|
||||
{
|
||||
return mSuggestionList.size();
|
||||
}
|
||||
|
||||
void LLLineEditor::replaceWithSuggestion(U32 index)
|
||||
{
|
||||
for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it)
|
||||
{
|
||||
if ( (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) )
|
||||
{
|
||||
deselect();
|
||||
|
||||
// Delete the misspelled word
|
||||
mText.erase(it->first, it->second - it->first);
|
||||
|
||||
// Insert the suggestion in its place
|
||||
LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]);
|
||||
mText.insert(it->first, suggestion);
|
||||
setCursor(it->first + (S32)suggestion.length());
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
mSpellCheckStart = mSpellCheckEnd = -1;
|
||||
}
|
||||
|
||||
void LLLineEditor::addToDictionary()
|
||||
{
|
||||
if (canAddToDictionary())
|
||||
{
|
||||
LLSpellChecker::instance().addToCustomDictionary(getMisspelledWord(mCursorPos));
|
||||
}
|
||||
}
|
||||
|
||||
bool LLLineEditor::canAddToDictionary() const
|
||||
{
|
||||
return (getSpellCheck()) && (isMisspelledWord(mCursorPos));
|
||||
}
|
||||
|
||||
void LLLineEditor::addToIgnore()
|
||||
{
|
||||
if (canAddToIgnore())
|
||||
{
|
||||
LLSpellChecker::instance().addToIgnoreList(getMisspelledWord(mCursorPos));
|
||||
}
|
||||
}
|
||||
|
||||
bool LLLineEditor::canAddToIgnore() const
|
||||
{
|
||||
return (getSpellCheck()) && (isMisspelledWord(mCursorPos));
|
||||
}
|
||||
|
||||
std::string LLLineEditor::getMisspelledWord(U32 pos) const
|
||||
{
|
||||
for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it)
|
||||
{
|
||||
if ( (it->first <= pos) && (it->second >= pos) )
|
||||
{
|
||||
return wstring_to_utf8str(mText.getWString().substr(it->first, it->second - it->first));
|
||||
}
|
||||
}
|
||||
return LLStringUtil::null;
|
||||
}
|
||||
|
||||
bool LLLineEditor::isMisspelledWord(U32 pos) const
|
||||
{
|
||||
for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it)
|
||||
{
|
||||
if ( (it->first <= pos) && (it->second >= pos) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLLineEditor::onSpellCheckSettingsChange()
|
||||
{
|
||||
// Recheck the spelling on every change
|
||||
mMisspellRanges.clear();
|
||||
mSpellCheckStart = mSpellCheckEnd = -1;
|
||||
}
|
||||
|
||||
BOOL LLLineEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
|
|
@ -866,6 +971,12 @@ void LLLineEditor::addChar(const llwchar uni_char)
|
|||
LLUI::reportBadKeystroke();
|
||||
}
|
||||
|
||||
if (!mReadOnly && mAutoreplaceCallback != NULL)
|
||||
{
|
||||
// call callback
|
||||
mAutoreplaceCallback(mText, mCursorPos);
|
||||
}
|
||||
|
||||
getWindow()->hideCursorUntilMouseMove();
|
||||
}
|
||||
|
||||
|
|
@ -1058,9 +1169,8 @@ void LLLineEditor::cut()
|
|||
LLUI::reportBadKeystroke();
|
||||
}
|
||||
else
|
||||
if( mKeystrokeCallback )
|
||||
{
|
||||
mKeystrokeCallback( this );
|
||||
onKeystroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1187,9 +1297,8 @@ void LLLineEditor::pasteHelper(bool is_primary)
|
|||
LLUI::reportBadKeystroke();
|
||||
}
|
||||
else
|
||||
if( mKeystrokeCallback )
|
||||
{
|
||||
mKeystrokeCallback( this );
|
||||
onKeystroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1442,9 +1551,10 @@ BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask )
|
|||
// Notify owner if requested
|
||||
if (!need_to_rollback && handled)
|
||||
{
|
||||
if (mKeystrokeCallback)
|
||||
onKeystroke();
|
||||
if ( (!selection_modified) && (KEY_BACKSPACE == key) )
|
||||
{
|
||||
mKeystrokeCallback(this);
|
||||
mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1497,12 +1607,11 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char)
|
|||
// Notify owner if requested
|
||||
if( !need_to_rollback && handled )
|
||||
{
|
||||
if( mKeystrokeCallback )
|
||||
{
|
||||
// HACK! The only usage of this callback doesn't do anything with the character.
|
||||
// We'll have to do something about this if something ever changes! - Doug
|
||||
mKeystrokeCallback( this );
|
||||
}
|
||||
// HACK! The only usage of this callback doesn't do anything with the character.
|
||||
// We'll have to do something about this if something ever changes! - Doug
|
||||
onKeystroke();
|
||||
|
||||
mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY);
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
|
|
@ -1531,9 +1640,7 @@ void LLLineEditor::doDelete()
|
|||
|
||||
if (!prevalidateInput(text_to_delete))
|
||||
{
|
||||
if( mKeystrokeCallback )
|
||||
mKeystrokeCallback( this );
|
||||
|
||||
onKeystroke();
|
||||
return;
|
||||
}
|
||||
setCursor(getCursor() + 1);
|
||||
|
|
@ -1549,10 +1656,9 @@ void LLLineEditor::doDelete()
|
|||
}
|
||||
else
|
||||
{
|
||||
if( mKeystrokeCallback )
|
||||
{
|
||||
mKeystrokeCallback( this );
|
||||
}
|
||||
onKeystroke();
|
||||
|
||||
mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1624,6 +1730,10 @@ void LLLineEditor::draw()
|
|||
background.stretch( -mBorderThickness );
|
||||
|
||||
S32 lineeditor_v_pad = (background.getHeight() - mGLFont->getLineHeight()) / 2;
|
||||
if (mSpellCheck)
|
||||
{
|
||||
lineeditor_v_pad += 1;
|
||||
}
|
||||
|
||||
drawBackground();
|
||||
|
||||
|
|
@ -1698,14 +1808,14 @@ void LLLineEditor::draw()
|
|||
{
|
||||
S32 select_left;
|
||||
S32 select_right;
|
||||
if( mSelectionStart < getCursor() )
|
||||
if (mSelectionStart < mSelectionEnd)
|
||||
{
|
||||
select_left = mSelectionStart;
|
||||
select_right = getCursor();
|
||||
select_right = mSelectionEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
select_left = getCursor();
|
||||
select_left = mSelectionEnd;
|
||||
select_right = mSelectionStart;
|
||||
}
|
||||
|
||||
|
|
@ -1749,7 +1859,7 @@ void LLLineEditor::draw()
|
|||
if( (rendered_pixels_right < (F32)mTextRightEdge) && (rendered_text < text_len) )
|
||||
{
|
||||
// unselected, right side
|
||||
mGLFont->render(
|
||||
rendered_text += mGLFont->render(
|
||||
mText, mScrollHPos + rendered_text,
|
||||
rendered_pixels_right, text_bottom,
|
||||
text_color,
|
||||
|
|
@ -1763,7 +1873,7 @@ void LLLineEditor::draw()
|
|||
}
|
||||
else
|
||||
{
|
||||
mGLFont->render(
|
||||
rendered_text = mGLFont->render(
|
||||
mText, mScrollHPos,
|
||||
rendered_pixels_right, text_bottom,
|
||||
text_color,
|
||||
|
|
@ -1778,6 +1888,101 @@ void LLLineEditor::draw()
|
|||
mBorder->setVisible(FALSE); // no more programmatic art.
|
||||
#endif
|
||||
|
||||
if ( (getSpellCheck()) && (mText.length() > 2) )
|
||||
{
|
||||
// Calculate start and end indices for the first and last visible word
|
||||
U32 start = prevWordPos(mScrollHPos), end = nextWordPos(mScrollHPos + rendered_text);
|
||||
|
||||
if ( (mSpellCheckStart != start) || (mSpellCheckEnd != end) )
|
||||
{
|
||||
const LLWString& text = mText.getWString().substr(start, end);
|
||||
|
||||
// Find the start of the first word
|
||||
U32 word_start = 0, word_end = 0;
|
||||
while ( (word_start < text.length()) && (!LLStringOps::isAlpha(text[word_start])) )
|
||||
{
|
||||
word_start++;
|
||||
}
|
||||
|
||||
// Iterate over all words in the text block and check them one by one
|
||||
mMisspellRanges.clear();
|
||||
while (word_start < text.length())
|
||||
{
|
||||
// Find the end of the current word (special case handling for "'" when it's used as a contraction)
|
||||
word_end = word_start + 1;
|
||||
while ( (word_end < text.length()) &&
|
||||
((LLWStringUtil::isPartOfWord(text[word_end])) ||
|
||||
((L'\'' == text[word_end]) && (word_end + 1 < text.length()) &&
|
||||
(LLStringOps::isAlnum(text[word_end - 1])) && (LLStringOps::isAlnum(text[word_end + 1])))) )
|
||||
{
|
||||
word_end++;
|
||||
}
|
||||
if (word_end > text.length())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Don't process words shorter than 3 characters
|
||||
std::string word = wstring_to_utf8str(text.substr(word_start, word_end - word_start));
|
||||
if ( (word.length() >= 3) && (!LLSpellChecker::instance().checkSpelling(word)) )
|
||||
{
|
||||
mMisspellRanges.push_back(std::pair<U32, U32>(start + word_start, start + word_end));
|
||||
}
|
||||
|
||||
// Find the start of the next word
|
||||
word_start = word_end + 1;
|
||||
while ( (word_start < text.length()) && (!LLWStringUtil::isPartOfWord(text[word_start])) )
|
||||
{
|
||||
word_start++;
|
||||
}
|
||||
}
|
||||
|
||||
mSpellCheckStart = start;
|
||||
mSpellCheckEnd = end;
|
||||
}
|
||||
|
||||
// Draw squiggly lines under any (visible) misspelled words
|
||||
for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it)
|
||||
{
|
||||
// Skip over words that aren't (partially) visible
|
||||
if ( ((it->first < start) && (it->second < start)) || (it->first > end) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip the current word if the user is still busy editing it
|
||||
if ( (!mSpellCheckTimer.hasExpired()) && (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
S32 pxWidth = getRect().getWidth();
|
||||
S32 pxStart = findPixelNearestPos(it->first - getCursor());
|
||||
if (pxStart > pxWidth)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
S32 pxEnd = findPixelNearestPos(it->second - getCursor());
|
||||
if (pxEnd > pxWidth)
|
||||
{
|
||||
pxEnd = pxWidth;
|
||||
}
|
||||
|
||||
S32 pxBottom = (S32)(text_bottom + mGLFont->getDescenderHeight());
|
||||
|
||||
gGL.color4ub(255, 0, 0, 200);
|
||||
while (pxStart + 1 < pxEnd)
|
||||
{
|
||||
gl_line_2d(pxStart, pxBottom, pxStart + 2, pxBottom - 2);
|
||||
if (pxStart + 3 < pxEnd)
|
||||
{
|
||||
gl_line_2d(pxStart + 2, pxBottom - 3, pxStart + 4, pxBottom - 1);
|
||||
}
|
||||
pxStart += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we're editing...
|
||||
if( hasFocus())
|
||||
{
|
||||
|
|
@ -2109,6 +2314,15 @@ void LLLineEditor::setSelectAllonFocusReceived(BOOL b)
|
|||
mSelectAllonFocusReceived = b;
|
||||
}
|
||||
|
||||
void LLLineEditor::onKeystroke()
|
||||
{
|
||||
if (mKeystrokeCallback)
|
||||
{
|
||||
mKeystrokeCallback(this);
|
||||
}
|
||||
|
||||
mSpellCheckStart = mSpellCheckEnd = -1;
|
||||
}
|
||||
|
||||
void LLLineEditor::setKeystrokeCallback(callback_t callback, void* user_data)
|
||||
{
|
||||
|
|
@ -2231,10 +2445,9 @@ void LLLineEditor::updatePreedit(const LLWString &preedit_string,
|
|||
|
||||
// Update of the preedit should be caused by some key strokes.
|
||||
mKeystrokeTimer.reset();
|
||||
if( mKeystrokeCallback )
|
||||
{
|
||||
mKeystrokeCallback( this );
|
||||
}
|
||||
onKeystroke();
|
||||
|
||||
mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY);
|
||||
}
|
||||
|
||||
BOOL LLLineEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const
|
||||
|
|
@ -2386,7 +2599,38 @@ void LLLineEditor::showContextMenu(S32 x, S32 y)
|
|||
|
||||
S32 screen_x, screen_y;
|
||||
localPointToScreen(x, y, &screen_x, &screen_y);
|
||||
menu->show(screen_x, screen_y);
|
||||
|
||||
setCursorAtLocalPos(x);
|
||||
if (hasSelection())
|
||||
{
|
||||
if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) )
|
||||
{
|
||||
deselect();
|
||||
}
|
||||
else
|
||||
{
|
||||
setCursor(llmax(mSelectionStart, mSelectionEnd));
|
||||
}
|
||||
}
|
||||
|
||||
bool use_spellcheck = getSpellCheck(), is_misspelled = false;
|
||||
if (use_spellcheck)
|
||||
{
|
||||
mSuggestionList.clear();
|
||||
|
||||
// If the cursor is on a misspelled word, retrieve suggestions for it
|
||||
std::string misspelled_word = getMisspelledWord(mCursorPos);
|
||||
if ((is_misspelled = !misspelled_word.empty()) == true)
|
||||
{
|
||||
LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList);
|
||||
}
|
||||
}
|
||||
|
||||
menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty()));
|
||||
menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled));
|
||||
menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled));
|
||||
menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled));
|
||||
menu->show(screen_x, screen_y, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include "llframetimer.h"
|
||||
|
||||
#include "lleditmenuhandler.h"
|
||||
#include "llspellcheckmenuhandler.h"
|
||||
#include "lluictrl.h"
|
||||
#include "lluiimage.h"
|
||||
#include "lluistring.h"
|
||||
|
|
@ -54,7 +55,7 @@ class LLButton;
|
|||
class LLContextMenu;
|
||||
|
||||
class LLLineEditor
|
||||
: public LLUICtrl, public LLEditMenuHandler, protected LLPreeditor
|
||||
: public LLUICtrl, public LLEditMenuHandler, protected LLPreeditor, public LLSpellCheckMenuHandler
|
||||
{
|
||||
public:
|
||||
|
||||
|
|
@ -86,6 +87,7 @@ public:
|
|||
|
||||
Optional<bool> select_on_focus,
|
||||
revert_on_esc,
|
||||
spellcheck,
|
||||
commit_on_focus_lost,
|
||||
ignore_tab,
|
||||
is_password;
|
||||
|
|
@ -146,6 +148,24 @@ public:
|
|||
virtual void deselect();
|
||||
virtual BOOL canDeselect() const;
|
||||
|
||||
// LLSpellCheckMenuHandler overrides
|
||||
/*virtual*/ bool getSpellCheck() const;
|
||||
|
||||
/*virtual*/ const std::string& getSuggestion(U32 index) const;
|
||||
/*virtual*/ U32 getSuggestionCount() const;
|
||||
/*virtual*/ void replaceWithSuggestion(U32 index);
|
||||
|
||||
/*virtual*/ void addToDictionary();
|
||||
/*virtual*/ bool canAddToDictionary() const;
|
||||
|
||||
/*virtual*/ void addToIgnore();
|
||||
/*virtual*/ bool canAddToIgnore() const;
|
||||
|
||||
// Spell checking helper functions
|
||||
std::string getMisspelledWord(U32 pos) const;
|
||||
bool isMisspelledWord(U32 pos) const;
|
||||
void onSpellCheckSettingsChange();
|
||||
|
||||
// view overrides
|
||||
virtual void draw();
|
||||
virtual void reshape(S32 width,S32 height,BOOL called_from_parent=TRUE);
|
||||
|
|
@ -169,6 +189,9 @@ public:
|
|||
virtual BOOL setTextArg( const std::string& key, const LLStringExplicit& text );
|
||||
virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text );
|
||||
|
||||
typedef boost::function<void(LLUIString&, S32&)> autoreplace_callback_t;
|
||||
autoreplace_callback_t mAutoreplaceCallback;
|
||||
void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; }
|
||||
void setLabel(const LLStringExplicit &new_label) { mLabel = new_label; }
|
||||
const std::string& getLabel() { return mLabel.getString(); }
|
||||
|
||||
|
|
@ -223,6 +246,7 @@ public:
|
|||
void setSelectAllonFocusReceived(BOOL b);
|
||||
void setSelectAllonCommit(BOOL b) { mSelectAllonCommit = b; }
|
||||
|
||||
void onKeystroke();
|
||||
typedef boost::function<void (LLLineEditor* caller, void* user_data)> callback_t;
|
||||
void setKeystrokeCallback(callback_t callback, void* user_data);
|
||||
|
||||
|
|
@ -322,6 +346,13 @@ protected:
|
|||
S32 mLastSelectionStart;
|
||||
S32 mLastSelectionEnd;
|
||||
|
||||
bool mSpellCheck;
|
||||
S32 mSpellCheckStart;
|
||||
S32 mSpellCheckEnd;
|
||||
LLTimer mSpellCheckTimer;
|
||||
std::list<std::pair<U32, U32> > mMisspellRanges;
|
||||
std::vector<std::string> mSuggestionList;
|
||||
|
||||
LLTextValidate::validate_func_t mPrevalidateFunc;
|
||||
LLTextValidate::validate_func_t mPrevalidateInputFunc;
|
||||
|
||||
|
|
|
|||
|
|
@ -3854,7 +3854,7 @@ void LLContextMenu::setVisible(BOOL visible)
|
|||
}
|
||||
|
||||
// Takes cursor position in screen space?
|
||||
void LLContextMenu::show(S32 x, S32 y)
|
||||
void LLContextMenu::show(S32 x, S32 y, LLView* spawning_view)
|
||||
{
|
||||
if (getChildList()->empty())
|
||||
{
|
||||
|
|
@ -3908,6 +3908,14 @@ void LLContextMenu::show(S32 x, S32 y)
|
|||
setRect(rect);
|
||||
arrange();
|
||||
|
||||
if (spawning_view)
|
||||
{
|
||||
mSpawningViewHandle = spawning_view->getHandle();
|
||||
}
|
||||
else
|
||||
{
|
||||
mSpawningViewHandle.markDead();
|
||||
}
|
||||
LLView::setVisible(TRUE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -670,7 +670,7 @@ public:
|
|||
|
||||
virtual void draw ();
|
||||
|
||||
virtual void show (S32 x, S32 y);
|
||||
virtual void show (S32 x, S32 y, LLView* spawning_view = NULL);
|
||||
virtual void hide ();
|
||||
|
||||
virtual BOOL handleHover ( S32 x, S32 y, MASK mask );
|
||||
|
|
@ -683,10 +683,14 @@ public:
|
|||
|
||||
LLHandle<LLContextMenu> getHandle() { return getDerivedHandle<LLContextMenu>(); }
|
||||
|
||||
LLView* getSpawningView() const { return mSpawningViewHandle.get(); }
|
||||
void setSpawningView(LLHandle<LLView> spawning_view) { mSpawningViewHandle = spawning_view; }
|
||||
|
||||
protected:
|
||||
BOOL mHoveredAnyItem;
|
||||
LLMenuItemGL* mHoverItem;
|
||||
LLRootHandle<LLContextMenu> mHandle;
|
||||
LLHandle<LLView> mSpawningViewHandle;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -389,12 +389,11 @@ void LLScrollContainer::calcVisibleSize( S32 *visible_width, S32 *visible_height
|
|||
{
|
||||
*show_h_scrollbar = TRUE;
|
||||
*visible_height -= scrollbar_size;
|
||||
|
||||
// Note: Do *not* recompute *show_v_scrollbar here because with
|
||||
// The view inside the scroll container should not be extended
|
||||
// to container's full height to ensure the correct computation
|
||||
// of *show_v_scrollbar after subtracting horizontal scrollbar_size.
|
||||
|
||||
// Must retest now that visible_height has changed
|
||||
if( !*show_v_scrollbar && ((doc_height - *visible_height) > 1) )
|
||||
{
|
||||
*show_v_scrollbar = TRUE;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,505 @@
|
|||
/**
|
||||
* @file llspellcheck.cpp
|
||||
* @brief Spell checking functionality
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "lldir.h"
|
||||
#include "llsdserialize.h"
|
||||
|
||||
#include "llspellcheck.h"
|
||||
#if LL_WINDOWS
|
||||
#include <hunspell/hunspelldll.h>
|
||||
#pragma comment(lib, "libhunspell.lib")
|
||||
#else
|
||||
#include <hunspell/hunspell.hxx>
|
||||
#endif
|
||||
|
||||
static const std::string DICT_DIR = "dictionaries";
|
||||
static const std::string DICT_FILE_CUSTOM = "user_custom.dic";
|
||||
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()
|
||||
{
|
||||
delete mHunspell;
|
||||
}
|
||||
|
||||
bool LLSpellChecker::checkSpelling(const std::string& word) const
|
||||
{
|
||||
if ( (!mHunspell) || (word.length() < 3) || (0 != mHunspell->spell(word.c_str())) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (mIgnoreList.size() > 0)
|
||||
{
|
||||
std::string word_lower(word);
|
||||
LLStringUtil::toLower(word_lower);
|
||||
return (mIgnoreList.end() != std::find(mIgnoreList.begin(), mIgnoreList.end(), word_lower));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
S32 LLSpellChecker::getSuggestions(const std::string& word, std::vector<std::string>& suggestions) const
|
||||
{
|
||||
suggestions.clear();
|
||||
if ( (!mHunspell) || (word.length() < 3) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
char** suggestion_list; int suggestion_cnt = 0;
|
||||
if ( (suggestion_cnt = mHunspell->suggest(&suggestion_list, word.c_str())) != 0 )
|
||||
{
|
||||
for (int suggestion_index = 0; suggestion_index < suggestion_cnt; suggestion_index++)
|
||||
{
|
||||
suggestions.push_back(suggestion_list[suggestion_index]);
|
||||
}
|
||||
mHunspell->free_list(&suggestion_list, suggestion_cnt);
|
||||
}
|
||||
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)
|
||||
{
|
||||
const LLSD& dict_entry = *it;
|
||||
if (dict_language == dict_entry["language"].asString())
|
||||
{
|
||||
return dict_entry;
|
||||
}
|
||||
}
|
||||
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();
|
||||
if (dict_language.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (LLSD::array_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it)
|
||||
{
|
||||
LLSD& dict_entry = *it;
|
||||
if (dict_language == dict_entry["language"].asString())
|
||||
{
|
||||
dict_entry = dict_info;
|
||||
return;
|
||||
}
|
||||
}
|
||||
sDictMap.append(dict_info);
|
||||
return;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLSpellChecker::refreshDictionaryMap()
|
||||
{
|
||||
const std::string app_path = getDictionaryAppPath();
|
||||
const std::string user_path = getDictionaryUserPath();
|
||||
|
||||
// Load dictionary information (file name, friendly name, ...)
|
||||
llifstream user_file(user_path + DICT_FILE_MAIN, std::ios::binary);
|
||||
if ( (!user_file.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, user_file)) || (0 == sDictMap.size()) )
|
||||
{
|
||||
llifstream app_file(app_path + DICT_FILE_MAIN, std::ios::binary);
|
||||
if ( (!app_file.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, app_file)) || (0 == sDictMap.size()) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Load user installed dictionary information
|
||||
llifstream custom_file(user_path + DICT_FILE_USER, std::ios::binary);
|
||||
if (custom_file.is_open())
|
||||
{
|
||||
LLSD custom_dict_map;
|
||||
LLSDSerialize::fromXMLDocument(custom_dict_map, custom_file);
|
||||
for (LLSD::array_iterator it = custom_dict_map.beginArray(); it != custom_dict_map.endArray(); ++it)
|
||||
{
|
||||
LLSD& dict_info = *it;
|
||||
dict_info["user_installed"] = true;
|
||||
setDictionaryData(dict_info);
|
||||
}
|
||||
custom_file.close();
|
||||
}
|
||||
|
||||
// Look for installed dictionaries
|
||||
std::string tmp_app_path, tmp_user_path;
|
||||
for (LLSD::array_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it)
|
||||
{
|
||||
LLSD& sdDict = *it;
|
||||
tmp_app_path = (sdDict.has("name")) ? app_path + sdDict["name"].asString() : LLStringUtil::null;
|
||||
tmp_user_path = (sdDict.has("name")) ? user_path + sdDict["name"].asString() : LLStringUtil::null;
|
||||
sdDict["installed"] =
|
||||
(!tmp_app_path.empty()) && ((gDirUtilp->fileExists(tmp_user_path + ".dic")) || (gDirUtilp->fileExists(tmp_app_path + ".dic")));
|
||||
}
|
||||
|
||||
sSettingsChangeSignal();
|
||||
}
|
||||
|
||||
void LLSpellChecker::addToCustomDictionary(const std::string& word)
|
||||
{
|
||||
if (mHunspell)
|
||||
{
|
||||
mHunspell->add(word.c_str());
|
||||
}
|
||||
addToDictFile(getDictionaryUserPath() + DICT_FILE_CUSTOM, word);
|
||||
sSettingsChangeSignal();
|
||||
}
|
||||
|
||||
void LLSpellChecker::addToIgnoreList(const std::string& word)
|
||||
{
|
||||
std::string word_lower(word);
|
||||
LLStringUtil::toLower(word_lower);
|
||||
if (mIgnoreList.end() == std::find(mIgnoreList.begin(), mIgnoreList.end(), word_lower))
|
||||
{
|
||||
mIgnoreList.push_back(word_lower);
|
||||
addToDictFile(getDictionaryUserPath() + DICT_FILE_IGNORE, word_lower);
|
||||
sSettingsChangeSignal();
|
||||
}
|
||||
}
|
||||
|
||||
void LLSpellChecker::addToDictFile(const std::string& dict_path, const std::string& word)
|
||||
{
|
||||
std::vector<std::string> word_list;
|
||||
|
||||
if (gDirUtilp->fileExists(dict_path))
|
||||
{
|
||||
llifstream file_in(dict_path, std::ios::in);
|
||||
if (file_in.is_open())
|
||||
{
|
||||
std::string word; int line_num = 0;
|
||||
while (getline(file_in, word))
|
||||
{
|
||||
// Skip over the first line since that's just a line count
|
||||
if (0 != line_num)
|
||||
{
|
||||
word_list.push_back(word);
|
||||
}
|
||||
line_num++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: show error message?
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
word_list.push_back(word);
|
||||
|
||||
llofstream file_out(dict_path, std::ios::out | std::ios::trunc);
|
||||
if (file_out.is_open())
|
||||
{
|
||||
file_out << word_list.size() << std::endl;
|
||||
for (std::vector<std::string>::const_iterator itWord = word_list.begin(); itWord != word_list.end(); ++itWord)
|
||||
{
|
||||
file_out << *itWord << std::endl;
|
||||
}
|
||||
file_out.close();
|
||||
}
|
||||
}
|
||||
|
||||
bool LLSpellChecker::isActiveDictionary(const std::string& dict_language) const
|
||||
{
|
||||
return
|
||||
(mDictLanguage == dict_language) ||
|
||||
(mDictSecondary.end() != std::find(mDictSecondary.begin(), mDictSecondary.end(), dict_language));
|
||||
}
|
||||
|
||||
void LLSpellChecker::setSecondaryDictionaries(dict_list_t dict_list)
|
||||
{
|
||||
if (!getUseSpellCheck())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we're only adding secondary dictionaries, or removing them
|
||||
dict_list_t dict_add(llmax(dict_list.size(), mDictSecondary.size())), dict_rem(llmax(dict_list.size(), mDictSecondary.size()));
|
||||
dict_list.sort();
|
||||
mDictSecondary.sort();
|
||||
dict_list_t::iterator end_added = std::set_difference(dict_list.begin(), dict_list.end(), mDictSecondary.begin(), mDictSecondary.end(), dict_add.begin());
|
||||
dict_list_t::iterator end_removed = std::set_difference(mDictSecondary.begin(), mDictSecondary.end(), dict_list.begin(), dict_list.end(), dict_rem.begin());
|
||||
|
||||
if (end_removed != dict_rem.begin()) // We can't remove secondary dictionaries so we need to recreate the Hunspell instance
|
||||
{
|
||||
mDictSecondary = dict_list;
|
||||
|
||||
std::string dict_language = mDictLanguage;
|
||||
initHunspell(dict_language);
|
||||
}
|
||||
else if (end_added != dict_add.begin()) // Add the new secondary dictionaries one by one
|
||||
{
|
||||
const std::string app_path = getDictionaryAppPath();
|
||||
const std::string user_path = getDictionaryUserPath();
|
||||
for (dict_list_t::const_iterator it_added = dict_add.begin(); it_added != end_added; ++it_added)
|
||||
{
|
||||
const LLSD dict_entry = getDictionaryData(*it_added);
|
||||
if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string strFileDic = dict_entry["name"].asString() + ".dic";
|
||||
if (gDirUtilp->fileExists(user_path + strFileDic))
|
||||
{
|
||||
mHunspell->add_dic((user_path + strFileDic).c_str());
|
||||
}
|
||||
else if (gDirUtilp->fileExists(app_path + strFileDic))
|
||||
{
|
||||
mHunspell->add_dic((app_path + strFileDic).c_str());
|
||||
}
|
||||
}
|
||||
mDictSecondary = dict_list;
|
||||
sSettingsChangeSignal();
|
||||
}
|
||||
}
|
||||
|
||||
void LLSpellChecker::initHunspell(const std::string& dict_language)
|
||||
{
|
||||
if (mHunspell)
|
||||
{
|
||||
delete mHunspell;
|
||||
mHunspell = NULL;
|
||||
mDictLanguage.clear();
|
||||
mDictFile.clear();
|
||||
mIgnoreList.clear();
|
||||
}
|
||||
|
||||
const LLSD dict_entry = (!dict_language.empty()) ? getDictionaryData(dict_language) : LLSD();
|
||||
if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) || (!dict_entry["is_primary"].asBoolean()))
|
||||
{
|
||||
sSettingsChangeSignal();
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string app_path = getDictionaryAppPath();
|
||||
const std::string user_path = getDictionaryUserPath();
|
||||
if (dict_entry.has("name"))
|
||||
{
|
||||
const std::string filename_aff = dict_entry["name"].asString() + ".aff";
|
||||
const std::string filename_dic = dict_entry["name"].asString() + ".dic";
|
||||
if ( (gDirUtilp->fileExists(user_path + filename_aff)) && (gDirUtilp->fileExists(user_path + filename_dic)) )
|
||||
{
|
||||
mHunspell = new Hunspell((user_path + filename_aff).c_str(), (user_path + filename_dic).c_str());
|
||||
}
|
||||
else if ( (gDirUtilp->fileExists(app_path + filename_aff)) && (gDirUtilp->fileExists(app_path + filename_dic)) )
|
||||
{
|
||||
mHunspell = new Hunspell((app_path + filename_aff).c_str(), (app_path + filename_dic).c_str());
|
||||
}
|
||||
if (!mHunspell)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mDictLanguage = dict_language;
|
||||
mDictFile = dict_entry["name"].asString();
|
||||
|
||||
if (gDirUtilp->fileExists(user_path + DICT_FILE_CUSTOM))
|
||||
{
|
||||
mHunspell->add_dic((user_path + DICT_FILE_CUSTOM).c_str());
|
||||
}
|
||||
|
||||
if (gDirUtilp->fileExists(user_path + DICT_FILE_IGNORE))
|
||||
{
|
||||
llifstream file_in(user_path + DICT_FILE_IGNORE, std::ios::in);
|
||||
if (file_in.is_open())
|
||||
{
|
||||
std::string word; int idxLine = 0;
|
||||
while (getline(file_in, word))
|
||||
{
|
||||
// Skip over the first line since that's just a line count
|
||||
if (0 != idxLine)
|
||||
{
|
||||
LLStringUtil::toLower(word);
|
||||
mIgnoreList.push_back(word);
|
||||
}
|
||||
idxLine++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (dict_list_t::const_iterator it = mDictSecondary.begin(); it != mDictSecondary.end(); ++it)
|
||||
{
|
||||
const LLSD dict_entry = getDictionaryData(*it);
|
||||
if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string filename_dic = dict_entry["name"].asString() + ".dic";
|
||||
if (gDirUtilp->fileExists(user_path + filename_dic))
|
||||
{
|
||||
mHunspell->add_dic((user_path + filename_dic).c_str());
|
||||
}
|
||||
else if (gDirUtilp->fileExists(app_path + filename_dic))
|
||||
{
|
||||
mHunspell->add_dic((app_path + filename_dic).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sSettingsChangeSignal();
|
||||
}
|
||||
|
||||
// static
|
||||
const std::string LLSpellChecker::getDictionaryAppPath()
|
||||
{
|
||||
std::string dict_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, DICT_DIR, "");
|
||||
return dict_path;
|
||||
}
|
||||
|
||||
// static
|
||||
const std::string LLSpellChecker::getDictionaryUserPath()
|
||||
{
|
||||
std::string dict_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, DICT_DIR, "");
|
||||
if (!gDirUtilp->fileExists(dict_path))
|
||||
{
|
||||
LLFile::mkdir(dict_path);
|
||||
}
|
||||
return dict_path;
|
||||
}
|
||||
|
||||
// static
|
||||
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
|
||||
const LLSD dict_info = getDictionaryData(dict_language);
|
||||
return
|
||||
(dict_info["user_installed"].asBoolean()) &&
|
||||
( (!getUseSpellCheck()) || (!LLSpellChecker::instance().isActiveDictionary(dict_language)) );
|
||||
}
|
||||
|
||||
// static
|
||||
void LLSpellChecker::removeDictionary(const std::string& dict_language)
|
||||
{
|
||||
if (!canRemoveDictionary(dict_language))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLSD dict_map = loadUserDictionaryMap();
|
||||
for (LLSD::array_const_iterator it = dict_map.beginArray(); it != dict_map.endArray(); ++it)
|
||||
{
|
||||
const LLSD& dict_info = *it;
|
||||
if (dict_info["language"].asString() == dict_language)
|
||||
{
|
||||
const std::string dict_dic = getDictionaryUserPath() + dict_info["name"].asString() + ".dic";
|
||||
if (gDirUtilp->fileExists(dict_dic))
|
||||
{
|
||||
LLFile::remove(dict_dic);
|
||||
}
|
||||
const std::string dict_aff = getDictionaryUserPath() + dict_info["name"].asString() + ".aff";
|
||||
if (gDirUtilp->fileExists(dict_aff))
|
||||
{
|
||||
LLFile::remove(dict_aff);
|
||||
}
|
||||
dict_map.erase(it - dict_map.beginArray());
|
||||
break;
|
||||
}
|
||||
}
|
||||
saveUserDictionaryMap(dict_map);
|
||||
|
||||
refreshDictionaryMap();
|
||||
}
|
||||
|
||||
// static
|
||||
LLSD LLSpellChecker::loadUserDictionaryMap()
|
||||
{
|
||||
LLSD dict_map;
|
||||
llifstream dict_file(getDictionaryUserPath() + DICT_FILE_USER, std::ios::binary);
|
||||
if (dict_file.is_open())
|
||||
{
|
||||
LLSDSerialize::fromXMLDocument(dict_map, dict_file);
|
||||
dict_file.close();
|
||||
}
|
||||
return dict_map;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLSpellChecker::saveUserDictionaryMap(const LLSD& dict_map)
|
||||
{
|
||||
llofstream dict_file(getDictionaryUserPath() + DICT_FILE_USER, std::ios::trunc);
|
||||
if (dict_file.is_open())
|
||||
{
|
||||
LLSDSerialize::toPrettyXML(dict_map, dict_file);
|
||||
dict_file.close();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
boost::signals2::connection LLSpellChecker::setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb)
|
||||
{
|
||||
return sSettingsChangeSignal.connect(cb);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLSpellChecker::setUseSpellCheck(const std::string& dict_language)
|
||||
{
|
||||
if ( (((dict_language.empty()) && (getUseSpellCheck())) || (!dict_language.empty())) &&
|
||||
(LLSpellChecker::instance().mDictLanguage != dict_language) )
|
||||
{
|
||||
LLSpellChecker::instance().initHunspell(dict_language);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLSpellChecker::initClass()
|
||||
{
|
||||
if (sDictMap.isUndefined())
|
||||
{
|
||||
refreshDictionaryMap();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
* @file llspellcheck.h
|
||||
* @brief Spell checking functionality
|
||||
*
|
||||
* $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 LLSPELLCHECK_H
|
||||
#define LLSPELLCHECK_H
|
||||
|
||||
#include "llsingleton.h"
|
||||
#include "llui.h"
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
class Hunspell;
|
||||
|
||||
class LLSpellChecker : public LLSingleton<LLSpellChecker>, public LLInitClass<LLSpellChecker>
|
||||
{
|
||||
friend class LLSingleton<LLSpellChecker>;
|
||||
friend class LLInitClass<LLSpellChecker>;
|
||||
protected:
|
||||
LLSpellChecker();
|
||||
~LLSpellChecker();
|
||||
|
||||
public:
|
||||
void addToCustomDictionary(const std::string& word);
|
||||
void addToIgnoreList(const std::string& word);
|
||||
bool checkSpelling(const std::string& word) const;
|
||||
S32 getSuggestions(const std::string& word, std::vector<std::string>& suggestions) const;
|
||||
protected:
|
||||
void addToDictFile(const std::string& dict_path, const std::string& word);
|
||||
void initHunspell(const std::string& dict_language);
|
||||
|
||||
public:
|
||||
typedef std::list<std::string> dict_list_t;
|
||||
|
||||
const std::string& getPrimaryDictionary() const { return mDictLanguage; }
|
||||
const dict_list_t& getSecondaryDictionaries() const { return mDictSecondary; }
|
||||
bool isActiveDictionary(const std::string& dict_language) const;
|
||||
void setSecondaryDictionaries(dict_list_t dict_list);
|
||||
|
||||
static 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; }
|
||||
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);
|
||||
static void setUseSpellCheck(const std::string& dict_language);
|
||||
protected:
|
||||
static LLSD loadUserDictionaryMap();
|
||||
static 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;
|
||||
std::string mDictLanguage;
|
||||
std::string mDictFile;
|
||||
dict_list_t mDictSecondary;
|
||||
std::vector<std::string> mIgnoreList;
|
||||
|
||||
static LLSD sDictMap;
|
||||
static settings_change_signal_t sSettingsChangeSignal;
|
||||
};
|
||||
|
||||
#endif // LLSPELLCHECK_H
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* @file llspellcheckmenuhandler.h
|
||||
* @brief Interface used by spell check menu handling
|
||||
*
|
||||
* $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 LLSPELLCHECKMENUHANDLER_H
|
||||
#define LLSPELLCHECKMENUHANDLER_H
|
||||
|
||||
class LLSpellCheckMenuHandler
|
||||
{
|
||||
public:
|
||||
virtual bool getSpellCheck() const { return false; }
|
||||
|
||||
virtual const std::string& getSuggestion(U32 index) const { return LLStringUtil::null; }
|
||||
virtual U32 getSuggestionCount() const { return 0; }
|
||||
virtual void replaceWithSuggestion(U32 index){}
|
||||
|
||||
virtual void addToDictionary() {}
|
||||
virtual bool canAddToDictionary() const { return false; }
|
||||
|
||||
virtual void addToIgnore() {}
|
||||
virtual bool canAddToIgnore() const { return false; }
|
||||
};
|
||||
|
||||
#endif // LLSPELLCHECKMENUHANDLER_H
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
#include "lllocalcliprect.h"
|
||||
#include "llmenugl.h"
|
||||
#include "llscrollcontainer.h"
|
||||
#include "llspellcheck.h"
|
||||
#include "llstl.h"
|
||||
#include "lltextparser.h"
|
||||
#include "lltextutil.h"
|
||||
|
|
@ -155,6 +156,7 @@ LLTextBase::Params::Params()
|
|||
plain_text("plain_text",false),
|
||||
track_end("track_end", false),
|
||||
read_only("read_only", false),
|
||||
spellcheck("spellcheck", false),
|
||||
v_pad("v_pad", 0),
|
||||
h_pad("h_pad", 0),
|
||||
clip("clip", true),
|
||||
|
|
@ -181,6 +183,9 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
|
|||
mFontShadow(p.font_shadow),
|
||||
mPopupMenu(NULL),
|
||||
mReadOnly(p.read_only),
|
||||
mSpellCheck(p.spellcheck),
|
||||
mSpellCheckStart(-1),
|
||||
mSpellCheckEnd(-1),
|
||||
mCursorColor(p.cursor_color),
|
||||
mFgColor(p.text_color),
|
||||
mBorderVisible( p.border_visible ),
|
||||
|
|
@ -246,6 +251,12 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
|
|||
addChild(mDocumentView);
|
||||
}
|
||||
|
||||
if (mSpellCheck)
|
||||
{
|
||||
LLSpellChecker::setSettingsChangeCallback(boost::bind(&LLTextBase::onSpellCheckSettingsChange, this));
|
||||
}
|
||||
mSpellCheckTimer.reset();
|
||||
|
||||
createDefaultSegment();
|
||||
|
||||
updateRects();
|
||||
|
|
@ -280,12 +291,23 @@ bool LLTextBase::truncate()
|
|||
if (getLength() >= S32(mMaxTextByteLength / 4))
|
||||
{
|
||||
// Have to check actual byte size
|
||||
LLWString text(getWText());
|
||||
S32 utf8_byte_size = wstring_utf8_length(text);
|
||||
S32 utf8_byte_size = 0;
|
||||
LLSD value = getViewModel()->getValue();
|
||||
if (value.type() == LLSD::TypeString)
|
||||
{
|
||||
// save a copy for strings.
|
||||
utf8_byte_size = value.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
// non string LLSDs need explicit conversion to string
|
||||
utf8_byte_size = value.asString().size();
|
||||
}
|
||||
|
||||
if ( utf8_byte_size > mMaxTextByteLength )
|
||||
{
|
||||
// Truncate safely in UTF-8
|
||||
std::string temp_utf8_text = wstring_to_utf8str(text);
|
||||
std::string temp_utf8_text = value.asString();
|
||||
temp_utf8_text = utf8str_truncate( temp_utf8_text, mMaxTextByteLength );
|
||||
LLWString text = utf8str_to_wstring( temp_utf8_text );
|
||||
// remove extra bit of current string, to preserve formatting, etc.
|
||||
|
|
@ -530,8 +552,92 @@ void LLTextBase::drawText()
|
|||
return;
|
||||
}
|
||||
|
||||
// Perform spell check if needed
|
||||
if ( (getSpellCheck()) && (getWText().length() > 2) )
|
||||
{
|
||||
// Calculate start and end indices for the spell checking range
|
||||
S32 start = line_start, end = getLineEnd(last_line);
|
||||
|
||||
if ( (mSpellCheckStart != start) || (mSpellCheckEnd != end) )
|
||||
{
|
||||
const LLWString& wstrText = getWText();
|
||||
mMisspellRanges.clear();
|
||||
|
||||
segment_set_t::const_iterator seg_it = getSegIterContaining(start);
|
||||
while (mSegments.end() != seg_it)
|
||||
{
|
||||
LLTextSegmentPtr text_segment = *seg_it;
|
||||
if ( (text_segment.isNull()) || (text_segment->getStart() >= end) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!text_segment->canEdit())
|
||||
{
|
||||
++seg_it;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Combine adjoining text segments into one
|
||||
U32 seg_start = text_segment->getStart(), seg_end = llmin(text_segment->getEnd(), end);
|
||||
while (mSegments.end() != ++seg_it)
|
||||
{
|
||||
text_segment = *seg_it;
|
||||
if ( (text_segment.isNull()) || (!text_segment->canEdit()) || (text_segment->getStart() >= end) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
seg_end = llmin(text_segment->getEnd(), end);
|
||||
}
|
||||
|
||||
// Find the start of the first word
|
||||
U32 word_start = seg_start, word_end = -1;
|
||||
while ( (word_start < wstrText.length()) && (!LLStringOps::isAlpha(wstrText[word_start])) )
|
||||
{
|
||||
word_start++;
|
||||
}
|
||||
|
||||
// Iterate over all words in the text block and check them one by one
|
||||
while (word_start < seg_end)
|
||||
{
|
||||
// Find the end of the current word (special case handling for "'" when it's used as a contraction)
|
||||
word_end = word_start + 1;
|
||||
while ( (word_end < seg_end) &&
|
||||
((LLWStringUtil::isPartOfWord(wstrText[word_end])) ||
|
||||
((L'\'' == wstrText[word_end]) &&
|
||||
(LLStringOps::isAlnum(wstrText[word_end - 1])) && (LLStringOps::isAlnum(wstrText[word_end + 1])))) )
|
||||
{
|
||||
word_end++;
|
||||
}
|
||||
if (word_end > seg_end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Don't process words shorter than 3 characters
|
||||
std::string word = wstring_to_utf8str(wstrText.substr(word_start, word_end - word_start));
|
||||
if ( (word.length() >= 3) && (!LLSpellChecker::instance().checkSpelling(word)) )
|
||||
{
|
||||
mMisspellRanges.push_back(std::pair<U32, U32>(word_start, word_end));
|
||||
}
|
||||
|
||||
// Find the start of the next word
|
||||
word_start = word_end + 1;
|
||||
while ( (word_start < seg_end) && (!LLWStringUtil::isPartOfWord(wstrText[word_start])) )
|
||||
{
|
||||
word_start++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mSpellCheckStart = start;
|
||||
mSpellCheckEnd = end;
|
||||
}
|
||||
}
|
||||
|
||||
LLTextSegmentPtr cur_segment = *seg_iter;
|
||||
|
||||
std::list<std::pair<U32, U32> >::const_iterator misspell_it = std::lower_bound(mMisspellRanges.begin(), mMisspellRanges.end(), std::pair<U32, U32>(line_start, 0));
|
||||
for (S32 cur_line = first_line; cur_line < last_line; cur_line++)
|
||||
{
|
||||
S32 next_line = cur_line + 1;
|
||||
|
|
@ -566,7 +672,8 @@ void LLTextBase::drawText()
|
|||
cur_segment = *seg_iter;
|
||||
}
|
||||
|
||||
S32 clipped_end = llmin( line_end, cur_segment->getEnd() ) - cur_segment->getStart();
|
||||
S32 seg_end = llmin(line_end, cur_segment->getEnd());
|
||||
S32 clipped_end = seg_end - cur_segment->getStart();
|
||||
|
||||
if (mUseEllipses // using ellipses
|
||||
&& clipped_end == line_end // last segment on line
|
||||
|
|
@ -578,6 +685,46 @@ void LLTextBase::drawText()
|
|||
text_rect.mRight -= 2;
|
||||
}
|
||||
|
||||
// Draw squiggly lines under any visible misspelled words
|
||||
while ( (mMisspellRanges.end() != misspell_it) && (misspell_it->first < seg_end) && (misspell_it->second > seg_start) )
|
||||
{
|
||||
// Skip the current word if the user is still busy editing it
|
||||
if ( (!mSpellCheckTimer.hasExpired()) && (misspell_it->first <= (U32)mCursorPos) && (misspell_it->second >= (U32)mCursorPos) )
|
||||
{
|
||||
++misspell_it;
|
||||
continue;
|
||||
}
|
||||
|
||||
U32 misspell_start = llmax<U32>(misspell_it->first, seg_start), misspell_end = llmin<U32>(misspell_it->second, seg_end);
|
||||
S32 squiggle_start = 0, squiggle_end = 0, pony = 0;
|
||||
cur_segment->getDimensions(seg_start - cur_segment->getStart(), misspell_start - seg_start, squiggle_start, pony);
|
||||
cur_segment->getDimensions(misspell_start - cur_segment->getStart(), misspell_end - misspell_start, squiggle_end, pony);
|
||||
squiggle_start += text_rect.mLeft;
|
||||
|
||||
pony = (squiggle_end + 3) / 6;
|
||||
squiggle_start += squiggle_end / 2 - pony * 3;
|
||||
squiggle_end = squiggle_start + pony * 6;
|
||||
|
||||
S32 squiggle_bottom = text_rect.mBottom + (S32)cur_segment->getStyle()->getFont()->getDescenderHeight();
|
||||
|
||||
gGL.color4ub(255, 0, 0, 200);
|
||||
while (squiggle_start + 1 < squiggle_end)
|
||||
{
|
||||
gl_line_2d(squiggle_start, squiggle_bottom, squiggle_start + 2, squiggle_bottom - 2);
|
||||
if (squiggle_start + 3 < squiggle_end)
|
||||
{
|
||||
gl_line_2d(squiggle_start + 2, squiggle_bottom - 3, squiggle_start + 4, squiggle_bottom - 1);
|
||||
}
|
||||
squiggle_start += 4;
|
||||
}
|
||||
|
||||
if (misspell_it->second > seg_end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
++misspell_it;
|
||||
}
|
||||
|
||||
text_rect.mLeft = (S32)(cur_segment->draw(seg_start - cur_segment->getStart(), clipped_end, selection_left, selection_right, text_rect));
|
||||
|
||||
seg_start = clipped_end + cur_segment->getStart();
|
||||
|
|
@ -592,8 +739,7 @@ void LLTextBase::drawText()
|
|||
|
||||
S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::segment_vec_t* segments )
|
||||
{
|
||||
LLWString text(getWText());
|
||||
S32 old_len = text.length(); // length() returns character length
|
||||
S32 old_len = getLength(); // length() returns character length
|
||||
S32 insert_len = wstr.length();
|
||||
|
||||
pos = getEditableIndex(pos, true);
|
||||
|
|
@ -653,8 +799,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
|
|||
}
|
||||
}
|
||||
|
||||
text.insert(pos, wstr);
|
||||
getViewModel()->setDisplay(text);
|
||||
getViewModel()->getEditableDisplay().insert(pos, wstr);
|
||||
|
||||
if ( truncate() )
|
||||
{
|
||||
|
|
@ -669,7 +814,6 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
|
|||
|
||||
S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length)
|
||||
{
|
||||
LLWString text(getWText());
|
||||
segment_set_t::iterator seg_iter = getSegIterContaining(pos);
|
||||
while(seg_iter != mSegments.end())
|
||||
{
|
||||
|
|
@ -715,8 +859,7 @@ S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length)
|
|||
++seg_iter;
|
||||
}
|
||||
|
||||
text.erase(pos, length);
|
||||
getViewModel()->setDisplay(text);
|
||||
getViewModel()->getEditableDisplay().erase(pos, length);
|
||||
|
||||
// recreate default segment in case we erased everything
|
||||
createDefaultSegment();
|
||||
|
|
@ -733,9 +876,7 @@ S32 LLTextBase::overwriteCharNoUndo(S32 pos, llwchar wc)
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
LLWString text(getWText());
|
||||
text[pos] = wc;
|
||||
getViewModel()->setDisplay(text);
|
||||
getViewModel()->getEditableDisplay()[pos] = wc;
|
||||
|
||||
onValueChange(pos, pos + 1);
|
||||
needsReflow(pos);
|
||||
|
|
@ -1103,6 +1244,99 @@ void LLTextBase::deselect()
|
|||
mIsSelecting = FALSE;
|
||||
}
|
||||
|
||||
bool LLTextBase::getSpellCheck() const
|
||||
{
|
||||
return (LLSpellChecker::getUseSpellCheck()) && (!mReadOnly) && (mSpellCheck);
|
||||
}
|
||||
|
||||
const std::string& LLTextBase::getSuggestion(U32 index) const
|
||||
{
|
||||
return (index < mSuggestionList.size()) ? mSuggestionList[index] : LLStringUtil::null;
|
||||
}
|
||||
|
||||
U32 LLTextBase::getSuggestionCount() const
|
||||
{
|
||||
return mSuggestionList.size();
|
||||
}
|
||||
|
||||
void LLTextBase::replaceWithSuggestion(U32 index)
|
||||
{
|
||||
for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it)
|
||||
{
|
||||
if ( (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) )
|
||||
{
|
||||
deselect();
|
||||
|
||||
// Delete the misspelled word
|
||||
removeStringNoUndo(it->first, it->second - it->first);
|
||||
|
||||
// Insert the suggestion in its place
|
||||
LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]);
|
||||
insertStringNoUndo(it->first, utf8str_to_wstring(mSuggestionList[index]));
|
||||
setCursorPos(it->first + (S32)suggestion.length());
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
mSpellCheckStart = mSpellCheckEnd = -1;
|
||||
}
|
||||
|
||||
void LLTextBase::addToDictionary()
|
||||
{
|
||||
if (canAddToDictionary())
|
||||
{
|
||||
LLSpellChecker::instance().addToCustomDictionary(getMisspelledWord(mCursorPos));
|
||||
}
|
||||
}
|
||||
|
||||
bool LLTextBase::canAddToDictionary() const
|
||||
{
|
||||
return (getSpellCheck()) && (isMisspelledWord(mCursorPos));
|
||||
}
|
||||
|
||||
void LLTextBase::addToIgnore()
|
||||
{
|
||||
if (canAddToIgnore())
|
||||
{
|
||||
LLSpellChecker::instance().addToIgnoreList(getMisspelledWord(mCursorPos));
|
||||
}
|
||||
}
|
||||
|
||||
bool LLTextBase::canAddToIgnore() const
|
||||
{
|
||||
return (getSpellCheck()) && (isMisspelledWord(mCursorPos));
|
||||
}
|
||||
|
||||
std::string LLTextBase::getMisspelledWord(U32 pos) const
|
||||
{
|
||||
for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it)
|
||||
{
|
||||
if ( (it->first <= pos) && (it->second >= pos) )
|
||||
{
|
||||
return wstring_to_utf8str(getWText().substr(it->first, it->second - it->first));
|
||||
}
|
||||
}
|
||||
return LLStringUtil::null;
|
||||
}
|
||||
|
||||
bool LLTextBase::isMisspelledWord(U32 pos) const
|
||||
{
|
||||
for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it)
|
||||
{
|
||||
if ( (it->first <= pos) && (it->second >= pos) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLTextBase::onSpellCheckSettingsChange()
|
||||
{
|
||||
// Recheck the spelling on every change
|
||||
mMisspellRanges.clear();
|
||||
mSpellCheckStart = mSpellCheckEnd = -1;
|
||||
}
|
||||
|
||||
// Sets the scrollbar from the cursor position
|
||||
void LLTextBase::updateScrollFromCursor()
|
||||
|
|
@ -1685,6 +1919,8 @@ static LLUIImagePtr image_from_icon_name(const std::string& icon_name)
|
|||
}
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PARSE_HTML("Parse HTML");
|
||||
|
||||
void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params)
|
||||
{
|
||||
LLStyle::Params style_params(input_params);
|
||||
|
|
@ -1693,15 +1929,13 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
|
|||
S32 part = (S32)LLTextParser::WHOLE;
|
||||
if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358).
|
||||
{
|
||||
LLFastTimer _(FTM_PARSE_HTML);
|
||||
S32 start=0,end=0;
|
||||
LLUrlMatch match;
|
||||
std::string text = new_text;
|
||||
while ( LLUrlRegistry::instance().findUrl(text, match,
|
||||
boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3)) )
|
||||
{
|
||||
|
||||
LLTextUtil::processUrlMatch(&match,this);
|
||||
|
||||
start = match.getStart();
|
||||
end = match.getEnd()+1;
|
||||
|
||||
|
|
@ -1737,6 +1971,8 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
|
|||
}
|
||||
}
|
||||
|
||||
LLTextUtil::processUrlMatch(&match,this);
|
||||
|
||||
// move on to the rest of the text after the Url
|
||||
if (end < (S32)text.length())
|
||||
{
|
||||
|
|
@ -1760,8 +1996,11 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
|
|||
}
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_APPEND_TEXT("Append Text");
|
||||
|
||||
void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params)
|
||||
{
|
||||
LLFastTimer _(FTM_APPEND_TEXT);
|
||||
if (new_text.empty())
|
||||
return;
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "v4color.h"
|
||||
#include "lleditmenuhandler.h"
|
||||
#include "llspellcheckmenuhandler.h"
|
||||
#include "llstyle.h"
|
||||
#include "llkeywords.h"
|
||||
#include "llpanel.h"
|
||||
|
|
@ -230,7 +231,8 @@ typedef LLPointer<LLTextSegment> LLTextSegmentPtr;
|
|||
///
|
||||
class LLTextBase
|
||||
: public LLUICtrl,
|
||||
protected LLEditMenuHandler
|
||||
protected LLEditMenuHandler,
|
||||
public LLSpellCheckMenuHandler
|
||||
{
|
||||
public:
|
||||
friend class LLTextSegment;
|
||||
|
|
@ -259,6 +261,7 @@ public:
|
|||
border_visible,
|
||||
track_end,
|
||||
read_only,
|
||||
spellcheck,
|
||||
allow_scroll,
|
||||
plain_text,
|
||||
wrap,
|
||||
|
|
@ -311,6 +314,24 @@ public:
|
|||
/*virtual*/ BOOL canDeselect() const;
|
||||
/*virtual*/ void deselect();
|
||||
|
||||
// LLSpellCheckMenuHandler overrides
|
||||
/*virtual*/ bool getSpellCheck() const;
|
||||
|
||||
/*virtual*/ const std::string& getSuggestion(U32 index) const;
|
||||
/*virtual*/ U32 getSuggestionCount() const;
|
||||
/*virtual*/ void replaceWithSuggestion(U32 index);
|
||||
|
||||
/*virtual*/ void addToDictionary();
|
||||
/*virtual*/ bool canAddToDictionary() const;
|
||||
|
||||
/*virtual*/ void addToIgnore();
|
||||
/*virtual*/ bool canAddToIgnore() const;
|
||||
|
||||
// Spell checking helper functions
|
||||
std::string getMisspelledWord(U32 pos) const;
|
||||
bool isMisspelledWord(U32 pos) const;
|
||||
void onSpellCheckSettingsChange();
|
||||
|
||||
// used by LLTextSegment layout code
|
||||
bool getWordWrap() { return mWordWrap; }
|
||||
bool getUseEllipses() { return mUseEllipses; }
|
||||
|
|
@ -540,6 +561,14 @@ protected:
|
|||
|
||||
BOOL mIsSelecting; // Are we in the middle of a drag-select?
|
||||
|
||||
// spell checking
|
||||
bool mSpellCheck;
|
||||
S32 mSpellCheckStart;
|
||||
S32 mSpellCheckEnd;
|
||||
LLTimer mSpellCheckTimer;
|
||||
std::list<std::pair<U32, U32> > mMisspellRanges;
|
||||
std::vector<std::string> mSuggestionList;
|
||||
|
||||
// configuration
|
||||
S32 mHPad; // padding on left of text
|
||||
S32 mVPad; // padding above text
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ S32 LLTextBox::getTextPixelHeight()
|
|||
|
||||
LLSD LLTextBox::getValue() const
|
||||
{
|
||||
return LLSD(getText());
|
||||
return getViewModel()->getValue();
|
||||
}
|
||||
|
||||
BOOL LLTextBox::setTextArg( const std::string& key, const LLStringExplicit& text )
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@
|
|||
#include "llwindow.h"
|
||||
#include "lltextparser.h"
|
||||
#include "llscrollcontainer.h"
|
||||
#include "llspellcheck.h"
|
||||
#include "llpanel.h"
|
||||
#include "llurlregistry.h"
|
||||
#include "lltooltip.h"
|
||||
|
|
@ -77,6 +78,7 @@ template class LLTextEditor* LLView::getChild<class LLTextEditor>(
|
|||
const S32 UI_TEXTEDITOR_LINE_NUMBER_MARGIN = 32;
|
||||
const S32 UI_TEXTEDITOR_LINE_NUMBER_DIGITS = 4;
|
||||
const S32 SPACES_PER_TAB = 4;
|
||||
const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
@ -1953,7 +1955,38 @@ void LLTextEditor::showContextMenu(S32 x, S32 y)
|
|||
|
||||
S32 screen_x, screen_y;
|
||||
localPointToScreen(x, y, &screen_x, &screen_y);
|
||||
mContextMenu->show(screen_x, screen_y);
|
||||
|
||||
setCursorAtLocalPos(x, y, false);
|
||||
if (hasSelection())
|
||||
{
|
||||
if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) )
|
||||
{
|
||||
deselect();
|
||||
}
|
||||
else
|
||||
{
|
||||
setCursorPos(llmax(mSelectionStart, mSelectionEnd));
|
||||
}
|
||||
}
|
||||
|
||||
bool use_spellcheck = getSpellCheck(), is_misspelled = false;
|
||||
if (use_spellcheck)
|
||||
{
|
||||
mSuggestionList.clear();
|
||||
|
||||
// If the cursor is on a misspelled word, retrieve suggestions for it
|
||||
std::string misspelled_word = getMisspelledWord(mCursorPos);
|
||||
if ((is_misspelled = !misspelled_word.empty()) == true)
|
||||
{
|
||||
LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList);
|
||||
}
|
||||
}
|
||||
|
||||
mContextMenu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty()));
|
||||
mContextMenu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled));
|
||||
mContextMenu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled));
|
||||
mContextMenu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled));
|
||||
mContextMenu->show(screen_x, screen_y, this);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2838,6 +2871,9 @@ void LLTextEditor::setKeystrokeCallback(const keystroke_signal_t::slot_type& cal
|
|||
void LLTextEditor::onKeyStroke()
|
||||
{
|
||||
mKeystrokeSignal(this);
|
||||
|
||||
mSpellCheckStart = mSpellCheckEnd = -1;
|
||||
mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY);
|
||||
}
|
||||
|
||||
//virtual
|
||||
|
|
|
|||
|
|
@ -831,7 +831,11 @@ void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LL
|
|||
|
||||
gGL.flush();
|
||||
glLineWidth(2.5f);
|
||||
glLineStipple(2, 0x3333 << shift);
|
||||
|
||||
if (!LLGLSLShader::sNoFixedFunction)
|
||||
{
|
||||
glLineStipple(2, 0x3333 << shift);
|
||||
}
|
||||
|
||||
gGL.begin(LLRender::LINES);
|
||||
{
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ public:
|
|||
// New functions
|
||||
/// Get the stored value in string form
|
||||
const LLWString& getDisplay() const { return mDisplay; }
|
||||
LLWString& getEditableDisplay() { mDirty = true; mUpdateFromDisplay = true; return mDisplay; }
|
||||
|
||||
/**
|
||||
* Set the display string directly (see LLTextEditor). What the user is
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ LLKeyStringTranslatorFunc* LLKeyboard::mStringTranslator = NULL; // Used for l10
|
|||
// Class Implementation
|
||||
//
|
||||
|
||||
LLKeyboard::LLKeyboard() : mCallbacks(NULL), mNumpadDistinct(ND_NUMLOCK_OFF)
|
||||
LLKeyboard::LLKeyboard() : mCallbacks(NULL)
|
||||
{
|
||||
S32 i;
|
||||
|
||||
|
|
|
|||
|
|
@ -62,14 +62,6 @@ class LLWindowCallbacks;
|
|||
|
||||
class LLKeyboard
|
||||
{
|
||||
public:
|
||||
typedef enum e_numpad_distinct
|
||||
{
|
||||
ND_NEVER,
|
||||
ND_NUMLOCK_OFF,
|
||||
ND_NUMLOCK_ON
|
||||
} ENumpadDistinct;
|
||||
|
||||
public:
|
||||
LLKeyboard();
|
||||
virtual ~LLKeyboard();
|
||||
|
|
@ -107,8 +99,6 @@ public:
|
|||
static BOOL keyFromString(const std::string& str, KEY *key); // False on failure
|
||||
static std::string stringFromKey(KEY key);
|
||||
static std::string stringFromAccelerator( MASK accel_mask, KEY key );
|
||||
e_numpad_distinct getNumpadDistinct() { return mNumpadDistinct; }
|
||||
void setNumpadDistinct(e_numpad_distinct val) { mNumpadDistinct = val; }
|
||||
|
||||
void setCallbacks(LLWindowCallbacks *cbs) { mCallbacks = cbs; }
|
||||
F32 getKeyElapsedTime( KEY key ); // Returns time in seconds since key was pressed.
|
||||
|
|
@ -135,8 +125,6 @@ protected:
|
|||
|
||||
static LLKeyStringTranslatorFunc* mStringTranslator; // Used for l10n + PC/Mac/Linux accelerator labeling
|
||||
|
||||
e_numpad_distinct mNumpadDistinct;
|
||||
|
||||
EKeyboardInsertMode mInsertMode;
|
||||
|
||||
static std::map<KEY,std::string> sKeysToNames;
|
||||
|
|
|
|||
|
|
@ -299,28 +299,11 @@ void LLKeyboardMacOSX::scanKeyboard()
|
|||
|
||||
BOOL LLKeyboardMacOSX::translateNumpadKey( const U16 os_key, KEY *translated_key )
|
||||
{
|
||||
if(mNumpadDistinct == ND_NUMLOCK_ON)
|
||||
{
|
||||
std::map<U16, KEY>::iterator iter= mTranslateNumpadMap.find(os_key);
|
||||
if(iter != mTranslateNumpadMap.end())
|
||||
{
|
||||
*translated_key = iter->second;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return translateKey(os_key, translated_key);
|
||||
}
|
||||
|
||||
U16 LLKeyboardMacOSX::inverseTranslateNumpadKey(const KEY translated_key)
|
||||
{
|
||||
if(mNumpadDistinct == ND_NUMLOCK_ON)
|
||||
{
|
||||
std::map<KEY, U16>::iterator iter= mInvTranslateNumpadMap.find(translated_key);
|
||||
if(iter != mInvTranslateNumpadMap.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
}
|
||||
return inverseTranslateKey(translated_key);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -312,29 +312,11 @@ void LLKeyboardSDL::scanKeyboard()
|
|||
|
||||
BOOL LLKeyboardSDL::translateNumpadKey( const U16 os_key, KEY *translated_key)
|
||||
{
|
||||
if(mNumpadDistinct == ND_NUMLOCK_ON)
|
||||
{
|
||||
std::map<U16, KEY>::iterator iter= mTranslateNumpadMap.find(os_key);
|
||||
if(iter != mTranslateNumpadMap.end())
|
||||
{
|
||||
*translated_key = iter->second;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
BOOL success = translateKey(os_key, translated_key);
|
||||
return success;
|
||||
return translateKey(os_key, translated_key);
|
||||
}
|
||||
|
||||
U16 LLKeyboardSDL::inverseTranslateNumpadKey(const KEY translated_key)
|
||||
{
|
||||
if(mNumpadDistinct == ND_NUMLOCK_ON)
|
||||
{
|
||||
std::map<KEY, U16>::iterator iter= mInvTranslateNumpadMap.find(translated_key);
|
||||
if(iter != mInvTranslateNumpadMap.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
}
|
||||
return inverseTranslateKey(translated_key);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -299,69 +299,13 @@ void LLKeyboardWin32::scanKeyboard()
|
|||
|
||||
BOOL LLKeyboardWin32::translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key)
|
||||
{
|
||||
if(mNumpadDistinct == ND_NUMLOCK_ON)
|
||||
{
|
||||
std::map<U16, KEY>::iterator iter = mTranslateNumpadMap.find(os_key);
|
||||
if (iter != mTranslateNumpadMap.end())
|
||||
{
|
||||
*translated_key = iter->second;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL success = translateKey(os_key, translated_key);
|
||||
if(mNumpadDistinct != ND_NEVER) {
|
||||
if(!success) return success;
|
||||
if(mask & MASK_EXTENDED)
|
||||
{
|
||||
// this is where we'd create new keycodes for extended keys
|
||||
// the set of extended keys includes the 'normal' arrow keys and
|
||||
// the pgup/dn/insert/home/end/delete cluster above the arrow keys
|
||||
// see http://windowssdk.msdn.microsoft.com/en-us/library/ms646280.aspx
|
||||
|
||||
// only process the return key if numlock is off
|
||||
if(((mNumpadDistinct == ND_NUMLOCK_OFF &&
|
||||
!(GetKeyState(VK_NUMLOCK) & 1))
|
||||
|| mNumpadDistinct == ND_NUMLOCK_ON) &&
|
||||
*translated_key == KEY_RETURN) {
|
||||
*translated_key = KEY_PAD_RETURN;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// the non-extended keys, those are in the numpad
|
||||
switch (*translated_key)
|
||||
{
|
||||
case KEY_LEFT:
|
||||
*translated_key = KEY_PAD_LEFT; break;
|
||||
case KEY_RIGHT:
|
||||
*translated_key = KEY_PAD_RIGHT; break;
|
||||
case KEY_UP:
|
||||
*translated_key = KEY_PAD_UP; break;
|
||||
case KEY_DOWN:
|
||||
*translated_key = KEY_PAD_DOWN; break;
|
||||
case KEY_HOME:
|
||||
*translated_key = KEY_PAD_HOME; break;
|
||||
case KEY_END:
|
||||
*translated_key = KEY_PAD_END; break;
|
||||
case KEY_PAGE_UP:
|
||||
*translated_key = KEY_PAD_PGUP; break;
|
||||
case KEY_PAGE_DOWN:
|
||||
*translated_key = KEY_PAD_PGDN; break;
|
||||
case KEY_INSERT:
|
||||
*translated_key = KEY_PAD_INS; break;
|
||||
case KEY_DELETE:
|
||||
*translated_key = KEY_PAD_DEL; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
return translateKey(os_key, translated_key);
|
||||
}
|
||||
|
||||
U16 LLKeyboardWin32::inverseTranslateExtendedKey(const KEY translated_key)
|
||||
{
|
||||
// if numlock is on, then we need to translate KEY_PAD_FOO to the corresponding number pad number
|
||||
if((mNumpadDistinct == ND_NUMLOCK_ON) && (GetKeyState(VK_NUMLOCK) & 1))
|
||||
if(GetKeyState(VK_NUMLOCK) & 1)
|
||||
{
|
||||
std::map<KEY, U16>::iterator iter = mInvTranslateNumpadMap.find(translated_key);
|
||||
if (iter != mInvTranslateNumpadMap.end())
|
||||
|
|
|
|||
|
|
@ -367,6 +367,10 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
|
|||
U32 fsaa_samples)
|
||||
: LLWindow(callbacks, fullscreen, flags)
|
||||
{
|
||||
|
||||
//MAINT-516 -- force a load of opengl32.dll just in case windows went sideways
|
||||
LoadLibrary(L"opengl32.dll");
|
||||
|
||||
mFSAASamples = fsaa_samples;
|
||||
mIconResource = gIconResource;
|
||||
mOverrideAspectRatio = 0.f;
|
||||
|
|
|
|||
|
|
@ -201,7 +201,8 @@ void LLControlVariable::setValue(const LLSD& new_value, bool saved_value)
|
|||
}
|
||||
|
||||
LLSD storable_value = getComparableValue(new_value);
|
||||
bool value_changed = llsd_compare(getValue(), storable_value) == FALSE;
|
||||
LLSD original_value = getValue();
|
||||
bool value_changed = llsd_compare(original_value, storable_value) == FALSE;
|
||||
if(saved_value)
|
||||
{
|
||||
// If we're going to save this value, return to default but don't fire
|
||||
|
|
@ -237,7 +238,7 @@ void LLControlVariable::setValue(const LLSD& new_value, bool saved_value)
|
|||
|
||||
if(value_changed)
|
||||
{
|
||||
mCommitSignal(this, storable_value);
|
||||
firePropertyChanged(original_value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -249,12 +250,13 @@ void LLControlVariable::setDefaultValue(const LLSD& value)
|
|||
// *NOTE: Default values are not saved, only read.
|
||||
|
||||
LLSD comparable_value = getComparableValue(value);
|
||||
bool value_changed = (llsd_compare(getValue(), comparable_value) == FALSE);
|
||||
LLSD original_value = getValue();
|
||||
bool value_changed = (llsd_compare(original_value, comparable_value) == FALSE);
|
||||
resetToDefault(false);
|
||||
mValues[0] = comparable_value;
|
||||
if(value_changed)
|
||||
{
|
||||
firePropertyChanged();
|
||||
firePropertyChanged(original_value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -277,6 +279,8 @@ void LLControlVariable::resetToDefault(bool fire_signal)
|
|||
{
|
||||
//The first setting is always the default
|
||||
//Pop to it and fire off the listener
|
||||
LLSD originalValue = mValues.back();
|
||||
|
||||
while(mValues.size() > 1)
|
||||
{
|
||||
mValues.pop_back();
|
||||
|
|
@ -284,7 +288,7 @@ void LLControlVariable::resetToDefault(bool fire_signal)
|
|||
|
||||
if(fire_signal)
|
||||
{
|
||||
firePropertyChanged();
|
||||
firePropertyChanged(originalValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ class LLControlVariable : public LLRefCount
|
|||
|
||||
public:
|
||||
typedef boost::signals2::signal<bool(LLControlVariable* control, const LLSD&), boost_boolean_combiner> validate_signal_t;
|
||||
typedef boost::signals2::signal<void(LLControlVariable* control, const LLSD&)> commit_signal_t;
|
||||
typedef boost::signals2::signal<void(LLControlVariable* control, const LLSD&, const LLSD&)> commit_signal_t;
|
||||
|
||||
private:
|
||||
std::string mName;
|
||||
|
|
@ -146,11 +146,11 @@ public:
|
|||
void setHiddenFromSettingsEditor(bool hide);
|
||||
void setComment(const std::string& comment);
|
||||
|
||||
void firePropertyChanged()
|
||||
{
|
||||
mCommitSignal(this, mValues.back());
|
||||
}
|
||||
private:
|
||||
void firePropertyChanged(const LLSD &pPreviousValue)
|
||||
{
|
||||
mCommitSignal(this, mValues.back(), pPreviousValue);
|
||||
}
|
||||
LLSD getComparableValue(const LLSD& value);
|
||||
bool llsd_compare(const LLSD& a, const LLSD & b);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ include(EXPAT)
|
|||
include(FMOD)
|
||||
include(OPENAL)
|
||||
include(FindOpenGL)
|
||||
include(Hunspell)
|
||||
include(JsonCpp)
|
||||
include(LLAudio)
|
||||
include(LLCharacter)
|
||||
|
|
@ -73,6 +74,7 @@ include_directories(
|
|||
${LLLOGIN_INCLUDE_DIRS}
|
||||
${UPDATER_INCLUDE_DIRS}
|
||||
${LIBS_PREBUILT_DIR}/include/collada
|
||||
${LIBS_PREBUILD_DIR}/include/hunspell
|
||||
${OPENAL_LIB_INCLUDE_DIRS}
|
||||
${LIBS_PREBUILT_DIR}/include/collada/1.4
|
||||
)
|
||||
|
|
@ -99,6 +101,7 @@ set(viewer_SOURCE_FILES
|
|||
llassetuploadresponders.cpp
|
||||
llattachmentsmgr.cpp
|
||||
llaudiosourcevo.cpp
|
||||
llautoreplace.cpp
|
||||
llavataractions.cpp
|
||||
llavatariconctrl.cpp
|
||||
llavatarlist.cpp
|
||||
|
|
@ -170,6 +173,7 @@ set(viewer_SOURCE_FILES
|
|||
llfloaterabout.cpp
|
||||
llfloaterbvhpreview.cpp
|
||||
llfloaterauction.cpp
|
||||
llfloaterautoreplacesettings.cpp
|
||||
llfloateravatar.cpp
|
||||
llfloateravatarpicker.cpp
|
||||
llfloateravatartextures.cpp
|
||||
|
|
@ -213,7 +217,6 @@ set(viewer_SOURCE_FILES
|
|||
llfloatermemleak.cpp
|
||||
llfloatermodelpreview.cpp
|
||||
llfloatermodeluploadbase.cpp
|
||||
llfloatermodelwizard.cpp
|
||||
llfloaternamedesc.cpp
|
||||
llfloaternotificationsconsole.cpp
|
||||
llfloaterobjectweights.cpp
|
||||
|
|
@ -239,6 +242,7 @@ set(viewer_SOURCE_FILES
|
|||
llfloatersidepanelcontainer.cpp
|
||||
llfloatersnapshot.cpp
|
||||
llfloatersounddevices.cpp
|
||||
llfloaterspellchecksettings.cpp
|
||||
llfloatertelehub.cpp
|
||||
llfloatertestinspectors.cpp
|
||||
llfloatertestlistview.cpp
|
||||
|
|
@ -673,6 +677,7 @@ set(viewer_HEADER_FILES
|
|||
llassetuploadresponders.h
|
||||
llattachmentsmgr.h
|
||||
llaudiosourcevo.h
|
||||
llautoreplace.h
|
||||
llavataractions.h
|
||||
llavatariconctrl.h
|
||||
llavatarlist.h
|
||||
|
|
@ -744,6 +749,7 @@ set(viewer_HEADER_FILES
|
|||
llfloaterabout.h
|
||||
llfloaterbvhpreview.h
|
||||
llfloaterauction.h
|
||||
llfloaterautoreplacesettings.h
|
||||
llfloateravatar.h
|
||||
llfloateravatarpicker.h
|
||||
llfloateravatartextures.h
|
||||
|
|
@ -787,7 +793,6 @@ set(viewer_HEADER_FILES
|
|||
llfloatermemleak.h
|
||||
llfloatermodelpreview.h
|
||||
llfloatermodeluploadbase.h
|
||||
llfloatermodelwizard.h
|
||||
llfloaternamedesc.h
|
||||
llfloaternotificationsconsole.h
|
||||
llfloaterobjectweights.h
|
||||
|
|
@ -813,6 +818,7 @@ set(viewer_HEADER_FILES
|
|||
llfloatersidepanelcontainer.h
|
||||
llfloatersnapshot.h
|
||||
llfloatersounddevices.h
|
||||
llfloaterspellchecksettings.h
|
||||
llfloatertelehub.h
|
||||
llfloatertestinspectors.h
|
||||
llfloatertestlistview.h
|
||||
|
|
@ -1614,6 +1620,9 @@ if (WINDOWS)
|
|||
${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}/${CMAKE_CFG_INTDIR}/SLVoice.exe
|
||||
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk.dll
|
||||
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/ortp.dll
|
||||
|
|
@ -1803,6 +1812,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
|
|||
${LLMATH_LIBRARIES}
|
||||
${LLCOMMON_LIBRARIES}
|
||||
${NDOF_LIBRARY}
|
||||
${HUNSPELL_LIBRARY}
|
||||
${viewer_LIBRARIES}
|
||||
${BOOST_PROGRAM_OPTIONS_LIBRARY}
|
||||
${BOOST_REGEX_LIBRARY}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -148,7 +148,7 @@
|
|||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>ApplyTextureImmediately</key>
|
||||
<key>TextureLivePreview</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Preview selections in texture picker immediately</string>
|
||||
|
|
@ -335,6 +335,17 @@
|
|||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>AutoReplace</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Replaces keywords with a configured word or phrase</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>AutoAcceptNewInventory</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
@ -4292,6 +4303,17 @@
|
|||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>InventoryInboxToggleState</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Stores the open/closed state of inventory Received items panel</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>InventoryLinking</key>
|
||||
<map>
|
||||
|
|
@ -6356,17 +6378,6 @@
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>NumpadControl</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>How numpad keys control your avatar. 0 = Like the normal arrow keys, 1 = Numpad moves avatar when numlock is off, 2 = Numpad moves avatar regardless of numlock (use this if you have no numlock)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>ObjectCacheEnabled</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
@ -7274,7 +7285,7 @@
|
|||
<key>WebContentWindowLimit</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Maximum number of web brower windows that can be open at once in the Web content floater (0 for no limit)</string>
|
||||
<string>Maximum number of web browser windows that can be open at once in the Web content floater (0 for no limit)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
|
|
@ -8093,6 +8104,18 @@
|
|||
<real>0</real>
|
||||
</map>
|
||||
|
||||
<key>RenderDepthPrePass</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>EXPERIMENTAL: Prime the depth buffer with simple prim geometry before rendering with textures.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
|
||||
<key>RenderDepthOfField</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
@ -9172,7 +9195,7 @@
|
|||
<key>RenderUseVAO</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Use GL Vertex Array Objects</string>
|
||||
<string>[EXPERIMENTAL] Use GL Vertex Array Objects</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
|
|
@ -9180,7 +9203,19 @@
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>RenderVBOMappingDisable</key>
|
||||
<key>RenderUseTransformFeedback</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>[EXPERIMENTAL] Use transform feedback shaders for LoD updates</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
|
||||
<key>RenderVBOMappingDisable</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Disable VBO glMapBufferARB</string>
|
||||
|
|
@ -10863,7 +10898,8 @@
|
|||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<real>0.1</real>
|
||||
</map> <key>ToolTipFadeTime</key>
|
||||
</map>
|
||||
<key>ToolTipFadeTime</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Seconds over which tooltip fades away</string>
|
||||
|
|
@ -12227,6 +12263,17 @@
|
|||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>RenderSynchronousOcclusion</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Don't let occlusion queries get more than one frame behind (block until they complete).</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>RenderDelayVBUpdate</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
@ -12260,6 +12307,28 @@
|
|||
<key>Value</key>
|
||||
<real>10.0</real>
|
||||
</map>
|
||||
<key>SpellCheck</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable spellchecking on line and text editors</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>SpellCheckDictionary</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Current primary and secondary dictionaries used for spell checking</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string>English (United States),Second Life Glossary</string>
|
||||
</map>
|
||||
<key>UseNewWalkRun</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ out vec4 frag_color;
|
|||
#define frag_color gl_FragColor
|
||||
#endif
|
||||
|
||||
uniform float minimum_alpha;
|
||||
|
||||
uniform sampler2DRect depthMap;
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
|
|
@ -70,9 +72,15 @@ void main()
|
|||
|
||||
vec4 diff= texture2D(diffuseMap,vary_texcoord0.xy);
|
||||
|
||||
if (diff.a < minimum_alpha)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
vec4 col = vec4(vary_ambient + vary_directional.rgb, 1.0);
|
||||
vec4 color = diff * col;
|
||||
|
||||
|
||||
color.rgb = atmosLighting(color.rgb);
|
||||
|
||||
color.rgb = scaleSoftClip(color.rgb);
|
||||
|
|
|
|||
|
|
@ -55,8 +55,6 @@ 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 vec3 color;
|
||||
|
|
@ -143,7 +141,8 @@ void main()
|
|||
discard;
|
||||
}
|
||||
|
||||
vec3 norm = texture2DRect(normalMap, frag.xy).xyz*2.0-1.0;
|
||||
vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
|
||||
norm = vec3((norm.xy-0.5)*2.0, norm.z);
|
||||
|
||||
norm = normalize(norm);
|
||||
float l_dist = -dot(lv, proj_n);
|
||||
|
|
|
|||
|
|
@ -42,12 +42,13 @@ uniform sampler2DRect depthMap;
|
|||
uniform vec3 env_mat[3];
|
||||
uniform float sun_wash;
|
||||
|
||||
uniform vec3 center;
|
||||
uniform vec3 color;
|
||||
uniform float falloff;
|
||||
uniform float size;
|
||||
|
||||
VARYING vec4 vary_fragcoord;
|
||||
VARYING vec3 trans_center;
|
||||
|
||||
uniform vec2 screen_res;
|
||||
|
||||
uniform mat4 inv_proj;
|
||||
|
|
@ -74,7 +75,7 @@ void main()
|
|||
frag.xy *= screen_res;
|
||||
|
||||
vec3 pos = getPosition(frag.xy).xyz;
|
||||
vec3 lv = center.xyz-pos;
|
||||
vec3 lv = trans_center.xyz-pos;
|
||||
float dist2 = dot(lv,lv);
|
||||
dist2 /= size;
|
||||
if (dist2 > 1.0)
|
||||
|
|
|
|||
|
|
@ -24,16 +24,22 @@
|
|||
*/
|
||||
|
||||
uniform mat4 modelview_projection_matrix;
|
||||
uniform mat4 modelview_matrix;
|
||||
|
||||
ATTRIBUTE vec3 position;
|
||||
|
||||
uniform vec3 center;
|
||||
uniform float size;
|
||||
|
||||
VARYING vec4 vary_fragcoord;
|
||||
VARYING vec3 trans_center;
|
||||
|
||||
void main()
|
||||
{
|
||||
//transform vertex
|
||||
vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0);
|
||||
vec3 p = position*sqrt(size)+center;
|
||||
vec4 pos = modelview_projection_matrix * vec4(p.xyz, 1.0);
|
||||
vary_fragcoord = pos;
|
||||
|
||||
trans_center = (modelview_matrix*vec4(center.xyz, 1.0)).xyz;
|
||||
gl_Position = pos;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* @file 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;
|
||||
|
||||
VARYING vec4 post_pos;
|
||||
|
||||
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);
|
||||
|
||||
post_pos = pos;
|
||||
|
||||
gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
|
||||
}
|
||||
|
|
@ -24,18 +24,21 @@
|
|||
*/
|
||||
|
||||
|
||||
#extension GL_ARB_texture_rectangle : enable
|
||||
|
||||
#ifdef DEFINE_GL_FRAGCOLOR
|
||||
out vec4 frag_color;
|
||||
#else
|
||||
#define frag_color gl_FragColor
|
||||
#endif
|
||||
|
||||
//class 1 -- no shadows
|
||||
|
||||
#extension GL_ARB_texture_rectangle : enable
|
||||
|
||||
uniform sampler2DRect diffuseRect;
|
||||
uniform sampler2DRect specularRect;
|
||||
uniform sampler2DRect depthMap;
|
||||
uniform sampler2DRect normalMap;
|
||||
uniform samplerCube environmentMap;
|
||||
uniform sampler2D noiseMap;
|
||||
uniform sampler2D projectionMap;
|
||||
|
||||
|
|
@ -46,6 +49,7 @@ 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;
|
||||
|
|
@ -53,19 +57,66 @@ uniform float far_clip;
|
|||
uniform vec3 proj_origin; //origin of projection to be used for angular attenuation
|
||||
uniform float sun_wash;
|
||||
|
||||
uniform vec3 center;
|
||||
uniform vec3 color;
|
||||
uniform float falloff;
|
||||
uniform float size;
|
||||
|
||||
VARYING vec4 vary_fragcoord;
|
||||
VARYING vec3 trans_center;
|
||||
|
||||
uniform vec2 screen_res;
|
||||
|
||||
uniform mat4 inv_proj;
|
||||
|
||||
vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
|
||||
{
|
||||
vec4 ret = texture2DLod(projectionMap, tc, lod);
|
||||
|
||||
vec2 dist = tc-vec2(0.5);
|
||||
|
||||
float det = max(1.0-lod/(proj_lod*0.5), 0.0);
|
||||
|
||||
float d = dot(dist,dist);
|
||||
|
||||
ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0);
|
||||
|
||||
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)
|
||||
{
|
||||
float depth = texture2DRect(depthMap, pos_screen.xy).a;
|
||||
float depth = texture2DRect(depthMap, pos_screen.xy).r;
|
||||
vec2 sc = pos_screen.xy*2.0;
|
||||
sc /= screen_res;
|
||||
sc -= vec2(1.0,1.0);
|
||||
|
|
@ -84,16 +135,16 @@ void main()
|
|||
frag.xy *= screen_res;
|
||||
|
||||
vec3 pos = getPosition(frag.xy).xyz;
|
||||
vec3 lv = center.xyz-pos.xyz;
|
||||
vec3 lv = trans_center.xyz-pos.xyz;
|
||||
float dist2 = dot(lv,lv);
|
||||
dist2 /= size;
|
||||
if (dist2 > 1.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
|
||||
vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
|
||||
norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
|
||||
norm = vec3((norm.xy-0.5)*2.0, norm.z);
|
||||
|
||||
norm = normalize(norm);
|
||||
float l_dist = -dot(lv, proj_n);
|
||||
|
|
@ -107,7 +158,11 @@ void main()
|
|||
proj_tc.xyz /= proj_tc.w;
|
||||
|
||||
float fa = falloff+1.0;
|
||||
float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
|
||||
float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0);
|
||||
if (dist_atten <= 0.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
lv = proj_origin-pos.xyz;
|
||||
lv = normalize(lv);
|
||||
|
|
@ -125,32 +180,32 @@ void main()
|
|||
proj_tc.y > 0.0)
|
||||
{
|
||||
float lit = 0.0;
|
||||
float amb_da = proj_ambiance;
|
||||
|
||||
if (da > 0.0)
|
||||
{
|
||||
float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
|
||||
float lod = diff * proj_lod;
|
||||
|
||||
vec4 plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
|
||||
vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod);
|
||||
|
||||
vec3 lcol = color.rgb * plcol.rgb * plcol.a;
|
||||
|
||||
lit = da * dist_atten * noise;
|
||||
|
||||
col = lcol*lit*diff_tex;
|
||||
amb_da += (da*0.5)*proj_ambiance;
|
||||
}
|
||||
|
||||
float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
|
||||
float lod = diff * proj_lod;
|
||||
vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
|
||||
//float amb_da = mix(proj_ambiance, proj_ambiance*max(-da, 0.0), max(da, 0.0));
|
||||
float amb_da = 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;
|
||||
}
|
||||
|
||||
|
|
@ -168,18 +223,22 @@ void main()
|
|||
{
|
||||
vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
|
||||
|
||||
vec3 stc = (proj_mat * vec4(pfinal.xyz, 1.0)).xyz;
|
||||
vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
|
||||
|
||||
if (stc.z > 0.0)
|
||||
{
|
||||
stc.xy /= stc.z+proj_near;
|
||||
|
||||
stc.xy /= stc.w;
|
||||
|
||||
float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0);
|
||||
|
||||
stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5);
|
||||
|
||||
if (stc.x < 1.0 &&
|
||||
stc.y < 1.0 &&
|
||||
stc.x > 0.0 &&
|
||||
stc.y > 0.0)
|
||||
{
|
||||
vec4 scol = texture2DLod(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
|
||||
vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
|
||||
col += dist_atten*scol.rgb*color.rgb*scol.a*spec.rgb;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* @file debugF.glsl
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2011, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifdef DEFINE_GL_FRAGCOLOR
|
||||
out vec4 frag_color;
|
||||
#else
|
||||
#define frag_color gl_FragColor
|
||||
#endif
|
||||
|
||||
uniform vec4 color;
|
||||
uniform vec4 clip_plane;
|
||||
|
||||
VARYING vec3 vary_position;
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
if (dot(vary_position,clip_plane.xyz)+clip_plane.w < 0.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
frag_color = color;
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* @file debugV.glsl
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2011, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
uniform mat4 modelview_projection_matrix;
|
||||
uniform mat4 modelview_matrix;
|
||||
|
||||
ATTRIBUTE vec3 position;
|
||||
|
||||
VARYING vec3 vary_position;
|
||||
|
||||
void main()
|
||||
{
|
||||
vary_position = (modelview_matrix*vec4(position.xyz,1.0)).xyz;
|
||||
gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* @file occlusionCubeV.glsl
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2007, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
uniform mat4 modelview_projection_matrix;
|
||||
|
||||
ATTRIBUTE vec3 position;
|
||||
|
||||
uniform vec3 box_center;
|
||||
uniform vec3 box_size;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 p = position*box_size+box_center;
|
||||
gl_Position = modelview_projection_matrix * vec4(p.xyz, 1.0);
|
||||
}
|
||||
|
||||
|
|
@ -23,9 +23,9 @@
|
|||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
ATTRIBUTE ivec4 texture_index;
|
||||
ATTRIBUTE int texture_index;
|
||||
|
||||
VARYING_FLAT ivec4 vary_texture_index;
|
||||
VARYING_FLAT int vary_texture_index;
|
||||
|
||||
void passTextureIndex()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* @file binormalV.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;
|
||||
|
||||
ATTRIBUTE vec3 binormal;
|
||||
|
||||
VARYING vec4 binormal_out;
|
||||
|
||||
void main()
|
||||
{
|
||||
binormal_out = vec4(normal_matrix * binormal, 0.0);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* @file colorV.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 int color_in;
|
||||
|
||||
ATTRIBUTE vec3 position;
|
||||
|
||||
VARYING int color_out;
|
||||
|
||||
void main()
|
||||
{
|
||||
color_out = color_in;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* @file normalV.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;
|
||||
|
||||
ATTRIBUTE vec3 normal;
|
||||
|
||||
VARYING vec4 normal_out;
|
||||
|
||||
void main()
|
||||
{
|
||||
normal_out = vec4(normalize(normal_matrix * normal), 0.0);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* @file positionV.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 int texture_index_in;
|
||||
|
||||
ATTRIBUTE vec3 position;
|
||||
|
||||
VARYING vec3 position_out;
|
||||
VARYING int texture_index_out;
|
||||
|
||||
void main()
|
||||
{
|
||||
texture_index_out = texture_index_in;
|
||||
position_out = (modelview_matrix*vec4(position, 1.0)).xyz;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* @file texcoordV.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 vec2 texcoord0;
|
||||
|
||||
VARYING vec2 texcoord_out;
|
||||
|
||||
void main()
|
||||
{
|
||||
texcoord_out = texcoord0;
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +31,8 @@ out vec4 frag_color;
|
|||
#define frag_color gl_FragColor
|
||||
#endif
|
||||
|
||||
uniform float minimum_alpha;
|
||||
|
||||
uniform sampler2DRectShadow shadowMap0;
|
||||
uniform sampler2DRectShadow shadowMap1;
|
||||
uniform sampler2DRectShadow shadowMap2;
|
||||
|
|
@ -97,6 +99,13 @@ void main()
|
|||
float shadow = 0.0;
|
||||
vec4 pos = vec4(vary_position, 1.0);
|
||||
|
||||
vec4 diff = texture2D(diffuseMap,vary_texcoord0.xy);
|
||||
|
||||
if (diff.a < minimum_alpha)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
vec4 spos = pos;
|
||||
|
||||
if (spos.z > -shadow_clip.w)
|
||||
|
|
@ -164,8 +173,6 @@ void main()
|
|||
shadow = 1.0;
|
||||
}
|
||||
|
||||
vec4 diff = texture2D(diffuseMap,vary_texcoord0.xy);
|
||||
|
||||
vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, 1.0);
|
||||
vec4 color = diff * col;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,6 @@ out vec4 frag_color;
|
|||
#define frag_color gl_FragColor
|
||||
#endif
|
||||
|
||||
VARYING vec4 vertex_color;
|
||||
|
||||
uniform sampler2DRect diffuseRect;
|
||||
uniform sampler2DRect specularRect;
|
||||
uniform sampler2DRect depthMap;
|
||||
|
|
@ -49,6 +47,7 @@ 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;
|
||||
|
|
@ -58,16 +57,65 @@ uniform float sun_wash;
|
|||
uniform int proj_shadow_idx;
|
||||
uniform float shadow_fade;
|
||||
|
||||
VARYING vec4 vary_light;
|
||||
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;
|
||||
|
||||
vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
|
||||
{
|
||||
vec4 ret = texture2DLod(projectionMap, tc, lod);
|
||||
|
||||
vec2 dist = tc-vec2(0.5);
|
||||
|
||||
float det = max(1.0-lod/(proj_lod*0.5), 0.0);
|
||||
|
||||
float d = dot(dist,dist);
|
||||
|
||||
ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0);
|
||||
|
||||
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)
|
||||
{
|
||||
float depth = texture2DRect(depthMap, pos_screen.xy).a;
|
||||
float depth = texture2DRect(depthMap, pos_screen.xy).r;
|
||||
vec2 sc = pos_screen.xy*2.0;
|
||||
sc /= screen_res;
|
||||
sc -= vec2(1.0,1.0);
|
||||
|
|
@ -85,6 +133,15 @@ void main()
|
|||
frag.xyz = frag.xyz*0.5+0.5;
|
||||
frag.xy *= screen_res;
|
||||
|
||||
vec3 pos = getPosition(frag.xy).xyz;
|
||||
vec3 lv = trans_center.xyz-pos.xyz;
|
||||
float dist2 = dot(lv,lv);
|
||||
dist2 /= size;
|
||||
if (dist2 > 1.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
float shadow = 1.0;
|
||||
|
||||
if (proj_shadow_idx >= 0)
|
||||
|
|
@ -96,15 +153,6 @@ void main()
|
|||
shadow = min(sh[proj_shadow_idx]+shadow_fade, 1.0);
|
||||
}
|
||||
|
||||
vec3 pos = getPosition(frag.xy).xyz;
|
||||
vec3 lv = vary_light.xyz-pos.xyz;
|
||||
float dist2 = dot(lv,lv);
|
||||
dist2 /= vary_light.w;
|
||||
if (dist2 > 1.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
|
||||
norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
|
||||
|
||||
|
|
@ -119,8 +167,12 @@ void main()
|
|||
|
||||
proj_tc.xyz /= proj_tc.w;
|
||||
|
||||
float fa = vertex_color.a+1.0;
|
||||
float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
|
||||
float fa = falloff+1.0;
|
||||
float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0);
|
||||
if (dist_atten <= 0.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
lv = proj_origin-pos.xyz;
|
||||
lv = normalize(lv);
|
||||
|
|
@ -138,37 +190,33 @@ void main()
|
|||
proj_tc.y > 0.0)
|
||||
{
|
||||
float lit = 0.0;
|
||||
float amb_da = proj_ambiance;
|
||||
|
||||
if (da > 0.0)
|
||||
{
|
||||
float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
|
||||
float lod = diff * proj_lod;
|
||||
|
||||
vec4 plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
|
||||
vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod);
|
||||
|
||||
vec3 lcol = vertex_color.rgb * plcol.rgb * plcol.a;
|
||||
vec3 lcol = color.rgb * plcol.rgb * plcol.a;
|
||||
|
||||
lit = da * dist_atten * noise;
|
||||
|
||||
col = lcol*lit*diff_tex*shadow;
|
||||
}
|
||||
|
||||
float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
|
||||
float lod = diff * proj_lod;
|
||||
vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
|
||||
//float amb_da = mix(proj_ambiance, proj_ambiance*max(-da, 0.0), max(da, 0.0));
|
||||
float amb_da = proj_ambiance;
|
||||
if (da > 0.0)
|
||||
{
|
||||
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*vertex_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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -185,19 +233,23 @@ void main()
|
|||
{
|
||||
vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
|
||||
|
||||
vec3 stc = (proj_mat * vec4(pfinal.xyz, 1.0)).xyz;
|
||||
vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
|
||||
|
||||
if (stc.z > 0.0)
|
||||
{
|
||||
stc.xy /= stc.z+proj_near;
|
||||
|
||||
stc.xy /= stc.w;
|
||||
|
||||
float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0);
|
||||
|
||||
stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5);
|
||||
|
||||
if (stc.x < 1.0 &&
|
||||
stc.y < 1.0 &&
|
||||
stc.x > 0.0 &&
|
||||
stc.y > 0.0)
|
||||
{
|
||||
vec4 scol = texture2DLod(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
|
||||
col += dist_atten*scol.rgb*vertex_color.rgb*scol.a*spec.rgb*shadow;
|
||||
vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
|
||||
col += dist_atten*scol.rgb*color.rgb*scol.a*spec.rgb*shadow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -520,6 +520,7 @@ Disregard128DefaultDrawDistance 1 0
|
|||
list ATIOldDriver
|
||||
RenderAvatarVP 0 0
|
||||
RenderAvatarCloth 0 0
|
||||
RenderVBOEnable 1 0
|
||||
|
||||
// ATI cards generally perform better when not using VBOs for streaming data
|
||||
|
||||
|
|
|
|||
|
|
@ -517,6 +517,7 @@ Disregard128DefaultDrawDistance 1 0
|
|||
list ATIOldDriver
|
||||
RenderAvatarVP 0 0
|
||||
RenderAvatarCloth 0 0
|
||||
RenderVBOEnable 1 0
|
||||
|
||||
// ATI cards generally perform better when not using VBOs for streaming data
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@
|
|||
#include "llviewermenu.h"
|
||||
#include "llviewerobjectlist.h"
|
||||
#include "llviewerparcelmgr.h"
|
||||
#include "llviewerregion.h"
|
||||
#include "llviewerstats.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "llvoavatarself.h"
|
||||
|
|
@ -113,6 +114,105 @@ const F32 MAX_FIDGET_TIME = 20.f; // seconds
|
|||
// The agent instance.
|
||||
LLAgent gAgent;
|
||||
|
||||
class LLTeleportRequest
|
||||
{
|
||||
public:
|
||||
enum EStatus
|
||||
{
|
||||
kPending,
|
||||
kStarted,
|
||||
kFailed,
|
||||
kRestartPending
|
||||
};
|
||||
|
||||
LLTeleportRequest();
|
||||
virtual ~LLTeleportRequest();
|
||||
|
||||
EStatus getStatus() const {return mStatus;};
|
||||
void setStatus(EStatus pStatus) {mStatus = pStatus;};
|
||||
|
||||
virtual bool canRestartTeleport();
|
||||
|
||||
virtual void startTeleport() = 0;
|
||||
virtual void restartTeleport();
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
EStatus mStatus;
|
||||
};
|
||||
|
||||
class LLTeleportRequestViaLandmark : public LLTeleportRequest
|
||||
{
|
||||
public:
|
||||
LLTeleportRequestViaLandmark(const LLUUID &pLandmarkId);
|
||||
virtual ~LLTeleportRequestViaLandmark();
|
||||
|
||||
virtual bool canRestartTeleport();
|
||||
|
||||
virtual void startTeleport();
|
||||
virtual void restartTeleport();
|
||||
|
||||
protected:
|
||||
inline const LLUUID &getLandmarkId() const {return mLandmarkId;};
|
||||
|
||||
private:
|
||||
LLUUID mLandmarkId;
|
||||
};
|
||||
|
||||
class LLTeleportRequestViaLure : public LLTeleportRequestViaLandmark
|
||||
{
|
||||
public:
|
||||
LLTeleportRequestViaLure(const LLUUID &pLureId, BOOL pIsLureGodLike);
|
||||
virtual ~LLTeleportRequestViaLure();
|
||||
|
||||
virtual bool canRestartTeleport();
|
||||
|
||||
virtual void startTeleport();
|
||||
|
||||
protected:
|
||||
inline BOOL isLureGodLike() const {return mIsLureGodLike;};
|
||||
|
||||
private:
|
||||
BOOL mIsLureGodLike;
|
||||
};
|
||||
|
||||
class LLTeleportRequestViaLocation : public LLTeleportRequest
|
||||
{
|
||||
public:
|
||||
LLTeleportRequestViaLocation(const LLVector3d &pPosGlobal);
|
||||
virtual ~LLTeleportRequestViaLocation();
|
||||
|
||||
virtual bool canRestartTeleport();
|
||||
|
||||
virtual void startTeleport();
|
||||
virtual void restartTeleport();
|
||||
|
||||
protected:
|
||||
inline const LLVector3d &getPosGlobal() const {return mPosGlobal;};
|
||||
|
||||
private:
|
||||
LLVector3d mPosGlobal;
|
||||
};
|
||||
|
||||
|
||||
class LLTeleportRequestViaLocationLookAt : public LLTeleportRequestViaLocation
|
||||
{
|
||||
public:
|
||||
LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal);
|
||||
virtual ~LLTeleportRequestViaLocationLookAt();
|
||||
|
||||
virtual bool canRestartTeleport();
|
||||
|
||||
virtual void startTeleport();
|
||||
virtual void restartTeleport();
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Statics
|
||||
//
|
||||
|
|
@ -247,6 +347,17 @@ LLAgent::LLAgent() :
|
|||
mGodLevelChangeSignal(),
|
||||
mCanEditParcel(false),
|
||||
mTeleportSourceSLURL(new LLSLURL),
|
||||
mTeleportRequest(),
|
||||
mTeleportFinishedSlot(),
|
||||
mTeleportFailedSlot(),
|
||||
mIsMaturityRatingChangingDuringTeleport(false),
|
||||
mMaturityRatingChange(0U),
|
||||
mIsDoSendMaturityPreferenceToServer(false),
|
||||
mMaturityPreferenceRequestId(0U),
|
||||
mMaturityPreferenceResponseId(0U),
|
||||
mMaturityPreferenceNumRetries(0U),
|
||||
mLastKnownRequestMaturity(SIM_ACCESS_MIN),
|
||||
mLastKnownResponseMaturity(SIM_ACCESS_MIN),
|
||||
mTeleportState( TELEPORT_NONE ),
|
||||
mRegionp(NULL),
|
||||
|
||||
|
|
@ -332,9 +443,21 @@ void LLAgent::init()
|
|||
|
||||
gSavedSettings.getControl("PreferredMaturity")->getValidateSignal()->connect(boost::bind(&LLAgent::validateMaturity, this, _2));
|
||||
gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLAgent::handleMaturity, this, _2));
|
||||
mLastKnownResponseMaturity = static_cast<U8>(gSavedSettings.getU32("PreferredMaturity"));
|
||||
mLastKnownRequestMaturity = mLastKnownResponseMaturity;
|
||||
mIsDoSendMaturityPreferenceToServer = true;
|
||||
|
||||
LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback(boost::bind(&LLAgent::parcelChangedCallback));
|
||||
|
||||
if (!mTeleportFinishedSlot.connected())
|
||||
{
|
||||
mTeleportFinishedSlot = LLViewerParcelMgr::getInstance()->setTeleportFinishedCallback(boost::bind(&LLAgent::handleTeleportFinished, this));
|
||||
}
|
||||
if (!mTeleportFailedSlot.connected())
|
||||
{
|
||||
mTeleportFailedSlot = LLViewerParcelMgr::getInstance()->setTeleportFailedCallback(boost::bind(&LLAgent::handleTeleportFailed, this));
|
||||
}
|
||||
|
||||
mInitialized = TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -344,6 +467,14 @@ void LLAgent::init()
|
|||
void LLAgent::cleanup()
|
||||
{
|
||||
mRegionp = NULL;
|
||||
if (mTeleportFinishedSlot.connected())
|
||||
{
|
||||
mTeleportFinishedSlot.disconnect();
|
||||
}
|
||||
if (mTeleportFailedSlot.connected())
|
||||
{
|
||||
mTeleportFailedSlot.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -2375,49 +2506,278 @@ bool LLAgent::isAdult() const
|
|||
return mAgentAccess->isAdult();
|
||||
}
|
||||
|
||||
void LLAgent::setTeen(bool teen)
|
||||
{
|
||||
mAgentAccess->setTeen(teen);
|
||||
}
|
||||
|
||||
//static
|
||||
int LLAgent::convertTextToMaturity(char text)
|
||||
{
|
||||
return LLAgentAccess::convertTextToMaturity(text);
|
||||
}
|
||||
|
||||
bool LLAgent::sendMaturityPreferenceToServer(int preferredMaturity)
|
||||
class LLMaturityPreferencesResponder : public LLHTTPClient::Responder
|
||||
{
|
||||
if (!getRegion())
|
||||
return false;
|
||||
|
||||
// Update agent access preference on the server
|
||||
std::string url = getRegion()->getCapability("UpdateAgentInformation");
|
||||
if (!url.empty())
|
||||
public:
|
||||
LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity);
|
||||
virtual ~LLMaturityPreferencesResponder();
|
||||
|
||||
virtual void result(const LLSD &pContent);
|
||||
virtual void error(U32 pStatus, const std::string& pReason);
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
U8 parseMaturityFromServerResponse(const LLSD &pContent);
|
||||
|
||||
LLAgent *mAgent;
|
||||
U8 mPreferredMaturity;
|
||||
U8 mPreviousMaturity;
|
||||
};
|
||||
|
||||
LLMaturityPreferencesResponder::LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity)
|
||||
: LLHTTPClient::Responder(),
|
||||
mAgent(pAgent),
|
||||
mPreferredMaturity(pPreferredMaturity),
|
||||
mPreviousMaturity(pPreviousMaturity)
|
||||
{
|
||||
}
|
||||
|
||||
LLMaturityPreferencesResponder::~LLMaturityPreferencesResponder()
|
||||
{
|
||||
}
|
||||
|
||||
void LLMaturityPreferencesResponder::result(const LLSD &pContent)
|
||||
{
|
||||
U8 actualMaturity = parseMaturityFromServerResponse(pContent);
|
||||
|
||||
if (actualMaturity != mPreferredMaturity)
|
||||
{
|
||||
// Set new access preference
|
||||
LLSD access_prefs = LLSD::emptyMap();
|
||||
if (preferredMaturity == SIM_ACCESS_PG)
|
||||
{
|
||||
access_prefs["max"] = "PG";
|
||||
}
|
||||
else if (preferredMaturity == SIM_ACCESS_MATURE)
|
||||
{
|
||||
access_prefs["max"] = "M";
|
||||
}
|
||||
if (preferredMaturity == SIM_ACCESS_ADULT)
|
||||
{
|
||||
access_prefs["max"] = "A";
|
||||
}
|
||||
|
||||
LLSD body = LLSD::emptyMap();
|
||||
body["access_prefs"] = access_prefs;
|
||||
llinfos << "Sending access prefs update to " << (access_prefs["max"].asString()) << " via capability to: "
|
||||
<< url << llendl;
|
||||
LLHTTPClient::post(url, body, new LLHTTPClient::Responder()); // Ignore response
|
||||
return true;
|
||||
llwarns << "while attempting to change maturity preference from '" << LLViewerRegion::accessToString(mPreviousMaturity)
|
||||
<< "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) << "', the server responded with '"
|
||||
<< LLViewerRegion::accessToString(actualMaturity) << "' [value:" << static_cast<U32>(actualMaturity) << ", llsd:"
|
||||
<< pContent << "]" << llendl;
|
||||
}
|
||||
mAgent->handlePreferredMaturityResult(actualMaturity);
|
||||
}
|
||||
|
||||
void LLMaturityPreferencesResponder::error(U32 pStatus, const std::string& pReason)
|
||||
{
|
||||
llwarns << "while attempting to change maturity preference from '" << LLViewerRegion::accessToString(mPreviousMaturity)
|
||||
<< "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) << "', we got an error because '"
|
||||
<< pReason << "' [status:" << pStatus << "]" << llendl;
|
||||
mAgent->handlePreferredMaturityError();
|
||||
}
|
||||
|
||||
U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent)
|
||||
{
|
||||
// stinson 05/24/2012 Pathfinding regions have re-defined the response behavior. In the old server code,
|
||||
// if you attempted to change the preferred maturity to the same value, the response content would be an
|
||||
// undefined LLSD block. In the new server code with pathfinding, the response content should always be
|
||||
// defined. Thus, the check for isUndefined() can be replaced with an assert after pathfinding is merged
|
||||
// into server trunk and fully deployed.
|
||||
U8 maturity = SIM_ACCESS_MIN;
|
||||
if (pContent.isUndefined())
|
||||
{
|
||||
maturity = mPreferredMaturity;
|
||||
}
|
||||
else
|
||||
{
|
||||
llassert(!pContent.isUndefined());
|
||||
llassert(pContent.isMap());
|
||||
|
||||
if (!pContent.isUndefined() && pContent.isMap())
|
||||
{
|
||||
// stinson 05/24/2012 Pathfinding regions have re-defined the response syntax. The if statement catches
|
||||
// the new syntax, and the else statement catches the old syntax. After pathfinding is merged into
|
||||
// server trunk and fully deployed, we can remove the else statement.
|
||||
if (pContent.has("access_prefs"))
|
||||
{
|
||||
llassert(pContent.has("access_prefs"));
|
||||
llassert(pContent.get("access_prefs").isMap());
|
||||
llassert(pContent.get("access_prefs").has("max"));
|
||||
llassert(pContent.get("access_prefs").get("max").isString());
|
||||
if (pContent.get("access_prefs").isMap() && pContent.get("access_prefs").has("max") &&
|
||||
pContent.get("access_prefs").get("max").isString())
|
||||
{
|
||||
LLSD::String actualPreference = pContent.get("access_prefs").get("max").asString();
|
||||
LLStringUtil::trim(actualPreference);
|
||||
maturity = LLViewerRegion::shortStringToAccess(actualPreference);
|
||||
}
|
||||
}
|
||||
else if (pContent.has("max"))
|
||||
{
|
||||
llassert(pContent.get("max").isString());
|
||||
if (pContent.get("max").isString())
|
||||
{
|
||||
LLSD::String actualPreference = pContent.get("max").asString();
|
||||
LLStringUtil::trim(actualPreference);
|
||||
maturity = LLViewerRegion::shortStringToAccess(actualPreference);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maturity;
|
||||
}
|
||||
|
||||
void LLAgent::handlePreferredMaturityResult(U8 pServerMaturity)
|
||||
{
|
||||
// Update the number of responses received
|
||||
++mMaturityPreferenceResponseId;
|
||||
llassert(mMaturityPreferenceResponseId <= mMaturityPreferenceRequestId);
|
||||
|
||||
// Update the last known server maturity response
|
||||
mLastKnownResponseMaturity = pServerMaturity;
|
||||
|
||||
// Ignore all responses if we know there are more unanswered requests that are expected
|
||||
if (mMaturityPreferenceResponseId == mMaturityPreferenceRequestId)
|
||||
{
|
||||
// If we received a response that matches the last known request, then we are good
|
||||
if (mLastKnownRequestMaturity == mLastKnownResponseMaturity)
|
||||
{
|
||||
mMaturityPreferenceNumRetries = 0;
|
||||
reportPreferredMaturitySuccess();
|
||||
llassert(static_cast<U8>(gSavedSettings.getU32("PreferredMaturity")) == mLastKnownResponseMaturity);
|
||||
}
|
||||
// Else, the viewer is out of sync with the server, so let's try to re-sync with the
|
||||
// server by re-sending our last known request. Cap the re-tries at 3 just to be safe.
|
||||
else if (++mMaturityPreferenceNumRetries <= 3)
|
||||
{
|
||||
llinfos << "Retrying attempt #" << mMaturityPreferenceNumRetries << " to set viewer preferred maturity to '"
|
||||
<< LLViewerRegion::accessToString(mLastKnownRequestMaturity) << "'" << llendl;
|
||||
sendMaturityPreferenceToServer(mLastKnownRequestMaturity);
|
||||
}
|
||||
// Else, the viewer is style out of sync with the server after 3 retries, so inform the user
|
||||
else
|
||||
{
|
||||
mMaturityPreferenceNumRetries = 0;
|
||||
reportPreferredMaturityError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLAgent::handlePreferredMaturityError()
|
||||
{
|
||||
// Update the number of responses received
|
||||
++mMaturityPreferenceResponseId;
|
||||
llassert(mMaturityPreferenceResponseId <= mMaturityPreferenceRequestId);
|
||||
|
||||
// Ignore all responses if we know there are more unanswered requests that are expected
|
||||
if (mMaturityPreferenceResponseId == mMaturityPreferenceRequestId)
|
||||
{
|
||||
mMaturityPreferenceNumRetries = 0;
|
||||
|
||||
// If we received a response that matches the last known request, then we are synced with
|
||||
// the server, but not quite sure why we are
|
||||
if (mLastKnownRequestMaturity == mLastKnownResponseMaturity)
|
||||
{
|
||||
llwarns << "Got an error but maturity preference '" << LLViewerRegion::accessToString(mLastKnownRequestMaturity)
|
||||
<< "' seems to be in sync with the server" << llendl;
|
||||
reportPreferredMaturitySuccess();
|
||||
}
|
||||
// Else, the more likely case is that the last request does not match the last response,
|
||||
// so inform the user
|
||||
else
|
||||
{
|
||||
reportPreferredMaturityError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLAgent::reportPreferredMaturitySuccess()
|
||||
{
|
||||
// If there is a pending teleport request waiting for the maturity preference to be synced with
|
||||
// the server, let's start the pending request
|
||||
if (hasPendingTeleportRequest())
|
||||
{
|
||||
startTeleportRequest();
|
||||
}
|
||||
}
|
||||
|
||||
void LLAgent::reportPreferredMaturityError()
|
||||
{
|
||||
// If there is a pending teleport request waiting for the maturity preference to be synced with
|
||||
// the server, we were unable to successfully sync with the server on maturity preference, so let's
|
||||
// just raise the screen.
|
||||
mIsMaturityRatingChangingDuringTeleport = false;
|
||||
if (hasPendingTeleportRequest())
|
||||
{
|
||||
setTeleportState(LLAgent::TELEPORT_NONE);
|
||||
}
|
||||
|
||||
// Get the last known maturity request from the user activity
|
||||
std::string preferredMaturity = LLViewerRegion::accessToString(mLastKnownRequestMaturity);
|
||||
LLStringUtil::toLower(preferredMaturity);
|
||||
|
||||
// Get the last known maturity response from the server
|
||||
std::string actualMaturity = LLViewerRegion::accessToString(mLastKnownResponseMaturity);
|
||||
LLStringUtil::toLower(actualMaturity);
|
||||
|
||||
// Notify the user
|
||||
LLSD args = LLSD::emptyMap();
|
||||
args["PREFERRED_MATURITY"] = preferredMaturity;
|
||||
args["ACTUAL_MATURITY"] = actualMaturity;
|
||||
LLNotificationsUtil::add("MaturityChangeError", args);
|
||||
|
||||
// Check the saved settings to ensure that we are consistent. If we are not consistent, update
|
||||
// the viewer, but do not send anything to server
|
||||
U8 localMaturity = static_cast<U8>(gSavedSettings.getU32("PreferredMaturity"));
|
||||
if (localMaturity != mLastKnownResponseMaturity)
|
||||
{
|
||||
bool tmpIsDoSendMaturityPreferenceToServer = mIsDoSendMaturityPreferenceToServer;
|
||||
mIsDoSendMaturityPreferenceToServer = false;
|
||||
llinfos << "Setting viewer preferred maturity to '" << LLViewerRegion::accessToString(mLastKnownResponseMaturity) << "'" << llendl;
|
||||
gSavedSettings.setU32("PreferredMaturity", static_cast<U32>(mLastKnownResponseMaturity));
|
||||
mIsDoSendMaturityPreferenceToServer = tmpIsDoSendMaturityPreferenceToServer;
|
||||
}
|
||||
}
|
||||
|
||||
bool LLAgent::isMaturityPreferenceSyncedWithServer() const
|
||||
{
|
||||
return (mMaturityPreferenceRequestId == mMaturityPreferenceResponseId);
|
||||
}
|
||||
|
||||
void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity)
|
||||
{
|
||||
// Only send maturity preference to the server if enabled
|
||||
if (mIsDoSendMaturityPreferenceToServer)
|
||||
{
|
||||
// Increment the number of requests. The handlers manage a separate count of responses.
|
||||
++mMaturityPreferenceRequestId;
|
||||
|
||||
// Update the last know maturity request
|
||||
mLastKnownRequestMaturity = pPreferredMaturity;
|
||||
|
||||
// Create a response handler
|
||||
LLHTTPClient::ResponderPtr responderPtr = LLHTTPClient::ResponderPtr(new LLMaturityPreferencesResponder(this, pPreferredMaturity, mLastKnownResponseMaturity));
|
||||
|
||||
// If we don't have a region, report it as an error
|
||||
if (getRegion() == NULL)
|
||||
{
|
||||
responderPtr->error(0U, "region is not defined");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find the capability to send maturity preference
|
||||
std::string url = getRegion()->getCapability("UpdateAgentInformation");
|
||||
|
||||
// If the capability is not defined, report it as an error
|
||||
if (url.empty())
|
||||
{
|
||||
responderPtr->error(0U, "capability 'UpdateAgentInformation' is not defined for region");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set new access preference
|
||||
LLSD access_prefs = LLSD::emptyMap();
|
||||
access_prefs["max"] = LLViewerRegion::accessToShortString(pPreferredMaturity);
|
||||
|
||||
LLSD body = LLSD::emptyMap();
|
||||
body["access_prefs"] = access_prefs;
|
||||
llinfos << "Sending viewer preferred maturity to '" << LLViewerRegion::accessToString(pPreferredMaturity)
|
||||
<< "' via capability to: " << url << llendl;
|
||||
LLSD headers;
|
||||
LLHTTPClient::post(url, body, responderPtr, headers, 30.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOL LLAgent::getAdminOverride() const
|
||||
|
|
@ -2446,11 +2806,6 @@ LLAgent::god_level_change_slot_t LLAgent::registerGodLevelChanageListener(god_le
|
|||
return mGodLevelChangeSignal.connect(pGodLevelChangeCallback);
|
||||
}
|
||||
|
||||
void LLAgent::setAOTransition()
|
||||
{
|
||||
mAgentAccess->setTransition();
|
||||
}
|
||||
|
||||
const LLAgentAccess& LLAgent::getAgentAccess()
|
||||
{
|
||||
return *mAgentAccess;
|
||||
|
|
@ -2461,9 +2816,9 @@ bool LLAgent::validateMaturity(const LLSD& newvalue)
|
|||
return mAgentAccess->canSetMaturity(newvalue.asInteger());
|
||||
}
|
||||
|
||||
void LLAgent::handleMaturity(const LLSD& newvalue)
|
||||
void LLAgent::handleMaturity(const LLSD &pNewValue)
|
||||
{
|
||||
sendMaturityPreferenceToServer(newvalue.asInteger());
|
||||
sendMaturityPreferenceToServer(static_cast<U8>(pNewValue.asInteger()));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
@ -3398,7 +3753,7 @@ void LLAgent::clearVisualParams(void *data)
|
|||
// protected
|
||||
bool LLAgent::teleportCore(bool is_local)
|
||||
{
|
||||
if(TELEPORT_NONE != mTeleportState)
|
||||
if ((TELEPORT_NONE != mTeleportState) && (mTeleportState != TELEPORT_PENDING))
|
||||
{
|
||||
llwarns << "Attempt to teleport when already teleporting." << llendl;
|
||||
return false;
|
||||
|
|
@ -3476,6 +3831,102 @@ bool LLAgent::teleportCore(bool is_local)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool LLAgent::hasRestartableFailedTeleportRequest()
|
||||
{
|
||||
return ((mTeleportRequest != NULL) && (mTeleportRequest->getStatus() == LLTeleportRequest::kFailed) &&
|
||||
mTeleportRequest->canRestartTeleport());
|
||||
}
|
||||
|
||||
void LLAgent::restartFailedTeleportRequest()
|
||||
{
|
||||
if (hasRestartableFailedTeleportRequest())
|
||||
{
|
||||
mTeleportRequest->setStatus(LLTeleportRequest::kRestartPending);
|
||||
startTeleportRequest();
|
||||
}
|
||||
}
|
||||
|
||||
void LLAgent::clearTeleportRequest()
|
||||
{
|
||||
mTeleportRequest.reset();
|
||||
}
|
||||
|
||||
void LLAgent::setMaturityRatingChangeDuringTeleport(U8 pMaturityRatingChange)
|
||||
{
|
||||
mIsMaturityRatingChangingDuringTeleport = true;
|
||||
mMaturityRatingChange = pMaturityRatingChange;
|
||||
}
|
||||
|
||||
bool LLAgent::hasPendingTeleportRequest()
|
||||
{
|
||||
return ((mTeleportRequest != NULL) &&
|
||||
((mTeleportRequest->getStatus() == LLTeleportRequest::kPending) ||
|
||||
(mTeleportRequest->getStatus() == LLTeleportRequest::kRestartPending)));
|
||||
}
|
||||
|
||||
void LLAgent::startTeleportRequest()
|
||||
{
|
||||
if (hasPendingTeleportRequest())
|
||||
{
|
||||
if (!isMaturityPreferenceSyncedWithServer())
|
||||
{
|
||||
gTeleportDisplay = TRUE;
|
||||
setTeleportState(TELEPORT_PENDING);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (mTeleportRequest->getStatus())
|
||||
{
|
||||
case LLTeleportRequest::kPending :
|
||||
mTeleportRequest->setStatus(LLTeleportRequest::kStarted);
|
||||
mTeleportRequest->startTeleport();
|
||||
break;
|
||||
case LLTeleportRequest::kRestartPending :
|
||||
llassert(mTeleportRequest->canRestartTeleport());
|
||||
mTeleportRequest->setStatus(LLTeleportRequest::kStarted);
|
||||
mTeleportRequest->restartTeleport();
|
||||
break;
|
||||
default :
|
||||
llassert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLAgent::handleTeleportFinished()
|
||||
{
|
||||
clearTeleportRequest();
|
||||
if (mIsMaturityRatingChangingDuringTeleport)
|
||||
{
|
||||
// notify user that the maturity preference has been changed
|
||||
std::string maturityRating = LLViewerRegion::accessToString(mMaturityRatingChange);
|
||||
LLStringUtil::toLower(maturityRating);
|
||||
LLSD args;
|
||||
args["RATING"] = maturityRating;
|
||||
LLNotificationsUtil::add("PreferredMaturityChanged", args);
|
||||
mIsMaturityRatingChangingDuringTeleport = false;
|
||||
}
|
||||
}
|
||||
|
||||
void LLAgent::handleTeleportFailed()
|
||||
{
|
||||
if (mTeleportRequest != NULL)
|
||||
{
|
||||
mTeleportRequest->setStatus(LLTeleportRequest::kFailed);
|
||||
}
|
||||
if (mIsMaturityRatingChangingDuringTeleport)
|
||||
{
|
||||
// notify user that the maturity preference has been changed
|
||||
std::string maturityRating = LLViewerRegion::accessToString(mMaturityRatingChange);
|
||||
LLStringUtil::toLower(maturityRating);
|
||||
LLSD args;
|
||||
args["RATING"] = maturityRating;
|
||||
LLNotificationsUtil::add("PreferredMaturityChanged", args);
|
||||
mIsMaturityRatingChangingDuringTeleport = false;
|
||||
}
|
||||
}
|
||||
|
||||
void LLAgent::teleportRequest(
|
||||
const U64& region_handle,
|
||||
const LLVector3& pos_local,
|
||||
|
|
@ -3507,6 +3958,12 @@ void LLAgent::teleportRequest(
|
|||
|
||||
// Landmark ID = LLUUID::null means teleport home
|
||||
void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id)
|
||||
{
|
||||
mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLandmark(landmark_asset_id));
|
||||
startTeleportRequest();
|
||||
}
|
||||
|
||||
void LLAgent::doTeleportViaLandmark(const LLUUID& landmark_asset_id)
|
||||
{
|
||||
LLViewerRegion *regionp = getRegion();
|
||||
if(regionp && teleportCore())
|
||||
|
|
@ -3522,6 +3979,12 @@ void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id)
|
|||
}
|
||||
|
||||
void LLAgent::teleportViaLure(const LLUUID& lure_id, BOOL godlike)
|
||||
{
|
||||
mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLure(lure_id, godlike));
|
||||
startTeleportRequest();
|
||||
}
|
||||
|
||||
void LLAgent::doTeleportViaLure(const LLUUID& lure_id, BOOL godlike)
|
||||
{
|
||||
LLViewerRegion* regionp = getRegion();
|
||||
if(regionp && teleportCore())
|
||||
|
|
@ -3554,23 +4017,32 @@ void LLAgent::teleportViaLure(const LLUUID& lure_id, BOOL godlike)
|
|||
// James Cook, July 28, 2005
|
||||
void LLAgent::teleportCancel()
|
||||
{
|
||||
LLViewerRegion* regionp = getRegion();
|
||||
if(regionp)
|
||||
if (!hasPendingTeleportRequest())
|
||||
{
|
||||
// send the message
|
||||
LLMessageSystem* msg = gMessageSystem;
|
||||
msg->newMessage("TeleportCancel");
|
||||
msg->nextBlockFast(_PREHASH_Info);
|
||||
msg->addUUIDFast(_PREHASH_AgentID, getID());
|
||||
msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
|
||||
sendReliableMessage();
|
||||
}
|
||||
gTeleportDisplay = FALSE;
|
||||
LLViewerRegion* regionp = getRegion();
|
||||
if(regionp)
|
||||
{
|
||||
// send the message
|
||||
LLMessageSystem* msg = gMessageSystem;
|
||||
msg->newMessage("TeleportCancel");
|
||||
msg->nextBlockFast(_PREHASH_Info);
|
||||
msg->addUUIDFast(_PREHASH_AgentID, getID());
|
||||
msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
|
||||
sendReliableMessage();
|
||||
}
|
||||
}
|
||||
clearTeleportRequest();
|
||||
gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
|
||||
}
|
||||
|
||||
|
||||
void LLAgent::teleportViaLocation(const LLVector3d& pos_global)
|
||||
{
|
||||
mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocation(pos_global));
|
||||
startTeleportRequest();
|
||||
}
|
||||
|
||||
void LLAgent::doTeleportViaLocation(const LLVector3d& pos_global)
|
||||
{
|
||||
LLViewerRegion* regionp = getRegion();
|
||||
U64 handle = to_region_handle(pos_global);
|
||||
|
|
@ -3613,6 +4085,12 @@ void LLAgent::teleportViaLocation(const LLVector3d& pos_global)
|
|||
|
||||
// Teleport to global position, but keep facing in the same direction
|
||||
void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global)
|
||||
{
|
||||
mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocationLookAt(pos_global));
|
||||
startTeleportRequest();
|
||||
}
|
||||
|
||||
void LLAgent::doTeleportViaLocationLookAt(const LLVector3d& pos_global)
|
||||
{
|
||||
mbTeleportKeepsLookAt = true;
|
||||
gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); // detach camera form avatar, so it keeps direction
|
||||
|
|
@ -4055,5 +4533,149 @@ LLAgentQueryManager::~LLAgentQueryManager()
|
|||
{
|
||||
}
|
||||
|
||||
// EOF
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLTeleportRequest
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LLTeleportRequest::LLTeleportRequest()
|
||||
: mStatus(kPending)
|
||||
{
|
||||
}
|
||||
|
||||
LLTeleportRequest::~LLTeleportRequest()
|
||||
{
|
||||
}
|
||||
|
||||
bool LLTeleportRequest::canRestartTeleport()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLTeleportRequest::restartTeleport()
|
||||
{
|
||||
llassert(0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLTeleportRequestViaLandmark
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LLTeleportRequestViaLandmark::LLTeleportRequestViaLandmark(const LLUUID &pLandmarkId)
|
||||
: LLTeleportRequest(),
|
||||
mLandmarkId(pLandmarkId)
|
||||
{
|
||||
}
|
||||
|
||||
LLTeleportRequestViaLandmark::~LLTeleportRequestViaLandmark()
|
||||
{
|
||||
}
|
||||
|
||||
bool LLTeleportRequestViaLandmark::canRestartTeleport()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLTeleportRequestViaLandmark::startTeleport()
|
||||
{
|
||||
gAgent.doTeleportViaLandmark(getLandmarkId());
|
||||
}
|
||||
|
||||
void LLTeleportRequestViaLandmark::restartTeleport()
|
||||
{
|
||||
gAgent.doTeleportViaLandmark(getLandmarkId());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLTeleportRequestViaLure
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LLTeleportRequestViaLure::LLTeleportRequestViaLure(const LLUUID &pLureId, BOOL pIsLureGodLike)
|
||||
: LLTeleportRequestViaLandmark(pLureId),
|
||||
mIsLureGodLike(pIsLureGodLike)
|
||||
{
|
||||
}
|
||||
|
||||
LLTeleportRequestViaLure::~LLTeleportRequestViaLure()
|
||||
{
|
||||
}
|
||||
|
||||
bool LLTeleportRequestViaLure::canRestartTeleport()
|
||||
{
|
||||
// stinson 05/17/2012 : cannot restart a teleport via lure because of server-side restrictions
|
||||
// The current scenario is as follows:
|
||||
// 1. User A initializes a request for User B to teleport via lure
|
||||
// 2. User B accepts the teleport via lure request
|
||||
// 3. The server sees the init request from User A and the accept request from User B and matches them up
|
||||
// 4. The server then removes the paired requests up from the "queue"
|
||||
// 5. The server then fails User B's teleport for reason of maturity level (for example)
|
||||
// 6. User B's viewer prompts user to increase their maturity level profile value.
|
||||
// 7. User B confirms and accepts increase in maturity level
|
||||
// 8. User B's viewer then attempts to teleport via lure again
|
||||
// 9. This request will time-out on the viewer-side because User A's initial request has been removed from the "queue" in step 4
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLTeleportRequestViaLure::startTeleport()
|
||||
{
|
||||
gAgent.doTeleportViaLure(getLandmarkId(), isLureGodLike());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLTeleportRequestViaLocation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LLTeleportRequestViaLocation::LLTeleportRequestViaLocation(const LLVector3d &pPosGlobal)
|
||||
: LLTeleportRequest(),
|
||||
mPosGlobal(pPosGlobal)
|
||||
{
|
||||
}
|
||||
|
||||
LLTeleportRequestViaLocation::~LLTeleportRequestViaLocation()
|
||||
{
|
||||
}
|
||||
|
||||
bool LLTeleportRequestViaLocation::canRestartTeleport()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLTeleportRequestViaLocation::startTeleport()
|
||||
{
|
||||
gAgent.doTeleportViaLocation(getPosGlobal());
|
||||
}
|
||||
|
||||
void LLTeleportRequestViaLocation::restartTeleport()
|
||||
{
|
||||
gAgent.doTeleportViaLocation(getPosGlobal());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLTeleportRequestViaLocationLookAt
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LLTeleportRequestViaLocationLookAt::LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal)
|
||||
: LLTeleportRequestViaLocation(pPosGlobal)
|
||||
{
|
||||
}
|
||||
|
||||
LLTeleportRequestViaLocationLookAt::~LLTeleportRequestViaLocationLookAt()
|
||||
{
|
||||
}
|
||||
|
||||
bool LLTeleportRequestViaLocationLookAt::canRestartTeleport()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLTeleportRequestViaLocationLookAt::startTeleport()
|
||||
{
|
||||
gAgent.doTeleportViaLocationLookAt(getPosGlobal());
|
||||
}
|
||||
|
||||
void LLTeleportRequestViaLocationLookAt::restartTeleport()
|
||||
{
|
||||
gAgent.doTeleportViaLocationLookAt(getPosGlobal());
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@
|
|||
#include "llcoordframe.h" // for mFrameAgent
|
||||
#include "llvoavatardefines.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
extern const BOOL ANIMATE;
|
||||
|
|
@ -56,6 +58,9 @@ class LLAgentAccess;
|
|||
class LLSLURL;
|
||||
class LLPauseRequestHandle;
|
||||
class LLUIColor;
|
||||
class LLTeleportRequest;
|
||||
|
||||
typedef boost::shared_ptr<LLTeleportRequest> LLTeleportRequestPtr;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Types
|
||||
|
|
@ -539,7 +544,8 @@ public:
|
|||
TELEPORT_MOVING = 3, // Viewer has received destination location from source simulator
|
||||
TELEPORT_START_ARRIVAL = 4, // Transition to ARRIVING. Viewer has received avatar update, etc., from destination simulator
|
||||
TELEPORT_ARRIVING = 5, // Make the user wait while content "pre-caches"
|
||||
TELEPORT_LOCAL = 6 // Teleporting in-sim without showing the progress screen
|
||||
TELEPORT_LOCAL = 6, // Teleporting in-sim without showing the progress screen
|
||||
TELEPORT_PENDING = 7
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
@ -556,9 +562,6 @@ private:
|
|||
// Teleport Actions
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
void teleportRequest(const U64& region_handle,
|
||||
const LLVector3& pos_local, // Go to a named location home
|
||||
bool look_at_from_camera = false);
|
||||
void teleportViaLandmark(const LLUUID& landmark_id); // Teleport to a landmark
|
||||
void teleportHome() { teleportViaLandmark(LLUUID::null); } // Go home
|
||||
void teleportViaLure(const LLUUID& lure_id, BOOL godlike); // To an invited location
|
||||
|
|
@ -569,6 +572,44 @@ public:
|
|||
protected:
|
||||
bool teleportCore(bool is_local = false); // Stuff for all teleports; returns true if the teleport can proceed
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Teleport State
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
bool hasRestartableFailedTeleportRequest();
|
||||
void restartFailedTeleportRequest();
|
||||
void clearTeleportRequest();
|
||||
void setMaturityRatingChangeDuringTeleport(U8 pMaturityRatingChange);
|
||||
|
||||
private:
|
||||
friend class LLTeleportRequest;
|
||||
friend class LLTeleportRequestViaLandmark;
|
||||
friend class LLTeleportRequestViaLure;
|
||||
friend class LLTeleportRequestViaLocation;
|
||||
friend class LLTeleportRequestViaLocationLookAt;
|
||||
|
||||
LLTeleportRequestPtr mTeleportRequest;
|
||||
boost::signals2::connection mTeleportFinishedSlot;
|
||||
boost::signals2::connection mTeleportFailedSlot;
|
||||
|
||||
bool mIsMaturityRatingChangingDuringTeleport;
|
||||
U8 mMaturityRatingChange;
|
||||
|
||||
bool hasPendingTeleportRequest();
|
||||
void startTeleportRequest();
|
||||
|
||||
void teleportRequest(const U64& region_handle,
|
||||
const LLVector3& pos_local, // Go to a named location home
|
||||
bool look_at_from_camera = false);
|
||||
void doTeleportViaLandmark(const LLUUID& landmark_id); // Teleport to a landmark
|
||||
void doTeleportViaLure(const LLUUID& lure_id, BOOL godlike); // To an invited location
|
||||
void doTeleportViaLocation(const LLVector3d& pos_global); // To a global location - this will probably need to be deprecated
|
||||
void doTeleportViaLocationLookAt(const LLVector3d& pos_global);// To a global location, preserving camera rotation
|
||||
|
||||
void handleTeleportFinished();
|
||||
void handleTeleportFailed();
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Teleport State
|
||||
//--------------------------------------------------------------------
|
||||
|
|
@ -614,8 +655,6 @@ public:
|
|||
const LLAgentAccess& getAgentAccess();
|
||||
BOOL canManageEstate() const;
|
||||
BOOL getAdminOverride() const;
|
||||
// ! BACKWARDS COMPATIBILITY ! This function can go away after the AO transition (see llstartup.cpp).
|
||||
void setAOTransition();
|
||||
private:
|
||||
LLAgentAccess * mAgentAccess;
|
||||
|
||||
|
|
@ -660,13 +699,28 @@ public:
|
|||
bool isTeen() const;
|
||||
bool isMature() const;
|
||||
bool isAdult() const;
|
||||
void setTeen(bool teen);
|
||||
void setMaturity(char text);
|
||||
static int convertTextToMaturity(char text);
|
||||
bool sendMaturityPreferenceToServer(int preferredMaturity); // ! "U8" instead of "int"?
|
||||
static int convertTextToMaturity(char text);
|
||||
|
||||
private:
|
||||
bool mIsDoSendMaturityPreferenceToServer;
|
||||
unsigned int mMaturityPreferenceRequestId;
|
||||
unsigned int mMaturityPreferenceResponseId;
|
||||
unsigned int mMaturityPreferenceNumRetries;
|
||||
U8 mLastKnownRequestMaturity;
|
||||
U8 mLastKnownResponseMaturity;
|
||||
|
||||
bool isMaturityPreferenceSyncedWithServer() const;
|
||||
void sendMaturityPreferenceToServer(U8 pPreferredMaturity);
|
||||
|
||||
friend class LLMaturityPreferencesResponder;
|
||||
void handlePreferredMaturityResult(U8 pServerMaturity);
|
||||
void handlePreferredMaturityError();
|
||||
void reportPreferredMaturitySuccess();
|
||||
void reportPreferredMaturityError();
|
||||
|
||||
// Maturity callbacks for PreferredMaturity control variable
|
||||
void handleMaturity(const LLSD& newvalue);
|
||||
void handleMaturity(const LLSD &pNewValue);
|
||||
bool validateMaturity(const LLSD& newvalue);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -33,8 +33,7 @@ LLAgentAccess::LLAgentAccess(LLControlGroup& savedSettings) :
|
|||
mSavedSettings(savedSettings),
|
||||
mAccess(SIM_ACCESS_PG),
|
||||
mAdminOverride(false),
|
||||
mGodLevel(GOD_NOT),
|
||||
mAOTransition(false)
|
||||
mGodLevel(GOD_NOT)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -133,18 +132,6 @@ bool LLAgentAccess::isAdult() const
|
|||
return mAccess >= SIM_ACCESS_ADULT;
|
||||
}
|
||||
|
||||
void LLAgentAccess::setTeen(bool teen)
|
||||
{
|
||||
if (teen)
|
||||
{
|
||||
mAccess = SIM_ACCESS_PG;
|
||||
}
|
||||
else
|
||||
{
|
||||
mAccess = SIM_ACCESS_MATURE;
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
int LLAgentAccess::convertTextToMaturity(char text)
|
||||
{
|
||||
|
|
@ -182,16 +169,6 @@ void LLAgentAccess::setMaturity(char text)
|
|||
mSavedSettings.setU32("PreferredMaturity", preferred_access);
|
||||
}
|
||||
|
||||
void LLAgentAccess::setTransition()
|
||||
{
|
||||
mAOTransition = true;
|
||||
}
|
||||
|
||||
bool LLAgentAccess::isInTransition() const
|
||||
{
|
||||
return mAOTransition;
|
||||
}
|
||||
|
||||
bool LLAgentAccess::canSetMaturity(S32 maturity)
|
||||
{
|
||||
if (isGodlike()) // Gods can always set their Maturity level
|
||||
|
|
|
|||
|
|
@ -59,13 +59,10 @@ public:
|
|||
bool isMature() const;
|
||||
bool isAdult() const;
|
||||
|
||||
void setTeen(bool teen);
|
||||
void setMaturity(char text);
|
||||
|
||||
static int convertTextToMaturity(char text);
|
||||
|
||||
void setTransition(); // sets the transition bit, which defaults to false
|
||||
bool isInTransition() const;
|
||||
bool canSetMaturity(S32 maturity);
|
||||
|
||||
private:
|
||||
|
|
@ -73,13 +70,6 @@ private:
|
|||
U8 mGodLevel;
|
||||
bool mAdminOverride;
|
||||
|
||||
// this should be deleted after the 60-day AO transition.
|
||||
// It should be safe to remove it in Viewer 2009
|
||||
// It's set by a special short-term flag in login.cgi
|
||||
// called ao_transition. When that's gone, this can go, along with
|
||||
// all of the code that depends on it.
|
||||
bool mAOTransition;
|
||||
|
||||
LLControlGroup& mSavedSettings;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -229,12 +229,13 @@ LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit
|
|||
|
||||
LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy()
|
||||
{
|
||||
LL_INFOS("Avatar") << self_av_string() << "done update appearance on destroy" << LL_ENDL;
|
||||
|
||||
selfStopPhase("update_appearance_on_destroy");
|
||||
|
||||
if (!LLApp::isExiting())
|
||||
{
|
||||
// speculative fix for MAINT-1150
|
||||
LL_INFOS("Avatar") << self_av_string() << "done update appearance on destroy" << LL_ENDL;
|
||||
|
||||
selfStopPhase("update_appearance_on_destroy");
|
||||
|
||||
LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
#include "llupdaterservice.h"
|
||||
#include "llcallfloater.h"
|
||||
#include "llfloatertexturefetchdebugger.h"
|
||||
#include "llspellcheck.h"
|
||||
|
||||
// Linden library includes
|
||||
#include "llavatarnamecache.h"
|
||||
|
|
@ -118,6 +119,7 @@
|
|||
// Third party library includes
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
|
||||
|
||||
|
|
@ -626,6 +628,7 @@ LLAppViewer::LLAppViewer() :
|
|||
mPurgeOnExit(false),
|
||||
mSecondInstance(false),
|
||||
mSavedFinalSnapshot(false),
|
||||
mSavePerAccountSettings(false), // don't save settings on logout unless login succeeded.
|
||||
mForceGraphicsDetail(false),
|
||||
mQuitRequested(false),
|
||||
mLogoutRequestSent(false),
|
||||
|
|
@ -1163,6 +1166,8 @@ void LLAppViewer::checkMemory()
|
|||
|
||||
static LLFastTimer::DeclareTimer FTM_MESSAGES("System Messages");
|
||||
static LLFastTimer::DeclareTimer FTM_SLEEP("Sleep");
|
||||
static LLFastTimer::DeclareTimer FTM_YIELD("Yield");
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_TEXTURE_CACHE("Texture Cache");
|
||||
static LLFastTimer::DeclareTimer FTM_DECODE("Image Decode");
|
||||
static LLFastTimer::DeclareTimer FTM_VFS("VFS Thread");
|
||||
|
|
@ -1348,6 +1353,7 @@ bool LLAppViewer::mainLoop()
|
|||
// yield some time to the os based on command line option
|
||||
if(mYieldTime >= 0)
|
||||
{
|
||||
LLFastTimer t(FTM_YIELD);
|
||||
ms_sleep(mYieldTime);
|
||||
}
|
||||
|
||||
|
|
@ -1800,6 +1806,13 @@ bool LLAppViewer::cleanup()
|
|||
{
|
||||
llinfos << "Not saving per-account settings; don't know the account name yet." << llendl;
|
||||
}
|
||||
// Only save per account settings if the previous login succeeded, otherwise
|
||||
// we might end up with a cleared out settings file in case a previous login
|
||||
// failed after loading per account settings.
|
||||
else if (!mSavePerAccountSettings)
|
||||
{
|
||||
llinfos << "Not saving per-account settings; last login was not successful." << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE);
|
||||
|
|
@ -2554,6 +2567,19 @@ bool LLAppViewer::initConfiguration()
|
|||
//gDirUtilp->setSkinFolder("default");
|
||||
}
|
||||
|
||||
if (gSavedSettings.getBOOL("SpellCheck"))
|
||||
{
|
||||
std::list<std::string> dict_list;
|
||||
std::string dict_setting = gSavedSettings.getString("SpellCheckDictionary");
|
||||
boost::split(dict_list, dict_setting, boost::is_any_of(std::string(",")));
|
||||
if (!dict_list.empty())
|
||||
{
|
||||
LLSpellChecker::setUseSpellCheck(dict_list.front());
|
||||
dict_list.pop_front();
|
||||
LLSpellChecker::instance().setSecondaryDictionaries(dict_list);
|
||||
}
|
||||
}
|
||||
|
||||
mYieldTime = gSavedSettings.getS32("YieldTime");
|
||||
|
||||
// Read skin/branding settings if specified.
|
||||
|
|
@ -5013,6 +5039,10 @@ void LLAppViewer::handleLoginComplete()
|
|||
mOnLoginCompleted();
|
||||
|
||||
writeDebugInfo();
|
||||
|
||||
// we logged in successfully, so save settings on logout
|
||||
llinfos << "Login successful, per account settings will be saved on log out." << llendl;
|
||||
mSavePerAccountSettings=true;
|
||||
}
|
||||
|
||||
void LLAppViewer::launchUpdater()
|
||||
|
|
|
|||
|
|
@ -247,6 +247,7 @@ private:
|
|||
bool mPurgeOnExit;
|
||||
|
||||
bool mSavedFinalSnapshot;
|
||||
bool mSavePerAccountSettings; // only save per account settings if login succeeded
|
||||
|
||||
bool mForceGraphicsDetail;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,771 @@
|
|||
/**
|
||||
* @file llautoreplace.cpp
|
||||
* @brief Auto Replace Manager
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "llautoreplace.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llboost.h"
|
||||
#include "llcontrol.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llnotificationsutil.h"
|
||||
|
||||
LLAutoReplace* LLAutoReplace::sInstance;
|
||||
|
||||
const char* LLAutoReplace::SETTINGS_FILE_NAME = "autoreplace.xml";
|
||||
|
||||
LLAutoReplace::LLAutoReplace()
|
||||
{
|
||||
}
|
||||
|
||||
LLAutoReplace::~LLAutoReplace()
|
||||
{
|
||||
sInstance = NULL;
|
||||
}
|
||||
|
||||
void LLAutoReplace::autoreplaceCallback(LLUIString& inputText, S32& cursorPos)
|
||||
{
|
||||
static LLCachedControl<bool> perform_autoreplace(gSavedSettings, "AutoReplace");
|
||||
if(perform_autoreplace)
|
||||
{
|
||||
S32 wordEnd = cursorPos-1;
|
||||
LLWString text = inputText.getWString();
|
||||
|
||||
bool atSpace = (text[wordEnd] == ' ');
|
||||
bool haveWord = (LLWStringUtil::isPartOfWord(text[wordEnd]));
|
||||
|
||||
if (atSpace || haveWord)
|
||||
{
|
||||
if (atSpace && wordEnd > 0)
|
||||
{
|
||||
// find out if this space immediately follows a word
|
||||
wordEnd--;
|
||||
haveWord = (LLWStringUtil::isPartOfWord(text[wordEnd]));
|
||||
}
|
||||
if (haveWord)
|
||||
{
|
||||
// wordEnd points to the end of a word, now find the start of the word
|
||||
std::string word;
|
||||
S32 wordStart = wordEnd;
|
||||
for ( S32 backOne = wordStart - 1;
|
||||
backOne >= 0 && LLWStringUtil::isPartOfWord(text[backOne]);
|
||||
backOne--
|
||||
)
|
||||
{
|
||||
wordStart--; // walk wordStart back to the beginning of the word
|
||||
}
|
||||
LL_DEBUGS("AutoReplace")<<"wordStart: "<<wordStart<<" wordEnd: "<<wordEnd<<LL_ENDL;
|
||||
std::string strText = std::string(text.begin(), text.end());
|
||||
std::string lastWord = strText.substr(wordStart, wordEnd-wordStart+1);
|
||||
std::string replacementWord( mSettings.replaceWord( lastWord ) );
|
||||
|
||||
if ( replacementWord != lastWord )
|
||||
{
|
||||
// The last word is one for which we have a replacement
|
||||
if (atSpace)
|
||||
{
|
||||
// replace the last word in the input
|
||||
LLWString strNew = utf8str_to_wstring(replacementWord);
|
||||
LLWString strOld = utf8str_to_wstring(lastWord);
|
||||
int size_change = strNew.size() - strOld.size();
|
||||
|
||||
text.replace(wordStart,lastWord.length(),strNew);
|
||||
inputText = wstring_to_utf8str(text);
|
||||
cursorPos+=size_change;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLAutoReplace* LLAutoReplace::getInstance()
|
||||
{
|
||||
if(!sInstance)
|
||||
{
|
||||
sInstance = new LLAutoReplace();
|
||||
sInstance->loadFromSettings();
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
std::string LLAutoReplace::getUserSettingsFileName()
|
||||
{
|
||||
std::string path=gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "");
|
||||
|
||||
if (!path.empty())
|
||||
{
|
||||
path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, SETTINGS_FILE_NAME);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string LLAutoReplace::getAppSettingsFileName()
|
||||
{
|
||||
std::string path=gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "");
|
||||
|
||||
if (!path.empty())
|
||||
{
|
||||
path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, SETTINGS_FILE_NAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_ERRS("AutoReplace") << "Failed to get app settings directory name" << LL_ENDL;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
LLAutoReplaceSettings LLAutoReplace::getSettings()
|
||||
{
|
||||
return mSettings;
|
||||
}
|
||||
|
||||
void LLAutoReplace::setSettings(const LLAutoReplaceSettings& newSettings)
|
||||
{
|
||||
mSettings.set(newSettings);
|
||||
/// Make the newSettings active and write them to user storage
|
||||
saveToUserSettings();
|
||||
}
|
||||
|
||||
void LLAutoReplace::loadFromSettings()
|
||||
{
|
||||
std::string filename=getUserSettingsFileName();
|
||||
if (filename.empty())
|
||||
{
|
||||
LL_INFOS("AutoReplace") << "no valid user settings directory." << LL_ENDL;
|
||||
}
|
||||
if(gDirUtilp->fileExists(filename))
|
||||
{
|
||||
LLSD userSettings;
|
||||
llifstream file;
|
||||
file.open(filename.c_str());
|
||||
if (file.is_open())
|
||||
{
|
||||
LLSDSerialize::fromXML(userSettings, file);
|
||||
}
|
||||
file.close();
|
||||
if ( mSettings.setFromLLSD(userSettings) )
|
||||
{
|
||||
LL_INFOS("AutoReplace") << "settings loaded from '" << filename << "'" << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "invalid settings found in '" << filename << "'" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else // no user settings found, try application settings
|
||||
{
|
||||
std::string defaultName = getAppSettingsFileName();
|
||||
LL_INFOS("AutoReplace") << " user settings file '" << filename << "' not found"<< LL_ENDL;
|
||||
|
||||
bool gotSettings = false;
|
||||
if(gDirUtilp->fileExists(defaultName))
|
||||
{
|
||||
LLSD appDefault;
|
||||
llifstream file;
|
||||
file.open(defaultName.c_str());
|
||||
if (file.is_open())
|
||||
{
|
||||
LLSDSerialize::fromXMLDocument(appDefault, file);
|
||||
}
|
||||
file.close();
|
||||
|
||||
if ( mSettings.setFromLLSD(appDefault) )
|
||||
{
|
||||
LL_INFOS("AutoReplace") << "settings loaded from '" << defaultName.c_str() << "'" << LL_ENDL;
|
||||
gotSettings = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "invalid settings found in '" << defaultName.c_str() << "'" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! gotSettings )
|
||||
{
|
||||
if (mSettings.setFromLLSD(mSettings.getExampleLLSD()))
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "no settings found; loaded example." << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "no settings found and example invalid!" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLAutoReplace::saveToUserSettings()
|
||||
{
|
||||
std::string filename=getUserSettingsFileName();
|
||||
llofstream file;
|
||||
file.open(filename.c_str());
|
||||
LLSDSerialize::toPrettyXML(mSettings.getAsLLSD(), file);
|
||||
file.close();
|
||||
LL_INFOS("AutoReplace") << "settings saved to '" << filename << "'" << LL_ENDL;
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// LLAutoReplaceSettings
|
||||
// ================================================================
|
||||
|
||||
const std::string LLAutoReplaceSettings::AUTOREPLACE_LIST_NAME = "name"; ///< key for looking up list names
|
||||
const std::string LLAutoReplaceSettings::AUTOREPLACE_LIST_REPLACEMENTS = "replacements"; ///< key for looking up replacement map
|
||||
|
||||
LLAutoReplaceSettings::LLAutoReplaceSettings()
|
||||
{
|
||||
}
|
||||
|
||||
LLAutoReplaceSettings::LLAutoReplaceSettings(const LLAutoReplaceSettings& settings)
|
||||
{
|
||||
// copy all values through fundamental type intermediates for thread safety
|
||||
mLists = LLSD::emptyArray();
|
||||
|
||||
for ( LLSD::array_const_iterator list = settings.mLists.beginArray(), listEnd = settings.mLists.endArray();
|
||||
list != listEnd;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( (*list).isMap() ) // can fail due to LLSD-30: ignore it
|
||||
{
|
||||
LLSD listMap = LLSD::emptyMap();
|
||||
std::string listName = (*list)[AUTOREPLACE_LIST_NAME];
|
||||
listMap[AUTOREPLACE_LIST_NAME] = listName;
|
||||
listMap[AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap();
|
||||
|
||||
for ( LLSD::map_const_iterator
|
||||
entry = (*list)[AUTOREPLACE_LIST_REPLACEMENTS].beginMap(),
|
||||
entriesEnd = (*list)[AUTOREPLACE_LIST_REPLACEMENTS].endMap();
|
||||
entry != entriesEnd;
|
||||
entry++
|
||||
)
|
||||
{
|
||||
std::string keyword = entry->first;
|
||||
std::string replacement = entry->second.asString();
|
||||
listMap[AUTOREPLACE_LIST_REPLACEMENTS].insert(keyword, LLSD(replacement));
|
||||
}
|
||||
|
||||
mLists.append(listMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLAutoReplaceSettings::set(const LLAutoReplaceSettings& newSettings)
|
||||
{
|
||||
mLists = newSettings.mLists;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::setFromLLSD(const LLSD& settingsFromLLSD)
|
||||
{
|
||||
bool settingsValid = true;
|
||||
|
||||
if ( settingsFromLLSD.isArray() )
|
||||
{
|
||||
for ( LLSD::array_const_iterator
|
||||
list = settingsFromLLSD.beginArray(),
|
||||
listEnd = settingsFromLLSD.endArray();
|
||||
settingsValid && list != listEnd;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( (*list).isDefined() ) // can be undef due to LLSD-30: ignore it
|
||||
{
|
||||
settingsValid = listIsValid(*list);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
settingsValid = false;
|
||||
LL_WARNS("AutoReplace") << "settings are not an array" << LL_ENDL;
|
||||
}
|
||||
|
||||
if ( settingsValid )
|
||||
{
|
||||
mLists = settingsFromLLSD;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "invalid settings discarded; using hard coded example" << LL_ENDL;
|
||||
}
|
||||
|
||||
return settingsValid;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::listNameMatches( const LLSD& list, const std::string name )
|
||||
{
|
||||
return list.isMap()
|
||||
&& list.has(AUTOREPLACE_LIST_NAME)
|
||||
&& list[AUTOREPLACE_LIST_NAME].asString() == name;
|
||||
}
|
||||
|
||||
const LLSD* LLAutoReplaceSettings::getListEntries(std::string listName)
|
||||
{
|
||||
const LLSD* returnedEntries = NULL;
|
||||
for( LLSD::array_const_iterator list = mLists.beginArray(), endList = mLists.endArray();
|
||||
returnedEntries == NULL && list != endList;
|
||||
list++
|
||||
)
|
||||
{
|
||||
const LLSD& thisList = *list;
|
||||
if ( listNameMatches(thisList, listName) )
|
||||
{
|
||||
returnedEntries = &thisList[AUTOREPLACE_LIST_REPLACEMENTS];
|
||||
}
|
||||
}
|
||||
return returnedEntries;
|
||||
}
|
||||
|
||||
std::string LLAutoReplaceSettings::replacementFor(std::string keyword, std::string listName)
|
||||
{
|
||||
std::string replacement;
|
||||
bool foundList = false;
|
||||
for( LLSD::array_const_iterator list = mLists.beginArray(), endList = mLists.endArray();
|
||||
! foundList && list != endList;
|
||||
list++
|
||||
)
|
||||
{
|
||||
const LLSD& thisList = *list;
|
||||
if ( listNameMatches(thisList, listName) )
|
||||
{
|
||||
foundList = true; // whether there is a replacement or not, we're done
|
||||
if ( thisList.isMap()
|
||||
&& thisList.has(AUTOREPLACE_LIST_REPLACEMENTS)
|
||||
&& thisList[AUTOREPLACE_LIST_REPLACEMENTS].has(keyword)
|
||||
)
|
||||
{
|
||||
replacement = thisList[AUTOREPLACE_LIST_REPLACEMENTS][keyword].asString();
|
||||
LL_DEBUGS("AutoReplace")<<"'"<<keyword<<"' -> '"<<replacement<<"'"<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (!foundList)
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<"failed to find list '"<<listName<<"'"<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (replacement.empty())
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<"failed to find '"<<keyword<<"'"<<LL_ENDL;
|
||||
}
|
||||
return replacement;
|
||||
}
|
||||
|
||||
LLSD LLAutoReplaceSettings::getListNames()
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"====="<<LL_ENDL;
|
||||
LLSD toReturn = LLSD::emptyArray();
|
||||
S32 counter=0;
|
||||
for( LLSD::array_const_iterator list = mLists.beginArray(), endList = mLists.endArray();
|
||||
list != endList;
|
||||
list++
|
||||
)
|
||||
{
|
||||
const LLSD& thisList = *list;
|
||||
if ( thisList.isMap() )
|
||||
{
|
||||
if ( thisList.has(AUTOREPLACE_LIST_NAME) )
|
||||
{
|
||||
std::string name = thisList[AUTOREPLACE_LIST_NAME].asString();
|
||||
LL_DEBUGS("AutoReplace")<<counter<<" '"<<name<<"'"<<LL_ENDL;
|
||||
toReturn.append(LLSD(name));
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_ERRS("AutoReplace") <<counter<<" ! MISSING "<<AUTOREPLACE_LIST_NAME<< LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<counter<<" ! not a map: "<<LLSD::typeString(thisList.type())<< LL_ENDL;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
LL_DEBUGS("AutoReplace")<<"^^^^^^"<<LL_ENDL;
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::listIsValid(const LLSD& list)
|
||||
{
|
||||
bool listValid = true;
|
||||
if ( ! list.isMap() )
|
||||
{
|
||||
listValid = false;
|
||||
LL_WARNS("AutoReplace") << "list is not a map" << LL_ENDL;
|
||||
}
|
||||
else if ( ! list.has(AUTOREPLACE_LIST_NAME)
|
||||
|| ! list[AUTOREPLACE_LIST_NAME].isString()
|
||||
|| list[AUTOREPLACE_LIST_NAME].asString().empty()
|
||||
)
|
||||
{
|
||||
listValid = false;
|
||||
LL_WARNS("AutoReplace")
|
||||
<< "list found without " << AUTOREPLACE_LIST_NAME
|
||||
<< " (or it is empty)"
|
||||
<< LL_ENDL;
|
||||
}
|
||||
else if ( ! list.has(AUTOREPLACE_LIST_REPLACEMENTS) || ! list[AUTOREPLACE_LIST_REPLACEMENTS].isMap() )
|
||||
{
|
||||
listValid = false;
|
||||
LL_WARNS("AutoReplace") << "list '" << list[AUTOREPLACE_LIST_NAME].asString() << "' without " << AUTOREPLACE_LIST_REPLACEMENTS << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( LLSD::map_const_iterator
|
||||
entry = list[AUTOREPLACE_LIST_REPLACEMENTS].beginMap(),
|
||||
entriesEnd = list[AUTOREPLACE_LIST_REPLACEMENTS].endMap();
|
||||
listValid && entry != entriesEnd;
|
||||
entry++
|
||||
)
|
||||
{
|
||||
if ( ! entry->second.isString() )
|
||||
{
|
||||
listValid = false;
|
||||
LL_WARNS("AutoReplace")
|
||||
<< "non-string replacement value found in list '"
|
||||
<< list[AUTOREPLACE_LIST_NAME].asString() << "'"
|
||||
<< LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return listValid;
|
||||
}
|
||||
|
||||
const LLSD* LLAutoReplaceSettings::exportList(std::string listName)
|
||||
{
|
||||
const LLSD* exportedList = NULL;
|
||||
for ( LLSD::array_const_iterator list = mLists.beginArray(), listEnd = mLists.endArray();
|
||||
exportedList == NULL && list != listEnd;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( listNameMatches(*list, listName) )
|
||||
{
|
||||
const LLSD& namedList = (*list);
|
||||
exportedList = &namedList;
|
||||
}
|
||||
}
|
||||
return exportedList;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::listNameIsUnique(const LLSD& newList)
|
||||
{
|
||||
bool nameIsUnique = true;
|
||||
// this must always be called with a valid list, so it is safe to assume it has a name
|
||||
std::string newListName = newList[AUTOREPLACE_LIST_NAME].asString();
|
||||
for ( LLSD::array_const_iterator list = mLists.beginArray(), listEnd = mLists.endArray();
|
||||
nameIsUnique && list != listEnd;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( listNameMatches(*list, newListName) )
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<"duplicate list name '"<<newListName<<"'"<<LL_ENDL;
|
||||
nameIsUnique = false;
|
||||
}
|
||||
}
|
||||
return nameIsUnique;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void LLAutoReplaceSettings::createEmptyList(LLSD& emptyList)
|
||||
{
|
||||
emptyList = LLSD::emptyMap();
|
||||
emptyList[AUTOREPLACE_LIST_NAME] = "Empty";
|
||||
emptyList[AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap();
|
||||
}
|
||||
|
||||
/* static */
|
||||
void LLAutoReplaceSettings::setListName(LLSD& list, const std::string& newName)
|
||||
{
|
||||
list[AUTOREPLACE_LIST_NAME] = newName;
|
||||
}
|
||||
|
||||
/* static */
|
||||
std::string LLAutoReplaceSettings::getListName(LLSD& list)
|
||||
{
|
||||
std::string name;
|
||||
if ( list.isMap() && list.has(AUTOREPLACE_LIST_NAME) && list[AUTOREPLACE_LIST_NAME].isString() )
|
||||
{
|
||||
name = list[AUTOREPLACE_LIST_NAME].asString();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
LLAutoReplaceSettings::AddListResult LLAutoReplaceSettings::addList(const LLSD& newList)
|
||||
{
|
||||
AddListResult result;
|
||||
if ( listIsValid( newList ) )
|
||||
{
|
||||
if ( listNameIsUnique( newList ) )
|
||||
{
|
||||
mLists.append(newList);
|
||||
result = AddListOk;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "attempt to add duplicate name" << LL_ENDL;
|
||||
result = AddListDuplicateName;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "attempt to add invalid list" << LL_ENDL;
|
||||
result = AddListInvalidList;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::removeReplacementList(std::string listName)
|
||||
{
|
||||
bool found = false;
|
||||
for( S32 index = 0; !found && mLists[index].isDefined(); index++ )
|
||||
{
|
||||
if( listNameMatches(mLists.get(index), listName) )
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"list '"<<listName<<"'"<<LL_ENDL;
|
||||
mLists.erase(index);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/// Move the named list up in the priority order
|
||||
bool LLAutoReplaceSettings::increaseListPriority(std::string listName)
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<listName<<LL_ENDL;
|
||||
bool found = false;
|
||||
S32 search_index, previous_index;
|
||||
LLSD targetList;
|
||||
// The following is working around the fact that LLSD arrays containing maps also seem to have undefined entries... see LLSD-30
|
||||
previous_index = -1;
|
||||
for ( search_index = 0, targetList = mLists[0];
|
||||
!found && search_index < mLists.size();
|
||||
search_index += 1, targetList = mLists[search_index]
|
||||
)
|
||||
{
|
||||
if ( targetList.isMap() )
|
||||
{
|
||||
if ( listNameMatches( targetList, listName) )
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"found at "<<search_index<<", previous is "<<previous_index<<LL_ENDL;
|
||||
found = true;
|
||||
if (previous_index >= 0)
|
||||
{
|
||||
LL_DEBUGS("AutoReplace") << "erase "<<search_index<<LL_ENDL;
|
||||
mLists.erase(search_index);
|
||||
LL_DEBUGS("AutoReplace") << "insert at "<<previous_index<<LL_ENDL;
|
||||
mLists.insert(previous_index, targetList);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "attempted to move top list up" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
previous_index = search_index;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("AutoReplace") << search_index<<" is "<<LLSD::typeString(targetList.type())<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/// Move the named list down in the priority order
|
||||
bool LLAutoReplaceSettings::decreaseListPriority(std::string listName)
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<listName<<LL_ENDL;
|
||||
S32 found_index = -1;
|
||||
S32 search_index;
|
||||
for ( search_index = 0;
|
||||
found_index == -1 && search_index < mLists.size();
|
||||
search_index++
|
||||
)
|
||||
{
|
||||
if ( listNameMatches( mLists[search_index], listName) )
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"found at index "<<search_index<<LL_ENDL;
|
||||
found_index = search_index;
|
||||
}
|
||||
}
|
||||
if (found_index != -1)
|
||||
{
|
||||
S32 next_index;
|
||||
for ( next_index = found_index+1;
|
||||
next_index < mLists.size() && ! mLists[next_index].isMap();
|
||||
next_index++
|
||||
)
|
||||
{
|
||||
// skipping over any undefined slots (see LLSD-30)
|
||||
LL_WARNS("AutoReplace")<<next_index<<" ! not a map: "<<LLSD::typeString(mLists[next_index].type())<< LL_ENDL;
|
||||
}
|
||||
if ( next_index < mLists.size() )
|
||||
{
|
||||
LLSD next_list = mLists[next_index];
|
||||
LL_DEBUGS("AutoReplace") << "erase "<<next_index<<LL_ENDL;
|
||||
mLists.erase(next_index);
|
||||
LL_DEBUGS("AutoReplace") << "insert at "<<found_index<<LL_ENDL;
|
||||
mLists.insert(found_index, next_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "attempted to move bottom list down" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "not found" << LL_ENDL;
|
||||
}
|
||||
return (found_index != -1);
|
||||
}
|
||||
|
||||
|
||||
std::string LLAutoReplaceSettings::replaceWord(const std::string currentWord)
|
||||
{
|
||||
std::string returnedWord = currentWord; // in case no replacement is found
|
||||
static LLCachedControl<bool> autoreplace_enabled(gSavedSettings, "AutoReplace");
|
||||
if ( autoreplace_enabled )
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"checking '"<<currentWord<<"'"<< LL_ENDL;
|
||||
//loop through lists in order
|
||||
bool found = false;
|
||||
for( LLSD::array_const_iterator list = mLists.beginArray(), endLists = mLists.endArray();
|
||||
! found && list != endLists;
|
||||
list++
|
||||
)
|
||||
{
|
||||
const LLSD& checkList = *list;
|
||||
const LLSD& replacements = checkList[AUTOREPLACE_LIST_REPLACEMENTS];
|
||||
|
||||
if ( replacements.has(currentWord) )
|
||||
{
|
||||
found = true;
|
||||
LL_DEBUGS("AutoReplace")
|
||||
<< " found in list '" << checkList[AUTOREPLACE_LIST_NAME].asString()
|
||||
<< " => '" << replacements[currentWord].asString() << "'"
|
||||
<< LL_ENDL;
|
||||
returnedWord = replacements[currentWord].asString();
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnedWord;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::addEntryToList(LLWString keyword, LLWString replacement, std::string listName)
|
||||
{
|
||||
bool added = false;
|
||||
|
||||
if ( ! keyword.empty() && ! replacement.empty() )
|
||||
{
|
||||
bool isOneWord = true;
|
||||
for (S32 character = 0; isOneWord && character < keyword.size(); character++ )
|
||||
{
|
||||
if ( ! LLWStringUtil::isPartOfWord(keyword[character]) )
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "keyword '" << wstring_to_utf8str(keyword) << "' not a single word (len "<<keyword.size()<<" '"<<character<<"')" << LL_ENDL;
|
||||
isOneWord = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isOneWord )
|
||||
{
|
||||
bool listFound = false;
|
||||
for( LLSD::array_iterator list = mLists.beginArray(), endLists = mLists.endArray();
|
||||
! listFound && list != endLists;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( listNameMatches(*list, listName) )
|
||||
{
|
||||
listFound = true;
|
||||
(*list)[AUTOREPLACE_LIST_REPLACEMENTS][wstring_to_utf8str(keyword)]=wstring_to_utf8str(replacement);
|
||||
}
|
||||
}
|
||||
if (listFound)
|
||||
{
|
||||
added = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "list '" << listName << "' not found" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::removeEntryFromList(std::string keyword, std::string listName)
|
||||
{
|
||||
bool found = false;
|
||||
for( LLSD::array_iterator list = mLists.beginArray(), endLists = mLists.endArray();
|
||||
! found && list != endLists;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( listNameMatches(*list, listName) )
|
||||
{
|
||||
found = true;
|
||||
(*list)[AUTOREPLACE_LIST_REPLACEMENTS].erase(keyword);
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "list '" << listName << "' not found" << LL_ENDL;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
LLSD LLAutoReplaceSettings::getExampleLLSD()
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<LL_ENDL;
|
||||
LLSD example = LLSD::emptyArray();
|
||||
|
||||
example[0] = LLSD::emptyMap();
|
||||
example[0][AUTOREPLACE_LIST_NAME] = "Example List 1";
|
||||
example[0][AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap();
|
||||
example[0][AUTOREPLACE_LIST_REPLACEMENTS]["keyword1"] = "replacement string 1";
|
||||
example[0][AUTOREPLACE_LIST_REPLACEMENTS]["keyword2"] = "replacement string 2";
|
||||
|
||||
example[1] = LLSD::emptyMap();
|
||||
example[1][AUTOREPLACE_LIST_NAME] = "Example List 2";
|
||||
example[1][AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap();
|
||||
example[1][AUTOREPLACE_LIST_REPLACEMENTS]["mistake1"] = "correction 1";
|
||||
example[1][AUTOREPLACE_LIST_REPLACEMENTS]["mistake2"] = "correction 2";
|
||||
|
||||
return example;
|
||||
}
|
||||
|
||||
const LLSD& LLAutoReplaceSettings::getAsLLSD()
|
||||
{
|
||||
return mLists;
|
||||
}
|
||||
|
||||
LLAutoReplaceSettings::~LLAutoReplaceSettings()
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
/**
|
||||
* @file llautoreplace.h
|
||||
* @brief Auto Replace Manager
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef LLAUTOREPLACE_H
|
||||
#define LLAUTOREPLACE_H
|
||||
|
||||
#include "lllineeditor.h"
|
||||
|
||||
class LLAutoReplace;
|
||||
|
||||
/** The configuration data for the LLAutoReplace object
|
||||
*
|
||||
* This is a separate class so that the LLFloaterAutoReplaceSettings
|
||||
* can have a copy of the configuration to manipulate before committing
|
||||
* the changes back to the LLAutoReplace singleton that provides the
|
||||
* autoreplace callback.
|
||||
*/
|
||||
class LLAutoReplaceSettings
|
||||
{
|
||||
public:
|
||||
LLAutoReplaceSettings();
|
||||
~LLAutoReplaceSettings();
|
||||
|
||||
/// Constructor for creating a tempory copy of the current settings
|
||||
LLAutoReplaceSettings(const LLAutoReplaceSettings& settings);
|
||||
|
||||
/// Replace the current settings with new ones and save them to the user settings file
|
||||
void set(const LLAutoReplaceSettings& newSettings);
|
||||
|
||||
/// Load the current settings read from an LLSD file
|
||||
bool setFromLLSD(const LLSD& settingsFromLLSD);
|
||||
///< @returns whether or not the settingsFromLLSD were valid
|
||||
|
||||
// ================================================================
|
||||
///@{ @name List Operations
|
||||
// ================================================================
|
||||
|
||||
/// @returns the configured list names as an LLSD Array of strings
|
||||
LLSD getListNames();
|
||||
|
||||
/// Status values returned from the addList method
|
||||
typedef enum
|
||||
{
|
||||
AddListOk,
|
||||
AddListDuplicateName,
|
||||
AddListInvalidList,
|
||||
} AddListResult;
|
||||
|
||||
/// Inserts a new list at the end of the priority order
|
||||
AddListResult addList(const LLSD& newList);
|
||||
|
||||
/// Removes the named list, @returns false if not found
|
||||
bool removeReplacementList(std::string listName);
|
||||
|
||||
/// Move the named list up in the priority order
|
||||
bool increaseListPriority(std::string listName);
|
||||
///< @returns false if the list is not found
|
||||
|
||||
/// Move the named list down in the priority order
|
||||
bool decreaseListPriority(std::string listName);
|
||||
///< @returns false if the list is not found
|
||||
|
||||
/// Get a copy of just one list (for saving to an export file)
|
||||
const LLSD* exportList(std::string listName);
|
||||
/// @returns an LLSD map
|
||||
|
||||
/// Checks for required elements, and that each has the correct type.
|
||||
bool listIsValid(const LLSD& listSettings);
|
||||
|
||||
/// Checks for required elements, and that each has the correct type.
|
||||
bool listNameIs(const LLSD& listSettings);
|
||||
|
||||
/// Checks to see if a new lists name conflicts with one in the settings
|
||||
bool listNameIsUnique(const LLSD& newList);
|
||||
/// @note must be called with LLSD that has passed listIsValid
|
||||
|
||||
/// Initializes emptyList to an empty list named 'Empty'
|
||||
static void createEmptyList(LLSD& emptyList);
|
||||
|
||||
/// Resets the name of a list to a new value
|
||||
static void setListName(LLSD& list, const std::string& newName);
|
||||
|
||||
/// Gets the name of a list
|
||||
static std::string getListName(LLSD& list);
|
||||
|
||||
///@}
|
||||
// ================================================================
|
||||
///@{ @name Replacement Entry Operations
|
||||
// ================================================================
|
||||
|
||||
/// Get the replacements specified by a given list
|
||||
const LLSD* getListEntries(std::string listName);
|
||||
///< @returns an LLSD Map of keyword -> replacement test pairs
|
||||
|
||||
/// Get the replacement for the keyword from the specified list
|
||||
std::string replacementFor(std::string keyword, std::string listName);
|
||||
|
||||
/// Adds a keywword/replacement pair to the named list
|
||||
bool addEntryToList(LLWString keyword, LLWString replacement, std::string listName);
|
||||
|
||||
/// Removes the keywword and its replacement from the named list
|
||||
bool removeEntryFromList(std::string keyword, std::string listName);
|
||||
|
||||
/**
|
||||
* Look for currentWord in the lists in order, returning any substitution found
|
||||
* If no configured substitution is found, returns currentWord
|
||||
*/
|
||||
std::string replaceWord(const std::string currentWord /**< word to search for */ );
|
||||
|
||||
/// Provides a hard-coded example of settings
|
||||
LLSD getExampleLLSD();
|
||||
|
||||
/// Get the actual settings as LLSD
|
||||
const LLSD& getAsLLSD();
|
||||
///< @note for use only in AutoReplace::saveToUserSettings
|
||||
|
||||
private:
|
||||
/// Efficiently and safely compare list names
|
||||
bool listNameMatches( const LLSD& list, const std::string name );
|
||||
|
||||
/// The actual llsd data structure
|
||||
LLSD mLists;
|
||||
|
||||
static const std::string AUTOREPLACE_LIST_NAME; ///< key for looking up list names
|
||||
static const std::string AUTOREPLACE_LIST_REPLACEMENTS; ///< key for looking up replacement map
|
||||
|
||||
/**<
|
||||
* LLSD structure of the lists
|
||||
* - The configuration is an array (mLists),
|
||||
* - Each entry in the array is a replacement list
|
||||
* - Each replacement list is a map with three keys:
|
||||
* @verbatim
|
||||
* "name" String the name of the list
|
||||
* "replacements" Map keyword -> replacement pairs
|
||||
*
|
||||
* <llsd>
|
||||
* <array>
|
||||
* <map>
|
||||
* <key>name</key> <string>List 1</string>
|
||||
* <key>data</key>
|
||||
* <map>
|
||||
* <key>keyword1</key> <string>replacement1</string>
|
||||
* <key>keyword2</key> <string>replacement2</string>
|
||||
* </map>
|
||||
* </map>
|
||||
* <map>
|
||||
* <key>name</key> <string>List 2</string>
|
||||
* <key>data</key>
|
||||
* <map>
|
||||
* <key>keyword1</key> <string>replacement1</string>
|
||||
* <key>keyword2</key> <string>replacement2</string>
|
||||
* </map>
|
||||
* </map>
|
||||
* </array>
|
||||
* </llsd>
|
||||
* @endverbatim
|
||||
*/
|
||||
};
|
||||
|
||||
/** Provides a facility to auto-replace text dynamically as it is entered.
|
||||
*
|
||||
* When the end of a word is detected (defined as any punctuation character,
|
||||
* or any whitespace except newline or return), the preceding word is used
|
||||
* as a lookup key in an ordered list of maps. If a match is found in any
|
||||
* map, the keyword is replaced by the associated value from the map.
|
||||
*
|
||||
* See the autoreplaceCallback method for how to add autoreplace functionality
|
||||
* to a text entry tool.
|
||||
*/
|
||||
class LLAutoReplace : public LLSingleton<LLAutoReplace>
|
||||
{
|
||||
public:
|
||||
LLAutoReplace();
|
||||
~LLAutoReplace();
|
||||
|
||||
/// @return a pointer to the active instance
|
||||
static LLAutoReplace* getInstance();
|
||||
|
||||
/// Callback that provides the hook for use in text entry methods
|
||||
void autoreplaceCallback(LLUIString& inputText, S32& cursorPos);
|
||||
|
||||
/// Get a copy of the current settings
|
||||
LLAutoReplaceSettings getSettings();
|
||||
|
||||
/// Commit new settings after making changes
|
||||
void setSettings(const LLAutoReplaceSettings& settings);
|
||||
|
||||
private:
|
||||
friend class LLSingleton<LLAutoReplace>;
|
||||
static LLAutoReplace* sInstance; ///< the active settings instance
|
||||
|
||||
LLAutoReplaceSettings mSettings; ///< configuration information
|
||||
|
||||
/// Read settings from persistent storage
|
||||
void loadFromSettings();
|
||||
|
||||
/// Make the newSettings active and write them to user storage
|
||||
void saveToUserSettings();
|
||||
|
||||
/// Compute the user settings file name
|
||||
std::string getUserSettingsFileName();
|
||||
|
||||
/// Compute the (read-ony) application settings file name
|
||||
std::string getAppSettingsFileName();
|
||||
|
||||
/// basename for the settings files
|
||||
static const char* SETTINGS_FILE_NAME;
|
||||
};
|
||||
|
||||
#endif /* LLAUTOREPLACE_H */
|
||||
|
|
@ -495,7 +495,7 @@ protected:
|
|||
|
||||
void showInfoCtrl()
|
||||
{
|
||||
if (mAvatarID.isNull() || mFrom.empty() || SYSTEM_FROM == mFrom) return;
|
||||
if (mAvatarID.isNull() || mFrom.empty() || CHAT_SOURCE_SYSTEM == mSourceType) return;
|
||||
|
||||
if (!sInfoCtrl)
|
||||
{
|
||||
|
|
@ -689,8 +689,11 @@ void LLChatHistory::clear()
|
|||
mLastFromID = LLUUID::null;
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_APPEND_MESSAGE("Append Chat Message");
|
||||
|
||||
void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LLStyle::Params& input_append_params)
|
||||
{
|
||||
LLFastTimer _(FTM_APPEND_MESSAGE);
|
||||
bool use_plain_text_chat_history = args["use_plain_text_chat_history"].asBoolean();
|
||||
|
||||
llassert(mEditor);
|
||||
|
|
@ -783,7 +786,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
|
|||
timestamp_style.color(timestamp_color);
|
||||
timestamp_style.readonly_color(timestamp_color);
|
||||
}
|
||||
mEditor->appendText("[" + chat.mTimeStr + "] ", mEditor->getText().size() != 0, timestamp_style);
|
||||
mEditor->appendText("[" + chat.mTimeStr + "] ", mEditor->getLength() != 0, timestamp_style);
|
||||
|
||||
if (utf8str_trim(chat.mFromName).size() != 0)
|
||||
{
|
||||
|
|
@ -842,7 +845,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
|
|||
else
|
||||
{
|
||||
view = getHeader(chat, style_params, args);
|
||||
if (mEditor->getText().size() == 0)
|
||||
if (mEditor->getLength() == 0)
|
||||
p.top_pad = 0;
|
||||
else
|
||||
p.top_pad = mTopHeaderPad;
|
||||
|
|
|
|||
|
|
@ -450,7 +450,7 @@ void LLDrawable::makeStatic(BOOL warning_enabled)
|
|||
{
|
||||
if (isState(ACTIVE))
|
||||
{
|
||||
clearState(ACTIVE);
|
||||
clearState(ACTIVE | ANIMATED_CHILD);
|
||||
|
||||
if (mParent.notNull() && mParent->isActive() && warning_enabled)
|
||||
{
|
||||
|
|
@ -538,9 +538,9 @@ F32 LLDrawable::updateXform(BOOL undamped)
|
|||
target_rot = new_rot;
|
||||
target_scale = new_scale;
|
||||
}
|
||||
else
|
||||
else if (mVObjp->getAngularVelocity().isExactlyZero())
|
||||
{
|
||||
// snap to final position
|
||||
// snap to final position (only if no target omega is applied)
|
||||
dist_squared = 0.0f;
|
||||
if (getVOVolume() && !isRoot())
|
||||
{ //child prim snapping to some position, needs a rebuild
|
||||
|
|
@ -549,15 +549,25 @@ F32 LLDrawable::updateXform(BOOL undamped)
|
|||
}
|
||||
}
|
||||
|
||||
if ((mCurrentScale != target_scale) ||
|
||||
(!isRoot() &&
|
||||
(dist_squared >= MIN_INTERPOLATE_DISTANCE_SQUARED ||
|
||||
!mVObjp->getAngularVelocity().isExactlyZero() ||
|
||||
target_pos != mXform.getPosition() ||
|
||||
target_rot != mXform.getRotation())))
|
||||
{ //child prim moving or scale change requires immediate rebuild
|
||||
LLVector3 vec = mCurrentScale-target_scale;
|
||||
|
||||
if (vec*vec > MIN_INTERPOLATE_DISTANCE_SQUARED)
|
||||
{ //scale change requires immediate rebuild
|
||||
mCurrentScale = target_scale;
|
||||
gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE);
|
||||
}
|
||||
else if (!isRoot() &&
|
||||
(!mVObjp->getAngularVelocity().isExactlyZero() ||
|
||||
dist_squared > 0.f))
|
||||
{ //child prim moving relative to parent, tag as needing to be rendered atomically and rebuild
|
||||
dist_squared = 1.f; //keep this object on the move list
|
||||
if (!isState(LLDrawable::ANIMATED_CHILD))
|
||||
{
|
||||
setState(LLDrawable::ANIMATED_CHILD);
|
||||
gPipeline.markRebuild(this, LLDrawable::REBUILD_ALL, TRUE);
|
||||
mVObjp->dirtySpatialGroup();
|
||||
}
|
||||
}
|
||||
else if (!getVOVolume() && !isAvatar())
|
||||
{
|
||||
movePartition();
|
||||
|
|
@ -568,9 +578,7 @@ F32 LLDrawable::updateXform(BOOL undamped)
|
|||
mXform.setRotation(target_rot);
|
||||
mXform.setScale(LLVector3(1,1,1)); //no scale in drawable transforms (IT'S A RULE!)
|
||||
mXform.updateMatrix();
|
||||
|
||||
mCurrentScale = target_scale;
|
||||
|
||||
|
||||
if (mSpatialBridge)
|
||||
{
|
||||
gPipeline.markMoved(mSpatialBridge, FALSE);
|
||||
|
|
@ -596,7 +604,11 @@ void LLDrawable::moveUpdatePipeline(BOOL moved)
|
|||
// Update the face centers.
|
||||
for (S32 i = 0; i < getNumFaces(); i++)
|
||||
{
|
||||
getFace(i)->updateCenterAgent();
|
||||
LLFace* face = getFace(i);
|
||||
if (face)
|
||||
{
|
||||
face->updateCenterAgent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -651,7 +663,6 @@ BOOL LLDrawable::updateMoveUndamped()
|
|||
}
|
||||
|
||||
mVObjp->clearChanged(LLXform::MOVED);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -727,7 +738,8 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
|
|||
for (S32 i = 0; i < getNumFaces(); i++)
|
||||
{
|
||||
LLFace* facep = getFace(i);
|
||||
if (force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA)
|
||||
if (facep &&
|
||||
(force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA))
|
||||
{
|
||||
LLVector4a box;
|
||||
box.setSub(facep->mExtents[1], facep->mExtents[0]);
|
||||
|
|
@ -771,18 +783,6 @@ void LLDrawable::updateTexture()
|
|||
|
||||
if (getVOVolume())
|
||||
{
|
||||
/*if (isActive())
|
||||
{
|
||||
if (isRoot())
|
||||
{
|
||||
mQuietCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
getParent()->mQuietCount = 0;
|
||||
}
|
||||
}*/
|
||||
|
||||
gPipeline.markRebuild(this, LLDrawable::REBUILD_MATERIAL, TRUE);
|
||||
}
|
||||
}
|
||||
|
|
@ -826,13 +826,16 @@ void LLDrawable::shiftPos(const LLVector4a &shift_vector)
|
|||
for (S32 i = 0; i < getNumFaces(); i++)
|
||||
{
|
||||
LLFace *facep = getFace(i);
|
||||
facep->mCenterAgent += LLVector3(shift_vector.getF32ptr());
|
||||
facep->mExtents[0].add(shift_vector);
|
||||
facep->mExtents[1].add(shift_vector);
|
||||
|
||||
if (!volume && facep->hasGeometry())
|
||||
if (facep)
|
||||
{
|
||||
facep->clearVertexBuffer();
|
||||
facep->mCenterAgent += LLVector3(shift_vector.getF32ptr());
|
||||
facep->mExtents[0].add(shift_vector);
|
||||
facep->mExtents[1].add(shift_vector);
|
||||
|
||||
if (!volume && facep->hasGeometry())
|
||||
{
|
||||
facep->clearVertexBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -954,7 +957,10 @@ void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp)
|
|||
for (S32 i = 0; i < getNumFaces(); ++i)
|
||||
{
|
||||
LLFace* facep = getFace(i);
|
||||
facep->clearVertexBuffer();
|
||||
if (facep)
|
||||
{
|
||||
facep->clearVertexBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1529,10 +1535,10 @@ BOOL LLDrawable::isAnimating() const
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
if (!isRoot() && !mVObjp->getAngularVelocity().isExactlyZero())
|
||||
{
|
||||
/*if (!isRoot() && !mVObjp->getAngularVelocity().isExactlyZero())
|
||||
{ //target omega
|
||||
return TRUE;
|
||||
}
|
||||
}*/
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -277,6 +277,7 @@ public:
|
|||
HAS_ALPHA = 0x04000000,
|
||||
RIGGED = 0x08000000,
|
||||
PARTITION_MOVE = 0x10000000,
|
||||
ANIMATED_CHILD = 0x20000000,
|
||||
} EDrawableFlags;
|
||||
|
||||
private: //aligned members
|
||||
|
|
@ -333,12 +334,14 @@ inline LLFace* LLDrawable::getFace(const S32 i) const
|
|||
|
||||
if ((U32) i >= mFaces.size())
|
||||
{
|
||||
llerrs << "Invalid face index." << llendl;
|
||||
llwarns << "Invalid face index." << llendl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!mFaces[i])
|
||||
{
|
||||
llerrs << "Null face found." << llendl;
|
||||
llwarns << "Null face found." << llendl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mFaces[i];
|
||||
|
|
|
|||
|
|
@ -405,6 +405,12 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
|
|||
{
|
||||
LLDrawInfo& params = **k;
|
||||
|
||||
if ((params.mVertexBuffer->getTypeMask() & mask) != mask)
|
||||
{ //FIXME!
|
||||
llwarns << "Missing required components, skipping render batch." << llendl;
|
||||
continue;
|
||||
}
|
||||
|
||||
LLRenderPass::applyModelMatrix(params);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -261,7 +261,9 @@ void LLDrawPoolAvatar::beginPostDeferredAlpha()
|
|||
sRenderingSkinned = TRUE;
|
||||
|
||||
gPipeline.bindDeferredShader(*sVertexProgram);
|
||||
|
||||
|
||||
sVertexProgram->setMinimumAlpha(0.2f);
|
||||
|
||||
sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -83,6 +83,8 @@ public:
|
|||
|
||||
static void initClass();
|
||||
|
||||
static void cacheFaceInVRAM(const LLVolumeFace& vf);
|
||||
|
||||
public:
|
||||
LLFace(LLDrawable* drawablep, LLViewerObject* objp) { init(drawablep, objp); }
|
||||
~LLFace() { destroy(); }
|
||||
|
|
@ -222,7 +224,7 @@ public:
|
|||
|
||||
//vertex buffer tracking
|
||||
void setVertexBuffer(LLVertexBuffer* buffer);
|
||||
void clearVertexBuffer(); //sets mVertexBuffer and mLastVertexBuffer to NULL
|
||||
void clearVertexBuffer(); //sets mVertexBuffer to NULL
|
||||
LLVertexBuffer* getVertexBuffer() const { return mVertexBuffer; }
|
||||
U32 getRiggedVertexBufferDataMask() const;
|
||||
S32 getRiggedIndex(U32 type) const;
|
||||
|
|
@ -255,8 +257,7 @@ public:
|
|||
|
||||
private:
|
||||
LLPointer<LLVertexBuffer> mVertexBuffer;
|
||||
LLPointer<LLVertexBuffer> mLastVertexBuffer;
|
||||
|
||||
|
||||
U32 mState;
|
||||
LLFacePool* mDrawPoolp;
|
||||
U32 mPoolType;
|
||||
|
|
@ -269,12 +270,6 @@ private:
|
|||
U32 mIndicesIndex; // index into draw pool for indices (yeah, I know!)
|
||||
S32 mIndexInTex ;
|
||||
|
||||
//previous rebuild's geometry info
|
||||
U16 mLastGeomCount;
|
||||
U16 mLastGeomIndex;
|
||||
U32 mLastIndicesCount;
|
||||
U32 mLastIndicesIndex;
|
||||
|
||||
LLXformMatrix* mXform;
|
||||
LLPointer<LLViewerTexture> mTexture;
|
||||
LLPointer<LLDrawable> mDrawablep;
|
||||
|
|
|
|||
|
|
@ -1191,7 +1191,7 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata)
|
|||
}
|
||||
else if (action == "paste")
|
||||
{
|
||||
pastFromClipboard();
|
||||
pasteFromClipboard();
|
||||
}
|
||||
else if (action == "delete")
|
||||
{
|
||||
|
|
@ -1239,7 +1239,7 @@ BOOL LLFavoritesBarCtrl::isClipboardPasteable() const
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
void LLFavoritesBarCtrl::pastFromClipboard() const
|
||||
void LLFavoritesBarCtrl::pasteFromClipboard() const
|
||||
{
|
||||
LLInventoryModel* model = &gInventory;
|
||||
if(model && isClipboardPasteable())
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ protected:
|
|||
bool enableSelected(const LLSD& userdata);
|
||||
void doToSelected(const LLSD& userdata);
|
||||
BOOL isClipboardPasteable() const;
|
||||
void pastFromClipboard() const;
|
||||
void pasteFromClipboard() const;
|
||||
|
||||
void showDropDownMenu();
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue