Merge pull request #3634 from secondlife/release/2024.12-ForeverFPS

Update develop with ForeverFPS
master
Jonathan "Geenz" Goodman 2025-03-01 16:37:59 -05:00 committed by GitHub
commit 5d78ff48cb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
148 changed files with 2116 additions and 1165 deletions

View File

@ -42,7 +42,7 @@ jobs:
needs: setup
strategy:
matrix:
runner: [windows-large, macos-12-large]
runner: [windows-large, macos-15-xlarge]
configuration: ${{ fromJSON(needs.setup.outputs.configurations) }}
runs-on: ${{ matrix.runner }}
outputs:
@ -64,7 +64,7 @@ jobs:
# autobuild-package.xml.
AUTOBUILD_VCS_INFO: "true"
AUTOBUILD_VSVER: "170"
DEVELOPER_DIR: "/Applications/Xcode_14.0.1.app/Contents/Developer"
DEVELOPER_DIR: "/Applications/Xcode_16.1.app/Contents/Developer"
# Ensure that Linden viewer builds engage Bugsplat.
BUGSPLAT_DB: ${{ needs.setup.outputs.bugsplat_db }}
build_coverity: false

View File

@ -37,7 +37,12 @@ jobs:
- name: Update Tag
uses: actions/github-script@v7.0.1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
# use a real access token instead of GITHUB_TOKEN default.
# required so that the results of this tag creation can trigger the build workflow
# https://stackoverflow.com/a/71372524
# https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow
# this token will need to be renewed anually in January
github-token: ${{ secrets.LL_TAG_RELEASE_TOKEN }}
script: |
github.rest.git.createRef({
owner: context.repo.owner,

View File

@ -29,6 +29,11 @@ else()
set( USE_AUTOBUILD_3P ON )
endif()
if (NOT DEFINED CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 20)
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(Variables)
include(BuildVersion)

View File

@ -300,7 +300,8 @@ EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByImageName(std::strin
LLWearableType::EType LLAvatarAppearanceDictionary::getTEWearableType(ETextureIndex index ) const
{
return getTexture(index)->mWearableType;
auto* tex = getTexture(index);
return tex ? tex->mWearableType : LLWearableType::WT_INVALID;
}
// static

View File

@ -652,7 +652,7 @@ void LLWearable::setVisualParamWeight(S32 param_index, F32 value)
}
else
{
LL_ERRS() << "LLWearable::setVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL;
LL_WARNS() << "LLWearable::setVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL;
}
}
@ -665,7 +665,7 @@ F32 LLWearable::getVisualParamWeight(S32 param_index) const
}
else
{
LL_WARNS() << "LLWerable::getVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL;
LL_WARNS() << "LLWearable::getVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL;
}
return (F32)-1.0;
}

View File

@ -68,7 +68,11 @@ public:
}
// shadow base-class string() method with UTF-8 aware method
std::string string() const { return super::u8string(); }
std::string string() const
{
auto u8 = super::u8string();
return std::string(u8.begin(), u8.end());
}
// On Posix systems, where value_type is already char, this operator
// std::string() method shadows the base class operator string_type()
// method. But on Windows, where value_type is wchar_t, the base class

View File

@ -1604,11 +1604,11 @@ namespace LLError
std::string LLUserWarningMsg::sLocalizedOutOfMemoryWarning;
LLUserWarningMsg::Handler LLUserWarningMsg::sHandler;
void LLUserWarningMsg::show(const std::string& message)
void LLUserWarningMsg::show(const std::string& message, S32 error_code)
{
if (sHandler)
{
sHandler(std::string(), message);
sHandler(std::string(), message, error_code);
}
}
@ -1616,7 +1616,7 @@ namespace LLError
{
if (sHandler && !sLocalizedOutOfMemoryTitle.empty())
{
sHandler(sLocalizedOutOfMemoryTitle, sLocalizedOutOfMemoryWarning);
sHandler(sLocalizedOutOfMemoryTitle, sLocalizedOutOfMemoryWarning, ERROR_BAD_ALLOC);
}
}
@ -1627,7 +1627,7 @@ namespace LLError
"Second Life viewer couldn't access some of the files it needs and will be closed."
"\n\nPlease reinstall viewer from https://secondlife.com/support/downloads/ and "
"contact https://support.secondlife.com if issue persists after reinstall.";
sHandler("Missing Files", error_string);
sHandler("Missing Files", error_string, ERROR_MISSING_FILES);
}
void LLUserWarningMsg::setHandler(const LLUserWarningMsg::Handler &handler)

View File

