Ansariel 2025-04-15 17:54:29 +02:00
commit 5197abfd1f
237 changed files with 5041 additions and 2005 deletions

View File

@ -42,8 +42,8 @@ jobs:
needs: setup
strategy:
matrix:
runner: [windows-large, macos-15-xlarge]
configuration: ${{ fromJSON(needs.setup.outputs.configurations) }}
runner: ${{ fromJson((github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/Second_Life')) && '["windows-large","macos-15-xlarge"]' || '["windows-latest","macos-15"]') }}
configuration: ${{ fromJson(needs.setup.outputs.configurations) }}
runs-on: ${{ matrix.runner }}
outputs:
viewer_channel: ${{ steps.build.outputs.viewer_channel }}

View File

@ -1330,9 +1330,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>47af788cc447a64e311e3a65b74a9cf9</string>
<string>478f6e900ac5b3319dd2aa89fbdddd0b</string>
<key>url</key>
<string>file:///opt/firestorm/kdu-8.4.1-darwin64-233220201.tar.bz2</string>
<string>file:///opt/firestorm/kdu-8.5-darwin64-250921045.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -1342,9 +1342,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>b464a547d5bedcc72e9173d860f40656</string>
<string>cceee36d06464806e9ecf75f24dd6530</string>
<key>url</key>
<string>file:///opt/firestorm/kdu-8.4.1-linux64-233220158.tar.bz2</string>
<string>file:///opt/firestorm/kdu-8.5-linux64-250921045.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
@ -1354,9 +1354,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>526965ad83ad9ee355b6596f489d82d9</string>
<string>f574412faea823a0e7dcc4a90dced185</string>
<key>url</key>
<string>file:///c:/cygwin/opt/firestorm/kdu-8.4.1-windows-233220159.tar.bz2</string>
<string>file:///c:/cygwin/opt/firestorm/kdu-8.5-windows64-250921045.tar.bz2</string>
</map>
<key>name</key>
<string>windows64</string>
@ -2326,11 +2326,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>191e4ef07a35f7147708415465191ce7622e3012</string>
<string>a3cc405d48a48a474d05b3de3d28da2005d80037</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openal-soft/releases/download/v1.23.1-8668009/openal-1.23.1-darwin64-8979520327.tar.zst</string>
<string>https://github.com/secondlife/3p-openal-soft/releases/download/v1.24.2-r1/openal-1.24.2-r1-darwin64-13245988487.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -2340,11 +2340,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>3bd8c9028ef42bdb43c7422e7d324e213fdb081e</string>
<string>a2b63f0f85ca156c59ee1d34ef96c8e50b89153c</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openal-soft/releases/download/v1.23.1-8668009/openal-1.23.1-linux64-8979520327.tar.zst</string>
<string>https://github.com/secondlife/3p-openal-soft/releases/download/v1.24.2-r1/openal-1.24.2-r1-linux64-13245988487.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@ -2354,11 +2354,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>4b849609abec790e89be5fad8ddee3717ee301c4</string>
<string>8ad24fba1191c9cb0d2ab36e64b04b4648a99f43</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openal-soft/releases/download/v1.23.1-8668009/openal-1.23.1-windows64-8979520327.tar.zst</string>
<string>https://github.com/secondlife/3p-openal-soft/releases/download/v1.24.2-r1/openal-1.24.2-r1-windows64-13245988487.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@ -3515,14 +3515,15 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>build</key>
<map>
<key>command</key>
<string>xcodebuild</string>
<string>cmake</string>
<key>options</key>
<array>
<string>-configuration</string>
<string>--build</string>
<string>.</string>
<string>--config</string>
<string>RelWithDebInfo</string>
<string>-project</string>
<string>SecondLife.xcodeproj</string>
<string>-parallelizeTargets</string>
<string>--parallel</string>
<string>$AUTOBUILD_CPU_COUNT</string>
</array>
</map>
<!-- FS:Ansariel: This will cause packages being installed twice
@ -3545,14 +3546,15 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>build</key>
<map>
<key>command</key>
<string>xcodebuild</string>
<string>cmake</string>
<key>options</key>
<array>
<string>-configuration</string>
<string>--build</string>
<string>.</string>
<string>--config</string>
<string>RelWithDebInfo</string>
<string>-project</string>
<string>SecondLife.xcodeproj</string>
<string>-parallelizeTargets</string>
<string>--parallel</string>
<string>$AUTOBUILD_CPU_COUNT</string>
</array>
</map>
<key>name</key>
@ -3579,14 +3581,15 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>build</key>
<map>
<key>command</key>
<string>xcodebuild</string>
<string>cmake</string>
<key>options</key>
<array>
<string>-configuration</string>
<string>--build</string>
<string>.</string>
<string>--config</string>
<string>Release</string>
<string>-project</string>
<string>SecondLife.xcodeproj</string>
<string>-parallelizeTargets</string>
<string>--parallel</string>
<string>$AUTOBUILD_CPU_COUNT</string>
</array>
</map>
<key>name</key>
@ -3605,14 +3608,15 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>build</key>
<map>
<key>command</key>
<string>xcodebuild</string>
<string>cmake</string>
<key>options</key>
<array>
<string>-configuration</string>
<string>--build</string>
<string>.</string>
<string>--config</string>
<string>Release</string>
<string>-project</string>
<string>SecondLife.xcodeproj</string>
<string>-parallelizeTargets</string>
<string>--parallel</string>
<string>$AUTOBUILD_CPU_COUNT</string>
</array>
</map>
<key>name</key>

View File

@ -41,7 +41,7 @@ add_compile_definitions(BOOST_BIND_GLOBAL_PLACEHOLDERS)
# Force enable SSE2 instructions in GLM per the manual
# https://github.com/g-truc/glm/blob/master/manual.md#section2_10
add_compile_definitions(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES=1 GLM_FORCE_SSE2=1)
add_compile_definitions(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES=1 GLM_FORCE_SSE2=1 GLM_ENABLE_EXPERIMENTAL=1)
# Configure crash reporting
set(RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in release builds")
@ -55,6 +55,11 @@ if(NON_RELEASE_CRASH_REPORTING)
add_compile_definitions( LL_SEND_CRASH_REPORTS=1)
endif()
set(USE_LTO OFF CACHE BOOL "Enable Link Time Optimization")
if(USE_LTO)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
endif()
# Don't bother with a MinSizeRel or Debug builds.
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release" CACHE STRING "Supported build types." FORCE)
@ -127,7 +132,7 @@ if (WINDOWS)
#ND: When using something like buildcache (https://github.com/mbitsnbites/buildcache)
# to make those wrappers work /Zi must be changed to /Z7, as /Zi due to it's nature is not compatible with caching
if( ${CMAKE_CXX_COMPILER_LAUNCHER} MATCHES ".*cache.*")
if(${CMAKE_CXX_COMPILER_LAUNCHER} MATCHES ".*cache.*")
add_compile_options( /Z7 )
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")

View File

@ -815,7 +815,6 @@ void LLAvatarAppearance::buildCharacter()
bool status = loadAvatar();
stop_glerror();
// gPrintMessagesThisFrame = true;
LL_DEBUGS() << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << LL_ENDL;
if (!status)

View File

@ -981,7 +981,7 @@ void LLPolyMesh::initializeForMorph()
LLVector4a::memcpyNonAliased16((F32*) mScaledNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
LLVector4a::memcpyNonAliased16((F32*) mScaledBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) mSharedData->mTexCoords, sizeof(LLVector2) * (mSharedData->mNumVertices + mSharedData->mNumVertices%2));
memcpy((F32*) mTexCoords, (F32*) mSharedData->mTexCoords, sizeof(LLVector2) * (mSharedData->mNumVertices)); // allocated in LLPolyMeshSharedData::allocateVertexData
for (S32 i = 0; i < mSharedData->mNumVertices; ++i)
{

View File

@ -652,9 +652,10 @@ void LLWearable::addVisualParam(LLVisualParam *param)
//void LLWearable::setVisualParamWeight(S32 param_index, F32 value)
void LLWearable::setVisualParamWeight(S32 param_index, F32 value, bool upload_bake)
{
if( is_in_map(mVisualParamIndexMap, param_index ) )
visual_param_index_map_t::iterator found = mVisualParamIndexMap.find(param_index);
if(found != mVisualParamIndexMap.end())
{
LLVisualParam *wearable_param = mVisualParamIndexMap[param_index];
LLVisualParam *wearable_param = found->second;
// <FS:Ansariel> [Legacy Bake]
//wearable_param->setWeight(value);
wearable_param->setWeight(value, upload_bake);
@ -667,10 +668,10 @@ void LLWearable::setVisualParamWeight(S32 param_index, F32 value, bool upload_ba
F32 LLWearable::getVisualParamWeight(S32 param_index) const
{
if( is_in_map(mVisualParamIndexMap, param_index ) )
visual_param_index_map_t::const_iterator found = mVisualParamIndexMap.find(param_index);
if(found != mVisualParamIndexMap.end())
{
const LLVisualParam *wearable_param = mVisualParamIndexMap.find(param_index)->second;
return wearable_param->getWeight();
return found->second->getWeight();
}
else
{
@ -743,7 +744,7 @@ void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp)
if (!avatarp) return;
// Pull params
for( LLVisualParam* param = avatarp->getFirstVisualParam(); param; param = avatarp->getNextVisualParam() )
for( const LLVisualParam* param = avatarp->getFirstVisualParam(); param; param = avatarp->getNextVisualParam() )
{
// cross-wearable parameters are not authoritative, as they are driven by a different wearable. So don't copy the values to the
// avatar object if cross wearable. Cross wearable params get their values from the avatar, they shouldn't write the other way.

View File

@ -190,7 +190,7 @@ LLAudioChannelOpenAL::~LLAudioChannelOpenAL()
void LLAudioChannelOpenAL::cleanup()
{
alSourceStop(mALSource);
alSourcei(mALSource, AL_BUFFER, 0); // <ND/> need to unset buffer too, or alDeleteBuffers will fail.
alSourcei(mALSource, AL_BUFFER, AL_NONE);
mCurrentBufferp = NULL;
}

View File

@ -282,7 +282,7 @@ public:
LLRunner& getRunner() { return mRunner; }
#ifdef LL_WINDOWS
virtual void reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { }
virtual bool reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { return false; }
#endif
public:

View File

@ -310,25 +310,54 @@ namespace
static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific
U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop)
U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS* exception_infop)
{
if (code == STATUS_MSC_EXCEPTION)
if (LLApp::instance()->reportCrashToBugsplat((void*)exception_infop))
{
// Handled
return EXCEPTION_CONTINUE_SEARCH;
}
else if (code == STATUS_MSC_EXCEPTION)
{
// C++ exception, go on
return EXCEPTION_CONTINUE_SEARCH;
}
else
{
// handle it
// handle it, convert to std::exception
return EXCEPTION_EXECUTE_HANDLER;
}
return EXCEPTION_CONTINUE_SEARCH;
}
void cpphandle(const LLCoros::callable_t& callable, const std::string& name)
{
// SE and C++ can not coexists, thus two handlers
try
{
callable();
}
catch (const LLCoros::Stop& exc)
{
LL_INFOS("LLCoros") << "coroutine " << name << " terminating because "
<< exc.what() << LL_ENDL;
}
catch (const LLContinueError&)
{
// Any uncaught exception derived from LLContinueError will be caught
// here and logged. This coroutine will terminate but the rest of the
// viewer will carry on.
LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name));
}
}
void sehandle(const LLCoros::callable_t& callable)
void sehandle(const LLCoros::callable_t& callable, const std::string& name)
{
__try
{
callable();
// handle stop and continue exceptions first
cpphandle(callable, name);
}
__except (exception_filter(GetExceptionCode(), GetExceptionInformation()))
{
@ -340,16 +369,7 @@ void sehandle(const LLCoros::callable_t& callable)
throw std::exception(integer_string);
}
}
#else // ! LL_WINDOWS
inline void sehandle(const LLCoros::callable_t& callable)
{
callable();
}
#endif // ! LL_WINDOWS
#endif // LL_WINDOWS
} // anonymous namespace
// Top-level wrapper around caller's coroutine callable.
@ -362,10 +382,14 @@ void LLCoros::toplevel(std::string name, callable_t callable)
// set it as current
mCurrent.reset(&corodata);
#ifdef LL_WINDOWS
// can not use __try directly, toplevel requires unwinding, thus use of a wrapper
sehandle(callable, name);
#else // LL_WINDOWS
// run the code the caller actually wants in the coroutine
try
{
sehandle(callable);
callable();
}
catch (const Stop& exc)
{
@ -387,6 +411,7 @@ void LLCoros::toplevel(std::string name, callable_t callable)
<< name << LL_ENDL;
LLCoros::instance().saveException(name, std::current_exception());
}
#endif // else LL_WINDOWS
}
//static

View File

@ -77,6 +77,15 @@ std::string LLDate::asRFC1123() const
return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT"));
}
std::string LLDate::toLocalDateString (std::string fmt) const
{
LL_PROFILE_ZONE_SCOPED;
time_t locSeconds = (time_t) mSecondsSinceEpoch;
struct tm * lt = localtime (&locSeconds);
return toHTTPDateString(lt, fmt);
}
std::string LLDate::toHTTPDateString (std::string fmt) const
{
LL_PROFILE_ZONE_SCOPED;

View File

@ -79,6 +79,7 @@ public:
std::string asRFC1123() const;
void toStream(std::ostream&) const;
bool split(S32 *year, S32 *month = NULL, S32 *day = NULL, S32 *hour = NULL, S32 *min = NULL, S32 *sec = NULL) const;
std::string toLocalDateString(std::string fmt) const;
std::string toHTTPDateString (std::string fmt) const;
static std::string toHTTPDateString (tm * gmt, std::string fmt);
/**

View File

@ -17,6 +17,7 @@
// std headers
// external library headers
// other Linden headers
#include "llapp.h"
#include "llcoros.h"
#include LLCOROS_MUTEX_HEADER
#include "llerror.h"
@ -102,19 +103,95 @@ std::string LL::WorkQueueBase::makeName(const std::string& name)
return STRINGIZE("WorkQueue" << num);
}
namespace
{
#if LL_WINDOWS
static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific
U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS* exception_infop)
{
if (LLApp::instance()->reportCrashToBugsplat((void*)exception_infop))
{
// Handled
return EXCEPTION_CONTINUE_SEARCH;
}
else if (code == STATUS_MSC_EXCEPTION)
{
// C++ exception, go on
return EXCEPTION_CONTINUE_SEARCH;
}
else
{
// handle it, convert to std::exception
return EXCEPTION_EXECUTE_HANDLER;
}
return EXCEPTION_CONTINUE_SEARCH;
}
void cpphandle(const LL::WorkQueueBase::Work& work)
{
// SE and C++ can not coexists, thus two handlers
try
{
work();
}
catch (const LLContinueError&)
{
// Any uncaught exception derived from LLContinueError will be caught
// here and logged. This coroutine will terminate but the rest of the
// viewer will carry on.
LOG_UNHANDLED_EXCEPTION(STRINGIZE("LLContinue in work queue"));
}
}
void sehandle(const LL::WorkQueueBase::Work& work)
{
__try
{
// handle stop and continue exceptions first
cpphandle(work);
}
__except (exception_filter(GetExceptionCode(), GetExceptionInformation()))
{
// convert to C++ styled exception
char integer_string[512];
sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode());
throw std::exception(integer_string);
}
}
#endif // LL_WINDOWS
} // anonymous namespace
void LL::WorkQueueBase::callWork(const Work& work)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
#ifdef LL_WINDOWS
// can not use __try directly, toplevel requires unwinding, thus use of a wrapper
sehandle(work);
#else // LL_WINDOWS
try
{
work();
}
catch (...)
catch (LLContinueError&)
{
// No matter what goes wrong with any individual work item, the worker
// thread must go on! Log our own instance name with the exception.
LOG_UNHANDLED_EXCEPTION(getKey());
}
catch (...)
{
// Stash any other kind of uncaught exception to be rethrown by main thread.
LL_WARNS("LLCoros") << "Capturing and rethrowing uncaught exception in WorkQueueBase "
<< getKey() << LL_ENDL;
LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop");
main_queue->post(
// Bind the current exception, rethrow it in main loop.
[exc = std::current_exception()]() { std::rethrow_exception(exc); });
}
#endif // else LL_WINDOWS
}
void LL::WorkQueueBase::error(const std::string& msg)

View File

@ -130,17 +130,6 @@ void LLSettingsBase::saveValuesIfNeeded()
}
//=========================================================================
void LLSettingsBase::lerpSettings(LLSettingsBase &other, F64 mix)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
saveValuesIfNeeded();
stringset_t skip = getSkipInterpolateKeys();
stringset_t slerps = getSlerpKeys();
mSettings = interpolateSDMap(mSettings, other.getSettings(), other.getParameterMap(), mix, skip, slerps);
setDirtyFlag(true);
loadValuesFromLLSD();
}
void LLSettingsBase::lerpVector2(LLVector2& a, const LLVector2& b, F32 mix)
{
a.mV[0] = lerp(a.mV[0], b.mV[0], mix);

View File

@ -348,13 +348,8 @@ protected:
LLSettingsBase();
LLSettingsBase(const LLSD setting);
static LLSD settingValidation(LLSD settings);
typedef std::set<std::string> stringset_t;
// combining settings objects. Customize for specific setting types
virtual void lerpSettings(LLSettingsBase &other, BlendFactor mix);
// combining settings maps where it can based on mix rate
// @settings initial value (mix==0)
// @other target value (mix==1)

View File

@ -290,108 +290,123 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECod
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; // <FS:Beq> instrument image decodes
LLImageDataLock lock(&base);
S32 data_size = base.getDataSize();
S32 max_bytes = (base.getMaxBytes() ? base.getMaxBytes() : data_size);
//
// Initialization
//
mCodeStreamp.reset();
// It's not clear to nat under what circumstances we would reuse a
// pre-existing LLKDUMemSource instance. As of 2016-08-05, it consists of
// two U32s and a pointer, so it's not as if it would be a huge overhead
// to allocate a new one every time.
// Also -- why is base.getData() tested specifically here? If that returns
// NULL, shouldn't we bail out of the whole method?
if (!mInputp && base.getData())
try
{
// The compressed data has been loaded
// Setup the source for the codestream
mInputp.reset(new LLKDUMemSource(base.getData(), data_size));
}
if (mInputp)
{
// This is LLKDUMemSource::reset(), not boost::scoped_ptr::reset().
mInputp->reset();
}
S32 data_size = base.getDataSize();
S32 max_bytes = (base.getMaxBytes() ? base.getMaxBytes() : data_size);
mCodeStreamp->create(mInputp.get());
//
// Initialization
//
mCodeStreamp.reset();
// Set the maximum number of bytes to use from the codestream
// *TODO: This seems to be wrong. The base class should have no idea of
// how j2c compression works so no good way of computing what's the byte
// range to be used.
// It's not clear to nat under what circumstances we would reuse a
// pre-existing LLKDUMemSource instance. As of 2016-08-05, it consists of
// two U32s and a pointer, so it's not as if it would be a huge overhead
// to allocate a new one every time.
// Also -- why is base.getData() tested specifically here? If that returns
// NULL, shouldn't we bail out of the whole method?
if (!mInputp && base.getData())
{
// The compressed data has been loaded
// Setup the source for the codestream
mInputp.reset(new LLKDUMemSource(base.getData(), data_size));
}
if (mInputp)
{
// This is LLKDUMemSource::reset(), not boost::scoped_ptr::reset().
mInputp->reset();
}
mCodeStreamp->create(mInputp.get());
// Set the maximum number of bytes to use from the codestream
// *TODO: This seems to be wrong. The base class should have no idea of
// how j2c compression works so no good way of computing what's the byte
// range to be used.
#if (KDU_MAJOR_VERSION*10000 + KDU_MINOR_VERSION*100 + KDU_PATCH_VERSION) >= 80200
mCodeStreamp->set_max_bytes(max_bytes, false);
mCodeStreamp->set_max_bytes(max_bytes, false);
#else
mCodeStreamp->set_max_bytes(max_bytes,true);
mCodeStreamp->set_max_bytes(max_bytes, true);
#endif
// If you want to flip or rotate the image for some reason, change
// the resolution, or identify a restricted region of interest, this is
// the place to do it. You may use "kdu_codestream::change_appearance"
// and "kdu_codestream::apply_input_restrictions" for this purpose.
// If you wish to truncate the code-stream prior to decompression, you
// may use "kdu_codestream::set_max_bytes".
// If you wish to retain all compressed data so that the material
// can be decompressed multiple times, possibly with different appearance
// parameters, you should call "kdu_codestream::set_persistent" here.
// There are a variety of other features which must be enabled at
// this point if you want to take advantage of them. See the
// descriptions appearing with the "kdu_codestream" interface functions
// in "kdu_compressed.h" for an itemized account of these capabilities.
// If you want to flip or rotate the image for some reason, change
// the resolution, or identify a restricted region of interest, this is
// the place to do it. You may use "kdu_codestream::change_appearance"
// and "kdu_codestream::apply_input_restrictions" for this purpose.
// If you wish to truncate the code-stream prior to decompression, you
// may use "kdu_codestream::set_max_bytes".
// If you wish to retain all compressed data so that the material
// can be decompressed multiple times, possibly with different appearance
// parameters, you should call "kdu_codestream::set_persistent" here.
// There are a variety of other features which must be enabled at
// this point if you want to take advantage of them. See the
// descriptions appearing with the "kdu_codestream" interface functions
// in "kdu_compressed.h" for an itemized account of these capabilities.
switch (mode)
{
case MODE_FAST:
mCodeStreamp->set_fast();
break;
case MODE_RESILIENT:
mCodeStreamp->set_resilient();
break;
case MODE_FUSSY:
mCodeStreamp->set_fussy();
break;
default:
llassert(0);
mCodeStreamp->set_fast();
}
kdu_dims dims;
mCodeStreamp->get_dims(0,dims);
S32 components = mCodeStreamp->get_num_components();
// Check that components have consistent dimensions (for PPM file)
for (int idx = 1; idx < components; ++idx)
{
kdu_dims other_dims;
mCodeStreamp->get_dims(idx, other_dims);
if (other_dims != dims)
switch (mode)
{
// This method is only called from methods that catch KDUError.
// We want to fail the image load, not crash the viewer.
LLTHROW(KDUError(STRINGIZE("Component " << idx << " dimensions "
<< stringize(other_dims)
<< " do not match component 0 dimensions "
<< stringize(dims) << "!")));
case MODE_FAST:
mCodeStreamp->set_fast();
break;
case MODE_RESILIENT:
mCodeStreamp->set_resilient();
break;
case MODE_FUSSY:
mCodeStreamp->set_fussy();
break;
default:
llassert(0);
mCodeStreamp->set_fast();
}
kdu_dims dims;
mCodeStreamp->get_dims(0, dims);
S32 components = mCodeStreamp->get_num_components();
// Check that components have consistent dimensions (for PPM file)
for (int idx = 1; idx < components; ++idx)
{
kdu_dims other_dims;
mCodeStreamp->get_dims(idx, other_dims);
if (other_dims != dims)
{
// This method is only called from methods that catch KDUError.
// We want to fail the image load, not crash the viewer.
LLTHROW(KDUError(STRINGIZE("Component " << idx << " dimensions "
<< stringize(other_dims)
<< " do not match component 0 dimensions "
<< stringize(dims) << "!")));
}
}
// Get the number of resolution levels in that image
mLevels = mCodeStreamp->get_min_dwt_levels();
// Set the base dimensions
base.setSize(dims.size.x, dims.size.y, components);
base.setLevels(mLevels);
if (!keep_codestream)
{
mCodeStreamp.reset();
mInputp.reset();
}
}
// Get the number of resolution levels in that image
mLevels = mCodeStreamp->get_min_dwt_levels();
// Set the base dimensions
base.setSize(dims.size.x, dims.size.y, components);
base.setLevels(mLevels);
if (!keep_codestream)
catch (std::bad_alloc&)
{
mCodeStreamp.reset();
mInputp.reset();
// we are in a thread, can't show an 'out of memory' here,
// main thread will keep going
throw;
}
catch (...)
{
LLTHROW(KDUError(STRINGIZE("Unknown J2C error : " +
boost::current_exception_diagnostic_information() << "!")));
}
}

View File

@ -24,6 +24,8 @@
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llmath.h"
static LL_ALIGN_16(const F32 M_IDENT_3A[12]) =

View File

@ -24,6 +24,8 @@
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llmath.h"
#include "llmatrix4a.h"

View File

@ -24,6 +24,8 @@
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llmath.h"
#include "llrigginginfo.h"

View File

@ -24,6 +24,8 @@
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llmemory.h"
#include "llmath.h"
#include "llquantize.h"

View File

@ -5635,14 +5635,22 @@ struct MikktData
{
U32 count = face->mNumIndices;
p.resize(count);
n.resize(count);
tc.resize(count);
t.resize(count);
if (face->mWeights)
try
{
w.resize(count);
p.resize(count);
n.resize(count);
tc.resize(count);
t.resize(count);
if (face->mWeights)
{
w.resize(count);
}
}
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS("LLCoros") << "Bad memory allocation in MikktData, elements count: " << count << LL_ENDL;
}
@ -5714,7 +5722,16 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
// and is executed on a background thread
MikktData data(this);
mikk::Mikktspace ctx(data);
ctx.genTangSpace();
try
{
ctx.genTangSpace();
}
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS("LLCoros") << "Bad memory allocation in MikktData::genTangSpace" << LL_ENDL;
}
//re-weld
meshopt_Stream mos[] =
@ -5727,7 +5744,15 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
};
std::vector<U32> remap;
remap.resize(data.p.size());
try
{
remap.resize(data.p.size());
}
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS("LLCoros") << "Failed to allocate memory for remap: " << (S32)data.p.size() << LL_ENDL;
}
U32 stream_count = data.w.empty() ? 4 : 5;

View File

@ -24,6 +24,8 @@
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llvolumeoctree.h"
#include "llvector4a.h"

View File

@ -28,6 +28,7 @@
#define LL_V3COLORUTIL_H
#include "v3color.h"
#include "v4color.h"
inline LLColor3 componentDiv(LLColor3 const &left, LLColor3 const & right)
{

View File

@ -585,7 +585,8 @@ void LLAssetStorage::getAssetData(const LLUUID uuid,
// static
void LLAssetStorage::removeAndCallbackPendingDownloads(const LLUUID& file_id, LLAssetType::EType file_type,
const LLUUID& callback_id, LLAssetType::EType callback_type,
S32 result_code, LLExtStat ext_status)
S32 result_code, LLExtStat ext_status,
S32 bytes_fetched)
{
// find and callback ALL pending requests for this UUID
// SJB: We process the callbacks in reverse order, I do not know if this is important,
@ -598,6 +599,10 @@ void LLAssetStorage::removeAndCallbackPendingDownloads(const LLUUID& file_id, LL
LLAssetRequest* tmp = *curiter;
if ((tmp->getUUID() == file_id) && (tmp->getType()== file_type))
{
if (bytes_fetched > 0)
{
tmp->mBytesFetched = bytes_fetched;
}
requests.push_front(tmp);
iter = gAssetStorage->mPendingDownloads.erase(curiter);
}
@ -664,6 +669,7 @@ void LLAssetStorage::downloadCompleteCallback(
callback_type = req->getType();
}
S32 bytes_fetched = 0;
if (LL_ERR_NOERR == result)
{
// we might have gotten a zero-size file
@ -677,21 +683,11 @@ void LLAssetStorage::downloadCompleteCallback(
}
else
{
#if 1
for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin();
iter != gAssetStorage->mPendingDownloads.end(); ++iter )
{
LLAssetRequest* dlreq = *iter;
if ((dlreq->getUUID() == file_id) && (dlreq->getType()== file_type))
{
dlreq->mBytesFetched = vfile.getSize();
}
}
#endif
bytes_fetched = vfile.getSize();
}
}
removeAndCallbackPendingDownloads(file_id, file_type, callback_id, callback_type, result, ext_status);
removeAndCallbackPendingDownloads(file_id, file_type, callback_id, callback_type, result, ext_status, bytes_fetched);
}
void LLAssetStorage::getEstateAsset(

View File

@ -324,7 +324,8 @@ public:
static void removeAndCallbackPendingDownloads(const LLUUID& file_id, LLAssetType::EType file_type,
const LLUUID& callback_id, LLAssetType::EType callback_type,
S32 result_code, LLExtStat ext_status);
S32 result_code, LLExtStat ext_status,
S32 bytes_fetched);
// download process callbacks
static void downloadCompleteCallback(

View File

@ -301,12 +301,12 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size):
mPoolSize(size),
mActiveCoprocsCount(0),
mPending(0),
mPendingCoprocs(std::make_shared<CoprocQueue_t>(LLCoprocedureManager::DEFAULT_QUEUE_SIZE)),
mHTTPPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mCoroMapping()
{
try
{
mPendingCoprocs = std::make_shared<CoprocQueue_t>(LLCoprocedureManager::DEFAULT_QUEUE_SIZE);
// store in our LLTempBoundListener so that when the LLCoprocedurePool is
// destroyed, we implicitly disconnect from this LLEventPump
// Monitores application status
@ -339,6 +339,11 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size):
llassert(0); // Fix Me! Ignoring missing listener!
}
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS("CoProcMgr") << "Bad memory allocation in LLCoprocedurePool::LLCoprocedurePool!" << LL_ENDL;
}
for (size_t count = 0; count < mPoolSize; ++count)
{

View File

@ -295,7 +295,15 @@ void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons
}
else
{
result = this->handleSuccess(response, status);
try
{
result = this->handleSuccess(response, status);
}
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS("CoreHTTP") << "Failed to allocate memory for response handling." << LL_ENDL;
}
}
buildStatusEntry(response, status, result);

View File

@ -95,6 +95,8 @@ LLExperienceCache::LLExperienceCache()
LLExperienceCache::~LLExperienceCache()
{
// can exit without cleanup()
sShutdown = true;
}
void LLExperienceCache::initSingleton()

View File

@ -32,8 +32,6 @@
#include "lltimer.h"
#include "llhost.h"
///////////////////////////////////////////////////////////
LLPacketBuffer::LLPacketBuffer(const LLHost &host, const char *datap, const S32 size) : mHost(host)
{
mSize = 0;
@ -41,7 +39,7 @@ LLPacketBuffer::LLPacketBuffer(const LLHost &host, const char *datap, const S32
if (size > NET_BUFFER_SIZE)
{
LL_ERRS() << "Sending packet > " << NET_BUFFER_SIZE << " of size " << size << LL_ENDL;
LL_ERRS() << "Constructing packet with size=" << size << " > " << NET_BUFFER_SIZE << LL_ENDL;
}
else
{
@ -51,7 +49,6 @@ LLPacketBuffer::LLPacketBuffer(const LLHost &host, const char *datap, const S32
mSize = size;
}
}
}
LLPacketBuffer::LLPacketBuffer (S32 hSocket)
@ -59,18 +56,29 @@ LLPacketBuffer::LLPacketBuffer (S32 hSocket)
init(hSocket);
}
///////////////////////////////////////////////////////////
LLPacketBuffer::~LLPacketBuffer ()
{
}
///////////////////////////////////////////////////////////
void LLPacketBuffer::init (S32 hSocket)
void LLPacketBuffer::init(S32 hSocket)
{
mSize = receive_packet(hSocket, mData);
mHost = ::get_sender();
mReceivingIF = ::get_receiving_interface();
}
void LLPacketBuffer::init(const char* buffer, S32 data_size, const LLHost& host)
{
if (data_size > NET_BUFFER_SIZE)
{
LL_ERRS() << "Initializing packet with size=" << data_size << " > " << NET_BUFFER_SIZE << LL_ENDL;
}
else
{
memcpy(mData, buffer, data_size);
mSize = data_size;
mHost = host;
mReceivingIF = ::get_receiving_interface();
}
}

View File

@ -35,20 +35,22 @@ class LLPacketBuffer
{
public:
LLPacketBuffer(const LLHost &host, const char *datap, const S32 size);
LLPacketBuffer(S32 hSocket); // receive a packet
LLPacketBuffer(S32 hSocket); // receive a packet
~LLPacketBuffer();
S32 getSize() const { return mSize; }
const char *getData() const { return mData; }
LLHost getHost() const { return mHost; }
LLHost getReceivingInterface() const { return mReceivingIF; }
void init(S32 hSocket);
void init(const char* buffer, S32 data_size, const LLHost& host);
protected:
char mData[NET_BUFFER_SIZE]; // packet data /* Flawfinder : ignore */
S32 mSize; // size of buffer in bytes
LLHost mHost; // source/dest IP and port
LLHost mReceivingIF; // source/dest IP and port
char mData[NET_BUFFER_SIZE]; // packet data /* Flawfinder : ignore */
S32 mSize; // size of buffer in bytes
LLHost mHost; // source/dest IP and port
LLHost mReceivingIF; // source/dest IP and port
};
#endif

View File

@ -1,6 +1,6 @@
/**
* @file llpacketring.cpp
* @brief implementation of LLPacketRing class for a packet.
* @brief implementation of LLPacketRing class.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
@ -43,313 +43,44 @@
#include "message.h"
#include "u64.h"
///////////////////////////////////////////////////////////
LLPacketRing::LLPacketRing () :
mUseInThrottle(false),
mUseOutThrottle(false),
mInThrottle(256000.f),
mOutThrottle(64000.f),
mActualBitsIn(0),
mActualBitsOut(0),
mMaxBufferLength(64000),
mInBufferLength(0),
mOutBufferLength(0),
mDropPercentage(0.0f),
mPacketsToDrop(0x0)
constexpr S16 MAX_BUFFER_RING_SIZE = 1024;
constexpr S16 DEFAULT_BUFFER_RING_SIZE = 256;
LLPacketRing::LLPacketRing ()
: mPacketRing(DEFAULT_BUFFER_RING_SIZE, nullptr)
{
LLHost invalid_host;
for (size_t i = 0; i < mPacketRing.size(); ++i)
{
mPacketRing[i] = new LLPacketBuffer(invalid_host, nullptr, 0);
}
}
///////////////////////////////////////////////////////////
LLPacketRing::~LLPacketRing ()
{
cleanup();
}
///////////////////////////////////////////////////////////
void LLPacketRing::cleanup ()
{
LLPacketBuffer *packetp;
while (!mReceiveQueue.empty())
for (auto packet : mPacketRing)
{
packetp = mReceiveQueue.front();
delete packetp;
mReceiveQueue.pop();
}
while (!mSendQueue.empty())
{
packetp = mSendQueue.front();
delete packetp;
mSendQueue.pop();
delete packet;
}
mPacketRing.clear();
mNumBufferedPackets = 0;
mNumBufferedBytes = 0;
mHeadIndex = 0;
}
///////////////////////////////////////////////////////////
void LLPacketRing::dropPackets (U32 num_to_drop)
{
mPacketsToDrop += num_to_drop;
}
///////////////////////////////////////////////////////////
void LLPacketRing::setDropPercentage (F32 percent_to_drop)
{
mDropPercentage = percent_to_drop;
}
void LLPacketRing::setUseInThrottle(const bool use_throttle)
{
mUseInThrottle = use_throttle;
}
void LLPacketRing::setUseOutThrottle(const bool use_throttle)
{
mUseOutThrottle = use_throttle;
}
void LLPacketRing::setInBandwidth(const F32 bps)
{
mInThrottle.setRate(bps);
}
void LLPacketRing::setOutBandwidth(const F32 bps)
{
mOutThrottle.setRate(bps);
}
///////////////////////////////////////////////////////////
S32 LLPacketRing::receiveFromRing (S32 socket, char *datap)
{
if (mInThrottle.checkOverflow(0))
{
// We don't have enough bandwidth, don't give them a packet.
return 0;
}
LLPacketBuffer *packetp = NULL;
if (mReceiveQueue.empty())
{
// No packets on the queue, don't give them any.
return 0;
}
S32 packet_size = 0;
packetp = mReceiveQueue.front();
mReceiveQueue.pop();
packet_size = packetp->getSize();
if (packetp->getData() != NULL)
{
memcpy(datap, packetp->getData(), packet_size); /*Flawfinder: ignore*/
}
// need to set sender IP/port!!
mLastSender = packetp->getHost();
mLastReceivingIF = packetp->getReceivingInterface();
delete packetp;
this->mInBufferLength -= packet_size;
// Adjust the throttle
mInThrottle.throttleOverflow(packet_size * 8.f);
return packet_size;
}
///////////////////////////////////////////////////////////
S32 LLPacketRing::receivePacket (S32 socket, char *datap)
{
S32 packet_size = 0;
// If using the throttle, simulate a limited size input buffer.
if (mUseInThrottle)
{
bool done = false;
// push any current net packet (if any) onto delay ring
while (!done)
{
LLPacketBuffer *packetp;
packetp = new LLPacketBuffer(socket);
if (packetp->getSize())
{
mActualBitsIn += packetp->getSize() * 8;
// Fake packet loss
if (mDropPercentage && (ll_frand(100.f) < mDropPercentage))
{
mPacketsToDrop++;
}
if (mPacketsToDrop)
{
delete packetp;
packetp = NULL;
packet_size = 0;
mPacketsToDrop--;
}
}
// If we faked packet loss, then we don't have a packet
// to use for buffer overflow testing
if (packetp)
{
if (mInBufferLength + packetp->getSize() > mMaxBufferLength)
{
// Toss it.
LL_WARNS() << "Throwing away packet, overflowing buffer" << LL_ENDL;
delete packetp;
packetp = NULL;
}
else if (packetp->getSize())
{
mReceiveQueue.push(packetp);
mInBufferLength += packetp->getSize();
}
else
{
delete packetp;
packetp = NULL;
done = true;
}
}
else
{
// No packetp, keep going? - no packetp == faked packet loss
}
}
// Now, grab data off of the receive queue according to our
// throttled bandwidth settings.
packet_size = receiveFromRing(socket, datap);
}
else
{
// no delay, pull straight from net
if (LLProxy::isSOCKSProxyEnabled())
{
U8 buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE];
packet_size = receive_packet(socket, static_cast<char*>(static_cast<void*>(buffer)));
if (packet_size > SOCKS_HEADER_SIZE)
{
// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)
memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size - SOCKS_HEADER_SIZE);
proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer));
mLastSender.setAddress(header->addr);
mLastSender.setPort(ntohs(header->port));
packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size
}
else
{
packet_size = 0;
}
}
else
{
packet_size = receive_packet(socket, datap);
mLastSender = ::get_sender();
}
mLastReceivingIF = ::get_receiving_interface();
if (packet_size) // did we actually get a packet?
{
if (mDropPercentage && (ll_frand(100.f) < mDropPercentage))
{
mPacketsToDrop++;
}
if (mPacketsToDrop)
{
packet_size = 0;
mPacketsToDrop--;
}
}
}
return packet_size;
bool drop = computeDrop();
return (mNumBufferedPackets > 0) ?
receiveOrDropBufferedPacket(datap, drop) :
receiveOrDropPacket(socket, datap, drop);
}
bool LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host)
bool send_packet_helper(int socket, const char * datap, S32 data_size, LLHost host)
{
bool status = true;
if (!mUseOutThrottle)
{
return sendPacketImpl(h_socket, send_buffer, buf_size, host );
}
else
{
mActualBitsOut += buf_size * 8;
LLPacketBuffer *packetp = NULL;
// See if we've got enough throttle to send a packet.
while (!mOutThrottle.checkOverflow(0.f))
{
// While we have enough bandwidth, send a packet from the queue or the current packet
S32 packet_size = 0;
if (!mSendQueue.empty())
{
// Send a packet off of the queue
LLPacketBuffer *packetp = mSendQueue.front();
mSendQueue.pop();
mOutBufferLength -= packetp->getSize();
packet_size = packetp->getSize();
status = sendPacketImpl(h_socket, packetp->getData(), packet_size, packetp->getHost());
delete packetp;
// Update the throttle
mOutThrottle.throttleOverflow(packet_size * 8.f);
}
else
{
// If the queue's empty, we can just send this packet right away.
status = sendPacketImpl(h_socket, send_buffer, buf_size, host );
packet_size = buf_size;
// Update the throttle
mOutThrottle.throttleOverflow(packet_size * 8.f);
// This was the packet we're sending now, there are no other packets
// that we need to send
return status;
}
}
// We haven't sent the incoming packet, add it to the queue
if (mOutBufferLength + buf_size > mMaxBufferLength)
{
// Nuke this packet, we overflowed the buffer.
// Toss it.
LL_WARNS() << "Throwing away outbound packet, overflowing buffer" << LL_ENDL;
}
else
{
static LLTimer queue_timer;
if ((mOutBufferLength > 4192) && queue_timer.getElapsedTimeF32() > 1.f)
{
// Add it to the queue
LL_INFOS() << "Outbound packet queue " << mOutBufferLength << " bytes" << LL_ENDL;
queue_timer.reset();
}
packetp = new LLPacketBuffer(host, send_buffer, buf_size);
mOutBufferLength += packetp->getSize();
mSendQueue.push(packetp);
}
}
return status;
}
bool LLPacketRing::sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host)
{
if (!LLProxy::isSOCKSProxyEnabled())
{
return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort());
return send_packet(socket, datap, data_size, host.getAddress(), host.getPort());
}
char headered_send_buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE];
@ -361,11 +92,274 @@ bool LLPacketRing::sendPacketImpl(int h_socket, const char * send_buffer, S32 bu
socks_header->atype = ADDRESS_IPV4;
socks_header->frag = 0;
memcpy(headered_send_buffer + SOCKS_HEADER_SIZE, send_buffer, buf_size);
memcpy(headered_send_buffer + SOCKS_HEADER_SIZE, datap, data_size);
return send_packet( h_socket,
return send_packet( socket,
headered_send_buffer,
buf_size + SOCKS_HEADER_SIZE,
data_size + SOCKS_HEADER_SIZE,
LLProxy::getInstance()->getUDPProxy().getAddress(),
LLProxy::getInstance()->getUDPProxy().getPort());
}
bool LLPacketRing::sendPacket(int socket, const char * datap, S32 data_size, LLHost host)
{
mActualBytesOut += data_size;
return send_packet_helper(socket, datap, data_size, host);
}
void LLPacketRing::dropPackets (U32 num_to_drop)
{
mPacketsToDrop += num_to_drop;
}
void LLPacketRing::setDropPercentage (F32 percent_to_drop)
{
mDropPercentage = percent_to_drop;
}
bool LLPacketRing::computeDrop()
{
bool drop= (mDropPercentage > 0.0f && (ll_frand(100.f) < mDropPercentage));
if (drop)
{
++mPacketsToDrop;
}
if (mPacketsToDrop > 0)
{
--mPacketsToDrop;
drop = true;
}
return drop;
}
S32 LLPacketRing::receiveOrDropPacket(S32 socket, char *datap, bool drop)
{
S32 packet_size = 0;
// pull straight from socket
if (LLProxy::isSOCKSProxyEnabled())
{
char buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; /* Flawfinder ignore */
packet_size = receive_packet(socket, buffer);
if (packet_size > 0)
{
mActualBytesIn += packet_size;
}
if (packet_size > SOCKS_HEADER_SIZE)
{
if (drop)
{
packet_size = 0;
}
else
{
// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)
packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size
memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size);
proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer));
mLastSender.setAddress(header->addr);
mLastSender.setPort(ntohs(header->port));
mLastReceivingIF = ::get_receiving_interface();
}
}
else
{
packet_size = 0;
}
}
else
{
packet_size = receive_packet(socket, datap);
if (packet_size > 0)
{
mActualBytesIn += packet_size;
if (drop)
{
packet_size = 0;
}
else
{
mLastSender = ::get_sender();
mLastReceivingIF = ::get_receiving_interface();
}
}
}
return packet_size;
}
S32 LLPacketRing::receiveOrDropBufferedPacket(char *datap, bool drop)
{
assert(mNumBufferedPackets > 0);
S32 packet_size = 0;
S16 ring_size = (S16)(mPacketRing.size());
S16 packet_index = (mHeadIndex + ring_size - mNumBufferedPackets) % ring_size;
LLPacketBuffer* packet = mPacketRing[packet_index];
packet_size = packet->getSize();
mLastSender = packet->getHost();
mLastReceivingIF = packet->getReceivingInterface();
--mNumBufferedPackets;
mNumBufferedBytes -= packet_size;
if (mNumBufferedPackets == 0)
{
assert(mNumBufferedBytes == 0);
}
if (!drop)
{
assert(packet_size > 0);
memcpy(datap, packet->getData(), packet_size);
}
else
{
packet_size = 0;
}
return packet_size;
}
S32 LLPacketRing::bufferInboundPacket(S32 socket)
{
if (mNumBufferedPackets == mPacketRing.size() && mNumBufferedPackets < MAX_BUFFER_RING_SIZE)
{
expandRing();
}
LLPacketBuffer* packet = mPacketRing[mHeadIndex];
S32 old_packet_size = packet->getSize();
S32 packet_size = 0;
if (LLProxy::isSOCKSProxyEnabled())
{
char buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; /* Flawfinder ignore */
packet_size = receive_packet(socket, buffer);
if (packet_size > 0)
{
mActualBytesIn += packet_size;
if (packet_size > SOCKS_HEADER_SIZE)
{
// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)
proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer));
LLHost sender;
sender.setAddress(header->addr);
sender.setPort(ntohs(header->port));
packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size
packet->init(buffer + SOCKS_HEADER_SIZE, packet_size, sender);
mHeadIndex = (mHeadIndex + 1) % (S16)(mPacketRing.size());
if (mNumBufferedPackets < MAX_BUFFER_RING_SIZE)
{
++mNumBufferedPackets;
mNumBufferedBytes += packet_size;
}
else
{
// we overwrote an older packet
mNumBufferedBytes += packet_size - old_packet_size;
}
}
else
{
packet_size = 0;
}
}
}
else
{
packet->init(socket);
packet_size = packet->getSize();
if (packet_size > 0)
{
mActualBytesIn += packet_size;
mHeadIndex = (mHeadIndex + 1) % (S16)(mPacketRing.size());
if (mNumBufferedPackets < MAX_BUFFER_RING_SIZE)
{
++mNumBufferedPackets;
mNumBufferedBytes += packet_size;
}
else
{
// we overwrote an older packet
mNumBufferedBytes += packet_size - old_packet_size;
}
}
}
return packet_size;
}
S32 LLPacketRing::drainSocket(S32 socket)
{
// drain into buffer
S32 packet_size = 1;
S32 num_loops = 0;
S32 old_num_packets = mNumBufferedPackets;
while (packet_size > 0)
{
packet_size = bufferInboundPacket(socket);
++num_loops;
}
S32 num_dropped_packets = (num_loops - 1 + old_num_packets) - mNumBufferedPackets;
if (num_dropped_packets > 0)
{
// It will eventually be accounted by mDroppedPackets
// and mPacketsLost, but track it here for logging purposes.
mNumDroppedPackets += num_dropped_packets;
}
return (S32)(mNumBufferedPackets);
}
bool LLPacketRing::expandRing()
{
// compute larger size
constexpr S16 BUFFER_RING_EXPANSION = 256;
S16 old_size = (S16)(mPacketRing.size());
S16 new_size = llmin(old_size + BUFFER_RING_EXPANSION, MAX_BUFFER_RING_SIZE);
if (new_size == old_size)
{
// mPacketRing is already maxed out
return false;
}
// make a larger ring and copy packet pointers
std::vector<LLPacketBuffer*> new_ring(new_size, nullptr);
for (S16 i = 0; i < old_size; ++i)
{
S16 j = (mHeadIndex + i) % old_size;
new_ring[i] = mPacketRing[j];
}
// allocate new packets for the remainder of new_ring
LLHost invalid_host;
for (S16 i = old_size; i < new_size; ++i)
{
new_ring[i] = new LLPacketBuffer(invalid_host, nullptr, 0);
}
// swap the rings and reset mHeadIndex
mPacketRing.swap(new_ring);
mHeadIndex = mNumBufferedPackets;
return true;
}
F32 LLPacketRing::getBufferLoadRate() const
{
// goes up to MAX_BUFFER_RING_SIZE
return (F32)mNumBufferedPackets / (F32)DEFAULT_BUFFER_RING_SIZE;
}
void LLPacketRing::dumpPacketRingStats()
{
mNumDroppedPacketsTotal += mNumDroppedPackets;
LL_INFOS("Messaging") << "Packet ring stats: " << std::endl
<< "Buffered packets: " << mNumBufferedPackets << std::endl
<< "Buffered bytes: " << mNumBufferedBytes << std::endl
<< "Dropped packets current: " << mNumDroppedPackets << std::endl
<< "Dropped packets total: " << mNumDroppedPacketsTotal << std::endl
<< "Dropped packets percentage: " << mDropPercentage << "%" << std::endl
<< "Actual in bytes: " << mActualBytesIn << std::endl
<< "Actual out bytes: " << mActualBytesOut << LL_ENDL;
mNumDroppedPackets = 0;
}

