summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--autobuild.xml14
-rwxr-xr-xdoc/contributions.txt5
-rw-r--r--indra/cmake/Copy3rdPartyLibs.cmake4
-rw-r--r--indra/cmake/FindOpenJPEG.cmake3
-rw-r--r--indra/cmake/OpenJPEG.cmake14
-rw-r--r--indra/integration_tests/llui_libtest/CMakeLists.txt4
-rw-r--r--indra/llcommon/llcoros.cpp74
-rw-r--r--indra/llcommon/llcoros.h6
-rw-r--r--indra/llcommon/llsdserialize.cpp121
-rw-r--r--indra/llcommon/llsdserialize.h6
-rw-r--r--indra/llimagej2coj/llimagej2coj.cpp1112
-rw-r--r--indra/llmath/llvolume.cpp20
-rw-r--r--indra/llmath/llvolume.h6
-rw-r--r--indra/llprimitive/llmodel.cpp10
-rw-r--r--indra/llprimitive/llmodel.h3
-rw-r--r--indra/newview/CMakeLists.txt6
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/skyF.glsl50
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/skyV.glsl35
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/skyF.glsl199
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/skyV.glsl42
-rw-r--r--indra/newview/llbuycurrencyhtml.cpp2
-rw-r--r--indra/newview/llcommandhandler.cpp82
-rw-r--r--indra/newview/llcommandhandler.h10
-rw-r--r--indra/newview/llfloater360capture.cpp14
-rw-r--r--indra/newview/llfloateropenobject.cpp14
-rw-r--r--indra/newview/llfloateropenobject.h2
-rw-r--r--indra/newview/llfloaterpathfindinglinksets.cpp19
-rw-r--r--indra/newview/llfloaterpathfindinglinksets.h5
-rw-r--r--indra/newview/llfloatersearch.cpp2
-rw-r--r--indra/newview/llfloaterworldmap.cpp4
-rw-r--r--indra/newview/llgroupactions.cpp27
-rw-r--r--indra/newview/llmaterialmgr.cpp18
-rw-r--r--indra/newview/llmeshrepository.cpp531
-rw-r--r--indra/newview/llmeshrepository.h33
-rw-r--r--indra/newview/llmodelpreview.cpp22
-rw-r--r--indra/newview/llpaneleditwearable.cpp2
-rw-r--r--indra/newview/llpanelobjectinventory.cpp21
-rw-r--r--indra/newview/llpanelobjectinventory.h11
-rw-r--r--indra/newview/llpanelprofile.cpp26
-rw-r--r--indra/newview/llpanelprofileclassifieds.cpp24
-rw-r--r--indra/newview/llpanelprofilepicks.cpp24
-rw-r--r--indra/newview/llviewerfloaterreg.cpp98
-rw-r--r--indra/newview/llviewerinput.cpp10
-rw-r--r--indra/newview/llviewerinventory.cpp2
-rw-r--r--indra/newview/llviewermenu.cpp1
-rw-r--r--indra/newview/llviewerpartsource.cpp2
-rw-r--r--indra/newview/llvovolume.cpp38
-rw-r--r--indra/newview/llvovolume.h4
-rw-r--r--indra/newview/skins/default/xui/en/floater_object_weights.xml21
-rw-r--r--indra/newview/skins/default/xui/en/floater_openobject.xml52
-rw-r--r--indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml49
-rw-r--r--indra/newview/skins/default/xui/en/panel_profile_secondlife.xml6
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml2
-rw-r--r--indra/newview/skins/default/xui/en/widgets/filter_editor.xml2
-rw-r--r--indra/newview/skins/default/xui/en/widgets/search_editor.xml2
-rwxr-xr-xindra/newview/viewer_manifest.py4
56 files changed, 1692 insertions, 1228 deletions
diff --git a/autobuild.xml b/autobuild.xml
index 5a5ffa2898..1a353fe2e9 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -2195,9 +2195,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
- <string>5abf2d9c0b250821c59cc60cd94fd8af</string>
+ <string>8114c6a7e499ea20d325db0de08ce30a</string>
<key>url</key>
- <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54840/510064/openjpeg-1.5.1.538970-darwin64-538970.tar.bz2</string>
+ <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/105469/923024/openjpeg-2.5.0.575496-darwin64-575496.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -2219,9 +2219,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
- <string>222a406ecb4071a9cc9635353afa337e</string>
+ <string>edc9388870d951632a6d595792293e05</string>
<key>url</key>
- <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54977/511775/openjpeg-1.5.1.538970-windows-538970.tar.bz2</string>
+ <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/105472/923036/openjpeg-2.5.0.575496-windows-575496.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
@@ -2231,16 +2231,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
- <string>5b5c80807fa8161f3480be3d89fe9516</string>
+ <string>b95f0732f2388ebb0ddf33d4a30e0ff1</string>
<key>url</key>
- <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54974/511767/openjpeg-1.5.1.538970-windows64-538970.tar.bz2</string>
+ <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/105471/923037/openjpeg-2.5.0.575496-windows64-575496.tar.bz2</string>
</map>
<key>name</key>
<string>windows64</string>
</map>
</map>
<key>version</key>
- <string>1.5.1.538970</string>
+ <string>2.5.0.575496</string>
</map>
<key>openssl</key>
<map>
diff --git a/doc/contributions.txt b/doc/contributions.txt
index 2c1e5487ce..0149dae3f2 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -1377,6 +1377,7 @@ Sovereign Engineer
OPEN-343
SL-11625
BUG-229030
+ SL-14696
SL-14705
SL-14706
SL-14707
@@ -1384,6 +1385,9 @@ Sovereign Engineer
SL-14732
SL-15096
SL-16127
+ SL-18249
+ SL-18394
+ SL-18412
SpacedOut Frye
VWR-34
VWR-45
@@ -1646,6 +1650,7 @@ Zi Ree
VWR-25588
STORM-1790
STORM-1842
+ SL-18348
Zipherius Turas
VWR-76
VWR-77
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index ff705101de..04b4202ca3 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -52,7 +52,7 @@ if(WINDOWS)
set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
set(release_files
- openjpeg.dll
+ openjp2.dll
libapr-1.dll
libaprutil-1.dll
libapriconv-1.dll
@@ -220,7 +220,7 @@ elseif(LINUX)
libgobject-2.0.so
libhunspell-1.3.so.0.0.0
libopenal.so
- libopenjpeg.so
+ libopenjp2.so
libuuid.so.16
libuuid.so.16.0.22
libfontconfig.so.1.8.0
diff --git a/indra/cmake/FindOpenJPEG.cmake b/indra/cmake/FindOpenJPEG.cmake
index 949384eec4..2d4353b54f 100644
--- a/indra/cmake/FindOpenJPEG.cmake
+++ b/indra/cmake/FindOpenJPEG.cmake
@@ -14,9 +14,10 @@ FIND_PATH(OPENJPEG_INCLUDE_DIR openjpeg.h
/usr/local/include
/usr/include/openjpeg
/usr/include
+include/openjpeg
)
-SET(OPENJPEG_NAMES ${OPENJPEG_NAMES} openjpeg)
+SET(OPENJPEG_NAMES ${OPENJPEG_NAMES} openjp2)
FIND_LIBRARY(OPENJPEG_LIBRARY
NAMES ${OPENJPEG_NAMES}
PATHS /usr/lib /usr/local/lib
diff --git a/indra/cmake/OpenJPEG.cmake b/indra/cmake/OpenJPEG.cmake
index bf0bde2ba7..a078c97cb8 100644
--- a/indra/cmake/OpenJPEG.cmake
+++ b/indra/cmake/OpenJPEG.cmake
@@ -8,15 +8,7 @@ if (USESYSTEMLIBS)
include(FindOpenJPEG)
else (USESYSTEMLIBS)
use_prebuilt_binary(openjpeg)
-
- if(WINDOWS)
- # Windows has differently named release and debug openjpeg(d) libs.
- set(OPENJPEG_LIBRARIES
- debug openjpegd
- optimized openjpeg)
- else(WINDOWS)
- set(OPENJPEG_LIBRARIES openjpeg)
- endif(WINDOWS)
-
- set(OPENJPEG_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/openjpeg)
+
+ set(OPENJPEG_LIBRARIES openjp2)
+ set(OPENJPEG_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/openjpeg)
endif (USESYSTEMLIBS)
diff --git a/indra/integration_tests/llui_libtest/CMakeLists.txt b/indra/integration_tests/llui_libtest/CMakeLists.txt
index d7706e73b2..3957ede77f 100644
--- a/indra/integration_tests/llui_libtest/CMakeLists.txt
+++ b/indra/integration_tests/llui_libtest/CMakeLists.txt
@@ -99,14 +99,14 @@ if (WINDOWS)
# Copy over OpenJPEG.dll
# *NOTE: On Windows with VS2005, only the first comment prints
set(OPENJPEG_RELEASE
- "${ARCH_PREBUILT_DIRS_RELEASE}/openjpeg.dll")
+ "${ARCH_PREBUILT_DIRS_RELEASE}/openjp2.dll")
add_custom_command( TARGET llui_libtest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${OPENJPEG_RELEASE} ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Copying OpenJPEG DLLs to binary directory"
)
set(OPENJPEG_DEBUG
- "${ARCH_PREBUILT_DIRS_DEBUG}/openjpegd.dll")
+ "${ARCH_PREBUILT_DIRS_DEBUG}/openjp2.dll")
add_custom_command( TARGET llui_libtest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${OPENJPEG_DEBUG} ${CMAKE_CURRENT_BINARY_DIR}
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp
index 14bfb98629..70d8dfc8b9 100644
--- a/indra/llcommon/llcoros.cpp
+++ b/indra/llcommon/llcoros.cpp
@@ -288,25 +288,15 @@ std::string LLCoros::launch(const std::string& prefix, const callable_t& callabl
return name;
}
+namespace
+{
+
#if LL_WINDOWS
static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific
-U32 cpp_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop, const std::string& name)
+U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop)
{
- // C++ exceptions were logged in toplevelTryWrapper, but not SEH
- // log SEH exceptions here, to make sure it gets into bugsplat's
- // report and because __try won't allow std::string operations
- if (code != STATUS_MSC_EXCEPTION)
- {
- LL_WARNS() << "SEH crash in " << name << ", code: " << code << LL_ENDL;
- }
- // Handle bugsplat here, since GetExceptionInformation() can only be
- // called from within filter for __except(filter), not from __except's {}
- // Bugsplat should get all exceptions, C++ and SEH
- LLApp::instance()->reportCrashToBugsplat(exception_infop);
-
- // Only convert non C++ exceptions.
if (code == STATUS_MSC_EXCEPTION)
{
// C++ exception, go on
@@ -319,28 +309,38 @@ U32 cpp_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop,
}
}
-void LLCoros::sehHandle(const std::string& name, const LLCoros::callable_t& callable)
+void sehandle(const LLCoros::callable_t& callable)
{
__try
{
- LLCoros::toplevelTryWrapper(name, callable);
+ callable();
}
- __except (cpp_exception_filter(GetExceptionCode(), GetExceptionInformation(), name))
+ __except (exception_filter(GetExceptionCode(), GetExceptionInformation()))
{
- // convert to C++ styled exception for handlers other than bugsplat
+ // convert to C++ styled exception
// Note: it might be better to use _se_set_translator
// if you want exception to inherit full callstack
- //
- // in case of bugsplat this will get to exceptionTerminateHandler and
- // looks like fiber will terminate application after that
char integer_string[512];
- sprintf(integer_string, "SEH crash in %s, code: %lu\n", name.c_str(), GetExceptionCode());
+ sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode());
throw std::exception(integer_string);
}
}
-#endif
-void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& callable)
+#else // ! LL_WINDOWS
+
+inline void sehandle(const LLCoros::callable_t& callable)
+{
+ callable();
+}
+
+#endif // ! LL_WINDOWS
+
+} // anonymous namespace
+
+// Top-level wrapper around caller's coroutine callable.
+// Normally we like to pass strings and such by const reference -- but in this
+// case, we WANT to copy both the name and the callable to our local stack!
+void LLCoros::toplevel(std::string name, callable_t callable)
{
// keep the CoroData on this top-level function's stack frame
CoroData corodata(name);
@@ -350,12 +350,12 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call
// run the code the caller actually wants in the coroutine
try
{
- callable();
+ sehandle(callable);
}
catch (const Stop& exc)
{
LL_INFOS("LLCoros") << "coroutine " << name << " terminating because "
- << exc.what() << LL_ENDL;
+ << exc.what() << LL_ENDL;
}
catch (const LLContinueError&)
{
@@ -366,36 +366,14 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call
}
catch (...)
{
-#if LL_WINDOWS
- // Any OTHER kind of uncaught exception will cause the viewer to
- // crash, SEH handling should catch it and report to bugsplat.
- LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name));
- // to not modify callstack
- throw;
-#else
// Stash any OTHER kind of uncaught exception in the rethrow() queue
// to be rethrown by the main fiber.
LL_WARNS("LLCoros") << "Capturing uncaught exception in coroutine "
<< name << LL_ENDL;
LLCoros::instance().saveException(name, std::current_exception());
-#endif
}
}
-// Top-level wrapper around caller's coroutine callable.
-// Normally we like to pass strings and such by const reference -- but in this
-// case, we WANT to copy both the name and the callable to our local stack!
-void LLCoros::toplevel(std::string name, callable_t callable)
-{
-#if LL_WINDOWS
- // Because SEH can's have unwinding, need to call a wrapper
- // 'try' is inside SEH handling to not catch LLContinue
- sehHandle(name, callable);
-#else
- toplevelTryWrapper(name, callable);
-#endif
-}
-
//static
void LLCoros::checkStop()
{
diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h
index dbff921f16..966ce03296 100644
--- a/indra/llcommon/llcoros.h
+++ b/indra/llcommon/llcoros.h
@@ -307,11 +307,7 @@ public:
private:
std::string generateDistinctName(const std::string& prefix) const;
- void toplevelTryWrapper(const std::string& name, const callable_t& callable);
-#if LL_WINDOWS
- void sehHandle(const std::string& name, const callable_t& callable); // calls toplevelTryWrapper
-#endif
- void toplevel(std::string name, callable_t callable); // calls sehHandle or toplevelTryWrapper
+ void toplevel(std::string name, callable_t callable);
struct CoroData;
static CoroData& get_CoroData(const std::string& caller);
void saveException(const std::string& name, std::exception_ptr exc);
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index 8b4a0ee6d8..a510b73096 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -34,6 +34,9 @@
#include <iostream>
#include "apr_base64.h"
+#include <boost/iostreams/device/array.hpp>
+#include <boost/iostreams/stream.hpp>
+
#ifdef LL_USESYSTEMLIBS
# include <zlib.h>
#else
@@ -2128,7 +2131,9 @@ std::string zip_llsd(LLSD& data)
{ //copy result into output
if (strm.avail_out >= CHUNK)
{
- free(output);
+ deflateEnd(&strm);
+ if(output)
+ free(output);
LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL;
return std::string();
}
@@ -2151,7 +2156,9 @@ std::string zip_llsd(LLSD& data)
}
else
{
- free(output);
+ deflateEnd(&strm);
+ if(output)
+ free(output);
LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL;
return std::string();
}
@@ -2162,7 +2169,8 @@ std::string zip_llsd(LLSD& data)
std::string result((char*) output, size);
deflateEnd(&strm);
- free(output);
+ if(output)
+ free(output);
return result;
}
@@ -2172,53 +2180,66 @@ std::string zip_llsd(LLSD& data)
// and deserializes from that copy using LLSDSerialize
LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is, S32 size)
{
+ std::unique_ptr<U8[]> in = std::unique_ptr<U8[]>(new(std::nothrow) U8[size]);
+ if (!in)
+ {
+ return ZR_MEM_ERROR;
+ }
+ is.read((char*) in.get(), size);
+
+ return unzip_llsd(data, in.get(), size);
+}
+
+LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, const U8* in, S32 size)
+{
U8* result = NULL;
U32 cur_size = 0;
z_stream strm;
- const U32 CHUNK = 65536;
+ constexpr U32 CHUNK = 1024 * 512;
- U8 *in = new(std::nothrow) U8[size];
- if (!in)
+ static thread_local std::unique_ptr<U8[]> out;
+ if (!out)
{
- return ZR_MEM_ERROR;
+ out = std::unique_ptr<U8[]>(new(std::nothrow) U8[CHUNK]);
}
- is.read((char*) in, size);
-
- U8 out[CHUNK];
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = size;
- strm.next_in = in;
+ strm.next_in = const_cast<U8*>(in);
S32 ret = inflateInit(&strm);
do
{
strm.avail_out = CHUNK;
- strm.next_out = out;
+ strm.next_out = out.get();
ret = inflate(&strm, Z_NO_FLUSH);
- if (ret == Z_STREAM_ERROR)
+ switch (ret)
+ {
+ case Z_NEED_DICT:
+ case Z_DATA_ERROR:
{
inflateEnd(&strm);
free(result);
- delete [] in;
return ZR_DATA_ERROR;
}
-
- switch (ret)
+ case Z_STREAM_ERROR:
+ case Z_BUF_ERROR:
{
- case Z_NEED_DICT:
- ret = Z_DATA_ERROR;
- case Z_DATA_ERROR:
+ inflateEnd(&strm);
+ free(result);
+ return ZR_BUFFER_ERROR;
+ }
+
case Z_MEM_ERROR:
+ {
inflateEnd(&strm);
free(result);
- delete [] in;
return ZR_MEM_ERROR;
- break;
+ }
}
U32 have = CHUNK-strm.avail_out;
@@ -2231,17 +2252,15 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
{
free(result);
}
- delete[] in;
return ZR_MEM_ERROR;
}
result = new_result;
- memcpy(result+cur_size, out, have);
+ memcpy(result+cur_size, out.get(), have);
cur_size += have;
- } while (ret == Z_OK);
+ } while (ret == Z_OK && ret != Z_STREAM_END);
inflateEnd(&strm);
- delete [] in;
if (ret != Z_STREAM_END)
{
@@ -2251,37 +2270,11 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
//result now points to the decompressed LLSD block
{
- std::istringstream istr;
- // Since we are using this for meshes, data we are dealing with tend to be large.
- // So string can potentially fail to allocate, make sure this won't cause problems
- try
- {
- std::string res_str((char*)result, cur_size);
-
- std::string deprecated_header("<? LLSD/Binary ?>");
-
- if (res_str.substr(0, deprecated_header.size()) == deprecated_header)
- {
- res_str = res_str.substr(deprecated_header.size() + 1, cur_size);
- }
- cur_size = res_str.size();
-
- istr.str(res_str);
- }
-#ifdef LL_WINDOWS
- catch (std::length_error)
- {
- free(result);
- return ZR_SIZE_ERROR;
- }
-#endif
- catch (std::bad_alloc&)
- {
- free(result);
- return ZR_MEM_ERROR;
- }
+ char* result_ptr = strip_deprecated_header((char*)result, cur_size);
- if (!LLSDSerialize::fromBinary(data, istr, cur_size, UNZIP_LLSD_MAX_DEPTH))
+ boost::iostreams::stream<boost::iostreams::array_source> istrm(result_ptr, cur_size);
+
+ if (!LLSDSerialize::fromBinary(data, istrm, cur_size, UNZIP_LLSD_MAX_DEPTH))
{
free(result);
return ZR_PARSE_ERROR;
@@ -2395,4 +2388,22 @@ U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32
return result;
}
+char* strip_deprecated_header(char* in, U32& cur_size, U32* header_size)
+{
+ const char* deprecated_header = "<? LLSD/Binary ?>";
+ constexpr size_t deprecated_header_size = 17;
+
+ if (cur_size > deprecated_header_size
+ && memcmp(in, deprecated_header, deprecated_header_size) == 0)
+ {
+ in = in + deprecated_header_size;
+ cur_size = cur_size - deprecated_header_size;
+ if (header_size)
+ {
+ *header_size = deprecated_header_size + 1;
+ }
+ }
+
+ return in;
+}
diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h
index d6079fd9fa..d33d2b6f34 100644
--- a/indra/llcommon/llsdserialize.h
+++ b/indra/llcommon/llsdserialize.h
@@ -858,9 +858,12 @@ public:
ZR_SIZE_ERROR,
ZR_DATA_ERROR,
ZR_PARSE_ERROR,
+ ZR_BUFFER_ERROR,
+ ZR_VERSION_ERROR
} EZipRresult;
// return OK or reason for failure
static EZipRresult unzip_llsd(LLSD& data, std::istream& is, S32 size);
+ static EZipRresult unzip_llsd(LLSD& data, const U8* in, S32 size);
};
//dirty little zip functions -- yell at davep
@@ -868,4 +871,7 @@ LL_COMMON_API std::string zip_llsd(LLSD& data);
LL_COMMON_API U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize,std::istream& is, S32 size);
+
+// returns a pointer to the array or past the array if the deprecated header exists
+LL_COMMON_API char* strip_deprecated_header(char* in, U32& cur_size, U32* header_size = nullptr);
#endif // LL_LLSDSERIALIZE_H
diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp
index 925da5674b..12985c3c7f 100644
--- a/indra/llimagej2coj/llimagej2coj.cpp
+++ b/indra/llimagej2coj/llimagej2coj.cpp
@@ -29,40 +29,41 @@
// this is defined so that we get static linking.
#include "openjpeg.h"
+#include "event.h"
+#include "cio.h"
-#include "lltimer.h"
-//#include "llmemory.h"
+#define MAX_ENCODED_DISCARD_LEVELS 5
// Factory function: see declaration in llimagej2c.cpp
LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl()
{
- return new LLImageJ2COJ();
+ return new LLImageJ2COJ();
}
std::string LLImageJ2COJ::getEngineInfo() const
{
#ifdef OPENJPEG_VERSION
- return std::string("OpenJPEG: " OPENJPEG_VERSION ", Runtime: ")
- + opj_version();
+ return std::string("OpenJPEG: " OPENJPEG_VERSION ", Runtime: ")
+ + opj_version();
#else
- return std::string("OpenJPEG runtime: ") + opj_version();
+ return std::string("OpenJPEG runtime: ") + opj_version();
#endif
}
// Return string from message, eliminating final \n if present
static std::string chomp(const char* msg)
{
- // stomp trailing \n
- std::string message = msg;
- if (!message.empty())
- {
- size_t last = message.size() - 1;
- if (message[last] == '\n')
- {
- message.resize( last );
- }
- }
- return message;
+ // stomp trailing \n
+ std::string message = msg;
+ if (!message.empty())
+ {
+ size_t last = message.size() - 1;
+ if (message[last] == '\n')
+ {
+ message.resize(last);
+ }
+}
+ return message;
}
/**
@@ -70,419 +71,770 @@ sample error callback expecting a LLFILE* client object
*/
void error_callback(const char* msg, void*)
{
- LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
+ LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
}
/**
sample warning callback expecting a LLFILE* client object
*/
void warning_callback(const char* msg, void*)
{
- LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
+ LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
}
/**
sample debug callback expecting no client object
*/
void info_callback(const char* msg, void*)
{
- LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
+ LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
}
// Divide a by 2 to the power of b and round upwards
int ceildivpow2(int a, int b)
{
- return (a + (1 << b) - 1) >> b;
+ return (a + (1 << b) - 1) >> b;
}
-
-LLImageJ2COJ::LLImageJ2COJ()
- : LLImageJ2CImpl()
+class JPEG2KBase
{
-}
+public:
+ JPEG2KBase() {}
+ U8* buffer = nullptr;
+ OPJ_SIZE_T size = 0;
+ OPJ_OFF_T offset = 0;
+};
-LLImageJ2COJ::~LLImageJ2COJ()
+#define WANT_VERBOSE_OPJ_SPAM LL_DEBUG
+
+static void opj_info(const char* msg, void* user_data)
{
+ llassert(user_data);
+#if WANT_VERBOSE_OPJ_SPAM
+ LL_INFOS("OpenJPEG") << msg << LL_ENDL;
+#endif
}
-bool LLImageJ2COJ::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region)
+static void opj_warn(const char* msg, void* user_data)
{
- // No specific implementation for this method in the OpenJpeg case
- return false;
+ llassert(user_data);
+#if WANT_VERBOSE_OPJ_SPAM
+ LL_WARNS("OpenJPEG") << msg << LL_ENDL;
+#endif
}
-bool LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
+static void opj_error(const char* msg, void* user_data)
{
- // No specific implementation for this method in the OpenJpeg case
- return false;
+ llassert(user_data);
+#if WANT_VERBOSE_OPJ_SPAM
+ LL_WARNS("OpenJPEG") << msg << LL_ENDL;
+#endif
}
-bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
+static OPJ_SIZE_T opj_read(void * buffer, OPJ_SIZE_T bytes, void* user_data)
{
- //
- // FIXME: Get the comment field out of the texture
- //
-
- LLTimer decode_timer;
-
- opj_dparameters_t parameters; /* decompression parameters */
- opj_event_mgr_t event_mgr; /* event manager */
- opj_image_t *image = NULL;
-
- opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */
- opj_cio_t *cio = NULL;
-
-
- /* configure the event callbacks (not required) */
- memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
- event_mgr.error_handler = error_callback;
- event_mgr.warning_handler = warning_callback;
- event_mgr.info_handler = info_callback;
-
- /* set decoding parameters to default values */
- opj_set_default_decoder_parameters(&parameters);
-
- parameters.cp_reduce = base.getRawDiscardLevel();
-
- /* decode the code-stream */
- /* ---------------------- */
-
- /* JPEG-2000 codestream */
-
- /* get a decoder handle */
- dinfo = opj_create_decompress(CODEC_J2K);
-
- /* catch events using our callbacks and give a local context */
- opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
-
- /* setup the decoder decoding parameters using user parameters */
- opj_setup_decoder(dinfo, &parameters);
-
- /* open a byte stream */
- cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize());
-
- /* decode the stream and fill the image structure */
- image = opj_decode(dinfo, cio);
-
- /* close the byte stream */
- opj_cio_close(cio);
-
- /* free remaining structures */
- if(dinfo)
- {
- opj_destroy_decompress(dinfo);
- }
-
- // The image decode failed if the return was NULL or the component
- // count was zero. The latter is just a sanity check before we
- // dereference the array.
- if(!image || !image->numcomps)
- {
- LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image!" << LL_ENDL;
- if (image)
- {
- opj_image_destroy(image);
- }
-
- return true; // done
- }
-
- // sometimes we get bad data out of the cache - check to see if the decode succeeded
- for (S32 i = 0; i < image->numcomps; i++)
- {
- if (image->comps[i].factor != base.getRawDiscardLevel())
- {
- // if we didn't get the discard level we're expecting, fail
- opj_image_destroy(image);
- base.mDecoding = false;
- return true;
- }
- }
-
- if(image->numcomps <= first_channel)
- {
- LL_WARNS() << "trying to decode more channels than are present in image: numcomps: " << image->numcomps << " first_channel: " << first_channel << LL_ENDL;
- if (image)
- {
- opj_image_destroy(image);
- }
-
- return true;
- }
-
- // Copy image data into our raw image format (instead of the separate channel format
-
- S32 img_components = image->numcomps;
- S32 channels = img_components - first_channel;
- if( channels > max_channel_count )
- channels = max_channel_count;
-
- // Component buffers are allocated in an image width by height buffer.
- // The image placed in that buffer is ceil(width/2^factor) by
- // ceil(height/2^factor) and if the factor isn't zero it will be at the
- // top left of the buffer with black filled in the rest of the pixels.
- // It is integer math so the formula is written in ceildivpo2.
- // (Assuming all the components have the same width, height and
- // factor.)
- S32 comp_width = image->comps[0].w;
- S32 f=image->comps[0].factor;
- S32 width = ceildivpow2(image->x1 - image->x0, f);
- S32 height = ceildivpow2(image->y1 - image->y0, f);
- raw_image.resize(width, height, channels);
- U8 *rawp = raw_image.getData();
-
- // first_channel is what channel to start copying from
- // dest is what channel to copy to. first_channel comes from the
- // argument, dest always starts writing at channel zero.
- for (S32 comp = first_channel, dest=0; comp < first_channel + channels;
- comp++, dest++)
- {
- if (image->comps[comp].data)
- {
- S32 offset = dest;
- for (S32 y = (height - 1); y >= 0; y--)
- {
- for (S32 x = 0; x < width; x++)
- {
- rawp[offset] = image->comps[comp].data[y*comp_width + x];
- offset += channels;
- }
- }
- }
- else // Some rare OpenJPEG versions have this bug.
- {
- LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image! (NULL comp data - OpenJPEG bug)" << LL_ENDL;
- opj_image_destroy(image);
-
- return true; // done
- }
- }
-
- /* free image data structure */
- opj_image_destroy(image);
-
- return true; // done
+ llassert(user_data);
+ JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
+ OPJ_SIZE_T remainder = (jpeg_codec->size - jpeg_codec->offset);
+ if (remainder <= 0)
+ {
+ jpeg_codec->offset = jpeg_codec->size;
+ // Indicate end of stream (hacky?)
+ return (OPJ_OFF_T)-1;
+ }
+ OPJ_SIZE_T to_read = llclamp(U32(bytes), U32(0), U32(remainder));
+ memcpy(buffer, jpeg_codec->buffer + jpeg_codec->offset, to_read);
+ jpeg_codec->offset += to_read;
+ return to_read;
}
-
-bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, bool reversible)
+static OPJ_SIZE_T opj_write(void * buffer, OPJ_SIZE_T bytes, void* user_data)
{
- const S32 MAX_COMPS = 5;
- opj_cparameters_t parameters; /* compression parameters */
- opj_event_mgr_t event_mgr; /* event manager */
-
-
- /*
- configure the event callbacks (not required)
- setting of each callback is optional
- */
- memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
- event_mgr.error_handler = error_callback;
- event_mgr.warning_handler = warning_callback;
- event_mgr.info_handler = info_callback;
-
- /* set encoding parameters to default values */
- opj_set_default_encoder_parameters(&parameters);
- parameters.cod_format = 0;
- parameters.cp_disto_alloc = 1;
-
- if (reversible)
- {
- parameters.tcp_numlayers = 1;
- parameters.tcp_rates[0] = 0.0f;
- }
- else
- {
- parameters.tcp_numlayers = 5;
- parameters.tcp_rates[0] = 1920.0f;
- parameters.tcp_rates[1] = 480.0f;
- parameters.tcp_rates[2] = 120.0f;
- parameters.tcp_rates[3] = 30.0f;
- parameters.tcp_rates[4] = 10.0f;
- parameters.irreversible = 1;
- if (raw_image.getComponents() >= 3)
- {
- parameters.tcp_mct = 1;
- }
- }
-
- if (!comment_text)
- {
- parameters.cp_comment = (char *) "";
- }
- else
- {
- // Awful hacky cast, too lazy to copy right now.
- parameters.cp_comment = (char *) comment_text;
- }
-
- //
- // Fill in the source image from our raw image
- //
- OPJ_COLOR_SPACE color_space = CLRSPC_SRGB;
- opj_image_cmptparm_t cmptparm[MAX_COMPS];
- opj_image_t * image = NULL;
- S32 numcomps = raw_image.getComponents();
- S32 width = raw_image.getWidth();
- S32 height = raw_image.getHeight();
-
- memset(&cmptparm[0], 0, MAX_COMPS * sizeof(opj_image_cmptparm_t));
- for(S32 c = 0; c < numcomps; c++) {
- cmptparm[c].prec = 8;
- cmptparm[c].bpp = 8;
- cmptparm[c].sgnd = 0;
- cmptparm[c].dx = parameters.subsampling_dx;
- cmptparm[c].dy = parameters.subsampling_dy;
- cmptparm[c].w = width;
- cmptparm[c].h = height;
- }
-
- /* create the image */
- image = opj_image_create(numcomps, &cmptparm[0], color_space);
-
- image->x1 = width;
- image->y1 = height;
-
- S32 i = 0;
- const U8 *src_datap = raw_image.getData();
- for (S32 y = height - 1; y >= 0; y--)
- {
- for (S32 x = 0; x < width; x++)
- {
- const U8 *pixel = src_datap + (y*width + x) * numcomps;
- for (S32 c = 0; c < numcomps; c++)
- {
- image->comps[c].data[i] = *pixel;
- pixel++;
- }
- i++;
- }
- }
-
-
-
- /* encode the destination image */
- /* ---------------------------- */
-
- int codestream_length;
- opj_cio_t *cio = NULL;
-
- /* get a J2K compressor handle */
- opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K);
-
- /* catch events using our callbacks and give a local context */
- opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr);
-
- /* setup the encoder parameters using the current image and using user parameters */
- opj_setup_encoder(cinfo, &parameters, image);
-
- /* open a byte stream for writing */
- /* allocate memory for all tiles */
- cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0);
-
- /* encode the image */
- bool bSuccess = opj_encode(cinfo, cio, image, NULL);
- if (!bSuccess)
- {
- opj_cio_close(cio);
- LL_DEBUGS("Texture") << "Failed to encode image." << LL_ENDL;
- return false;
- }
- codestream_length = cio_tell(cio);
-
- base.copyData(cio->buffer, codestream_length);
- base.updateData(); // set width, height
-
- /* close and free the byte stream */
- opj_cio_close(cio);
-
- /* free remaining compression structures */
- opj_destroy_compress(cinfo);
-
-
- /* free user parameters structure */
- if(parameters.cp_matrice) free(parameters.cp_matrice);
-
- /* free image data */
- opj_image_destroy(image);
- return true;
+ llassert(user_data);
+ JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
+ OPJ_SIZE_T remainder = jpeg_codec->size - jpeg_codec->offset;
+ if (remainder < bytes)
+ {
+ OPJ_SIZE_T new_size = jpeg_codec->size + (bytes - remainder);
+ U8* new_buffer = (U8*)ll_aligned_malloc_16(new_size);
+ memcpy(new_buffer, jpeg_codec->buffer, jpeg_codec->offset);
+ U8* old_buffer = jpeg_codec->buffer;
+ jpeg_codec->buffer = new_buffer;
+ ll_aligned_free_16(old_buffer);
+ jpeg_codec->size = new_size;
+ }
+ memcpy(jpeg_codec->buffer + jpeg_codec->offset, buffer, bytes);
+ jpeg_codec->offset += bytes;
+ return bytes;
}
-bool LLImageJ2COJ::getMetadata(LLImageJ2C &base)
+static OPJ_OFF_T opj_skip(OPJ_OFF_T bytes, void* user_data)
{
- //
- // FIXME: We get metadata by decoding the ENTIRE image.
- //
-
- // Update the raw discard level
- base.updateRawDiscardLevel();
-
- opj_dparameters_t parameters; /* decompression parameters */
- opj_event_mgr_t event_mgr; /* event manager */
- opj_image_t *image = NULL;
-
- opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */
- opj_cio_t *cio = NULL;
-
-
- /* configure the event callbacks (not required) */
- memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
- event_mgr.error_handler = error_callback;
- event_mgr.warning_handler = warning_callback;
- event_mgr.info_handler = info_callback;
-
- /* set decoding parameters to default values */
- opj_set_default_decoder_parameters(&parameters);
-
- // Only decode what's required to get the size data.
- parameters.cp_limit_decoding=LIMIT_TO_MAIN_HEADER;
+ JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
+ jpeg_codec->offset += bytes;
+
+ if (jpeg_codec->offset > jpeg_codec->size)
+ {
+ jpeg_codec->offset = jpeg_codec->size;
+ // Indicate end of stream
+ return (OPJ_OFF_T)-1;
+ }
+
+ if (jpeg_codec->offset < 0)
+ {
+ // Shouldn't be possible?
+ jpeg_codec->offset = 0;
+ return (OPJ_OFF_T)-1;
+ }
+
+ return bytes;
+}
- //parameters.cp_reduce = mRawDiscardLevel;
+static OPJ_BOOL opj_seek(OPJ_OFF_T bytes, void * user_data)
+{
+ JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
+ jpeg_codec->offset = bytes;
+ jpeg_codec->offset = llclamp(U32(jpeg_codec->offset), U32(0), U32(jpeg_codec->size));
+ return OPJ_TRUE;
+}
- /* decode the code-stream */
- /* ---------------------- */
+static void opj_free_user_data(void * user_data)
+{
+ JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
+ // Don't free, data is managed externally
+ jpeg_codec->buffer = nullptr;
+ jpeg_codec->size = 0;
+ jpeg_codec->offset = 0;
+}
- /* JPEG-2000 codestream */
+static void opj_free_user_data_write(void * user_data)
+{
+ JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
+ // Free, data was allocated here
+ ll_aligned_free_16(jpeg_codec->buffer);
+ jpeg_codec->buffer = nullptr;
+ jpeg_codec->size = 0;
+ jpeg_codec->offset = 0;
+}
- /* get a decoder handle */
- dinfo = opj_create_decompress(CODEC_J2K);
+class JPEG2KDecode : public JPEG2KBase
+{
+public:
+
+ JPEG2KDecode(S8 discardLevel)
+ {
+ memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
+ memset(&parameters, 0, sizeof(opj_dparameters_t));
+ event_mgr.error_handler = error_callback;
+ event_mgr.warning_handler = warning_callback;
+ event_mgr.info_handler = info_callback;
+ opj_set_default_decoder_parameters(&parameters);
+ parameters.cp_reduce = discardLevel;
+ }
+
+ ~JPEG2KDecode()
+ {
+ if (decoder)
+ {
+ opj_destroy_codec(decoder);
+ }
+ decoder = nullptr;
+
+ if (image)
+ {
+ opj_image_destroy(image);
+ }
+ image = nullptr;
+
+ if (stream)
+ {
+ opj_stream_destroy(stream);
+ }
+ stream = nullptr;
+
+ if (codestream_info)
+ {
+ opj_destroy_cstr_info(&codestream_info);
+ }
+ codestream_info = nullptr;
+ }
+
+ bool readHeader(
+ U8* data,
+ U32 dataSize,
+ S32& widthOut,
+ S32& heightOut,
+ S32& components,
+ S32& discard_level)
+ {
+ parameters.flags |= OPJ_DPARAMETERS_DUMP_FLAG;
+
+ decoder = opj_create_decompress(OPJ_CODEC_J2K);
+
+ if (!opj_setup_decoder(decoder, &parameters))
+ {
+ return false;
+ }
+
+ if (stream)
+ {
+ opj_stream_destroy(stream);
+ }
+
+ stream = opj_stream_create(dataSize, true);
+ if (!stream)
+ {
+ return false;
+ }
+
+ opj_stream_set_user_data(stream, this, opj_free_user_data);
+ opj_stream_set_user_data_length(stream, dataSize);
+ opj_stream_set_read_function(stream, opj_read);
+ opj_stream_set_write_function(stream, opj_write);
+ opj_stream_set_skip_function(stream, opj_skip);
+ opj_stream_set_seek_function(stream, opj_seek);
+
+ buffer = data;
+ size = dataSize;
+ offset = 0;
+
+ // enable decoding partially loaded images
+ opj_decoder_set_strict_mode(decoder, OPJ_FALSE);
+
+ /* Read the main header of the codestream and if necessary the JP2 boxes*/
+ if (!opj_read_header((opj_stream_t*)stream, decoder, &image))
+ {
+ return false;
+ }
+
+ codestream_info = opj_get_cstr_info(decoder);
+
+ if (!codestream_info)
+ {
+ return false;
+ }
+
+ U32 tileDimX = codestream_info->tdx;
+ U32 tileDimY = codestream_info->tdy;
+ U32 tilesW = codestream_info->tw;
+ U32 tilesH = codestream_info->th;
+
+ widthOut = S32(tilesW * tileDimX);
+ heightOut = S32(tilesH * tileDimY);
+ components = codestream_info->nbcomps;
+
+ discard_level = 0;
+ while (tilesW > 1 && tilesH > 1 && discard_level < MAX_DISCARD_LEVEL)
+ {
+ discard_level++;
+ tilesW >>= 1;
+ tilesH >>= 1;
+ }
+
+ return true;
+ }
+
+ bool decode(U8* data, U32 dataSize, U32* channels, U8 discard_level)
+ {
+ parameters.flags &= ~OPJ_DPARAMETERS_DUMP_FLAG;
+
+ decoder = opj_create_decompress(OPJ_CODEC_J2K);
+ opj_setup_decoder(decoder, &parameters);
+
+ opj_set_info_handler(decoder, opj_info, this);
+ opj_set_warning_handler(decoder, opj_warn, this);
+ opj_set_error_handler(decoder, opj_error, this);
+
+ if (stream)
+ {
+ opj_stream_destroy(stream);
+ }
+
+ stream = opj_stream_create(dataSize, true);
+ if (!stream)
+ {
+ return false;
+ }
+
+ opj_stream_set_user_data(stream, this, opj_free_user_data);
+ opj_stream_set_user_data_length(stream, dataSize);
+ opj_stream_set_read_function(stream, opj_read);
+ opj_stream_set_write_function(stream, opj_write);
+ opj_stream_set_skip_function(stream, opj_skip);
+ opj_stream_set_seek_function(stream, opj_seek);
+
+ buffer = data;
+ size = dataSize;
+ offset = 0;
+
+ if (image)
+ {
+ opj_image_destroy(image);
+ image = nullptr;
+ }
+
+ // needs to happen before opj_read_header and opj_decode...
+ opj_set_decoded_resolution_factor(decoder, discard_level);
+
+ // enable decoding partially loaded images
+ opj_decoder_set_strict_mode(decoder, OPJ_FALSE);
+
+ if (!opj_read_header(stream, decoder, &image))
+ {
+ return false;
+ }
+
+ // needs to happen before decode which may fail
+ if (channels)
+ {
+ *channels = image->numcomps;
+ }
+
+ OPJ_BOOL decoded = opj_decode(decoder, stream, image);
+
+ // count was zero. The latter is just a sanity check before we
+ // dereference the array.
+ if (!decoded || !image || !image->numcomps)
+ {
+ opj_end_decompress(decoder, stream);
+ return false;
+ }
+
+ opj_end_decompress(decoder, stream);
+
+ return true;
+ }
+
+ opj_image_t* getImage() { return image; }
+
+private:
+ opj_dparameters_t parameters;
+ opj_event_mgr_t event_mgr;
+ opj_image_t* image = nullptr;
+ opj_codec_t* decoder = nullptr;
+ opj_stream_t* stream = nullptr;
+ opj_codestream_info_v2_t* codestream_info = nullptr;
+};
+
+class JPEG2KEncode : public JPEG2KBase
+{
+public:
+ const OPJ_UINT32 TILE_SIZE = 64 * 64 * 3;
+
+ JPEG2KEncode(const char* comment_text_in, bool reversible)
+ {
+ memset(&parameters, 0, sizeof(opj_cparameters_t));
+ memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
+ event_mgr.error_handler = error_callback;
+ event_mgr.warning_handler = warning_callback;
+ event_mgr.info_handler = info_callback;
+
+ opj_set_default_encoder_parameters(&parameters);
+ parameters.cod_format = OPJ_CODEC_J2K;
+ parameters.cp_disto_alloc = 1;
+ parameters.max_cs_size = (1 << 15);
+
+ if (reversible)
+ {
+ parameters.tcp_numlayers = 1;
+ parameters.tcp_rates[0] = 1.0f;
+ }
+ else
+ {
+ parameters.tcp_numlayers = 5;
+ parameters.tcp_rates[0] = 1920.0f;
+ parameters.tcp_rates[1] = 960.0f;
+ parameters.tcp_rates[2] = 480.0f;
+ parameters.tcp_rates[3] = 120.0f;
+ parameters.tcp_rates[4] = 30.0f;
+ parameters.irreversible = 1;
+ parameters.tcp_mct = 1;
+ }
+
+ if (comment_text)
+ {
+ free(comment_text);
+ }
+ comment_text = comment_text_in ? strdup(comment_text_in) : nullptr;
+
+ parameters.cp_comment = comment_text ? comment_text : (char*)"no comment";
+ llassert(parameters.cp_comment);
+ }
+
+ ~JPEG2KEncode()
+ {
+ if (encoder)
+ {
+ opj_destroy_codec(encoder);
+ }
+ encoder = nullptr;
+
+ if (image)
+ {
+ opj_image_destroy(image);
+ }
+ image = nullptr;
+
+ if (stream)
+ {
+ opj_stream_destroy(stream);
+ }
+ stream = nullptr;
+
+ if (comment_text)
+ {
+ free(comment_text);
+ }
+ comment_text = nullptr;
+ }
+
+ bool encode(const LLImageRaw& rawImageIn, LLImageJ2C &compressedImageOut)
+ {
+ setImage(rawImageIn);
+
+ encoder = opj_create_compress(OPJ_CODEC_J2K);
+
+ parameters.tcp_mct = (image->numcomps >= 3) ? 1 : 0;
+ parameters.cod_format = OPJ_CODEC_J2K;
+ parameters.prog_order = OPJ_RLCP;
+ parameters.cp_disto_alloc = 1;
+
+ if (!opj_setup_encoder(encoder, &parameters, image))
+ {
+ return false;
+ }
+
+ opj_set_info_handler(encoder, opj_info, this);
+ opj_set_warning_handler(encoder, opj_warn, this);
+ opj_set_error_handler(encoder, opj_error, this);
+
+ U32 tile_count = (rawImageIn.getWidth() >> 6) * (rawImageIn.getHeight() >> 6);
+ U32 data_size_guess = tile_count * TILE_SIZE;
+
+ // will be freed in opj_free_user_data_write
+ buffer = (U8*)ll_aligned_malloc_16(data_size_guess);
+ size = data_size_guess;
+ offset = 0;
+
+ memset(buffer, 0, data_size_guess);
+
+ if (stream)
+ {
+ opj_stream_destroy(stream);
+ }
+
+ stream = opj_stream_create(data_size_guess, false);
+ if (!stream)
+ {
+ return false;
+ }
+
+ opj_stream_set_user_data(stream, this, opj_free_user_data_write);
+ opj_stream_set_user_data_length(stream, data_size_guess);
+ opj_stream_set_read_function(stream, opj_read);
+ opj_stream_set_write_function(stream, opj_write);
+ opj_stream_set_skip_function(stream, opj_skip);
+ opj_stream_set_seek_function(stream, opj_seek);
+
+ OPJ_BOOL started = opj_start_compress(encoder, image, stream);
+
+ if (!started)
+ {
+ return false;
+ }
+
+ if (!opj_encode(encoder, stream))
+ {
+ return false;
+ }
+
+ OPJ_BOOL encoded = opj_end_compress(encoder, stream);
+
+ // if we successfully encoded, then stream out the compressed data...
+ if (encoded)
+ {
+ // "append" (set) the data we "streamed" (memcopied) for writing to the formatted image
+ // with side-effect of setting the actually encoded size to same
+ compressedImageOut.allocateData(offset);
+ memcpy(compressedImageOut.getData(), buffer, offset);
+ compressedImageOut.updateData(); // update width, height etc from header
+ }
+ return encoded;
+ }
+
+ void setImage(const LLImageRaw& raw)
+ {
+ opj_image_cmptparm_t cmptparm[MAX_ENCODED_DISCARD_LEVELS];
+ memset(&cmptparm[0], 0, MAX_ENCODED_DISCARD_LEVELS * sizeof(opj_image_cmptparm_t));
+
+ S32 numcomps = raw.getComponents();
+ S32 width = raw.getWidth();
+ S32 height = raw.getHeight();
+
+ for (S32 c = 0; c < numcomps; c++)
+ {
+ cmptparm[c].prec = 8;
+ cmptparm[c].bpp = 8;
+ cmptparm[c].sgnd = 0;
+ cmptparm[c].dx = parameters.subsampling_dx;
+ cmptparm[c].dy = parameters.subsampling_dy;
+ cmptparm[c].w = width;
+ cmptparm[c].h = height;
+ }
+
+ image = opj_image_create(numcomps, &cmptparm[0], OPJ_CLRSPC_SRGB);
+
+ image->x1 = width;
+ image->y1 = height;
+
+ const U8 *src_datap = raw.getData();
+
+ S32 i = 0;
+ for (S32 y = height - 1; y >= 0; y--)
+ {
+ for (S32 x = 0; x < width; x++)
+ {
+ const U8 *pixel = src_datap + (y*width + x) * numcomps;
+ for (S32 c = 0; c < numcomps; c++)
+ {
+ image->comps[c].data[i] = *pixel;
+ pixel++;
+ }
+ i++;
+ }
+ }
+
+ // This likely works, but there seems to be an issue openjpeg side
+ // check over after gixing that.
+
+ // De-interleave to component plane data
+ /*
+ switch (numcomps)
+ {
+ case 0:
+ default:
+ break;
+
+ case 1:
+ {
+ U32 rBitDepth = image->comps[0].bpp;
+ U32 bytesPerPixel = rBitDepth >> 3;
+ memcpy(image->comps[0].data, src, width * height * bytesPerPixel);
+ }
+ break;
+
+ case 2:
+ {
+ U32 rBitDepth = image->comps[0].bpp;
+ U32 gBitDepth = image->comps[1].bpp;
+ U32 totalBitDepth = rBitDepth + gBitDepth;
+ U32 bytesPerPixel = totalBitDepth >> 3;
+ U32 stride = width * bytesPerPixel;
+ U32 offset = 0;
+ for (S32 y = height - 1; y >= 0; y--)
+ {
+ const U8* component = src + (y * stride);
+ for (S32 x = 0; x < width; x++)
+ {
+ image->comps[0].data[offset] = *component++;
+ image->comps[1].data[offset] = *component++;
+ offset++;
+ }
+ }
+ }
+ break;
+
+ case 3:
+ {
+ U32 rBitDepth = image->comps[0].bpp;
+ U32 gBitDepth = image->comps[1].bpp;
+ U32 bBitDepth = image->comps[2].bpp;
+ U32 totalBitDepth = rBitDepth + gBitDepth + bBitDepth;
+ U32 bytesPerPixel = totalBitDepth >> 3;
+ U32 stride = width * bytesPerPixel;
+ U32 offset = 0;
+ for (S32 y = height - 1; y >= 0; y--)
+ {
+ const U8* component = src + (y * stride);
+ for (S32 x = 0; x < width; x++)
+ {
+ image->comps[0].data[offset] = *component++;
+ image->comps[1].data[offset] = *component++;
+ image->comps[2].data[offset] = *component++;
+ offset++;
+ }
+ }
+ }
+ break;
+
+
+ case 4:
+ {
+ U32 rBitDepth = image->comps[0].bpp;
+ U32 gBitDepth = image->comps[1].bpp;
+ U32 bBitDepth = image->comps[2].bpp;
+ U32 aBitDepth = image->comps[3].bpp;
+
+ U32 totalBitDepth = rBitDepth + gBitDepth + bBitDepth + aBitDepth;
+ U32 bytesPerPixel = totalBitDepth >> 3;
+
+ U32 stride = width * bytesPerPixel;
+ U32 offset = 0;
+ for (S32 y = height - 1; y >= 0; y--)
+ {
+ const U8* component = src + (y * stride);
+ for (S32 x = 0; x < width; x++)
+ {
+ image->comps[0].data[offset] = *component++;
+ image->comps[1].data[offset] = *component++;
+ image->comps[2].data[offset] = *component++;
+ image->comps[3].data[offset] = *component++;
+ offset++;
+ }
+ }
+ }
+ break;
+ }*/
+ }
+
+ opj_image_t* getImage() { return image; }
+
+private:
+ opj_cparameters_t parameters;
+ opj_event_mgr_t event_mgr;
+ opj_image_t* image = nullptr;
+ opj_codec_t* encoder = nullptr;
+ opj_stream_t* stream = nullptr;
+ char* comment_text = nullptr;
+};
- /* catch events using our callbacks and give a local context */
- opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
- /* setup the decoder decoding parameters using user parameters */
- opj_setup_decoder(dinfo, &parameters);
+LLImageJ2COJ::LLImageJ2COJ()
+ : LLImageJ2CImpl()
+{
+}
- /* open a byte stream */
- cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize());
- /* decode the stream and fill the image structure */
- image = opj_decode(dinfo, cio);
+LLImageJ2COJ::~LLImageJ2COJ()
+{
+}
- /* close the byte stream */
- opj_cio_close(cio);
+bool LLImageJ2COJ::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region)
+{
+ base.mDiscardLevel = discard_level;
+ return false;
+}
- /* free remaining structures */
- if(dinfo)
- {
- opj_destroy_decompress(dinfo);
- }
+bool LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
+{
+ // No specific implementation for this method in the OpenJpeg case
+ return false;
+}
- if(!image)
- {
- LL_WARNS() << "ERROR -> getMetadata: failed to decode image!" << LL_ENDL;
- return false;
- }
+bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
+{
+ JPEG2KDecode decoder(0);
+
+ U32 image_channels = 0;
+ S32 data_size = base.getDataSize();
+ S32 max_bytes = (base.getMaxBytes() ? base.getMaxBytes() : data_size);
+ bool decoded = decoder.decode(base.getData(), max_bytes, &image_channels, base.mDiscardLevel);
+
+ // set correct channel count early so failed decodes don't miss it...
+ S32 channels = (S32)image_channels - first_channel;
+ channels = llmin(channels, max_channel_count);
+
+ if (!decoded)
+ {
+ // reset the channel count if necessary
+ if (raw_image.getComponents() != channels)
+ {
+ raw_image.resize(raw_image.getWidth(), raw_image.getHeight(), S8(channels));
+ }
+
+ LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image!" << LL_ENDL;
+ return true; // done
+ }
+
+ opj_image_t *image = decoder.getImage();
+
+ // Component buffers are allocated in an image width by height buffer.
+ // The image placed in that buffer is ceil(width/2^factor) by
+ // ceil(height/2^factor) and if the factor isn't zero it will be at the
+ // top left of the buffer with black filled in the rest of the pixels.
+ // It is integer math so the formula is written in ceildivpo2.
+ // (Assuming all the components have the same width, height and
+ // factor.)
+ U32 comp_width = image->comps[0].w; // leave this unshifted by 'f' discard factor, the strides are always for the full buffer width
+ U32 f = image->comps[0].factor;
+
+ // do size the texture to the mem we'll acrually use...
+ U32 width = image->comps[0].w;
+ U32 height = image->comps[0].h;
+
+ raw_image.resize(U16(width), U16(height), S8(channels));
+
+ U8 *rawp = raw_image.getData();
+
+ // first_channel is what channel to start copying from
+ // dest is what channel to copy to. first_channel comes from the
+ // argument, dest always starts writing at channel zero.
+ for (S32 comp = first_channel, dest = 0; comp < first_channel + channels; comp++, dest++)
+ {
+ llassert(image->comps[comp].data);
+ if (image->comps[comp].data)
+ {
+ S32 offset = dest;
+ for (S32 y = (height - 1); y >= 0; y--)
+ {
+ for (S32 x = 0; x < width; x++)
+ {
+ rawp[offset] = image->comps[comp].data[y*comp_width + x];
+ offset += channels;
+ }
+ }
+ }
+ else // Some rare OpenJPEG versions have this bug.
+ {
+ LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed! (OpenJPEG bug)" << LL_ENDL;
+ }
+ }
+
+ base.setDiscardLevel(f);
+
+ return true; // done
+}
- // Copy image data into our raw image format (instead of the separate channel format
- S32 width = 0;
- S32 height = 0;
- S32 img_components = image->numcomps;
- width = image->x1 - image->x0;
- height = image->y1 - image->y0;
- base.setSize(width, height, img_components);
+bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, bool reversible)
+{
+ JPEG2KEncode encode(comment_text, reversible);
+ bool encoded = encode.encode(raw_image, base);
+ if (encoded)
+ {
+ LL_WARNS() << "Openjpeg encoding implementation isn't complete, returning false" << LL_ENDL;
+ }
+ return encoded;
+ //return false;
+}
- /* free image data structure */
- opj_image_destroy(image);
- return true;
+bool LLImageJ2COJ::getMetadata(LLImageJ2C &base)
+{
+ JPEG2KDecode decode(0);
+
+ S32 width = 0;
+ S32 height = 0;
+ S32 components = 0;
+ S32 discard_level = 0;
+
+ U32 dataSize = base.getDataSize();
+ U8* data = base.getData();
+ bool header_read = decode.readHeader(data, dataSize, width, height, components, discard_level);
+ if (!header_read)
+ {
+ return false;
+ }
+
+ base.mDiscardLevel = discard_level;
+ base.setSize(width, height, components);
+ return true;
}
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 93f1d508f3..91457fbebe 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -2391,7 +2391,25 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD with code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL;
return false;
}
-
+ return unpackVolumeFacesInternal(mdl);
+}
+
+bool LLVolume::unpackVolumeFaces(U8* in_data, S32 size)
+{
+ //input data is now pointing at a zlib compressed block of LLSD
+ //decompress block
+ LLSD mdl;
+ U32 uzip_result = LLUZipHelper::unzip_llsd(mdl, in_data, size);
+ if (uzip_result != LLUZipHelper::ZR_OK)
+ {
+ LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD with code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL;
+ return false;
+ }
+ return unpackVolumeFacesInternal(mdl);
+}
+
+bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
+{
{
U32 face_count = mdl.size();
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index 9697952f5b..b53b0fd1cc 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -1096,8 +1096,12 @@ protected:
BOOL generate();
void createVolumeFaces();
public:
- virtual bool unpackVolumeFaces(std::istream& is, S32 size);
+ bool unpackVolumeFaces(std::istream& is, S32 size);
+ bool unpackVolumeFaces(U8* in_data, S32 size);
+private:
+ bool unpackVolumeFacesInternal(const LLSD& mdl);
+public:
virtual void setMeshAssetLoaded(BOOL loaded);
virtual BOOL isMeshAssetLoaded();
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 555164f3b0..444d9a5366 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -1389,6 +1389,16 @@ LLMeshSkinInfo::LLMeshSkinInfo(LLSD& skin):
fromLLSD(skin);
}
+LLMeshSkinInfo::LLMeshSkinInfo(const LLUUID& mesh_id, LLSD& skin) :
+ mMeshID(mesh_id),
+ mPelvisOffset(0.0),
+ mLockScaleIfJointPosition(false),
+ mInvalidJointsScrubbed(false),
+ mJointNumsInitialized(false)
+{
+ fromLLSD(skin);
+}
+
void LLMeshSkinInfo::fromLLSD(LLSD& skin)
{
if (skin.has("joint_names"))
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index a6ab96ab18..9c99bb75a0 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -41,12 +41,13 @@ class domMesh;
#define MAX_MODEL_FACES 8
LL_ALIGN_PREFIX(16)
-class LLMeshSkinInfo
+class LLMeshSkinInfo : public LLRefCount
{
LL_ALIGN_NEW
public:
LLMeshSkinInfo();
LLMeshSkinInfo(LLSD& data);
+ LLMeshSkinInfo(const LLUUID& mesh_id, LLSD& data);
void fromLLSD(LLSD& data);
LLSD asLLSD(bool include_joints, bool lock_scale_if_joint_position) const;
void updateHash();
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 7d78ec9e3c..4fe83f0c45 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1825,9 +1825,9 @@ if (WINDOWS)
${SHARED_LIB_STAGING_DIR}/Release/libcollada14dom22.dll
${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libcollada14dom22.dll
${SHARED_LIB_STAGING_DIR}/Debug/libcollada14dom22-d.dll
- ${SHARED_LIB_STAGING_DIR}/Release/openjpeg.dll
- ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/openjpeg.dll
- ${SHARED_LIB_STAGING_DIR}/Debug/openjpegd.dll
+ ${SHARED_LIB_STAGING_DIR}/Release/openjp2.dll
+ ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/openjp2.dll
+ ${SHARED_LIB_STAGING_DIR}/Debug/openjp2.dll
${SHARED_LIB_STAGING_DIR}/Release/libhunspell.dll
${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libhunspell.dll
${SHARED_LIB_STAGING_DIR}/Debug/libhunspell.dll
diff --git a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl
index 331249dc33..de22312d3c 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl
@@ -25,6 +25,17 @@
/*[EXTRA_CODE_HERE]*/
+// Inputs
+VARYING vec4 vary_HazeColor;
+VARYING float vary_LightNormPosDot;
+
+uniform sampler2D rainbow_map;
+uniform sampler2D halo_map;
+
+uniform float moisture_level;
+uniform float droplet_radius;
+uniform float ice_level;
+
#ifdef DEFINE_GL_FRAGCOLOR
out vec4 frag_data[3];
#else
@@ -35,11 +46,34 @@ out vec4 frag_data[3];
// The fragment shader for the sky
/////////////////////////////////////////////////////////////////////////
-VARYING vec4 vary_HazeColor;
+vec3 rainbow(float d)
+{
+ // 'Interesting' values of d are -0.75 .. -0.825, i.e. when view vec nearly opposite of sun vec
+ // Rainbox tex is mapped with REPEAT, so -.75 as tex coord is same as 0.25. -0.825 -> 0.175. etc.
+ // SL-13629
+ // Unfortunately the texture is inverted, so we need to invert the y coord, but keep the 'interesting'
+ // part within the same 0.175..0.250 range, i.e. d = (1 - d) - 1.575
+ d = clamp(-0.575 - d, 0.0, 1.0);
+
+ // With the colors in the lower 1/4 of the texture, inverting the coords leaves most of it inaccessible.
+ // So, we can stretch the texcoord above the colors (ie > 0.25) to fill the entire remaining coordinate
+ // space. This improves gradation, reduces banding within the rainbow interior. (1-0.25) / (0.425/0.25) = 4.2857
+ float interior_coord = max(0.0, d - 0.25) * 4.2857;
+ d = clamp(d, 0.0, 0.25) + interior_coord;
+
+ float rad = (droplet_radius - 5.0f) / 1024.0f;
+ return pow(texture2D(rainbow_map, vec2(rad+0.5, d)).rgb, vec3(1.8)) * moisture_level;
+}
+
+vec3 halo22(float d)
+{
+ d = clamp(d, 0.1, 1.0);
+ float v = sqrt(clamp(1 - (d * d), 0, 1));
+ return texture2D(halo_map, vec2(0, v)).rgb * ice_level;
+}
/// Soft clips the light with a gamma correction
vec3 scaleSoftClip(vec3 light);
-vec3 srgb_to_linear(vec3 c);
void main()
{
@@ -48,14 +82,18 @@ void main()
// the fragment) if the sky wouldn't show up because the clouds
// are fully opaque.
- vec4 color;
- color = vary_HazeColor;
+ vec4 color = vary_HazeColor;
+ float rel_pos_lightnorm = vary_LightNormPosDot;
+ float optic_d = rel_pos_lightnorm;
+ vec3 halo_22 = halo22(optic_d);
+ color.rgb += rainbow(optic_d);
+ color.rgb += halo_22;
color.rgb *= 2.;
color.rgb = scaleSoftClip(color.rgb);
- /// Gamma correct for WL (soft clip effect).
- frag_data[0] = vec4(color.rgb, 0.0);
+ // Gamma correct for WL (soft clip effect).
+ frag_data[0] = vec4(color.rgb, 1.0);
frag_data[1] = vec4(0.0,0.0,0.0,0.0);
frag_data[2] = vec4(0.0,0.0,0.0,1.0); //1.0 in norm.w masks off fog
diff --git a/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl b/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl
index 28a1faf24f..6db4690bff 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl
@@ -33,6 +33,7 @@ ATTRIBUTE vec3 position;
// Output parameters
VARYING vec4 vary_HazeColor;
+VARYING float vary_LightNormPosDot;
// Inputs
uniform vec3 camPosLocal;
@@ -72,27 +73,29 @@ void main()
vec3 rel_pos = position.xyz - camPosLocal.xyz + vec3(0, 50, 0);
// Adj position vector to clamp altitude
- if (rel_pos.y > 0)
+ if (rel_pos.y > 0.)
{
rel_pos *= (max_y / rel_pos.y);
}
- if (rel_pos.y < 0)
+ if (rel_pos.y < 0.)
{
rel_pos *= (-32000. / rel_pos.y);
}
- // Can normalize then
- vec3 rel_pos_norm = normalize(rel_pos);
+ // Normalized
+ vec3 rel_pos_norm = normalize(rel_pos);
+ float rel_pos_len = length(rel_pos);
- float rel_pos_len = length(rel_pos);
+ // Grab this value and pass to frag shader for rainbows
+ float rel_pos_lightnorm_dot = dot(rel_pos_norm, lightnorm.xyz);
+ vary_LightNormPosDot = rel_pos_lightnorm_dot;
// Initialize temp variables
vec4 sunlight = (sun_up_factor == 1) ? sunlight_color : moonlight_color;
- vec4 light_atten;
// Sunlight attenuation effect (hue and brightness) due to atmosphere
// this is used later for sunlight modulation at various altitudes
- light_atten = (blue_density + vec4(haze_density * 0.25)) * (density_multiplier * max_y);
+ vec4 light_atten = (blue_density + vec4(haze_density * 0.25)) * (density_multiplier * max_y);
// Calculate relative weights
vec4 combined_haze = abs(blue_density) + vec4(abs(haze_density));
@@ -112,7 +115,7 @@ void main()
combined_haze = exp(-combined_haze * density_dist);
// Compute haze glow
- float haze_glow = 1.0 - dot(rel_pos_norm, lightnorm.xyz);
+ float haze_glow = 1.0 - rel_pos_lightnorm_dot;
// haze_glow is 0 at the sun and increases away from sun
haze_glow = max(haze_glow, .001);
// Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot)
@@ -123,30 +126,30 @@ void main()
// Add "minimum anti-solar illumination"
// For sun, add to glow. For moon, remove glow entirely. SL-13768
- haze_glow = (sun_moon_glow_factor < 1.0) ? 0.0 : (haze_glow + 0.25);
+ haze_glow = (sun_moon_glow_factor < 1.0) ? 0.0 : (sun_moon_glow_factor * (haze_glow + 0.25));
- vec4 color =
- (blue_horizon * blue_weight * (sunlight + ambient_color) + (haze_horizon * haze_weight) * (sunlight * haze_glow + ambient_color));
+ // Haze color above cloud
+ vec4 color = (blue_horizon * blue_weight * (sunlight + ambient_color)
+ + (haze_horizon * haze_weight) * (sunlight * haze_glow + ambient_color));
// Final atmosphere additive
color *= (1. - combined_haze);
// Increase ambient when there are more clouds
- vec4 tmpAmbient = ambient_color;
- tmpAmbient += max(vec4(0), (1. - ambient_color)) * cloud_shadow * 0.5;
+ vec4 ambient = ambient_color + max(vec4(0), (1. - ambient_color)) * cloud_shadow * 0.5;
// Dim sunlight by cloud shadow percentage
sunlight *= max(0.0, (1. - cloud_shadow));
// Haze color below cloud
- vec4 additiveColorBelowCloud =
- (blue_horizon * blue_weight * (sunlight + tmpAmbient) + (haze_horizon * haze_weight) * (sunlight * haze_glow + tmpAmbient));
+ vec4 add_below_cloud = (blue_horizon * blue_weight * (sunlight + ambient)
+ + (haze_horizon * haze_weight) * (sunlight * haze_glow + ambient));
// Attenuate cloud color by atmosphere
combined_haze = sqrt(combined_haze); // less atmos opacity (more transparency) below clouds
// At horizon, blend high altitude sky color towards the darker color below the clouds
- color += (additiveColorBelowCloud - color) * (1. - sqrt(combined_haze));
+ color += (add_below_cloud - color) * (1. - sqrt(combined_haze));
// Haze color above cloud
vary_HazeColor = color;
diff --git a/indra/newview/app_settings/shaders/class2/deferred/skyF.glsl b/indra/newview/app_settings/shaders/class2/deferred/skyF.glsl
deleted file mode 100644
index 6841a8194f..0000000000
--- a/indra/newview/app_settings/shaders/class2/deferred/skyF.glsl
+++ /dev/null
@@ -1,199 +0,0 @@
-/**
- * @file class2/deferred/skyF.glsl
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2005, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-uniform mat4 modelview_projection_matrix;
-
-// SKY ////////////////////////////////////////////////////////////////////////
-// The vertex shader for creating the atmospheric sky
-///////////////////////////////////////////////////////////////////////////////
-
-// Inputs
-uniform vec3 camPosLocal;
-
-uniform vec4 lightnorm;
-uniform vec4 sunlight_color;
-uniform vec4 moonlight_color;
-uniform int sun_up_factor;
-uniform vec4 ambient_color;
-uniform vec4 blue_horizon;
-uniform vec4 blue_density;
-uniform float haze_horizon;
-uniform float haze_density;
-
-uniform float cloud_shadow;
-uniform float density_multiplier;
-uniform float distance_multiplier;
-uniform float max_y;
-
-uniform vec4 glow;
-uniform float sun_moon_glow_factor;
-
-uniform vec4 cloud_color;
-
-#ifdef DEFINE_GL_FRAGCOLOR
-out vec4 frag_data[3];
-#else
-#define frag_data gl_FragData
-#endif
-
-VARYING vec3 pos;
-
-/////////////////////////////////////////////////////////////////////////
-// The fragment shader for the sky
-/////////////////////////////////////////////////////////////////////////
-
-uniform sampler2D rainbow_map;
-uniform sampler2D halo_map;
-
-uniform float moisture_level;
-uniform float droplet_radius;
-uniform float ice_level;
-
-vec3 rainbow(float d)
-{
- // d is the dot product of view and sun directions, so ranging -1.0..1.0
- // 'interesting' values of d are the range -0.75..-0.825, when view is nearly opposite of sun vec
- // Rainbox texture mode is GL_REPEAT, so tc of -.75 is equiv to 0.25, -0.825 equiv to 0.175.
-
- // SL-13629 Rainbow texture has colors within the correct .175...250 range, but order is inverted.
- // Rather than replace the texture, we mirror and translate the y tc to keep the colors within the
- // interesting range, but in reversed order: i.e. d = (1 - d) - 1.575
- d = clamp(-0.575 - d, 0.0, 1.0);
-
- // With the colors in the lower 1/4 of the texture, inverting the coords leaves most of it inaccessible.
- // So, we can stretch the texcoord above the colors (ie > 0.25) to fill the entire remaining coordinate
- // space. This improves gradation, reduces banding within the rainbow interior. (1-0.25) / (0.425/0.25) = 4.2857
- float interior_coord = max(0.0, d - 0.25) * 4.2857;
- d = clamp(d, 0.0, 0.25) + interior_coord;
-
- float rad = (droplet_radius - 5.0f) / 1024.0f;
- return pow(texture2D(rainbow_map, vec2(rad, d)).rgb, vec3(1.8)) * moisture_level;
-}
-
-vec3 halo22(float d)
-{
- d = clamp(d, 0.1, 1.0);
- float v = sqrt(clamp(1 - (d * d), 0, 1));
- return texture2D(halo_map, vec2(0, v)).rgb * ice_level;
-}
-
-/// Soft clips the light with a gamma correction
-vec3 scaleSoftClip(vec3 light);
-
-void main()
-{
- // World / view / projection
- // Get relative position (offset why?)
- vec3 rel_pos = pos.xyz - camPosLocal.xyz + vec3(0, 50, 0);
-
- // Adj position vector to clamp altitude
- if (rel_pos.y > 0.)
- {
- rel_pos *= (max_y / rel_pos.y);
- }
- if (rel_pos.y < 0.)
- {
- rel_pos *= (-32000. / rel_pos.y);
- }
-
- // Normalized
- vec3 rel_pos_norm = normalize(rel_pos);
- float rel_pos_len = length(rel_pos);
-
- // Initialize temp variables
- vec4 sunlight = (sun_up_factor == 1) ? sunlight_color : moonlight_color;
-
- // Sunlight attenuation effect (hue and brightness) due to atmosphere
- // this is used later for sunlight modulation at various altitudes
- vec4 light_atten = (blue_density + vec4(haze_density * 0.25)) * (density_multiplier * max_y);
-
- // Calculate relative weights
- vec4 combined_haze = abs(blue_density) + vec4(abs(haze_density));
- vec4 blue_weight = blue_density / combined_haze;
- vec4 haze_weight = haze_density / combined_haze;
-
- // Compute sunlight from rel_pos & lightnorm (for long rays like sky)
- float off_axis = 1.0 / max(1e-6, max(0, rel_pos_norm.y) + lightnorm.y);
- sunlight *= exp(-light_atten * off_axis);
-
- // Distance
- float density_dist = rel_pos_len * density_multiplier;
-
- // Transparency (-> combined_haze)
- // ATI Bugfix -- can't store combined_haze*density_dist in a variable because the ati
- // compiler gets confused.
- combined_haze = exp(-combined_haze * density_dist);
-
- // Compute haze glow
- float haze_glow = dot(rel_pos_norm, lightnorm.xyz);
- haze_glow = 1. - haze_glow;
- // haze_glow is 0 at the sun and increases away from sun
- haze_glow = max(haze_glow, .001);
- // Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot)
- haze_glow *= glow.x;
- // Higher glow.x gives dimmer glow (because next step is 1 / "angle")
- haze_glow = pow(haze_glow, glow.z);
- // glow.z should be negative, so we're doing a sort of (1 / "angle") function
-
- // Add "minimum anti-solar illumination"
- // For sun, add to glow. For moon, remove glow entirely. SL-13768
- haze_glow = (sun_moon_glow_factor < 1.0) ? 0.0 : (sun_moon_glow_factor * (haze_glow + 0.25));
-
- // Haze color above cloud
- vec4 color = blue_horizon * blue_weight * (sunlight + ambient_color)
- + haze_horizon * haze_weight * (sunlight * haze_glow + ambient_color);
-
- // Final atmosphere additive
- color *= (1. - combined_haze);
-
- // Increase ambient when there are more clouds
- // TODO 9/20: DJH what does this do? max(0,(1-ambient)) will change the color
- vec4 ambient = ambient_color + max(vec4(0), (1. - ambient_color)) * cloud_shadow * 0.5;
-
- // Dim sunlight by cloud shadow percentage
- sunlight *= max(0.0, (1. - cloud_shadow));
-
- // Haze color below cloud
- vec4 add_below_cloud = blue_horizon * blue_weight * (sunlight + ambient)
- + haze_horizon * haze_weight * (sunlight * haze_glow + ambient);
-
- // Attenuate cloud color by atmosphere
- combined_haze = sqrt(combined_haze); // less atmos opacity (more transparency) below clouds
-
- // At horizon, blend high altitude sky color towards the darker color below the clouds
- color += (add_below_cloud - color) * (1. - sqrt(combined_haze));
-
- float optic_d = dot(rel_pos_norm, lightnorm.xyz);
- vec3 halo_22 = halo22(optic_d);
- color.rgb += rainbow(optic_d);
- color.rgb += halo_22;
- color.rgb *= 2.;
- color.rgb = scaleSoftClip(color.rgb);
-
- // Gamma correct for WL (soft clip effect).
- frag_data[0] = vec4(color.rgb, 1.0);
- frag_data[1] = vec4(0.0, 0.0, 0.0, 0.0);
- frag_data[2] = vec4(0.0, 0.0, 0.0, 1.0); // 1.0 in norm.w masks off fog
-}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/skyV.glsl b/indra/newview/app_settings/shaders/class2/deferred/skyV.glsl
deleted file mode 100644
index bcf775577a..0000000000
--- a/indra/newview/app_settings/shaders/class2/deferred/skyV.glsl
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * @file WLSkyV.glsl
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2005, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-uniform mat4 modelview_projection_matrix;
-
-ATTRIBUTE vec3 position;
-
-// SKY ////////////////////////////////////////////////////////////////////////
-// The vertex shader for creating the atmospheric sky
-///////////////////////////////////////////////////////////////////////////////
-
-VARYING vec3 pos;
-
-void main()
-{
-
- // World / view / projection
- pos = position.xyz;
- gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
-}
diff --git a/indra/newview/llbuycurrencyhtml.cpp b/indra/newview/llbuycurrencyhtml.cpp
index 1c69dadb12..7ad06f8eaa 100644
--- a/indra/newview/llbuycurrencyhtml.cpp
+++ b/indra/newview/llbuycurrencyhtml.cpp
@@ -41,7 +41,7 @@ class LLBuyCurrencyHTMLHandler :
{
public:
// requests will be throttled from a non-trusted browser
- LLBuyCurrencyHTMLHandler() : LLCommandHandler( "buycurrencyhtml", UNTRUSTED_ALLOW ) {}
+ LLBuyCurrencyHTMLHandler() : LLCommandHandler( "buycurrencyhtml", UNTRUSTED_THROTTLE) {}
bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
{
diff --git a/indra/newview/llcommandhandler.cpp b/indra/newview/llcommandhandler.cpp
index 23e2271eae..74f37961c7 100644
--- a/indra/newview/llcommandhandler.cpp
+++ b/indra/newview/llcommandhandler.cpp
@@ -39,6 +39,7 @@
#define THROTTLE_PERIOD 5 // required seconds between throttled commands
static LLCommandDispatcherListener sCommandDispatcherListener;
+const std::string LLCommandHandler::NAV_TYPE_CLICKED = "clicked";
//---------------------------------------------------------------------------
// Underlying registry for command handlers, not directly accessible.
@@ -64,6 +65,9 @@ public:
bool trusted_browser);
private:
+ void notifySlurlBlocked();
+ void notifySlurlThrottled();
+
friend LLSD LLCommandDispatcher::enumerate();
std::map<std::string, LLCommandHandlerInfo> mMap;
};
@@ -96,8 +100,6 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
const std::string& nav_type,
bool trusted_browser)
{
- static bool slurl_blocked = false;
- static bool slurl_throttled = false;
static F64 last_throttle_time = 0.0;
F64 cur_time = 0.0;
std::map<std::string, LLCommandHandlerInfo>::iterator it = mMap.find(cmd);
@@ -115,44 +117,45 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
// block request from external browser, but report as
// "handled" because it was well formatted.
LL_WARNS_ONCE("SLURL") << "Blocked SLURL command from untrusted browser" << LL_ENDL;
- if (! slurl_blocked)
- {
- if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT)
- {
- // Note: commands can arrive before we initialize everything we need for Notification.
- LLNotificationsUtil::add("BlockedSLURL");
- }
- slurl_blocked = true;
- }
+ notifySlurlBlocked();
return true;
+ case LLCommandHandler::UNTRUSTED_CLICK_ONLY:
+ if (nav_type == LLCommandHandler::NAV_TYPE_CLICKED
+ && info.mHandler->canHandleUntrusted(params, query_map, web, nav_type))
+ {
+ break;
+ }
+ LL_WARNS_ONCE("SLURL") << "Blocked SLURL click-only command " << cmd << " from untrusted browser" << LL_ENDL;
+ notifySlurlBlocked();
+ return true;
+
case LLCommandHandler::UNTRUSTED_THROTTLE:
+ //skip initial request from external browser before STATE_BROWSER_INIT
+ if (LLStartUp::getStartupState() == STATE_FIRST)
+ {
+ return true;
+ }
+ if (!info.mHandler->canHandleUntrusted(params, query_map, web, nav_type))
+ {
+ LL_WARNS_ONCE("SLURL") << "Blocked SLURL command from untrusted browser" << LL_ENDL;
+ notifySlurlBlocked();
+ return true;
+ }
// if users actually click on a link, we don't need to throttle it
// (throttling mechanism is used to prevent an avalanche of clicks via
// javascript
- if ( nav_type == "clicked" )
+ if (nav_type == LLCommandHandler::NAV_TYPE_CLICKED)
{
break;
}
- //skip initial request from external browser before STATE_BROWSER_INIT
- if (LLStartUp::getStartupState() == STATE_FIRST)
- {
- return true;
- }
cur_time = LLTimer::getElapsedSeconds();
if (cur_time < last_throttle_time + THROTTLE_PERIOD)
{
// block request from external browser if it happened
// within THROTTLE_PERIOD seconds of the last command
LL_WARNS_ONCE("SLURL") << "Throttled SLURL command from untrusted browser" << LL_ENDL;
- if (! slurl_throttled)
- {
- if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT)
- {
- LLNotificationsUtil::add("ThrottledSLURL");
- }
- slurl_throttled = true;
- }
+ notifySlurlThrottled();
return true;
}
last_throttle_time = cur_time;
@@ -163,6 +166,34 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
return info.mHandler->handle(params, query_map, web);
}
+void LLCommandHandlerRegistry::notifySlurlBlocked()
+{
+ static bool slurl_blocked = false;
+ if (!slurl_blocked)
+ {
+ if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT)
+ {
+ // Note: commands can arrive before we initialize everything we need for Notification.
+ LLNotificationsUtil::add("BlockedSLURL");
+ }
+ slurl_blocked = true;
+ }
+}
+
+void LLCommandHandlerRegistry::notifySlurlThrottled()
+{
+ static bool slurl_throttled = false;
+ if (!slurl_throttled)
+ {
+ if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT)
+ {
+ // Note: commands can arrive before we initialize everything we need for Notification.
+ LLNotificationsUtil::add("ThrottledSLURL");
+ }
+ slurl_throttled = true;
+ }
+}
+
//---------------------------------------------------------------------------
// Automatic registration of commands, runs before main()
//---------------------------------------------------------------------------
@@ -230,6 +261,7 @@ symbol_info symbols[] =
{
ent(LLCommandHandler::UNTRUSTED_ALLOW), // allow commands from untrusted browsers
ent(LLCommandHandler::UNTRUSTED_BLOCK), // ignore commands from untrusted browsers
+ ent(LLCommandHandler::UNTRUSTED_CLICK_ONLY), // allow untrusted, but only if clicked
ent(LLCommandHandler::UNTRUSTED_THROTTLE) // allow untrusted, but only a few per min.
};
diff --git a/indra/newview/llcommandhandler.h b/indra/newview/llcommandhandler.h
index 1e0895565a..763e3ee51f 100644
--- a/indra/newview/llcommandhandler.h
+++ b/indra/newview/llcommandhandler.h
@@ -65,9 +65,12 @@ public:
{
UNTRUSTED_ALLOW, // allow commands from untrusted browsers
UNTRUSTED_BLOCK, // ignore commands from untrusted browsers
+ UNTRUSTED_CLICK_ONLY, // allow untrusted, but only if clicked
UNTRUSTED_THROTTLE // allow untrusted, but only a few per min.
};
+ static const std::string NAV_TYPE_CLICKED;
+
LLCommandHandler(const char* command, EUntrustedAccess untrusted_access);
// Automatically registers object to get called when
// command is executed. All commands can be processed
@@ -76,6 +79,13 @@ public:
virtual ~LLCommandHandler();
+ virtual bool canHandleUntrusted(
+ const LLSD& params,
+ const LLSD& query_map,
+ LLMediaCtrl* web,
+ const std::string& nav_type)
+ { return true; }
+
virtual bool handle(const LLSD& params,
const LLSD& query_map,
LLMediaCtrl* web) = 0;
diff --git a/indra/newview/llfloater360capture.cpp b/indra/newview/llfloater360capture.cpp
index c075f7e8bd..8ad0bb3995 100644
--- a/indra/newview/llfloater360capture.cpp
+++ b/indra/newview/llfloater360capture.cpp
@@ -84,7 +84,7 @@ LLFloater360Capture::~LLFloater360Capture()
// Tell the Simulator not to send us everything anymore
// and revert to the regular "keyhole" frustum of interest
// list updates.
- if (gSavedSettings.getBOOL("360CaptureUseInterestListCap"))
+ if (gSavedSettings.getBOOL("360CaptureUseInterestListCap") && !LLApp::isExiting())
{
const bool send_everything = false;
changeInterestListMode(send_everything);
@@ -537,7 +537,8 @@ void LLFloater360Capture::capture360Images()
// We need to convert from the angle getYaw() gives us into something
// the XMP data field wants (N=0, E=90, S=180, W= 270 etc.)
mInitialHeadingDeg = (360 + 90 - (int)(camera->getYaw() * RAD_TO_DEG)) % 360;
- LL_INFOS("360Capture") << "Recording a heading of " << (int)(mInitialHeadingDeg) << LL_ENDL;
+ LL_INFOS("360Capture") << "Recording a heading of " << (int)(mInitialHeadingDeg)
+ << " Image size: " << (S32)mSourceImageSize << LL_ENDL;
// camera constants for the square, cube map capture image
camera->setAspect(1.0); // must set aspect ratio first to avoid undesirable clamping of vertical FoV
@@ -587,6 +588,9 @@ void LLFloater360Capture::capture360Images()
// for each of the 6 directions we shoot...
for (int i = 0; i < 6; i++)
{
+ LLAppViewer::instance()->pauseMainloopTimeout();
+ LLViewerStats::instance().getRecording().stop();
+
// these buffers are where the raw, captured pixels are stored and
// the first time we use them, we have to make a new one
if (mRawImages[i] == nullptr)
@@ -624,8 +628,10 @@ void LLFloater360Capture::capture360Images()
auto duration = std::chrono::duration_cast<std::chrono::duration<double>>(t_end - t_start);
encode_time_total += duration.count();
- // ping the main loop in case the snapshot process takes a really long
- // time and we get disconnected
+ LLViewerStats::instance().getRecording().resume();
+ LLAppViewer::instance()->resumeMainloopTimeout();
+
+ // update main loop timeout state
LLAppViewer::instance()->pingMainloopTimeout("LLFloater360Capture::capture360Images");
}
diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp
index 2a1749bd42..a682064dad 100644
--- a/indra/newview/llfloateropenobject.cpp
+++ b/indra/newview/llfloateropenobject.cpp
@@ -56,8 +56,6 @@ LLFloaterOpenObject::LLFloaterOpenObject(const LLSD& key)
mDirty(TRUE)
{
mCommitCallbackRegistrar.add("OpenObject.MoveToInventory", boost::bind(&LLFloaterOpenObject::onClickMoveToInventory, this));
- mCommitCallbackRegistrar.add("OpenObject.MoveAndWear", boost::bind(&LLFloaterOpenObject::onClickMoveAndWear, this));
- mCommitCallbackRegistrar.add("OpenObject.ReplaceOutfit", boost::bind(&LLFloaterOpenObject::onClickReplace, this));
mCommitCallbackRegistrar.add("OpenObject.Cancel", boost::bind(&LLFloaterOpenObject::onClickCancel, this));
}
@@ -243,18 +241,6 @@ void LLFloaterOpenObject::onClickMoveToInventory()
closeFloater();
}
-void LLFloaterOpenObject::onClickMoveAndWear()
-{
- moveToInventory(true, false);
- closeFloater();
-}
-
-void LLFloaterOpenObject::onClickReplace()
-{
- moveToInventory(true, true);
- closeFloater();
-}
-
void LLFloaterOpenObject::onClickCancel()
{
closeFloater();
diff --git a/indra/newview/llfloateropenobject.h b/indra/newview/llfloateropenobject.h
index 2e761f99bf..745753316b 100644
--- a/indra/newview/llfloateropenobject.h
+++ b/indra/newview/llfloateropenobject.h
@@ -63,8 +63,6 @@ protected:
void moveToInventory(bool wear, bool replace = false);
void onClickMoveToInventory();
- void onClickMoveAndWear();
- void onClickReplace();
void onClickCancel();
static void callbackCreateInventoryCategory(const LLUUID& category_id, LLUUID object_id, bool wear, bool replace = false);
static void callbackMoveInventory(S32 result, void* data);
diff --git a/indra/newview/llfloaterpathfindinglinksets.cpp b/indra/newview/llfloaterpathfindinglinksets.cpp
index 1e46d7a402..03aede94c6 100644
--- a/indra/newview/llfloaterpathfindinglinksets.cpp
+++ b/indra/newview/llfloaterpathfindinglinksets.cpp
@@ -44,6 +44,7 @@
#include "llpathfindinglinkset.h"
#include "llpathfindinglinksetlist.h"
#include "llpathfindingmanager.h"
+#include "llsearcheditor.h"
#include "llscrolllistitem.h"
#include "llsd.h"
#include "lltextbase.h"
@@ -114,17 +115,13 @@ BOOL LLFloaterPathfindingLinksets::postBuild()
{
mBeaconColor = LLUIColorTable::getInstance()->getColor("PathfindingLinksetBeaconColor");
- mFilterByName = findChild<LLLineEditor>("filter_by_name");
- llassert(mFilterByName != NULL);
- mFilterByName->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this));
- mFilterByName->setSelectAllonFocusReceived(true);
- mFilterByName->setCommitOnFocusLost(true);
-
- mFilterByDescription = findChild<LLLineEditor>("filter_by_description");
- llassert(mFilterByDescription != NULL);
- mFilterByDescription->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this));
- mFilterByDescription->setSelectAllonFocusReceived(true);
- mFilterByDescription->setCommitOnFocusLost(true);
+ mFilterByName = getChild<LLSearchEditor>("filter_by_name");
+ mFilterByName->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this));
+ mFilterByName->setCommitOnFocusLost(true);
+
+ mFilterByDescription = getChild<LLSearchEditor>("filter_by_description");
+ mFilterByDescription->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this));
+ mFilterByDescription->setCommitOnFocusLost(true);
mFilterByLinksetUse = findChild<LLComboBox>("filter_by_linkset_use");
llassert(mFilterByLinksetUse != NULL);
diff --git a/indra/newview/llfloaterpathfindinglinksets.h b/indra/newview/llfloaterpathfindinglinksets.h
index 7149da9215..a954d8a8ec 100644
--- a/indra/newview/llfloaterpathfindinglinksets.h
+++ b/indra/newview/llfloaterpathfindinglinksets.h
@@ -42,6 +42,7 @@ class LLSD;
class LLTextBase;
class LLUICtrl;
class LLVector3;
+class LLSearchEditor;
class LLFloaterPathfindingLinksets : public LLFloaterPathfindingObjects
{
@@ -105,8 +106,8 @@ private:
LLPathfindingLinkset::ELinksetUse convertToLinksetUse(LLSD pXuiValue) const;
LLSD convertToXuiValue(LLPathfindingLinkset::ELinksetUse pLinksetUse) const;
- LLLineEditor *mFilterByName;
- LLLineEditor *mFilterByDescription;
+ LLSearchEditor *mFilterByName;
+ LLSearchEditor *mFilterByDescription;
LLComboBox *mFilterByLinksetUse;
LLComboBox *mEditLinksetUse;
LLScrollListItem *mEditLinksetUseUnset;
diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp
index bb3ed77772..7e6af45515 100644
--- a/indra/newview/llfloatersearch.cpp
+++ b/indra/newview/llfloatersearch.cpp
@@ -45,7 +45,7 @@ class LLSearchHandler : public LLCommandHandler
{
public:
// requires trusted browser to trigger
- LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_THROTTLE) { }
+ LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_CLICK_ONLY) { }
bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web)
{
if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableSearch"))
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index 977023cfe4..4f772aa141 100644
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -123,7 +123,7 @@ class LLWorldMapHandler : public LLCommandHandler
{
public:
// requires trusted browser to trigger
- LLWorldMapHandler() : LLCommandHandler("worldmap", UNTRUSTED_THROTTLE ) { }
+ LLWorldMapHandler() : LLCommandHandler("worldmap", UNTRUSTED_CLICK_ONLY ) { }
bool handle(const LLSD& params, const LLSD& query_map,
LLMediaCtrl* web)
@@ -160,7 +160,7 @@ class LLMapTrackAvatarHandler : public LLCommandHandler
{
public:
// requires trusted browser to trigger
- LLMapTrackAvatarHandler() : LLCommandHandler("maptrackavatar", UNTRUSTED_THROTTLE)
+ LLMapTrackAvatarHandler() : LLCommandHandler("maptrackavatar", UNTRUSTED_CLICK_ONLY)
{
}
diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp
index 84a1278767..815840f990 100644
--- a/indra/newview/llgroupactions.cpp
+++ b/indra/newview/llgroupactions.cpp
@@ -52,7 +52,32 @@ class LLGroupHandler : public LLCommandHandler
{
public:
// requires trusted browser to trigger
- LLGroupHandler() : LLCommandHandler("group", UNTRUSTED_THROTTLE) { }
+ LLGroupHandler() : LLCommandHandler("group", UNTRUSTED_CLICK_ONLY) { }
+
+ virtual bool canHandleUntrusted(
+ const LLSD& params,
+ const LLSD& query_map,
+ LLMediaCtrl* web,
+ const std::string& nav_type)
+ {
+ if (params.size() < 1)
+ {
+ return true; // don't block, will fail later
+ }
+
+ if (nav_type == NAV_TYPE_CLICKED)
+ {
+ return true;
+ }
+
+ const std::string verb = params[0].asString();
+ if (verb == "create")
+ {
+ return false;
+ }
+ return true;
+ }
+
bool handle(const LLSD& tokens, const LLSD& query_map,
LLMediaCtrl* web)
{
diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp
index 11aa607393..6e1e6506d9 100644
--- a/indra/newview/llmaterialmgr.cpp
+++ b/indra/newview/llmaterialmgr.cpp
@@ -429,12 +429,10 @@ void LLMaterialMgr::onGetResponse(bool success, const LLSD& content, const LLUUI
llassert(content.has(MATERIALS_CAP_ZIP_FIELD));
llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary());
- LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();
- std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size());
- std::istringstream content_stream(content_string);
+ const LLSD::Binary& content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();
LLSD response_data;
- U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_stream, content_binary.size());
+ U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_binary.data(), content_binary.size());
if (uzip_result != LLUZipHelper::ZR_OK)
{
LL_WARNS("Materials") << "Cannot unzip LLSD binary content: " << uzip_result << LL_ENDL;
@@ -472,12 +470,10 @@ void LLMaterialMgr::onGetAllResponse(bool success, const LLSD& content, const LL
llassert(content.has(MATERIALS_CAP_ZIP_FIELD));
llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary());
- LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();
- std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size());
- std::istringstream content_stream(content_string);
+ const LLSD::Binary& content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();
LLSD response_data;
- U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_stream, content_binary.size());
+ U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_binary.data(), content_binary.size());
if (uzip_result != LLUZipHelper::ZR_OK)
{
LL_WARNS("Materials") << "Cannot unzip LLSD binary content: " << uzip_result << LL_ENDL;
@@ -541,12 +537,10 @@ void LLMaterialMgr::onPutResponse(bool success, const LLSD& content)
llassert(content.has(MATERIALS_CAP_ZIP_FIELD));
llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary());
- LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();
- std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size());
- std::istringstream content_stream(content_string);
+ const LLSD::Binary& content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();
LLSD response_data;
- U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_stream, content_binary.size());
+ U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_binary.data(), content_binary.size());
if (uzip_result != LLUZipHelper::ZR_OK)
{
LL_WARNS("Materials") << "Cannot unzip LLSD binary content: " << uzip_result << LL_ENDL;
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 4dd0543693..f937754368 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -77,6 +77,8 @@
#include "lluploaddialog.h"
#include "llfloaterreg.h"
+#include "boost/iostreams/device/array.hpp"
+#include "boost/iostreams/stream.hpp"
#include "boost/lexical_cast.hpp"
#ifndef LL_WINDOWS
@@ -138,7 +140,7 @@
// data copied
// headerReceived() invoked
// LLSD parsed
-// mMeshHeader, mMeshHeaderSize updated
+// mMeshHeader updated
// scan mPendingLOD for LOD request
// push LODRequest to mLODReqQ
// ...
@@ -246,7 +248,6 @@
// sActiveLODRequests mMutex rw.any.mMutex, ro.repo.none [1]
// sMaxConcurrentRequests mMutex wo.main.none, ro.repo.none, ro.main.mMutex
// mMeshHeader mHeaderMutex rw.repo.mHeaderMutex, ro.main.mHeaderMutex, ro.main.none [0]
-// mMeshHeaderSize mHeaderMutex rw.repo.mHeaderMutex
// mSkinRequests mMutex rw.repo.mMutex, ro.repo.none [5]
// mSkinInfoQ mMutex rw.repo.mMutex, rw.main.mMutex [5] (was: [0])
// mDecompositionRequests mMutex rw.repo.mMutex, ro.repo.none [5]
@@ -858,6 +859,12 @@ LLMeshRepoThread::~LLMeshRepoThread()
mHttpRequestSet.clear();
mHttpHeaders.reset();
+ while (!mSkinInfoQ.empty())
+ {
+ delete mSkinInfoQ.front();
+ mSkinInfoQ.pop_front();
+ }
+
while (!mDecompositionQ.empty())
{
delete mDecompositionQ.front();
@@ -947,7 +954,8 @@ void LLMeshRepoThread::run()
else
{
// too many fails
- mUnavailableQ.push(req);
+ LLMutexLock lock(mMutex);
+ mUnavailableQ.push_back(req);
LL_WARNS() << "Failed to load " << req.mMeshParams << " , skip" << LL_ENDL;
}
}
@@ -1023,37 +1031,42 @@ void LLMeshRepoThread::run()
if (!mSkinRequests.empty())
{
- std::set<UUIDBasedRequest> incomplete;
- while (!mSkinRequests.empty() && mHttpRequestSet.size() < sRequestHighWater)
- {
- mMutex->lock();
- std::set<UUIDBasedRequest>::iterator iter = mSkinRequests.begin();
- UUIDBasedRequest req = *iter;
- mSkinRequests.erase(iter);
- mMutex->unlock();
- if (req.isDelayed())
- {
- incomplete.insert(req);
- }
- else if (!fetchMeshSkinInfo(req.mId))
- {
- if (req.canRetry())
- {
- req.updateTime();
- incomplete.insert(req);
- }
- else
- {
- LL_DEBUGS() << "mSkinRequests failed: " << req.mId << LL_ENDL;
- }
- }
- }
+ std::list<UUIDBasedRequest> incomplete;
+ while (!mSkinRequests.empty() && mHttpRequestSet.size() < sRequestHighWater)
+ {
- if (!incomplete.empty())
- {
- LLMutexLock locker(mMutex);
- mSkinRequests.insert(incomplete.begin(), incomplete.end());
- }
+ mMutex->lock();
+ auto req = mSkinRequests.front();
+ mSkinRequests.pop_front();
+ mMutex->unlock();
+ if (req.isDelayed())
+ {
+ incomplete.emplace_back(req);
+ }
+ else if (!fetchMeshSkinInfo(req.mId, req.canRetry()))
+ {
+ if (req.canRetry())
+ {
+ req.updateTime();
+ incomplete.emplace_back(req);
+ }
+ else
+ {
+ LLMutexLock locker(mMutex);
+ mSkinUnavailableQ.push_back(req);
+ LL_DEBUGS() << "mSkinReqQ failed: " << req.mId << LL_ENDL;
+ }
+ }
+ }
+
+ if (!incomplete.empty())
+ {
+ LLMutexLock locker(mMutex);
+ for (const auto& req : incomplete)
+ {
+ mSkinRequests.push_back(req);
+ }
+ }
}
// holding lock, try next list
@@ -1152,7 +1165,7 @@ void LLMeshRepoThread::run()
// Mutex: LLMeshRepoThread::mMutex must be held on entry
void LLMeshRepoThread::loadMeshSkinInfo(const LLUUID& mesh_id)
{
- mSkinRequests.insert(UUIDBasedRequest(mesh_id));
+ mSkinRequests.push_back(UUIDBasedRequest(mesh_id));
}
// Mutex: LLMeshRepoThread::mMutex must be held on entry
@@ -1178,10 +1191,13 @@ void LLMeshRepoThread::lockAndLoadMeshLOD(const LLVolumeParams& mesh_params, S32
void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
{ //could be called from any thread
+ const LLUUID& mesh_id = mesh_params.getSculptID();
LLMutexLock lock(mMutex);
- mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID());
+ LLMutexLock header_lock(mHeaderMutex);
+ mesh_header_map::iterator iter = mMeshHeader.find(mesh_id);
if (iter != mMeshHeader.end())
{ //if we have the header, request LOD byte range
+
LODRequest req(mesh_params, lod);
{
mLODReqQ.push(req);
@@ -1191,8 +1207,7 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
else
{
HeaderRequest req(mesh_params);
-
- pending_lod_map::iterator pending = mPendingLOD.find(mesh_params);
+ pending_lod_map::iterator pending = mPendingLOD.find(mesh_id);
if (pending != mPendingLOD.end())
{ //append this lod request to existing header request
@@ -1202,7 +1217,7 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
else
{ //if no header request is pending, fetch header
mHeaderReqQ.push(req);
- mPendingLOD[mesh_params].push_back(lod);
+ mPendingLOD[mesh_id].push_back(lod);
}
}
}
@@ -1307,7 +1322,7 @@ LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url,
}
-bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
+bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry)
{
if (!mHeaderMutex)
@@ -1317,7 +1332,8 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
mHeaderMutex->lock();
- if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
+ auto header_it = mMeshHeader.find(mesh_id);
+ if (header_it == mMeshHeader.end())
{ //we have no header info for this mesh, do nothing
mHeaderMutex->unlock();
return false;
@@ -1325,13 +1341,14 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
++LLMeshRepository::sMeshRequestCount;
bool ret = true;
- U32 header_size = mMeshHeaderSize[mesh_id];
+ U32 header_size = header_it->second.first;
if (header_size > 0)
{
- S32 version = mMeshHeader[mesh_id]["version"].asInteger();
- S32 offset = header_size + mMeshHeader[mesh_id]["skin"]["offset"].asInteger();
- S32 size = mMeshHeader[mesh_id]["skin"]["size"].asInteger();
+ const LLSD& header = header_it->second.second;
+ S32 version = header["version"].asInteger();
+ S32 offset = header_size + header["skin"]["offset"].asInteger();
+ S32 size = header["skin"]["size"].asInteger();
mHeaderMutex->unlock();
@@ -1387,13 +1404,28 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
<< LL_ENDL;
ret = false;
}
- else
+ else if(can_retry)
{
handler->mHttpHandle = handle;
mHttpRequestSet.insert(handler);
}
+ else
+ {
+ LLMutexLock locker(mMutex);
+ mSkinUnavailableQ.emplace_back(mesh_id);
+ }
+ }
+ else
+ {
+ LLMutexLock locker(mMutex);
+ mSkinUnavailableQ.emplace_back(mesh_id);
}
}
+ else
+ {
+ LLMutexLock locker(mMutex);
+ mSkinUnavailableQ.emplace_back(mesh_id);
+ }
}
else
{
@@ -1413,21 +1445,23 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
mHeaderMutex->lock();
- if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
+ auto header_it = mMeshHeader.find(mesh_id);
+ if (header_it == mMeshHeader.end())
{ //we have no header info for this mesh, do nothing
mHeaderMutex->unlock();
return false;
}
++LLMeshRepository::sMeshRequestCount;
- U32 header_size = mMeshHeaderSize[mesh_id];
+ U32 header_size = header_it->second.first;
bool ret = true;
if (header_size > 0)
{
- S32 version = mMeshHeader[mesh_id]["version"].asInteger();
- S32 offset = header_size + mMeshHeader[mesh_id]["physics_convex"]["offset"].asInteger();
- S32 size = mMeshHeader[mesh_id]["physics_convex"]["size"].asInteger();
+ const auto& header = header_it->second.second;
+ S32 version = header["version"].asInteger();
+ S32 offset = header_size + header["physics_convex"]["offset"].asInteger();
+ S32 size = header["physics_convex"]["size"].asInteger();
mHeaderMutex->unlock();
@@ -1510,21 +1544,23 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
mHeaderMutex->lock();
- if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
+ auto header_it = mMeshHeader.find(mesh_id);
+ if (header_it == mMeshHeader.end())
{ //we have no header info for this mesh, do nothing
mHeaderMutex->unlock();
return false;
}
++LLMeshRepository::sMeshRequestCount;
- U32 header_size = mMeshHeaderSize[mesh_id];
+ U32 header_size = header_it->second.first;
bool ret = true;
if (header_size > 0)
{
- S32 version = mMeshHeader[mesh_id]["version"].asInteger();
- S32 offset = header_size + mMeshHeader[mesh_id]["physics_mesh"]["offset"].asInteger();
- S32 size = mMeshHeader[mesh_id]["physics_mesh"]["size"].asInteger();
+ const auto& header = header_it->second.second;
+ S32 version = header["version"].asInteger();
+ S32 offset = header_size + header["physics_mesh"]["offset"].asInteger();
+ S32 size = header["physics_mesh"]["size"].asInteger();
mHeaderMutex->unlock();
@@ -1704,20 +1740,25 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod,
return false;
}
- mHeaderMutex->lock();
+ const LLUUID& mesh_id = mesh_params.getSculptID();
+ mHeaderMutex->lock();
+ auto header_it = mMeshHeader.find(mesh_id);
+ if (header_it == mMeshHeader.end())
+ { //we have no header info for this mesh, do nothing
+ mHeaderMutex->unlock();
+ return false;
+ }
++LLMeshRepository::sMeshRequestCount;
bool retval = true;
-
- LLUUID mesh_id = mesh_params.getSculptID();
- U32 header_size = mMeshHeaderSize[mesh_id];
-
+ U32 header_size = header_it->second.first;
if (header_size > 0)
{
- S32 version = mMeshHeader[mesh_id]["version"].asInteger();
- S32 offset = header_size + mMeshHeader[mesh_id][header_lod[lod]]["offset"].asInteger();
- S32 size = mMeshHeader[mesh_id][header_lod[lod]]["size"].asInteger();
+ const auto& header = header_it->second.second;
+ S32 version = header["version"].asInteger();
+ S32 offset = header_size + header[header_lod[lod]]["offset"].asInteger();
+ S32 size = header[header_lod[lod]]["size"].asInteger();
mHeaderMutex->unlock();
if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
@@ -1792,17 +1833,20 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod,
}
else
{
- mUnavailableQ.push(LODRequest(mesh_params, lod));
+ LLMutexLock lock(mMutex);
+ mUnavailableQ.push_back(LODRequest(mesh_params, lod));
}
}
else
{
- mUnavailableQ.push(LODRequest(mesh_params, lod));
+ LLMutexLock lock(mMutex);
+ mUnavailableQ.push_back(LODRequest(mesh_params, lod));
}
}
else
{
- mUnavailableQ.push(LODRequest(mesh_params, lod));
+ LLMutexLock lock(mMutex);
+ mUnavailableQ.push_back(LODRequest(mesh_params, lod));
}
}
else
@@ -1821,27 +1865,12 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes
U32 header_size = 0;
if (data_size > 0)
{
- std::istringstream stream;
- try
- {
- std::string res_str((char*)data, data_size);
+ U32 dsize = data_size;
+ char* result_ptr = strip_deprecated_header((char*)data, dsize, &header_size);
- std::string deprecated_header("<? LLSD/Binary ?>");
+ data_size = dsize;
- if (res_str.substr(0, deprecated_header.size()) == deprecated_header)
- {
- res_str = res_str.substr(deprecated_header.size() + 1, data_size);
- header_size = deprecated_header.size() + 1;
- }
- data_size = res_str.size();
-
- stream.str(res_str);
- }
- catch (std::bad_alloc&)
- {
- // out of memory, we won't be able to process this mesh
- return MESH_OUT_OF_MEMORY;
- }
+ boost::iostreams::stream<boost::iostreams::array_source> stream(result_ptr, data_size);
if (!LLSDSerialize::fromBinary(header, stream, data_size))
{
@@ -1878,8 +1907,7 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes
{
LLMutexLock lock(mHeaderMutex);
- mMeshHeaderSize[mesh_id] = header_size;
- mMeshHeader[mesh_id] = header;
+ mMeshHeader[mesh_id] = { header_size, header };
LLMeshRepository::sCacheBytesHeaders += header_size;
}
@@ -1887,7 +1915,7 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes
LLMutexLock lock(mMutex); // make sure only one thread access mPendingLOD at the same time.
//check for pending requests
- pending_lod_map::iterator iter = mPendingLOD.find(mesh_params);
+ pending_lod_map::iterator iter = mPendingLOD.find(mesh_id);
if (iter != mPendingLOD.end())
{
for (U32 i = 0; i < iter->second.size(); ++i)
@@ -1911,26 +1939,14 @@ EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_p
}
LLPointer<LLVolume> volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod));
- std::istringstream stream;
- try
- {
- std::string mesh_string((char*)data, data_size);
- stream.str(mesh_string);
- }
- catch (std::bad_alloc&)
- {
- // out of memory, we won't be able to process this mesh
- return MESH_OUT_OF_MEMORY;
- }
-
- if (volume->unpackVolumeFaces(stream, data_size))
+ if (volume->unpackVolumeFaces(data, data_size))
{
if (volume->getNumFaces() > 0)
{
LoadedMesh mesh(volume, mesh_params, lod);
{
LLMutexLock lock(mMutex);
- mLoadedQ.push(mesh);
+ mLoadedQ.push_back(mesh);
// LLPointer is not thread safe, since we added this pointer into
// threaded list, make sure counter gets decreased inside mutex lock
// and won't affect mLoadedQ processing
@@ -1953,10 +1969,7 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat
{
try
{
- std::string res_str((char*)data, data_size);
- std::istringstream stream(res_str);
-
- U32 uzip_result = LLUZipHelper::unzip_llsd(skin, stream, data_size);
+ U32 uzip_result = LLUZipHelper::unzip_llsd(skin, data, data_size);
if (uzip_result != LLUZipHelper::ZR_OK)
{
LL_WARNS(LOG_MESH) << "Mesh skin info parse error. Not a valid mesh asset! ID: " << mesh_id
@@ -1973,8 +1986,16 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat
}
{
- LLMeshSkinInfo info(skin);
- info.mMeshID = mesh_id;
+ LLMeshSkinInfo* info = nullptr;
+ try
+ {
+ info = new LLMeshSkinInfo(mesh_id, skin);
+ }
+ catch (const std::bad_alloc& ex)
+ {
+ LL_WARNS() << "Failed to allocate skin info with exception: " << ex.what() << LL_ENDL;
+ return false;
+ }
// LL_DEBUGS(LOG_MESH) << "info pelvis offset" << info.mPelvisOffset << LL_ENDL;
{
@@ -1994,10 +2015,7 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3
{
try
{
- std::string res_str((char*)data, data_size);
- std::istringstream stream(res_str);
-
- U32 uzip_result = LLUZipHelper::unzip_llsd(decomp, stream, data_size);
+ U32 uzip_result = LLUZipHelper::unzip_llsd(decomp, data, data_size);
if (uzip_result != LLUZipHelper::ZR_OK)
{
LL_WARNS(LOG_MESH) << "Mesh decomposition parse error. Not a valid mesh asset! ID: " << mesh_id
@@ -2006,7 +2024,7 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3
return false;
}
}
- catch (std::bad_alloc&)
+ catch (const std::bad_alloc&)
{
LL_WARNS(LOG_MESH) << "Out of memory for mesh ID " << mesh_id << " of size: " << data_size << LL_ENDL;
return false;
@@ -2043,32 +2061,8 @@ EMeshProcessingResult LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_
volume_params.setSculptID(mesh_id, LL_SCULPT_TYPE_MESH);
LLPointer<LLVolume> volume = new LLVolume(volume_params,0);
- std::istringstream stream;
- try
- {
- std::string mesh_string((char*)data, data_size);
- stream.str(mesh_string);
- }
- catch (std::bad_alloc&)
- {
- // out of memory, we won't be able to process this mesh
- delete d;
- return MESH_OUT_OF_MEMORY;
- }
-
- if (volume->unpackVolumeFaces(stream, data_size))
+ if (volume->unpackVolumeFaces(data, data_size))
{
- //load volume faces into decomposition buffer
- S32 vertex_count = 0;
- S32 index_count = 0;
-
- for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
- {
- const LLVolumeFace& face = volume->getVolumeFace(i);
- vertex_count += face.mNumVertices;
- index_count += face.mNumIndices;
- }
-
d->mPhysicsShapeMesh.clear();
std::vector<LLVector3>& pos = d->mPhysicsShapeMesh.mPositions;
@@ -2881,58 +2875,72 @@ void LLMeshRepoThread::notifyLoadedMeshes()
return;
}
- while (!mLoadedQ.empty())
+ if (!mLoadedQ.empty())
{
+ std::deque<LoadedMesh> loaded_queue;
+
mMutex->lock();
- if (mLoadedQ.empty())
+ if (!mLoadedQ.empty())
{
+ loaded_queue.swap(mLoadedQ);
mMutex->unlock();
- break;
- }
- LoadedMesh mesh = mLoadedQ.front(); // make sure nothing else owns volume pointer by this point
- mLoadedQ.pop();
- mMutex->unlock();
-
- update_metrics = true;
- if (mesh.mVolume->getNumVolumeFaces() > 0)
- {
- gMeshRepo.notifyMeshLoaded(mesh.mMeshParams, mesh.mVolume);
- }
- else
- {
- gMeshRepo.notifyMeshUnavailable(mesh.mMeshParams,
- LLVolumeLODGroup::getVolumeDetailFromScale(mesh.mVolume->getDetail()));
+
+ update_metrics = true;
+
+ // Process the elements free of the lock
+ for (const auto& mesh : loaded_queue)
+ {
+ if (mesh.mVolume->getNumVolumeFaces() > 0)
+ {
+ gMeshRepo.notifyMeshLoaded(mesh.mMeshParams, mesh.mVolume);
+ }
+ else
+ {
+ gMeshRepo.notifyMeshUnavailable(mesh.mMeshParams,
+ LLVolumeLODGroup::getVolumeDetailFromScale(mesh.mVolume->getDetail()));
+ }
+ }
}
}
- while (!mUnavailableQ.empty())
+ if (!mUnavailableQ.empty())
{
+ std::deque<LODRequest> unavil_queue;
+
mMutex->lock();
- if (mUnavailableQ.empty())
+ if (!mUnavailableQ.empty())
{
+ unavil_queue.swap(mUnavailableQ);
mMutex->unlock();
- break;
- }
-
- LODRequest req = mUnavailableQ.front();
- mUnavailableQ.pop();
- mMutex->unlock();
- update_metrics = true;
- gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD);
+ update_metrics = true;
+
+ // Process the elements free of the lock
+ for (const auto& req : unavil_queue)
+ {
+ gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD);
+ }
+ }
}
- if (! mSkinInfoQ.empty() || ! mDecompositionQ.empty())
+ if (!mSkinInfoQ.empty() || !mSkinUnavailableQ.empty() || ! mDecompositionQ.empty())
{
if (mMutex->trylock())
{
- std::list<LLMeshSkinInfo> skin_info_q;
+ std::deque<LLMeshSkinInfo*> skin_info_q;
+ std::deque<UUIDBasedRequest> skin_info_unavail_q;
std::list<LLModel::Decomposition*> decomp_q;
if (! mSkinInfoQ.empty())
{
skin_info_q.swap(mSkinInfoQ);
}
+
+ if (! mSkinUnavailableQ.empty())
+ {
+ skin_info_unavail_q.swap(mSkinUnavailableQ);
+ }
+
if (! mDecompositionQ.empty())
{
decomp_q.swap(mDecompositionQ);
@@ -2946,6 +2954,11 @@ void LLMeshRepoThread::notifyLoadedMeshes()
gMeshRepo.notifySkinInfoReceived(skin_info_q.front());
skin_info_q.pop_front();
}
+ while (! skin_info_unavail_q.empty())
+ {
+ gMeshRepo.notifySkinInfoUnavailable(skin_info_unavail_q.front().mId);
+ skin_info_unavail_q.pop_front();
+ }
while (! decomp_q.empty())
{
@@ -2970,7 +2983,7 @@ S32 LLMeshRepoThread::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo
if (iter != mMeshHeader.end())
{
- LLSD& header = iter->second;
+ LLSD& header = iter->second.second;
return LLMeshRepository::getActualMeshLOD(header, lod);
}
@@ -3173,7 +3186,7 @@ void LLMeshHeaderHandler::processFailure(LLCore::HttpStatus status)
LLMutexLock lock(gMeshRepo.mThread->mMutex);
for (int i(0); i < 4; ++i)
{
- gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, i));
+ gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, i));
}
}
@@ -3202,7 +3215,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b
LLMutexLock lock(gMeshRepo.mThread->mMutex);
for (int i(0); i < 4; ++i)
{
- gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, i));
+ gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, i));
}
}
else if (data && data_size > 0)
@@ -3215,8 +3228,8 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b
LLMeshRepoThread::mesh_header_map::iterator iter = gMeshRepo.mThread->mMeshHeader.find(mesh_id);
if (iter != gMeshRepo.mThread->mMeshHeader.end())
{
- header_bytes = (S32)gMeshRepo.mThread->mMeshHeaderSize[mesh_id];
- header = iter->second;
+ header_bytes = (S32)iter->second.first;
+ header = iter->second.second;
}
if (header_bytes > 0
@@ -3284,7 +3297,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b
LLMutexLock lock(gMeshRepo.mThread->mMutex);
for (int i(0); i < 4; ++i)
{
- gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, i));
+ gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, i));
}
}
}
@@ -3311,7 +3324,7 @@ void LLMeshLODHandler::processFailure(LLCore::HttpStatus status)
<< LL_ENDL;
LLMutexLock lock(gMeshRepo.mThread->mMutex);
- gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, mLOD));
+ gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, mLOD));
}
void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */,
@@ -3348,7 +3361,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body
<< " Not retrying."
<< LL_ENDL;
LLMutexLock lock(gMeshRepo.mThread->mMutex);
- gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, mLOD));
+ gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, mLOD));
}
}
else
@@ -3359,7 +3372,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body
<< " Data size: " << data_size
<< LL_ENDL;
LLMutexLock lock(gMeshRepo.mThread->mMutex);
- gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, mLOD));
+ gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, mLOD));
}
}
@@ -3377,9 +3390,8 @@ void LLMeshSkinInfoHandler::processFailure(LLCore::HttpStatus status)
<< ", Reason: " << status.toString()
<< " (" << status.toTerseString() << "). Not retrying."
<< LL_ENDL;
-
- // *TODO: Mark mesh unavailable on error. For now, simply leave
- // request unfulfilled rather than retry forever.
+ LLMutexLock lock(gMeshRepo.mThread->mMutex);
+ gMeshRepo.mThread->mSkinUnavailableQ.emplace_back(mMeshID);
}
void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */,
@@ -3410,7 +3422,8 @@ void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /*
LL_WARNS(LOG_MESH) << "Error during mesh skin info processing. ID: " << mMeshID
<< ", Unknown reason. Not retrying."
<< LL_ENDL;
- // *TODO: Mark mesh unavailable on error
+ LLMutexLock lock(gMeshRepo.mThread->mMutex);
+ gMeshRepo.mThread->mSkinUnavailableQ.emplace_back(mMeshID);
}
}
@@ -3519,7 +3532,7 @@ LLMeshRepository::LLMeshRepository()
mMeshThreadCount(0),
mThread(NULL)
{
-
+ mSkinInfoCullTimer.resetWithExpiry(10.f);
}
void LLMeshRepository::init()
@@ -3620,6 +3633,22 @@ S32 LLMeshRepository::update()
return size ;
}
+void LLMeshRepository::unregisterMesh(LLVOVolume* vobj)
+{
+ for (auto& lod : mLoadingMeshes)
+ {
+ for (auto& param : lod)
+ {
+ vector_replace_with_last(param.second, vobj);
+ }
+ }
+
+ for (auto& skin_pair : mLoadingSkins)
+ {
+ vector_replace_with_last(skin_pair.second, vobj);
+ }
+}
+
S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
@@ -3635,15 +3664,19 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para
{
LLMutexLock lock(mMeshMutex);
//add volume to list of loading meshes
- mesh_load_map::iterator iter = mLoadingMeshes[detail].find(mesh_params);
+ const auto& mesh_id = mesh_params.getSculptID();
+ mesh_load_map::iterator iter = mLoadingMeshes[detail].find(mesh_id);
if (iter != mLoadingMeshes[detail].end())
{ //request pending for this mesh, append volume id to list
- iter->second.insert(vobj->getID());
+ auto it = std::find(iter->second.begin(), iter->second.end(), vobj);
+ if (it == iter->second.end()) {
+ iter->second.push_back(vobj);
+ }
}
else
{
//first request for this mesh
- mLoadingMeshes[detail][mesh_params].insert(vobj->getID());
+ mLoadingMeshes[detail][mesh_id].push_back(vobj);
mPendingRequests.push_back(LLMeshRepoThread::LODRequest(mesh_params, detail));
LLMeshRepository::sLODPending++;
}
@@ -3800,6 +3833,28 @@ void LLMeshRepository::notifyLoadedMeshes()
//call completed callbacks on finished decompositions
mDecompThread->notifyCompleted();
+ if (mSkinInfoCullTimer.checkExpirationAndReset(10.f))
+ {
+ //// Clean up dead skin info
+ //U64Bytes skinbytes(0);
+ for (auto iter = mSkinMap.begin(), ender = mSkinMap.end(); iter != ender;)
+ {
+ auto copy_iter = iter++;
+
+ //skinbytes += U64Bytes(sizeof(LLMeshSkinInfo));
+ //skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(std::string));
+ //skinbytes += U64Bytes(copy_iter->second->mJointNums.size() * sizeof(S32));
+ //skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(LLMatrix4a));
+ //skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(LLMatrix4));
+
+ if (copy_iter->second->getNumRefs() == 1)
+ {
+ mSkinMap.erase(copy_iter);
+ }
+ }
+ //LL_INFOS() << "Skin info cache elements:" << mSkinMap.size() << " Memory: " << U64Kilobytes(skinbytes) << LL_ENDL;
+ }
+
// For major operations, attempt to get the required locks
// without blocking and punt if they're not available. The
// longest run of holdoffs is kept in sMaxLockHoldoffs just
@@ -3870,10 +3925,9 @@ void LLMeshRepository::notifyLoadedMeshes()
for (mesh_load_map::iterator iter = mLoadingMeshes[i].begin(); iter != mLoadingMeshes[i].end(); ++iter)
{
F32 max_score = 0.f;
- for (std::set<LLUUID>::iterator obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter)
+ for (auto obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter)
{
- LLViewerObject* object = gObjectList.findObject(*obj_iter);
-
+ LLVOVolume* object = *obj_iter;
if (object)
{
LLDrawable* drawable = object->mDrawable;
@@ -3885,7 +3939,7 @@ void LLMeshRepository::notifyLoadedMeshes()
}
}
- score_map[iter->first.getSculptID()] = max_score;
+ score_map[iter->first] = max_score;
}
}
@@ -3937,24 +3991,39 @@ void LLMeshRepository::notifyLoadedMeshes()
mThread->mSignal->signal();
}
-void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info)
+void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo* info)
{
- mSkinMap[info.mMeshID] = info;
+ mSkinMap[info->mMeshID] = info; // Cache into LLPointer
// Alternative: We can get skin size from header
- sCacheBytesSkins += info.sizeBytes();
+ sCacheBytesSkins += info->sizeBytes();
- skin_load_map::iterator iter = mLoadingSkins.find(info.mMeshID);
+ skin_load_map::iterator iter = mLoadingSkins.find(info->mMeshID);
if (iter != mLoadingSkins.end())
{
- for (std::set<LLUUID>::iterator obj_id = iter->second.begin(); obj_id != iter->second.end(); ++obj_id)
+ for (LLVOVolume* vobj : iter->second)
{
- LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*obj_id);
if (vobj)
{
- vobj->notifyMeshLoaded();
+ vobj->notifySkinInfoLoaded(info);
+ }
+ }
+ mLoadingSkins.erase(iter);
+ }
+}
+
+void LLMeshRepository::notifySkinInfoUnavailable(const LLUUID& mesh_id)
+{
+ skin_load_map::iterator iter = mLoadingSkins.find(mesh_id);
+ if (iter != mLoadingSkins.end())
+ {
+ for (LLVOVolume* vobj : iter->second)
+ {
+ if (vobj)
+ {
+ vobj->notifySkinInfoUnavailable();
}
}
- mLoadingSkins.erase(info.mMeshID);
+ mLoadingSkins.erase(iter);
}
}
@@ -3983,14 +4052,15 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol
S32 detail = LLVolumeLODGroup::getVolumeDetailFromScale(volume->getDetail());
//get list of objects waiting to be notified this mesh is loaded
- mesh_load_map::iterator obj_iter = mLoadingMeshes[detail].find(mesh_params);
+ const auto& mesh_id = mesh_params.getSculptID();
+ mesh_load_map::iterator obj_iter = mLoadingMeshes[detail].find(mesh_id);
if (volume && obj_iter != mLoadingMeshes[detail].end())
{
//make sure target volume is still valid
if (volume->getNumVolumeFaces() <= 0)
{
- LL_WARNS(LOG_MESH) << "Mesh loading returned empty volume. ID: " << mesh_params.getSculptID()
+ LL_WARNS(LOG_MESH) << "Mesh loading returned empty volume. ID: " << mesh_id
<< LL_ENDL;
}
@@ -4004,37 +4074,35 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol
}
else
{
- LL_WARNS(LOG_MESH) << "Couldn't find system volume for mesh " << mesh_params.getSculptID()
+ LL_WARNS(LOG_MESH) << "Couldn't find system volume for mesh " << mesh_id
<< LL_ENDL;
}
}
//notify waiting LLVOVolume instances that their requested mesh is available
- for (std::set<LLUUID>::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter)
+ for (LLVOVolume* vobj : obj_iter->second)
{
- LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter);
if (vobj)
{
vobj->notifyMeshLoaded();
}
}
- mLoadingMeshes[detail].erase(mesh_params);
+ mLoadingMeshes[detail].erase(obj_iter);
}
}
void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod)
{ //called from main thread
//get list of objects waiting to be notified this mesh is loaded
- mesh_load_map::iterator obj_iter = mLoadingMeshes[lod].find(mesh_params);
-
- F32 detail = LLVolumeLODGroup::getVolumeScaleFromDetail(lod);
-
+ const auto& mesh_id = mesh_params.getSculptID();
+ mesh_load_map::iterator obj_iter = mLoadingMeshes[lod].find(mesh_id);
if (obj_iter != mLoadingMeshes[lod].end())
{
- for (std::set<LLUUID>::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter)
+ F32 detail = LLVolumeLODGroup::getVolumeScaleFromDetail(lod);
+
+ for (LLVOVolume* vobj : obj_iter->second)
{
- LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter);
if (vobj)
{
LLVolume* obj_volume = vobj->getVolume();
@@ -4048,7 +4116,7 @@ void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params,
}
}
- mLoadingMeshes[lod].erase(mesh_params);
+ mLoadingMeshes[lod].erase(obj_iter);
}
}
@@ -4057,7 +4125,7 @@ S32 LLMeshRepository::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo
return mThread->getActualMeshLOD(mesh_params, lod);
}
-const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj)
+const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, LLVOVolume* requesting_obj)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
if (mesh_id.notNull())
@@ -4065,7 +4133,7 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const
skin_map::iterator iter = mSkinMap.find(mesh_id);
if (iter != mSkinMap.end())
{
- return &(iter->second);
+ return iter->second;
}
//no skin info known about given mesh, try to fetch it
@@ -4074,14 +4142,22 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const
LLMutexLock lock(mMeshMutex);
//add volume to list of loading meshes
skin_load_map::iterator iter = mLoadingSkins.find(mesh_id);
- if (iter == mLoadingSkins.end())
- { //no request pending for this skin info
+ if (iter != mLoadingSkins.end())
+ { //request pending for this mesh, append volume id to list
+ auto it = std::find(iter->second.begin(), iter->second.end(), requesting_obj);
+ if (it == iter->second.end()) {
+ iter->second.push_back(requesting_obj);
+ }
+ }
+ else
+ {
+ //first request for this mesh
+ mLoadingSkins[mesh_id].push_back(requesting_obj);
mPendingSkinRequests.push(mesh_id);
}
- mLoadingSkins[mesh_id].insert(requesting_obj->getID());
}
}
- return NULL;
+ return nullptr;
}
void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
@@ -4184,16 +4260,13 @@ bool LLMeshRepository::hasPhysicsShape(const LLUUID& mesh_id)
bool LLMeshRepoThread::hasPhysicsShapeInHeader(const LLUUID& mesh_id)
{
LLMutexLock lock(mHeaderMutex);
- if (mMeshHeaderSize[mesh_id] > 0)
+ mesh_header_map::iterator iter = mMeshHeader.find(mesh_id);
+ if (iter != mMeshHeader.end() && iter->second.first > 0)
{
- mesh_header_map::iterator iter = mMeshHeader.find(mesh_id);
- if (iter != mMeshHeader.end())
+ LLSD &mesh = iter->second.second;
+ if (mesh.has("physics_mesh") && mesh["physics_mesh"].has("size") && (mesh["physics_mesh"]["size"].asInteger() > 0))
{
- LLSD &mesh = iter->second;
- if (mesh.has("physics_mesh") && mesh["physics_mesh"].has("size") && (mesh["physics_mesh"]["size"].asInteger() > 0))
- {
- return true;
- }
+ return true;
}
}
@@ -4218,9 +4291,9 @@ S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod)
{
LLMutexLock lock(mThread->mHeaderMutex);
LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id);
- if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0)
+ if (iter != mThread->mMeshHeader.end() && iter->second.first > 0)
{
- LLSD& header = iter->second;
+ const LLSD& header = iter->second.second;
if (header.has("404"))
{
@@ -4324,9 +4397,9 @@ F32 LLMeshRepository::getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* by
{
LLMutexLock lock(mThread->mHeaderMutex);
LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id);
- if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0)
+ if (iter != mThread->mMeshHeader.end() && iter->second.first > 0)
{
- result = getStreamingCostLegacy(iter->second, radius, bytes, bytes_visible, lod, unscaled_value);
+ result = getStreamingCostLegacy(iter->second.second, radius, bytes, bytes_visible, lod, unscaled_value);
}
}
if (result > 0.f)
@@ -4639,9 +4712,9 @@ bool LLMeshRepository::getCostData(LLUUID mesh_id, LLMeshCostData& data)
{
LLMutexLock lock(mThread->mHeaderMutex);
LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id);
- if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0)
+ if (iter != mThread->mMeshHeader.end() && iter->second.first > 0)
{
- LLSD& header = iter->second;
+ LLSD& header = iter->second.second;
bool header_invalid = (header.has("404")
|| !header.has("lowest_lod")
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index f61da3e571..e3688ff243 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -210,10 +210,8 @@ public:
LLCondition* mSignal;
//map of known mesh headers
- typedef std::map<LLUUID, LLSD> mesh_header_map;
+ typedef boost::unordered_map<LLUUID, std::pair<U32, LLSD>> mesh_header_map; // pair is header_size and data
mesh_header_map mMeshHeader;
-
- std::map<LLUUID, U32> mMeshHeaderSize;
class HeaderRequest : public RequestStats
{
@@ -283,10 +281,13 @@ public:
};
//set of requested skin info
- std::set<UUIDBasedRequest> mSkinRequests;
+ std::deque<UUIDBasedRequest> mSkinRequests;
// list of completed skin info requests
- std::list<LLMeshSkinInfo> mSkinInfoQ;
+ std::deque<LLMeshSkinInfo*> mSkinInfoQ;
+
+ // list of skin info requests that have failed or are unavailaibe
+ std::deque<UUIDBasedRequest> mSkinUnavailableQ;
//set of requested decompositions
std::set<UUIDBasedRequest> mDecompositionRequests;
@@ -304,13 +305,13 @@ public:
std::queue<LODRequest> mLODReqQ;
//queue of unavailable LODs (either asset doesn't exist or asset doesn't have desired LOD)
- std::queue<LODRequest> mUnavailableQ;
+ std::deque<LODRequest> mUnavailableQ;
//queue of successfully loaded meshes
- std::queue<LoadedMesh> mLoadedQ;
+ std::deque<LoadedMesh> mLoadedQ;
//map of pending header requests and currently desired LODs
- typedef std::map<LLVolumeParams, std::vector<S32> > pending_lod_map;
+ typedef boost::unordered_map<LLUUID, std::vector<S32> > pending_lod_map;
pending_lod_map mPendingLOD;
// llcorehttp library interface objects.
@@ -354,7 +355,7 @@ public:
//send request for skin info, returns true if header info exists
// (should hold onto mesh_id and try again later if header info does not exist)
- bool fetchMeshSkinInfo(const LLUUID& mesh_id);
+ bool fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry = true);
//send request for decomposition, returns true if header info exists
// (should hold onto mesh_id and try again later if header info does not exist)
@@ -577,18 +578,20 @@ public:
void shutdown();
S32 update();
+ void unregisterMesh(LLVOVolume* volume);
//mesh management functions
S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0, S32 last_lod = -1);
void notifyLoadedMeshes();
void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume);
void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod);
- void notifySkinInfoReceived(LLMeshSkinInfo& info);
+ void notifySkinInfoReceived(LLMeshSkinInfo* info);
+ void notifySkinInfoUnavailable(const LLUUID& info);
void notifyDecompositionReceived(LLModel::Decomposition* info);
S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
static S32 getActualMeshLOD(LLSD& header, S32 lod);
- const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj = nullptr);
+ const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id, LLVOVolume* requesting_obj = nullptr);
LLModel::Decomposition* getDecomposition(const LLUUID& mesh_id);
void fetchPhysicsShape(const LLUUID& mesh_id);
bool hasPhysicsShape(const LLUUID& mesh_id);
@@ -613,10 +616,10 @@ public:
static void metricsProgress(unsigned int count);
static void metricsUpdate();
- typedef std::map<LLVolumeParams, std::set<LLUUID> > mesh_load_map;
+ typedef boost::unordered_map<LLUUID, std::vector<LLVOVolume*> > mesh_load_map;
mesh_load_map mLoadingMeshes[4];
- typedef std::unordered_map<LLUUID, LLMeshSkinInfo> skin_map;
+ typedef std::unordered_map<LLUUID, LLPointer<LLMeshSkinInfo>> skin_map;
skin_map mSkinMap;
typedef std::map<LLUUID, LLModel::Decomposition*> decomposition_map;
@@ -627,7 +630,7 @@ public:
std::vector<LLMeshRepoThread::LODRequest> mPendingRequests;
//list of mesh ids awaiting skin info
- typedef std::map<LLUUID, std::set<LLUUID> > skin_load_map;
+ typedef boost::unordered_map<LLUUID, std::vector<LLVOVolume*> > skin_load_map;
skin_load_map mLoadingSkins;
//list of mesh ids that need to send skin info fetch requests
@@ -652,6 +655,8 @@ public:
std::vector<LLMeshUploadThread*> mUploadWaitList;
LLPhysicsDecomp* mDecompThread;
+
+ LLFrameTimer mSkinInfoCullTimer;
class inventory_data
{
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 3401587450..45b42a32ea 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1905,32 +1905,16 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
if (sloppy_ratio < 0)
{
// Sloppy method didn't work, try with smaller decimation values
- S32 size_vertices = 0;
-
- for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
- {
- const LLVolumeFace &face = base->getVolumeFace(face_idx);
- size_vertices += face.mNumVertices;
- }
-
- // Complex models aren't supposed to get here, they are supposed
- // to work on a first try of sloppy due to having more viggle room.
- // If they didn't, something is likely wrong, no point locking the
- // thread in a long calculation that will fail.
- const U32 too_many_vertices = 27000;
- if (size_vertices > too_many_vertices)
- {
- LL_WARNS() << "Sloppy optimization method failed for a complex model " << target_model->getName() << LL_ENDL;
- }
- else
{
// Find a decimator that does work
F32 sloppy_decimation_step = sqrt((F32)decimation); // example: 27->15->9->5->3
F32 sloppy_decimator = indices_decimator / sloppy_decimation_step;
+ U64Microseconds end_time = LLTimer::getTotalTime() + U64Seconds(5);
while (sloppy_ratio < 0
&& sloppy_decimator > precise_ratio
- && sloppy_decimator > 1)// precise_ratio isn't supposed to be below 1, but check just in case
+ && sloppy_decimator > 1 // precise_ratio isn't supposed to be below 1, but check just in case
+ && end_time > LLTimer::getTotalTime())
{
sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY);
sloppy_decimator = sloppy_decimator / sloppy_decimation_step;
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index ea10aa75ae..0103bf628a 100644
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -1663,7 +1663,7 @@ void LLPanelEditWearable::initPreviousAlphaTextureEntry(LLAvatarAppearanceDefine
class LLMetricSystemHandler : public LLCommandHandler
{
public:
- LLMetricSystemHandler() : LLCommandHandler("metricsystem", UNTRUSTED_THROTTLE) { }
+ LLMetricSystemHandler() : LLCommandHandler("metricsystem", UNTRUSTED_CLICK_ONLY) { }
bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
{
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index 17b4528d97..445bed673b 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -1275,7 +1275,8 @@ LLPanelObjectInventory::LLPanelObjectInventory(const LLPanelObjectInventory::Par
mHaveInventory(FALSE),
mIsInventoryEmpty(TRUE),
mInventoryNeedsUpdate(FALSE),
- mInventoryViewModel(p.name)
+ mInventoryViewModel(p.name),
+ mShowRootFolder(p.show_root_folder)
{
// Setup context menu callbacks
mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelObjectInventory::doToSelected, this, _2));
@@ -1527,15 +1528,23 @@ void LLPanelObjectInventory::createFolderViews(LLInventoryObject* inventory_root
p.font_highlight_color = item_color;
LLFolderViewFolder* new_folder = LLUICtrlFactory::create<LLFolderViewFolder>(p);
- new_folder->addToFolder(mFolders);
- new_folder->toggleOpen();
+
+ if (mShowRootFolder)
+ {
+ new_folder->addToFolder(mFolders);
+ new_folder->toggleOpen();
+ }
if (!contents.empty())
{
- createViewsForCategory(&contents, inventory_root, new_folder);
+ createViewsForCategory(&contents, inventory_root, mShowRootFolder ? new_folder : mFolders);
}
- // Refresh for label to add item count
- new_folder->refresh();
+
+ if (mShowRootFolder)
+ {
+ // Refresh for label to add item count
+ new_folder->refresh();
+ }
}
}
diff --git a/indra/newview/llpanelobjectinventory.h b/indra/newview/llpanelobjectinventory.h
index 7b9ecfb8f3..0e450d8ce9 100644
--- a/indra/newview/llpanelobjectinventory.h
+++ b/indra/newview/llpanelobjectinventory.h
@@ -48,8 +48,14 @@ class LLViewerObject;
class LLPanelObjectInventory : public LLPanel, public LLVOInventoryListener
{
public:
- // dummy param block for template registration purposes
- struct Params : public LLPanel::Params {};
+ struct Params : public LLInitParam::Block<Params, LLPanel::Params>
+ {
+ Optional<bool> show_root_folder;
+
+ Params()
+ : show_root_folder("show_root_folder", true)
+ {}
+ };
LLPanelObjectInventory(const Params&);
virtual ~LLPanelObjectInventory();
@@ -110,6 +116,7 @@ private:
BOOL mIsInventoryEmpty; // 'Empty' label
BOOL mInventoryNeedsUpdate; // for idle, set on changed callback
LLFolderViewModelInventory mInventoryViewModel;
+ bool mShowRootFolder;
};
#endif // LL_LLPANELOBJECTINVENTORY_H
diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp
index f4eaa78f11..deebf0cd1b 100644
--- a/indra/newview/llpanelprofile.cpp
+++ b/indra/newview/llpanelprofile.cpp
@@ -484,6 +484,30 @@ public:
// requires trusted browser to trigger
LLAgentHandler() : LLCommandHandler("agent", UNTRUSTED_THROTTLE) { }
+ virtual bool canHandleUntrusted(
+ const LLSD& params,
+ const LLSD& query_map,
+ LLMediaCtrl* web,
+ const std::string& nav_type)
+ {
+ if (params.size() < 2)
+ {
+ return true; // don't block, will fail later
+ }
+
+ if (nav_type == NAV_TYPE_CLICKED)
+ {
+ return true;
+ }
+
+ const std::string verb = params[1].asString();
+ if (verb == "about" || verb == "inspect" || verb == "reportAbuse")
+ {
+ return true;
+ }
+ return false;
+ }
+
bool handle(const LLSD& params, const LLSD& query_map,
LLMediaCtrl* web)
{
@@ -1280,6 +1304,8 @@ void LLPanelProfileSecondLife::fillRightsData()
void LLPanelProfileSecondLife::fillAgeData(const LLDate &born_on)
{
+ // Date from server comes already converted to stl timezone,
+ // so display it as an UTC + 0
std::string name_and_date = getString("date_format");
LLSD args_name;
args_name["datetime"] = (S32)born_on.secondsSinceEpoch();
diff --git a/indra/newview/llpanelprofileclassifieds.cpp b/indra/newview/llpanelprofileclassifieds.cpp
index a3913ddc49..1ff12b4f37 100644
--- a/indra/newview/llpanelprofileclassifieds.cpp
+++ b/indra/newview/llpanelprofileclassifieds.cpp
@@ -81,6 +81,30 @@ public:
std::set<LLUUID> mClassifiedIds;
std::string mRequestVerb;
+
+ virtual bool canHandleUntrusted(
+ const LLSD& params,
+ const LLSD& query_map,
+ LLMediaCtrl* web,
+ const std::string& nav_type)
+ {
+ if (params.size() < 1)
+ {
+ return true; // don't block, will fail later
+ }
+
+ if (nav_type == NAV_TYPE_CLICKED)
+ {
+ return true;
+ }
+
+ const std::string verb = params[0].asString();
+ if (verb == "create")
+ {
+ return false;
+ }
+ return true;
+ }
bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
{
diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp
index 774119f169..45d0252e4f 100644
--- a/indra/newview/llpanelprofilepicks.cpp
+++ b/indra/newview/llpanelprofilepicks.cpp
@@ -63,6 +63,30 @@ public:
// requires trusted browser to trigger
LLPickHandler() : LLCommandHandler("pick", UNTRUSTED_THROTTLE) { }
+ virtual bool canHandleUntrusted(
+ const LLSD& params,
+ const LLSD& query_map,
+ LLMediaCtrl* web,
+ const std::string& nav_type)
+ {
+ if (params.size() < 1)
+ {
+ return true; // don't block, will fail later
+ }
+
+ if (nav_type == NAV_TYPE_CLICKED)
+ {
+ return true;
+ }
+
+ const std::string verb = params[0].asString();
+ if (verb == "create")
+ {
+ return false;
+ }
+ return true;
+ }
+
bool handle(const LLSD& params, const LLSD& query_map,
LLMediaCtrl* web)
{
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 06a6c5e373..b4382a4646 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -173,11 +173,103 @@
class LLFloaterOpenHandler : public LLCommandHandler
{
public:
- // requires trusted browser to trigger
+ // requires trusted browser to trigger or an explicit click
LLFloaterOpenHandler() : LLCommandHandler("openfloater", UNTRUSTED_THROTTLE) { }
- bool handle(const LLSD& params, const LLSD& query_map,
- LLMediaCtrl* web)
+ bool canHandleUntrusted(
+ const LLSD& params,
+ const LLSD& query_map,
+ LLMediaCtrl* web,
+ const std::string& nav_type) override
+ {
+ if (params.size() != 1)
+ {
+ return true; // will fail silently
+ }
+
+ std::string fl_name = params[0].asString();
+
+ if (nav_type == NAV_TYPE_CLICKED)
+ {
+ const std::list<std::string> blacklist_clicked = {
+ "camera_presets",
+ "delete_pref_preset",
+ "forget_username",
+ "god_tools",
+ "group_picker",
+ "hud",
+ "incoming_call",
+ "linkreplace",
+ "message_critical", // Modal!!! Login specific.
+ "message_tos", // Modal!!! Login specific.
+ "save_pref_preset",
+ "save_camera_preset",
+ "region_restarting",
+ "outfit_snapshot",
+ "upload_anim_bvh",
+ "upload_anim_anim",
+ "upload_image",
+ "upload_model",
+ "upload_script",
+ "upload_sound"
+ };
+ return std::find(blacklist_clicked.begin(), blacklist_clicked.end(), fl_name) == blacklist_clicked.end();
+ }
+ else
+ {
+ const std::list<std::string> blacklist_untrusted = {
+ "360capture",
+ "block_timers",
+ "add_payment_method",
+ "appearance",
+ "associate_listing",
+ "avatar_picker",
+ "camera",
+ "camera_presets",
+ "classified",
+ "add_landmark",
+ "delete_pref_preset",
+ "env_fixed_environmentent_water",
+ "env_fixed_environmentent_sky",
+ "env_edit_extdaycycle",
+ "font_test",
+ "forget_username",
+ "god_tools",
+ "group_picker",
+ "hud",
+ "incoming_call",
+ "linkreplace",
+ "mem_leaking",
+ "marketplace_validation",
+ "message_critical", // Modal!!! Login specific. If this is in use elsewhere, better to create a non modal variant
+ "message_tos", // Modal!!! Login specific.
+ "mute_object_by_name",
+ "publish_classified",
+ "save_pref_preset",
+ "save_camera_preset",
+ "region_restarting",
+ "script_debug",
+ "script_debug_output",
+ "sell_land",
+ "outfit_snapshot",
+ "upload_anim_bvh",
+ "upload_anim_anim",
+ "upload_image",
+ "upload_model",
+ "upload_script",
+ "upload_sound"
+ };
+ return std::find(blacklist_untrusted.begin(), blacklist_untrusted.end(), fl_name) == blacklist_untrusted.end();
+ }
+
+
+ return true;
+ }
+
+ bool handle(
+ const LLSD& params,
+ const LLSD& query_map,
+ LLMediaCtrl* web) override
{
if (params.size() != 1)
{
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index 43b9cd90bd..6bab2c2100 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -1614,12 +1614,22 @@ BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask,
clicktype = CLICK_DOUBLELEFT;
}
+ // If the first LMB click is handled by the menu, skip the following double click
+ static bool skip_double_click = false;
+ if (clicktype == CLICK_LEFT && down )
+ {
+ skip_double_click = handled;
+ }
if (double_click_sp && down)
{
// Consume click.
// Due to handling, double click that is not handled will be immediately followed by LMB click
}
+ else if (clicktype == CLICK_DOUBLELEFT && skip_double_click)
+ {
+ handled = true;
+ }
// If UI handled 'down', it should handle 'up' as well
// If we handle 'down' not by UI, then we should handle 'up'/'level' regardless of UI
else if (handled)
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 55ac817479..50252556de 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -232,7 +232,7 @@ class LLInventoryHandler : public LLCommandHandler
{
public:
// requires trusted browser to trigger
- LLInventoryHandler() : LLCommandHandler("inventory", UNTRUSTED_THROTTLE) { }
+ LLInventoryHandler() : LLCommandHandler("inventory", UNTRUSTED_CLICK_ONLY) { }
bool handle(const LLSD& params, const LLSD& query_map,
LLMediaCtrl* web)
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index f76031953d..6c06360636 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -5613,6 +5613,7 @@ class LLToolsSelectNextPartFace : public view_listener_t
}
}
LLSelectMgr::getInstance()->selectObjectOnly(to_select, new_te);
+ LLSelectMgr::getInstance()->addAsIndividual(to_select, new_te, false);
}
else
{
diff --git a/indra/newview/llviewerpartsource.cpp b/indra/newview/llviewerpartsource.cpp
index f042040e98..1751ee1ebb 100644
--- a/indra/newview/llviewerpartsource.cpp
+++ b/indra/newview/llviewerpartsource.cpp
@@ -793,7 +793,7 @@ void LLViewerPartSourceBeam::update(const F32 dt)
}
LLViewerPart* part = new LLViewerPart();
- part->init(this, mImagep, NULL);
+ part->init(this, mImagep, updatePart);
part->mFlags = LLPartData::LL_PART_INTERP_COLOR_MASK |
LLPartData::LL_PART_INTERP_SCALE_MASK |
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index f4a938e57d..8cfa83ba46 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -228,6 +228,9 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
mColorChanged = FALSE;
mSpotLightPriority = 0.f;
+ mSkinInfoFailed = false;
+ mSkinInfo = NULL;
+
mMediaImplList.resize(getNumTEs());
mLastFetchedMediaVersion = -1;
mServerDrawableUpdateCount = 0;
@@ -244,6 +247,8 @@ LLVOVolume::~LLVOVolume()
delete mVolumeImpl;
mVolumeImpl = NULL;
+ gMeshRepo.unregisterMesh(this);
+
if(!mMediaImplList.empty())
{
for(U32 i = 0 ; i < mMediaImplList.size() ; i++)
@@ -1095,6 +1100,12 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bo
// if it's a mesh
if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
{
+ if (mSkinInfo && mSkinInfo->mMeshID != volume_params.getSculptID())
+ {
+ mSkinInfo = NULL;
+ mSkinInfoFailed = false;
+ }
+
if (!getVolume()->isMeshAssetLoaded())
{
//load request not yet issued, request pipeline load this mesh
@@ -1106,6 +1117,14 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bo
}
}
+ if (!mSkinInfo && !mSkinInfoFailed)
+ {
+ const LLMeshSkinInfo* skin_info = gMeshRepo.getSkinInfo(volume_params.getSculptID(), this);
+ if (skin_info)
+ {
+ notifySkinInfoLoaded(skin_info);
+ }
+ }
}
else // otherwise is sculptie
{
@@ -1158,6 +1177,9 @@ void LLVOVolume::updateSculptTexture()
{
mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
}
+
+ mSkinInfoFailed = false;
+ mSkinInfo = NULL;
}
else
{
@@ -1212,6 +1234,20 @@ void LLVOVolume::notifyMeshLoaded()
updateVisualComplexity();
}
+void LLVOVolume::notifySkinInfoLoaded(const LLMeshSkinInfo* skin)
+{
+ mSkinInfoFailed = false;
+ mSkinInfo = skin;
+
+ notifyMeshLoaded();
+}
+
+void LLVOVolume::notifySkinInfoUnavailable()
+{
+ mSkinInfoFailed = true;
+ mSkinInfo = nullptr;
+}
+
// sculpt replaces generate() for sculpted surfaces
void LLVOVolume::sculpt()
{
@@ -3645,7 +3681,7 @@ const LLMeshSkinInfo* LLVOVolume::getSkinInfo() const
{
if (getVolume())
{
- return gMeshRepo.getSkinInfo(getMeshID(), this);
+ return mSkinInfo;
}
else
{
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 4136c13315..12681e2bd9 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -350,6 +350,8 @@ public:
void updateVisualComplexity();
void notifyMeshLoaded();
+ void notifySkinInfoLoaded(const LLMeshSkinInfo* skin);
+ void notifySkinInfoUnavailable();
// Returns 'true' iff the media data for this object is in flight
bool isMediaDataBeingFetched() const;
@@ -433,6 +435,8 @@ private:
LLPointer<LLRiggedVolume> mRiggedVolume;
+ bool mSkinInfoFailed;
+ LLConstPointer<LLMeshSkinInfo> mSkinInfo;
// statics
public:
static F32 sLODSlopDistanceFactor;// Changing this to zero, effectively disables the LOD transition slop
diff --git a/indra/newview/skins/default/xui/en/floater_object_weights.xml b/indra/newview/skins/default/xui/en/floater_object_weights.xml
index eb283a1043..889efa061c 100644
--- a/indra/newview/skins/default/xui/en/floater_object_weights.xml
+++ b/indra/newview/skins/default/xui/en/floater_object_weights.xml
@@ -2,7 +2,7 @@
<floater
can_close="true"
can_tear_off="false"
- height="315"
+ height="289"
help_topic="object_weights"
layout="topleft"
name="object_weights"
@@ -320,23 +320,4 @@
top_delta="0"
value="Total capacity"
width="130" />
- <view_border
- bevel_style="none"
- follows="top|left"
- height="0"
- layout="topleft"
- left="10"
- name="land_impacts_text_border"
- top_pad="5"
- width="180"/>
-
- <text
- follows="left|top"
- height="16"
- layout="topleft"
- left="10"
- name="help_SLURL"
- top_pad="10"
- value="[secondlife:///app/help/object_weights What is all this?...]"
- width="180" />
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_openobject.xml b/indra/newview/skins/default/xui/en/floater_openobject.xml
index 912db80bcc..ec03d7d32c 100644
--- a/indra/newview/skins/default/xui/en/floater_openobject.xml
+++ b/indra/newview/skins/default/xui/en/floater_openobject.xml
@@ -3,7 +3,7 @@
legacy_header_height="18"
can_resize="true"
default_tab_group="1"
- height="370"
+ height="350"
layout="topleft"
min_height="190"
min_width="285"
@@ -31,62 +31,18 @@
background_visible="false"
draw_border="false"
follows="all"
- height="240"
+ height="265"
layout="topleft"
+ show_root_folder="false"
left="10"
name="object_contents"
top_pad="0"
width="284" />
- <view_border
- bevel_style="none"
- follows="bottom|left"
- height="50"
- highlight_light_color="0.6 0.6 0.6"
- layout="topleft"
- left="10"
- name="border"
- top_pad="5"
- width="270"/>
- <text
- follows="bottom|left"
- height="15"
- layout="topleft"
- left="15"
- name="border_note"
- text_color="White"
- top_delta="5">
- Copy to inventory and wear
- </text>
- <button
- follows="bottom|left"
- height="23"
- label="Add to outfit"
- label_selected="Add to outfit"
- layout="topleft"
- left="15"
- name="copy_and_wear_button"
- top_pad="3"
- width="135">
- <button.commit_callback
- function="OpenObject.MoveAndWear" />
- </button>
- <button
- follows="bottom|left"
- height="23"
- label="Replace outfit"
- label_selected="Replace outfit"
- layout="topleft"
- left_pad="5"
- name="copy_and_replace_button"
- width="120">
- <button.commit_callback
- function="OpenObject.ReplaceOutfit" />
- </button>
<button
follows="bottom|left"
height="23"
label="Only copy to inventory"
- label_selected="Only copy to inventory"
+ label_selected="Copy to inventory"
layout="topleft"
left="15"
name="copy_to_inventory_button"
diff --git a/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml b/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml
index 41384a77b8..59117c0178 100644
--- a/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml
+++ b/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml
@@ -82,17 +82,20 @@
width="62">
Name
</text>
- <line_editor
- border_style="line"
- border_thickness="1"
- follows="left|top"
- height="20"
- layout="topleft"
- left_pad="0"
- top_pad="-18"
- max_length_chars="255"
- name="filter_by_name"
- width="161" />
+
+ <search_editor
+ follows="left|top"
+ search_button_visible="false"
+ height="20"
+ text_readonly_color="DkGray"
+ label="Objects by Name"
+ layout="topleft"
+ left_pad="0"
+ top_pad="-18"
+ name="filter_by_name"
+ select_on_focus="true"
+ width="161">
+ </search_editor>
<text
name="linksets_desc_label"
height="13"
@@ -108,17 +111,19 @@
width="88">
Description
</text>
- <line_editor
- border_style="line"
- border_thickness="1"
- follows="left|top"
- height="20"
- layout="topleft"
- left_pad="0"
- top_pad="-17"
- max_length_chars="255"
- name="filter_by_description"
- width="162" />
+ <search_editor
+ follows="left|top"
+ search_button_visible="false"
+ height="20"
+ text_readonly_color="DkGray"
+ label="Objects by Description"
+ layout="topleft"
+ left_pad="0"
+ top_pad="-17"
+ name="filter_by_description"
+ select_on_focus="true"
+ width="162">
+ </search_editor>
<combo_box
height="20"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
index 551b477876..777b37d666 100644
--- a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
@@ -9,9 +9,13 @@
follows="all"
layout="topleft"
>
+ <!--
+ Date from server comes already converted to stl timezone,
+ so display it as an UTC+0
+ -->
<string
name="date_format"
- value="SL birthdate: [mth,datetime,slt] [day,datetime,slt], [year,datetime,slt]" />
+ value="SL birthdate: [mth,datetime,utc] [day,datetime,utc], [year,datetime,utc]" />
<string
name="age_format"
value="[AGE]" />
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 6f95e282ca..b88a01f035 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -3983,7 +3983,7 @@ Please check http://status.secondlifegrid.net to see if there is a known problem
<string name="Premium_PlusMembership">Premium Plus</string>
<string name="InternalMembership">Internal</string> <!-- No need to translate -->
- <string name="MembershipUpgradeText">Upgrade to Premium</string>
+ <string name="MembershipUpgradeText">Change membership plan...</string>
<string name="MembershipPremiumText">My Premium membership</string>
<!-- Question strings for delete items notifications -->
diff --git a/indra/newview/skins/default/xui/en/widgets/filter_editor.xml b/indra/newview/skins/default/xui/en/widgets/filter_editor.xml
index 1c4822b8d5..9c80deeafc 100644
--- a/indra/newview/skins/default/xui/en/widgets/filter_editor.xml
+++ b/indra/newview/skins/default/xui/en/widgets/filter_editor.xml
@@ -6,7 +6,7 @@
text_pad_left="7"
select_on_focus="true"
text_tentative_color="TextFgTentativeColor"
- highlight_text_field="false"
+ highlight_text_field="true"
background_image="TextField_Search_Off"
background_image_disabled="TextField_Search_Disabled"
background_image_focused="TextField_Search_Active"
diff --git a/indra/newview/skins/default/xui/en/widgets/search_editor.xml b/indra/newview/skins/default/xui/en/widgets/search_editor.xml
index dc5a07bf4f..18d99f1ed1 100644
--- a/indra/newview/skins/default/xui/en/widgets/search_editor.xml
+++ b/indra/newview/skins/default/xui/en/widgets/search_editor.xml
@@ -7,7 +7,7 @@
text_pad_right="6"
select_on_focus="true"
text_tentative_color="TextFgTentativeColor"
- highlight_text_field="false"
+ highlight_text_field="true"
background_image="TextField_Search_Off"
background_image_disabled="TextField_Search_Disabled"
background_image_focused="TextField_Search_Active"
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index de5ac5ed3d..a1d2d12779 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -518,7 +518,7 @@ class WindowsManifest(ViewerManifest):
self.path("alut.dll")
# For textures
- self.path("openjpeg.dll")
+ self.path("openjp2.dll")
# Uriparser
self.path("uriparser.dll")
@@ -1498,7 +1498,7 @@ class Linux_i686_Manifest(LinuxManifest):
self.path("libdirectfb-1.*.so.*")
self.path("libfusion-1.*.so.*")
self.path("libdirect-1.*.so.*")
- self.path("libopenjpeg.so*")
+ self.path("libopenjp2.so*")
self.path("libdirectfb-1.4.so.5")
self.path("libfusion-1.4.so.5")
self.path("libdirect-1.4.so.5*")