@ -308,7 +308,16 @@ namespace LLError
class LLUserWarningMsg
{
public:
typedef std::function<void(const std::string&, const std::string&)> Handler;
// error codes, tranlates to last_exec states like LAST_EXEC_OTHER_CRASH
typedef enum
{
ERROR_OTHER = 0,
ERROR_BAD_ALLOC = 1,
ERROR_MISSING_FILES = 2,
} eLastExecEvent;
// tittle, message and error code to include in error marker file
typedef std::function<void(const std::string&, const std::string&, S32 error_code)> Handler;
static void setHandler(const Handler&);
static void setOutOfMemoryStrings(const std::string& title, const std::string& message);
@ -316,7 +325,7 @@ namespace LLError
static void showOutOfMemory();
static void showMissingFiles();
// Genering error
static void show(const std::string&);
static void show(const std::string&, S32 error_code = -1);
private:
// needs to be preallocated before viewer runs out of memory

View File

@ -146,7 +146,7 @@ size_t LLQueuedThread::updateQueue(F32 max_time_ms)
// schedule a call to threadedUpdate for every call to updateQueue
if (!isQuitting())
{
mRequestQueue.post([=]()
mRequestQueue.post([=, this]()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD("qt - update");
mIdleThread = false;
@ -474,7 +474,7 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req)
#else
using namespace std::chrono_literals;
auto retry_time = LL::WorkQueue::TimePoint::clock::now() + 16ms;
mRequestQueue.post([=]
mRequestQueue.post([=, this]
{
LL_PROFILE_ZONE_NAMED("processRequest - retry");
if (LL::WorkQueue::TimePoint::clock::now() < retry_time)

View File

@ -918,7 +918,7 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const
}
//sd[INV_FLAGS_LABEL] = (S32)mFlags;
sd[INV_FLAGS_LABEL] = ll_sd_from_U32(mFlags);
sd[INV_SALE_INFO_LABEL] = mSaleInfo;
sd[INV_SALE_INFO_LABEL] = mSaleInfo.asLLSD();
sd[INV_NAME_LABEL] = mName;
sd[INV_DESC_LABEL] = mDescription;
sd[INV_CREATION_DATE_LABEL] = (S32) mCreationDate;

View File

@ -89,8 +89,14 @@ bool LLSaleInfo::exportLegacyStream(std::ostream& output_stream) const
LLSD LLSaleInfo::asLLSD() const
{
LLSD sd = LLSD();
sd["sale_type"] = lookup(mSaleType);
LLSD sd;
const char* type = lookup(mSaleType);
if (!type)
{
LL_WARNS_ONCE() << "Unknown sale type: " << mSaleType << LL_ENDL;
type = lookup(LLSaleInfo::FS_NOT);
}
sd["sale_type"] = type;
sd["sale_price"] = mSalePrice;
return sd;
}

View File

@ -137,7 +137,8 @@ const std::string LLSettingsSky::SETTING_REFLECTION_PROBE_AMBIANCE("reflection_p
const LLUUID LLSettingsSky::DEFAULT_ASSET_ID("651510b8-5f4d-8991-1592-e7eeab2a5a06");
F32 LLSettingsSky::sAutoAdjustProbeAmbiance = 1.f;
const F32 LLSettingsSky::DEFAULT_AUTO_ADJUST_PROBE_AMBIANCE = 1.f;
F32 LLSettingsSky::sAutoAdjustProbeAmbiance = DEFAULT_AUTO_ADJUST_PROBE_AMBIANCE;
static const LLUUID DEFAULT_SUN_ID("32bfbcea-24b1-fb9d-1ef9-48a28a63730f"); // dataserver
static const LLUUID DEFAULT_MOON_ID("d07f6eed-b96a-47cd-b51d-400ad4a1c428"); // dataserver
@ -2032,43 +2033,43 @@ F32 LLSettingsSky::getGamma() const
return mGamma;
}
F32 LLSettingsSky::getHDRMin() const
F32 LLSettingsSky::getHDRMin(bool auto_adjust) const
{
if (mCanAutoAdjust)
if (mCanAutoAdjust && !auto_adjust)
return 0.f;
return mHDRMin;
}
F32 LLSettingsSky::getHDRMax() const
F32 LLSettingsSky::getHDRMax(bool auto_adjust) const
{
if (mCanAutoAdjust)
if (mCanAutoAdjust && !auto_adjust)
return 0.f;
return mHDRMax;
}
F32 LLSettingsSky::getHDROffset() const
F32 LLSettingsSky::getHDROffset(bool auto_adjust) const
{
if (mCanAutoAdjust)
if (mCanAutoAdjust && !auto_adjust)
return 1.0f;
return mHDROffset;
}
F32 LLSettingsSky::getTonemapMix() const
F32 LLSettingsSky::getTonemapMix(bool auto_adjust) const
{
if (mCanAutoAdjust)
if (mCanAutoAdjust && !auto_adjust)
{
// legacy settings do not support tonemaping
return 0.0f;
}
return mTonemapMix;
}
void LLSettingsSky::setTonemapMix(F32 mix)
{
if (mCanAutoAdjust)
return;
mTonemapMix = mix;
}

View File

@ -103,6 +103,7 @@ public:
static const LLUUID DEFAULT_ASSET_ID;
static const F32 DEFAULT_AUTO_ADJUST_PROBE_AMBIANCE;
static F32 sAutoAdjustProbeAmbiance;
typedef PTR_NAMESPACE::shared_ptr<LLSettingsSky> ptr_t;
@ -209,10 +210,10 @@ public:
F32 getGamma() const;
F32 getHDRMin() const;
F32 getHDRMax() const;
F32 getHDROffset() const;
F32 getTonemapMix() const;
F32 getHDRMin(bool auto_adjust = false) const;
F32 getHDRMax(bool auto_adjust = false) const;
F32 getHDROffset(bool auto_adjust = false) const;
F32 getTonemapMix(bool auto_adjust = false) const;
void setTonemapMix(F32 mix);
void setGamma(F32 val);

View File

@ -33,6 +33,9 @@ class LLRotation;
#include <assert.h>
#include "llpreprocessor.h"
#include "llmemory.h"
#include "glm/vec3.hpp"
#include "glm/vec4.hpp"
#include "glm/gtc/type_ptr.hpp"
///////////////////////////////////
// FIRST TIME USERS PLEASE READ
@ -364,6 +367,16 @@ public:
inline operator LLQuad() const;
explicit inline operator glm::vec3() const
{
return glm::make_vec3(getF32ptr());
};
explicit inline operator glm::vec4() const
{
return glm::make_vec4(getF32ptr());
};
private:
LLQuad mQ{};
};

View File

@ -31,6 +31,11 @@
#include "llmath.h"
#include "llsd.h"
#include "glm/vec3.hpp"
#include "glm/vec4.hpp"
#include "glm/gtc/type_ptr.hpp"
class LLVector2;
class LLVector4;
class LLVector4a;
@ -66,6 +71,11 @@ class LLVector3
explicit LLVector3(const LLVector4a& vec); // Initializes LLVector4 to (vec[0]. vec[1], vec[2])
explicit LLVector3(const LLSD& sd);
// GLM interop
explicit LLVector3(const glm::vec3& vec); // Initializes LLVector3 to (vec[0]. vec[1], vec[2])
explicit LLVector3(const glm::vec4& vec); // Initializes LLVector3 to (vec[0]. vec[1], vec[2])
explicit inline operator glm::vec3() const; // Initializes glm::vec3 to (vec[0]. vec[1], vec[2])
explicit inline operator glm::vec4() const; // Initializes glm::vec4 to (vec[0]. vec[1], vec[2], 1)
LLSD getValue() const;
@ -92,6 +102,8 @@ class LLVector3
inline void set(const F32 *vec); // Sets LLVector3 to vec
const LLVector3& set(const LLVector4 &vec);
const LLVector3& set(const LLVector3d &vec);// Sets LLVector3 to vec
inline void set(const glm::vec4& vec); // Sets LLVector3 to vec
inline void set(const glm::vec3& vec); // Sets LLVector3 to vec
inline void setVec(F32 x, F32 y, F32 z); // deprecated
inline void setVec(const LLVector3 &vec); // deprecated
@ -190,6 +202,20 @@ inline LLVector3::LLVector3(const F32 *vec)
mV[VZ] = vec[VZ];
}
inline LLVector3::LLVector3(const glm::vec3& vec)
{
mV[VX] = vec.x;
mV[VY] = vec.y;
mV[VZ] = vec.z;
}
inline LLVector3::LLVector3(const glm::vec4& vec)
{
mV[VX] = vec.x;
mV[VY] = vec.y;
mV[VZ] = vec.z;
}
/*
inline LLVector3::LLVector3(const LLVector3 &copy)
{
@ -259,6 +285,20 @@ inline void LLVector3::set(const F32 *vec)
mV[2] = vec[2];
}
inline void LLVector3::set(const glm::vec4& vec)
{
mV[VX] = vec.x;
mV[VY] = vec.y;
mV[VZ] = vec.z;
}
inline void LLVector3::set(const glm::vec3& vec)
{
mV[VX] = vec.x;
mV[VY] = vec.y;
mV[VZ] = vec.z;
}
// deprecated
inline void LLVector3::setVec(F32 x, F32 y, F32 z)
{
@ -471,6 +511,17 @@ inline LLVector3 operator-(const LLVector3 &a)
return LLVector3( -a.mV[0], -a.mV[1], -a.mV[2] );
}
inline LLVector3::operator glm::vec3() const
{
// Do not use glm::make_vec3 it can result in a buffer overrun on some platforms due to glm::vec3 being a simd vector internally
return glm::vec3(mV[VX], mV[VY], mV[VZ]);
}
inline LLVector3::operator glm::vec4() const
{
return glm::vec4(mV[VX], mV[VY], mV[VZ], 1.f);
}
inline F32 dist_vec(const LLVector3 &a, const LLVector3 &b)
{
F32 x = a.mV[0] - b.mV[0];

View File

@ -32,6 +32,10 @@
#include "v3math.h"
#include "v2math.h"
#include "glm/vec3.hpp"
#include "glm/vec4.hpp"
#include "glm/gtc/type_ptr.hpp"
class LLMatrix3;
class LLMatrix4;
class LLQuaternion;
@ -73,6 +77,11 @@ class LLVector4
mV[3] = (F32)sd[3].asReal();
}
// GLM interop
explicit LLVector4(const glm::vec3& vec); // Initializes LLVector4 to (vec, 1)
explicit LLVector4(const glm::vec4& vec); // Initializes LLVector4 to vec
explicit operator glm::vec3() const; // Initializes glm::vec3 to (vec[0]. vec[1], vec[2])
explicit operator glm::vec4() const; // Initializes glm::vec4 to (vec[0]. vec[1], vec[2], vec[3])
inline bool isFinite() const; // checks to see if all values of LLVector3 are finite
@ -85,6 +94,8 @@ class LLVector4
inline void set(const LLVector4 &vec); // Sets LLVector4 to vec
inline void set(const LLVector3 &vec, F32 w = 1.f); // Sets LLVector4 to LLVector3 vec
inline void set(const F32 *vec); // Sets LLVector4 to vec
inline void set(const glm::vec4& vec); // Sets LLVector4 to vec
inline void set(const glm::vec3& vec, F32 w = 1.f); // Sets LLVector4 to LLVector3 vec with w defaulted to 1
inline void setVec(F32 x, F32 y, F32 z); // deprecated
inline void setVec(F32 x, F32 y, F32 z, F32 w); // deprecated
@ -223,6 +234,21 @@ inline LLVector4::LLVector4(const LLSD &sd)
setValue(sd);
}
inline LLVector4::LLVector4(const glm::vec3& vec)
{
mV[VX] = vec.x;
mV[VY] = vec.y;
mV[VZ] = vec.z;
mV[VW] = 1.f;
}
inline LLVector4::LLVector4(const glm::vec4& vec)
{
mV[VX] = vec.x;
mV[VY] = vec.y;
mV[VZ] = vec.z;
mV[VW] = vec.w;
}
inline bool LLVector4::isFinite() const
{
@ -297,6 +323,21 @@ inline void LLVector4::set(const F32 *vec)
mV[VW] = vec[VW];
}
inline void LLVector4::set(const glm::vec4& vec)
{
mV[VX] = vec.x;
mV[VY] = vec.y;
mV[VZ] = vec.z;
mV[VW] = vec.w;
}
inline void LLVector4::set(const glm::vec3& vec, F32 w)
{
mV[VX] = vec.x;
mV[VY] = vec.y;
mV[VZ] = vec.z;
mV[VW] = w;
}
// deprecated
inline void LLVector4::setVec(F32 x, F32 y, F32 z)
@ -466,6 +507,16 @@ inline LLVector4 operator-(const LLVector4 &a)
return LLVector4( -a.mV[VX], -a.mV[VY], -a.mV[VZ] );
}
inline LLVector4::operator glm::vec3() const
{
return glm::vec3(mV[VX], mV[VY], mV[VZ]);
}
inline LLVector4::operator glm::vec4() const
{
return glm::make_vec4(mV);
}
inline F32 dist_vec(const LLVector4 &a, const LLVector4 &b)
{
LLVector4 vec = a - b;

View File

@ -109,7 +109,7 @@ LLCubeMapArray::~LLCubeMapArray()
{
}
void LLCubeMapArray::allocate(U32 resolution, U32 components, U32 count, bool use_mips)
void LLCubeMapArray::allocate(U32 resolution, U32 components, U32 count, bool use_mips, bool hdr)
{
U32 texname = 0;
mWidth = resolution;
@ -127,7 +127,11 @@ void LLCubeMapArray::allocate(U32 resolution, U32 components, U32 count, bool us
bind(0);
free_cur_tex_image();
U32 format = components == 4 ? GL_RGBA16F : GL_RGB16F;
U32 format = components == 4 ? GL_RGBA16F : GL_R11F_G11F_B10F;
if (!hdr)
{
format = components == 4 ? GL_RGBA8 : GL_RGB8;
}
U32 mip = 0;
U32 mip_resolution = resolution;
while (mip_resolution >= 1)

View File

@ -52,7 +52,7 @@ public:
// components - number of components per pixel
// count - number of cube maps in the array
// use_mips - if true, mipmaps will be allocated for this cube map array and anisotropic filtering will be used
void allocate(U32 res, U32 components, U32 count, bool use_mips = true);
void allocate(U32 res, U32 components, U32 count, bool use_mips = true, bool hdr = true);
void bind(S32 stage);
void unbind();

View File

@ -107,7 +107,7 @@ bool LLFontBitmapCache::nextOpenPos(S32 width, S32& pos_x, S32& pos_y, EFontGlyp
mBitmapHeight = image_height;
S32 num_components = getNumComponents(bitmap_type);
mImageRawVec[bitmap_idx].push_back(new LLImageRaw(mBitmapWidth, mBitmapHeight, num_components));
mImageRawVec[bitmap_idx].emplace_back(new LLImageRaw(mBitmapWidth, mBitmapHeight, num_components));
bitmap_num = static_cast<U32>(mImageRawVec[bitmap_idx].size()) - 1;
LLImageRaw* image_raw = getImageRaw(bitmap_type, bitmap_num);
@ -117,7 +117,7 @@ bool LLFontBitmapCache::nextOpenPos(S32 width, S32& pos_x, S32& pos_y, EFontGlyp
}
// Make corresponding GL image.
mImageGLVec[bitmap_idx].push_back(new LLImageGL(image_raw, false, false));
mImageGLVec[bitmap_idx].emplace_back(new LLImageGL(image_raw, false, false));
LLImageGL* image_gl = getImageGL(bitmap_type, bitmap_num);
// Start at beginning of the new image.
@ -141,6 +141,7 @@ bool LLFontBitmapCache::nextOpenPos(S32 width, S32& pos_x, S32& pos_y, EFontGlyp
bitmap_num = getNumBitmaps(bitmap_type) - 1;
mCurrentOffsetX[bitmap_idx] += width + 1;
mGeneration++;
return true;
}
@ -168,6 +169,7 @@ void LLFontBitmapCache::reset()
mBitmapWidth = 0;
mBitmapHeight = 0;
mGeneration++;
}
//static

View File

@ -63,6 +63,7 @@ public:
U32 getNumBitmaps(EFontGlyphType bitmapType) const { return (bitmapType < EFontGlyphType::Count) ? static_cast<U32>(mImageRawVec[static_cast<U32>(bitmapType)].size()) : 0U; }
S32 getBitmapWidth() const { return mBitmapWidth; }
S32 getBitmapHeight() const { return mBitmapHeight; }
S32 getCacheGeneration() const { return mGeneration; }
protected:
static U32 getNumComponents(EFontGlyphType bitmap_type);
@ -74,6 +75,7 @@ private:
S32 mCurrentOffsetY[static_cast<U32>(EFontGlyphType::Count)] = { 1 };
S32 mMaxCharWidth = 0;
S32 mMaxCharHeight = 0;
S32 mGeneration = 0;
std::vector<LLPointer<LLImageRaw>> mImageRawVec[static_cast<U32>(EFontGlyphType::Count)];
std::vector<LLPointer<LLImageGL>> mImageGLVec[static_cast<U32>(EFontGlyphType::Count)];
};

View File

@ -146,7 +146,6 @@ LLFontFreetype::LLFontFreetype()
mIsFallback(false),
mFTFace(NULL),
mRenderGlyphCount(0),
mAddGlyphCount(0),
mStyle(0),
mPointSize(0)
{
@ -552,7 +551,7 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l
return NULL;
llassert(!mIsFallback);
fontp->renderGlyph(requested_glyph_type, glyph_index);
fontp->renderGlyph(requested_glyph_type, glyph_index, wch);
EFontGlyphType bitmap_glyph_type = EFontGlyphType::Unspecified;
switch (fontp->mFTFace->glyph->bitmap.pixel_mode)
@ -574,7 +573,6 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l
S32 pos_x, pos_y;
U32 bitmap_num;
mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_glyph_type, bitmap_num);
mAddGlyphCount++;
LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index, requested_glyph_type);
gi->mXBitmapOffset = pos_x;
@ -697,7 +695,7 @@ void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const
}
}
void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) const
void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index, llwchar wch) const
{
if (mFTFace == NULL)
return;
@ -712,11 +710,28 @@ void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) co
FT_Error error = FT_Load_Glyph(mFTFace, glyph_index, load_flags);
if (FT_Err_Ok != error)
{
if (error == FT_Err_Out_Of_Memory)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "Out of memory loading glyph for character " << llformat("U+%xu", U32(wch)) << LL_ENDL;
}
std::string message = llformat(
"Error %d (%s) loading glyph %u: bitmap_type=%u, load_flags=%d",
error, FT_Error_String(error), glyph_index, bitmap_type, load_flags);
"Error %d (%s) loading wchar %u glyph %u/%u: bitmap_type=%u, load_flags=%d",
error, FT_Error_String(error), wch, glyph_index, mFTFace->num_glyphs, bitmap_type, load_flags);
LL_WARNS_ONCE() << message << LL_ENDL;
error = FT_Load_Glyph(mFTFace, glyph_index, load_flags ^ FT_LOAD_COLOR);
if (FT_Err_Invalid_Outline == error
|| 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)
{
error = FT_Load_Glyph(mFTFace, glyph_index, load_flags ^ FT_LOAD_COLOR);
}
}
llassert_always_msg(FT_Err_Ok == error, message.c_str());
}

View File

@ -156,7 +156,7 @@ private:
bool hasGlyph(llwchar wch) const; // Has a glyph for this character
LLFontGlyphInfo* addGlyph(llwchar wch, EFontGlyphType glyph_type) const; // Add a new character to the font if necessary
LLFontGlyphInfo* addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index, EFontGlyphType bitmap_type) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found)
void renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) const;
void renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index, llwchar wch) const;
void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const;
std::string mName;
@ -187,7 +187,6 @@ private:
mutable LLFontBitmapCache* mFontBitmapCachep;
mutable S32 mRenderGlyphCount;
mutable S32 mAddGlyphCount;
};
#endif // LL_FONTFREETYPE_H

View File

@ -58,6 +58,7 @@ F32 LLFontGL::sVertDPI = 96.f;
F32 LLFontGL::sHorizDPI = 96.f;
F32 LLFontGL::sScaleX = 1.f;
F32 LLFontGL::sScaleY = 1.f;
S32 LLFontGL::sResolutionGeneration = 0;
bool LLFontGL::sDisplayFont = true ;
std::string LLFontGL::sAppDir;
@ -109,6 +110,12 @@ S32 LLFontGL::getNumFaces(const std::string& filename)
return mFontFreetype->getNumFaces(filename);
}
S32 LLFontGL::getCacheGeneration() const
{
const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache();
return font_bitmap_cache->getCacheGeneration();
}
S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
ShadowType shadow, S32 max_chars, F32* right_x, bool use_ellipses, bool use_color) const
{
@ -249,6 +256,10 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache();
// This looks wrong, value is dynamic.
// LLFontBitmapCache::nextOpenPos can alter these values when
// new characters get added to cache, which affects whole string.
// Todo: Perhaps value should update after symbols were added?
F32 inv_width = 1.f / font_bitmap_cache->getBitmapWidth();
F32 inv_height = 1.f / font_bitmap_cache->getBitmapHeight();
@ -270,6 +281,10 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
const LLFontGlyphInfo* next_glyph = NULL;
// string can have more than one glyph per char (ex: bold or shadow),
// make sure that GLYPH_BATCH_SIZE won't end up with half a symbol.
// See drawGlyph.
// Ex: with shadows it's 6 glyps per char. 30 fits exactly 5 chars.
static constexpr S32 GLYPH_BATCH_SIZE = 30;
static thread_local LLVector4a vertices[GLYPH_BATCH_SIZE * 6];
static thread_local LLVector2 uvs[GLYPH_BATCH_SIZE * 6];
@ -282,6 +297,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
std::pair<EFontGlyphType, S32> bitmap_entry = std::make_pair(EFontGlyphType::Grayscale, -1);
S32 glyph_count = 0;
llwchar last_char = wstr[begin_offset];
for (i = begin_offset; i < begin_offset + length; i++)
{
llwchar wch = wstr[i];
@ -299,7 +315,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
}
// Per-glyph bitmap texture.
std::pair<EFontGlyphType, S32> next_bitmap_entry = fgi->mBitmapEntry;
if (next_bitmap_entry != bitmap_entry)
if (next_bitmap_entry != bitmap_entry || last_char != wch)
{
// Actually draw the queued glyphs before switching their texture;
// otherwise the queued glyphs will be taken from wrong textures.
@ -316,6 +332,11 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
bitmap_entry = next_bitmap_entry;
LLImageGL* font_image = font_bitmap_cache->getImageGL(bitmap_entry.first, bitmap_entry.second);
gGL.getTexUnit(0)->bind(font_image);
// For some reason it's not enough to compare by bitmap_entry.
// Issue hits emojis, japenese and chinese glyphs, only on first run.
// Todo: figure it out, there might be a bug with raw image data.
last_char = wch;
}
if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))

View File

@ -90,6 +90,7 @@ public:
bool loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool is_fallback, S32 face_n);
S32 getNumFaces(const std::string& filename);
S32 getCacheGeneration() const;
S32 render(const LLWString &text, S32 begin_offset,
const LLRect& rect,
@ -224,6 +225,7 @@ public:
static F32 sHorizDPI;
static F32 sScaleX;
static F32 sScaleY;
static S32 sResolutionGeneration;
static bool sDisplayFont ;
static std::string sAppDir; // For loading fonts

View File

@ -146,7 +146,9 @@ S32 LLFontVertexBuffer::render(
|| mLastScaleY != LLFontGL::sScaleY
|| mLastVertDPI != LLFontGL::sVertDPI
|| mLastHorizDPI != LLFontGL::sHorizDPI
|| mLastOrigin != LLFontGL::sCurOrigin)
|| mLastOrigin != LLFontGL::sCurOrigin
|| mLastResGeneration != LLFontGL::sResolutionGeneration
|| mLastFontCacheGen != fontp->getCacheGeneration())
{
genBuffers(fontp, text, begin_offset, x, y, color, halign, valign,
style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
@ -178,6 +180,9 @@ void LLFontVertexBuffer::genBuffers(
{
// todo: add a debug build assert if this triggers too often for to long?
mBufferList.clear();
// Save before rendreing, it can change mid-render,
// so will need to rerender previous characters
mLastFontCacheGen = fontp->getCacheGeneration();
gGL.beginList(&mBufferList);
mChars = fontp->render(text, begin_offset, x, y, color, halign, valign,
@ -201,6 +206,7 @@ void LLFontVertexBuffer::genBuffers(
mLastVertDPI = LLFontGL::sVertDPI;
mLastHorizDPI = LLFontGL::sHorizDPI;
mLastOrigin = LLFontGL::sCurOrigin;
mLastResGeneration = LLFontGL::sResolutionGeneration;
if (right_x)
{

View File

@ -117,8 +117,13 @@ private:
F32 mLastScaleY = 1.f;
F32 mLastVertDPI = 0.f;
F32 mLastHorizDPI = 0.f;
S32 mLastResGeneration = 0;
LLCoordGL mLastOrigin;
// Adding new characters to bitmap cache can alter value from getBitmapWidth();
// which alters whole string. So rerender when new characters were added to cache.
S32 mLastFontCacheGen = 0;
static bool sEnableBufferCollection;
};

View File

@ -59,6 +59,7 @@ public:
bool attachNothing = false;
bool hasHeroProbes = false;
bool isPBRTerrain = false;
bool hasTonemap = false;
};
// ============= Structure for caching shader uniforms ===============

View File

@ -330,6 +330,7 @@ S32 LLImageGL::dataFormatBits(S32 dataformat)
case GL_RGB: return 24;
case GL_SRGB: return 24;
case GL_RGB8: return 24;
case GL_R11F_G11F_B10F: return 32;
case GL_RGBA: return 32;
case GL_RGBA8: return 32;
case GL_RGB10_A2: return 32;
@ -1773,7 +1774,7 @@ void LLImageGL::syncToMainThread(LLGLuint new_tex_name)
ref();
LL::WorkQueue::postMaybe(
mMainQueue,
[=]()
[=, this]()
{
LL_PROFILE_ZONE_NAMED("cglt - delete callback");
syncTexName(new_tex_name);

View File

@ -737,9 +737,8 @@ void LLLightState::setPosition(const LLVector4& position)
++gGL.mLightHash;
mPosition = position;
//transform position by current modelview matrix
glm::vec4 pos(glm::make_vec4(position.mV));
const glm::mat4& mat = gGL.getModelviewMatrix();
pos = mat * pos;
glm::vec4 pos(position);
pos = gGL.getModelviewMatrix() * pos;
mPosition.set(glm::value_ptr(pos));
}
@ -794,7 +793,7 @@ void LLLightState::setSpotDirection(const LLVector3& direction)
++gGL.mLightHash;
//transform direction by current modelview matrix
glm::vec3 dir(glm::make_vec3(direction.mV));
glm::vec3 dir(direction);
const glm::mat3 mat(gGL.getModelviewMatrix());
dir = mat * dir;
@ -2088,12 +2087,14 @@ void set_last_projection(const glm::mat4& mat)
glm::vec3 mul_mat4_vec3(const glm::mat4& mat, const glm::vec3& vec)
{
//const float w = vec[0] * mat[0][3] + vec[1] * mat[1][3] + vec[2] * mat[2][3] + mat[3][3];
//return glm::vec3(
// (vec[0] * mat[0][0] + vec[1] * mat[1][0] + vec[2] * mat[2][0] + mat[3][0]) / w,
// (vec[0] * mat[0][1] + vec[1] * mat[1][1] + vec[2] * mat[2][1] + mat[3][1]) / w,
// (vec[0] * mat[0][2] + vec[1] * mat[1][2] + vec[2] * mat[2][2] + mat[3][2]) / w
//);
#if 1 // SIMD path results in strange crashes. Fall back to scalar for now.
const float w = vec[0] * mat[0][3] + vec[1] * mat[1][3] + vec[2] * mat[2][3] + mat[3][3];
return glm::vec3(
(vec[0] * mat[0][0] + vec[1] * mat[1][0] + vec[2] * mat[2][0] + mat[3][0]) / w,
(vec[0] * mat[0][1] + vec[1] * mat[1][1] + vec[2] * mat[2][1] + mat[3][1]) / w,
(vec[0] * mat[0][2] + vec[1] * mat[1][2] + vec[2] * mat[2][2] + mat[3][2]) / w
);
#else
LLVector4a x, y, z, s, t, p, q;
x.splat(vec.x);
@ -2123,4 +2124,5 @@ glm::vec3 mul_mat4_vec3(const glm::mat4& mat, const glm::vec3& vec)
res.setAdd(x, z);
res.div(q);
return glm::make_vec3(res.getF32ptr());
#endif
}

View File

@ -291,6 +291,14 @@ bool LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
}
}
if (features->hasTonemap)
{
if (!shader->attachFragmentObject("deferred/tonemapUtilF.glsl"))
{
return false;
}
}
// NOTE order of shader object attaching is VERY IMPORTANT!!!
if (features->hasAtmospherics)
{
@ -466,6 +474,7 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
if (filename.empty())
{
LL_WARNS("ShaderLoading") << "tried loading empty filename" << LL_ENDL;
return 0;
}
@ -923,6 +932,8 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
}
LL_WARNS("ShaderLoading") << "Failed to load " << filename << LL_ENDL;
}
LL_DEBUGS("ShaderLoading") << "loadShaderFile() completed, ret: " << U32(ret) << LL_ENDL;
return ret;
}
@ -1389,6 +1400,7 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("screenTex");
mReservedUniforms.push_back("screenDepth");
mReservedUniforms.push_back("refTex");
mReservedUniforms.push_back("exclusionTex");
mReservedUniforms.push_back("eyeVec");
mReservedUniforms.push_back("time");
mReservedUniforms.push_back("waveDir1");

View File

@ -36,6 +36,8 @@ public:
LLShaderMgr();
virtual ~LLShaderMgr();
// Note: although you can use statically hashed strings to just bind a random uniform, it's generally preferably that you use this.
// Always document what the actual shader uniform is next to the shader uniform in this struct.
// clang-format off
typedef enum
{ // Shader uniform name, set in LLShaderMgr::initAttribsAndUniforms()
@ -234,6 +236,7 @@ public:
WATER_SCREENTEX, // "screenTex"
WATER_SCREENDEPTH, // "screenDepth"
WATER_REFTEX, // "refTex"
WATER_EXCLUSIONTEX, // "exclusionTex"
WATER_EYEVEC, // "eyeVec"
WATER_TIME, // "time"
WATER_WAVE_DIR1, // "waveDir1"

View File

@ -28,6 +28,7 @@
#include "llfolderview.h"
#include "llfolderviewmodel.h"
#include "llcallbacklist.h"
#include "llclipboard.h" // *TODO: remove this once hack below gone.
#include "llkeyboard.h"
#include "lllineeditor.h"
@ -274,7 +275,11 @@ LLFolderView::~LLFolderView( void )
mRenamer = NULL;
mStatusTextBox = NULL;
if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die();
if (mPopupMenuHandle.get())
{
mPopupMenuHandle.get()->die();
gIdleCallbacks.deleteFunction(onIdleUpdateMenu, this);
}
mPopupMenuHandle.markDead();
mAutoOpenItems.removeAllNodes();
@ -1095,7 +1100,10 @@ bool LLFolderView::handleKeyHere( KEY key, MASK mask )
LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
if (menu && menu->isOpen())
{
LLMenuGL::sMenuContainer->hideMenus();
if (LLMenuGL::sMenuContainer->hideMenus())
{
gIdleCallbacks.deleteFunction(onIdleUpdateMenu, this);
}
}
switch( key )
@ -1340,7 +1348,10 @@ bool LLFolderView::handleUnicodeCharHere(llwchar uni_char)
LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
if (menu && menu->isOpen())
{
LLMenuGL::sMenuContainer->hideMenus();
if (LLMenuGL::sMenuContainer->hideMenus())
{
gIdleCallbacks.deleteFunction(onIdleUpdateMenu, this);
}
}
//do text search
@ -1612,7 +1623,11 @@ void LLFolderView::deleteAllChildren()
{
LLUI::getInstance()->removePopup(mRenamer);
}
if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die();
if (mPopupMenuHandle.get())
{
mPopupMenuHandle.get()->die();
gIdleCallbacks.deleteFunction(onIdleUpdateMenu, this);
}
mPopupMenuHandle.markDead();
mScrollContainer = NULL;
mRenameItem = NULL;
@ -1979,9 +1994,24 @@ void LLFolderView::updateMenu()
LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
if (menu && menu->getVisible())
{
updateMenuOptions(menu);
// When fetching folders in bulk or in parts, each callback
// cause updateMenu individually, so make sure it gets called
// only once per frame, after callbacks are done.
// gIdleCallbacks has built in dupplicate protection.
gIdleCallbacks.addFunction(onIdleUpdateMenu, this);
}
}
void LLFolderView::onIdleUpdateMenu(void* user_data)
{
LLFolderView* self = (LLFolderView*)user_data;
LLMenuGL* menu = (LLMenuGL*)self->mPopupMenuHandle.get();
if (menu)
{
self->updateMenuOptions(menu);
menu->needsArrange(); // update menu height if needed
}
gIdleCallbacks.deleteFunction(onIdleUpdateMenu, self);
}
bool LLFolderView::isFolderSelected()

View File

@ -266,6 +266,7 @@ public:
private:
void updateMenuOptions(LLMenuGL* menu);
void updateRenamerPosition();
static void onIdleUpdateMenu(void* user_data);
protected:
LLScrollContainer* mScrollContainer; // NULL if this is not a child of a scroll container.
@ -414,6 +415,7 @@ public:
virtual void doItem(LLFolderViewItem* item) {}
void setApply(bool apply);
void clearOpenFolders() { mOpenFolders.clear(); }
bool hasOpenFolders() { return !mOpenFolders.empty(); }
protected:
std::set<LLUUID> mOpenFolders;
bool mApply;

View File

@ -1555,7 +1555,7 @@ bool LLNotifications::loadTemplates()
gDirUtilp->findSkinnedFilenames(LLDir::XUI, "notifications.xml", LLDir::ALL_SKINS);
if (search_paths.empty())
{
LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"));
LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"), LLError::LLUserWarningMsg::ERROR_MISSING_FILES);
LL_ERRS() << "Problem finding notifications.xml" << LL_ENDL;
}
@ -1565,7 +1565,7 @@ bool LLNotifications::loadTemplates()
if (!success || root.isNull() || !root->hasName( "notifications" ))
{
LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"));
LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"), LLError::LLUserWarningMsg::ERROR_MISSING_FILES);
LL_ERRS() << "Problem reading XML from UI Notifications file: " << base_filename << LL_ENDL;
return false;
}
@ -1576,7 +1576,7 @@ bool LLNotifications::loadTemplates()
if(!params.validateBlock())
{
LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"));
LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"), LLError::LLUserWarningMsg::ERROR_MISSING_FILES);
LL_ERRS() << "Problem reading XUI from UI Notifications file: " << base_filename << LL_ENDL;
return false;
}
@ -1643,7 +1643,7 @@ bool LLNotifications::loadVisibilityRules()
if(!params.validateBlock())
{
LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"));
LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"), LLError::LLUserWarningMsg::ERROR_MISSING_FILES);
LL_ERRS() << "Problem reading UI Notification Visibility Rules file: " << full_filename << LL_ENDL;
return false;
}

View File

@ -39,7 +39,7 @@ LLStyle::Params::Params()
readonly_color("readonly_color", LLColor4::black),
selected_color("selected_color", LLColor4::black),
alpha("alpha", 1.f),
font("font", LLFontGL::getFontMonospace()),
font("font", LLStyle::getDefaultFont()),
image("image"),
link_href("href"),
is_link("is_link")
@ -70,6 +70,11 @@ const LLFontGL* LLStyle::getFont() const
return mFont;
}
const LLFontGL* LLStyle::getDefaultFont()
{
return LLFontGL::getFontMonospace();
}
void LLStyle::setLinkHREF(const std::string& href)
{
mLink = href;

View File

@ -72,6 +72,7 @@ public:
void setFont(const LLFontGL* font);
const LLFontGL* getFont() const;
static const LLFontGL* getDefaultFont();
const std::string& getLinkHREF() const { return mLink; }
void setLinkHREF(const std::string& href);

View File

@ -1438,7 +1438,8 @@ void LLTextBase::onVisibilityChange( bool new_visibility )
//virtual
void LLTextBase::setValue(const LLSD& value )
{
setText(value.asString());
static const LLStyle::Params input_params = LLStyle::Params();
setText(value.asString(), input_params);
}
//virtual
@ -3880,8 +3881,7 @@ bool LLInlineViewSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& w
if (mForceNewLine)
{
// Chat, string can't be smaller then font height even if it is empty
LLStyleSP s(new LLStyle(LLStyle::Params().visible(true)));
height = s->getFont()->getLineHeight();
height = LLStyle::getDefaultFont()->getLineHeight();
return true; // new line
}
@ -3945,9 +3945,7 @@ void LLInlineViewSegment::linkToDocument(LLTextBase* editor)
LLLineBreakTextSegment::LLLineBreakTextSegment(S32 pos):LLTextSegment(pos,pos+1)
{
LLStyleSP s( new LLStyle(LLStyle::Params().visible(true)));
mFontHeight = s->getFont()->getLineHeight();
mFontHeight = LLStyle::getDefaultFont()->getLineHeight();
}
LLLineBreakTextSegment::LLLineBreakTextSegment(LLStyleConstSP style,S32 pos):LLTextSegment(pos,pos+1)
{

View File

@ -159,7 +159,8 @@ LLSD LLTextBox::getValue() const
bool LLTextBox::setTextArg( const std::string& key, const LLStringExplicit& text )
{
mText.setArg(key, text);
LLTextBase::setText(mText.getString());
static const LLStyle::Params input_params = LLStyle::Params();
LLTextBase::setText(mText.getString(), input_params);
return true;
}

View File

@ -48,7 +48,7 @@ bool LLTransUtil::parseStrings(const std::string& xml_filename, const std::set<s
"Second Life viewer couldn't access some of the files it needs and will be closed."
"\n\nPlease reinstall viewer from https://secondlife.com/support/downloads/ and "
"contact https://support.secondlife.com if issue persists after reinstall.";
LLError::LLUserWarningMsg::show(error_string);
LLError::LLUserWarningMsg::show(error_string, LLError::LLUserWarningMsg::ERROR_MISSING_FILES);
gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN);
LL_ERRS() << "Couldn't load string table " << xml_filename << " " << errno << LL_ENDL;
return false;

View File

@ -194,6 +194,11 @@ bool LLWindowCallbacks::handleDPIChanged(LLWindow *window, F32 ui_scale_factor,
return false;
}
bool LLWindowCallbacks::handleDisplayChanged()
{
return false;
}
bool LLWindowCallbacks::handleWindowDidChangeScreen(LLWindow *window)
{
return false;

View File

@ -69,6 +69,7 @@ public:
virtual bool handleTimerEvent(LLWindow *window);
virtual bool handleDeviceChange(LLWindow *window);
virtual bool handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height);
virtual bool handleDisplayChanged();
virtual bool handleWindowDidChangeScreen(LLWindow *window);
enum DragNDropAction {

View File

@ -1060,7 +1060,7 @@ F32 LLWindowMacOSX::getGamma()
&greenGamma,
&blueMin,
&blueMax,
&blueGamma) == noErr)
&blueGamma) == kCGErrorSuccess)
{
// So many choices...
// Let's just return the green channel gamma for now.
@ -1111,7 +1111,7 @@ bool LLWindowMacOSX::setGamma(const F32 gamma)
&greenGamma,
&blueMin,
&blueMax,
&blueGamma) != noErr)
&blueGamma) != kCGErrorSuccess)
{
return false;
}
@ -1126,7 +1126,7 @@ bool LLWindowMacOSX::setGamma(const F32 gamma)
gamma,
blueMin,
blueMax,
gamma) != noErr)
gamma) != kCGErrorSuccess)
{
return false;
}
@ -1178,7 +1178,7 @@ bool LLWindowMacOSX::setCursorPosition(const LLCoordWindow position)
newPosition.y = screen_pos.mY;
CGSetLocalEventsSuppressionInterval(0.0);
if(CGWarpMouseCursorPosition(newPosition) == noErr)
if(CGWarpMouseCursorPosition(newPosition) == kCGErrorSuccess)
{
result = true;
}

View File

@ -44,6 +44,7 @@
#include "llstring.h"
#include "lldir.h"
#include "llsdutil.h"
#include "llsys.h"
#include "llglslshader.h"
#include "llthreadsafequeue.h"
#include "stringize.h"
@ -80,10 +81,6 @@ const S32 BITS_PER_PIXEL = 32;
const S32 MAX_NUM_RESOLUTIONS = 32;
const F32 ICON_FLASH_TIME = 0.5f;
#ifndef WM_DPICHANGED
#define WM_DPICHANGED 0x02E0
#endif
#ifndef USER_DEFAULT_SCREEN_DPI
#define USER_DEFAULT_SCREEN_DPI 96 // Win7
#endif
@ -1317,8 +1314,7 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo
catch (...)
{
LOG_UNHANDLED_EXCEPTION("ChoosePixelFormat");
OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"),
mCallbacks->translateString("MBError"), OSMB_OK);
LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBPixelFmtErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/);
close();
return false;
}
@ -1329,8 +1325,7 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo
if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR),
&pfd))
{
OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"),
mCallbacks->translateString("MBError"), OSMB_OK);
LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBPixelFmtDescErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/);
close();
return false;
}
@ -1368,8 +1363,7 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo
if (!SetPixelFormat(mhDC, pixel_format, &pfd))
{
OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"),
mCallbacks->translateString("MBError"), OSMB_OK);
LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBPixelFmtSetErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/);
close();
return false;
}
@ -1377,16 +1371,14 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo
if (!(mhRC = SafeCreateContext(mhDC)))
{
OSMessageBox(mCallbacks->translateString("MBGLContextErr"),
mCallbacks->translateString("MBError"), OSMB_OK);
LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBGLContextErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/);
close();
return false;
}
if (!wglMakeCurrent(mhDC, mhRC))
{
OSMessageBox(mCallbacks->translateString("MBGLContextActErr"),
mCallbacks->translateString("MBError"), OSMB_OK);
LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBGLContextActErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/);
close();
return false;
}
@ -1592,15 +1584,14 @@ const S32 max_format = (S32)num_formats - 1;
if (!mhDC)
{
OSMessageBox(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK);
LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBDevContextErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/);
close();
return false;
}
if (!SetPixelFormat(mhDC, pixel_format, &pfd))
{
OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"),
mCallbacks->translateString("MBError"), OSMB_OK);
LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBPixelFmtSetErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/);
close();
return false;
}
@ -1632,7 +1623,7 @@ const S32 max_format = (S32)num_formats - 1;
{
LL_WARNS("Window") << "No wgl_ARB_pixel_format extension!" << LL_ENDL;
// cannot proceed without wgl_ARB_pixel_format extension, shutdown same as any other gGLManager.initGL() failure
OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK);
LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBVideoDrvErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/);
close();
return false;
}
@ -1641,7 +1632,7 @@ const S32 max_format = (S32)num_formats - 1;
if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR),
&pfd))
{
OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK);
LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBPixelFmtDescErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/);
close();
return false;
}
@ -1663,14 +1654,14 @@ const S32 max_format = (S32)num_formats - 1;
if (!wglMakeCurrent(mhDC, mhRC))
{
OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK);
LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBGLContextActErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/);
close();
return false;
}
if (!gGLManager.initGL())
{
OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK);
LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBVideoDrvErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/);
close();
return false;
}
@ -1875,7 +1866,7 @@ void* LLWindowWin32::createSharedContext()
if (!rc && !(rc = wglCreateContext(mhDC)))
{
close();
OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK);
LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBGLContextErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/);
}
return rc;
@ -2974,6 +2965,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
return 0;
}
case WM_DISPLAYCHANGE:
{
WINDOW_IMP_POST(window_imp->mCallbacks->handleDisplayChanged());
}
case WM_SETFOCUS:
{
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETFOCUS");
@ -4681,6 +4677,23 @@ void LLWindowWin32::LLWindowWin32Thread::checkDXMem()
// Alternatively use GetDesc from below to get adapter's memory
UINT64 budget_mb = info.Budget / (1024 * 1024);
if (gGLManager.mIsIntel)
{
U32Megabytes phys_mb = gSysMemory.getPhysicalMemoryKB();
LL_WARNS() << "Physical memory: " << phys_mb << " MB" << LL_ENDL;
if (phys_mb > 0)
{
// Intel uses 'shared' vram, cap it to 25% of total memory
// Todo: consider caping all adapters at least to 50% ram
budget_mb = llmin(budget_mb, (UINT64)(phys_mb * 0.25));
}
else
{
// if no data available, cap to 2Gb
budget_mb = llmin(budget_mb, (UINT64)2048);
}
}
if (gGLManager.mVRAM < (S32)budget_mb)
{
gGLManager.mVRAM = (S32)budget_mb;

View File

@ -156,6 +156,7 @@ set(viewer_SOURCE_FILES
lldrawpooltree.cpp
lldrawpoolwater.cpp
lldrawpoolwlsky.cpp
lldrawpoolwaterexclusion.cpp
lldynamictexture.cpp
llemote.cpp
llenvironment.cpp
@ -823,6 +824,7 @@ set(viewer_HEADER_FILES
lldrawpooltree.h
lldrawpoolwater.h
lldrawpoolwlsky.h
lldrawpoolwaterexclusion.h
lldynamictexture.h
llemote.h
llenvironment.h

View File

@ -12717,7 +12717,7 @@
<key>UpdaterWillingToTest</key>
<map>
<key>Comment</key>
<string>Whether or not the updater should offer test candidate upgrades.</string>
<string>Whether or not the updater should offer Beta upgrades.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>

View File

@ -28,138 +28,11 @@
out vec4 frag_color;
uniform sampler2D diffuseRect;
uniform sampler2D exposureMap;
uniform vec2 screen_res;
in vec2 vary_fragcoord;
vec3 linear_to_srgb(vec3 cl);
//===============================================================
// tone mapping taken from Khronos sample implementation
//===============================================================
// sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT
const mat3 ACESInputMat = mat3
(
0.59719, 0.07600, 0.02840,
0.35458, 0.90834, 0.13383,
0.04823, 0.01566, 0.83777
);
// ODT_SAT => XYZ => D60_2_D65 => sRGB
const mat3 ACESOutputMat = mat3
(
1.60475, -0.10208, -0.00327,
-0.53108, 1.10813, -0.07276,
-0.07367, -0.00605, 1.07602
);
// ACES tone map (faster approximation)
// see: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
vec3 toneMapACES_Narkowicz(vec3 color)
{
const float A = 2.51;
const float B = 0.03;
const float C = 2.43;
const float D = 0.59;
const float E = 0.14;
return clamp((color * (A * color + B)) / (color * (C * color + D) + E), 0.0, 1.0);
}
// ACES filmic tone map approximation
// see https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
vec3 RRTAndODTFit(vec3 color)
{
vec3 a = color * (color + 0.0245786) - 0.000090537;
vec3 b = color * (0.983729 * color + 0.4329510) + 0.238081;
return a / b;
}
// tone mapping
vec3 toneMapACES_Hill(vec3 color)
{
color = ACESInputMat * color;
// Apply RRT and ODT
color = RRTAndODTFit(color);
color = ACESOutputMat * color;
// Clamp to [0, 1]
color = clamp(color, 0.0, 1.0);
return color;
}
// Khronos Neutral tonemapping
// https://github.com/KhronosGroup/ToneMapping/tree/main
// Input color is non-negative and resides in the Linear Rec. 709 color space.
// Output color is also Linear Rec. 709, but in the [0, 1] range.
vec3 PBRNeutralToneMapping( vec3 color )
{
const float startCompression = 0.8 - 0.04;
const float desaturation = 0.15;
float x = min(color.r, min(color.g, color.b));
float offset = x < 0.08 ? x - 6.25 * x * x : 0.04;
color -= offset;
float peak = max(color.r, max(color.g, color.b));
if (peak < startCompression) return color;
const float d = 1. - startCompression;
float newPeak = 1. - d * d / (peak + d - startCompression);
color *= newPeak / peak;
float g = 1. - 1. / (desaturation * (peak - newPeak) + 1.);
return mix(color, newPeak * vec3(1, 1, 1), g);
}
uniform float exposure;
uniform float tonemap_mix;
uniform int tonemap_type;
vec3 toneMap(vec3 color)
{
#ifndef NO_POST
float exp_scale = texture(exposureMap, vec2(0.5,0.5)).r;
color *= exposure * exp_scale;
vec3 clamped_color = clamp(color.rgb, vec3(0.0), vec3(1.0));
switch(tonemap_type)
{
case 0:
color = PBRNeutralToneMapping(color);
break;
case 1:
color = toneMapACES_Hill(color);
break;
}
// mix tonemapped and linear here to provide adjustment
color = mix(clamped_color, color, tonemap_mix);
#endif
return color;
}
//===============================================================
void debugExposure(inout vec3 color)
{
float exp_scale = texture(exposureMap, vec2(0.5,0.5)).r;
exp_scale *= 0.5;
if (abs(vary_fragcoord.y-exp_scale) < 0.01 && vary_fragcoord.x < 0.1)
{
color = vec3(1,0,0);
}
}
vec3 toneMap(vec3 color);
void main()
{

View File

@ -0,0 +1,180 @@
/**
* @file postDeferredTonemap.glsl
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
/*[EXTRA_CODE_HERE]*/
uniform sampler2D exposureMap;
uniform vec2 screen_res;
in vec2 vary_fragcoord;
//===============================================================
// tone mapping taken from Khronos sample implementation
//===============================================================
// sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT
const mat3 ACESInputMat = mat3
(
0.59719, 0.07600, 0.02840,
0.35458, 0.90834, 0.13383,
0.04823, 0.01566, 0.83777
);
// ODT_SAT => XYZ => D60_2_D65 => sRGB
const mat3 ACESOutputMat = mat3
(
1.60475, -0.10208, -0.00327,
-0.53108, 1.10813, -0.07276,
-0.07367, -0.00605, 1.07602
);
// ACES tone map (faster approximation)
// see: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
vec3 toneMapACES_Narkowicz(vec3 color)
{
const float A = 2.51;
const float B = 0.03;
const float C = 2.43;
const float D = 0.59;
const float E = 0.14;
return clamp((color * (A * color + B)) / (color * (C * color + D) + E), 0.0, 1.0);
}
// ACES filmic tone map approximation
// see https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
vec3 RRTAndODTFit(vec3 color)
{
vec3 a = color * (color + 0.0245786) - 0.000090537;
vec3 b = color * (0.983729 * color + 0.4329510) + 0.238081;
return a / b;
}
// tone mapping
vec3 toneMapACES_Hill(vec3 color)
{
color = ACESInputMat * color;
// Apply RRT and ODT
color = RRTAndODTFit(color);
color = ACESOutputMat * color;
// Clamp to [0, 1]
color = clamp(color, 0.0, 1.0);
return color;
}
// Khronos Neutral tonemapping
// https://github.com/KhronosGroup/ToneMapping/tree/main
// Input color is non-negative and resides in the Linear Rec. 709 color space.
// Output color is also Linear Rec. 709, but in the [0, 1] range.
vec3 PBRNeutralToneMapping( vec3 color )
{
const float startCompression = 0.8 - 0.04;
const float desaturation = 0.15;
float x = min(color.r, min(color.g, color.b));
float offset = x < 0.08 ? x - 6.25 * x * x : 0.04;
color -= offset;
float peak = max(color.r, max(color.g, color.b));
if (peak < startCompression) return color;
const float d = 1. - startCompression;
float newPeak = 1. - d * d / (peak + d - startCompression);
color *= newPeak / peak;
float g = 1. - 1. / (desaturation * (peak - newPeak) + 1.);
return mix(color, newPeak * vec3(1, 1, 1), g);
}
uniform float exposure;
uniform float tonemap_mix;
uniform int tonemap_type;
vec3 toneMap(vec3 color)
{
#ifndef NO_POST
float exp_scale = texture(exposureMap, vec2(0.5,0.5)).r;
color *= exposure * exp_scale;
vec3 clamped_color = clamp(color.rgb, vec3(0.0), vec3(1.0));
switch(tonemap_type)
{
case 0:
color = PBRNeutralToneMapping(color);
break;
case 1:
color = toneMapACES_Hill(color);
break;
}
// mix tonemapped and linear here to provide adjustment
color = mix(clamped_color, color, tonemap_mix);
#endif
return color;
}
vec3 toneMapNoExposure(vec3 color)
{
#ifndef NO_POST
vec3 clamped_color = clamp(color.rgb, vec3(0.0), vec3(1.0));
switch(tonemap_type)
{
case 0:
color = PBRNeutralToneMapping(color);
break;
case 1:
color = toneMapACES_Hill(color);
break;
}
// mix tonemapped and linear here to provide adjustment
color = mix(clamped_color, color, tonemap_mix);
#endif
return color;
}
//===============================================================
void debugExposure(inout vec3 color)
{
float exp_scale = texture(exposureMap, vec2(0.5,0.5)).r;
exp_scale *= 0.5;
if (abs(vary_fragcoord.y-exp_scale) < 0.01 && vary_fragcoord.x < 0.1)
{
color = vec3(1,0,0);
}
}

View File

@ -41,6 +41,26 @@ vec3 srgb_to_linear(vec3 cs)
}
vec4 srgb_to_linear4(vec4 cs)
{
vec4 low_range = cs / vec4(12.92);
vec4 high_range = pow((cs+vec4(0.055))/vec4(1.055), vec4(2.4));
bvec4 lte = lessThanEqual(cs,vec4(0.04045));
#ifdef OLD_SELECT
vec4 result;
result.r = lte.r ? low_range.r : high_range.r;
result.g = lte.g ? low_range.g : high_range.g;
result.b = lte.b ? low_range.b : high_range.b;
result.a = lte.a ? low_range.a : high_range.a;
return result;
#else
return mix(high_range, low_range, lte);
#endif
}
vec3 linear_to_srgb(vec3 cl)
{
cl = clamp(cl, vec3(0), vec3(1));

View File

@ -66,11 +66,11 @@ vec4 getWaterFogViewNoClip(vec3 pos)
float t2 = kd + ks * es;
float t3 = pow(F, t2*l) - 1.0;
float L = min(t1/t2*t3, 1.0);
float L = pow(min(t1/t2*t3, 1.0), 1.0/1.7);
float D = pow(0.98, l*kd);
return vec4(srgb_to_linear(kc.rgb*L), D);
return vec4(srgb_to_linear(kc.rgb)*L, D);
}
vec4 getWaterFogView(vec3 pos)

View File

@ -0,0 +1,57 @@
/**
* @file simpleColorF.glsl
*
* $LicenseInfo:firstyear=2025&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2007, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
out vec4 frag_color;
in vec4 vertex_color;
in vec4 vertex_position;
uniform vec4 waterPlane;
uniform float waterSign;
void waterClip(vec3 pos)
{
// TODO: make this less branchy
if (waterSign > 0)
{
if ((dot(pos.xyz, waterPlane.xyz) + waterPlane.w) < 0.0)
{
discard;
}
}
else
{
if ((dot(pos.xyz, waterPlane.xyz) + waterPlane.w) > 0.0)
{
discard;
}
}
}
void main()
{
frag_color = vertex_color;
}

View File

@ -0,0 +1,43 @@
/**
* @file simpleNoAtmosV.glsl
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2007, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
uniform mat4 modelview_matrix;
uniform mat4 modelview_projection_matrix;
uniform vec4 color;
in vec3 position;
out vec4 vertex_color;
out vec4 vertex_position;
void main()
{
//transform vertex
vec4 pos = (modelview_matrix * vec4(position.xyz, 1.0));
vertex_position = modelview_projection_matrix * vec4(position.xyz, 1.0);
gl_Position = vertex_position;
vertex_color = color;
}

View File

@ -150,7 +150,7 @@ vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec
float amb_da = 0.0;//ambiance;
if (da > 0)
{
lit = max(da * dist_atten,0.0);
lit = clamp(da * dist_atten, 0.0, 1.0);
col = lit * light_col * diffuse;
amb_da += (da*0.5+0.5) * ambiance;
}

View File

@ -140,7 +140,7 @@ vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 npos, vec3 diffuse, vec4 spe
float amb_da = ambiance;
if (da >= 0)
{
lit = max(da * dist_atten, 0.0);
lit = clamp(da * dist_atten, 0.0, 1.0);
col = lit * light_col * diffuse;
amb_da += (da*0.5 + 0.5) * ambiance;
}

View File

@ -38,6 +38,8 @@ uniform float max_probe_lod;
uniform bool transparent_surface;
uniform int classic_mode;
#define MAX_REFMAP_COUNT 256 // must match LL_MAX_REFLECTION_PROBE_COUNT
layout (std140) uniform ReflectionProbes
@ -739,7 +741,10 @@ void doProbeSample(inout vec3 ambenv, inout vec3 glossenv,
vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
ambenv = sampleProbeAmbient(pos, norm, amblit);
ambenv = amblit;
if (classic_mode == 0)
ambenv = sampleProbeAmbient(pos, norm, amblit);
float lod = (1.0-glossiness)*reflection_lods;
glossenv = sampleProbes(pos, normalize(refnormpersp), lod);
@ -784,9 +789,6 @@ void sampleReflectionProbesWater(inout vec3 ambenv, inout vec3 glossenv,
probeIndex[probeInfluences++] = 0;
doProbeSample(ambenv, glossenv, tc, pos, norm, glossiness, false, amblit);
// fudge factor to get PBR water at a similar luminance ot legacy water
glossenv *= 0.4;
}
void debugTapRefMap(vec3 pos, vec3 dir, float depth, int i, inout vec4 col)
@ -845,7 +847,10 @@ void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout
vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
ambenv = sampleProbeAmbient(pos, norm, amblit);
ambenv = amblit;
if (classic_mode == 0)
ambenv = sampleProbeAmbient(pos, norm, amblit);
if (glossiness > 0.0)
{

View File

@ -35,13 +35,25 @@ vec4 getWaterFogView(vec3 pos);
uniform int above_water;
uniform sampler2D exclusionTex;
void main()
{
vec2 tc = vary_fragcoord.xy/vary_fragcoord.w*0.5+0.5;
float depth = getDepth(tc.xy);
float mask = texture(exclusionTex, tc.xy).r;
if (above_water > 0)
{
// Just discard if we're in the exclusion mask.
// The previous invisiprim hack we're replacing would also crank up water fog desntiy.
// But doing that makes exclusion surfaces very slow as we'd need to render even more into the mask.
// - Geenz 2025-02-06
if (mask < 1)
{
discard;
}
// we want to depth test when the camera is above water, but some GPUs have a hard time
// with depth testing against render targets that are bound for sampling in the same shader
// so we do it manually here
@ -51,11 +63,13 @@ void main()
{
discard;
}
}
vec4 pos = getPositionWithDepth(tc, depth);
vec4 fogged = getWaterFogView(pos.xyz);
fogged.a = max(pow(fogged.a, 1.7), 0);
frag_color = max(fogged, vec4(0)); //output linear since local lights will be added to this shader's results

View File

@ -26,6 +26,7 @@
out vec4 frag_color;
uniform sampler2D bumpMap;
uniform sampler2D exclusionTex;
#ifdef TRANSPARENT_WATER
uniform sampler2D screenTex;
@ -59,6 +60,9 @@ void mirrorClip(vec3 position);
void main()
{
mirrorClip(vary_position);
vec2 screen_tc = (refCoord.xy/refCoord.z) * 0.5 + 0.5;
float water_mask = texture(exclusionTex, screen_tc).r;
vec4 color;
//get detail normals
@ -68,8 +72,8 @@ void main()
vec3 wavef = normalize(wave1+wave2+wave3);
//figure out distortion vector (ripply)
vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5;
distort = distort+wavef.xy*refScale;
vec2 distort = screen_tc;
distort = mix(distort, distort+wavef.xy*refScale, water_mask);
#ifdef TRANSPARENT_WATER
vec4 fb = texture(screenTex, distort);

View File

@ -25,6 +25,8 @@
// class3/environment/waterF.glsl
#define WATER_MINIMAL 1
out vec4 frag_color;
#ifdef HAS_SUN_SHADOW
@ -86,23 +88,17 @@ uniform sampler2D screenTex;
uniform sampler2D depthMap;
#endif
uniform sampler2D refTex;
uniform sampler2D exclusionTex;
uniform float sunAngle;
uniform float sunAngle2;
uniform int classic_mode;
uniform vec3 lightDir;
uniform vec3 specular;
uniform float lightExp;
uniform float blurMultiplier;
uniform float refScale;
uniform float kd;
uniform vec2 screenRes;
uniform vec3 normScale;
uniform float fresnelScale;
uniform float fresnelOffset;
uniform float blurMultiplier;
uniform vec4 waterFogColor;
uniform vec3 waterFogColorLinear;
//bigWave is (refCoord.w, view.w);
in vec4 refCoord;
@ -122,6 +118,10 @@ vec3 BlendNormal(vec3 bump1, vec3 bump2)
vec3 srgb_to_linear(vec3 col);
vec3 linear_to_srgb(vec3 col);
vec3 atmosLighting(vec3 light);
vec3 scaleSoftClip(vec3 light);
vec3 toneMapNoExposure(vec3 color);
vec3 vN, vT, vB;
vec3 transform_normal(vec3 vNt)
@ -132,59 +132,107 @@ vec3 transform_normal(vec3 vNt)
void sampleReflectionProbesWater(inout vec3 ambenv, inout vec3 glossenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, vec3 amblit_linear);
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear);
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit);
vec3 getPositionWithNDC(vec3 ndc);
void generateWaveNormals(out vec3 wave1, out vec3 wave2, out vec3 wave3)
{
// Generate all of our wave normals.
// We layer these back and forth.
vec2 bigwave = vec2(refCoord.w, view.w);
vec3 wave1_a = texture(bumpMap, bigwave).xyz * 2.0 - 1.0;
vec3 wave2_a = texture(bumpMap, littleWave.xy).xyz * 2.0 - 1.0;
vec3 wave3_a = texture(bumpMap, littleWave.zw).xyz * 2.0 - 1.0;
vec3 wave1_b = texture(bumpMap2, bigwave).xyz * 2.0 - 1.0;
vec3 wave2_b = texture(bumpMap2, littleWave.xy).xyz * 2.0 - 1.0;
vec3 wave3_b = texture(bumpMap2, littleWave.zw).xyz * 2.0 - 1.0;
wave1 = BlendNormal(wave1_a, wave1_b);
wave2 = BlendNormal(wave2_a, wave2_b);
wave3 = BlendNormal(wave3_a, wave3_b);
}
void calculateFresnelFactors(out vec3 df3, out vec2 df2, vec3 viewVec, vec3 wave1, vec3 wave2, vec3 wave3, vec3 wavef)
{
// We calculate the fresnel here.
// We do this by getting the dot product for each sets of waves, and applying scale and offset.
df3 = max(vec3(0), vec3(
dot(viewVec, wave1),
dot(viewVec, (wave2 + wave3) * 0.5),
dot(viewVec, wave3)
) * fresnelScale + fresnelOffset);
df3 *= df3;
df2 = max(vec2(0), vec2(
df3.x + df3.y + df3.z,
dot(viewVec, wavef) * fresnelScale + fresnelOffset
));
}
void main()
{
mirrorClip(vary_position);
vN = vary_normal;
vT = vary_tangent;
vB = cross(vN, vT);
vec3 pos = vary_position.xyz;
float linear_depth = 1 / -pos.z;
float dist = length(pos.xyz);
//normalize view vector
vec3 viewVec = normalize(pos.xyz);
//get wave normals
vec2 bigwave = vec2(refCoord.w, view.w);
vec3 wave1_a = texture(bumpMap, bigwave, -2 ).xyz*2.0-1.0;
vec3 wave2_a = texture(bumpMap, littleWave.xy).xyz*2.0-1.0;
vec3 wave3_a = texture(bumpMap, littleWave.zw).xyz*2.0-1.0;
// Setup our waves.
vec3 wave1_b = texture(bumpMap2, bigwave ).xyz*2.0-1.0;
vec3 wave2_b = texture(bumpMap2, littleWave.xy).xyz*2.0-1.0;
vec3 wave3_b = texture(bumpMap2, littleWave.zw).xyz*2.0-1.0;
vec3 wave1 = vec3(0, 0, 1);
vec3 wave2 = vec3(0, 0, 1);
vec3 wave3 = vec3(0, 0, 1);
//wave1_a = wave2_a = wave3_a = wave1_b = wave2_b = wave3_b = vec3(0,0,1);
vec3 wave1 = BlendNormal(wave1_a, wave1_b);
vec3 wave2 = BlendNormal(wave2_a, wave2_b);
vec3 wave3 = BlendNormal(wave3_a, wave3_b);
generateWaveNormals(wave1, wave2, wave3);
float dmod = sqrt(dist);
vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5;
//wave1 = transform_normal(wave1);
//wave2 = transform_normal(wave2);
//wave3 = transform_normal(wave3);
vec3 wavef = (wave1 + wave2 * 0.4 + wave3 * 0.6) * 0.5;
vec3 df3 = vec3(0);
vec2 df2 = vec2(0);
vec3 sunlit;
vec3 amblit;
vec3 additive;
vec3 atten;
calcAtmosphericVarsLinear(pos.xyz, wavef, vary_light_dir, sunlit, amblit, additive, atten);
calculateFresnelFactors(df3, df2, normalize(view.xyz), wave1, wave2, wave3, wavef);
vec3 waver = wavef*3;
vec3 up = transform_normal(vec3(0,0,1));
float vdu = -dot(viewVec, up)*2;
vec3 wave_ibl = wavef;
vec3 wave_ibl = wavef * normScale;
wave_ibl.z *= 2.0;
wave_ibl = transform_normal(normalize(wave_ibl));
vec3 norm = transform_normal(normalize(wavef));
vdu = clamp(vdu, 0, 1);
wavef.z *= max(vdu*vdu*vdu, 0.1);
//wavef.z *= max(vdu*vdu*vdu, 0.1);
wavef = normalize(wavef);
@ -194,62 +242,66 @@ void main()
float dist2 = dist;
dist = max(dist, 5.0);
float dmod = sqrt(dist);
//figure out distortion vector (ripply)
vec2 distort2 = distort + waver.xy * refScale / max(dmod, 1.0);
vec2 distort2 = distort + waver.xy * refScale / max(dmod, 1.0) * 2;
distort2 = clamp(distort2, vec2(0), vec2(0.999));
vec3 sunlit;
vec3 amblit;
vec3 additive;
vec3 atten;
float shadow = 1.0f;
float water_mask = texture(exclusionTex, distort).r;
#ifdef HAS_SUN_SHADOW
shadow = sampleDirectionalShadow(pos.xyz, norm.xyz, distort);
#endif
calcAtmosphericVarsLinear(pos.xyz, wavef, vary_light_dir, sunlit, amblit, additive, atten);
vec3 sunlit_linear = srgb_to_linear(sunlit);
vec3 sunlit_linear = sunlit;
float fade = 1;
#ifdef TRANSPARENT_WATER
vec4 fb = texture(screenTex, distort2);
float depth = texture(depthMap, distort2).r;
vec3 refPos = getPositionWithNDC(vec3(distort2*2.0-vec2(1.0), depth*2.0-1.0));
float depth = texture(depthMap, distort).r;
if (refPos.z > pos.z-0.05)
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;
distort2 = mix(distort, distort2, min(1, fade * 10));
depth = texture(depthMap, distort2).r;
refPos = getPositionWithNDC(vec3(distort2 * 2.0 - vec2(1.0), depth * 2.0 - 1.0));
if (pos.z < refPos.z - 0.05)
{
//we sampled an above water sample, don't distort
distort2 = distort;
fb = texture(screenTex, distort2);
depth = texture(depthMap, distort2).r;
refPos = getPositionWithNDC(vec3(distort2 * 2.0 - vec2(1.0), depth * 2.0 - 1.0));
}
vec4 fb = texture(screenTex, distort2);
#else
vec4 fb = applyWaterFogViewLinear(viewVec*2048.0, vec4(1.0));
if (water_mask < 1)
discard;
#endif
// fudge sample on other side of water to be a tad darker
fb.rgb *= 0.75;
float metallic = 0.0;
float perceptualRoughness = 0.05;
float gloss = 1.0 - perceptualRoughness;
float metallic = 1.0;
float perceptualRoughness = blurMultiplier;
float gloss = 1 - perceptualRoughness;
vec3 irradiance = vec3(0);
vec3 radiance = vec3(0);
sampleReflectionProbesWater(irradiance, radiance, distort2, pos.xyz, wave_ibl.xyz, gloss, amblit);
vec3 legacyenv = vec3(0);
irradiance = vec3(0);
// TODO: Make this an option.
#ifdef WATER_MINIMAL
sampleReflectionProbesWater(irradiance, radiance, distort2, pos.xyz, wave_ibl.xyz, gloss, amblit);
#elif WATER_MINIMAL_PLUS
sampleReflectionProbes(irradiance, radiance, distort2, pos.xyz, wave_ibl.xyz, gloss, false, amblit);
#endif
vec3 diffuseColor = vec3(0);
vec3 specularColor = vec3(0);
calcDiffuseSpecular(vec3(1), metallic, diffuseColor, specularColor);
vec3 specular_linear = srgb_to_linear(specular);
calcDiffuseSpecular(specular_linear, metallic, diffuseColor, specularColor);
vec3 v = -normalize(pos.xyz);
@ -257,46 +309,36 @@ void main()
float ao = 1.0;
vec3 light_dir = transform_normal(lightDir);
perceptualRoughness = 0.0;
metallic = 1.0;
float NdotV = clamp(abs(dot(norm, v)), 0.001, 1.0);
float nl = 0;
vec3 diffPunc = vec3(0);
vec3 specPunc = vec3(0);
pbrPunctual(vec3(0), specularColor, 0.1, metallic, normalize(wavef+up*max(dist, 32.0)/32.0*(1.0-vdu)), v, normalize(light_dir), nl, diffPunc, specPunc);
pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, normalize(wavef+up*max(dist, 32.0)/32.0*(1.0-vdu)), v, normalize(light_dir), nl, diffPunc, specPunc);
vec3 punctual = clamp(nl * (diffPunc + specPunc), vec3(0), vec3(10));
vec3 punctual = clamp(nl * (diffPunc + specPunc), vec3(0), vec3(10)) * sunlit_linear * shadow * atten;
radiance *= df2.y;
//radiance = toneMapNoExposure(radiance);
vec3 color = vec3(0);
color = mix(fb.rgb, radiance, min(1, df2.x)) + punctual.rgb;
vec3 color = punctual * sunlit_linear * 2.75 * shadow;
vec3 iblDiff;
vec3 iblSpec;
pbrIbl(vec3(0), vec3(1), radiance, vec3(0), ao, NdotV, 0.0, iblDiff, iblSpec);
float water_haze_scale = 4;
color += iblDiff + iblSpec;
if (classic_mode > 0)
water_haze_scale = 1;
float nv = clamp(abs(dot(norm.xyz, v)), 0.001, 1.0);
vec2 brdf = BRDF(clamp(nv, 0, 1), 1.0);
float f = 1.0-brdf.y; //1.0 - (brdf.x+brdf.y);
f *= 0.9;
f *= f;
// This looks super janky, but we do this to restore water haze in the distance.
// These values were finagled in to try and bring back some of the distant brightening on legacy water. Also works reasonably well on PBR skies such as PBR midday.
// color = mix(color, additive * water_haze_scale, (1 - atten));
// incoming scale is [0, 1] with 0.5 being default
// shift to 0.5 to 1.5
f *= (fresnelScale - 0.5)+1.0;
// We shorten the fade here at the shoreline so it doesn't appear too soft from a distance.
fade *= 60;
fade = min(1, fade);
color = mix(fb.rgb, color, fade);
// incoming offset is [0, 1] with 0.5 being default
// shift from -1 to 1
f += (fresnelOffset - 0.5) * 2.0;
float spec = min(max(max(punctual.r, punctual.g), punctual.b), 0);
f = clamp(f, 0, 1);
color = ((1.0 - f) * color) + fb.rgb;
float spec = min(max(max(punctual.r, punctual.g), punctual.b), 0.05);
frag_color = max(vec4(color, spec), vec4(0));
frag_color = min(vec4(1),max(vec4(color.rgb, spec * water_mask), vec4(0)));
}

View File

@ -85,6 +85,7 @@ RenderExposure 1 4
RenderTonemapType 1 1
RenderTonemapMix 1 1
RenderDisableVintageMode 1 1
RenderMaxTextureResolution 1 2048
//
// Low Graphics Settings
@ -126,6 +127,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 512
//
// Medium Low Graphics Settings
@ -167,6 +169,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 1024
//
// Medium Graphics Settings (standard)
@ -207,6 +210,7 @@ RenderCASSharpness 1 0
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
//
// Medium High Graphics Settings
@ -247,6 +251,7 @@ RenderCASSharpness 1 0
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
//
// High Graphics Settings (SSAO + sun shadows)
@ -287,6 +292,7 @@ RenderCASSharpness 1 0.4
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
//
// High Ultra Graphics Settings (deferred + SSAO + all shadows)
@ -327,6 +333,7 @@ RenderCASSharpness 1 0.4
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
//
// Ultra graphics (REALLY PURTY!)
@ -367,6 +374,7 @@ RenderCASSharpness 1 0.4
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
//
// Class Unknown Hardware (unknown)
@ -399,6 +407,7 @@ RenderShadowDetail 0 0
RenderReflectionProbeDetail 0 -1
RenderMirrors 0 0
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 2048
list Intel
RenderAnisotropic 1 0

View File

@ -85,6 +85,7 @@ RenderTonemapType 1 1
RenderTonemapMix 1 1
RenderDisableVintageMode 1 1
RenderDownScaleMethod 1 0
RenderMaxTextureResolution 1 2048
//
// Low Graphics Settings
@ -126,6 +127,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 512
//
// Medium Low Graphics Settings
@ -167,6 +169,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 1024
//
// Medium Graphics Settings (standard)
@ -207,6 +210,7 @@ RenderCASSharpness 1 0
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
//
// Medium High Graphics Settings
@ -247,6 +251,7 @@ RenderCASSharpness 1 0
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
//
// High Graphics Settings (SSAO + sun shadows)
@ -287,6 +292,7 @@ RenderCASSharpness 1 0
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
//
// High Ultra Graphics Settings (SSAO + all shadows)
@ -327,6 +333,7 @@ RenderCASSharpness 1 0.4
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
//
// Ultra graphics (REALLY PURTY!)
@ -367,6 +374,7 @@ RenderCASSharpness 1 0.4
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
//
// Class Unknown Hardware (unknown)
@ -398,6 +406,7 @@ RenderDeferredSSAO 0 0
RenderShadowDetail 0 0
RenderMirrors 0 0
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 2048
list TexUnit8orLess
RenderDeferredSSAO 0 0

View File

@ -356,8 +356,9 @@ void GLTFSceneManager::addGLTFObject(LLViewerObject* obj, LLUUID gltf_id)
llassert(obj->getVolume()->getParams().getSculptID() == gltf_id);
llassert(obj->getVolume()->getParams().getSculptType() == LL_SCULPT_TYPE_GLTF);
if (obj->mGLTFAsset)
{ // object already has a GLTF asset, don't reload it
if (obj->mGLTFAsset || obj->mIsGLTFAssetMissing )
{
// object already has a GLTF asset or load failed, don't reload it
// TODO: below assertion fails on dupliate requests for assets -- possibly need to touch up asset loading state machine
// llassert(std::find(mObjects.begin(), mObjects.end(), obj) != mObjects.end());
@ -398,16 +399,19 @@ void GLTFSceneManager::onGLTFBinLoadComplete(const LLUUID& id, LLAssetType::ETyp
}
else
{
LL_WARNS("GLTF") << "Failed to prepare GLTF asset: " << id << LL_ENDL;
LL_WARNS("GLTF") << "Failed to prepare GLTF asset: " << id << ". Marking as missing." << LL_ENDL;
obj->mIsGLTFAssetMissing = true;
obj->mGLTFAsset = nullptr;
}
}
}
obj->unref(); // todo: use LLPointer
}
}
else
{
LL_WARNS("GLTF") << "Failed to load GLTF asset: " << id << LL_ENDL;
LL_WARNS("GLTF") << "Failed to load GLTF asset: " << id << ". Marking as missing." << LL_ENDL;
obj->mIsGLTFAssetMissing = true;
obj->unref();
}
});
@ -446,7 +450,8 @@ void GLTFSceneManager::onGLTFLoadComplete(const LLUUID& id, LLAssetType::EType a
}
else
{
LL_WARNS("GLTF") << "Buffer URI is not a valid UUID: " << buffer.mUri << LL_ENDL;
LL_WARNS("GLTF") << "Buffer URI is not a valid UUID: " << buffer.mUri << " for asset id: " << id << ". Marking as missing." << LL_ENDL;
obj->mIsGLTFAssetMissing = true;
obj->unref();
return;
}
@ -455,7 +460,8 @@ void GLTFSceneManager::onGLTFLoadComplete(const LLUUID& id, LLAssetType::EType a
}
else
{
LL_WARNS("GLTF") << "Failed to load GLTF asset: " << id << LL_ENDL;
LL_WARNS("GLTF") << "Failed to load GLTF asset: " << id << ". Marking as missing." << LL_ENDL;
obj->mIsGLTFAssetMissing = true;
obj->unref();
}
}
@ -500,7 +506,7 @@ void GLTFSceneManager::update()
LLNewBufferedResourceUploadInfo::uploadFinish_f finish = [this, buffer](LLUUID assetId, LLSD response)
{
LLAppViewer::instance()->postToMainCoro(
[=]()
[=, this]()
{
if (mUploadingAsset)
{
@ -517,6 +523,7 @@ void GLTFSceneManager::update()
if (mUploadingObject)
{
mUploadingObject->mGLTFAsset = nullptr;
mUploadingObject->mIsGLTFAssetMissing = false;
mUploadingObject->setGLTFAsset(assetId);
mUploadingObject->markForUpdate();
mUploadingObject = nullptr;
@ -975,9 +982,9 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset)
LLVector4a t;
agent_to_asset.affineTransform(gDebugRaycastStart, t);
start = glm::make_vec4(t.getF32ptr());
start = vec4(t);
agent_to_asset.affineTransform(gDebugRaycastEnd, t);
end = glm::make_vec4(t.getF32ptr());
end = vec4(t);
start.w = end.w = 1.0;

View File

@ -56,6 +56,7 @@
#include "llgroupmgr.h"
#include "llhudmanager.h"
#include "lljoystickbutton.h"
#include "lllandmarkactions.h"
#include "llmorphview.h"
#include "llmoveview.h"
#include "llnavigationbar.h" // to show/hide navigation bar when changing mouse look state
@ -4317,8 +4318,17 @@ void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id)
void LLAgent::doTeleportViaLandmark(const LLUUID& landmark_asset_id)
{
LLViewerRegion *regionp = getRegion();
if(regionp && teleportCore())
bool is_local(false);
LLViewerRegion* regionp = getRegion();
if (LLLandmark* landmark = gLandmarkList.getAsset(landmark_asset_id, NULL))
{
LLVector3d pos_global;
landmark->getGlobalPos(pos_global);
is_local = (regionp->getHandle() == to_region_handle_global((F32)pos_global.mdV[VX], (F32)pos_global.mdV[VY]));
}
if(regionp && teleportCore(is_local))
{
LL_INFOS("Teleport") << "Sending TeleportLandmarkRequest. Current region handle " << regionp->getHandle()
<< " region id " << regionp->getRegionID()
@ -4879,10 +4889,19 @@ void LLAgent::parseTeleportMessages(const std::string& xml_filename)
LLXMLNodePtr root;
bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);
if (!success || !root || !root->hasName( "teleport_messages" ))
if (!success)
{
LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS() << "Problem reading teleport string XML file: "
<< xml_filename << LL_ENDL;
<< xml_filename << LL_ENDL;
return;
}
if (!root || !root->hasName("teleport_messages"))
{
LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS() << "Invalid teleport string XML file: "
<< xml_filename << LL_ENDL;
return;
}

View File

@ -28,6 +28,7 @@
#include "llagentpicksinfo.h"
#include "llagent.h"
#include "llagentbenefits.h"
#include "llavatarpropertiesprocessor.h"
const S32 MAX_AVATAR_PICKS = 10;
@ -85,10 +86,9 @@ private:
LLAgentPicksInfo::LLAgentPicksInfo()
: mAgentPicksObserver(NULL)
, mMaxNumberOfPicks(MAX_AVATAR_PICKS)
// Disable Pick creation until we get number of Picks from server - in case
// avatar has maximum number of Picks.
, mNumberOfPicks(mMaxNumberOfPicks)
, mNumberOfPicks(S32_MAX)
{
}
@ -110,7 +110,13 @@ void LLAgentPicksInfo::requestNumberOfPicks()
mAgentPicksObserver->sendAgentPicksRequest();
}
bool LLAgentPicksInfo::isPickLimitReached()
// static
S32 LLAgentPicksInfo::getMaxNumberOfPicks()
{
return LLAgentBenefitsMgr::current().getPicksLimit();
}
bool LLAgentPicksInfo::isPickLimitReached() const
{
return getNumberOfPicks() >= getMaxNumberOfPicks();
}

View File

@ -52,17 +52,17 @@ public:
/**
* Returns number of Picks.
*/
S32 getNumberOfPicks() { return mNumberOfPicks; }
S32 getNumberOfPicks() const { return mNumberOfPicks; }
/**
* Returns maximum number of Picks.
*/
S32 getMaxNumberOfPicks() { return mMaxNumberOfPicks; }
static S32 getMaxNumberOfPicks();
/**
* Returns true if Agent has maximum allowed number of Picks.
*/
bool isPickLimitReached();
bool isPickLimitReached() const;
/**
* After creating or deleting a Pick we can assume operation on server will be
@ -83,15 +83,9 @@ private:
*/
void setNumberOfPicks(S32 number) { mNumberOfPicks = number; }
/**
* Sets maximum number of Picks.
*/
void setMaxNumberOfPicks(S32 max_picks) { mMaxNumberOfPicks = max_picks; }
private:
LLAgentPicksObserver* mAgentPicksObserver;
S32 mMaxNumberOfPicks;
S32 mNumberOfPicks;
};

View File

@ -537,9 +537,14 @@ LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy()
selfStopPhase("update_appearance_on_destroy");
LLAppearanceMgr::instance().updateAppearanceFromCOF(mEnforceItemRestrictions,
mEnforceOrdering,
mPostUpdateFunc);
//avoid calling an update inside coroutine
bool force_restrictions(mEnforceItemRestrictions);
bool enforce_ordering(mEnforceOrdering);
nullary_func_t post_update_func(mPostUpdateFunc);
doOnIdleOneTime([force_restrictions,enforce_ordering,post_update_func]()
{
LLAppearanceMgr::instance().updateAppearanceFromCOF(force_restrictions, enforce_ordering, post_update_func);
});
}
}