View File

@ -25,16 +25,14 @@
* $/LicenseInfo$
*/
#ifndef LL_LLPACKETRING_H
#define LL_LLPACKETRING_H
#pragma once
#include <queue>
#include <vector>
#include "llhost.h"
#include "llpacketbuffer.h"
#include "llproxy.h"
#include "llthrottle.h"
#include "net.h"
class LLPacketRing
{
@ -42,60 +40,71 @@ public:
LLPacketRing();
~LLPacketRing();
void cleanup();
// receive one packet: either buffered or from the socket
S32 receivePacket (S32 socket, char *datap);
// send one packet
bool sendPacket(int h_socket, const char * send_buffer, S32 buf_size, LLHost host);
// drains packets from socket and returns final mNumBufferedPackets
S32 drainSocket(S32 socket);
void dropPackets(U32);
void setDropPercentage (F32 percent_to_drop);
void setUseInThrottle(const bool use_throttle);
void setUseOutThrottle(const bool use_throttle);
void setInBandwidth(const F32 bps);
void setOutBandwidth(const F32 bps);
S32 receivePacket (S32 socket, char *datap);
S32 receiveFromRing (S32 socket, char *datap);
bool sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host);
inline LLHost getLastSender() const;
inline LLHost getLastReceivingInterface() const;
inline LLHost getLastSender();
inline LLHost getLastReceivingInterface();
S32 getActualInBytes() const { return mActualBytesIn; }
S32 getActualOutBytes() const { return mActualBytesOut; }
S32 getAndResetActualInBits() { S32 bits = mActualBytesIn * 8; mActualBytesIn = 0; return bits;}
S32 getAndResetActualOutBits() { S32 bits = mActualBytesOut * 8; mActualBytesOut = 0; return bits;}
S32 getAndResetActualInBits() { S32 bits = mActualBitsIn; mActualBitsIn = 0; return bits;}
S32 getAndResetActualOutBits() { S32 bits = mActualBitsOut; mActualBitsOut = 0; return bits;}
S32 getNumBufferedPackets() const { return (S32)(mNumBufferedPackets); }
S32 getNumBufferedBytes() const { return mNumBufferedBytes; }
S32 getNumDroppedPackets() const { return mNumDroppedPacketsTotal + mNumDroppedPackets; }
F32 getBufferLoadRate() const; // from 0 to 4 (0 - empty, 1 - default size is full)
void dumpPacketRingStats();
protected:
bool mUseInThrottle;
bool mUseOutThrottle;
// returns 'true' if we should intentionally drop a packet
bool computeDrop();
// For simulating a lower-bandwidth connection - BPS
LLThrottle mInThrottle;
LLThrottle mOutThrottle;
// returns packet_size of received packet, zero or less if no packet found
S32 receiveOrDropPacket(S32 socket, char *datap, bool drop);
S32 receiveOrDropBufferedPacket(char *datap, bool drop);
S32 mActualBitsIn;
S32 mActualBitsOut;
S32 mMaxBufferLength; // How much data can we queue up before dropping data.
S32 mInBufferLength; // Current incoming buffer length
S32 mOutBufferLength; // Current outgoing buffer length
// returns packet_size of packet buffered
S32 bufferInboundPacket(S32 socket);
F32 mDropPercentage; // % of packets to drop
U32 mPacketsToDrop; // drop next n packets
// returns 'true' if ring was expanded
bool expandRing();
std::queue<LLPacketBuffer *> mReceiveQueue;
std::queue<LLPacketBuffer *> mSendQueue;
protected:
std::vector<LLPacketBuffer*> mPacketRing;
S16 mHeadIndex { 0 };
S16 mNumBufferedPackets { 0 };
S32 mNumDroppedPackets { 0 };
S32 mNumDroppedPacketsTotal { 0 };
S32 mNumBufferedBytes { 0 };
S32 mActualBytesIn { 0 };
S32 mActualBytesOut { 0 };
F32 mDropPercentage { 0.0f }; // % of inbound packets to drop
U32 mPacketsToDrop { 0 }; // drop next inbound n packets
// These are the sender and receiving_interface for the last packet delivered by receivePacket()
LLHost mLastSender;
LLHost mLastReceivingIF;
private:
bool sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host);
};
inline LLHost LLPacketRing::getLastSender()
inline LLHost LLPacketRing::getLastSender() const
{
return mLastSender;
}
inline LLHost LLPacketRing::getLastReceivingInterface()
inline LLHost LLPacketRing::getLastReceivingInterface() const
{
return mLastReceivingIF;
}
#endif