View File

@ -298,6 +298,7 @@ bool gUseQuickTime = true;
eLastExecEvent gLastExecEvent = LAST_EXEC_NORMAL;
S32 gLastExecDuration = -1; // (<0 indicates unknown)
LLUUID gLastAgentSessionId;
#if LL_WINDOWS
# define LL_PLATFORM_KEY "win"
@ -372,7 +373,6 @@ const int MAX_MARKER_LENGTH = 1024;
const std::string MARKER_FILE_NAME("SecondLife.exec_marker");
const std::string START_MARKER_FILE_NAME("SecondLife.start_marker");
const std::string ERROR_MARKER_FILE_NAME("SecondLife.error_marker");
const std::string LLERROR_MARKER_FILE_NAME("SecondLife.llerror_marker");
const std::string LOGOUT_MARKER_FILE_NAME("SecondLife.logout_marker");
static bool gDoDisconnect = false;
static std::string gLaunchFileOnQuit;
@ -2219,6 +2219,7 @@ bool LLAppViewer::initThreads()
return true;
}
// Callback for all LL_ERROR calls
void errorCallback(LLError::ELevel level, const std::string &error_string)
{
if (level == LLError::LEVEL_ERROR)
@ -2234,15 +2235,38 @@ void errorCallback(LLError::ELevel level, const std::string &error_string)
// haven't actually trashed anything yet, we can afford to write the whole
// static info file.
LLAppViewer::instance()->writeDebugInfo();
std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME);
if (!LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB))
{
// If marker doesn't exist, create a marker with llerror code for next launch
// otherwise don't override existing file
LLAppViewer::instance()->createErrorMarker(LAST_EXEC_LLERROR_CRASH);
}
}
}
void errorMSG(const std::string& title_string, const std::string& message_string)
// Callback for LLError::LLUserWarningMsg
void errorHandler(const std::string& title_string, const std::string& message_string, S32 code)
{
if (!message_string.empty())
{
OSMessageBox(message_string, title_string.empty() ? LLTrans::getString("MBFatalError") : title_string, OSMB_OK);
}
switch (code)
{
case LLError::LLUserWarningMsg::ERROR_OTHER:
LLAppViewer::instance()->createErrorMarker(LAST_EXEC_OTHER_CRASH);
break;
case LLError::LLUserWarningMsg::ERROR_BAD_ALLOC:
LLAppViewer::instance()->createErrorMarker(LAST_EXEC_BAD_ALLOC);
break;
case LLError::LLUserWarningMsg::ERROR_MISSING_FILES:
LLAppViewer::instance()->createErrorMarker(LAST_EXEC_MISSING_FILES);
break;
default:
break;
}
}
void LLAppViewer::initLoggingAndGetLastDuration()
@ -2256,7 +2280,7 @@ void LLAppViewer::initLoggingAndGetLastDuration()
LLError::addGenericRecorder(&errorCallback);
//LLError::setTimeFunction(getRuntime);
LLError::LLUserWarningMsg::setHandler(errorMSG);
LLError::LLUserWarningMsg::setHandler(errorHandler);
if (mSecondInstance)
@ -2540,6 +2564,7 @@ bool LLAppViewer::initConfiguration()
OSMessageBox(
"Unable to load default settings file. The installation may be corrupted.",
LLStringUtil::null,OSMB_OK);
LLAppViewer::instance()->createErrorMarker(LAST_EXEC_MISSING_FILES);
return false;
}
@ -3702,16 +3727,21 @@ bool LLAppViewer::markerIsSameVersion(const std::string& marker_name) const
bool sameVersion = false;
std::string my_version(LLVersionInfo::instance().getChannelAndVersion());
char marker_version[MAX_MARKER_LENGTH];
char marker_data[MAX_MARKER_LENGTH];
S32 marker_version_length;
LLAPRFile marker_file;
marker_file.open(marker_name, LL_APR_RB);
if (marker_file.getFileHandle())
{
marker_version_length = marker_file.read(marker_version, sizeof(marker_version));
std::string marker_string(marker_version, marker_version_length);
if ( 0 == my_version.compare( 0, my_version.length(), marker_version, 0, marker_version_length ) )
marker_version_length = marker_file.read(marker_data, sizeof(marker_data));
std::string marker_string(marker_data, marker_version_length);
size_t pos = marker_string.find('\n');
if (pos != std::string::npos)
{
marker_string = marker_string.substr(0, pos);
}
if ( 0 == my_version.compare( 0, my_version.length(), marker_string, 0, marker_string.length()) )
{
sameVersion = true;
}
@ -3725,6 +3755,88 @@ bool LLAppViewer::markerIsSameVersion(const std::string& marker_name) const
return sameVersion;
}
void LLAppViewer::recordSessionToMarker()
{
std::string marker_version(LLVersionInfo::instance().getChannelAndVersion());
std::string uuid_str = "\n" + gAgentSessionID.asString();
if (marker_version.length() + uuid_str.length() > MAX_MARKER_LENGTH)
{
LL_WARNS_ONCE("MarkerFile") << "Version length (" << marker_version.length() << ")"
<< " greater than maximum (" << MAX_MARKER_LENGTH << ")"
<< ": marker matching may be incorrect"
<< LL_ENDL;
}
mMarkerFile.seek(APR_SET, (S32)marker_version.length());
mMarkerFile.write(uuid_str.data(), (S32)uuid_str.length());
}
LLUUID LLAppViewer::getMarkerSessionId(const std::string& marker_name) const
{
std::string data;
if (getMarkerData(marker_name, data))
{
return LLUUID(data);
}
return LLUUID();
}
S32 LLAppViewer::getMarkerErrorCode(const std::string& marker_name) const
{
std::string data;
if (getMarkerData(marker_name, data))
{
if (data.empty())
{
return 0;
}
else
{
return std::stoi(data);
}
}
return -1;
}
bool LLAppViewer::getMarkerData(const std::string& marker_name, std::string& data) const
{
bool sameVersion = false;
std::string my_version(LLVersionInfo::instance().getChannelAndVersion());
char marker_data[MAX_MARKER_LENGTH];
S32 marker_version_length;
LLAPRFile marker_file;
marker_file.open(marker_name, LL_APR_RB);
if (marker_file.getFileHandle())
{
marker_version_length = marker_file.read(marker_data, sizeof(marker_data));
marker_file.close();
std::string marker_string(marker_data, marker_version_length);
size_t pos = marker_string.find('\n');
if (pos != std::string::npos)
{
data = marker_string.substr(pos + 1, marker_version_length - pos - 1);
marker_string = marker_string.substr(0, pos);
}
if (0 == my_version.compare(0, my_version.length(), marker_string, 0, marker_string.length()))
{
sameVersion = true;
}
else
{
return false;
}
LL_DEBUGS("MarkerFile") << "Compare markers for '" << marker_name << "': "
<< "\n mine '" << my_version << "'"
<< "\n marker '" << marker_string << "'"
<< "\n " << (sameVersion ? "same" : "different") << " version"
<< LL_ENDL;
return true;
}
return false;
}
void LLAppViewer::processMarkerFiles()
{
//We've got 4 things to test for here
@ -3743,6 +3855,10 @@ void LLAppViewer::processMarkerFiles()
// File exists...
// first, read it to see if it was created by the same version (we need this later)
marker_is_same_version = markerIsSameVersion(mMarkerFileName);
if (marker_is_same_version)
{
gLastAgentSessionId = getMarkerSessionId(mMarkerFileName);
}
// now test to see if this file is locked by a running process (try to open for write)
marker_log_stream << "Checking exec marker file for lock...";
@ -3832,44 +3948,27 @@ void LLAppViewer::processMarkerFiles()
}
LLAPRFile::remove(logout_marker_file);
}
// further refine based on whether or not a marker created during an llerr crash is found
std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME);
if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB))
{
if (markerIsSameVersion(llerror_marker_file))
{
if ( gLastExecEvent == LAST_EXEC_LOGOUT_FROZE )
{
gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL;
}
else
{
gLastExecEvent = LAST_EXEC_LLERROR_CRASH;
LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LLERROR_CRASH" << LL_ENDL;
}
}
else
{
LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' found, but versions did not match" << LL_ENDL;
}
LLAPRFile::remove(llerror_marker_file);
}
// and last refine based on whether or not a marker created during a non-llerr crash is found
std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME);
if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB))
{
if (markerIsSameVersion(error_marker_file))
S32 marker_code = getMarkerErrorCode(error_marker_file);
if (marker_code >= 0)
{
if (gLastExecEvent == LAST_EXEC_LOGOUT_FROZE)
{
gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL;
}
else if (marker_code > 0 && marker_code < (S32)LAST_EXEC_COUNT)
{
gLastExecEvent = (eLastExecEvent)marker_code;
LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
}
else
{
gLastExecEvent = LAST_EXEC_OTHER_CRASH;
LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
LL_INFOS("MarkerFile") << "Error marker '" << error_marker_file << "' crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
}
}
else
@ -5159,6 +5258,24 @@ void LLAppViewer::postToMainCoro(const LL::WorkQueue::Work& work)
gMainloopWork.post(work);
}
void LLAppViewer::createErrorMarker(eLastExecEvent error_code) const
{
if (!mSecondInstance)
{
std::string error_marker = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME);
LLAPRFile file;
file.open(error_marker, LL_APR_WB);
if (file.getFileHandle())
{
recordMarkerVersion(file);
std::string data = "\n" + std::to_string((S32)error_code);
file.write(data.data(), static_cast<S32>(data.length()));
file.close();
}
}
}
void LLAppViewer::outOfMemorySoftQuit()
{
if (!mQuitRequested)

View File

@ -66,6 +66,20 @@ class LLViewerRegion;
extern LLTrace::BlockTimerStatHandle FTM_FRAME;
typedef enum
{
LAST_EXEC_NORMAL = 0,
LAST_EXEC_FROZE,
LAST_EXEC_LLERROR_CRASH,
LAST_EXEC_OTHER_CRASH,
LAST_EXEC_LOGOUT_FROZE,
LAST_EXEC_LOGOUT_CRASH,
LAST_EXEC_BAD_ALLOC,
LAST_EXEC_MISSING_FILES,
LAST_EXEC_GRAPHICS_INIT,
LAST_EXEC_COUNT
} eLastExecEvent;
class LLAppViewer : public LLApp
{
public:
@ -147,6 +161,7 @@ public:
void saveExperienceCache();
void removeMarkerFiles();
void recordSessionToMarker();
void removeDumpDir();
// LLAppViewer testing helpers.
@ -227,6 +242,9 @@ public:
// post given work to the "mainloop" work queue for handling on the main thread
void postToMainCoro(const LL::WorkQueue::Work& work);
// Writes an error code into the error_marker file for use on next startup.
void createErrorMarker(eLastExecEvent error_code) const;
// Attempt a 'soft' quit with disconnect and saving of settings/cache.
// Intended to be thread safe.
// Good chance of viewer crashing either way, but better than alternatives.
@ -272,6 +290,9 @@ private:
void processMarkerFiles();
static void recordMarkerVersion(LLAPRFile& marker_file);
bool markerIsSameVersion(const std::string& marker_name) const;
LLUUID getMarkerSessionId(const std::string& marker_name) const;
S32 getMarkerErrorCode(const std::string& marker_name) const;
bool getMarkerData(const std::string& marker_name, std::string &data) const;
void idle();
void idleShutdown();
@ -347,18 +368,9 @@ private:
extern LLSD gDebugInfo;
extern bool gShowObjectUpdates;
typedef enum
{
LAST_EXEC_NORMAL = 0,
LAST_EXEC_FROZE,
LAST_EXEC_LLERROR_CRASH,
LAST_EXEC_OTHER_CRASH,
LAST_EXEC_LOGOUT_FROZE,
LAST_EXEC_LOGOUT_CRASH
} eLastExecEvent;
extern eLastExecEvent gLastExecEvent; // llstartup
extern S32 gLastExecDuration; ///< the duration of the previous run in seconds (<0 indicates unknown)
extern LLUUID gLastAgentSessionId; // will be set if agent logged in
extern const char* gPlatform;

View File

@ -357,8 +357,9 @@ void LLConversationItemSession::clearParticipants()
void LLConversationItemSession::clearAndDeparentModels()
{
for (LLFolderViewModelItem* child : mChildren)
for (child_list_t::iterator it = mChildren.begin(); it != mChildren.end();)
{
LLFolderViewModelItem* child = *it;
if (child->getNumRefs() == 0)
{
// LLConversationItemParticipant can be created but not assigned to any view,
@ -370,8 +371,8 @@ void LLConversationItemSession::clearAndDeparentModels()
// Model is still assigned to some view/widget
child->setParent(NULL);
}
it = mChildren.erase(it);
}
mChildren.clear();
}
LLConversationItemParticipant* LLConversationItemSession::findParticipant(const LLUUID& participant_id)

View File

@ -42,6 +42,7 @@
#include "lldrawpooltree.h"
#include "lldrawpoolterrain.h"
#include "lldrawpoolwater.h"
#include "lldrawpoolwaterexclusion.h"
#include "llface.h"
#include "llviewerobjectlist.h" // For debug listing.
#include "pipeline.h"
@ -119,6 +120,9 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerTexture *tex0)
case POOL_GLTF_PBR_ALPHA_MASK:
poolp = new LLDrawPoolGLTFPBR(LLDrawPool::POOL_GLTF_PBR_ALPHA_MASK);
break;
case POOL_WATEREXCLUSION:
poolp = new LLDrawPoolWaterExclusion();
break;
default:
LL_ERRS() << "Unknown draw pool type!" << LL_ENDL;
return NULL;

View File

@ -55,6 +55,7 @@ public:
// based on fill rate and likelihood to occlude future passes (faster, large occluders first).
//
POOL_SKY = 1,
POOL_WATEREXCLUSION,
POOL_WL_SKY,
POOL_SIMPLE,
POOL_FULLBRIGHT,
@ -140,7 +141,7 @@ public:
PASS_GRASS,
PASS_FULLBRIGHT,
PASS_FULLBRIGHT_RIGGED,
PASS_INVISIBLE,
PASS_INVISIBLE, // Formerly, invisiprims. Now, water exclusion surfaces.
PASS_INVISIBLE_RIGGED,
PASS_INVISI_SHINY,
PASS_INVISI_SHINY_RIGGED,

View File

@ -176,175 +176,158 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass)
light_diffuse *= (1.5f + (6.f * ground_proj_sq));
}
// set up normal maps filtering
for (auto norm_map : mWaterNormp)
{
if (norm_map) norm_map->setFilteringOption(has_normal_mips ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT);
}
LLTexUnit::eTextureFilterOptions filter_mode = has_normal_mips ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT;
LLColor4 specular(sun_up ? psky->getSunlightColor() : psky->getMoonlightColor());
F32 phase_time = (F32) LLFrameTimer::getElapsedSeconds() * 0.5f;
LLGLSLShader *shader = nullptr;
// two passes, first with standard water shader bound, second with edge water shader bound
for (int edge = 0; edge < 2; edge++)
// One pass, one of two shaders. Void water and region water share state.
// There isn't a good reason anymore to really have void water run in a separate pass.
// It also just introduced a bunch of weird state consistency stuff that we really don't need.
// Not to mention, re-binding the the same shader and state for that shader is kind of wasteful.
// - Geenz 2025-02-11
// select shader
if (underwater)
{
// select shader
if (underwater)
{
shader = &gUnderWaterProgram;
}
else
{
if (edge)
{
shader = &gWaterEdgeProgram;
}
else
{
shader = &gWaterProgram;
}
}
gPipeline.bindDeferredShader(*shader, nullptr, &gPipeline.mWaterDis);
//bind normal map
S32 bumpTex = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP);
S32 bumpTex2 = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP2);
LLViewerTexture* tex_a = mWaterNormp[0];
LLViewerTexture* tex_b = mWaterNormp[1];
F32 blend_factor = (F32)pwater->getBlendFactor();
gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
if (tex_a && (!tex_b || (tex_a == tex_b)))
{
gGL.getTexUnit(bumpTex)->bind(tex_a);
blend_factor = 0; // only one tex provided, no blending
}
else if (tex_b && !tex_a)
{
gGL.getTexUnit(bumpTex)->bind(tex_b);
blend_factor = 0; // only one tex provided, no blending
}
else if (tex_b != tex_a)
{
gGL.getTexUnit(bumpTex)->bind(tex_a);
gGL.getTexUnit(bumpTex2)->bind(tex_b);
}
// bind reflection texture from RenderTarget
S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX);
F32 screenRes[] = { 1.f / gGLViewport[2], 1.f / gGLViewport[3] };
shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes);
shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor);
F32 fog_density = pwater->getModifiedWaterFogDensity(underwater);
if (screentex > -1)
{
shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, fog_density);
gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis);
}
if (mShaderLevel == 1)
{
fog_color.mV[VALPHA] = (F32)(log(fog_density) / log(2));
}
F32 water_height = environment.getWaterHeight();
F32 camera_height = LLViewerCamera::getInstance()->getOrigin().mV[2];
shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, camera_height - water_height);
shader->uniform1f(LLShaderMgr::WATER_TIME, phase_time);
shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV);
shader->uniform4fv(LLShaderMgr::SPECULAR_COLOR, 1, specular.mV);
shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV);
shader->uniform3fv(LLShaderMgr::WATER_FOGCOLOR_LINEAR, 1, fog_color_linear.mV);
shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV);
shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp);
shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV);
shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV);
shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV);
shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV);
shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale());
shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset());
shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, pwater->getBlurMultiplier());
F32 sunAngle = llmax(0.f, light_dir.mV[1]);
F32 scaledAngle = 1.f - sunAngle;
shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up ? 1 : 0);
shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE, sunAngle);
shader->uniform1f(LLShaderMgr::WATER_SCALED_ANGLE, scaledAngle);
shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE2, 0.1f + 0.2f * sunAngle);
shader->uniform1i(LLShaderMgr::WATER_EDGE_FACTOR, edge ? 1 : 0);
// SL-15861 This was changed from getRotatedLightNorm() as it was causing
// lightnorm in shaders\class1\windlight\atmosphericsFuncs.glsl in have inconsistent additive lighting for 180 degrees of the FOV.
LLVector4 rotated_light_direction = LLEnvironment::instance().getClampedLightNorm();
shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV);
shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV);
if (LLViewerCamera::getInstance()->cameraUnderWater())
{
shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow());
}
else
{
shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove());
}
LLGLDisable cullface(GL_CULL_FACE);
LLVOWater* water = nullptr;
for (LLFace* const& face : mDrawFace)
{
if (!face) continue;
water = static_cast<LLVOWater*>(face->getViewerObject());
if (!water) continue;
if ((bool)edge == (bool)water->getIsEdgePatch())
{
face->renderIndexed();
// Note non-void water being drawn, updates required
if (!edge) // SL-16461 remove !LLPipeline::sUseOcclusion check
{
sNeedsReflectionUpdate = true;
sNeedsDistortionUpdate = true;
}
}
}
shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
shader->disableTexture(LLShaderMgr::WATER_SCREENTEX);
shader->disableTexture(LLShaderMgr::BUMP_MAP);
shader->disableTexture(LLShaderMgr::WATER_REFTEX);
// clean up
gPipeline.unbindDeferredShader(*shader);
gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
shader = &gUnderWaterProgram;
}
else
{
shader = &gWaterProgram;
}
gGL.getTexUnit(0)->activate();
gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
gPipeline.bindDeferredShader(*shader, nullptr, &gPipeline.mWaterDis);
LLViewerTexture* tex_a = mWaterNormp[0];
LLViewerTexture* tex_b = mWaterNormp[1];
F32 blend_factor = (F32)pwater->getBlendFactor();
if (tex_a && (!tex_b || (tex_a == tex_b)))
{
shader->bindTexture(LLViewerShaderMgr::BUMP_MAP, tex_a);
tex_a->setFilteringOption(filter_mode);
blend_factor = 0; // only one tex provided, no blending
}
else if (tex_b && !tex_a)
{
shader->bindTexture(LLViewerShaderMgr::BUMP_MAP, tex_b);
tex_b->setFilteringOption(filter_mode);
blend_factor = 0; // only one tex provided, no blending
}
else if (tex_b != tex_a)
{
shader->bindTexture(LLViewerShaderMgr::BUMP_MAP, tex_a);
tex_a->setFilteringOption(filter_mode);
shader->bindTexture(LLViewerShaderMgr::BUMP_MAP2, tex_b);
tex_b->setFilteringOption(filter_mode);
}
shader->bindTexture(LLShaderMgr::WATER_EXCLUSIONTEX, &gPipeline.mWaterExclusionMask);
shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor);
F32 fog_density = pwater->getModifiedWaterFogDensity(underwater);
shader->bindTexture(LLShaderMgr::WATER_SCREENTEX, &gPipeline.mWaterDis);
if (mShaderLevel == 1)
{
fog_color.mV[VALPHA] = (F32)(log(fog_density) / log(2));
}
F32 water_height = environment.getWaterHeight();
F32 camera_height = LLViewerCamera::getInstance()->getOrigin().mV[2];
shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, camera_height - water_height);
shader->uniform1f(LLShaderMgr::WATER_TIME, phase_time);
shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV);
shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV);
shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV);
shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV);
shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV);
shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV);
shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale());
shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset());
shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, fmaxf(0, pwater->getBlurMultiplier()) * 2);
static LLStaticHashedString s_exposure("exposure");
static LLStaticHashedString tonemap_mix("tonemap_mix");
static LLStaticHashedString tonemap_type("tonemap_type");
static LLCachedControl<F32> exposure(gSavedSettings, "RenderExposure", 1.f);
F32 e = llclamp(exposure(), 0.5f, 4.f);
static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", false);
shader->uniform1f(s_exposure, e);
static LLCachedControl<U32> tonemap_type_setting(gSavedSettings, "RenderTonemapType", 0U);
shader->uniform1i(tonemap_type, tonemap_type_setting);
shader->uniform1f(tonemap_mix, psky->getTonemapMix(should_auto_adjust()));
F32 sunAngle = llmax(0.f, light_dir.mV[1]);
F32 scaledAngle = 1.f - sunAngle;
shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up ? 1 : 0);
// SL-15861 This was changed from getRotatedLightNorm() as it was causing
// lightnorm in shaders\class1\windlight\atmosphericsFuncs.glsl in have inconsistent additive lighting for 180 degrees of the FOV.
LLVector4 rotated_light_direction = LLEnvironment::instance().getClampedLightNorm();
shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV);
shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV);
if (LLViewerCamera::getInstance()->cameraUnderWater())
{
shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow());
}
else
{
shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove());
}
LLGLDisable cullface(GL_CULL_FACE);
// Only push the water planes once.
// Previously we did this twice: once for void water and one for region water.
// However, the void water and region water shaders are the same exact shader.
// They also had the same exact state with the sole exception setting an edge water flag.
// That flag was not actually used anywhere in the shaders.
// - Geenz 2025-02-11
pushWaterPlanes(0);
// clean up
gPipeline.unbindDeferredShader(*shader);
gGL.setColorMask(true, false);
}
void LLDrawPoolWater::pushWaterPlanes(int pass)
{
LLVOWater* water = nullptr;
for (LLFace* const& face : mDrawFace)
{
water = static_cast<LLVOWater*>(face->getViewerObject());
face->renderIndexed();
// Note non-void water being drawn, updates required
// Previously we had some logic to determine if this pass was also our water edge pass.
// Now we only have one pass. Check if we're doing a region water plane or void water plane.
// - Geenz 2025-02-11
if (!water->getIsEdgePatch())
{
sNeedsReflectionUpdate = true;
sNeedsDistortionUpdate = true;
}
}
}
LLViewerTexture *LLDrawPoolWater::getDebugTexture()
{
return LLViewerTextureManager::getFetchedTexture(IMG_SMOKE);

View File

@ -74,6 +74,8 @@ public:
void setOpaqueTexture(const LLUUID& opaqueTextureId);
void setNormalMaps(const LLUUID& normalMapId, const LLUUID& nextNormalMapId);
void pushWaterPlanes(int pass);
protected:
void renderOpaqueLegacyWater();
};

View File

@ -0,0 +1,79 @@
/**
* @file lldrawpool.cpp
* @brief LLDrawPoolMaterials class implementation
* @author Jonathan "Geenz" Goodman
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2013, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "lldrawpoolwaterexclusion.h"
#include "llviewershadermgr.h"
#include "pipeline.h"
#include "llglcommonfunc.h"
#include "llvoavatar.h"
#include "lldrawpoolwater.h"
LLDrawPoolWaterExclusion::LLDrawPoolWaterExclusion() : LLRenderPass(LLDrawPool::POOL_WATEREXCLUSION)
{
LL_INFOS("DPInvisible") << "Creating water exclusion draw pool" << LL_ENDL;
}
void LLDrawPoolWaterExclusion::render(S32 pass)
{ // render invisiprims
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; // LL_RECORD_BLOCK_TIME(FTM_RENDER_INVISIBLE);
if (gPipeline.shadersLoaded())
{
gDrawColorProgram.bind();
}
LLGLDepthTest depth(GL_TRUE);
gDrawColorProgram.uniform4f(LLShaderMgr::DIFFUSE_COLOR, 1, 1, 1, 1);
LLDrawPoolWater* pwaterpool = (LLDrawPoolWater*)gPipeline.getPool(LLDrawPool::POOL_WATER);
if (pwaterpool)
{
// Just treat our water planes as double sided for the purposes of generating the exclusion mask.
LLGLDisable cullface(GL_CULL_FACE);
pwaterpool->pushWaterPlanes(0);
// Take care of the edge water tiles.
pwaterpool->pushWaterPlanes(1);
}
gDrawColorProgram.uniform4f(LLShaderMgr::DIFFUSE_COLOR, 0, 0, 0, 1);
static LLStaticHashedString waterSign("waterSign");
gDrawColorProgram.uniform1f(waterSign, 1.f);
pushBatches(LLRenderPass::PASS_INVISIBLE, false, false);
if (gPipeline.shadersLoaded())
{
gDrawColorProgram.unbind();
}
}

View File

@ -0,0 +1,61 @@
/**
* @file lldrawpoolwaterexclusion.h
* @brief LLDrawPoolWaterExclusion class definition
* @author Jonathan "Geenz" Goodman
*
* $LicenseInfo:firstyear=2025&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2013, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLDRAWPOOLWATEREXCLUSION_H
#define LL_LLDRAWPOOLWATEREXCLUSION_H
#include "v4coloru.h"
#include "v2math.h"
#include "v3math.h"
#include "llvertexbuffer.h"
#include "lldrawpool.h"
class LLViewerTexture;
class LLDrawInfo;
class LLGLSLShader;
class LLDrawPoolWaterExclusion : public LLRenderPass
{
public:
LLDrawPoolWaterExclusion();
enum
{
VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX
};
virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
virtual void prerender() {}
virtual void render(S32 pass = 0);
virtual void beginRenderPass(S32 pass) {}
virtual void endRenderPass(S32 pass) {}
virtual S32 getNumPasses() { return 1; }
};
#endif // LL_LLDRAWPOOLWATEREXCLUSION_H

View File

@ -893,7 +893,7 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, const LLVector4a& po
//VECTORIZE THIS
// see if we have a non-default mapping
U8 texgen = getTextureEntry()->getTexGen();
U8 texgen = tep->getTexGen();
if (texgen != LLTextureEntry::TEX_GEN_DEFAULT)
{
LLVector4a& center = *(mDrawablep->getVOVolume()->getVolume()->getVolumeFace(mTEOffset).mCenter);
@ -983,8 +983,17 @@ bool LLFace::calcAlignedPlanarTE(const LLFace* align_to, LLVector2* res_st_offs
return false;
}
const LLTextureEntry *orig_tep = align_to->getTextureEntry();
if (!orig_tep)
{
return false;
}
const LLTextureEntry* tep = getTextureEntry();
if (!tep)
{
return false;
}
if ((orig_tep->getTexGen() != LLTextureEntry::TEX_GEN_PLANAR) ||
(getTextureEntry()->getTexGen() != LLTextureEntry::TEX_GEN_PLANAR))
(tep->getTexGen() != LLTextureEntry::TEX_GEN_PLANAR))
{
return false;
}
@ -1563,7 +1572,8 @@ bool LLFace::getGeometryVolume(const LLVolume& volume,
bump_t_primary_light_ray.load3((offset_multiple * t_scale * primary_light_ray).mV);
}
U8 texgen = getTextureEntry()->getTexGen();
const LLTextureEntry* tep = getTextureEntry();
U8 texgen = tep ? tep->getTexGen() : LLTextureEntry::TEX_GEN_DEFAULT;
if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT)
{ //planar texgen needs binormals
mVObjp->getVolume()->genTangents(face_index);
@ -2051,7 +2061,12 @@ bool LLFace::getGeometryVolume(const LLVolume& volume,
LLStrider<LLColor4U> emissive;
mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount);
U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255);
const LLTextureEntry* tep = getTextureEntry();
U8 glow = 0;
if (tep)
{
glow = (U8)llclamp((S32)(tep->getGlow() * 255), 0, 255);
}
LLVector4a src;

View File

@ -633,7 +633,8 @@ void LLFloaterIMSessionTab::appendMessage(const LLChat& chat, const LLSD& args)
chat_args["show_names_for_p2p_conv"] = !mIsP2PChat ||
gSavedSettings.getBOOL("IMShowNamesForP2PConv");
mChatHistory->appendMessage(chat, chat_args);
static const LLStyle::Params input_append_params = LLStyle::Params();
mChatHistory->appendMessage(chat, chat_args, input_append_params);
}
void LLFloaterIMSessionTab::updateUsedEmojis(LLWStringView text)

View File

@ -60,6 +60,10 @@ LLPanelSnapshot* LLFloaterSnapshot::Impl::getActivePanel(LLFloaterSnapshotBase*
{
LLSideTrayPanelContainer* panel_container = floater->getChild<LLSideTrayPanelContainer>("panel_container");
LLPanelSnapshot* active_panel = dynamic_cast<LLPanelSnapshot*>(panel_container->getCurrentPanel());
if (!active_panel)
{
LL_WARNS() << "No snapshot active panel, current panel index: " << panel_container->getCurrentPanelIndex() << LL_ENDL;
}
if (!ok_if_not_found)
{
llassert_always(active_panel != NULL);
@ -643,20 +647,18 @@ void LLFloaterSnapshotBase::ImplBase::setWorking(bool working)
working_lbl->setVisible(working);
mFloater->getChild<LLUICtrl>("working_indicator")->setVisible(working);
if (working)
{
const std::string panel_name = getActivePanel(mFloater, false)->getName();
const std::string prefix = panel_name.substr(getSnapshotPanelPrefix().size());
std::string progress_text = mFloater->getString(prefix + "_" + "progress_str");
working_lbl->setValue(progress_text);
}
// All controls should be disabled while posting.
mFloater->setCtrlsEnabled(!working);
LLPanelSnapshot* active_panel = getActivePanel(mFloater);
if (active_panel)
if (LLPanelSnapshot* active_panel = getActivePanel(mFloater))
{
active_panel->enableControls(!working);
if (working)
{
const std::string panel_name = active_panel->getName();
const std::string prefix = panel_name.substr(getSnapshotPanelPrefix().size());
std::string progress_text = mFloater->getString(prefix + "_" + "progress_str");
working_lbl->setValue(progress_text);
}
}
}

View File

@ -472,9 +472,9 @@ bool LLGLTFPreviewTexture::render()
gPipeline.setupHWLights();
glm::mat4 mat = get_current_modelview();
glm::vec4 transformed_light_dir = glm::make_vec4(light_dir.mV);
glm::vec4 transformed_light_dir(light_dir);
transformed_light_dir = mat * transformed_light_dir;
SetTemporarily<LLVector4> force_sun_direction_high_graphics(&gPipeline.mTransformedSunDir, LLVector4(glm::value_ptr(transformed_light_dir)));
SetTemporarily<LLVector4> force_sun_direction_high_graphics(&gPipeline.mTransformedSunDir, LLVector4(transformed_light_dir));
// Override lights to ensure the sun is always shining from a certain direction (low graphics)
// See also force_sun_direction_high_graphics and fixup_shader_constants
{

View File

@ -80,6 +80,17 @@ void LLHeroProbeManager::update()
return;
}
// Part of a hacky workaround to fix #3331.
// For some reason clearing shaders will cause mirrors to actually work.
// There's likely some deeper state issue that needs to be resolved.
// - Geenz 2025-02-25
if (!mInitialized && LLStartUp::getStartupState() > STATE_PRECACHE)
{
LLViewerShaderMgr::instance()->clearShaderCache();
LLViewerShaderMgr::instance()->setShaders();
mInitialized = true;
}
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
llassert(!gCubeSnapshot); // assert a snapshot is not in progress
if (LLAppViewer::instance()->logoutRequestSent())
@ -89,9 +100,11 @@ void LLHeroProbeManager::update()
initReflectionMaps();
static LLCachedControl<bool> render_hdr(gSavedSettings, "RenderHDREnabled", true);
if (!mRenderTarget.isComplete())
{
U32 color_fmt = GL_RGBA16F;
U32 color_fmt = render_hdr ? GL_RGBA16F : GL_RGBA8;
mRenderTarget.allocate(mProbeResolution, mProbeResolution, color_fmt, true);
}
@ -103,7 +116,7 @@ void LLHeroProbeManager::update()
mMipChain.resize(count);
for (U32 i = 0; i < count; ++i)
{
mMipChain[i].allocate(res, res, GL_RGBA16F);
mMipChain[i].allocate(res, res, render_hdr ? GL_RGBA16F : GL_RGBA8);
res /= 2;
}
}
@ -220,7 +233,7 @@ void LLHeroProbeManager::renderProbes()
static LLCachedControl<S32> sUpdateRate(gSavedSettings, "RenderHeroProbeUpdateRate", 0);
F32 near_clip = 0.01f;
if (mNearestHero != nullptr &&
if (mNearestHero != nullptr && !mNearestHero->isDead() &&
!gTeleportDisplay && !gDisconnected && !LLAppViewer::instance()->logoutRequestSent())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("hpmu - realtime");
@ -249,12 +262,13 @@ void LLHeroProbeManager::renderProbes()
LL_PROFILE_ZONE_NUM(gFrameCount % rate);
LL_PROFILE_ZONE_NUM(rate);
bool dynamic = mNearestHero->getReflectionProbeIsDynamic() && sDetail() > 0;
for (U32 i = 0; i < 6; ++i)
{
if ((gFrameCount % rate) == (i % rate))
{ // update 6/rate faces per frame
LL_PROFILE_ZONE_NUM(i);
updateProbeFace(mProbes[0], i, mNearestHero->getReflectionProbeIsDynamic() && sDetail > 0, near_clip);
updateProbeFace(mProbes[0], i, dynamic, near_clip);
}
}
generateRadiance(mProbes[0]);
@ -537,8 +551,10 @@ void LLHeroProbeManager::initReflectionMaps()
mTexture = new LLCubeMapArray();
static LLCachedControl<bool> render_hdr(gSavedSettings, "RenderHDREnabled", true);
// store mReflectionProbeCount+2 cube maps, final two cube maps are used for render target and radiance map generation source)
mTexture->allocate(mProbeResolution, 3, mReflectionProbeCount + 2);
mTexture->allocate(mProbeResolution, 3, mReflectionProbeCount + 2, true, render_hdr);
if (mDefaultProbe.isNull())
{

View File

@ -144,6 +144,7 @@ private:
std::vector<LLPointer<LLVOVolume>> mHeroVOList;
LLPointer<LLVOVolume> mNearestHero;
// Part of a hacky workaround to fix #3331.
bool mInitialized = false;
};

View File

@ -106,7 +106,7 @@ void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent,
LLRect world_view_rect = gViewerWindow->getWorldViewRectRaw();
glm::ivec4 viewport(world_view_rect.mLeft, world_view_rect.mBottom, world_view_rect.getWidth(), world_view_rect.getHeight());
glm::vec3 win_coord = glm::project(glm::make_vec3(render_pos.mV), get_current_modelview(), get_current_projection(), viewport);
glm::vec3 win_coord = glm::project(glm::vec3(render_pos), get_current_modelview(), get_current_projection(), viewport);
//fonts all render orthographically, set up projection``
gGL.matrixMode(LLRender::MM_PROJECTION);

View File

@ -4231,14 +4231,9 @@ void LLFolderBridge::staticFolderOptionsMenu()
bool LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type)
{
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t item_array;
model->collectDescendentsIf(mUUID,
cat_array,
item_array,
return model->hasMatchingDescendents(mUUID,
LLInventoryModel::EXCLUDE_TRASH,
is_type);
return !item_array.empty();
}
void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items)
@ -4415,21 +4410,26 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
//Added by aura to force inventory pull on right-click to display folder options correctly. 07-17-06
mCallingCards = mWearables = false;
LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD);
if (checkFolderForContentsOfType(model, is_callingcard))
if (gInventory.getRootFolderID() != mUUID)
{
mCallingCards=true;
LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD);
if (checkFolderForContentsOfType(model, is_callingcard))
{
mCallingCards = true;
}
const std::vector<LLAssetType::EType> types = { LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART, LLAssetType::AT_OBJECT, LLAssetType::AT_GESTURE };
LLIsOneOfTypes is_wearable(types);
if (checkFolderForContentsOfType(model, is_wearable))
{
mWearables = true;
}
}
LLFindWearables is_wearable;
LLIsType is_object( LLAssetType::AT_OBJECT );
LLIsType is_gesture( LLAssetType::AT_GESTURE );
if (checkFolderForContentsOfType(model, is_wearable) ||
checkFolderForContentsOfType(model, is_object) ||
checkFolderForContentsOfType(model, is_gesture) )
else
{
mWearables=true;
// Assume that there are wearables in the root folder
mWearables = true;
}
}
else
@ -4442,13 +4442,10 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
LLFolderType::EType type = category->getPreferredType();
const bool is_system_folder = LLFolderType::lookupIsProtectedType(type);
LLFindWearables is_wearable;
LLIsType is_object(LLAssetType::AT_OBJECT);
LLIsType is_gesture(LLAssetType::AT_GESTURE);
const std::vector<LLAssetType::EType> types = { LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART, LLAssetType::AT_OBJECT, LLAssetType::AT_GESTURE };
LLIsOneOfTypes is_wearable(types);
if (checkFolderForContentsOfType(model, is_wearable) ||
checkFolderForContentsOfType(model, is_object) ||
checkFolderForContentsOfType(model, is_gesture))
if (checkFolderForContentsOfType(model, is_wearable))
{
mWearables = true;
}
@ -4571,14 +4568,11 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t&
// wearables related functionality for folders.
//is_wearable
LLFindWearables is_wearable;
LLIsType is_object( LLAssetType::AT_OBJECT );
LLIsType is_gesture( LLAssetType::AT_GESTURE );
const std::vector<LLAssetType::EType> types = { LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART, LLAssetType::AT_OBJECT, LLAssetType::AT_GESTURE };
LLIsOneOfTypes is_wearable(types);
if (mWearables ||
checkFolderForContentsOfType(model, is_wearable) ||
checkFolderForContentsOfType(model, is_object) ||
checkFolderForContentsOfType(model, is_gesture) )
checkFolderForContentsOfType(model, is_wearable))
{
// Only enable add/replace outfit for non-system folders.
if (!is_system_folder)

View File

@ -2634,6 +2634,22 @@ bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
return false;
}
bool LLIsOneOfTypes::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
for (LLAssetType::EType &type : mTypes)
{
if (type == LLAssetType::AT_CATEGORY)
{
if (cat) return true;
}
if (item)
{
if (item->getType() == type) return true;
}
}
return false;
}
bool LLIsNotType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
if(mType == LLAssetType::AT_CATEGORY)

View File

@ -245,6 +245,24 @@ protected:
LLAssetType::EType mType;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLIsOneOfTypes
//
// Implementation of a LLInventoryCollectFunctor which returns true if
// the type is one of the types passed in during construction.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLIsOneOfTypes : public LLInventoryCollectFunctor
{
public:
LLIsOneOfTypes(const std::vector<LLAssetType::EType> &types) : mTypes(types) {}
virtual ~LLIsOneOfTypes() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
protected:
std::vector <LLAssetType::EType> mTypes;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLIsNotType
//

View File

@ -1305,6 +1305,47 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
}
}
bool LLInventoryModel::hasMatchingDescendents(const LLUUID& id,
bool include_trash,
LLInventoryCollectFunctor& matches)
{
if (!include_trash)
{
const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH);
if (trash_id.notNull() && (trash_id == id))
return false;
}
cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id);
if (cat_array)
{
for (auto& cat : *cat_array)
{
if (matches(cat, NULL))
{
return true;
}
if (hasMatchingDescendents(cat->getUUID(), include_trash, matches))
{
return true;
}
}
}
item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id);
if (item_array)
{
for (auto& item : *item_array)
{
if (matches(NULL, item))
{
return true;
}
}
}
return false;
}
void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask)
{
const LLInventoryObject *obj = getObject(object_id);

View File

@ -287,6 +287,9 @@ public:
item_array_t& items,
bool include_trash,
LLInventoryCollectFunctor& add);
bool hasMatchingDescendents(const LLUUID& id,
bool include_trash,
LLInventoryCollectFunctor& add);
// Collect all items in inventory that are linked to item_id.
// Assumes item_id is itself not a linked item.

View File

@ -579,7 +579,7 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve
{
if (model_item && view_item && viewmodel_item)
{
const LLUUID& idp = viewmodel_item->getUUID();
const LLUUID idp = viewmodel_item->getUUID();
view_item->destroyView();
removeItemID(idp);
}
@ -1334,6 +1334,8 @@ void LLInventoryPanel::openStartFolderOrMyInventory()
LLFolderViewFolder *fchild = dynamic_cast<LLFolderViewFolder*>(child);
if (fchild
&& fchild->getViewModelItem()
// Is this right? Name might be localized,
// use FT_ROOT_INVENTORY or gInventory.getRootFolderID()?
&& fchild->getViewModelItem()->getName() == "My Inventory")
{
fchild->setOpen(true);

View File

@ -212,6 +212,7 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
request_params["read_critical"] = false; // handleTOSResponse
request_params["last_exec_event"] = mLastExecEvent;
request_params["last_exec_duration"] = mLastExecDuration;
request_params["last_exec_session_id"] = mLastAgentSessionId.asString();
request_params["mac"] = (char*)hashed_unique_id_string;
request_params["version"] = LLVersionInfo::instance().getVersion();
request_params["channel"] = LLVersionInfo::instance().getChannel();

View File

@ -64,6 +64,7 @@ public:
void setSerialNumber(const std::string& sn) { mSerialNumber = sn; }
void setLastExecEvent(int lee) { mLastExecEvent = lee; }
void setLastExecDuration(S32 duration) { mLastExecDuration = duration; }
void setLastAgentSessionId(const LLUUID& id) { mLastAgentSessionId = id; }
void setPlatformInfo(const std::string platform, const std::string platform_version, const std::string platform_name);
void setNotificationsInterface(LLNotificationsInterface* ni) { mNotifications = ni; }
@ -101,6 +102,7 @@ private:
std::string mSerialNumber;
int mLastExecEvent;
S32 mLastExecDuration;
LLUUID mLastAgentSessionId;
std::string mPlatform;
std::string mPlatformVersion;
std::string mPlatformVersionName;

View File

@ -548,8 +548,8 @@ LLViewerFetchedTexture* LLMeshUploadThread::FindViewerTexture(const LLImportMate
return ppTex ? (*ppTex).get() : NULL;
}
volatile S32 LLMeshRepoThread::sActiveHeaderRequests = 0;
volatile S32 LLMeshRepoThread::sActiveLODRequests = 0;
std::atomic<S32> LLMeshRepoThread::sActiveHeaderRequests = 0;
std::atomic<S32> LLMeshRepoThread::sActiveLODRequests = 0;
U32 LLMeshRepoThread::sMaxConcurrentRequests = 1;
S32 LLMeshRepoThread::sRequestLowWater = REQUEST2_LOW_WATER_MIN;
S32 LLMeshRepoThread::sRequestHighWater = REQUEST2_HIGH_WATER_MIN;
@ -3916,7 +3916,7 @@ void LLMeshRepository::notifyLoadedMeshes()
}
// erase from background thread
mThread->mWorkQueue.post([=]()
mThread->mWorkQueue.post([=, this]()
{
mThread->mSkinMap.erase(id);
});

View File

@ -256,8 +256,8 @@ class LLMeshRepoThread : public LLThread
{
public:
volatile static S32 sActiveHeaderRequests;
volatile static S32 sActiveLODRequests;
static std::atomic<S32> sActiveHeaderRequests;
static std::atomic<S32> sActiveLODRequests;
static U32 sMaxConcurrentRequests;
static S32 sRequestLowWater;
static S32 sRequestHighWater;

View File

@ -139,32 +139,60 @@ void LLPanelContents::getState(LLViewerObject *objectp )
void LLPanelContents::onFilterEdit()
{
const std::string& filter_substring = mFilterEditor->getText();
if (filter_substring.empty())
if (!mPanelInventoryObject->hasInventory())
{
if (mPanelInventoryObject->getFilter().getFilterSubString().empty())
{
// The current filter and the new filter are empty, nothing to do
return;
}
mSavedFolderState.setApply(true);
mPanelInventoryObject->getRootFolder()->applyFunctorRecursively(mSavedFolderState);
// Add a folder with the current item to the list of previously opened folders
LLOpenFoldersWithSelection opener;
mPanelInventoryObject->getRootFolder()->applyFunctorRecursively(opener);
mPanelInventoryObject->getRootFolder()->scrollToShowSelection();
mDirtyFilter = true;
}
else if (mPanelInventoryObject->getFilter().getFilterSubString().empty())
else
{
// The first letter in search term, save existing folder open state
if (!mPanelInventoryObject->getFilter().isNotDefault())
LLFolderView* root_folder = mPanelInventoryObject->getRootFolder();
if (filter_substring.empty())
{
mSavedFolderState.setApply(false);
mPanelInventoryObject->getRootFolder()->applyFunctorRecursively(mSavedFolderState);
if (mPanelInventoryObject->getFilter().getFilterSubString().empty())
{
// The current filter and the new filter are empty, nothing to do
return;
}
if (mDirtyFilter && !mSavedFolderState.hasOpenFolders())
{
if (root_folder)
{
root_folder->setOpenArrangeRecursively(true, LLFolderViewFolder::ERecurseType::RECURSE_DOWN);
}
}
else
{
mSavedFolderState.setApply(true);
if (root_folder)
{
root_folder->applyFunctorRecursively(mSavedFolderState);
}
}
mDirtyFilter = false;
// Add a folder with the current item to the list of previously opened folders
if (root_folder)
{
LLOpenFoldersWithSelection opener;
root_folder->applyFunctorRecursively(opener);
root_folder->scrollToShowSelection();
}
}
else if (mPanelInventoryObject->getFilter().getFilterSubString().empty())
{
// The first letter in search term, save existing folder open state
if (!mPanelInventoryObject->getFilter().isNotDefault())
{
mSavedFolderState.setApply(false);
if (root_folder)
{
root_folder->applyFunctorRecursively(mSavedFolderState);
}
mDirtyFilter = false;
}
}
}
mPanelInventoryObject->getFilter().setFilterSubString(filter_substring);
}

View File

@ -70,6 +70,8 @@ protected:
void getState(LLViewerObject *object);
void onFilterEdit();
bool mDirtyFilter { false };
public:
class LLFilterEditor* mFilterEditor;
LLSaveFolderState mSavedFolderState;

View File

@ -438,7 +438,7 @@ void LLPanelEmojiComplete::updateConstraints()
{
mRenderRect = getLocalRect();
mEmojiWidth = (U16)(mIconFont->getWidthF32(u8"\U0001F431") + mPadding * 2);
mEmojiWidth = (U16)(mIconFont->getWidthF32(LLWString(1, 0x1F431).c_str()) + mPadding * 2);
if (mVertical)
{
mEmojiHeight = mIconFont->getLineHeight() + mPadding * 2;

View File

@ -898,6 +898,10 @@ struct LLPanelFaceGetIsAlignedTEFunctor : public LLSelectedTEFunctor
if (facep->calcAlignedPlanarTE(mCenterFace, &aligned_st_offset, &aligned_st_scale, &aligned_st_rot))
{
const LLTextureEntry* tep = facep->getTextureEntry();
if (!tep)
{
return false;
}
LLVector2 st_offset, st_scale;
tep->getOffset(&st_offset.mV[VX], &st_offset.mV[VY]);
tep->getScale(&st_scale.mV[VX], &st_scale.mV[VY]);

View File

@ -56,6 +56,7 @@ LLPanelGroupBulkImpl::LLPanelGroupBulkImpl(const LLUUID& group_id) :
mGroupID(group_id),
mBulkAgentList(NULL),
mOKButton(NULL),
mAddButton(nullptr),
mRemoveButton(NULL),
mGroupName(NULL),
mLoadingText(),
@ -79,29 +80,18 @@ LLPanelGroupBulkImpl::~LLPanelGroupBulkImpl()
}
}
// static
void LLPanelGroupBulkImpl::callbackClickAdd(void* userdata)
void LLPanelGroupBulkImpl::callbackClickAdd(LLPanelGroupBulk* panelp)
{
if (LLPanelGroupBulk* panelp = (LLPanelGroupBulk*)userdata)
{
// Right now this is hard coded with some knowledge that it is part
// of a floater since the avatar picker needs to be added as a dependent
// floater to the parent floater.
// Soon the avatar picker will be embedded into this panel
// instead of being it's own separate floater. But that is next week.
// This will do for now. -jwolk May 10, 2006
LLView* button = panelp->findChild<LLButton>("add_button");
LLFloater* root_floater = gFloaterView->getParentFloater(panelp);
LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(
[&](const uuid_vec_t& agent_ids, const std::vector<LLAvatarName>&)
{
panelp->mImplementation->addUsers(agent_ids);
}, true, false, false, root_floater->getName(), button);
if (picker)
LLFloater* root_floater = gFloaterView->getParentFloater(panelp);
LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(
[this](const uuid_vec_t& agent_ids, const std::vector<LLAvatarName>&)
{
root_floater->addDependentFloater(picker);
LLGroupMgr::getInstance()->sendCapGroupMembersRequest(panelp->mImplementation->mGroupID);
}
addUsers(agent_ids);
}, true, false, false, root_floater->getName(), mAddButton);
if (picker)
{
root_floater->addDependentFloater(picker);
LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
}
}

View File

@ -68,35 +68,26 @@ bool LLPanelGroupBulkBan::postBuild()
mImplementation->mBulkAgentList->setCommitCallback(LLPanelGroupBulkImpl::callbackSelect, mImplementation);
}
LLButton* button = getChild<LLButton>("add_button", recurse);
if ( button )
mImplementation->mAddButton = getChild<LLButton>("add_button", recurse);
// default to opening avatarpicker automatically
mImplementation->mAddButton->setClickedCallback(
[this](LLUICtrl* ctrl, const LLSD& param)
{
// default to opening avatarpicker automatically
// (*impl::callbackClickAdd)((void*)this);
button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickAdd, this);
}
mImplementation->callbackClickAdd(this);
});
mImplementation->mRemoveButton =
getChild<LLButton>("remove_button", recurse);
if ( mImplementation->mRemoveButton )
{
mImplementation->mRemoveButton->setClickedCallback(LLPanelGroupBulkImpl::callbackClickRemove, mImplementation);
mImplementation->mRemoveButton->setEnabled(false);
}
mImplementation->mRemoveButton->setClickedCallback(LLPanelGroupBulkImpl::callbackClickRemove, mImplementation);
mImplementation->mRemoveButton->setEnabled(false);
mImplementation->mOKButton =
getChild<LLButton>("ban_button", recurse);
if ( mImplementation->mOKButton )
{
mImplementation->mOKButton->setClickedCallback(LLPanelGroupBulkBan::callbackClickSubmit, this);
mImplementation->mOKButton->setEnabled(false);
}
mImplementation->mOKButton->setClickedCallback(LLPanelGroupBulkBan::callbackClickSubmit, this);
mImplementation->mOKButton->setEnabled(false);
button = getChild<LLButton>("cancel_button", recurse);
if ( button )
{
button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickCancel, mImplementation);
}
LLButton* button = getChild<LLButton>("cancel_button", recurse);
button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickCancel, mImplementation);
mImplementation->mTooManySelected = getString("ban_selection_too_large");
mImplementation->mBanNotPermitted = getString("ban_not_permitted");

View File

@ -44,7 +44,7 @@ public:
LLPanelGroupBulkImpl(const LLUUID& group_id);
~LLPanelGroupBulkImpl();
static void callbackClickAdd(void* userdata);
void callbackClickAdd(LLPanelGroupBulk* panelp);
static void callbackClickRemove(void* userdata);
static void callbackClickCancel(void* userdata);
@ -70,6 +70,7 @@ public:
LLNameListCtrl* mBulkAgentList;
LLButton* mOKButton;
LLButton* mAddButton;
LLButton* mRemoveButton;
LLTextBox* mGroupName;

View File

@ -2425,10 +2425,14 @@ void LLPanelMainInventory::updateCombinationVisibility()
mCombinationGalleryLayoutPanel->setVisible(!is_gallery_empty);
mCombinationListLayoutPanel->setVisible(show_inv_pane);
mCombinationInventoryPanel->getRootFolder()->setForceArrange(!show_inv_pane);
if(mCombinationInventoryPanel->hasVisibleItems())
LLFolderView* root_folder = mCombinationInventoryPanel->getRootFolder();
if (root_folder)
{
mForceShowInvLayout = false;
root_folder->setForceArrange(!show_inv_pane);
if (mCombinationInventoryPanel->hasVisibleItems())
{
mForceShowInvLayout = false;
}
}
if(is_gallery_empty)
{

View File

@ -85,6 +85,8 @@ public:
static void idle(void* user_data);
bool hasInventory(){ return mHaveInventory; };
protected:
void reset();
/*virtual*/ void inventoryChanged(LLViewerObject* object,

View File

@ -660,11 +660,11 @@ void LLPanelPrimMediaControls::updateShape()
for(; vert_it != vert_end; ++vert_it)
{
// project silhouette vertices into screen space
glm::vec3 screen_vert(glm::make_vec3(vert_it->mV));
glm::vec3 screen_vert(*vert_it);
screen_vert = mul_mat4_vec3(mat, screen_vert);
// add to screenspace bounding box
update_min_max(min, max, LLVector3(glm::value_ptr(screen_vert)));
update_min_max(min, max, LLVector3(screen_vert));
}
// convert screenspace bbox to pixels (in screen coords)

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