View File

@ -465,7 +465,7 @@ void LLProxy::applyProxySettings(CURL* handle)
/**
* @brief Send one TCP packet and receive one in return.
*
* This operation is done synchronously with a 1000ms timeout. Therefore, it should not be used when a blocking
* This operation is done synchronously with a 100ms timeout. Therefore, it should not be used when a blocking
* operation would impact the operation of the viewer.
*
* @param handle_ptr Pointer to a connected LLSocket of type STREAM_TCP.
@ -482,7 +482,7 @@ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataou
apr_size_t expected_len = outlen;
handle->setBlocking(100000); // <FS:Beq/> extend the arbitrary timeout value to 100ms. this should be more than enough for most LAN proxies and plenty for a localhost
handle->setBlocking(100000); // 100ms, 100000us. Should be sufficient for localhost, nearby network
rv = apr_socket_send(apr_socket, dataout, &outlen);
if (APR_SUCCESS != rv)

View File

@ -659,8 +659,7 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count )
// UseCircuitCode is allowed in even from an invalid circuit, so that
// we can toss circuits around.
if(
valid_packet &&
else if (
!cdp &&
(mTemplateMessageReader->getMessageName() !=
_PREHASH_UseCircuitCode))
@ -670,8 +669,7 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count )
valid_packet = false;
}
if(
valid_packet &&
if ( valid_packet &&
cdp &&
!cdp->getTrusted() &&
mTemplateMessageReader->isTrusted())
@ -683,7 +681,7 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count )
valid_packet = false;
}
if( valid_packet )
if ( valid_packet )
{
logValidMsg(cdp, host, recv_reliable, recv_resent, acks>0 );
@ -737,6 +735,7 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count )
// Check to see if we need to print debug info
if ((mt_sec - mCircuitPrintTime) > mCircuitPrintFreq)
{
mPacketRing.dumpPacketRingStats();
dumpCircuitInfo();
mCircuitPrintTime = mt_sec;
}
@ -832,6 +831,11 @@ void LLMessageSystem::processAcks(LockMessageChecker&, F32 collect_time)
}
}
S32 LLMessageSystem::drainUdpSocket()
{
return mPacketRing.drainSocket(mSocket);
}
void LLMessageSystem::copyMessageReceivedToSend()
{
// NOTE: babbage: switch builder to match reader to avoid

View File

@ -417,6 +417,9 @@ public:
bool checkMessages(LockMessageChecker&, S64 frame_count = 0 );
void processAcks(LockMessageChecker&, F32 collect_time = 0.f);
// returns total number of buffered packets after the drain
S32 drainUdpSocket();
bool isMessageFast(const char *msg);
bool isMessage(const char *msg)
{
@ -535,7 +538,6 @@ public:
//void buildMessage();
S32 zeroCode(U8 **data, S32 *data_size);
S32 zeroCodeExpand(U8 **data, S32 *data_size);
S32 zeroCodeAdjustCurrentSendTotal();
@ -752,6 +754,7 @@ public:
S32 getReceiveBytes() const;
S32 getUnackedListSize() const { return mUnackedListSize; }
F32 getBufferLoadRate() const { return mPacketRing.getBufferLoadRate(); }
//const char* getCurrentSMessageName() const { return mCurrentSMessageName; }
//const char* getCurrentSBlockName() const { return mCurrentSBlockName; }
@ -842,12 +845,10 @@ private:
LLUUID mSessionID;
void addTemplate(LLMessageTemplate *templatep);
bool decodeTemplate( const U8* buffer, S32 buffer_size, LLMessageTemplate** msg_template );
void logMsgFromInvalidCircuit( const LLHost& sender, bool recv_reliable );
void logTrustedMsgFromUntrustedCircuit( const LLHost& sender );
void logValidMsg(LLCircuitData *cdp, const LLHost& sender, bool recv_reliable, bool recv_resent, bool recv_acks );
void logRanOffEndOfPacket( const LLHost& sender );
class LLMessageCountInfo
{

View File

@ -76,14 +76,8 @@ static U32 gsnReceivingIFAddr = INVALID_HOST_IP_ADDRESS; // Address to which dat
const char* LOOPBACK_ADDRESS_STRING = "127.0.0.1";
const char* BROADCAST_ADDRESS_STRING = "255.255.255.255";
#if LL_DARWIN
// macOS returns an error when trying to set these to 400000. Smaller values succeed.
const int SEND_BUFFER_SIZE = 200000;
const int RECEIVE_BUFFER_SIZE = 200000;
#else // LL_DARWIN
const int SEND_BUFFER_SIZE = 400000;
const int RECEIVE_BUFFER_SIZE = 400000;
#endif // LL_DARWIN
const int SEND_BUFFER_SIZE = 200000;
const int RECEIVE_BUFFER_SIZE = 800000;
// universal functions (cross-platform)

View File

@ -406,9 +406,14 @@ void LLPluginProcessParent::idle(void)
apr_sockaddr_t* addr = NULL;
mListenSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
mBoundPort = 0;
if (!mListenSocket)
{
killSockets();
errorState();
break;
}
// This code is based on parts of LLSocket::create() in lliosocket.cpp.
status = apr_sockaddr_info_get(
&addr,
"127.0.0.1",

View File

@ -105,6 +105,36 @@ LLCubeMapArray::LLCubeMapArray()
}
LLCubeMapArray::LLCubeMapArray(LLCubeMapArray& lhs, U32 width, U32 count) : mTextureStage(0)
{
mWidth = width;
mCount = count;
// Allocate a new cubemap array with the same criteria as the incoming cubemap array
allocate(mWidth, lhs.mImage->getComponents(), count, lhs.mImage->getUseMipMaps(), lhs.mHDR);
// Copy each cubemap from the incoming array to the new array
U32 min_count = std::min(count, lhs.mCount);
for (U32 i = 0; i < min_count * 6; ++i)
{
U32 src_resolution = lhs.mWidth;
U32 dst_resolution = mWidth;
{
GLint components = GL_RGB;
if (mImage->getComponents() == 4)
components = GL_RGBA;
GLint format = GL_RGB;
// Handle different resolutions by scaling the image
LLPointer<LLImageRaw> src_image = new LLImageRaw(lhs.mWidth, lhs.mWidth, lhs.mImage->getComponents());
glGetTexImage(GL_TEXTURE_CUBE_MAP_ARRAY, 0, components, GL_UNSIGNED_BYTE, src_image->getData());
LLPointer<LLImageRaw> scaled_image = src_image->scaled(mWidth, mWidth);
glTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, 0, 0, i, mWidth, mWidth, 1, components, GL_UNSIGNED_BYTE, scaled_image->getData());
}
}
}
LLCubeMapArray::~LLCubeMapArray()
{
}
@ -115,6 +145,8 @@ void LLCubeMapArray::allocate(U32 resolution, U32 components, U32 count, bool us
mWidth = resolution;
mCount = count;
mHDR = hdr;
LLImageGL::generateTextures(1, &texname);
mImage = new LLImageGL(resolution, resolution, components, use_mips);

View File

@ -36,6 +36,7 @@ class LLCubeMapArray : public LLRefCount
{
public:
LLCubeMapArray();
LLCubeMapArray(LLCubeMapArray& lhs, U32 width, U32 count);
static GLenum sTargets[6];
@ -73,4 +74,5 @@ protected:
U32 mWidth = 0;
U32 mCount = 0;
S32 mTextureStage;
bool mHDR;
};

View File

@ -822,11 +822,11 @@ void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index, ll
|| FT_Err_Invalid_Composite == error
|| (FT_Err_Ok != error && LLStringOps::isEmoji(wch)))
{
glyph_index = FT_Get_Char_Index(mFTFace, '?');
// if '?' is not present, potentially can use last index, that's supposed to be null glyph
if (glyph_index > 0)
// value~0 always corresponds to the 'missing glyph'
error = FT_Load_Glyph(mFTFace, 0, FT_LOAD_FORCE_AUTOHINT);
if (FT_Err_Ok != error)
{
error = FT_Load_Glyph(mFTFace, glyph_index, load_flags ^ FT_LOAD_COLOR);
LL_ERRS() << "Loading fallback for char '" << (U32)wch << "', glyph " << glyph_index << " failed with error : " << (S32)error << LL_ENDL;
}
}

View File

@ -2536,12 +2536,15 @@ void LLGLState::checkStates(GLboolean writeAlpha)
return;
}
GLint src;
GLint dst;
glGetIntegerv(GL_BLEND_SRC, &src);
glGetIntegerv(GL_BLEND_DST, &dst);
llassert_always(src == GL_SRC_ALPHA);
llassert_always(dst == GL_ONE_MINUS_SRC_ALPHA);
GLint srcRGB, dstRGB, srcAlpha, dstAlpha;
glGetIntegerv(GL_BLEND_SRC_RGB, &srcRGB);
glGetIntegerv(GL_BLEND_DST_RGB, &dstRGB);
glGetIntegerv(GL_BLEND_SRC_ALPHA, &srcAlpha);
glGetIntegerv(GL_BLEND_DST_ALPHA, &dstAlpha);
llassert_always(srcRGB == GL_SRC_ALPHA);
llassert_always(srcAlpha == GL_SRC_ALPHA);
llassert_always(dstRGB == GL_ONE_MINUS_SRC_ALPHA);
llassert_always(dstAlpha == GL_ONE_MINUS_SRC_ALPHA);
// disable for now until usage is consistent
//GLboolean colorMask[4];

View File

@ -901,7 +901,7 @@ void LLButton::draw()
// Highlight if needed
if( ll::ui::SearchableControl::getHighlighted() )
label_color = ll::ui::SearchableControl::getHighlightColor();
label_color = ll::ui::SearchableControl::getHighlightFontColor();
// overlay with keyboard focus border
if (hasFocus())

View File

@ -174,12 +174,14 @@ bool LLCommandManager::load()
if (!parser.readXUI(commands_file, commandsParams))
{
LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS() << "Unable to load xml file: " << commands_file << LL_ENDL;
return false;
}
if (!commandsParams.validateBlock())
{
LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS() << "Invalid commands file: " << commands_file << LL_ENDL;
return false;
}

View File

@ -23,9 +23,7 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
// <FS:Ansariel> Remove ugly dependency
//#include "../newview/llviewerprecompiledheaders.h"
#include "linden_common.h"
#include "llflashtimer.h"

View File

@ -529,7 +529,7 @@ void LLMenuItemGL::draw( void )
// Highlight if needed
if( ll::ui::SearchableControl::getHighlighted() )
color = ll::ui::SearchableControl::getHighlightColor();
color = ll::ui::SearchableControl::getHighlightFontColor();
// Draw the text on top.
if (mBriefItem)

View File

@ -615,6 +615,13 @@ void LLNotification::cancel()
LLSD LLNotification::getResponseTemplate(EResponseTemplateType type)
{
LLSD response = LLSD::emptyMap();
if (!mForm)
{
LL_WARNS("Notifications") << "Null form when getting response template for notification " << getName() << LL_ENDL;
return response;
}
for (S32 element_idx = 0;
element_idx < mForm->getNumElements();
++element_idx)
@ -1257,9 +1264,26 @@ LLNotifications::LLNotifications()
LLInstanceTracker<LLNotificationChannel, std::string>::instanceCount();
}
LLNotifications::~LLNotifications()
{
// Clear explicitly, something in ~LLNotifications() crashes so narrowing down suspects
pHistoryChannel = nullptr;
pExpirationChannel = nullptr;
mGlobalStrings.clear();
mTemplates.clear();
mVisibilityRules.clear();
mUniqueNotifications.clear();
mListener = nullptr;
}
void LLNotifications::clear()
{
mDefaultChannels.clear();
mDefaultChannels.clear();
// At this point mTemplates still gets used by lingering notifications
// to do responses (ex: group notice will call forceResponse()), but
// since network should be down and everything save, it's questionable
// whether it should stay that way
}
// The expiration channel gets all notifications that are cancelled
@ -1472,6 +1496,13 @@ bool LLNotifications::templateExists(std::string_view name)
void LLNotifications::forceResponse(const LLNotification::Params& params, S32 option)
{
LLNotificationPtr temp_notify(new LLNotification(params));
if (!temp_notify->getForm())
{
LL_WARNS("Notifications") << "Cannot force response for notification with null form: " << (std::string)params.name << LL_ENDL;
return;
}
LLSD response = temp_notify->getResponseTemplate();
LLSD selected_item = temp_notify->getForm()->getElement(option);

View File

@ -892,7 +892,7 @@ class LLNotifications :
{
LLSINGLETON(LLNotifications);
LOG_CLASS(LLNotifications);
virtual ~LLNotifications() {}
virtual ~LLNotifications();
public:

View File

@ -3861,7 +3861,7 @@ bool LLScrollListCtrl::highlightMatchingItems(const std::string& filter_str)
bool res = false;
setHighlightedColor(LLUIColorTable::instance().getColor("SearchableControlHighlightColor", LLColor4::red));
setHighlightedColor(LLUIColorTable::instance().getColor("SearchableControlHighlightBgColor", LLColor4::red4));
std::string filter_str_lc(filter_str);
LLStringUtil::toLower(filter_str_lc);

View File

@ -43,9 +43,15 @@ namespace ll
virtual ~SearchableControl()
{ }
const LLColor4& getHighlightColor( ) const
const LLColor4& getHighlightBgColor( ) const
{
static LLUIColor highlight_color = LLUIColorTable::instance().getColor("SearchableControlHighlightColor", LLColor4::red);
static LLUIColor highlight_color = LLUIColorTable::instance().getColor("SearchableControlHighlightBgColor", LLColor4::red4);
return highlight_color.get();
}
const LLColor4& getHighlightFontColor() const
{
static LLUIColor highlight_color = LLUIColorTable::instance().getColor("SearchableControlHighlightFontColor", LLColor4::red4);
return highlight_color.get();
}

View File

@ -1524,7 +1524,7 @@ void LLTextBase::draw()
// Draw highlighted if needed
if( ll::ui::SearchableControl::getHighlighted() )
{
const LLColor4& bg_color = ll::ui::SearchableControl::getHighlightColor();
const LLColor4& bg_color = ll::ui::SearchableControl::getHighlightBgColor();
LLRect bg_rect = mVisibleTextRect;
if( mScroller )
bg_rect.intersectWith( text_rect );

View File

@ -81,13 +81,12 @@ protected:
LLUIString mText;
callback_t mClickedCallback;
bool mShowCursorHand;
// <FS:ND> Searchable text for UI filter
protected:
virtual std::string _getSearchText() const
{
return LLTextBase::_getSearchText() + mText.getString();
}
// </FS:ND>
};
// Build time optimization, generate once in .cpp file

View File

@ -209,8 +209,15 @@ public:
}
virtual bool execute( LLTextBase* editor, S32* delta )
{
mWString = editor->getWText().substr(getPosition(), mLen);
*delta = remove(editor, getPosition(), mLen );
try
{
mWString = editor->getWText().substr(getPosition(), mLen);
*delta = remove(editor, getPosition(), mLen);
}
catch (std::out_of_range&)
{
return false;
}
return (*delta != 0);
}
virtual S32 undo( LLTextBase* editor )

View File

@ -31,8 +31,6 @@
#include "llrect.h"
#include "llcoord.h"
#include "llcontrol.h"
#include "llcoord.h"
#include "llcontrol.h"
#include "llinitparam.h"
#include "llregistry.h"
#include "llrender2dutils.h"

View File

@ -287,6 +287,10 @@ void callResetKeys()
bool callUnicodeCallback(wchar_t character, unsigned int mask)
{
if (!gWindowImplementation)
{
return false;
}
NativeKeyEventData eventData;
memset(&eventData, 0, sizeof(NativeKeyEventData));
@ -308,7 +312,7 @@ bool callUnicodeCallback(wchar_t character, unsigned int mask)
void callFocus()
{
if (gWindowImplementation)
if (gWindowImplementation && gWindowImplementation->getCallbacks())
{
gWindowImplementation->getCallbacks()->handleFocus(gWindowImplementation);
}
@ -316,7 +320,7 @@ void callFocus()
void callFocusLost()
{
if (gWindowImplementation)
if (gWindowImplementation && gWindowImplementation->getCallbacks())
{
gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation);
}
@ -324,6 +328,10 @@ void callFocusLost()
void callRightMouseDown(float *pos, MASK mask)
{
if (!gWindowImplementation)
{
return;
}
if (gWindowImplementation->allowsLanguageInput())
{
gWindowImplementation->interruptLanguageTextInput();
@ -337,6 +345,10 @@ void callRightMouseDown(float *pos, MASK mask)
void callRightMouseUp(float *pos, MASK mask)
{
if (!gWindowImplementation)
{
return;
}
if (gWindowImplementation->allowsLanguageInput())
{
gWindowImplementation->interruptLanguageTextInput();
@ -350,6 +362,10 @@ void callRightMouseUp(float *pos, MASK mask)
void callLeftMouseDown(float *pos, MASK mask)
{
if (!gWindowImplementation)
{
return;
}
if (gWindowImplementation->allowsLanguageInput())
{
gWindowImplementation->interruptLanguageTextInput();
@ -363,6 +379,10 @@ void callLeftMouseDown(float *pos, MASK mask)
void callLeftMouseUp(float *pos, MASK mask)
{
if (!gWindowImplementation)
{
return;
}
if (gWindowImplementation->allowsLanguageInput())
{
gWindowImplementation->interruptLanguageTextInput();
@ -377,6 +397,10 @@ void callLeftMouseUp(float *pos, MASK mask)
void callDoubleClick(float *pos, MASK mask)
{
if (!gWindowImplementation)
{
return;
}
if (gWindowImplementation->allowsLanguageInput())
{
gWindowImplementation->interruptLanguageTextInput();
@ -390,7 +414,7 @@ void callDoubleClick(float *pos, MASK mask)
void callResize(unsigned int width, unsigned int height)
{
if (gWindowImplementation != NULL)
if (gWindowImplementation && gWindowImplementation->getCallbacks())
{
gWindowImplementation->getCallbacks()->handleResize(gWindowImplementation, width, height);
}
@ -398,6 +422,10 @@ void callResize(unsigned int width, unsigned int height)
void callMouseMoved(float *pos, MASK mask)
{
if (!gWindowImplementation)
{
return;
}
LLCoordGL outCoords;
outCoords.mX = ll_round(pos[0]);
outCoords.mY = ll_round(pos[1]);
@ -411,6 +439,10 @@ void callMouseMoved(float *pos, MASK mask)
void callMouseDragged(float *pos, MASK mask)
{
if (!gWindowImplementation)
{
return;
}
LLCoordGL outCoords;
outCoords.mX = ll_round(pos[0]);
outCoords.mY = ll_round(pos[1]);
@ -432,6 +464,10 @@ void callScrollMoved(float deltaX, float deltaY)
void callMouseExit()
{
if (!gWindowImplementation)
{
return;
}
gWindowImplementation->getCallbacks()->handleMouseLeave(gWindowImplementation);
}
@ -483,11 +519,19 @@ void callWindowDidChangeScreen()
void callDeltaUpdate(float *delta, MASK mask)
{
if (!gWindowImplementation)
{
return;
}
gWindowImplementation->updateMouseDeltas(delta);
}
void callOtherMouseDown(float *pos, MASK mask, int button)
{
if (!gWindowImplementation)
{
return;
}
LLCoordGL outCoords;
outCoords.mX = ll_round(pos[0]);
outCoords.mY = ll_round(pos[1]);
@ -508,6 +552,10 @@ void callOtherMouseDown(float *pos, MASK mask, int button)
void callOtherMouseUp(float *pos, MASK mask, int button)
{
if (!gWindowImplementation)
{
return;
}
LLCoordGL outCoords;
outCoords.mX = ll_round(pos[0]);
outCoords.mY = ll_round(pos[1]);
@ -532,27 +580,43 @@ void callModifier(MASK mask)
void callHandleDragEntered(std::string url)
{
if (!gWindowImplementation)
{
return;
}
gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_START_TRACKING);
}
void callHandleDragExited(std::string url)
{
if (!gWindowImplementation)
{
return;
}
gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_STOP_TRACKING);
}
void callHandleDragUpdated(std::string url)
{
if (!gWindowImplementation)
{
return;
}
gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_TRACK);
}
void callHandleDragDropped(std::string url)
{
if (!gWindowImplementation)
{
return;
}
gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_DROPPED);
}
void callQuitHandler()
{
if (gWindowImplementation)
if (gWindowImplementation && gWindowImplementation->getCallbacks())
{
if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation))
{
@ -563,7 +627,7 @@ void callQuitHandler()
void getPreeditSelectionRange(int *position, int *length)
{
if (gWindowImplementation->getPreeditor())
if (gWindowImplementation && gWindowImplementation->getPreeditor())
{
gWindowImplementation->getPreeditor()->getSelectionRange(position, length);
}
@ -571,7 +635,7 @@ void getPreeditSelectionRange(int *position, int *length)
void getPreeditMarkedRange(int *position, int *length)
{
if (gWindowImplementation->getPreeditor())
if (gWindowImplementation && gWindowImplementation->getPreeditor())
{
gWindowImplementation->getPreeditor()->getPreeditRange(position, length);
}
@ -579,7 +643,7 @@ void getPreeditMarkedRange(int *position, int *length)
void setPreeditMarkedRange(int position, int length)
{
if (gWindowImplementation->getPreeditor())
if (gWindowImplementation && gWindowImplementation->getPreeditor())
{
gWindowImplementation->getPreeditor()->markAsPreedit(position, length);
}
@ -588,7 +652,7 @@ void setPreeditMarkedRange(int position, int length)
bool handleUnicodeCharacter(wchar_t c)
{
bool success = false;
if (gWindowImplementation->getPreeditor())
if (gWindowImplementation && gWindowImplementation->getPreeditor())
{
success = gWindowImplementation->getPreeditor()->handleUnicodeCharHere(c);
}
@ -598,7 +662,7 @@ bool handleUnicodeCharacter(wchar_t c)
void resetPreedit()
{
if (gWindowImplementation->getPreeditor())
if (gWindowImplementation && gWindowImplementation->getPreeditor())
{
gWindowImplementation->getPreeditor()->resetPreedit();
}
@ -608,7 +672,7 @@ void resetPreedit()
// This largely mirrors the old implementation, only sans the carbon parameters.
void setMarkedText(unsigned short *unitext, unsigned int *selectedRange, unsigned int *replacementRange, long text_len, attributedStringInfo segments)
{
if (gWindowImplementation->getPreeditor())
if (gWindowImplementation && gWindowImplementation->getPreeditor())
{
LLPreeditor *preeditor = gWindowImplementation->getPreeditor();
preeditor->resetPreedit();
@ -631,7 +695,7 @@ void setMarkedText(unsigned short *unitext, unsigned int *selectedRange, unsigne
void getPreeditLocation(float *location, unsigned int length)
{
if (gWindowImplementation->getPreeditor())
if (gWindowImplementation && gWindowImplementation->getPreeditor())
{
LLPreeditor *preeditor = gWindowImplementation->getPreeditor();
LLCoordGL coord;

View File

@ -4183,18 +4183,15 @@ void LLWindowWin32::fillCompositionLogfont(LOGFONT *logfont)
break;
}
// <FS:Beq> FIRE-34906 (BugSplat) crash when mPreEditor is NULL. (affects at least version 6.6.17->7.1.11)
// logfont->lfHeight = mPreeditor->getPreeditFontSize();
if(mPreeditor)
if (mPreeditor)
{
logfont->lfHeight = mPreeditor->getPreeditFontSize();
}
else
{
// In the absence of other options, use the default font height for monospace.
logfont->lfHeight = LLFontGL::getFontMonospace()->getLineHeight();
// todo: extract from some font * LLUI::getScaleFactor() intead
logfont->lfHeight = 10;
}
// </FS:Beq>
logfont->lfWeight = FW_NORMAL;
}

View File

@ -306,6 +306,7 @@ void LLXMLNode::addChild(LLXMLNodePtr& new_child)
// virtual
LLXMLNodePtr LLXMLNode::createChild(const char* name, bool is_attribute)
{
// Todo: validate to make sure node name is valid? (no spaces, etc)
return createChild(gStringTable.addStringEntry(name), is_attribute);
}

View File

@ -125,12 +125,15 @@ LLXmlTreeNode::LLXmlTreeNode( const std::string& name, LLXmlTreeNode* parent, LL
LLXmlTreeNode::~LLXmlTreeNode()
{
attribute_map_t::iterator iter;
for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++)
delete iter->second;
for(LLXmlTreeNode* node : mChildren)
for (auto& attr : mAttributes)
{
delete node;
delete attr.second;
}
mAttributes.clear();
for (auto& child : mChildren)
{
delete child;
}
mChildren.clear();
}

View File

@ -413,6 +413,7 @@ set(viewer_SOURCE_FILES
llfloatersettingscolor.cpp
llfloatersettingsdebug.cpp
llfloatersidepanelcontainer.cpp
llfloaterslapptest.cpp
llfloatersnapshot.cpp
llfloatersounddevices.cpp
llfloaterspellchecksettings.cpp
@ -1233,6 +1234,7 @@ set(viewer_HEADER_FILES
llfloatersettingscolor.h
llfloatersettingsdebug.h
llfloatersidepanelcontainer.h
llfloaterslapptest.h
llfloatersnapshot.h
llfloatersounddevices.h
llfloaterspellchecksettings.h
@ -1761,11 +1763,24 @@ if (DARWIN)
LIST(APPEND viewer_SOURCE_FILES llfilepicker_mac.mm)
LIST(APPEND viewer_HEADER_FILES llfilepicker_mac.h)
set_source_files_properties(
llappviewermacosx-objc.mm
PROPERTIES
SKIP_PRECOMPILE_HEADERS TRUE
)
set_source_files_properties(
llfilepicker_mac.mm
PROPERTIES
SKIP_PRECOMPILE_HEADERS TRUE
)
# This should be compiled with the viewer.
LIST(APPEND viewer_SOURCE_FILES llappdelegate-objc.mm)
set_source_files_properties(
llappdelegate-objc.mm
PROPERTIES
SKIP_PRECOMPILE_HEADERS TRUE
COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}"
# BugsplatMac is a module, imported with @import. That language feature
# demands these -f switches.
@ -2185,7 +2200,11 @@ list(APPEND EVENT_HOST_SCRIPTS ${EVENT_HOST_SCRIPT_GLOB_LIST})
set(PACKAGE ON CACHE BOOL
"Add a package target that builds an installer package.")
if (OPENSIM )
if(USE_PRECOMPILED_HEADERS)
target_precompile_headers( ${VIEWER_BINARY_NAME} PRIVATE llviewerprecompiledheaders.h )
endif(USE_PRECOMPILED_HEADERS)
if (OPENSIM)
set(ND_VIEWER_FLAVOR "oss")
else (OPENSIM)
set(ND_VIEWER_FLAVOR "hvk")
@ -2201,10 +2220,6 @@ if (WINDOWS)
)
target_compile_options(${VIEWER_BINARY_NAME} PRIVATE /bigobj)
if(USE_PRECOMPILED_HEADERS)
target_precompile_headers( ${VIEWER_BINARY_NAME} PRIVATE llviewerprecompiledheaders.h )
endif(USE_PRECOMPILED_HEADERS)
# If adding a file to viewer_manifest.py in the WindowsManifest.construct() method, be sure to add the dependency
# here.
# *NOTE:Mani - This is a crappy hack to have important dependencies for the viewer_manifest copy action

View File

@ -1 +1 @@
7.1.12
7.1.13

View File

@ -93,6 +93,7 @@
<string>RenderTerrainPBRPlanarSampleCount</string>
<string>RenderTerrainPBRTriplanarBlendFactor</string>
<string>RenderTerrainScale</string>
<string>RenderTextureVRAMDivisor</string>
<string>RenderTonemapMix</string>
<string>RenderTonemapType</string>
<string>RenderTreeLODFactor</string>

View File

@ -1911,7 +1911,20 @@
<key>Value</key>
<real>0.7</real>
</map>
<key>AudioStreamingMedia</key>
<!-- <FS> [FIRE-35317] Restore AudioLevelWind debug setting -->
<key>AudioLevelWind</key>
<map>
<key>Comment</key>
<string>Audio level of wind noise when standing still</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>0.5</real>
</map>
<!-- </FS> -->
<key>AudioStreamingMedia</key>
<map>
<key>Comment</key>
<string>Enable streaming</string>
@ -6267,6 +6280,17 @@
<key>Value</key>
<integer>5000</integer>
</map>
<key>InventoryExposeFolderID</key>
<map>
<key>Comment</key>
<string>Allows copying folder id from context menu</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>MarketplaceListingsSortOrder</key>
<map>
<key>Comment</key>
@ -11232,6 +11256,17 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>768</integer>
</map>
<key>RenderTextureVRAMDivisor</key>
<map>
<key>Comment</key>
<string>Divisor for maximum amount of VRAM the viewer will use for textures. 1 = all the VRAM. Used in conjunction with RenderMaxVRAMBudget.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>RenderMinFreeMainMemoryThreshold</key>
<map>
<key>Comment</key>
@ -12623,6 +12658,28 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>1</integer>
</map>
<key>RenderReflectionProbeDynamicAllocation</key>
<map>
<key>Comment</key>
<string>Enable dynamic allocation of reflection probes. -1 means no dynamic allocation. Sets a buffer to allocate when a dynamic allocation occurs otherwise.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>RenderReflectionProbeCount</key>
<map>
<key>Comment</key>
<string>Number of probes to render. Maximum of 256. Clamps to the nearest power of 2.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>256</integer>
</map>
<key>RenderReflectionProbeResolution</key>
<map>
<key>Comment</key>
@ -15428,7 +15485,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>0.04</real>
<real>0.0095</real>
</map>
<key>TextureScaleMaxAreaFactor</key>
<map>

View File

@ -80,6 +80,18 @@ vec3 atmosFragLightingLinear(vec3 light, vec3 additive, vec3 atten);
vec4 decodeNormal(vec4 norm);
vec3 clampHDRRange(vec3 color)
{
// Why do this?
// There are situations where the color range will go to something insane - potentially producing infs and NaNs even.
// This is a safety measure to prevent that.
// As to the specific number there - allegedly some HDR displays expect values to be in the 0-11.2 range. Citation needed.
// -Geenz 2025-03-05
color = mix(color, vec3(1), isinf(color));
color = mix(color, vec3(0.0), isnan(color));
return clamp(color, vec3(0.0), vec3(11.2));
}
float calcLegacyDistanceAttenuation(float distance, float falloff)
{
float dist_atten = 1.0 - clamp((distance + falloff)/(1.0 + falloff), 0.0, 1.0);

View File

@ -69,6 +69,8 @@ void dofSampleNear(inout vec4 diff, inout float w, float min_sc, vec2 tc)
w += wg;
}
vec3 clampHDRRange(vec3 color);
void main()
{
vec2 tc = vary_fragcoord.xy;
@ -120,5 +122,6 @@ void main()
diff /= w;
}
diff.rgb = clampHDRRange(diff.rgb);
frag_color = diff;
}

View File

@ -43,6 +43,8 @@ vec3 legacyGamma(vec3 color)
return c;
}
vec3 clampHDRRange(vec3 color);
void main()
{
//this is the one of the rare spots where diffuseRect contains linear color values (not sRGB)
@ -53,6 +55,7 @@ void main()
diff.rgb = legacyGamma(diff.rgb);
#endif
frag_color = max(diff, vec4(0));
diff.rgb = clampHDRRange(diff.rgb);
frag_color = diff;
}

View File

@ -71,6 +71,7 @@ float noise(vec2 x) {
//=============================
vec3 clampHDRRange(vec3 color);
void main()
@ -84,6 +85,7 @@ void main()
diff.rgb += nz*0.003;
#endif
diff.rgb = clampHDRRange(diff.rgb);
frag_color = diff;
gl_FragDepth = texture(depthMap, vary_fragcoord.xy).r;

View File

@ -34,6 +34,8 @@ in vec2 vary_fragcoord;
vec3 linear_to_srgb(vec3 cl);
vec3 toneMap(vec3 color);
vec3 clampHDRRange(vec3 color);
void main()
{
//this is the one of the rare spots where diffuseRect contains linear color values (not sRGB)
@ -45,6 +47,7 @@ void main()
diff.rgb = clamp(diff.rgb, vec3(0.0), vec3(1.0));
#endif
diff.rgb = clampHDRRange(diff.rgb);
//debugExposure(diff.rgb);
frag_color = max(diff, vec4(0));
}

View File

@ -154,6 +154,7 @@ void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, ou
if (classic_mode < 1)
{
amblit = srgb_to_linear(amblit);
amblit = vec3(dot(amblit, vec3(0.2126, 0.7152, 0.0722)));
sunlit = srgb_to_linear(sunlit);
}

View File

@ -104,6 +104,7 @@ vec3 pbrBaseLight(vec3 diffuseColor,
vec3 atten);
GBufferInfo getGBuffer(vec2 screenpos);
vec3 clampHDRRange(vec3 color);
void adjustIrradiance(inout vec3 irradiance, float ambocc)
{
@ -278,6 +279,7 @@ void main()
float final_scale = 1;
if (classic_mode > 0)
final_scale = 1.1;
frag_color.rgb = max(color.rgb * final_scale, vec3(0)); //output linear since local lights will be added to this shader's results
frag_color.rgb = clampHDRRange(color.rgb * final_scale); //output linear since local lights will be added to this shader's results
frag_color.a = 0.0;
}

View File

@ -263,7 +263,12 @@ void main()
vec3 refPos = getPositionWithNDC(vec3(distort*2.0-vec2(1.0), depth*2.0-1.0));
// Calculate some distance fade in the water to better assist with refraction blending and reducing the refraction texture's "disconnect".
fade = max(0,min(1, (pos.z - refPos.z) / 10)) * water_mask;
#ifdef SHORELINE_FADE
fade = max(0,min(1, (pos.z - refPos.z) / 10));
#else
fade = 1;
#endif
fade *= water_mask;
distort2 = mix(distort, distort2, min(1, fade * 10));
depth = texture(depthMap, distort2).r;

View File

@ -1,4 +1,4 @@
version 73
version 74
// The version number above should be incremented IF AND ONLY IF some
// change has been made that is sufficiently important to justify
// resetting the graphics preferences of all users to the recommended
@ -86,6 +86,7 @@ RenderTonemapType 1 1
RenderTonemapMix 1 1
RenderDisableVintageMode 1 1
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
// Low Graphics Settings
@ -128,6 +129,7 @@ RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 512
RenderReflectionProbeCount 1 1
//
// Medium Low Graphics Settings
@ -170,6 +172,7 @@ RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 1024
RenderReflectionProbeCount 1 32
//
// Medium Graphics Settings (standard)
@ -211,6 +214,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 64
//
// Medium High Graphics Settings
@ -241,7 +245,7 @@ RenderFSAASamples 1 1
RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 2
RenderReflectionProbeLevel 1 1
RenderMirrors 1 0
RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 6
@ -252,6 +256,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 64
//
// High Graphics Settings (SSAO + sun shadows)
@ -282,7 +287,7 @@ RenderFSAASamples 1 2
RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 3
RenderReflectionProbeLevel 1 2
RenderMirrors 1 0
RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 8
@ -293,6 +298,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 128
//
// High Ultra Graphics Settings (deferred + SSAO + all shadows)
@ -334,6 +340,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
// Ultra graphics (REALLY PURTY!)
@ -375,6 +382,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
// Class Unknown Hardware (unknown)
@ -408,6 +416,7 @@ RenderReflectionProbeDetail 0 -1
RenderMirrors 0 0
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 0 0
list Intel
RenderAnisotropic 1 0
@ -429,6 +438,7 @@ RenderMirrors 0 0
RenderGLMultiThreadedTextures 0 0
RenderGLMultiThreadedMedia 0 0
RenderDisableVintageMode 1 0
RenderReflectionProbeCount 0 0
list TexUnit16orLess
RenderTerrainPBRDetail 1 -1

View File

@ -1,4 +1,4 @@
version 53
version 54
// The version number above should be incremented IF AND ONLY IF some
// change has been made that is sufficiently important to justify
// resetting the graphics preferences of all users to the recommended
@ -86,6 +86,7 @@ RenderTonemapType 1 1
RenderTonemapMix 1 1
RenderDisableVintageMode 1 1
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
// Low Graphics Settings
@ -128,6 +129,7 @@ RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 512
RenderReflectionProbeCount 1 1
//
// Medium Low Graphics Settings
@ -170,6 +172,7 @@ RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 1024
RenderReflectionProbeCount 1 32
//
// Medium Graphics Settings (standard)
@ -211,6 +214,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 64
//
// Medium High Graphics Settings
@ -241,7 +245,7 @@ RenderFSAASamples 1 1
RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 2
RenderReflectionProbeLevel 1 1
RenderMirrors 1 0
RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 6
@ -252,6 +256,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 64
//
// High Graphics Settings (SSAO + sun shadows)
@ -282,7 +287,7 @@ RenderFSAASamples 1 2
RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 3
RenderReflectionProbeLevel 1 2
RenderMirrors 1 0
RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 8
@ -293,6 +298,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 128
//
// High Ultra Graphics Settings (deferred + SSAO + all shadows)
@ -334,6 +340,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
// Ultra graphics (REALLY PURTY!)
@ -375,6 +382,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
// Class Unknown Hardware (unknown)
@ -408,6 +416,7 @@ RenderReflectionProbeDetail 0 -1
RenderMirrors 0 0
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 0 0
list Intel
RenderAnisotropic 1 0
@ -431,6 +440,7 @@ RenderMirrors 0 0
RenderGLMultiThreadedTextures 0 0
RenderGLMultiThreadedMedia 0 0
RenderDisableVintageMode 1 0
RenderReflectionProbeCount 0 0
list TexUnit16orLess
RenderTerrainPBRDetail 1 -1

View File

@ -1,4 +1,4 @@
version 72
version 73
// The version number above should be incremented IF AND ONLY IF some
// change has been made that is sufficiently important to justify
// resetting the graphics preferences of all users to the recommended
@ -86,6 +86,7 @@ RenderTonemapMix 1 1
RenderDisableVintageMode 1 1
RenderDownScaleMethod 1 0
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
// Low Graphics Settings
@ -128,6 +129,7 @@ RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 512
RenderReflectionProbeCount 1 1
//
// Medium Low Graphics Settings
@ -170,6 +172,7 @@ RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 1024
RenderReflectionProbeCount 1 32
//
// Medium Graphics Settings (standard)
@ -211,6 +214,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 64
//
// Medium High Graphics Settings
@ -252,6 +256,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 64
//
// High Graphics Settings (SSAO + sun shadows)
@ -293,6 +298,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 128
//
// High Ultra Graphics Settings (SSAO + all shadows)
@ -334,6 +340,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
// Ultra graphics (REALLY PURTY!)
@ -375,6 +382,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
// Class Unknown Hardware (unknown)
@ -407,6 +415,7 @@ RenderShadowDetail 0 0
RenderMirrors 0 0
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 0 0
list TexUnit8orLess
RenderDeferredSSAO 0 0
@ -447,6 +456,7 @@ RenderReflectionProbeDetail 0 0
RenderReflectionsEnabled 0 0
RenderMirrors 0 0
RenderDisableVintageMode 1 0
RenderReflectionProbeCount 0 0
list VaryingVectors16orLess
RenderTerrainPBRPlanarSampleCount 1 1

View File

@ -134,6 +134,36 @@ void FSPanelFace::updateSelectedGLTFMaterials(std::function<void(LLGLTFMaterial*
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&select_func);
}
void FSPanelFace::updateSelectedGLTFMaterialsWithScale(std::function<void(LLGLTFMaterial*, const F32, const F32)> func)
{
struct LLSelectedTEGLTFMaterialFunctor : public LLSelectedTEFunctor
{
LLSelectedTEGLTFMaterialFunctor(std::function<void(LLGLTFMaterial*, const F32, const F32)> func) : mFunc(func) {}
virtual ~LLSelectedTEGLTFMaterialFunctor() {};
bool apply(LLViewerObject* object, S32 face) override
{
LLGLTFMaterial new_override;
const LLTextureEntry* tep = object->getTE(face);
if (tep->getGLTFMaterialOverride())
{
new_override = *tep->getGLTFMaterialOverride();
}
U32 s_axis = VX;
U32 t_axis = VY;
LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
mFunc(&new_override, object->getScale().mV[s_axis], object->getScale().mV[t_axis]);
LLGLTFMaterialList::queueModify(object, face, &new_override);
return true;
}
std::function<void(LLGLTFMaterial*, const F32, const F32)> mFunc;
} select_func(func);
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&select_func);
}
template<typename T>
void readSelectedGLTFMaterial(std::function<T(const LLGLTFMaterial*)> func, T& value, bool& identical, bool has_tolerance, T tolerance)
{
@ -154,6 +184,36 @@ void readSelectedGLTFMaterial(std::function<T(const LLGLTFMaterial*)> func, T& v
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&select_func, value, has_tolerance, tolerance);
}
void getSelectedGLTFMaterialMaxRepeats(LLGLTFMaterial::TextureInfo channel, F32& repeats, bool& identical)
{
// The All channel should read base color values
if (channel == LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_COUNT)
channel = LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_BASE_COLOR;
struct LLSelectedTEGetGLTFMaterialMaxRepeatsFunctor : public LLSelectedTEGetFunctor<F32>
{
LLSelectedTEGetGLTFMaterialMaxRepeatsFunctor(LLGLTFMaterial::TextureInfo channel) : mChannel(channel) {}
virtual ~LLSelectedTEGetGLTFMaterialMaxRepeatsFunctor() {};
F32 get(LLViewerObject* object, S32 face) override
{
const LLTextureEntry* tep = object->getTE(face);
const LLGLTFMaterial* render_material = tep->getGLTFRenderMaterial();
if (!render_material)
return 0.f;
U32 s_axis = VX;
U32 t_axis = VY;
LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
F32 repeats_u = render_material->mTextureTransform[mChannel].mScale[VX] / object->getScale().mV[s_axis];
F32 repeats_v = render_material->mTextureTransform[mChannel].mScale[VY] / object->getScale().mV[t_axis];
return llmax(repeats_u, repeats_v);
}
LLGLTFMaterial::TextureInfo mChannel;
} max_repeats_func(channel);
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&max_repeats_func, repeats);
}
//
// keep LLRenderMaterialFunctor in sync with llmaterialeditor.cpp - Would be nice if we
// had this in its own file so we could include it from both sides ... -Zi
@ -560,7 +620,8 @@ std::string USE_TEXTURE_LABEL; // subtly different (and more clear) name fr
FSPanelFace::FSPanelFace() :
LLPanel(),
mNeedMediaTitle(true),
mUnsavedChanges(0)
mUnsavedChanges(0),
mExcludeWater(false)
{
// register callbacks before buildFromFile() or they won't work!
mCommitCallbackRegistrar.add("BuildTool.Flip", boost::bind(&FSPanelFace::onCommitFlip, this, _2));
@ -599,6 +660,9 @@ void FSPanelFace::onMatTabChange()
static S32 last_mat = -1;
if( auto curr_mat = getCurrentMaterialType(); curr_mat != last_mat )
{
// Fixes some UI desync
updateUI(true);
LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
LLViewerObject* objectp = node ? node->getObject() : NULL;
if(objectp)
@ -627,6 +691,32 @@ void FSPanelFace::onMatTabChange()
}
}
void FSPanelFace::onMatChannelTabChange()
{
// Fixes some UI desync
static S32 last_channel = -1;
if (auto curr_channel = getCurrentMatChannel(); curr_channel != last_channel)
{
last_channel = curr_channel;
if (!mSetChannelTab)
updateUI(true);
}
mSetChannelTab = false;
}
void FSPanelFace::onPBRChannelTabChange()
{
// Fixes some UI desync
static S32 last_channel = -1;
if (auto curr_channel = getCurrentPBRChannel(); curr_channel != last_channel)
{
last_channel = curr_channel;
if (!mSetChannelTab)
updateUI(true);
}
mSetChannelTab = false;
}
bool FSPanelFace::postBuild()
{
//
@ -651,9 +741,9 @@ bool FSPanelFace::postBuild()
SKIN_CHECK(mComboAlphaMode = findChild<LLComboBox>("combobox alphamode"));
SKIN_CHECK(mCtrlMaskCutoff = findChild<LLSpinCtrl>("maskcutoff"));
SKIN_CHECK(mCheckFullbright = findChild<LLCheckBoxCtrl>("checkbox fullbright"));
SKIN_CHECK(mCheckHideWater = findChild<LLCheckBoxCtrl>("checkbox_hide_water"));
// Blinn-Phong texture transforms and controls
SKIN_CHECK(mLabelTexGen = findChild<LLView>("tex gen"));
SKIN_CHECK(mComboTexGen = findChild<LLComboBox>("combobox texgen"));
SKIN_CHECK(mCheckPlanarAlign = findChild<LLCheckBoxCtrl>("checkbox planar align"));
SKIN_CHECK(mLabelBumpiness = findChild<LLView>("label bumpiness"));
@ -725,6 +815,9 @@ bool FSPanelFace::postBuild()
// hook up callbacks and do setup of all relevant UI elements here
//
mTabsPBRMatMedia->setCommitCallback(boost::bind(&FSPanelFace::onMatTabChange, this));
mTabsMatChannel->setCommitCallback(boost::bind(&FSPanelFace::onMatChannelTabChange, this));
mTabsPBRChannel->setCommitCallback(boost::bind(&FSPanelFace::onPBRChannelTabChange, this));
// common controls and parameters for Blinn-Phong and PBR
mBtnCopyFaces->setCommitCallback(boost::bind(&FSPanelFace::onCopyFaces, this));
mBtnPasteFaces->setCommitCallback(boost::bind(&FSPanelFace::onPasteFaces, this));
@ -736,6 +829,7 @@ bool FSPanelFace::postBuild()
mComboAlphaMode->setCommitCallback(boost::bind(&FSPanelFace::onCommitAlphaMode, this));
mCtrlMaskCutoff->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialMaskCutoff, this));
mCheckFullbright->setCommitCallback(boost::bind(&FSPanelFace::onCommitFullbright, this));
mCheckHideWater->setCommitCallback(boost::bind(&FSPanelFace::onCommitHideWater, this));
// Blinn-Phong texture transforms and controls
mComboTexGen->setCommitCallback(boost::bind(&FSPanelFace::onCommitTexGen, this));
@ -885,9 +979,9 @@ bool FSPanelFace::postBuild()
changePrecision(gSavedSettings.getS32("FSBuildToolDecimalPrecision"));
selectMaterialType(MATMEDIA_PBR); // TODO: add tab switching signal
selectMatChannel(LLRender::DIFFUSE_MAP); // TODO: add tab switching signal
selectPBRChannel(LLRender::NUM_TEXTURE_CHANNELS); // TODO: add tab switching signal
selectMaterialType(MATMEDIA_PBR);
selectMatChannel(LLRender::DIFFUSE_MAP);
selectPBRChannel(LLRender::NUM_TEXTURE_CHANNELS);
return true;
}
@ -1565,6 +1659,21 @@ void FSPanelFace::updateUI(bool force_set_values /*false*/)
mCtrlColorTransp->setEnabled(editable );
mColorTransPercent->setMouseOpaque(editable );
// Water exclusion
mExcludeWater = (id == IMG_ALPHA_GRAD) && normmap_id.isNull() && specmap_id.isNull() && (transparency == 0);
{
mCheckHideWater->setEnabled(editable && !has_pbr_material && !isMediaTexSelected());
mCheckHideWater->set(mExcludeWater);
editable &= !mExcludeWater;
// disable controls for water exclusion face after updateVisibility, so the whole panel is not hidden
// TODO
// mComboMatMedia->setEnabled(editable);
// mRadioMaterialType->setEnabled(editable);
// mRadioPbrType->setEnabled(editable);
// mCheckSyncSettings->setEnabled(editable);
}
// Shiny
U8 shiny = 0;
{
@ -1985,7 +2094,6 @@ void FSPanelFace::updateUI(bool force_set_values /*false*/)
mComboTexGen->setEnabled(editable);
mComboTexGen->setTentative(!identical);
mLabelTexGen->setEnabled(editable);
}
{
@ -2005,13 +2113,19 @@ void FSPanelFace::updateUI(bool force_set_values /*false*/)
F32 repeats_norm = 1.f;
F32 repeats_spec = 1.f;
F32 repeats_pbr_basecolor = 1.f;
F32 repeats_pbr_metallic_roughness = 1.f;
F32 repeats_pbr_normal = 1.f;
F32 repeats_pbr_emissive = 1.f;
bool identical_diff_repeats = false;
bool identical_norm_repeats = false;
bool identical_spec_repeats = false;
LLSelectedTE::getMaxDiffuseRepeats(repeats_diff, identical_diff_repeats);
LLSelectedTEMaterial::getMaxNormalRepeats(repeats_norm, identical_norm_repeats);
LLSelectedTEMaterial::getMaxSpecularRepeats(repeats_spec, identical_spec_repeats);
bool identical_pbr_basecolor_repeats = false;
bool identical_pbr_metallic_roughness_repeats = false;
bool identical_pbr_normal_repeats = false;
bool identical_pbr_emissive_repeats = false;
S32 index = mComboTexGen->getCurrentIndex();
bool enabled = editable && (index != 1);
@ -2021,15 +2135,26 @@ void FSPanelFace::updateUI(bool force_set_values /*false*/)
F32 repeats = 1.0f;
LLRender::eTexIndex material_channel = LLRender::DIFFUSE_MAP;
if (material_selection == MATMEDIA_MATERIAL)
if (material_selection != MATMEDIA_PBR)
{
material_channel = getCurrentMatChannel();
LLSelectedTE::getMaxDiffuseRepeats(repeats_diff, identical_diff_repeats);
LLSelectedTEMaterial::getMaxNormalRepeats(repeats_norm, identical_norm_repeats);
LLSelectedTEMaterial::getMaxSpecularRepeats(repeats_spec, identical_spec_repeats);
}
// TODO: check if repeats per meter even apply to PBR materials -Zi
else if (material_selection == MATMEDIA_PBR)
{
enabled = editable;
material_channel = getCurrentPBRChannel();
getSelectedGLTFMaterialMaxRepeats(LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_BASE_COLOR,
repeats_pbr_basecolor, identical_pbr_basecolor_repeats);
getSelectedGLTFMaterialMaxRepeats(LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS,
repeats_pbr_metallic_roughness, identical_pbr_metallic_roughness_repeats);
getSelectedGLTFMaterialMaxRepeats(LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_NORMAL,
repeats_pbr_normal, identical_pbr_normal_repeats);
getSelectedGLTFMaterialMaxRepeats(LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_EMISSIVE,
repeats_pbr_emissive, identical_pbr_emissive_repeats);
}
switch (material_channel)
@ -2069,11 +2194,40 @@ void FSPanelFace::updateUI(bool force_set_values /*false*/)
repeats = repeats_norm;
}
break;
case LLRender::NUM_TEXTURE_CHANNELS:
case LLRender::BASECOLOR_MAP:
{
identical_repeats = identical_pbr_basecolor_repeats;
repeats = repeats_pbr_basecolor;
}
break;
case LLRender::METALLIC_ROUGHNESS_MAP:
{
identical_repeats = identical_pbr_metallic_roughness_repeats;
repeats = repeats_pbr_metallic_roughness;
}
break;
case LLRender::GLTF_NORMAL_MAP:
{
identical_repeats = identical_pbr_normal_repeats;
repeats = repeats_pbr_normal;
}
break;
case LLRender::EMISSIVE_MAP:
{
identical_repeats = identical_pbr_emissive_repeats;
repeats = repeats_pbr_emissive;
}
break;
}
bool repeats_tentative = !identical_repeats;
if (force_set_values)
if (force_set_values || material_selection == MATMEDIA_PBR)
{
//onCommit, previosly edited element updates related ones
mCtrlRpt->forceSetValue(editable ? repeats : 1.0f);
@ -2444,7 +2598,9 @@ void FSPanelFace::updateCopyTexButton()
mBtnCopyFaces->setEnabled(objectp && objectp->getPCode() == LL_PCODE_VOLUME && objectp->permModify()
&& !objectp->isPermanentEnforced() && !objectp->isInventoryPending()
&& (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1)
&& LLMaterialEditor::canClipboardObjectsMaterial());
&& LLMaterialEditor::canClipboardObjectsMaterial()
&& !mExcludeWater
);
std::string tooltip = (objectp && objectp->isInventoryPending()) ? LLTrans::getString("LoadingContents") : getString("paste_options");
mBtnCopyFaces->setToolTip(tooltip);
}
@ -3235,6 +3391,7 @@ void FSPanelFace::onCommitShinyColor()
void FSPanelFace::onCommitAlpha()
{
mCtrlColorTransp->setFocus(true);
sendAlpha();
}
@ -3262,6 +3419,13 @@ void FSPanelFace::onSelectShinyColor()
void FSPanelFace::updateVisibility(LLViewerObject* objectp /* = nullptr */)
{
S32 materials_media = getCurrentMaterialType();
bool show_media = materials_media == MATMEDIA_MEDIA;
bool show_material = materials_media == MATMEDIA_MATERIAL;
// Shared material controls
mCheckSyncMaterials->setVisible(show_material || show_media);
updateAlphaControls();
// TODO: is this still needed? -Zi
updateShinyControls();
@ -3382,8 +3546,40 @@ void FSPanelFace::onCommitFullbright()
sendFullbright();
}
void FSPanelFace::onCommitHideWater()
{
if (mCheckHideWater->get())
{
LLHandle<LLPanel> handle = getHandle();
LLNotificationsUtil::add("WaterExclusionSurfacesWarning", LLSD(), LLSD(),
[handle](const LLSD& notification, const LLSD& response)
{
if(FSPanelFace* panel = (FSPanelFace*)handle.get())
{
if (LLNotificationsUtil::getSelectedOption(notification, response) == 1)
{
panel->mCheckHideWater->setValue(false);
return;
}
// apply invisiprim texture and reset related params to set water exclusion surface
panel->sendBump(0);
panel->sendShiny(0);
LLSelectMgr::getInstance()->selectionSetAlphaOnly(1.f);
LLSelectMgr::getInstance()->selectionSetImage(IMG_ALPHA_GRAD);
LLSelectedTEMaterial::setDiffuseAlphaMode(panel, LLMaterial::DIFFUSE_ALPHA_MODE_BLEND);
}
});
}
else
{
// reset texture to default plywood
LLSelectMgr::getInstance()->selectionSetImage(DEFAULT_OBJECT_TEXTURE);
}
}
void FSPanelFace::onCommitGlow()
{
mCtrlGlow->setFocus(true);
sendGlow();
}
@ -3495,6 +3691,7 @@ void FSPanelFace::onCommitPbr(const LLUICtrl* pbr_ctrl)
}
else if (pbr_ctrl == mAlphaPBR)
{
mAlphaPBR->setFocus(true);
mUnsavedChanges |= MATERIAL_BASE_COLOR_DIRTY;
}
else if (pbr_ctrl == mAlphaModePBR)
@ -3503,14 +3700,17 @@ void FSPanelFace::onCommitPbr(const LLUICtrl* pbr_ctrl)
}
else if (pbr_ctrl == mMaskCutoffPBR)
{
mMaskCutoffPBR->setFocus(true);
mUnsavedChanges |= MATERIAL_ALPHA_CUTOFF_DIRTY;
}
else if (pbr_ctrl == mMetallicFactorPBR)
{
mMetallicFactorPBR->setFocus(true);
mUnsavedChanges |= MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY;
}
else if (pbr_ctrl == mRoughnessFactorPBR)
{
mRoughnessFactorPBR->setFocus(true);
mUnsavedChanges |= MATERIAL_METALLIC_ROUGHTNESS_ROUGHNESS_DIRTY;
}
}
@ -3823,6 +4023,7 @@ void FSPanelFace::syncOffsetY(FSPanelFace* self, F32 offsetV)
void FSPanelFace::onCommitMaterialBumpyOffsetX()
{
mCtrlBumpyOffsetU->setFocus(true);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
syncOffsetX(this, getCurrentBumpyOffsetU());
@ -3835,6 +4036,7 @@ void FSPanelFace::onCommitMaterialBumpyOffsetX()
void FSPanelFace::onCommitMaterialBumpyOffsetY()
{
mCtrlBumpyOffsetV->setFocus(true);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
syncOffsetY(this, getCurrentBumpyOffsetV());
@ -3847,6 +4049,7 @@ void FSPanelFace::onCommitMaterialBumpyOffsetY()
void FSPanelFace::onCommitMaterialShinyOffsetX()
{
mCtrlShinyOffsetU->setFocus(true);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
syncOffsetX(this, getCurrentShinyOffsetU());
@ -3859,6 +4062,7 @@ void FSPanelFace::onCommitMaterialShinyOffsetX()
void FSPanelFace::onCommitMaterialShinyOffsetY()
{
mCtrlShinyOffsetV->setFocus(true);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
syncOffsetY(this, getCurrentShinyOffsetV());
@ -3887,6 +4091,7 @@ void FSPanelFace::syncRepeatY(FSPanelFace* self, F32 scaleV)
void FSPanelFace::onCommitMaterialBumpyScaleX()
{
mCtrlBumpyScaleU->setFocus(true);
F32 bumpy_scale_u = getCurrentBumpyScaleU();
if (isIdenticalPlanarTexgen())
{
@ -3906,6 +4111,7 @@ void FSPanelFace::onCommitMaterialBumpyScaleX()
void FSPanelFace::onCommitMaterialBumpyScaleY()
{
mCtrlBumpyScaleV->setFocus(true);
F32 bumpy_scale_v = getCurrentBumpyScaleV();
if (isIdenticalPlanarTexgen())
{
@ -3925,6 +4131,7 @@ void FSPanelFace::onCommitMaterialBumpyScaleY()
void FSPanelFace::onCommitMaterialShinyScaleX()
{
mCtrlShinyScaleU->setFocus(true);
F32 shiny_scale_u = getCurrentShinyScaleU();
if (isIdenticalPlanarTexgen())
{
@ -3944,6 +4151,7 @@ void FSPanelFace::onCommitMaterialShinyScaleX()
void FSPanelFace::onCommitMaterialShinyScaleY()
{
mCtrlShinyScaleV->setFocus(true);
F32 shiny_scale_v = getCurrentShinyScaleV();
if (isIdenticalPlanarTexgen())
{
@ -3971,6 +4179,7 @@ void FSPanelFace::syncMaterialRot(FSPanelFace* self, F32 rot, int te)
void FSPanelFace::onCommitMaterialBumpyRot()
{
mCtrlBumpyRot->setFocus(true);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
mCtrlTexRot->forceSetValue(LLSD(getCurrentBumpyRot()));
@ -3995,6 +4204,7 @@ void FSPanelFace::onCommitMaterialBumpyRot()
void FSPanelFace::onCommitMaterialShinyRot()
{
mCtrlShinyRot->setFocus(true);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
mCtrlTexRot->forceSetValue(LLSD(getCurrentShinyRot()));
@ -4019,21 +4229,25 @@ void FSPanelFace::onCommitMaterialShinyRot()
void FSPanelFace::onCommitMaterialGloss()
{
mCtrlGlossiness->setFocus(true);
LLSelectedTEMaterial::setSpecularLightExponent(this, getCurrentGlossiness());
}
void FSPanelFace::onCommitMaterialEnv()
{
mCtrlEnvironment->setFocus(true);
LLSelectedTEMaterial::setEnvironmentIntensity(this, getCurrentEnvIntensity());
}
void FSPanelFace::onCommitMaterialMaskCutoff()
{
mCtrlMaskCutoff->setFocus(true);
LLSelectedTEMaterial::setAlphaMaskCutoff(this, getCurrentAlphaMaskCutoff());
}
void FSPanelFace::onCommitTextureScaleX()
{
mCtrlTexScaleU->setFocus(true);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
F32 bumpy_scale_u = (F32)mCtrlTexScaleU->getValue().asReal();
@ -4052,6 +4266,7 @@ void FSPanelFace::onCommitTextureScaleX()
void FSPanelFace::onCommitTextureScaleY()
{
mCtrlTexScaleV->setFocus(true);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
F32 bumpy_scale_v = (F32)mCtrlTexScaleV->getValue().asReal();
@ -4070,6 +4285,7 @@ void FSPanelFace::onCommitTextureScaleY()
void FSPanelFace::onCommitTextureRot()
{
mCtrlTexRot->setFocus(true);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
syncMaterialRot(this, (F32)mCtrlTexRot->getValue().asReal());
@ -4084,6 +4300,7 @@ void FSPanelFace::onCommitTextureRot()
void FSPanelFace::onCommitTextureOffsetX()
{
mCtrlTexOffsetU->setFocus(true);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
syncOffsetX(this, (F32)mCtrlTexOffsetU->getValue().asReal());
@ -4097,6 +4314,7 @@ void FSPanelFace::onCommitTextureOffsetX()
void FSPanelFace::onCommitTextureOffsetY()
{
mCtrlTexOffsetV->setFocus(true);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
syncOffsetY(this, (F32)mCtrlTexOffsetV->getValue().asReal());
@ -4111,12 +4329,15 @@ void FSPanelFace::onCommitTextureOffsetY()
// Commit the number of repeats per meter
void FSPanelFace::onCommitRepeatsPerMeter()
{
mCtrlRpt->setFocus(true);
S32 materials_media = getCurrentMaterialType();
LLRender::eTexIndex material_channel = LLRender::DIFFUSE_MAP;
// TODO: check if repeats per meter is even used for PBR -Zi
LLGLTFMaterial::TextureInfo material_type = LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR;
if (materials_media == MATMEDIA_PBR)
{
material_channel = getCurrentPBRChannel();
material_type = getCurrentPBRType(material_channel);
}
if (materials_media == MATMEDIA_MATERIAL)
@ -4133,23 +4354,21 @@ void FSPanelFace::onCommitRepeatsPerMeter()
bool identical_scale_t = false;
LLSelectedTE::getObjectScaleS(obj_scale_s, identical_scale_s);
LLSelectedTE::getObjectScaleS(obj_scale_t, identical_scale_t);
LLSelectedTE::getObjectScaleT(obj_scale_t, identical_scale_t);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
if (mCheckSyncMaterials->isAvailable() && gSavedSettings.getBOOL("SyncMaterialSettings"))
{
LLSelectMgr::getInstance()->selectionTexScaleAutofit(repeats_per_meter);
mCtrlBumpyScaleU->setValue(obj_scale_s * repeats_per_meter);
mCtrlBumpyScaleV->setValue(obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::setNormalRepeatX(this, obj_scale_s * repeats_per_meter);
LLSelectedTEMaterial::setNormalRepeatY(this, obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::selectionNormalScaleAutofit(this, repeats_per_meter);
mCtrlShinyScaleU->setValue(obj_scale_s * repeats_per_meter);
mCtrlShinyScaleV->setValue(obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::setSpecularRepeatX(this, obj_scale_s * repeats_per_meter);
LLSelectedTEMaterial::setSpecularRepeatY(this, obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::selectionSpecularScaleAutofit(this, repeats_per_meter);
}
else
{
@ -4166,8 +4385,7 @@ void FSPanelFace::onCommitRepeatsPerMeter()
mCtrlBumpyScaleU->setValue(obj_scale_s * repeats_per_meter);
mCtrlBumpyScaleV->setValue(obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::setNormalRepeatX(this, obj_scale_s * repeats_per_meter);
LLSelectedTEMaterial::setNormalRepeatY(this, obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::selectionNormalScaleAutofit(this, repeats_per_meter);
}
break;
@ -4176,8 +4394,21 @@ void FSPanelFace::onCommitRepeatsPerMeter()
mCtrlShinyScaleU->setValue(obj_scale_s * repeats_per_meter);
mCtrlShinyScaleV->setValue(obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::setSpecularRepeatX(this, obj_scale_s * repeats_per_meter);
LLSelectedTEMaterial::setSpecularRepeatY(this, obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::selectionSpecularScaleAutofit(this, repeats_per_meter);
}
break;
case LLRender::BASECOLOR_MAP:
case LLRender::METALLIC_ROUGHNESS_MAP:
case LLRender::GLTF_NORMAL_MAP:
case LLRender::EMISSIVE_MAP:
case LLRender::NUM_TEXTURE_CHANNELS:
{
updateGLTFTextureTransformWithScale(material_type, [&](LLGLTFMaterial::TextureTransform* new_transform, F32 scale_s, F32 scale_t)
{
new_transform->mScale.mV[VX] = scale_s * repeats_per_meter;
new_transform->mScale.mV[VY] = scale_t * repeats_per_meter;
});
}
break;
@ -5143,10 +5374,33 @@ void FSPanelFace::updateGLTFTextureTransform(const LLGLTFMaterial::TextureInfo t
}
}
void FSPanelFace::updateGLTFTextureTransformWithScale(const LLGLTFMaterial::TextureInfo texture_info, std::function<void(LLGLTFMaterial::TextureTransform*, const F32, const F32)> edit)
{
if (texture_info == LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT)
{
updateSelectedGLTFMaterialsWithScale([&](LLGLTFMaterial* new_override, const F32 scale_s, const F32 scale_t)
{
for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
{
LLGLTFMaterial::TextureTransform& new_transform = new_override->mTextureTransform[(LLGLTFMaterial::TextureInfo)i];
edit(&new_transform, scale_s, scale_t);
}
});
}
else
{
updateSelectedGLTFMaterialsWithScale([&](LLGLTFMaterial* new_override, const F32 scale_s, const F32 scale_t)
{
LLGLTFMaterial::TextureTransform& new_transform = new_override->mTextureTransform[texture_info];
edit(&new_transform, scale_s, scale_t);
});
}
}
void FSPanelFace::setMaterialOverridesFromSelection()
{
// TODO: move to .h -Zi
std::map<LLGLTFMaterial::TextureInfo, std::string> spinner_suffixes{
static std::map<LLGLTFMaterial::TextureInfo, std::string> spinner_suffixes{
{ LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_BASE_COLOR, "_Base" },
{ LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_NORMAL, "_Normal" },
{ LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, "_Metallic" },
@ -5249,6 +5503,16 @@ void FSPanelFace::setMaterialOverridesFromSelection()
gltfCtrlTextureRotation->setTentative(!rotation_same);
gltfCtrlTextureOffsetU->setTentative(!offset_u_same);
gltfCtrlTextureOffsetV->setTentative(!offset_v_same);
// Fixes some UI desync
if (getCurrentMaterialType() == MATMEDIA_PBR)
{
F32 repeats = 1.f;
bool identical = false;
getSelectedGLTFMaterialMaxRepeats(getPBRDropChannel(), repeats, identical);
mCtrlRpt->forceSetValue(repeats);
mCtrlRpt->setTentative(!identical);
}
}
void FSPanelFace::Selection::connect()
@ -5328,10 +5592,10 @@ bool FSPanelFace::Selection::compareSelection()
return selection_changed;
}
void FSPanelFace::onCommitGLTFUVSpinner(const LLUICtrl* ctrl, const LLSD& user_data)
void FSPanelFace::onCommitGLTFUVSpinner(LLUICtrl* ctrl, const LLSD& user_data)
{
// TODO: put into .h -Zi
std::map<std::string, LLGLTFMaterial::TextureInfo> types =
static std::map<std::string, LLGLTFMaterial::TextureInfo> types =
{
{ "all", LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT },
{ "base", LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR },
@ -5352,6 +5616,7 @@ void FSPanelFace::onCommitGLTFUVSpinner(const LLUICtrl* ctrl, const LLSD& user_d
const std::string& spinner_name = ctrl->getName();
const float value = (F32)ctrl->getValue().asReal();
ctrl->setFocus(true);
if (LLStringUtil::startsWith(spinner_name, "gltfTextureScaleU"))
{
@ -5470,6 +5735,26 @@ bool FSPanelFace::isIdenticalPlanarTexgen()
return (identical_texgen && (selected_texgen == LLTextureEntry::TEX_GEN_PLANAR));
}
bool FSPanelFace::isMediaTexSelected()
{
LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
if (LLViewerObject* objectp = node->getObject())
{
S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces());
for (S32 te = 0; te < num_tes; ++te)
{
if (node->isTESelected(te))
{
if (objectp->getTE(te) && objectp->getTE(te)->hasMedia())
{
return true;
}
}
}
}
return false;
}
void FSPanelFace::LLSelectedTE::getFace(LLFace*& face_to_return, bool& identical_face)
{
struct LLSelectedTEGetFace : public LLSelectedTEGetFunctor<LLFace *>
@ -5597,6 +5882,7 @@ void FSPanelFace::LLSelectedTEMaterial::getMaxSpecularRepeats(F32& repeats, bool
LLMaterial* mat = object->getTEref(face).getMaterialParams().get();
U32 s_axis = VX;
U32 t_axis = VY;
LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
F32 repeats_s = 1.0f;
F32 repeats_t = 1.0f;
if (mat)
@ -5622,6 +5908,7 @@ void FSPanelFace::LLSelectedTEMaterial::getMaxNormalRepeats(F32& repeats, bool&
LLMaterial* mat = object->getTEref(face).getMaterialParams().get();
U32 s_axis = VX;
U32 t_axis = VY;
LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
F32 repeats_s = 1.0f;
F32 repeats_t = 1.0f;
if (mat)
@ -5669,6 +5956,62 @@ void FSPanelFace::LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(U8& diffuse_a
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &get_diff_mode, diffuse_alpha_mode);
}
void FSPanelFace::LLSelectedTEMaterial::selectionNormalScaleAutofit(FSPanelFace* panel_face, F32 repeats_per_meter)
{
struct f : public LLSelectedTEFunctor
{
FSPanelFace* mFacePanel;
F32 mRepeatsPerMeter;
f(FSPanelFace* face_panel, const F32& repeats_per_meter) : mFacePanel(face_panel), mRepeatsPerMeter(repeats_per_meter) {}
bool apply(LLViewerObject* object, S32 te)
{
if (object->permModify())
{
// Compute S,T to axis mapping
U32 s_axis, t_axis;
if (!LLPrimitive::getTESTAxes(te, &s_axis, &t_axis))
return true;
F32 new_s = object->getScale().mV[s_axis] * mRepeatsPerMeter;
F32 new_t = object->getScale().mV[t_axis] * mRepeatsPerMeter;
setNormalRepeatX(mFacePanel, new_s, te);
setNormalRepeatY(mFacePanel, new_t, te);
}
return true;
}
} setfunc(panel_face, repeats_per_meter);
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
}
void FSPanelFace::LLSelectedTEMaterial::selectionSpecularScaleAutofit(FSPanelFace* panel_face, F32 repeats_per_meter)
{
struct f : public LLSelectedTEFunctor
{
FSPanelFace* mFacePanel;
F32 mRepeatsPerMeter;
f(FSPanelFace* face_panel, const F32& repeats_per_meter) : mFacePanel(face_panel), mRepeatsPerMeter(repeats_per_meter) {}
bool apply(LLViewerObject* object, S32 te)
{
if (object->permModify())
{
// Compute S,T to axis mapping
U32 s_axis, t_axis;
if (!LLPrimitive::getTESTAxes(te, &s_axis, &t_axis))
return true;
F32 new_s = object->getScale().mV[s_axis] * mRepeatsPerMeter;
F32 new_t = object->getScale().mV[t_axis] * mRepeatsPerMeter;
setSpecularRepeatX(mFacePanel, new_s, te);
setSpecularRepeatY(mFacePanel, new_t, te);
}
return true;
}
} setfunc(panel_face, repeats_per_meter);
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
}
void FSPanelFace::LLSelectedTE::getObjectScaleS(F32& scale_s, bool& identical)
{
struct LLSelectedTEGetObjectScaleS : public LLSelectedTEGetFunctor<F32>
@ -6002,6 +6345,23 @@ LLRender::eTexIndex FSPanelFace::getCurrentPBRChannel() const
return LLRender::NUM_TEXTURE_CHANNELS;
}
LLGLTFMaterial::TextureInfo FSPanelFace::getCurrentPBRType(LLRender::eTexIndex pbr_channel) const
{
switch (pbr_channel)
{
case LLRender::GLTF_NORMAL_MAP:
return LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL;
case LLRender::BASECOLOR_MAP:
return LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR;
case LLRender::METALLIC_ROUGHNESS_MAP:
return LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS;
case LLRender::EMISSIVE_MAP:
return LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE;
default:
return LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT;
}
}
void FSPanelFace::selectMaterialType(S32 material_type)
{
if (material_type == MATMEDIA_PBR)
@ -6021,6 +6381,7 @@ void FSPanelFace::selectMaterialType(S32 material_type)
void FSPanelFace::selectMatChannel(LLRender::eTexIndex mat_channel)
{
mSetChannelTab = true;
if (mat_channel == LLRender::NORMAL_MAP)
{
mTabsMatChannel->selectTabByName("panel_blinn_phong_normal");
@ -6037,6 +6398,7 @@ void FSPanelFace::selectMatChannel(LLRender::eTexIndex mat_channel)
void FSPanelFace::selectPBRChannel(LLRender::eTexIndex pbr_channel)
{
mSetChannelTab = true;
if (pbr_channel == LLRender::GLTF_NORMAL_MAP)
{
mTabsPBRChannel->selectTabByName("panel_pbr_transforms_normal");

View File

@ -137,6 +137,8 @@ protected:
void updateMediaSettings();
void updateMediaTitle();
bool isMediaTexSelected();
void getState();
void sendTexture(); // applies and sends texture
@ -159,6 +161,7 @@ protected:
// common controls and parameters for Blinn-Phong and PBR
void onCopyFaces(); // <FS> Extended copy & paste buttons
void onPasteFaces();
void onCommitHideWater();
void onCommitGlow();
void onCommitRepeatsPerMeter();
@ -284,7 +287,7 @@ protected:
static void syncMaterialRot(FSPanelFace* self, F32 rot, int te = -1);
// unify all GLTF spinners with no switching around required -Zi
void onCommitGLTFUVSpinner(const LLUICtrl* ctrl, const LLSD& user_data);
void onCommitGLTFUVSpinner(LLUICtrl* ctrl, const LLSD& user_data);
void onClickBtnSelectSameTexture(const LLUICtrl* ctrl, const LLSD& user_data); // Find all faces with same texture
void onShowFindAllButton(LLUICtrl* ctrl, const LLSD& user_data); // Find all faces with same texture
@ -341,6 +344,8 @@ public:
// public to give functors access -Zi
LLTabContainer* mTabsMatChannel;
void onMatTabChange();
void onMatChannelTabChange();
void onPBRChannelTabChange();
private:
bool isAlpha() { return mIsAlpha; }
@ -378,6 +383,7 @@ private:
S32 getCurrentMaterialType() const;
LLRender::eTexIndex getCurrentMatChannel() const;
LLRender::eTexIndex getCurrentPBRChannel() const;
LLGLTFMaterial::TextureInfo getCurrentPBRType(LLRender::eTexIndex pbr_channel) const;
void selectMaterialType(S32 material_type);
void selectMatChannel(LLRender::eTexIndex mat_channel);
@ -396,6 +402,7 @@ private:
// private Tab controls
LLTabContainer* mTabsPBRMatMedia;
LLTabContainer* mTabsPBRChannel;
bool mSetChannelTab = false;
// common controls and parameters for Blinn-Phong and PBR
LLButton* mBtnCopyFaces;
@ -410,9 +417,9 @@ private:
LLComboBox* mComboAlphaMode;
LLSpinCtrl* mCtrlMaskCutoff;
LLCheckBoxCtrl* mCheckFullbright;
LLCheckBoxCtrl* mCheckHideWater;
// private Blinn-Phong texture transforms and controls
LLView* mLabelTexGen;
LLView* mLabelBumpiness;
LLComboBox* mComboBumpiness;
LLView* mLabelShininess;
@ -631,11 +638,14 @@ private:
void updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool& has_faces_without_pbr, bool force_set_values);
void updateSelectedGLTFMaterials(std::function<void(LLGLTFMaterial*)> func);
void updateSelectedGLTFMaterialsWithScale(std::function<void(LLGLTFMaterial*, const F32, const F32)> func);
void updateGLTFTextureTransform(const LLGLTFMaterial::TextureInfo texture_info, std::function<void(LLGLTFMaterial::TextureTransform*)> edit);
void updateGLTFTextureTransformWithScale(const LLGLTFMaterial::TextureInfo texture_info, std::function<void(LLGLTFMaterial::TextureTransform*, const F32, const F32)> edit);
void setMaterialOverridesFromSelection();
bool mIsAlpha;
bool mExcludeWater;
LLSD mClipboardParams;
@ -722,6 +732,8 @@ public:
static void getMaxSpecularRepeats(F32& repeats, bool& identical);
static void getMaxNormalRepeats(F32& repeats, bool& identical);
static void getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha);
static void selectionNormalScaleAutofit(FSPanelFace* panel_face, F32 repeats_per_meter);
static void selectionSpecularScaleAutofit(FSPanelFace* panel_face, F32 repeats_per_meter);
FS_DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getNormalID,LLUUID::null, false, LLUUID::null);
FS_DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getSpecularID,LLUUID::null, false, LLUUID::null);

View File

@ -26,8 +26,6 @@
* $/LicenseInfo$
*/
#define GLM_ENABLE_EXPERIMENTAL 1
#include "glm/vec2.hpp"
#include "glm/vec3.hpp"
#include "glm/vec4.hpp"

View File

@ -69,9 +69,16 @@ void GLTFSceneManager::load()
{
return;
}
if (filenames.size() > 0)
try
{
GLTFSceneManager::instance().load(filenames[0]);
if (filenames.size() > 0)
{
GLTFSceneManager::instance().load(filenames[0]);
}
}
catch (std::bad_alloc&)
{
LLNotificationsUtil::add("CannotOpenFileTooBig");
}
},
LLFilePicker::FFLOAD_GLTF,

View File

@ -3082,7 +3082,10 @@ void LLAgent::endAnimationUpdateUI()
gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode());
}
gFloaterTools->dirty();
if (gFloaterTools)
{
gFloaterTools->dirty();
}
// Don't let this be called more than once if the camera
// mode hasn't changed. --JC
@ -5169,9 +5172,14 @@ void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id)
void LLAgent::doTeleportViaLandmark(const LLUUID& landmark_asset_id)
{
bool is_local(false);
LLViewerRegion* regionp = getRegion();
LLViewerRegion* regionp = getRegion();
if (!regionp)
{
LL_WARNS("Teleport") << "called when agent region is null" << LL_ENDL;
return;
}
bool is_local(false);
if (LLLandmark* landmark = gLandmarkList.getAsset(landmark_asset_id, NULL))
{
LLVector3d pos_global;

View File

@ -1419,8 +1419,6 @@ void AISUpdate::parseCategory(const LLSD& category_map, S32 depth)
&& curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN
&& version > curr_cat->getVersion())
{
// Potentially should new_cat->setVersion(unknown) here,
// but might be waiting for a callback that would increment
LL_DEBUGS("Inventory") << "Category " << category_id
<< " is stale. Known version: " << curr_cat->getVersion()
<< " server version: " << version << LL_ENDL;

View File

@ -301,7 +301,8 @@ struct AttachmentInfo
// AttachmentInfo(metadata.logFilePathname, "text/plain"),
// AttachmentInfo(metadata.userSettingsPathname, "text/xml"),
// AttachmentInfo(metadata.accountSettingsPathname, "text/xml"),
// AttachmentInfo(metadata.staticDebugPathname, "text/xml")
// AttachmentInfo(metadata.staticDebugPathname, "text/xml"),
// AttachmentInfo(metadata.attributesPathname, "text/xml")
//};
std::vector<AttachmentInfo> info{};

View File

@ -5187,48 +5187,64 @@ void wear_multiple(const uuid_vec_t& ids, bool replace)
LLAppearanceMgr::instance().wearItemsOnAvatar(ids, true, replace, cb);
}
// SLapp for easy-wearing of a stock (library) avatar
//
bool wear_category(const LLSD& query_map, bool append)
{
LLUUID folder_uuid;
if (query_map.has("folder_name"))
{
std::string outfit_folder_name = query_map["folder_name"];
folder_uuid = findDescendentCategoryIDByName(gInventory.getLibraryRootFolderID(), outfit_folder_name);
if (folder_uuid.isNull())
LL_WARNS() << "Couldn't find " << std::quoted(outfit_folder_name) << " in the Library" << LL_ENDL;
}
if (folder_uuid.isNull() && query_map.has("folder_id"))
{
folder_uuid = query_map["folder_id"].asUUID();
}
if (folder_uuid.notNull())
{
if (LLViewerInventoryCategory* cat = gInventory.getCategory(folder_uuid))
{
if (bool is_library = gInventory.isObjectDescendentOf(folder_uuid, gInventory.getRootFolderID()))
{
LLPointer<LLInventoryCategory> new_category = new LLInventoryCategory(folder_uuid, LLUUID::null, LLFolderType::FT_CLOTHING, "Quick Appearance");
LLAppearanceMgr::getInstance()->wearInventoryCategory(new_category, true, append);
}
else
{
LLAppearanceMgr::getInstance()->wearInventoryCategory(cat, true, append);
}
return true;
}
else
{
LL_WARNS() << "Couldn't find folder id" << folder_uuid << " in Inventory" << LL_ENDL;
}
}
return false;
}
class LLWearFolderHandler : public LLCommandHandler
{
public:
// not allowed from outside the app
LLWearFolderHandler() : LLCommandHandler("wear_folder", UNTRUSTED_BLOCK) { }
LLWearFolderHandler() : LLCommandHandler("wear_folder", UNTRUSTED_BLOCK) {}
bool handle(const LLSD& tokens,
const LLSD& query_map,
const std::string& grid,
LLMediaCtrl* web)
{
LLSD::UUID folder_uuid;
if (folder_uuid.isNull() && query_map.has("folder_name"))
if (wear_category(query_map, false))
{
std::string outfit_folder_name = query_map["folder_name"];
folder_uuid = findDescendentCategoryIDByName(
gInventory.getLibraryRootFolderID(),
outfit_folder_name);
}
if (folder_uuid.isNull() && query_map.has("folder_id"))
{
folder_uuid = query_map["folder_id"].asUUID();
}
// Assume this is coming from the predefined avatars web floater
LLUIUsage::instance().logCommand("Avatar.WearPredefinedAppearance");
if (folder_uuid.notNull())
{
LLPointer<LLInventoryCategory> category = new LLInventoryCategory(folder_uuid,
LLUUID::null,
LLFolderType::FT_CLOTHING,
"Quick Appearance");
if ( gInventory.getCategory( folder_uuid ) != NULL )
{
// Assume this is coming from the predefined avatars web floater
LLUIUsage::instance().logCommand("Avatar.WearPredefinedAppearance");
LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false);
// *TODOw: This may not be necessary if initial outfit is chosen already -- josh
gAgent.setOutfitChosen(true);
}
// *TODOw: This may not be necessary if initial outfit is chosen already -- josh
gAgent.setOutfitChosen(true);
}
// release avatar picker keyboard focus
@ -5238,4 +5254,46 @@ public:
}
};
class LLAddFolderHandler : public LLCommandHandler
{
public:
// not allowed from outside the app
LLAddFolderHandler() : LLCommandHandler("add_folder", UNTRUSTED_BLOCK) {}
bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web)
{
wear_category(query_map, true);
return true;
}
};
class LLRemoveFolderHandler : public LLCommandHandler
{
public:
LLRemoveFolderHandler() : LLCommandHandler("remove_folder", UNTRUSTED_BLOCK) {}
bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web)
{
if (query_map.has("folder_id"))
{
LLUUID folder_id = query_map["folder_id"].asUUID();
if (folder_id.notNull())
{
if (LLViewerInventoryCategory* cat = gInventory.getCategory(folder_id))
{
LLAppearanceMgr::instance().takeOffOutfit(cat->getLinkedUUID());
}
else
{
LL_WARNS() << "Couldn't find folder id" << folder_id << " in Inventory" << LL_ENDL;
}
}
}
return true;
}
};
LLWearFolderHandler gWearFolderHandler;
LLAddFolderHandler gAddFolderHandler;
LLRemoveFolderHandler gRemoveFolderHandler;

View File

@ -382,10 +382,6 @@ std::string gLastVersionChannel;
LLVector3 gWindVec(3.0, 3.0, 0.0);
LLVector3 gRelativeWindVec(0.0, 0.0, 0.0);
U32 gPacketsIn = 0;
bool gPrintMessagesThisFrame = false;
bool gRandomizeFramerate = false;
bool gPeriodicSlowFrame = false;
@ -393,6 +389,7 @@ bool gCrashOnStartup = false;
bool gLogoutInProgress = false;
bool gSimulateMemLeak = false;
bool gDoDisconnect = false;
// We don't want anyone, especially threads working on the graphics pipeline,
// to have to block due to this WorkQueue being full.
@ -428,11 +425,6 @@ const std::string MARKER_FILE_NAME(SAFE_FILE_NAME_PREFIX + ".exec_marker"); //FS
const std::string START_MARKER_FILE_NAME(SAFE_FILE_NAME_PREFIX + ".start_marker"); //FS new modified LL new
const std::string ERROR_MARKER_FILE_NAME(SAFE_FILE_NAME_PREFIX + ".error_marker"); //FS orig modified LL
const std::string LOGOUT_MARKER_FILE_NAME(SAFE_FILE_NAME_PREFIX + ".logout_marker"); //FS orig modified LL
//static bool gDoDisconnect = false;
// [RLVa:KB] - Checked: RLVa-2.3
bool gDoDisconnect = false;
// [/RLVa:KB]
static std::string gLaunchFileOnQuit;
// Used on Win32 for other apps to identify our window (eg, win_setup)
@ -520,9 +512,9 @@ void idle_afk_check()
// Enforce an idle time of 30 minutes if @allowidle=n restricted
S32 afk_timeout = (!gRlvHandler.hasBehaviour(RLV_BHVR_ALLOWIDLE)) ? sAFKTimeout : 60 * 30;
// [/RLVa:KB]
// F32 afk_timeout = (F32)gSavedSettings.getS32("AFKTimeout");
// static LLCachedControl<S32> afk_timeout(gSavedSettings, "AFKTimeout", 300);
// <FS:CR> Explicit conversions just cos.
//if (afk_timeout && (current_idle > afk_timeout) && ! gAgent.getAFK())
//if (afk_timeout() && (current_idle > (F32)afk_timeout()) && !gAgent.getAFK())
if (static_cast<S32>(afk_timeout) && (current_idle > static_cast<F32>(afk_timeout)) && ! gAgent.getAFK())
{
LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL;
@ -2778,6 +2770,14 @@ void LLAppViewer::initLoggingAndGetLastDuration()
{
LL_WARNS("MarkerFile") << duration_log_msg << LL_ENDL;
}
std::string user_data_path_cef_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.log");
if (gDirUtilp->fileExists(user_data_path_cef_log))
{
std::string user_data_path_cef_old = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.old");
LLFile::remove(user_data_path_cef_old, ENOENT);
LLFile::rename(user_data_path_cef_log, user_data_path_cef_old);
}
}
}
@ -3549,9 +3549,10 @@ void LLAppViewer::initStrings()
std::string strings_path_full = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, strings_file);
if (strings_path_full.empty() || !LLFile::isfile(strings_path_full))
{
std::string crash_reason;
if (strings_path_full.empty())
{
LL_WARNS() << "The file '" << strings_file << "' is not found" << LL_ENDL;
crash_reason = "The file '" + strings_file + "' is not found";
}
else
{
@ -3559,24 +3560,23 @@ void LLAppViewer::initStrings()
int rc = LLFile::stat(strings_path_full, &st);
if (rc != 0)
{
LL_WARNS() << "The file '" << strings_path_full << "' failed to get status. Error code: " << rc << LL_ENDL;
crash_reason = "The file '" + strings_path_full + "' failed to get status. Error code: " + std::to_string(rc);
}
else if (S_ISDIR(st.st_mode))
{
LL_WARNS() << "The filename '" << strings_path_full << "' is a directory name" << LL_ENDL;
crash_reason = "The filename '" + strings_path_full + "' is a directory name";
}
else
{
LL_WARNS() << "The filename '" << strings_path_full << "' doesn't seem to be a regular file name" << LL_ENDL;
crash_reason = "The filename '" + strings_path_full + "' doesn't seem to be a regular file name";
}
}
// initial check to make sure files are there failed
gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN);
LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS() << "Viewer failed to find localization and UI files."
<< " Please reinstall viewer from https://www.firestormviewer.org/downloads"
<< " and contact https://www.firestormviewer.org/support if issue persists after reinstall." << LL_ENDL;
LL_ERRS() << "Viewer failed to open some of localization and UI files."
<< " " << crash_reason << "." << LL_ENDL;
}
LLTransUtil::parseStrings(strings_file, default_trans_args);
LLTransUtil::parseLanguageStrings("language_settings.xml");
@ -5045,7 +5045,7 @@ U32 LLAppViewer::getTextureCacheVersion()
U32 LLAppViewer::getDiskCacheVersion()
{
// Viewer disk cache version intorduced in Simple Cache Viewer, change if the cache format changes.
const U32 DISK_CACHE_VERSION = 1;
const U32 DISK_CACHE_VERSION = 2;
return DISK_CACHE_VERSION ;
}
@ -5442,11 +5442,35 @@ void LLAppViewer::saveFinalSnapshot()
}
}
static const char PRODUCTION_CACHE_FORMAT_STRING[] = "%s.%s";
static const char GRID_CACHE_FORMAT_STRING[] = "%s.%s.%s";
std::string get_name_cache_filename(const std::string &base_file, const std::string& extention)
{
std::string filename;
std::string path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, base_file));
// <FS:Ansariel> OpenSim compatibility
//if (LLGridManager::getInstance()->isInProductionGrid())
if (LLGridManager::getInstance()->isInSLMain())
// </FS:Ansariel>
{
filename = llformat(PRODUCTION_CACHE_FORMAT_STRING, path.c_str(), extention.c_str());
}
else
{
// NOTE: The inventory cache filenames now include the grid name.
// Add controls against directory traversal or problematic pathname lengths
// if your viewer uses grid names from an untrusted source.
const std::string& grid_id_str = LLGridManager::getInstance()->getGridId();
const std::string& grid_id_lower = utf8str_tolower(grid_id_str);
filename = llformat(GRID_CACHE_FORMAT_STRING, path.c_str(), grid_id_lower.c_str(), extention.c_str());
}
return filename;
}
void LLAppViewer::loadNameCache()
{
// display names cache
std::string filename =
gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml");
std::string filename = get_name_cache_filename("avatar_name_cache", "xml");
LL_INFOS("AvNameCache") << filename << LL_ENDL;
llifstream name_cache_stream(filename.c_str());
if(name_cache_stream.is_open())
@ -5461,8 +5485,8 @@ void LLAppViewer::loadNameCache()
if (!gCacheName) return;
std::string name_cache;
name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
// is there a reason for the "cache" extention?
std::string name_cache = get_name_cache_filename("name", "cache");
llifstream cache_file(name_cache.c_str());
if(cache_file.is_open())
{
@ -5473,8 +5497,7 @@ void LLAppViewer::loadNameCache()
void LLAppViewer::saveNameCache()
{
// display names cache
std::string filename =
gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml");
std::string filename = get_name_cache_filename("avatar_name_cache", "xml");
llofstream name_cache_stream(filename.c_str());
if(name_cache_stream.is_open())
{
@ -5484,8 +5507,7 @@ void LLAppViewer::saveNameCache()
// real names cache
if (gCacheName)
{
std::string name_cache;
name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
std::string name_cache = get_name_cache_filename("name", "cache");
llofstream cache_file(name_cache.c_str());
if(cache_file.is_open())
{
@ -5792,6 +5814,20 @@ void LLAppViewer::idle()
if (gTeleportDisplay)
{
if (gAgent.getTeleportState() == LLAgent::TELEPORT_ARRIVING)
{
// Teleported, but waiting for things to load, start processing surface data
{
LL_RECORD_BLOCK_TIME(FTM_NETWORK);
gVLManager.unpackData();
}
{
LL_RECORD_BLOCK_TIME(FTM_REGION_UPDATE);
const F32 max_region_update_time = .001f; // 1ms
LLWorld::getInstance()->updateRegions(max_region_update_time);
}
}
return;
}
@ -6094,15 +6130,28 @@ void LLAppViewer::sendLogoutRequest()
gLogoutInProgress = true;
if (!mSecondInstance)
{
mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME);
mLogoutMarkerFile.open(mLogoutMarkerFileName, LL_APR_WB);
if (mLogoutMarkerFile.getFileHandle())
mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME);
try
{
LL_INFOS("MarkerFile") << "Created logout marker file '"<< mLogoutMarkerFileName << "' " << LL_ENDL;
recordMarkerVersion(mLogoutMarkerFile);
if (!mLogoutMarkerFile.getFileHandle())
{
mLogoutMarkerFile.open(mLogoutMarkerFileName, LL_APR_WB);
if (mLogoutMarkerFile.getFileHandle())
{
LL_INFOS("MarkerFile") << "Created logout marker file '" << mLogoutMarkerFileName << "' " << LL_ENDL;
recordMarkerVersion(mLogoutMarkerFile);
}
else
{
LL_WARNS("MarkerFile") << "Cannot create logout marker file " << mLogoutMarkerFileName << LL_ENDL;
}
}
else
{
LL_WARNS("MarkerFile") << "Atempted to reopen file '" << mLogoutMarkerFileName << "' " << LL_ENDL;
}
}
else
catch (...)
{
LL_WARNS("MarkerFile") << "Cannot create logout marker file " << mLogoutMarkerFileName << LL_ENDL;
}
@ -6235,13 +6284,10 @@ void LLAppViewer::idleNameCache()
// Handle messages, and all message related stuff
//
#define TIME_THROTTLE_MESSAGES
#ifdef TIME_THROTTLE_MESSAGES
#define CHECK_MESSAGES_DEFAULT_MAX_TIME .020f // 50 ms = 50 fps (just for messages!)
constexpr F32 CHECK_MESSAGES_DEFAULT_MAX_TIME = 0.020f; // 50 ms = 50 fps (just for messages!)
#define CHECK_MESSAGES_MAX_TIME_LIMIT 1.0f // 1 second, a long time but still able to stay connected
static F32 CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
#endif
static LLTrace::BlockTimerStatHandle FTM_IDLE_NETWORK("Idle Network");
static LLTrace::BlockTimerStatHandle FTM_MESSAGE_ACKS("Message Acks");
@ -6258,8 +6304,8 @@ void LLAppViewer::idleNetwork()
gObjectList.mNumNewObjects = 0;
S32 total_decoded = 0;
static LLCachedControl<bool> speedTest(gSavedSettings, "SpeedTest");
if (!speedTest)
static LLCachedControl<bool> speed_test(gSavedSettings, "SpeedTest", false);
if (!speed_test())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("idle network"); //LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode
@ -6269,6 +6315,7 @@ void LLAppViewer::idleNetwork()
F32 total_time = 0.0f;
{
bool needs_drain = false;
LockMessageChecker lmc(gMessageSystem);
while (lmc.checkAllMessages(frame_count, gServicePump))
{
@ -6281,66 +6328,45 @@ void LLAppViewer::idleNetwork()
}
total_decoded++;
gPacketsIn++;
if (total_decoded > MESSAGE_MAX_PER_FRAME)
{
needs_drain = true;
break;
}
#ifdef TIME_THROTTLE_MESSAGES
// Prevent slow packets from completely destroying the frame rate.
// This usually happens due to clumps of avatars taking huge amount
// of network processing time (which needs to be fixed, but this is
// a good limit anyway).
total_time = check_message_timer.getElapsedTimeF32();
if (total_time >= CheckMessagesMaxTime)
{
needs_drain = true;
break;
#endif
}
}
// Handle per-frame message system processing.
lmc.processAcks(gSavedSettings.getF32("AckCollectTime"));
}
#ifdef TIME_THROTTLE_MESSAGES
if (total_time >= CheckMessagesMaxTime)
{
// <FS:Beq> Don't allow busy network to excessively starve rendering loop
// // Increase CheckMessagesMaxTime so that we will eventually catch up
// CheckMessagesMaxTime *= 1.035f; // 3.5% ~= x2 in 20 frames, ~8x in 60 frames
// }
// else
// {
if( CheckMessagesMaxTime < CHECK_MESSAGES_MAX_TIME_LIMIT ) // cap the increase to avoid logout through ping starvation
{// Increase CheckMessagesMaxTime so that we will eventually catch up
CheckMessagesMaxTime *= 1.035f; // 3.5% ~= x2 in 20 frames, ~8x in 60 frames
if (needs_drain || gMessageSystem->mPacketRing.getNumBufferedPackets() > 0)
{
// Rather than allow packets to silently backup on the socket
// we drain them into our own buffer so we know how many exist.
S32 num_buffered_packets = gMessageSystem->drainUdpSocket();
if (num_buffered_packets > 0)
{
// Increase CheckMessagesMaxTime so that we will eventually catch up
CheckMessagesMaxTime *= 1.035f; // 3.5% ~= 2x in 20 frames, ~8x in 60 frames
}
}
else
{
CheckMessagesMaxTime = CHECK_MESSAGES_MAX_TIME_LIMIT;
// Reset CheckMessagesMaxTime to default value
CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
}
}
else
{
// </FS:Beq>
// Reset CheckMessagesMaxTime to default value
CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
}
#endif
// Decode enqueued messages...
S32 remaining_possible_decodes = MESSAGE_MAX_PER_FRAME - total_decoded;
// Handle per-frame message system processing.
if( remaining_possible_decodes <= 0 )
{
LL_INFOS() << "Maxed out number of messages per frame at " << MESSAGE_MAX_PER_FRAME << LL_ENDL;
}
if (gPrintMessagesThisFrame)
{
LL_INFOS() << "Decoded " << total_decoded << " msgs this frame!" << LL_ENDL;
gPrintMessagesThisFrame = false;
static LLCachedControl<F32> ack_collection_time(gSavedSettings, "AckCollectTime", 0.1f);
lmc.processAcks(ack_collection_time());
}
}
add(LLStatViewer::NUM_NEW_OBJECTS, gObjectList.mNumNewObjects);
@ -6348,6 +6374,7 @@ void LLAppViewer::idleNetwork()
// Retransmit unacknowledged packets.
gXferManager->retransmitUnackedPackets();
gAssetStorage->checkForTimeouts();
gViewerThrottle.setBufferLoadRate(gMessageSystem->getBufferLoadRate());
gViewerThrottle.updateDynamicThrottle();
// Check that the circuit between the viewer and the agent's current
@ -6541,6 +6568,27 @@ void LLAppViewer::forceErrorDriverCrash()
//}
// </FS:Ansariel>
void LLAppViewer::forceErrorCoroprocedureCrash()
{
LL_WARNS() << "Forcing a crash in LLCoprocedureManager" << LL_ENDL;
LLCoprocedureManager::instance().enqueueCoprocedure("Upload", "DeliberateCrash",
[](LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t&, const LLUUID&)
{
LL_WARNS() << "Forcing a deliberate bad memory access from LLCoprocedureManager" << LL_ENDL;
S32* crash = NULL;
*crash = 0xDEADBEEF;
});
}
void LLAppViewer::forceErrorWorkQueueCrash()
{
LL::WorkQueue::ptr_t workqueue = LL::WorkQueue::getInstance("General");
if (workqueue)
{
workqueue->post([]() { throw LLException("This is a deliberate crash from General Queue"); });
}
}
void LLAppViewer::forceErrorThreadCrash()
{
class LLCrashTestThread : public LLThread

View File

@ -173,6 +173,8 @@ public:
virtual void forceErrorDriverCrash();
// <FS:Ansariel> Wrongly merged back in by LL
//virtual void forceErrorCoroutineCrash();
virtual void forceErrorCoroprocedureCrash();
virtual void forceErrorWorkQueueCrash();
virtual void forceErrorThreadCrash();
// The list is found in app_settings/settings_files.xml
@ -444,11 +446,10 @@ extern std::string gLastVersionChannel;
extern LLVector3 gWindVec;
extern LLVector3 gRelativeWindVec;
extern U32 gPacketsIn;
extern bool gPrintMessagesThisFrame;
extern bool gRandomizeFramerate;
extern bool gPeriodicSlowFrame;
extern bool gDoDisconnect;
extern bool gSimulateMemLeak;

View File

@ -41,6 +41,7 @@ void clearDumpLogsDir();
struct CrashMetadata
{
std::string logFilePathname;
std::string attributesPathname;
std::string userSettingsPathname;
std::string accountSettingsPathname;
std::string staticDebugPathname;

View File

@ -172,6 +172,8 @@ CrashMetadataSingleton::CrashMetadataSingleton()
// Note: we depend on being able to read the static_debug_info.log file
// from the *previous* run before we overwrite it with the new one for
// *this* run. LLAppViewer initialization must happen in the Right Order.
// Todo: consider converting static file into bugspalt attributes file
staticDebugPathname = *gViewerAppPtr->getStaticDebugFile();
std::ifstream static_file(staticDebugPathname);
LLSD info;
@ -215,7 +217,32 @@ CrashMetadataSingleton::CrashMetadataSingleton()
}
}
}
// Populate bugsplat attributes
LLXMLNodePtr out_node = new LLXMLNode("XmlCrashContext", false);
out_node->createChild("OS", false)->setValue(OSInfo);
out_node->createChild("AppState", false)->setValue(info["StartupState"].asString());
out_node->createChild("GraphicsCard", false)->setValue(info["GraphicsCard"].asString());
out_node->createChild("GLVersion", false)->setValue(info["GLInfo"]["GLVersion"].asString());
out_node->createChild("GLRenderer", false)->setValue(info["GLInfo"]["GLRenderer"].asString());
out_node->createChild("RAM", false)->setValue(info["RAMInfo"]["Physical"].asString());
if (!out_node->isNull())
{
attributesPathname = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "CrashContext.xml");
LLFILE* fp = LLFile::fopen(attributesPathname, "w");
if (fp != NULL)
{
LLXMLNode::writeHeaderToFile(fp);
out_node->writeToFile(fp);
fclose(fp);
}
}
}
// else Todo: consider fillig at least some values, like OS
}
// Avoid having to compile all of our LLSingleton machinery in Objective-C++.

View File

@ -200,10 +200,10 @@ namespace
// sBugSplatSender->setDefaultUserDescription(WCSTR(LLError::getFatalMessage()));
// sBugSplatSender->setAttribute(WCSTR(L"OS"), WCSTR(LLOSInfo::instance().getOSStringSimple())); // In case we ever stop using email for this
// sBugSplatSender->setAttribute(WCSTR(L"AppState"), WCSTR(LLStartUp::getStartupStateString()));
// sBugSplatSender->setAttribute(WCSTR(L"GL Vendor"), WCSTR(gGLManager.mGLVendor));
// sBugSplatSender->setAttribute(WCSTR(L"GL Version"), WCSTR(gGLManager.mGLVersionString));
// sBugSplatSender->setAttribute(WCSTR(L"GPU Version"), WCSTR(gGLManager.mDriverVersionVendorString));
// sBugSplatSender->setAttribute(WCSTR(L"GL Renderer"), WCSTR(gGLManager.mGLRenderer));
// sBugSplatSender->setAttribute(WCSTR(L"GLVendor"), WCSTR(gGLManager.mGLVendor));
// sBugSplatSender->setAttribute(WCSTR(L"GLVersion"), WCSTR(gGLManager.mGLVersionString));
// sBugSplatSender->setAttribute(WCSTR(L"GPUVersion"), WCSTR(gGLManager.mDriverVersionVendorString));
// sBugSplatSender->setAttribute(WCSTR(L"GLRenderer"), WCSTR(gGLManager.mGLRenderer));
// sBugSplatSender->setAttribute(WCSTR(L"VRAM"), WCSTR(STRINGIZE(gGLManager.mVRAM)));
// sBugSplatSender->setAttribute(WCSTR(L"RAM"), WCSTR(STRINGIZE(gSysMemory.getPhysicalMemoryKB().value())));
@ -1022,14 +1022,16 @@ bool LLAppViewerWin32::cleanup()
return result;
}
void LLAppViewerWin32::reportCrashToBugsplat(void* pExcepInfo)
bool LLAppViewerWin32::reportCrashToBugsplat(void* pExcepInfo)
{
#if defined(LL_BUGSPLAT)
if (sBugSplatSender)
{
sBugSplatSender->createReport((EXCEPTION_POINTERS*)pExcepInfo);
return true;
}
#endif // LL_BUGSPLAT
return false;
}
void LLAppViewerWin32::initLoggingAndGetLastDuration()

View File

@ -43,7 +43,7 @@ public:
bool init() override; // Override to do application initialization
bool cleanup() override;
void reportCrashToBugsplat(void* pExcepInfo) override;
bool reportCrashToBugsplat(void* pExcepInfo) override;
protected:
void initLoggingAndGetLastDuration() override; // Override to clean stack_trace info.

View File

@ -783,6 +783,7 @@ void LLAvatarPropertiesProcessor::sendClassifiedInfoUpdate(const LLAvatarClassif
void LLAvatarPropertiesProcessor::sendPickInfoRequest(const LLUUID& creator_id, const LLUUID& pick_id)
{
LL_DEBUGS("PickInfo") << " Requiesting pick info for " << pick_id << LL_ENDL;
// Must ask for a pick based on the creator id because
// the pick database is distributed to the inventory cluster. JC
std::vector<std::string> request_params{ creator_id.asString(), pick_id.asString() };

View File

@ -42,6 +42,7 @@
#include "llinventorymodel.h"
#include "llnotifications.h"
#include "llslurl.h"
#include "llstartup.h"
#include "llimview.h"
#include "lltrans.h"
#include "llviewercontrol.h"
@ -279,6 +280,22 @@ S32 LLAvatarTracker::addBuddyList(const LLAvatarTracker::buddy_map_t& buds)
<< "]" << LL_ENDL;
}
}
// It's possible that the buddy list getting propagated from the inventory may have happened after we actually got the buddy list.
// Any buddies that we got prior will reside in a special queue that we must process and update statuses accordingly with.
// Do that here.
// -Geenz 2025-03-12
while (!mBuddyStatusQueue.empty())
{
auto buddyStatus = mBuddyStatusQueue.front();
mBuddyStatusQueue.pop();
if (mBuddyInfo.find(buddyStatus.first) != mBuddyInfo.end())
{
setBuddyOnline(buddyStatus.first, buddyStatus.second);
}
}
// do not notify observers here - list can be large so let it be done on idle.
return new_buddy_count;
@ -343,9 +360,12 @@ void LLAvatarTracker::setBuddyOnline(const LLUUID& id, bool is_online)
{
//<FS:LO> Fix possible log spam with a large friendslist when SL messes up.
//LL_WARNS() << "!! No buddy info found for " << id
LL_WARNS() << "Did we receive a buddy status update before the buddy info?" << LL_ENDL;
LL_DEBUGS() << "!! No buddy info found for " << id
<< ", setting to " << (is_online ? "Online" : "Offline") << LL_ENDL;
LL_DEBUGS() << "Did we receive a buddy status update before the buddy info?" << LL_ENDL;
//</FS:LO>
mBuddyStatusQueue.push(std::make_pair(id, is_online));
}
}
@ -496,7 +516,7 @@ void LLAvatarTracker::idleNotifyObservers()
void LLAvatarTracker::notifyObservers()
{
if (mIsNotifyObservers)
if (mIsNotifyObservers || (LLStartUp::getStartupState() <= STATE_INVENTORY_CALLBACKS))
{
// Don't allow multiple calls.
// new masks and ids will be processed later from idle.
@ -790,6 +810,8 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)
{
LL_WARNS() << "Received online notification for unknown buddy: "
<< agent_id << " is " << (online ? "ONLINE" : "OFFLINE") << LL_ENDL;
LL_WARNS() << "Adding buddy to buddy queue." << LL_ENDL;
mBuddyStatusQueue.push(std::make_pair(agent_id, true));
}
if(tracking_id == agent_id)
@ -812,7 +834,11 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)
mModifyMask |= LLFriendObserver::ONLINE;
instance().notifyObservers();
gInventory.notifyObservers();
// Skip if we had received the friends list before the inventory callbacks were properly initialized
if (LLStartUp::getStartupState() > STATE_INVENTORY_CALLBACKS)
{
gInventory.notifyObservers();
}
}
}

View File

@ -110,6 +110,7 @@ public:
// add or remove agents from buddy list. Each method takes a set
// of buddies and returns how many were actually added or removed.
typedef std::map<LLUUID, LLRelationship*> buddy_map_t;
typedef std::queue<std::pair<LLUUID, bool>> buddy_status_queue_t;
S32 addBuddyList(const buddy_map_t& buddies);
//S32 removeBuddyList(const buddy_list_t& exes);
@ -200,6 +201,7 @@ protected:
//LLInventoryObserver* mInventoryObserver;
buddy_map_t mBuddyInfo;
buddy_status_queue_t mBuddyStatusQueue;
typedef std::set<LLUUID> changed_buddy_t;
changed_buddy_t mChangedBuddyIDs;

View File

@ -417,11 +417,12 @@ void LLNotificationChiclet::setCounter(S32 counter)
bool LLNotificationChiclet::ChicletNotificationChannel::filterNotification( LLNotificationPtr notification )
{
bool displayNotification;
//LLFloaterNotificationsTabbed* floater = LLFloaterNotificationsTabbed::getInstance(); // <FS:Ansariel> Optional legacy notification well
if ( (notification->getName() == "ScriptDialog") // special case for scripts
// if there is no toast window for the notification, filter it
//|| (!LLNotificationWellWindow::getInstance()->findItemByID(notification->getID()))
// <FS:Ansariel> Optional legacy notification well
//|| (!LLFloaterNotificationsTabbed::getInstance()->findItemByID(notification->getID(), notification->getName()))
//|| (floater && !LLFloaterNotificationsTabbed::getInstance()->findItemByID(notification->getID(), notification->getName()))
|| ((!gSavedSettings.getBOOL("FSInternalLegacyNotificationWell") && !LLFloaterNotificationsTabbed::getInstance()->findItemByID(notification->getID(), notification->getName()))
|| (gSavedSettings.getBOOL("FSInternalLegacyNotificationWell") && !LLNotificationWellWindow::getInstance()->findItemByID(notification->getID())))
// </FS:Ansariel>

View File

@ -33,6 +33,7 @@
// viewer includes
#include "llagent.h"
#include "llagentcamera.h"
#include "llcriticaldamp.h"
#include "llface.h"
#include "lllightconstants.h"
@ -259,7 +260,15 @@ void LLDrawable::cleanupReferences()
std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
mFaces.clear();
gPipeline.unlinkDrawable(this);
if (gPipeline.mInitialized)
{
gPipeline.unlinkDrawable(this);
}
else if (getSpatialGroup())
{
// Not supposed to happen?
getSpatialGroup()->getSpatialPartition()->remove(this, getSpatialGroup());
}
removeFromOctree();
@ -785,6 +794,14 @@ bool LLDrawable::updateMove()
makeActive();
// #3256 force undampened movement for attached objects in mouselook
// to prevent animation bork for linkset with animated parts
if (!isRoot() && gAgentCamera.cameraMouselook() &&
!mVObjp->isRiggedMesh() && mVObjp->getAvatar() && mVObjp->getAvatar()->isSelf())
{
return updateMoveUndamped();
}
return isState(MOVE_UNDAMPED) ? updateMoveUndamped() : updateMoveDamped();
}

View File

@ -114,13 +114,9 @@ void LLDrawPoolTree::beginShadowPass(S32 pass)
{
LL_PROFILE_ZONE_SCOPED;
// <FS:PP> Attempt to speed up things a little
// glPolygonOffset(gSavedSettings.getF32("RenderDeferredTreeShadowOffset"),
// gSavedSettings.getF32("RenderDeferredTreeShadowBias"));
static LLCachedControl<F32> RenderDeferredTreeShadowOffset(gSavedSettings, "RenderDeferredTreeShadowOffset");
static LLCachedControl<F32> RenderDeferredTreeShadowBias(gSavedSettings, "RenderDeferredTreeShadowBias");
glPolygonOffset(RenderDeferredTreeShadowOffset, RenderDeferredTreeShadowBias);
// </FS:PP>
static LLCachedControl<F32> shadow_offset(gSavedSettings, "RenderDeferredTreeShadowOffset");
static LLCachedControl<F32> shadow_bias(gSavedSettings, "RenderDeferredTreeShadowBias");
glPolygonOffset(shadow_offset(), shadow_bias());
LLEnvironment& environment = LLEnvironment::instance();

View File

@ -116,18 +116,27 @@ namespace Details
void LLEventPollImpl::handleMessage(const LLSD& content)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
std::string msg_name = content["message"];
std::string msg_name = content["message"].asString();
LLSD message;
message["sender"] = mSenderIp;
// <FS:ND> Guard against messages with no "body"
try
{
message["sender"] = mSenderIp;
// <FS:ND> Guard against messages with no "body"
// message["body"] = content["body"];
// message["body"] = content["body"];
if( content.has( "body" ) )
message["body"] = content["body"];
else
LL_WARNS() << "Malformed content? " << ll_pretty_print_sd( content ) << LL_ENDL;
// <FS:ND>
}
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS("LLCoros") << "Bad memory allocation on message: " << msg_name << LL_ENDL;
}
if( content.has( "body" ) )
message["body"] = content["body"];
else
LL_WARNS() << "Malformed content? " << ll_pretty_print_sd( content ) << LL_ENDL;
// <FS:ND>
LLMessageSystem::dispatch(msg_name, message);
}

View File

@ -2370,7 +2370,7 @@ bool LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("calcPixelArea - rigged");
//override with joint volume face joint bounding boxes
LLVOAvatar* avatar = mVObjp->getAvatar();
LLVOAvatar* avatar = mVObjp.notNull() ? mVObjp->getAvatar() : nullptr;
bool hasRiggedExtents = false;
if (avatar && avatar->mDrawable)

View File

@ -199,6 +199,7 @@ bool LLFetchedGLTFMaterial::replaceLocalTexture(const LLUUID& tracking_id, const
{
mTrackingIdToLocalTexture.erase(tracking_id);
}
updateLocalTexDataDigest();
return res;
}

View File

@ -33,6 +33,7 @@
#include "llagentui.h"
#include "llbase64.h"
#include "llcallbacklist.h"
#include "lldate.h"
#include "llenvironment.h"
#include "llimagejpeg.h"
#include "llmediactrl.h"
@ -703,7 +704,15 @@ void LLFloater360Capture::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent
);
// execute the command on the page
mWebBrowser->getMediaPlugin()->executeJavaScript(cmd);
LLPluginClassMedia* plugin = mWebBrowser->getMediaPlugin();
if (plugin)
{
plugin->executeJavaScript(cmd);
}
else
{
LL_WARNS("360Capture") << "No media plugin found" << LL_ENDL;
}
}
}
break;
@ -784,7 +793,15 @@ void LLFloater360Capture::onSaveLocalBtn()
// send it to the browser instance, triggering the equirectangular capture
// process and complimentary offer to save the image
mWebBrowser->getMediaPlugin()->executeJavaScript(cmd);
LLPluginClassMedia* plugin = mWebBrowser->getMediaPlugin();
if (plugin)
{
plugin->executeJavaScript(cmd);
}
else
{
LL_WARNS("360Capture") << "No media plugin found" << LL_ENDL;
}
}
// We capture all 6 images sequentially and if parts of the world are moving
@ -874,15 +891,7 @@ const std::string LLFloater360Capture::generate_proposed_filename()
filename << "_";
// add in the current HH-MM-SS (with leading 0's) so users can easily save many shots in same folder
std::time_t cur_epoch = std::time(nullptr);
std::tm* tm_time = std::localtime(&cur_epoch);
filename << std::setfill('0') << std::setw(4) << (tm_time->tm_year + 1900);
filename << std::setfill('0') << std::setw(2) << (tm_time->tm_mon + 1);
filename << std::setfill('0') << std::setw(2) << tm_time->tm_mday;
filename << "_";
filename << std::setfill('0') << std::setw(2) << tm_time->tm_hour;
filename << std::setfill('0') << std::setw(2) << tm_time->tm_min;
filename << std::setfill('0') << std::setw(2) << tm_time->tm_sec;
filename << LLDate::now().toLocalDateString("%Y%m%d_%H%M%S");
// the unusual way we save the output image (originates in the
// embedded browser and not the C++ code) means that the system

View File

@ -31,6 +31,7 @@
#include "llagent.h"
#include "llagentui.h"
#include "llcombobox.h"
#include "llfloaterreg.h"
#include "llinventoryfunctions.h"
#include "llinventoryobserver.h"
#include "lllandmarkactions.h"
@ -397,6 +398,7 @@ void LLFloaterCreateLandmark::setItem(const uuid_set_t& items)
{
mItem = item;
mAssetID = mItem->getAssetUUID();
mParentID = mItem->getParentUUID();
setVisibleAndFrontmost(true);
break;
}
@ -426,8 +428,7 @@ void LLFloaterCreateLandmark::updateItem(const uuid_set_t& items, U32 mask)
closeFloater();
}
LLUUID folder_id = mFolderCombo->getValue().asUUID();
if (folder_id != mItem->getParentUUID())
if (mParentID != mItem->getParentUUID())
{
// user moved landmark in inventory,
// assume that we are done all other changes should already be commited

View File

@ -69,6 +69,7 @@ private:
LLTextEditor* mNotesEditor;
LLUUID mLandmarksID;
LLUUID mAssetID;
LLUUID mParentID;
LLLandmarksInventoryObserver* mInventoryObserver;
LLPointer<LLInventoryItem> mItem;

View File

@ -60,8 +60,7 @@ static const S32 USED_EMOJIS_IMAGE_INDEX = 0x23F2;
// https://www.compart.com/en/unicode/U+1F6D1
static const S32 EMPTY_LIST_IMAGE_INDEX = 0x1F6D1;
// The following categories should follow the required alphabetic order
static const std::string RECENTLY_USED_CATEGORY = "1 recently used";
static const std::string FREQUENTLY_USED_CATEGORY = "2 frequently used";
static const std::string FREQUENTLY_USED_CATEGORY = "frequently used";
// Floater state related variables
static std::list<llwchar> sRecentlyUsed;
@ -459,11 +458,10 @@ void LLFloaterEmojiPicker::fillGroups()
params.name = "all_categories";
createGroupButton(params, rect, ALL_EMOJIS_IMAGE_INDEX);
// Create group and button for "Recently used" and/or "Frequently used"
if (!sRecentlyUsed.empty() || !sFrequentlyUsed.empty())
// Create group and button for "Frequently used"
if (!sFrequentlyUsed.empty())
{
std::map<std::string, std::vector<LLEmojiSearchResult>> cats;
fillCategoryRecentlyUsed(cats);
fillCategoryFrequentlyUsed(cats);
if (!cats.empty())
@ -496,40 +494,6 @@ void LLFloaterEmojiPicker::fillGroups()
resizeGroupButtons();
}
void LLFloaterEmojiPicker::fillCategoryRecentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats)
{
if (sRecentlyUsed.empty())
return;
std::vector<LLEmojiSearchResult> emojis;
// In case of empty mFilterPattern we'd use sRecentlyUsed directly
if (!mFilterPattern.empty())
{
// List all emojis in "Recently used"
const LLEmojiDictionary::emoji2descr_map_t& emoji2descr = LLEmojiDictionary::instance().getEmoji2Descr();
std::size_t begin, end;
for (llwchar emoji : sRecentlyUsed)
{
auto e2d = emoji2descr.find(emoji);
if (e2d != emoji2descr.end() && !e2d->second->ShortCodes.empty())
{
for (const std::string& shortcode : e2d->second->ShortCodes)
{
if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern))
{
emojis.emplace_back(emoji, shortcode, begin, end);
}
}
}
}
if (emojis.empty())
return;
}
cats.emplace(std::make_pair(RECENTLY_USED_CATEGORY, emojis));
}
void LLFloaterEmojiPicker::fillCategoryFrequentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats)
{
if (sFrequentlyUsed.empty())
@ -770,7 +734,6 @@ void LLFloaterEmojiPicker::fillEmojisCategory(const std::vector<LLEmojiSearchRes
{
// Place the category title
std::string title =
category == RECENTLY_USED_CATEGORY ? getString("title_for_recently_used") :
category == FREQUENTLY_USED_CATEGORY ? getString("title_for_frequently_used") :
isupper(category.front()) ? category : LLStringUtil::capitalize(category);
LLEmojiGridDivider* div = new LLEmojiGridDivider(row_panel_params, title);
@ -783,21 +746,7 @@ void LLFloaterEmojiPicker::fillEmojisCategory(const std::vector<LLEmojiSearchRes
{
const LLEmojiDictionary::emoji2descr_map_t& emoji2descr = LLEmojiDictionary::instance().getEmoji2Descr();
LLEmojiSearchResult emoji { 0, "", 0, 0 };
if (category == RECENTLY_USED_CATEGORY)
{
for (llwchar code : sRecentlyUsed)
{
const LLEmojiDictionary::emoji2descr_map_t::const_iterator& e2d = emoji2descr.find(code);
if (e2d != emoji2descr.end() && !e2d->second->ShortCodes.empty())
{
emoji.Character = code;
emoji.String = e2d->second->ShortCodes.front();
createEmojiIcon(emoji, category, row_panel_params, row_list_params, icon_params,
icon_rect, max_icons, bg, row, icon_index);
}
}
}
else if (category == FREQUENTLY_USED_CATEGORY)
if (category == FREQUENTLY_USED_CATEGORY)
{
for (const auto& code : sFrequentlyUsed)
{

View File

@ -68,7 +68,6 @@ public:
private:
void initialize();
void fillGroups();
void fillCategoryRecentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats);
void fillCategoryFrequentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats);
void fillGroupEmojis(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats, U32 index);
void createGroupButton(LLButton::Params& params, const LLRect& rect, llwchar emoji);

View File

@ -1951,7 +1951,7 @@ bool LLFloaterIMContainer::removeConversationListItem(const LLUUID& uuid, bool c
mConversationEventQueue.erase(uuid);
// Don't let the focus fall IW, select and refocus on the first conversation in the list
if (change_focus)
if (change_focus && isInVisibleChain())
{
setFocus(true);
if (new_selection)
@ -1971,6 +1971,10 @@ bool LLFloaterIMContainer::removeConversationListItem(const LLUUID& uuid, bool c
}
}
}
else
{
LL_INFOS() << "Conversation widgets: " << (S32)mConversationsWidgets.size() << LL_ENDL;
}
return is_widget_selected;
}

Some files were not shown because too many files have changed in this diff Show More