diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index cb070b0881..0851d20be0 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -1,5 +1,6 @@
# Replace tabs with spaces
1b68f71348ecf3983b76b40d7940da8377f049b7
+33418a77b716e122da9778869cdbabe97c83ff37
# Trim trailing whitespace
a0b3021bdcf76859054fda8e30abb3ed47749e83
8444cd9562a6a7b755fcb075864e205122354192
diff --git a/.github/workflows/tag-release.yaml b/.github/workflows/tag-release.yaml
index b73ec502f1..65d1d43a83 100644
--- a/.github/workflows/tag-release.yaml
+++ b/.github/workflows/tag-release.yaml
@@ -26,23 +26,22 @@ on:
jobs:
tag-release:
runs-on: ubuntu-latest
- env:
- GITHUB_TAG_TOKEN: ${{ secrets.GITHUB_TAG_TOKEN }}
steps:
- name: Setup Env Vars
run: |
CHANNEL="${{ inputs.channel }}"
echo VIEWER_CHANNEL="Second_Life_${CHANNEL:-Develop}" >> ${GITHUB_ENV}
- echo NIGHTLY_DATE=$(date --rfc-3339=date) >> ${GITHUB_ENV}
+ NIGHTLY_DATE=$(date --rfc-3339=date)
+ echo NIGHTLY_DATE=${NIGHTLY_DATE} >> ${GITHUB_ENV}
+ echo TAG_ID="$(echo ${{ github.sha }} | cut -c1-8)-${{ inputs.project || '${NIGHTLY_DATE}' }}" >> ${GITHUB_ENV}
- name: Update Tag
uses: actions/github-script@v7.0.1
- if: env.GITHUB_TAG_TOKEN
with:
- github-token: ${{ env.GITHUB_TAG_TOKEN }}
+ github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
- github.rest.git.createRef(
+ github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
- ref: "refs/tags/${{ env.VIEWER_CHANNEL }}#${{ env.NIGHTLY_DATE }}",
+ ref: "refs/tags/${{ env.VIEWER_CHANNEL }}#${{ env.TAG_ID }}",
sha: context.sha
- )
+ })
diff --git a/autobuild.xml b/autobuild.xml
index e6b7a0fa32..5695a5105b 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -3063,66 +3063,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
name
vlc-bin
- xmlrpc-epi
-
vulkan_gltf
platforms
diff --git a/doc/testplans/pbr_terrain_appearance.md b/doc/testplans/pbr_terrain_appearance.md
index 11b501be3a..770e39204e 100644
--- a/doc/testplans/pbr_terrain_appearance.md
+++ b/doc/testplans/pbr_terrain_appearance.md
@@ -50,3 +50,14 @@ If triplanar mapping is enabled, and an avatar faces an axially-aligned wall, th
Textures of materials should not appear mirrored.
When triplanar mapping is enabled, rotations on the axially aligned walls should apply in the same direction as they would on flat ground.
+
+## PBR Terrain Normal Textures
+
+This section assumes terrain normal maps are enabled at the current graphics setting.
+
+PBR terrain should have approximately correct lighting based on the normal texture:
+
+- When on flat ground
+- On cliffs, when triplanar mapping is enabled. Lighting will be somewhat less accurate when the cliff face is not axially aligned.
+- If no Terrain Texture Transform is applied.
+- If a Terrain Texture Transform is applied, especially for rotation or negative scale.
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index c58f9a0c1a..965a12787d 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -66,7 +66,6 @@ set(cmake_SOURCE_FILES
VisualLeakDetector.cmake
LibVLCPlugin.cmake
WebRTC.cmake
- XmlRpcEpi.cmake
xxHash.cmake
ZLIBNG.cmake
)
diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake
index 9e3707ff17..dd43ca4916 100644
--- a/indra/cmake/LLCommon.cmake
+++ b/indra/cmake/LLCommon.cmake
@@ -6,5 +6,3 @@ include(EXPAT)
include(Tracy)
include(xxHash)
include(ZLIBNG)
-
-include(XmlRpcEpi)
diff --git a/indra/cmake/XmlRpcEpi.cmake b/indra/cmake/XmlRpcEpi.cmake
deleted file mode 100644
index 6409f9d6e2..0000000000
--- a/indra/cmake/XmlRpcEpi.cmake
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- cmake -*-
-include(Prebuilt)
-
-include_guard()
-add_library( ll::xmlrpc-epi INTERFACE IMPORTED )
-
-use_system_binary( xmlrpc-epi )
-
-use_prebuilt_binary(xmlrpc-epi)
-target_link_libraries(ll::xmlrpc-epi INTERFACE xmlrpc-epi )
-target_include_directories( ll::xmlrpc-epi SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include)
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index d7dc22c7a0..1f90504e8b 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -248,6 +248,24 @@ int LLFile::close(LLFILE * file)
return ret_value;
}
+std::string LLFile::getContents(const std::string& filename)
+{
+ LLFILE* fp = fopen(filename, "rb"); /* Flawfinder: ignore */
+ if (fp)
+ {
+ fseek(fp, 0, SEEK_END);
+ U32 length = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ std::vector buffer(length);
+ size_t nread = fread(buffer.data(), 1, length, fp);
+ fclose(fp);
+
+ return std::string(buffer.data(), nread);
+ }
+
+ return LLStringUtil::null;
+}
int LLFile::remove(const std::string& filename, int supress_error)
{
diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h
index 2564671b13..74110343fc 100644
--- a/indra/llcommon/llfile.h
+++ b/indra/llcommon/llfile.h
@@ -67,6 +67,8 @@ public:
static int close(LLFILE * file);
+ static std::string getContents(const std::string& filename);
+
// perms is a permissions mask like 0777 or 0700. In most cases it will
// be overridden by the user's umask. It is ignored on Windows.
// mkdir() considers "directory already exists" to be SUCCESS.
diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp
index f7162bcf6e..104c40f0d7 100644
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -86,7 +86,7 @@ void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size)
void LLMemory::updateMemoryInfo()
{
LL_PROFILE_ZONE_SCOPED
- U32Kilobytes avail_phys; // align MemInfo across platforms
+ U32Kilobytes avail_phys;
#if LL_WINDOWS
PROCESS_MEMORY_COUNTERS counters;
@@ -97,25 +97,11 @@ void LLMemory::updateMemoryInfo()
}
sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(counters.WorkingSetSize));
- // sample(sAllocatedMem, sAllocatedMemInKB); // align MemInfo across platforms
sAllocatedPageSizeInKB = U32Kilobytes::convert(U64Bytes(counters.PagefileUsage));
sample(sVirtualMem, sAllocatedPageSizeInKB);
- // align MemInfo across platforms
- // U32Kilobytes avail_phys, avail_virtual;
- // LLMemoryInfo::getAvailableMemoryKB(avail_phys, avail_virtual) ;
- // sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB);
-
- // if(sMaxPhysicalMemInKB > sAllocatedMemInKB)
- // {
- // sAvailPhysicalMemInKB = sMaxPhysicalMemInKB - sAllocatedMemInKB ;
- // }
- // else
- // {
- // sAvailPhysicalMemInKB = U32Kilobytes(0);
- // }
- U32Kilobytes avail_virtual;
+ U32Kilobytes avail_virtual;
LLMemoryInfo::getAvailableMemoryKB(avail_phys, avail_virtual) ;
- //
+
#elif defined(LL_DARWIN)
task_vm_info info;
mach_msg_type_number_t infoCount = TASK_VM_INFO_COUNT;
@@ -151,26 +137,20 @@ void LLMemory::updateMemoryInfo()
if (result == KERN_SUCCESS) {
// This is what Chrome reports as 'the "Physical Memory Free" value reported by the Memory Monitor in Instruments.'
// Note though that inactive pages are not included here and not yet free, but could become so under memory pressure.
- // align MemInfo across platforms
- // sAvailPhysicalMemInKB = U32Bytes(vmstat.free_count * page_size);
- // sMaxPhysicalMemInKB = LLMemoryInfo::getHardwareMemSize();
avail_phys = U32Bytes(vmstat.free_count * page_size);
sMaxHeapSizeInKB = LLMemoryInfo::getHardwareMemSize();
- //
}
else
{
LL_WARNS() << "task_info failed" << LL_ENDL;
}
- // align MemInfo across platforms
#elif defined(LL_LINUX)
// Use sysinfo() to get the total physical memory.
struct sysinfo info;
sysinfo(&info);
sMaxHeapSizeInKB = U32Kilobytes::convert((U64Bytes)info.totalram); // Total RAM in system
avail_phys = U32Kilobytes::convert((U64Bytes)info.freeram); // Total Free RAM in system
- sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(LLMemory::getCurrentRSS())); // represents the RAM allocated by this process only (inline with the windows implementation)
- //
+ sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(LLMemory::getCurrentRSS())); // represents the RAM allocated by this process only (in line with the windows implementation)
#else
//not valid for other systems for now.
LL_WARNS() << "LLMemory::updateMemoryInfo() not implemented for this platform." << LL_ENDL;
@@ -178,10 +158,9 @@ void LLMemory::updateMemoryInfo()
sMaxPhysicalMemInKB = U64Bytes(U32_MAX);
sAvailPhysicalMemInKB = U64Bytes(U32_MAX);
#endif
- // align MemInfo across platforms
sample(sAllocatedMem, sAllocatedMemInKB);
// sMaxPhysicalMem - max this process can use = the lesser of (what we already have + what's available) or MaxHeap
- sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB);
+ sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB);
if(sMaxPhysicalMemInKB > sAllocatedMemInKB)
{
@@ -191,7 +170,6 @@ void LLMemory::updateMemoryInfo()
{
sAvailPhysicalMemInKB = U32Kilobytes(0);
}
- //
return ;
}
diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index 663ceac22b..b36ff7d263 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -30,6 +30,7 @@
#include "linden_common.h"
#include "llsd.h"
+#include "llbase64.h"
#include "llerror.h"
#include "../llmath/llmath.h"
#include "llformat.h"
@@ -142,6 +143,8 @@ public:
virtual const String& asStringRef() const { static const std::string empty; return empty; }
+ virtual String asXMLRPCValue() const { return ""; }
+
virtual bool has(const String&) const { return false; }
virtual LLSD get(const String&) const { return LLSD(); }
virtual LLSD getKeys() const { return LLSD::emptyArray(); }
@@ -222,6 +225,8 @@ namespace
virtual LLSD::Integer asInteger() const { return mValue ? 1 : 0; }
virtual LLSD::Real asReal() const { return mValue ? 1 : 0; }
virtual LLSD::String asString() const;
+
+ virtual LLSD::String asXMLRPCValue() const { return mValue ? "1" : "0"; }
};
LLSD::String ImplBoolean::asString() const
@@ -243,6 +248,8 @@ namespace
virtual LLSD::Integer asInteger() const { return mValue; }
virtual LLSD::Real asReal() const { return mValue; }
virtual LLSD::String asString() const;
+
+ virtual LLSD::String asXMLRPCValue() const { return "" + std::to_string(mValue) + ""; }
};
LLSD::String ImplInteger::asString() const
@@ -259,6 +266,8 @@ namespace
virtual LLSD::Integer asInteger() const;
virtual LLSD::Real asReal() const { return mValue; }
virtual LLSD::String asString() const;
+
+ virtual LLSD::String asXMLRPCValue() const { return "" + std::to_string(mValue) + ""; }
};
LLSD::Boolean ImplReal::asBoolean() const
@@ -286,9 +295,11 @@ namespace
virtual LLSD::URI asURI() const { return LLURI(mValue); }
virtual size_t size() const { return mValue.size(); }
virtual const LLSD::String& asStringRef() const { return mValue; }
+
+ virtual LLSD::String asXMLRPCValue() const { return "" + LLStringFn::xml_encode(mValue) + ""; }
};
- LLSD::Integer ImplString::asInteger() const
+ LLSD::Integer ImplString::asInteger() const
{
// This must treat "1.23" not as an error, but as a number, which is
// then truncated down to an integer. Hence, this code doesn't call
@@ -298,7 +309,7 @@ namespace
return (int)asReal();
}
- LLSD::Real ImplString::asReal() const
+ LLSD::Real ImplString::asReal() const
{
F64 v = 0.0;
std::istringstream i_stream(mValue);
@@ -323,6 +334,8 @@ namespace
virtual LLSD::String asString() const{ return mValue.asString(); }
virtual LLSD::UUID asUUID() const { return mValue; }
+
+ virtual LLSD::String asXMLRPCValue() const { return "" + mValue.asString() + ""; }
};
@@ -344,6 +357,8 @@ namespace
}
virtual LLSD::String asString() const{ return mValue.asString(); }
virtual LLSD::Date asDate() const { return mValue; }
+
+ virtual LLSD::String asXMLRPCValue() const { return "" + mValue.toHTTPDateString("%FT%T") + ""; }
};
@@ -355,6 +370,8 @@ namespace
virtual LLSD::String asString() const{ return mValue.asString(); }
virtual LLSD::URI asURI() const { return mValue; }
+
+ virtual LLSD::String asXMLRPCValue() const { return "" + LLStringFn::xml_encode(mValue.asString()) + ""; }
};
@@ -365,13 +382,15 @@ namespace
ImplBinary(const LLSD::Binary& v) : Base(v) { }
virtual const LLSD::Binary& asBinary() const{ return mValue; }
+
+ virtual LLSD::String asXMLRPCValue() const { return "" + LLBase64::encode(mValue.data(), mValue.size()) + ""; }
};
class ImplMap : public LLSD::Impl
{
private:
- typedef std::map DataMap;
+ typedef std::map DataMap;
DataMap mData;
@@ -387,6 +406,19 @@ namespace
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
+ virtual LLSD::String asXMLRPCValue() const
+ {
+ std::ostringstream os;
+ os << "";
+ for (const auto& it : mData)
+ {
+ os << "" << LLStringFn::xml_encode(it.first) << ""
+ << it.second.asXMLRPCValue() << "";
+ }
+ os << "";
+ return os.str();
+ }
+
virtual bool has(const LLSD::String&) const;
using LLSD::Impl::get; // Unhiding get(size_t)
@@ -511,7 +543,7 @@ namespace
class ImplArray : public LLSD::Impl
{
private:
- typedef std::vector DataVector;
+ typedef std::vector DataVector;
DataVector mData;
@@ -527,6 +559,18 @@ namespace
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
+ virtual LLSD::String asXMLRPCValue() const
+ {
+ std::ostringstream os;
+ os << "";
+ for (const auto& it : mData)
+ {
+ os << it.asXMLRPCValue();
+ }
+ os << "";
+ return os.str();
+ }
+
using LLSD::Impl::get; // Unhiding get(LLSD::String)
using LLSD::Impl::erase; // Unhiding erase(LLSD::String)
using LLSD::Impl::ref; // Unhiding ref(LLSD::String)
@@ -872,6 +916,155 @@ const LLSD::Binary& LLSD::asBinary() const { return safe(impl).asBinary(); }
const LLSD::String& LLSD::asStringRef() const { return safe(impl).asStringRef(); }
+LLSD::String LLSD::asXMLRPCValue() const { return "" + safe(impl).asXMLRPCValue() + ""; }
+
+static bool inline check(bool condition, const char* warning_message)
+{
+ if (!condition)
+ {
+ LL_WARNS() << warning_message << LL_ENDL;
+ }
+
+ return condition;
+}
+
+static bool parseXMLRPCArrayValue(LLSD& target, LLSD::TreeNode* node)
+{
+ LLSD::TreeNode* data = node->getFirstChild();
+ if (!check(data, "No array inner XML element ( expected)") ||
+ !check(data->hasName("data"), "Invalid array inner XML element ( expected)") ||
+ !check(!data->getNextSibling(), "Multiple array inner XML elements (single expected)"))
+ return false;
+
+ for (LLSD::TreeNode* item = data->getFirstChild(); item; item = item->getNextSibling())
+ {
+ LLSD value;
+ if (!value.fromXMLRPCValue(item))
+ return false;
+
+ target.append(value);
+ }
+
+ return true;
+}
+
+static bool parseXMLRPCStructValue(LLSD& target, LLSD::TreeNode* node)
+{
+ for (LLSD::TreeNode* item = node->getFirstChild(); item; item = item->getNextSibling())
+ {
+ if (!check(item->hasName("member"), "Invalid struct inner XML element ( expected)"))
+ return false;
+
+ std::string name;
+ LLSD value;
+ for (LLSD::TreeNode* subitem = item->getFirstChild(); subitem; subitem = subitem->getNextSibling())
+ {
+ if (subitem->hasName("name"))
+ {
+ name = LLStringFn::xml_decode(subitem->getTextContents());
+ }
+ else if (!value.fromXMLRPCValue(subitem))
+ {
+ return false;
+ }
+ }
+ if (!check(!name.empty(), "Empty struct member name"))
+ return false;
+
+ target.insert(name, value);
+ }
+
+ return true;
+}
+
+bool LLSD::fromXMLRPCValue(TreeNode* node)
+{
+ clear();
+
+ llassert(node);
+ if (!node)
+ return false;
+
+ if (!check(node->hasName("value"), "Invalid XML element ( expected)"))
+ return false;
+
+ TreeNode* inner = node->getFirstChild();
+ if (!inner)
+ {
+ check(false, "No inner XML element (value type expected)");
+ // Value with no type qualifier is treated as string
+ assign(LLStringFn::xml_decode(node->getTextContents()));
+ return true;
+ }
+
+ if (!check(!inner->getNextSibling(), "Multiple inner XML elements (single expected)"))
+ return false;
+
+ if (inner->hasName("string"))
+ {
+ assign(LLStringFn::xml_decode(inner->getTextContents()));
+ return true;
+ }
+
+ if (inner->hasName("int") || inner->hasName("i4"))
+ {
+ assign(std::stoi(inner->getTextContents()));
+ return true;
+ }
+
+ if (inner->hasName("double"))
+ {
+ assign(std::stod(inner->getTextContents()));
+ return true;
+ }
+
+ if (inner->hasName("boolean"))
+ {
+ assign(!!std::stoi(inner->getTextContents()));
+ return true;
+ }
+
+ if (inner->hasName("dateTime.iso8601"))
+ {
+ assign(Date(inner->getTextContents()));
+ return true;
+ }
+
+ if (inner->hasName("base64"))
+ {
+ std::string decoded = LLBase64::decodeAsString(inner->getTextContents());
+ Binary binary(decoded.size());
+ memcpy(binary.data(), decoded.data(), decoded.size());
+ assign(binary);
+ return true;
+ }
+
+ if (inner->hasName("array"))
+ {
+ if (!parseXMLRPCArrayValue(*this, inner))
+ {
+ clear();
+ return false;
+ }
+ return true;
+ }
+
+ if (inner->hasName("struct"))
+ {
+ if (!parseXMLRPCStructValue(*this, inner))
+ {
+ clear();
+ return false;
+ }
+ return true;
+ }
+
+ check(false, "Unknown inner XML element (known value type expected)");
+ // Value with unknown type qualifier is treated as string
+ assign(LLStringFn::xml_decode(inner->getTextContents()));
+ return true;
+}
+
// const char * helpers
LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
void LLSD::assign(const char* v)
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index a5e735b561..5532decfc3 100644
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -259,10 +259,24 @@ public:
UUID asUUID() const;
Date asDate() const;
URI asURI() const;
- const Binary& asBinary() const;
+ const Binary& asBinary() const;
// asStringRef on any non-string type will return a ref to an empty string.
- const String& asStringRef() const;
+ const String& asStringRef() const;
+
+ // Return "<((type))>((scalar value or recursive calls))((type))>"
+ // See http://xmlrpc.com/spec.md
+ String asXMLRPCValue() const;
+
+ struct TreeNode
+ {
+ virtual bool hasName(const String& name) const = 0;
+ virtual String getTextContents() const = 0;
+ virtual TreeNode* getFirstChild() const = 0;
+ virtual TreeNode* getNextSibling() const = 0;
+ };
+
+ bool fromXMLRPCValue(TreeNode* node);
operator Boolean() const { return asBoolean(); }
operator Integer() const { return asInteger(); }
@@ -275,7 +289,7 @@ public:
// This is needed because most platforms do not automatically
// convert the boolean negation as a bool in an if statement.
- bool operator!() const {return !asBoolean();}
+ bool operator!() const { return !asBoolean(); }
//@}
/** @name Character Pointer Helpers
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index 1200da23e5..58010f1448 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -1280,6 +1280,75 @@ namespace LLStringFn
return output;
}
+ using literals_t = std::map;
+ static const literals_t xml_elem_literals =
+ {
+ { '<', "<" },
+ { '>', ">" },
+ { '&', "&" }
+ };
+ static const literals_t xml_attr_literals =
+ {
+ { '"', """ },
+ { '\'', "'" }
+ };
+
+ static void literals_encode(std::string& text, const literals_t& literals)
+ {
+ for (const std::pair it : literals)
+ {
+ std::string::size_type pos = 0;
+ while ((pos = text.find(it.first, pos)) != std::string::npos)
+ {
+ text.replace(pos, 1, it.second);
+ pos += it.second.size();
+ }
+ }
+ }
+
+ static void literals_decode(std::string& text, const literals_t& literals)
+ {
+ for (const std::pair it : literals)
+ {
+ std::string::size_type pos = 0;
+ while ((pos = text.find(it.second, pos)) != std::string::npos)
+ {
+ text[pos++] = it.first;
+ text.erase(pos, it.second.size() - 1);
+ }
+ }
+ }
+
+ /**
+ * @brief Replace all characters that are not allowed in XML 1.0
+ * with corresponding literals: [ < > & ] => [ < > & ]
+ */
+ std::string xml_encode(const std::string& input, bool for_attribute)
+ {
+ std::string result(input);
+ literals_encode(result, xml_elem_literals);
+ if (for_attribute)
+ {
+ literals_encode(result, xml_attr_literals);
+ }
+ return result;
+ }
+
+ /**
+ * @brief Replace some of XML literals that are defined in XML 1.0
+ * with corresponding characters: [ < > & ] => [ < > & ]
+ */
+ std::string xml_decode(const std::string& input, bool for_attribute)
+ {
+ std::string result(input);
+ literals_decode(result, xml_elem_literals);
+ if (for_attribute)
+ {
+ literals_decode(result, xml_attr_literals);
+ }
+ return result;
+ }
+
/**
* @brief Replace all control characters (c < 0x20) with replacement in
* string.
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 42bbb565a1..198ccb1fc3 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -902,6 +902,20 @@ namespace LLStringFn
LL_COMMON_API std::string strip_invalid_xml(const std::string& input);
+ /**
+ * @brief Replace all characters that are not allowed in XML 1.0
+ * with corresponding literals: [ < > & ] => [ < > & ]
+ */
+ LL_COMMON_API std::string xml_encode(const std::string& input, bool for_attribute = false);
+
+
+ /**
+ * @brief Replace some of XML literals that are defined in XML 1.0
+ * with corresponding characters: [ < > & ] => [ < > & ]
+ */
+ LL_COMMON_API std::string xml_decode(const std::string& input, bool for_attribute = false);
+
+
/**
* @brief Replace all control characters (0 <= c < 0x20) with replacement in
* string. This is safe for utf-8
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt
index 324809c18e..0a1bdc2dbe 100644
--- a/indra/llmessage/CMakeLists.txt
+++ b/indra/llmessage/CMakeLists.txt
@@ -28,7 +28,6 @@ set(llmessage_SOURCE_FILES
lldatapacker.cpp
lldispatcher.cpp
llexperiencecache.cpp
- llfiltersd2xmlrpc.cpp
llgenericstreamingmessage.cpp
llhost.cpp
llhttpnode.cpp
@@ -113,7 +112,6 @@ set(llmessage_HEADER_FILES
lleventflags.h
llexperiencecache.h
llextendedstatus.h
- llfiltersd2xmlrpc.h
llfollowcamparams.h
llgenericstreamingmessage.h
llhost.h
@@ -195,7 +193,6 @@ target_link_libraries(
llfilesystem
llmath
llcorehttp
- ll::xmlrpc-epi
llxml # For accessing settings
)
target_include_directories( llmessage INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/indra/llmessage/llfiltersd2xmlrpc.cpp b/indra/llmessage/llfiltersd2xmlrpc.cpp
deleted file mode 100644
index b31c3e7c57..0000000000
--- a/indra/llmessage/llfiltersd2xmlrpc.cpp
+++ /dev/null
@@ -1,787 +0,0 @@
-/**
- * @file llfiltersd2xmlrpc.cpp
- * @author Phoenix
- * @date 2005-04-26
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-/**
- * xml rpc request:
- *
- *
- * examples.getStateName
- * 41
- *
- *
- *
- * xml rpc response:
- *
- *
- *
- * South Dakota
- *
- *
- *
- * xml rpc fault:
- *
- *
- *
- *
- * faultCode4
- * faultString...
- *
- *
- *
- *
- * llsd rpc request:
- *
- * { 'method':'...', 'parameter':...]}
- *
- *
- * llsd rpc response:
- *
- * { 'response':... }
- *
- *
- * llsd rpc fault:
- *
- * { 'fault': {'code':i..., 'description':'...'} }
- *
- *
- */
-
-#include "linden_common.h"
-#include "llfiltersd2xmlrpc.h"
-
-#include
-#include
-
-#ifdef LL_USESYSTEMLIBS
-#include
-#else
-#include
-#endif
-
-#include "apr_base64.h"
-
-#include "llbuffer.h"
-#include "llbufferstream.h"
-#include "llfasttimer.h"
-#include "llmemorystream.h"
-#include "llsd.h"
-#include "llsdserialize.h"
-#include "lluuid.h"
-
-// spammy mode
-//#define LL_SPEW_STREAM_OUT_DEBUGGING 1
-
-/**
- * String constants
- */
-static const char XML_HEADER[] = "";
-static const char XMLRPC_REQUEST_HEADER_1[] = "";
-static const char XMLRPC_REQUEST_HEADER_2[] = "";
-static const char XMLRPC_REQUEST_FOOTER[] = "";
-static const char XMLRPC_METHOD_RESPONSE_HEADER[] = "";
-static const char XMLRPC_METHOD_RESPONSE_FOOTER[] = "";
-static const char XMLRPC_RESPONSE_HEADER[] = "";
-static const char XMLRPC_RESPONSE_FOOTER[] = "";
-static const char XMLRPC_FAULT_1[] = "faultCode";
-static const char XMLRPC_FAULT_2[] = "faultString";
-static const char XMLRPC_FAULT_3[] = "";
-static const char LLSDRPC_RESPONSE_HEADER[] = "{'response':";
-static const char LLSDRPC_RESPONSE_FOOTER[] = "}";
-const char LLSDRPC_REQUEST_HEADER_1[] = "{'method':'";
-const char LLSDRPC_REQUEST_HEADER_2[] = "', 'parameter': ";
-const char LLSDRPC_REQUEST_FOOTER[] = "}";
-static const char LLSDRPC_FAULT_HADER_1[] = "{ 'fault': {'code':i";
-static const char LLSDRPC_FAULT_HADER_2[] = ", 'description':";
-static const char LLSDRPC_FAULT_FOOTER[] = "} }";
-static const S32 DEFAULT_PRECISION = 20;
-
-/**
- * LLFilterSD2XMLRPC
- */
-LLFilterSD2XMLRPC::LLFilterSD2XMLRPC()
-{
-}
-
-LLFilterSD2XMLRPC::~LLFilterSD2XMLRPC()
-{
-}
-
-std::string xml_escape_string(const std::string& in)
-{
- std::ostringstream out;
- std::string::const_iterator it = in.begin();
- std::string::const_iterator end = in.end();
- for(; it != end; ++it)
- {
- // Skip invalid characters. There a s few more, but those would need inspecting of the UTF-8 sequence.
- // See http://en.wikipedia.org/wiki/Valid_characters_in_XML
- if( *it >= 0 && *it < 20 && *it != 0x09 && *it != 0x0A && *it != 0x0D )
- {
- out << "?";
- continue;
- }
- //
-
- switch((*it))
- {
- case '<':
- out << "<";
- break;
- case '>':
- out << ">";
- break;
- case '&':
- out << "&";
- break;
- case '\'':
- out << "'";
- break;
- case '"':
- out << """;
- break;
- default:
- out << (*it);
- break;
- }
- }
- return out.str();
-}
-
-void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd)
-{
- ostr << "";
- switch(sd.type())
- {
- case LLSD::TypeMap:
- {
-#if LL_SPEW_STREAM_OUT_DEBUGGING
- LL_INFOS() << "streamOut(map) BEGIN" << LL_ENDL;
-#endif
- ostr << "";
- if(ostr.fail())
- {
- LL_INFOS() << "STREAM FAILURE writing struct" << LL_ENDL;
- }
- LLSD::map_const_iterator it = sd.beginMap();
- LLSD::map_const_iterator end = sd.endMap();
- for(; it != end; ++it)
- {
- ostr << "" << xml_escape_string((*it).first)
- << "";
- streamOut(ostr, (*it).second);
- if(ostr.fail())
- {
- LL_INFOS() << "STREAM FAILURE writing '" << (*it).first
- << "' with sd type " << (*it).second.type() << LL_ENDL;
- }
- ostr << "";
- }
- ostr << "";
-#if LL_SPEW_STREAM_OUT_DEBUGGING
- LL_INFOS() << "streamOut(map) END" << LL_ENDL;
-#endif
- break;
- }
- case LLSD::TypeArray:
- {
-#if LL_SPEW_STREAM_OUT_DEBUGGING
- LL_INFOS() << "streamOut(array) BEGIN" << LL_ENDL;
-#endif
- ostr << "";
- LLSD::array_const_iterator it = sd.beginArray();
- LLSD::array_const_iterator end = sd.endArray();
- for(; it != end; ++it)
- {
- streamOut(ostr, *it);
- if(ostr.fail())
- {
- LL_INFOS() << "STREAM FAILURE writing array element sd type "
- << (*it).type() << LL_ENDL;
- }
- }
-#if LL_SPEW_STREAM_OUT_DEBUGGING
- LL_INFOS() << "streamOut(array) END" << LL_ENDL;
-#endif
- ostr << "";
- break;
- }
- case LLSD::TypeUndefined:
- // treat undefined as a bool with a false value.
- case LLSD::TypeBoolean:
-#if LL_SPEW_STREAM_OUT_DEBUGGING
- LL_INFOS() << "streamOut(bool)" << LL_ENDL;
-#endif
- ostr << "" << (sd.asBoolean() ? "1" : "0") << "";
- break;
- case LLSD::TypeInteger:
-#if LL_SPEW_STREAM_OUT_DEBUGGING
- LL_INFOS() << "streamOut(int)" << LL_ENDL;
-#endif
- ostr << "" << sd.asInteger() << "";
- break;
- case LLSD::TypeReal:
-#if LL_SPEW_STREAM_OUT_DEBUGGING
- LL_INFOS() << "streamOut(real)" << LL_ENDL;
-#endif
- ostr << "" << sd.asReal() << "";
- break;
- case LLSD::TypeString:
-#if LL_SPEW_STREAM_OUT_DEBUGGING
- LL_INFOS() << "streamOut(string)" << LL_ENDL;
-#endif
- ostr << "" << xml_escape_string(sd.asString()) << "";
- break;
- case LLSD::TypeUUID:
-#if LL_SPEW_STREAM_OUT_DEBUGGING
- LL_INFOS() << "streamOut(uuid)" << LL_ENDL;
-#endif
- // serialize it as a string
- ostr << "" << sd.asString() << "";
- break;
- case LLSD::TypeURI:
- {
-#if LL_SPEW_STREAM_OUT_DEBUGGING
- LL_INFOS() << "streamOut(uri)" << LL_ENDL;
-#endif
- // serialize it as a string
- ostr << "" << xml_escape_string(sd.asString()) << "";
- break;
- }
- case LLSD::TypeBinary:
- {
-#if LL_SPEW_STREAM_OUT_DEBUGGING
- LL_INFOS() << "streamOut(binary)" << LL_ENDL;
-#endif
- // this is pretty inefficient, but we'll deal with that
- // problem when it becomes one.
- ostr << "";
- LLSD::Binary buffer = sd.asBinary();
- if(!buffer.empty())
- {
- // *TODO: convert to LLBase64
- int b64_buffer_length = apr_base64_encode_len(static_cast(buffer.size()));
- char* b64_buffer = new char[b64_buffer_length];
- b64_buffer_length = apr_base64_encode_binary(
- b64_buffer,
- &buffer[0],
- static_cast(buffer.size()));
- ostr.write(b64_buffer, b64_buffer_length - 1);
- delete[] b64_buffer;
- }
- ostr << "";
- break;
- }
- case LLSD::TypeDate:
-#if LL_SPEW_STREAM_OUT_DEBUGGING
- LL_INFOS() << "streamOut(date)" << LL_ENDL;
-#endif
- // no need to escape this since it will be alpha-numeric.
- ostr << "" << sd.asString() << "";
- break;
- default:
- // unhandled type
- LL_WARNS() << "Unhandled structured data type: " << sd.type()
- << LL_ENDL;
- break;
- }
- ostr << "";
-}
-
-/**
- * LLFilterSD2XMLRPCResponse
- */
-
-LLFilterSD2XMLRPCResponse::LLFilterSD2XMLRPCResponse()
-{
-}
-
-LLFilterSD2XMLRPCResponse::~LLFilterSD2XMLRPCResponse()
-{
-}
-
-
-// virtual
-LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_PROFILE_ZONE_SCOPED;
-
- PUMP_DEBUG;
- // This pipe does not work if it does not have everyting. This
- // could be addressed by making a stream parser for llsd which
- // handled partial information.
- if(!eos)
- {
- return STATUS_BREAK;
- }
-
- PUMP_DEBUG;
- // we have everyting in the buffer, so turn the structure data rpc
- // response into an xml rpc response.
- LLBufferStream stream(channels, buffer.get());
- stream << XML_HEADER << XMLRPC_METHOD_RESPONSE_HEADER;
- LLSD sd;
- LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in()));
-
- PUMP_DEBUG;
- LLIOPipe::EStatus rv = STATUS_ERROR;
- if(sd.has("response"))
- {
- PUMP_DEBUG;
- // it is a normal response. pack it up and ship it out.
- stream.precision(DEFAULT_PRECISION);
- stream << XMLRPC_RESPONSE_HEADER;
- streamOut(stream, sd["response"]);
- stream << XMLRPC_RESPONSE_FOOTER << XMLRPC_METHOD_RESPONSE_FOOTER;
- rv = STATUS_DONE;
- }
- else if(sd.has("fault"))
- {
- PUMP_DEBUG;
- // it is a fault.
- stream << XMLRPC_FAULT_1 << sd["fault"]["code"].asInteger()
- << XMLRPC_FAULT_2
- << xml_escape_string(sd["fault"]["description"].asString())
- << XMLRPC_FAULT_3 << XMLRPC_METHOD_RESPONSE_FOOTER;
- rv = STATUS_DONE;
- }
- else
- {
- LL_WARNS() << "Unable to determine the type of LLSD response." << LL_ENDL;
- }
- PUMP_DEBUG;
- return rv;
-}
-
-/**
- * LLFilterSD2XMLRPCRequest
- */
-LLFilterSD2XMLRPCRequest::LLFilterSD2XMLRPCRequest()
-{
-}
-
-LLFilterSD2XMLRPCRequest::LLFilterSD2XMLRPCRequest(const char* method)
-{
- if(method)
- {
- mMethod.assign(method);
- }
-}
-
-LLFilterSD2XMLRPCRequest::~LLFilterSD2XMLRPCRequest()
-{
-}
-
-// virtual
-LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_PROFILE_ZONE_SCOPED;
- // This pipe does not work if it does not have everyting. This
- // could be addressed by making a stream parser for llsd which
- // handled partial information.
- PUMP_DEBUG;
- if(!eos)
- {
- LL_INFOS() << "!eos" << LL_ENDL;
- return STATUS_BREAK;
- }
-
- // See if we can parse it
- LLBufferStream stream(channels, buffer.get());
- LLSD sd;
- LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in()));
- if(stream.fail())
- {
- LL_INFOS() << "STREAM FAILURE reading structure data." << LL_ENDL;
- }
-
- PUMP_DEBUG;
- // We can get the method and parameters from either the member
- // function or passed in via the buffer. We prefer the buffer if
- // we found a parameter and a method, or fall back to using
- // mMethod and putting everyting in the buffer into the parameter.
- std::string method;
- LLSD param_sd;
- if(sd.has("method") && sd.has("parameter"))
- {
- method = sd["method"].asString();
- param_sd = sd["parameter"];
- }
- else
- {
- method = mMethod;
- param_sd = sd;
- }
- if(method.empty())
- {
- LL_WARNS() << "SD -> XML Request no method found." << LL_ENDL;
- return STATUS_ERROR;
- }
-
- PUMP_DEBUG;
- // We have a method, and some kind of parameter, so package it up
- // and send it out.
- LLBufferStream ostream(channels, buffer.get());
- ostream.precision(DEFAULT_PRECISION);
- if(ostream.fail())
- {
- LL_INFOS() << "STREAM FAILURE setting precision" << LL_ENDL;
- }
- ostream << XML_HEADER << XMLRPC_REQUEST_HEADER_1
- << xml_escape_string(method) << XMLRPC_REQUEST_HEADER_2;
- if(ostream.fail())
- {
- LL_INFOS() << "STREAM FAILURE writing method headers" << LL_ENDL;
- }
- switch(param_sd.type())
- {
- case LLSD::TypeMap:
- // If the params are a map, then we do not want to iterate
- // through them since the iterators returned will be map
- // ordered un-named values, which will lose the names, and
- // only stream the values, turning it into an array.
- ostream << "";
- streamOut(ostream, param_sd);
- ostream << "";
- break;
- case LLSD::TypeArray:
- {
-
- LLSD::array_iterator it = param_sd.beginArray();
- LLSD::array_iterator end = param_sd.endArray();
- for(; it != end; ++it)
- {
- ostream << "";
- streamOut(ostream, *it);
- ostream << "";
- }
- break;
- }
- default:
- ostream << "";
- streamOut(ostream, param_sd);
- ostream << "";
- break;
- }
-
- stream << XMLRPC_REQUEST_FOOTER;
- return STATUS_DONE;
-}
-
-/**
- * LLFilterXMLRPCResponse2LLSD
- */
-// this is a c function here since it's really an implementation
-// detail that requires a header file just get the definition of the
-// parameters.
-LLIOPipe::EStatus stream_out(std::ostream& ostr, XMLRPC_VALUE value)
-{
- XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(value);
- LLIOPipe::EStatus status = LLIOPipe::STATUS_OK;
- switch(type)
- {
- case xmlrpc_type_base64:
- {
- S32 len = XMLRPC_GetValueStringLen(value);
- const char* buf = XMLRPC_GetValueBase64(value);
- ostr << " b(";
- if((len > 0) && buf)
- {
- ostr << len << ")\"";
- ostr.write(buf, len);
- ostr << "\"";
- }
- else
- {
- ostr << "0)\"\"";
- }
- break;
- }
- case xmlrpc_type_boolean:
- //LL_DEBUGS() << "stream_out() bool" << LL_ENDL;
- ostr << " " << (XMLRPC_GetValueBoolean(value) ? "true" : "false");
- break;
- case xmlrpc_type_datetime:
- ostr << " d\"" << XMLRPC_GetValueDateTime_ISO8601(value) << "\"";
- break;
- case xmlrpc_type_double:
- ostr << " r" << XMLRPC_GetValueDouble(value);
- //LL_DEBUGS() << "stream_out() double" << XMLRPC_GetValueDouble(value)
- // << LL_ENDL;
- break;
- case xmlrpc_type_int:
- ostr << " i" << XMLRPC_GetValueInt(value);
- //LL_DEBUGS() << "stream_out() integer:" << XMLRPC_GetValueInt(value)
- // << LL_ENDL;
- break;
- case xmlrpc_type_string:
- //LL_DEBUGS() << "stream_out() string: " << str << LL_ENDL;
- ostr << " s(" << XMLRPC_GetValueStringLen(value) << ")'"
- << XMLRPC_GetValueString(value) << "'";
- break;
- case xmlrpc_type_array: // vector
- case xmlrpc_type_mixed: // vector
- {
- //LL_DEBUGS() << "stream_out() array" << LL_ENDL;
- ostr << " [";
- U32 needs_comma = 0;
- XMLRPC_VALUE current = XMLRPC_VectorRewind(value);
- while(current && (LLIOPipe::STATUS_OK == status))
- {
- if(needs_comma++) ostr << ",";
- status = stream_out(ostr, current);
- current = XMLRPC_VectorNext(value);
- }
- ostr << "]";
- break;
- }
- case xmlrpc_type_struct: // still vector
- {
- //LL_DEBUGS() << "stream_out() struct" << LL_ENDL;
- ostr << " {";
- std::string name;
- U32 needs_comma = 0;
- XMLRPC_VALUE current = XMLRPC_VectorRewind(value);
- while(current && (LLIOPipe::STATUS_OK == status))
- {
- if(needs_comma++) ostr << ",";
- name.assign(XMLRPC_GetValueID(current));
- ostr << "'" << LLSDNotationFormatter::escapeString(name) << "':";
- status = stream_out(ostr, current);
- current = XMLRPC_VectorNext(value);
- }
- ostr << "}";
- break;
- }
- case xmlrpc_type_empty:
- case xmlrpc_type_none:
- default:
- status = LLIOPipe::STATUS_ERROR;
- LL_WARNS() << "Found an empty xmlrpc type.." << LL_ENDL;
- // not much we can do here...
- break;
- };
- return status;
-}
-
-LLFilterXMLRPCResponse2LLSD::LLFilterXMLRPCResponse2LLSD()
-{
-}
-
-LLFilterXMLRPCResponse2LLSD::~LLFilterXMLRPCResponse2LLSD()
-{
-}
-
-LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_PROFILE_ZONE_SCOPED;
-
- PUMP_DEBUG;
- if(!eos) return STATUS_BREAK;
- if(!buffer) return STATUS_ERROR;
-
- PUMP_DEBUG;
- // *FIX: This technique for reading data is far from optimal. We
- // need to have some kind of istream interface into the xml
- // parser...
- S32 bytes = buffer->countAfter(channels.in(), NULL);
- if(!bytes) return STATUS_ERROR;
- char* buf = new char[bytes + 1];
- buf[bytes] = '\0';
- buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes);
-
- //LL_DEBUGS() << "xmlrpc response: " << buf << LL_ENDL;
-
- PUMP_DEBUG;
- XMLRPC_REQUEST response = XMLRPC_REQUEST_FromXML(
- buf,
- bytes,
- NULL);
- if(!response)
- {
- LL_WARNS() << "XML -> SD Response unable to parse xml." << LL_ENDL;
- delete[] buf;
- return STATUS_ERROR;
- }
-
- PUMP_DEBUG;
- LLBufferStream stream(channels, buffer.get());
- stream.precision(DEFAULT_PRECISION);
- if(XMLRPC_ResponseIsFault(response))
- {
- PUMP_DEBUG;
- stream << LLSDRPC_FAULT_HADER_1
- << XMLRPC_GetResponseFaultCode(response)
- << LLSDRPC_FAULT_HADER_2;
- const char* fault_str = XMLRPC_GetResponseFaultString(response);
- std::string fault_string;
- if(fault_str)
- {
- fault_string.assign(fault_str);
- }
- stream << "'" << LLSDNotationFormatter::escapeString(fault_string)
- << "'" <countAfter(channels.in(), NULL);
- if(!bytes) return STATUS_ERROR;
- char* buf = new char[bytes + 1];
- buf[bytes] = '\0';
- buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes);
-
- //LL_DEBUGS() << "xmlrpc request: " << buf << LL_ENDL;
-
- // Check the value in the buffer. XMLRPC_REQUEST_FromXML will report a error code 4 if
- // values that are less than 0x20 are passed to it, except
- // 0x09: Horizontal tab; 0x0a: New Line; 0x0d: Carriage
- U8* cur_pBuf = (U8*)buf;
- U8 cur_char;
- for (S32 i=0; i SD Request process parse error." << LL_ENDL;
- delete[] buf;
- return STATUS_ERROR;
- }
-
- PUMP_DEBUG;
- LLBufferStream stream(channels, buffer.get());
- stream.precision(DEFAULT_PRECISION);
- const char* name = XMLRPC_RequestGetMethodName(request);
- stream << LLSDRPC_REQUEST_HEADER_1 << (name ? name : "")
- << LLSDRPC_REQUEST_HEADER_2;
- XMLRPC_VALUE param = XMLRPC_RequestGetData(request);
- if(param)
- {
- PUMP_DEBUG;
- S32 size = XMLRPC_VectorSize(param);
- if(size > 1)
- {
- // if there are multiple parameters, stuff the values into
- // an array so that the next step in the chain can read them.
- stream << "[";
- }
- XMLRPC_VALUE current = XMLRPC_VectorRewind(param);
- bool needs_comma = false;
- while(current)
- {
- if(needs_comma)
- {
- stream << ",";
- }
- needs_comma = true;
- stream_out(stream, current);
- current = XMLRPC_VectorNext(param);
- }
- if(size > 1)
- {
- // close the array
- stream << "]";
- }
- }
- stream << LLSDRPC_REQUEST_FOOTER;
- XMLRPC_RequestFree(request, 1);
- delete[] buf;
- PUMP_DEBUG;
- return STATUS_DONE;
-}
-
diff --git a/indra/llmessage/llfiltersd2xmlrpc.h b/indra/llmessage/llfiltersd2xmlrpc.h
deleted file mode 100644
index 55938d3e2b..0000000000
--- a/indra/llmessage/llfiltersd2xmlrpc.h
+++ /dev/null
@@ -1,271 +0,0 @@
-/**
- * @file llfiltersd2xmlrpc.h
- * @author Phoenix
- * @date 2005-04-26
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLFILTERSD2XMLRPC_H
-#define LL_LLFILTERSD2XMLRPC_H
-
-/**
- * These classes implement the necessary pipes for translating between
- * xmlrpc and llsd rpc. The llsd rpcs mechanism was developed as an
- * extensible and easy to parse serialization grammer which maintains
- * a time efficient in-memory representation.
- */
-
-#include
-#include "lliopipe.h"
-
-/**
- * @class LLFilterSD2XMLRPC
- * @brief Filter from serialized LLSD to an XMLRPC method call
- *
- * This clas provides common functionality for the LLFilterSD2XMLRPRC
- * request and response classes.
- */
-class LLFilterSD2XMLRPC : public LLIOPipe
-{
-public:
- LLFilterSD2XMLRPC();
- virtual ~LLFilterSD2XMLRPC();
-
-protected:
- /**
- * @brief helper method
- */
- void streamOut(std::ostream& ostr, const LLSD& sd);
-};
-
-/**
- * @class LLFilterSD2XMLRPCResponse
- * @brief Filter from serialized LLSD to an XMLRPC response
- *
- * This class filters a serialized LLSD object to an xmlrpc
- * repsonse. Since resonses are limited to a single param, the xmlrprc
- * response only serializes it as one object.
- * This class correctly handles normal llsd responses as well as llsd
- * rpc faults.
- *
- * For example, if given:
- * {'response':[ i200, r3.4, {"foo":"bar"} ]}
- * Would generate:
- *
- *
- *
- * 200
- * 3.4
- *
- * foobar
- *
- *
- *
- */
-class LLFilterSD2XMLRPCResponse : public LLFilterSD2XMLRPC
-{
-public:
- // constructor
- LLFilterSD2XMLRPCResponse();
-
- // destructor
- virtual ~LLFilterSD2XMLRPCResponse();
-
- /* @name LLIOPipe virtual implementations
- */
- //@{
-protected:
- /**
- * @brief Process the data in buffer.
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-};
-
-/**
- * @class LLFilterSD2XMLRPCRequest
- * @brief Filter from serialized LLSD to an XMLRPC method call
- *
- * This class will accept any kind of serialized LLSD object, but you
- * probably want to have an array on the outer boundary since this
- * object will interpret each element in the top level LLSD as a
- * parameter into the xmlrpc spec.
- *
- * For example, you would represent 3 params as:
- *
- * {'method'='foo', 'parameter':[i200, r3.4, {"foo":"bar"}]}
- *
- * To generate:
- *
- *
- *
- * 200
- * 3.4
- *
- * foobar
- *
- *
- *
- * This class will accept 2 different kinds of encodings. The first
- * just an array of params as long as you specify the method in the
- * constructor. It will also accept a structured data in the form:
- * {'method':'$method_name', 'parameter':[...] } In the latter form, the
- * encoded 'method' will be used regardless of the construction of the
- * object, and the 'parameter' will be used as parameter to the call.
- */
-class LLFilterSD2XMLRPCRequest : public LLFilterSD2XMLRPC
-{
-public:
- // constructor
- LLFilterSD2XMLRPCRequest();
-
- // constructor
- LLFilterSD2XMLRPCRequest(const char* method);
-
- // destructor
- virtual ~LLFilterSD2XMLRPCRequest();
-
- /* @name LLIOPipe virtual implementations
- */
- //@{
-protected:
- /**
- * @brief Process the data in buffer.
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
-protected:
- // The method name of this request.
- std::string mMethod;
-};
-
-/**
- * @class LLFilterXMLRPCResponse2LLSD
- * @brief Filter from serialized XMLRPC method response to LLSD
- *
- * The xmlrpc spec states that responses can only have one element
- * which can be of any supported type.
- * This takes in xml of the form:
- *
- *
- * ok
- *
- * And processes it into:
- * 'ok'
- *
- */
-class LLFilterXMLRPCResponse2LLSD : public LLIOPipe
-{
-public:
- // constructor
- LLFilterXMLRPCResponse2LLSD();
-
- // destructor
- virtual ~LLFilterXMLRPCResponse2LLSD();
-
- /* @name LLIOPipe virtual implementations
- */
- //@{
-protected:
- /**
- * @brief Process the data in buffer.
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
-protected:
-};
-
-/**
- * @class LLFilterXMLRPCRequest2LLSD
- * @brief Filter from serialized XMLRPC method call to LLSD
- *
- * This takes in xml of the form:
- *
- *
- * repeat
- *
- * 4
- * ok
- *
- *
- * And processes it into:
- * { 'method':'repeat', 'params':[i4, 'ok'] }
- */
-class LLFilterXMLRPCRequest2LLSD : public LLIOPipe
-{
-public:
- // constructor
- LLFilterXMLRPCRequest2LLSD();
-
- // destructor
- virtual ~LLFilterXMLRPCRequest2LLSD();
-
- /* @name LLIOPipe virtual implementations
- */
- //@{
-protected:
- /**
- * @brief Process the data in buffer.
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
-protected:
-};
-
-/**
- * @brief This function takes string, and escapes it appropritately
- * for inclusion as xml data.
- */
-std::string xml_escape_string(const std::string& in);
-
-/**
- * @brief Externally available constants
- */
-extern const char LLSDRPC_REQUEST_HEADER_1[];
-extern const char LLSDRPC_REQUEST_HEADER_2[];
-extern const char LLSDRPC_REQUEST_FOOTER[];
-
-#endif // LL_LLFILTERSD2XMLRPC_H
diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp
index 682bbf698a..87e7400a24 100644
--- a/indra/llrender/llgltexture.cpp
+++ b/indra/llrender/llgltexture.cpp
@@ -354,20 +354,6 @@ void LLGLTexture::forceUpdateBindStats(void) const
return mGLTexturep->forceUpdateBindStats() ;
}
-U32 LLGLTexture::getTexelsInAtlas() const
-{
- llassert(mGLTexturep.notNull()) ;
-
- return mGLTexturep->getTexelsInAtlas() ;
-}
-
-U32 LLGLTexture::getTexelsInGLTexture() const
-{
- llassert(mGLTexturep.notNull()) ;
-
- return mGLTexturep->getTexelsInGLTexture() ;
-}
-
bool LLGLTexture::isGLTextureCreated() const
{
llassert(mGLTexturep.notNull()) ;
@@ -375,13 +361,6 @@ bool LLGLTexture::isGLTextureCreated() const
return mGLTexturep->isGLTextureCreated() ;
}
-S32 LLGLTexture::getDiscardLevelInAtlas() const
-{
- llassert(mGLTexturep.notNull()) ;
-
- return mGLTexturep->getDiscardLevelInAtlas() ;
-}
-
void LLGLTexture::destroyGLTexture()
{
if(mGLTexturep.notNull() && mGLTexturep->getHasGLTexture())
diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h
index f63f529ba8..46c314a00d 100644
--- a/indra/llrender/llgltexture.h
+++ b/indra/llrender/llgltexture.h
@@ -51,10 +51,10 @@ public:
BOOST_NONE = 0,
BOOST_AVATAR ,
BOOST_AVATAR_BAKED ,
- BOOST_SCULPTED ,
BOOST_TERRAIN , // Needed for minimap generation for now. Lower than BOOST_HIGH so the texture stats don't get forced, i.e. texture stats are manually managed by minimap/terrain instead.
BOOST_HIGH = 10,
+ BOOST_SCULPTED ,
BOOST_BUMP ,
BOOST_UNUSED_1 , // Placeholder to avoid disrupting habits around texture debug
BOOST_SELECTED ,
@@ -75,7 +75,6 @@ public:
AVATAR_SCRATCH_TEX,
DYNAMIC_TEX,
MEDIA,
- ATLAS,
OTHER,
MAX_GL_IMAGE_CATEGORY
};
@@ -159,10 +158,7 @@ public:
bool isJustBound()const ;
void forceUpdateBindStats(void) const;
- U32 getTexelsInAtlas() const ;
- U32 getTexelsInGLTexture() const ;
bool isGLTextureCreated() const ;
- S32 getDiscardLevelInAtlas() const ;
LLGLTextureState getTextureState() const { return mTextureState; }
//---------------------------------------------------------------------------------------------
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index afe9c90aaf..bbe69da6a0 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -41,6 +41,7 @@
#include "llrender.h"
#include "llwindow.h"
#include "llframetimer.h"
+#include
extern LL_COMMON_API bool on_main_thread();
@@ -130,10 +131,9 @@ S32 LLImageGL::sCount = 0;
bool LLImageGL::sGlobalUseAnisotropic = false;
F32 LLImageGL::sLastFrameTime = 0.f;
-bool LLImageGL::sAllowReadBackRaw = false ;
LLImageGL* LLImageGL::sDefaultGLTexture = NULL ;
bool LLImageGL::sCompressTextures = false;
-std::set LLImageGL::sImageList;
+std::unordered_set LLImageGL::sImageList;
bool LLImageGLThread::sEnabledTextures = false;
@@ -150,6 +150,9 @@ S32 LLImageGL::sMaxCategories = 1 ;
//optimization for when we don't need to calculate mIsMask
bool LLImageGL::sSkipAnalyzeAlpha;
+U32 LLImageGL::sScratchPBO = 0;
+U32 LLImageGL::sScratchPBOSize = 0;
+
//------------------------
//****************************************************************************************************
@@ -159,20 +162,6 @@ bool LLImageGL::sSkipAnalyzeAlpha;
//**************************************************************************************
//below are functions for debug use
//do not delete them even though they are not currently being used.
-void check_all_images()
-{
- for (std::set::iterator iter = LLImageGL::sImageList.begin();
- iter != LLImageGL::sImageList.end(); iter++)
- {
- LLImageGL* glimage = *iter;
- if (glimage->getTexName() && glimage->isGLTextureCreated())
- {
- gGL.getTexUnit(0)->bind(glimage) ;
- glimage->checkTexSize() ;
- gGL.getTexUnit(0)->unbind(glimage->getTarget()) ;
- }
- }
-}
void LLImageGL::checkTexSize(bool forced) const
{
@@ -252,6 +241,11 @@ void LLImageGL::initClass(LLWindow* window, S32 num_catagories, bool skip_analyz
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
sSkipAnalyzeAlpha = skip_analyze_alpha;
+ if (sScratchPBO == 0)
+ {
+ glGenBuffers(1, &sScratchPBO);
+ }
+
if (thread_texture_loads || thread_media_updates)
{
LLImageGLThread::createInstance(window);
@@ -265,6 +259,12 @@ void LLImageGL::cleanupClass()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
LLImageGLThread::deleteSingleton();
+ if (sScratchPBO != 0)
+ {
+ glDeleteBuffers(1, &sScratchPBO);
+ sScratchPBO = 0;
+ sScratchPBOSize = 0;
+ }
}
@@ -360,66 +360,19 @@ void LLImageGL::updateStats(F32 current_time)
//----------------------------------------------------------------------------
//static
-void LLImageGL::destroyGL(bool save_state)
+void LLImageGL::destroyGL()
{
for (S32 stage = 0; stage < gGLManager.mNumTextureImageUnits; stage++)
{
gGL.getTexUnit(stage)->unbind(LLTexUnit::TT_TEXTURE);
}
-
- sAllowReadBackRaw = true ;
- for (std::set::iterator iter = sImageList.begin();
- iter != sImageList.end(); iter++)
- {
- LLImageGL* glimage = *iter;
- if (glimage->mTexName)
- {
- if (save_state && glimage->isGLTextureCreated() && glimage->mComponents)
- {
- glimage->mSaveData = new LLImageRaw;
- if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) //necessary, keep it.
- {
- glimage->mSaveData = NULL ;
- }
- }
-
- glimage->destroyGLTexture();
- stop_glerror();
- }
- }
- sAllowReadBackRaw = false ;
-}
-
-//static
-void LLImageGL::restoreGL()
-{
- for (std::set::iterator iter = sImageList.begin();
- iter != sImageList.end(); iter++)
- {
- LLImageGL* glimage = *iter;
- if(glimage->getTexName())
- {
- LL_ERRS() << "tex name is not 0." << LL_ENDL ;
- }
- if (glimage->mSaveData.notNull())
- {
- if (glimage->getComponents() && glimage->mSaveData->getComponents())
- {
- glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData, 0, true, glimage->getCategory());
- stop_glerror();
- }
- glimage->mSaveData = NULL; // deletes data
- }
- }
}
//static
void LLImageGL::dirtyTexOptions()
{
- for (std::set::iterator iter = sImageList.begin();
- iter != sImageList.end(); iter++)
+ for (auto& glimage : sImageList)
{
- LLImageGL* glimage = *iter;
glimage->mTexOptionsDirty = true;
stop_glerror();
}
@@ -542,10 +495,6 @@ void LLImageGL::init(bool usemipmaps)
mHeight = 0;
mCurrentDiscardLevel = -1;
- mDiscardLevelInAtlas = -1 ;
- mTexelsInAtlas = 0 ;
- mTexelsInGLTexture = 0 ;
-
mAllowCompression = true;
mTarget = GL_TEXTURE_2D;
@@ -622,9 +571,6 @@ bool LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve
return false;
}
- // pickmask validity depends on old image size, delete it
- freePickMask();
-
mWidth = width;
mHeight = height;
mComponents = ncomponents;
@@ -1025,98 +971,6 @@ bool LLImageGL::setImage(const U8* data_in, bool data_hasmips /* = false */, S32
return true;
}
-bool LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image)
-{
- //not compatible with core GL profile
- llassert(!LLRender::sGLCoreProfile);
-
- if (gGLManager.mIsDisabled)
- {
- LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL;
- return false;
- }
- llassert(gGLManager.mInited);
- stop_glerror();
-
- if (discard_level < 0)
- {
- llassert(mCurrentDiscardLevel >= 0);
- discard_level = mCurrentDiscardLevel;
- }
-
- // Actual image width/height = raw image width/height * 2^discard_level
- S32 w = raw_image->getWidth() << discard_level;
- S32 h = raw_image->getHeight() << discard_level;
-
- // setSize may call destroyGLTexture if the size does not match
- if (!setSize(w, h, raw_image->getComponents(), discard_level))
- {
- LL_WARNS() << "Trying to create a texture with incorrect dimensions!" << LL_ENDL;
- return false;
- }
-
- if (!mHasExplicitFormat)
- {
- switch (mComponents)
- {
- case 1:
- // Use luminance alpha (for fonts)
- mFormatInternal = GL_LUMINANCE8;
- mFormatPrimary = GL_LUMINANCE;
- mFormatType = GL_UNSIGNED_BYTE;
- break;
- case 2:
- // Use luminance alpha (for fonts)
- mFormatInternal = GL_LUMINANCE8_ALPHA8;
- mFormatPrimary = GL_LUMINANCE_ALPHA;
- mFormatType = GL_UNSIGNED_BYTE;
- break;
- case 3:
- mFormatInternal = GL_RGB8;
- mFormatPrimary = GL_RGB;
- mFormatType = GL_UNSIGNED_BYTE;
- break;
- case 4:
- mFormatInternal = GL_RGBA8;
- mFormatPrimary = GL_RGBA;
- mFormatType = GL_UNSIGNED_BYTE;
- break;
- default:
- LL_ERRS() << "Bad number of components for texture: " << (U32) getComponents() << LL_ENDL;
- }
- }
-
- mCurrentDiscardLevel = discard_level;
- mDiscardLevelInAtlas = discard_level;
- mTexelsInAtlas = raw_image->getWidth() * raw_image->getHeight() ;
- mLastBindTime = sLastFrameTime;
- mGLTextureCreated = false ;
-
- glPixelStorei(GL_UNPACK_ROW_LENGTH, raw_image->getWidth());
- stop_glerror();
-
- if(mFormatSwapBytes)
- {
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
- stop_glerror();
- }
-
- return true ;
-}
-
-void LLImageGL::postAddToAtlas()
-{
- if(mFormatSwapBytes)
- {
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
- stop_glerror();
- }
-
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
- gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption);
- stop_glerror();
-}
-
U32 type_width_from_pixtype(U32 pixtype)
{
U32 type_width = 0;
@@ -1752,7 +1606,6 @@ bool LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, bool data_
mTextureMemory = (S64Bytes)getMipBytes(mCurrentDiscardLevel);
- mTexelsInGLTexture = getWidth() * getHeight();
// mark this as bound at this point, so we don't throw it out immediately
mLastBindTime = sLastFrameTime;
@@ -1830,8 +1683,7 @@ void LLImageGL::syncTexName(LLGLuint texname)
bool LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const
{
- llassert_always(sAllowReadBackRaw) ;
- //LL_ERRS() << "should not call this function!" << LL_ENDL ;
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
if (discard_level < 0)
{
@@ -2297,6 +2149,8 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
//----------------------------------------------------------------------------
U32 LLImageGL::createPickMask(S32 pWidth, S32 pHeight)
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+ freePickMask();
U32 pick_width = pWidth/2 + 1;
U32 pick_height = pHeight/2 + 1;
@@ -2314,7 +2168,6 @@ U32 LLImageGL::createPickMask(S32 pWidth, S32 pHeight)
//----------------------------------------------------------------------------
void LLImageGL::freePickMask()
{
- // pickmask validity depends on old image size, delete it
if (mPickMask != NULL)
{
delete [] mPickMask;
@@ -2352,16 +2205,16 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in)
return ;
}
- freePickMask();
-
if (mFormatType != GL_UNSIGNED_BYTE ||
((mFormatPrimary != GL_RGBA)
&& (mFormatPrimary != GL_SRGB_ALPHA)))
{
//cannot generate a pick mask for this texture
+ freePickMask();
return;
}
+
#ifdef SHOW_ASSERT
const U32 pickSize = createPickMask(width, height);
#else // SHOW_ASSERT
@@ -2463,6 +2316,73 @@ void LLImageGL::resetCurTexSizebar()
sCurTexSizeBar = -1 ;
sCurTexPickSize = -1 ;
}
+
+bool LLImageGL::scaleDown(S32 desired_discard)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+
+ if (mTarget != GL_TEXTURE_2D)
+ {
+ return false;
+ }
+
+ desired_discard = llmin(desired_discard, mMaxDiscardLevel);
+
+ if (desired_discard <= mCurrentDiscardLevel)
+ {
+ return false;
+ }
+
+ S32 mip = desired_discard - mCurrentDiscardLevel;
+
+ S32 desired_width = getWidth(desired_discard);
+ S32 desired_height = getHeight(desired_discard);
+
+ U64 size = getBytes(desired_discard);
+ llassert(size <= 2048*2048*4); // we shouldn't be using this method to downscale huge textures, but it'll work
+ gGL.getTexUnit(0)->bind(this);
+
+
+ if (sScratchPBO == 0)
+ {
+ glGenBuffers(1, &sScratchPBO);
+ sScratchPBOSize = 0;
+ }
+
+ glBindBuffer(GL_PIXEL_PACK_BUFFER, sScratchPBO);
+
+ if (size > sScratchPBOSize)
+ {
+ glBufferData(GL_PIXEL_PACK_BUFFER, size, NULL, GL_STREAM_COPY);
+ sScratchPBOSize = size;
+ }
+
+ glGetTexImage(mTarget, mip, mFormatPrimary, mFormatType, nullptr);
+
+ free_tex_image(mTexName);
+
+ glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
+
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, sScratchPBO);
+ glTexImage2D(mTarget, 0, mFormatPrimary, desired_width, desired_height, 0, mFormatPrimary, mFormatType, nullptr);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ alloc_tex_image(desired_width, desired_height, mFormatPrimary);
+
+ if (mHasMipMaps)
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glGenerateMipmap");
+ glGenerateMipmap(mTarget);
+ }
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ mCurrentDiscardLevel = desired_discard;
+
+ return true;
+}
+
+
//----------------------------------------------------------------------------
#if LL_IMAGEGL_THREAD_CHECK
void LLImageGL::checkActiveThread()
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 52eec54465..58b7d514e4 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -39,6 +39,7 @@
#include "llrender.h"
#include "threadpool.h"
#include "workqueue.h"
+#include
#define LL_IMAGEGL_THREAD_CHECK 0 //set to 1 to enable thread debugging for ImageGL
@@ -83,9 +84,8 @@ public:
// needs to be called every frame
static void updateStats(F32 current_time);
- // Save off / restore GL textures
- static void destroyGL(bool save_state = true);
- static void restoreGL();
+ // cleanup GL state
+ static void destroyGL();
static void dirtyTexOptions();
static bool checkSize(S32 width, S32 height);
@@ -148,6 +148,10 @@ public:
S32 getDiscardLevel() const { return mCurrentDiscardLevel; }
S32 getMaxDiscardLevel() const { return mMaxDiscardLevel; }
+ // override the current discard level
+ // should only be used for local textures where you know exactly what you're doing
+ void setDiscardLevel(S32 level) { mCurrentDiscardLevel = level; }
+
S32 getCurrentWidth() const { return mWidth ;}
S32 getCurrentHeight() const { return mHeight ;}
S32 getWidth(S32 discard_level = -1) const;
@@ -197,26 +201,26 @@ public:
void setFilteringOption(LLTexUnit::eTextureFilterOptions option);
LLTexUnit::eTextureFilterOptions getFilteringOption(void) const { return mFilterOption; }
- LLGLenum getTexTarget()const { return mTarget ;}
- S8 getDiscardLevelInAtlas()const {return mDiscardLevelInAtlas;}
- U32 getTexelsInAtlas()const { return mTexelsInAtlas ;}
- U32 getTexelsInGLTexture()const {return mTexelsInGLTexture;}
-
+ LLGLenum getTexTarget()const { return mTarget; }
void init(bool usemipmaps);
virtual void cleanup(); // Clean up the LLImageGL so it can be reinitialized. Be careful when using this in derived class destructors
void setNeedsAlphaAndPickMask(bool need_mask);
- bool preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image);
- void postAddToAtlas() ;
-
#if LL_IMAGEGL_THREAD_CHECK
// thread debugging
std::thread::id mActiveThread;
void checkActiveThread();
#endif
+ // scale down to the desired discard level using GPU
+ // returns true if texture was scaled down
+ // desired discard will be clamped to max discard
+ // if desired discard is less than or equal to current discard, no scaling will occur
+ // only works for GL_TEXTURE_2D target
+ bool scaleDown(S32 desired_discard);
+
public:
// Various GL/Rendering options
S64Bytes mTextureMemory;
@@ -243,15 +247,10 @@ private:
bool mGLTextureCreated ;
LLGLuint mTexName;
- //LLGLuint mNewTexName = 0; // tex name set by background thread to be applied in main thread
U16 mWidth;
U16 mHeight;
S8 mCurrentDiscardLevel;
- S8 mDiscardLevelInAtlas;
- U32 mTexelsInAtlas ;
- U32 mTexelsInGLTexture;
-
bool mAllowCompression;
protected:
@@ -278,7 +277,7 @@ protected:
// STATICS
public:
- static std::set sImageList;
+ static std::unordered_set sImageList;
static S32 sCount;
static F32 sLastFrameTime;
@@ -304,6 +303,8 @@ public:
private:
static S32 sMaxCategories;
static bool sSkipAnalyzeAlpha;
+ static U32 sScratchPBO;
+ static U32 sScratchPBOSize;
//the flag to allow to call readBackRaw(...).
//can be removed if we do not use that function at all.
diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp
index 9076f54795..a7167e3330 100644
--- a/indra/llui/llaccordionctrl.cpp
+++ b/indra/llui/llaccordionctrl.cpp
@@ -390,12 +390,10 @@ void LLAccordionCtrl::initNoTabsWidget(const LLTextBox::Params& tb_params)
void LLAccordionCtrl::updateNoTabsHelpTextVisibility()
{
- bool visible_exists = false;
- std::vector::const_iterator it = mAccordionTabs.begin();
- const std::vector::const_iterator it_end = mAccordionTabs.end();
- while (it < it_end)
+ bool visible_exists{ false };
+ for (auto accordion_tab : mAccordionTabs)
{
- if ((*(it++))->getVisible())
+ if (accordion_tab->getVisible())
{
visible_exists = true;
break;
diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp
index 6d58a2545c..ac66525030 100644
--- a/indra/llui/llaccordionctrltab.cpp
+++ b/indra/llui/llaccordionctrltab.cpp
@@ -602,15 +602,13 @@ void LLAccordionCtrlTab::setSelected(bool is_selected)
LLView* LLAccordionCtrlTab::findContainerView()
{
- child_list_const_iter_t it = getChildList()->begin(), it_end = getChildList()->end();
- while (it != it_end)
+ for (auto child : *getChildList())
{
- LLView* child = *(it++);
if (DD_HEADER_NAME != child->getName() && child->getVisible())
return child;
}
- return NULL;
+ return nullptr;
}
void LLAccordionCtrlTab::selectOnFocusReceived()
diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp
index fee05ff218..9ed24f1908 100644
--- a/indra/llui/llflatlistview.cpp
+++ b/indra/llui/llflatlistview.cpp
@@ -1274,17 +1274,15 @@ void LLFlatListView::detachItems(std::vector& detached_items)
detached_items.clear();
// Go through items and detach valid items, remove them from items panel
// and add to detached_items.
- pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end();
- while (iter != iter_end)
+ for (auto item_pair : mItemPairs)
{
- LLPanel* pItem = (*iter)->first;
+ LLPanel* pItem = item_pair->first;
if (1 == pItem->notify(action))
{
- selectItemPair((*iter), false);
+ selectItemPair(item_pair, false);
mItemsPanel->removeChild(pItem);
- detached_items.push_back(pItem);
+ detached_items.emplace_back(pItem);
}
- iter++;
}
if (!detached_items.empty())
{
@@ -1292,12 +1290,10 @@ void LLFlatListView::detachItems(std::vector& detached_items)
if (detached_items.size() == mItemPairs.size())
{
// This way will be faster if all items were disconnected
- pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end();
- while (iter != iter_end)
+ for (auto item_pair : mItemPairs)
{
- (*iter)->first = NULL;
- delete *iter;
- iter++;
+ item_pair->first = nullptr;
+ delete item_pair;
}
mItemPairs.clear();
// Also set items panel height to zero.
@@ -1310,26 +1306,16 @@ void LLFlatListView::detachItems(std::vector& detached_items)
}
else
{
- std::vector::const_iterator
- detached_iter = detached_items.begin(),
- detached_iter_end = detached_items.end();
- while (detached_iter < detached_iter_end)
+ for (auto detached_item : detached_items)
{
- LLPanel* pDetachedItem = *detached_iter;
- pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end();
- while (iter != iter_end)
+ auto found_pos = std::find_if(mItemPairs.begin(), mItemPairs.end(), [detached_item](auto item_pair) { return item_pair->first == detached_item; });
+ if (found_pos != mItemPairs.end())
{
- item_pair_t* item_pair = *iter;
- if (item_pair->first == pDetachedItem)
- {
- mItemPairs.erase(iter);
- item_pair->first = NULL;
- delete item_pair;
- break;
- }
- iter++;
+ mItemPairs.erase(found_pos);
+ auto item_pair = *found_pos;
+ item_pair->first = nullptr;
+ delete item_pair;
}
- detached_iter++;
}
rearrangeItems();
}
@@ -1436,11 +1422,10 @@ void LLFlatListViewEx::filterItems(bool re_sort, bool notify_parent)
action.with("match_filter", cur_filter);
mHasMatchedItems = false;
- bool visibility_changed = false;
- pairs_const_iterator_t iter = getItemPairs().begin(), iter_end = getItemPairs().end();
- while (iter != iter_end)
+ bool visibility_changed{ false };
+ for (auto item_pair : getItemPairs())
{
- LLPanel* pItem = (*(iter++))->first;
+ LLPanel* pItem = item_pair->first;
visibility_changed |= updateItemVisibility(pItem, action);
}
diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp
index 92a2827d73..6dc632aba4 100644
--- a/indra/llwebrtc/llwebrtc.cpp
+++ b/indra/llwebrtc/llwebrtc.cpp
@@ -35,6 +35,7 @@
#include "api/media_stream_interface.h"
#include "api/media_stream_track.h"
#include "modules/audio_processing/audio_buffer.h"
+#include "modules/audio_mixer/audio_mixer_impl.h"
namespace llwebrtc
{
@@ -88,7 +89,7 @@ void LLAudioDeviceObserver::OnRenderData(const void *audio_samples,
{
}
-LLCustomProcessor::LLCustomProcessor() : mSampleRateHz(0), mNumChannels(0), mMicrophoneEnergy(0.0)
+LLCustomProcessor::LLCustomProcessor() : mSampleRateHz(0), mNumChannels(0), mMicrophoneEnergy(0.0), mGain(1.0)
{
memset(mSumVector, 0, sizeof(mSumVector));
}
@@ -128,9 +129,13 @@ void LLCustomProcessor::Process(webrtc::AudioBuffer *audio_in)
for (size_t index = 0; index < stream_config.num_samples(); index++)
{
float sample = frame_samples[index];
+ sample = sample * mGain; // apply gain
+ frame_samples[index] = sample; // write processed sample back to buffer.
energy += sample * sample;
}
+ audio_in->CopyFrom(&frame[0], stream_config);
+
// smooth it.
size_t buffer_size = sizeof(mSumVector) / sizeof(mSumVector[0]);
float totalSum = 0;
@@ -236,9 +241,9 @@ void LLWebRTCImpl::init()
webrtc::AudioProcessing::Config apm_config;
apm_config.echo_canceller.enabled = false;
apm_config.echo_canceller.mobile_mode = false;
- apm_config.gain_controller1.enabled = true;
+ apm_config.gain_controller1.enabled = false;
apm_config.gain_controller1.mode = webrtc::AudioProcessing::Config::GainController1::kAdaptiveAnalog;
- apm_config.gain_controller2.enabled = true;
+ apm_config.gain_controller2.enabled = false;
apm_config.high_pass_filter.enabled = true;
apm_config.noise_suppression.enabled = true;
apm_config.noise_suppression.level = webrtc::AudioProcessing::Config::NoiseSuppression::kVeryHigh;
@@ -260,6 +265,7 @@ void LLWebRTCImpl::init()
mAudioProcessingModule->ApplyConfig(apm_config);
mAudioProcessingModule->Initialize(processing_config);
+
mPeerConnectionFactory = webrtc::CreatePeerConnectionFactory(mNetworkThread.get(),
mWorkerThread.get(),
mSignalingThread.get(),
@@ -336,9 +342,9 @@ void LLWebRTCImpl::setAudioConfig(LLWebRTCDeviceInterface::AudioConfig config)
webrtc::AudioProcessing::Config apm_config;
apm_config.echo_canceller.enabled = config.mEchoCancellation;
apm_config.echo_canceller.mobile_mode = false;
- apm_config.gain_controller1.enabled = true;
+ apm_config.gain_controller1.enabled = config.mAGC;
apm_config.gain_controller1.mode = webrtc::AudioProcessing::Config::GainController1::kAdaptiveAnalog;
- apm_config.gain_controller2.enabled = true;
+ apm_config.gain_controller2.enabled = false;
apm_config.high_pass_filter.enabled = true;
apm_config.transient_suppression.enabled = true;
apm_config.pipeline.multi_channel_render = true;
@@ -612,6 +618,8 @@ float LLWebRTCImpl::getTuningAudioLevel() { return -20 * log10f(mTuningAudioDevi
float LLWebRTCImpl::getPeerConnectionAudioLevel() { return -20 * log10f(mPeerCustomProcessor->getMicrophoneEnergy()); }
+void LLWebRTCImpl::setPeerConnectionGain(float gain) { mPeerCustomProcessor->setGain(gain); }
+
//
// Peer Connection Helpers
@@ -937,7 +945,7 @@ void LLWebRTCPeerConnectionImpl::setSendVolume(float volume)
{
for (auto &track : mLocalStream->GetAudioTracks())
{
- track->GetSource()->SetVolume(volume);
+ track->GetSource()->SetVolume(volume*5.0);
}
}
});
diff --git a/indra/llwebrtc/llwebrtc.h b/indra/llwebrtc/llwebrtc.h
index b0b47bacc1..54eefc8554 100644
--- a/indra/llwebrtc/llwebrtc.h
+++ b/indra/llwebrtc/llwebrtc.h
@@ -145,6 +145,7 @@ class LLWebRTCDeviceInterface
virtual void setTuningMode(bool enable) = 0;
virtual float getTuningAudioLevel() = 0; // for use during tuning
virtual float getPeerConnectionAudioLevel() = 0; // for use when not tuning
+ virtual void setPeerConnectionGain(float gain) = 0;
};
// LLWebRTCAudioInterface provides the viewer with a way
diff --git a/indra/llwebrtc/llwebrtc_impl.h b/indra/llwebrtc/llwebrtc_impl.h
index cb54e83a63..2fb5525519 100644
--- a/indra/llwebrtc/llwebrtc_impl.h
+++ b/indra/llwebrtc/llwebrtc_impl.h
@@ -121,6 +121,8 @@ class LLCustomProcessor : public webrtc::CustomProcessing
float getMicrophoneEnergy() { return mMicrophoneEnergy; }
+ void setGain(float gain) { mGain = gain; }
+
protected:
static const int NUM_PACKETS_TO_FILTER = 30; // 300 ms of smoothing
int mSampleRateHz;
@@ -128,6 +130,7 @@ class LLCustomProcessor : public webrtc::CustomProcessing
float mSumVector[NUM_PACKETS_TO_FILTER];
float mMicrophoneEnergy;
+ float mGain;
};
@@ -160,6 +163,8 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceS
float getTuningAudioLevel() override;
float getPeerConnectionAudioLevel() override;
+ void setPeerConnectionGain(float gain) override;
+
//
// AudioDeviceSink
//
diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp
index 49d5e89c47..8a5586ec23 100644
--- a/indra/llxml/llxmlnode.cpp
+++ b/indra/llxml/llxmlnode.cpp
@@ -653,32 +653,24 @@ bool LLXMLNode::updateNode(
// static
bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree)
{
- // Read file
- LL_DEBUGS("XMLNode") << "parsing XML file: " << filename << LL_ENDL;
- LLFILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */
- if (fp == NULL)
+ std::string xml = LLFile::getContents(filename);
+ if (xml.empty())
{
- node = NULL ;
- return false;
+ LL_WARNS("XMLNode") << "no XML file: " << filename << LL_ENDL;
+ }
+ else if (parseBuffer(xml.data(), xml.size(), node, defaults_tree))
+ {
+ return true;
}
- fseek(fp, 0, SEEK_END);
- U32 length = ftell(fp);
- fseek(fp, 0, SEEK_SET);
- U8* buffer = new U8[length+1];
- size_t nread = fread(buffer, 1, length, fp);
- buffer[nread] = 0;
- fclose(fp);
-
- bool rv = parseBuffer(buffer, static_cast(nread), node, defaults_tree);
- delete [] buffer;
- return rv;
+ node = nullptr;
+ return false;
}
// static
bool LLXMLNode::parseBuffer(
- U8* buffer,
- U32 length,
+ const char* buffer,
+ U64 length,
LLXMLNodePtr& node,
LLXMLNode* defaults)
{
@@ -693,10 +685,11 @@ bool LLXMLNode::parseBuffer(
file_node->mParser = &my_parser;
- XML_SetUserData(my_parser, (void *)file_node_ptr);
+ XML_SetUserData(my_parser, file_node_ptr);
// Do the parsing
- if (XML_Parse(my_parser, (const char *)buffer, length, true) != XML_STATUS_OK)
+ bool success = XML_STATUS_OK == XML_Parse(my_parser, buffer, (int)length, true);
+ if (!success)
{
#ifdef LL_RELEASE_WITH_DEBUG_INFO
LL_ERRS() << "";
@@ -708,12 +701,16 @@ bool LLXMLNode::parseBuffer(
LL_CONT<< "Error parsing xml error code: "
<< XML_ErrorString(XML_GetErrorCode(my_parser))
<< " on line " << XML_GetCurrentLineNumber(my_parser)
+ << ", column " << XML_GetCurrentColumnNumber(my_parser)
<< LL_ENDL;
}
// Deinit
XML_ParserFree(my_parser);
+ if (!success)
+ return false;
+
if (!file_node->mChildren || file_node->mChildren->map.size() != 1)
{
LL_WARNS() << "Parse failure - wrong number of top-level nodes xml."
diff --git a/indra/llxml/llxmlnode.h b/indra/llxml/llxmlnode.h
index b8e29bbfef..b8f9e1ff69 100644
--- a/indra/llxml/llxmlnode.h
+++ b/indra/llxml/llxmlnode.h
@@ -129,20 +129,20 @@ public:
void addChild(LLXMLNodePtr& new_child);
void setParent(LLXMLNodePtr& new_parent); // reparent if necessary
- // Serialization
+ // Deserialization
static bool parseFile(
const std::string& filename,
LLXMLNodePtr& node,
- LLXMLNode* defaults_tree);
+ LLXMLNode* defaults = nullptr);
static bool parseBuffer(
- U8* buffer,
- U32 length,
+ const char* buffer,
+ U64 length,
LLXMLNodePtr& node,
- LLXMLNode* defaults);
+ LLXMLNode* defaults = nullptr);
static bool parseStream(
std::istream& str,
LLXMLNodePtr& node,
- LLXMLNode* defaults);
+ LLXMLNode* defaults = nullptr);
static bool updateNode(
LLXMLNodePtr& node,
LLXMLNodePtr& update_node);
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index f7c605e921..56819614a7 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -331,6 +331,7 @@ set(viewer_SOURCE_FILES
llfloaterfonttest.cpp
llfloaterforgetuser.cpp
llfloatergesture.cpp
+ llfloatergltfasseteditor.cpp
llfloatergodtools.cpp
llfloatergotoline.cpp
llfloatergridstatus.cpp
@@ -429,6 +430,8 @@ set(viewer_SOURCE_FILES
llgesturemgr.cpp
llgiveinventory.cpp
llglsandbox.cpp
+ llgltffolderitem.cpp
+ llgltffoldermodel.cpp
llgltfmateriallist.cpp
llgltfmaterialpreviewmgr.cpp
llgroupactions.cpp
@@ -1133,6 +1136,7 @@ set(viewer_HEADER_FILES
llfloaterfonttest.h
llfloaterforgetuser.h
llfloatergesture.h
+ llfloatergltfasseteditor.h
llfloatergodtools.h
llfloatergotoline.h
llfloatergridstatus.h
@@ -1233,6 +1237,8 @@ set(viewer_HEADER_FILES
llgesturelistener.h
llgesturemgr.h
llgiveinventory.h
+ llgltffolderitem.h
+ llgltffoldermodel.h
llgltfmateriallist.h
llgltfmaterialpreviewmgr.h
llgroupactions.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 219901ae78..f960f6100c 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -11129,6 +11129,28 @@ Change of this parameter will affect the layout of buttons in notification toast
Value
0
+ RenderMinFreeMainMemoryThreshold
+
+ Comment
+ Minimum of available physical memory in MB before textures get scaled down
+ Persist
+ 1
+ Type
+ U32
+ Value
+ 512
+
+ RenderLowMemMinDiscardIncrement
+
+ Comment
+ Minimum increment of discard level if system memory gets low
+ Persist
+ 1
+ Type
+ F32
+ Value
+ 0.1
+
RenderMaxTextureIndex
Comment
@@ -17355,7 +17377,7 @@ Change of this parameter will affect the layout of buttons in notification toast
Type
Boolean
Value
- 1
+ 0
AutoDisengageMic
@@ -25741,16 +25763,5 @@ Change of this parameter will affect the layout of buttons in notification toast
Value
1
- FSMinFreeMainMemoryTextureDiscardThreshold
-
- Comment
- Minimum of available physical memory in MB before textures get scaled down
- Persist
- 1
- Type
- S32
- Value
- 512
-
diff --git a/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl b/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl
index 902746366d..6d05d983f3 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl
@@ -25,24 +25,53 @@
/*[EXTRA_CODE_HERE]*/
+
+
+// generate a normal map using an approximation of the old emboss bump map "brightness/darkness" technique
+// srcMap is a source color image, output should be a normal
+
out vec4 frag_color;
-uniform sampler2D alphaMap;
+uniform sampler2D srcMap;
in vec2 vary_texcoord0;
uniform float stepX;
uniform float stepY;
uniform float norm_scale;
+uniform int bump_code;
+
+#define BE_BRIGHTNESS 1
+#define BE_DARKNESS 2
+
+// get luminance or inverse luminance depending on bump_code
+float getBumpValue(vec2 texcoord)
+{
+ vec3 c = texture(srcMap, texcoord).rgb;
+
+ vec3 WEIGHT = vec3(0.2995, 0.5875, 0.1145);
+
+ float l = dot(c, WEIGHT);
+
+ if (bump_code == BE_DARKNESS)
+ {
+ l = 1.0 - l;
+ }
+
+ return l;
+}
+
void main()
{
- float c = texture(alphaMap, vary_texcoord0).r;
+ float c = getBumpValue(vary_texcoord0).r;
- vec3 right = vec3(norm_scale, 0, (texture(alphaMap, vary_texcoord0+vec2(stepX, 0)).r-c)*255);
- vec3 left = vec3(-norm_scale, 0, (texture(alphaMap, vary_texcoord0-vec2(stepX, 0)).r-c)*255);
- vec3 up = vec3(0, -norm_scale, (texture(alphaMap, vary_texcoord0-vec2(0, stepY)).r-c)*255);
- vec3 down = vec3(0, norm_scale, (texture(alphaMap, vary_texcoord0+vec2(0, stepY)).r-c)*255);
+ float scaler = 512.0;
+
+ vec3 right = vec3(norm_scale, 0, (getBumpValue(vary_texcoord0+vec2(stepX, 0)).r-c)*scaler);
+ vec3 left = vec3(-norm_scale, 0, (getBumpValue(vary_texcoord0-vec2(stepX, 0)).r-c)*scaler);
+ vec3 up = vec3(0, -norm_scale, (getBumpValue(vary_texcoord0-vec2(0, stepY)).r-c)*scaler);
+ vec3 down = vec3(0, norm_scale, (getBumpValue(vary_texcoord0+vec2(0, stepY)).r-c)*scaler);
vec3 norm = cross(right, down) + cross(down, left) + cross(left,up) + cross(up, right);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl
index ae179d3f37..66adf50fa9 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl
@@ -69,7 +69,7 @@ flat out float vary_sign;
out vec3 vary_normal;
vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
-vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
+vec4 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
void main()
@@ -103,8 +103,9 @@ void main()
n = normalize(n);
- vary_tangent = normalize(tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0));
- vary_sign = tangent.w;
+ vec4 transformed_tangent = tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0);
+ vary_tangent = normalize(transformed_tangent.xyz);
+ vary_sign = transformed_tangent.w;
vary_normal = n;
vertex_color = diffuse_color;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl
index fd020afd57..0ad9bf5e4b 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl
@@ -63,7 +63,7 @@ out vec3 vary_normal;
out vec3 vary_position;
vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
-vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
+vec4 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
void main()
{
@@ -97,8 +97,9 @@ void main()
n = normalize(n);
- vary_tangent = normalize(tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0));
- vary_sign = tangent.w;
+ vec4 transformed_tangent = tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0);
+ vary_tangent = normalize(transformed_tangent.xyz);
+ vary_sign = transformed_tangent.w;
vary_normal = n;
vertex_color = diffuse_color;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl
index 2cb7ff196b..6ca35419f2 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl
@@ -75,6 +75,9 @@ PBRMix terrain_sample_and_multiply_pbr(
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, sampler2D tex_vNt
+#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
+ , float transform_sign
+#endif
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, sampler2D tex_emissive
@@ -139,7 +142,7 @@ in vec3 vary_position;
in vec3 vary_normal;
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
in vec3 vary_tangents[4];
-flat in float vary_sign;
+flat in float vary_signs[4];
#endif
in vec4 vary_texcoord0;
in vec4 vary_texcoord1;
@@ -150,11 +153,11 @@ float terrain_mix(TerrainMix tm, vec4 tms4);
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
// from mikktspace.com
-vec3 mikktspace(vec3 vNt, vec3 vT)
+vec3 mikktspace(vec3 vNt, vec3 vT, float sign)
{
vec3 vN = vary_normal;
- vec3 vB = vary_sign * cross(vN, vT);
+ vec3 vB = sign * cross(vN, vT);
vec3 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
tnorm *= gl_FrontFacing ? 1.0 : -1.0;
@@ -216,6 +219,9 @@ void main()
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, detail_0_normal
+#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
+ , vary_signs[0]
+#endif
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, detail_0_emissive
@@ -231,7 +237,7 @@ void main()
#endif
);
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
- mix2.vNt = mikktspace(mix2.vNt, vary_tangents[0]);
+ mix2.vNt = mikktspace(mix2.vNt, vary_tangents[0], vary_signs[0]);
#endif
pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.x);
break;
@@ -258,6 +264,9 @@ void main()
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, detail_1_normal
+#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
+ , vary_signs[1]
+#endif
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, detail_1_emissive
@@ -273,7 +282,7 @@ void main()
#endif
);
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
- mix2.vNt = mikktspace(mix2.vNt, vary_tangents[1]);
+ mix2.vNt = mikktspace(mix2.vNt, vary_tangents[1], vary_signs[1]);
#endif
pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.y);
break;
@@ -300,6 +309,9 @@ void main()
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, detail_2_normal
+#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
+ , vary_signs[2]
+#endif
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, detail_2_emissive
@@ -315,7 +327,7 @@ void main()
#endif
);
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
- mix2.vNt = mikktspace(mix2.vNt, vary_tangents[2]);
+ mix2.vNt = mikktspace(mix2.vNt, vary_tangents[2], vary_signs[2]);
#endif
pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.z);
break;
@@ -342,6 +354,9 @@ void main()
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, detail_3_normal
+#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
+ , vary_signs[3]
+#endif
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, detail_3_emissive
@@ -357,7 +372,7 @@ void main()
#endif
);
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
- mix2.vNt = mikktspace(mix2.vNt, vary_tangents[3]);
+ mix2.vNt = mikktspace(mix2.vNt, vary_tangents[3], vary_signs[3]);
#endif
pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.w);
break;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl
index 1ae9efe544..5098de717e 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl
@@ -256,11 +256,12 @@ vec3 _t_normal_post_1(vec3 vNt0, float sign_or_zero)
}
// Triplanar-specific normal texture fixes
-vec3 _t_normal_post_x(vec3 vNt0)
+vec3 _t_normal_post_x(vec3 vNt0, float tangent_sign)
{
vec3 vNt_x = _t_normal_post_1(vNt0, sign(vary_vertex_normal.x));
// *HACK: Transform normals according to orientation of the UVs
vNt_x.xy = vec2(-vNt_x.y, vNt_x.x);
+ vNt_x.xy *= tangent_sign;
return vNt_x;
}
vec3 _t_normal_post_y(vec3 vNt0)
@@ -285,6 +286,7 @@ PBRMix terrain_sample_pbr(
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, sampler2D tex_vNt
+ , float tangent_sign
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, sampler2D tex_emissive
@@ -314,7 +316,7 @@ PBRMix terrain_sample_pbr(
);
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
// Triplanar-specific normal texture fix
- mix_x.vNt = _t_normal_post_x(mix_x.vNt);
+ mix_x.vNt = _t_normal_post_x(mix_x.vNt, tangent_sign);
#endif
mix = mix_pbr(mix, mix_x, tw.weight.x);
break;
@@ -420,6 +422,9 @@ PBRMix terrain_sample_and_multiply_pbr(
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, sampler2D tex_vNt
+#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
+ , float tangent_sign
+#endif
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, sampler2D tex_emissive
@@ -446,6 +451,9 @@ PBRMix terrain_sample_and_multiply_pbr(
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, tex_vNt
+#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
+ , tangent_sign
+#endif
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, tex_emissive
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl
index f8e826bbdb..c90b2b5926 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl
@@ -43,7 +43,7 @@ out vec3 vary_vertex_normal; // Used by pbrterrainUtilF.glsl
out vec3 vary_normal;
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
out vec3 vary_tangents[4];
-flat out float vary_sign;
+flat out float vary_signs[4];
#endif
out vec4 vary_texcoord0;
out vec4 vary_texcoord1;
@@ -60,7 +60,7 @@ out vec3 vary_position;
uniform vec4[5] terrain_texture_transforms;
vec2 terrain_texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform);
-vec3 terrain_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform);
+vec4 terrain_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform);
void main()
{
@@ -75,28 +75,35 @@ void main()
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
{
vec4[2] ttt;
+ vec4 transformed_tangent;
// material 1
ttt[0].xyz = terrain_texture_transforms[0].xyz;
ttt[1].x = terrain_texture_transforms[0].w;
ttt[1].y = terrain_texture_transforms[1].x;
- vary_tangents[0] = normalize(terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt));
+ transformed_tangent = terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt);
+ vary_tangents[0] = normalize(transformed_tangent.xyz);
+ vary_signs[0] = transformed_tangent.w;
// material 2
ttt[0].xyz = terrain_texture_transforms[1].yzw;
ttt[1].xy = terrain_texture_transforms[2].xy;
- vary_tangents[1] = normalize(terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt));
+ transformed_tangent = terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt);
+ vary_tangents[1] = normalize(transformed_tangent.xyz);
+ vary_signs[1] = transformed_tangent.w;
// material 3
ttt[0].xy = terrain_texture_transforms[2].zw;
ttt[0].z = terrain_texture_transforms[3].x;
ttt[1].xy = terrain_texture_transforms[3].yz;
- vary_tangents[2] = normalize(terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt));
+ transformed_tangent = terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt);
+ vary_tangents[2] = normalize(transformed_tangent.xyz);
+ vary_signs[2] = transformed_tangent.w;
// material 4
ttt[0].x = terrain_texture_transforms[3].w;
ttt[0].yz = terrain_texture_transforms[4].xy;
ttt[1].xy = terrain_texture_transforms[4].zw;
- vary_tangents[3] = normalize(terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt));
+ transformed_tangent = terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt);
+ vary_tangents[3] = normalize(transformed_tangent.xyz);
+ vary_signs[3] = transformed_tangent.w;
}
-
- vary_sign = tangent.w;
#endif
vary_normal = normalize(n);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl b/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl
index 767416d564..c75a0e0d5d 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl
@@ -94,36 +94,48 @@ vec2 terrain_texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform)
// Take the rotation only from both transforms and apply to the tangent. This
// accounts for the change of the topology of the normal texture when a texture
// rotation is applied to it.
+// In practice, this applies the inverse of the texture transform to the tangent.
+// It is effectively an inverse of the rotation
// *HACK: Assume the imported GLTF model did not have both normal texture
// transforms and tangent vertices. The use of this function is inconsistent
// with the GLTF sample viewer when that is the case. See getNormalInfo in
// https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Viewer/47a191931461a6f2e14de48d6da0f0eb6ec2d147/source/Renderer/shaders/material_info.glsl
// We may want to account for this case during GLTF model import.
// -Cosmic,2023-06-06
-vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform)
+vec4 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform)
{
- vec2 weights = vec2(0, 1);
+ // Immediately convert to left-handed coordinate system, but it has no
+ // effect here because y is 0 ((1,0) -> (1,0))
+ vec2 weights = vec2(1, 0);
- // Apply texture animation first to avoid shearing and other artifacts (rotation only)
- mat2 sl_rot_scale;
- sl_rot_scale[0][0] = sl_animation_transform[0][0];
- sl_rot_scale[0][1] = sl_animation_transform[0][1];
- sl_rot_scale[1][0] = sl_animation_transform[1][0];
- sl_rot_scale[1][1] = sl_animation_transform[1][1];
- weights = sl_rot_scale * weights;
- // Remove scale
- weights = normalize(weights);
-
- // Convert to left-handed coordinate system
- weights.y = -weights.y;
-
- // Apply KHR_texture_transform (rotation only)
- float khr_rotation = khr_gltf_transform[0].z;
+ // Apply inverse KHR_texture_transform (rotation and scale sign only)
+ float khr_rotation = -khr_gltf_transform[0].z;
mat2 khr_rotation_mat = mat2(
cos(khr_rotation),-sin(khr_rotation),
sin(khr_rotation), cos(khr_rotation)
);
weights = khr_rotation_mat * weights;
+ vec2 khr_scale_sign = sign(khr_gltf_transform[0].xy);
+ weights *= khr_scale_sign.xy;
+
+ // *NOTE: Delay conversion to right-handed coordinate system here, to
+ // remove the need for computing the inverse of the SL texture animation
+ // matrix.
+
+ // Apply texture animation last to avoid shearing and other artifacts (rotation only)
+ mat2 inv_sl_rot_scale;
+ inv_sl_rot_scale[0][0] = sl_animation_transform[0][0];
+ inv_sl_rot_scale[0][1] = sl_animation_transform[0][1];
+ inv_sl_rot_scale[1][0] = sl_animation_transform[1][0];
+ inv_sl_rot_scale[1][1] = sl_animation_transform[1][1];
+ weights = inv_sl_rot_scale * weights;
+ // *NOTE: Scale to be removed later
+
+ // Set weights to default if 0 for some reason
+ weights.x += 1.0 - abs(sign(sign(weights.x) + (0.5 * sign(weights.y))));
+
+ // Remove scale from SL texture animation transform
+ weights = normalize(weights);
// Convert back to right-handed coordinate system
weights.y = -weights.y;
@@ -132,27 +144,41 @@ vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] kh
// from the normal and tangent, as seen in the fragment shader
vec3 vertex_binormal = vertex_tangent.w * cross(vertex_normal, vertex_tangent.xyz);
- return (weights.x * vertex_binormal.xyz) + (weights.y * vertex_tangent.xyz);
+ // An additional sign flip prevents the binormal from being flipped as a
+ // result of a propagation of the tangent sign during the cross product.
+ float sign_flip = khr_scale_sign.x * khr_scale_sign.y;
+ return vec4((weights.x * vertex_tangent.xyz) + (weights.y * vertex_binormal.xyz), vertex_tangent.w * sign_flip);
}
// Similar to tangent_space_transform but no texture animation support.
-vec3 terrain_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform)
+vec4 terrain_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform)
{
- // Immediately convert to left-handed coordinate system ((0,1) -> (0, -1))
- vec2 weights = vec2(0, -1);
+ // Immediately convert to left-handed coordinate system, but it has no
+ // effect here because y is 0 ((1,0) -> (1,0))
+ vec2 weights = vec2(1, 0);
- // Apply KHR_texture_transform (rotation only)
- float khr_rotation = khr_gltf_transform[0].z;
+ // Apply inverse KHR_texture_transform (rotation and scale sign only)
+ float khr_rotation = -khr_gltf_transform[0].z;
mat2 khr_rotation_mat = mat2(
cos(khr_rotation),-sin(khr_rotation),
sin(khr_rotation), cos(khr_rotation)
);
weights = khr_rotation_mat * weights;
+ vec2 khr_scale_sign = sign(khr_gltf_transform[0].xy);
+ weights *= khr_scale_sign.xy;
+
+ // Set weights to default if 0 for some reason
+ weights.x += 1.0 - abs(sign(sign(weights.x) + (0.5 * sign(weights.y))));
// Convert back to right-handed coordinate system
weights.y = -weights.y;
+ // Similar to the MikkTSpace-compatible method of extracting the binormal
+ // from the normal and tangent, as seen in the fragment shader
vec3 vertex_binormal = vertex_tangent.w * cross(vertex_normal, vertex_tangent.xyz);
- return (weights.x * vertex_binormal.xyz) + (weights.y * vertex_tangent.xyz);
+ // An additional sign flip prevents the binormal from being flipped as a
+ // result of a propagation of the tangent sign during the cross product.
+ float sign_flip = khr_scale_sign.x * khr_scale_sign.y;
+ return vec4((weights.x * vertex_tangent.xyz) + (weights.y * vertex_binormal.xyz), vertex_tangent.w * sign_flip);
}
diff --git a/indra/newview/fsslurl.cpp b/indra/newview/fsslurl.cpp
index 1bd12e15ab..d6a7d61e9a 100644
--- a/indra/newview/fsslurl.cpp
+++ b/indra/newview/fsslurl.cpp
@@ -33,7 +33,6 @@
#include "llpanellogin.h"
#include "llviewercontrol.h"
#include "llviewernetwork.h"
-#include "llfiltersd2xmlrpc.h"
#include "curl/curl.h"
#include "llstartup.h"
// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d)
@@ -630,7 +629,7 @@ std::string LLSLURL::getLoginString() const
LL_WARNS("AppInit") << "Unexpected SLURL type for login string" << (int)mType << LL_ENDL;
break;
}
- return xml_escape_string(unescaped_start.str());
+ return LLStringFn::xml_encode(unescaped_start.str(), true);
}
bool LLSLURL::operator==(const LLSLURL& rhs)
diff --git a/indra/newview/gltf/buffer_util.h b/indra/newview/gltf/buffer_util.h
index 40f9448aaf..89cedf4a47 100644
--- a/indra/newview/gltf/buffer_util.h
+++ b/indra/newview/gltf/buffer_util.h
@@ -180,6 +180,16 @@ namespace LL
data[3] = src[3];
}
+ template<>
+ inline void copyVec4(U8* src, U64& dst)
+ {
+ U8* data = (U8*)&dst;
+ data[0] = src[0];
+ data[1] = src[1];
+ data[2] = src[2];
+ data[3] = src[3];
+ }
+
template<>
inline void copyVec4(U16* src, LLColor4U& dst)
{
diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp
index 318e765cdb..aaf6eac620 100644
--- a/indra/newview/gltfscenemanager.cpp
+++ b/indra/newview/gltfscenemanager.cpp
@@ -42,6 +42,7 @@
#include "llviewertexturelist.h"
#include "llimagej2c.h"
#include "llfloaterperms.h"
+#include "llfloaterreg.h"
#include "llagentbenefits.h"
#include "llfilesystem.h"
#include "boost/json.hpp"
@@ -144,7 +145,7 @@ void GLTFSceneManager::uploadSelection()
}
else
{
- raw = image.mTexture->getCachedRawImage();
+ raw = image.mTexture->getRawImage();
}
if (raw.notNull())
@@ -314,6 +315,7 @@ void GLTFSceneManager::load(const std::string& filename)
{
mObjects.push_back(obj);
}
+ LLFloaterReg::showInstance("gltf_asset_editor");
}
}
else
@@ -339,6 +341,7 @@ void GLTFSceneManager::renderAlpha()
void GLTFSceneManager::addGLTFObject(LLViewerObject* obj, LLUUID gltf_id)
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF;
llassert(obj->getVolume()->getParams().getSculptID() == gltf_id);
llassert(obj->getVolume()->getParams().getSculptType() == LL_SCULPT_TYPE_GLTF);
diff --git a/indra/newview/llcurrencyuimanager.cpp b/indra/newview/llcurrencyuimanager.cpp
index 099c7b2282..d75e90ba19 100644
--- a/indra/newview/llcurrencyuimanager.cpp
+++ b/indra/newview/llcurrencyuimanager.cpp
@@ -111,16 +111,17 @@ public:
bool hasEstimate() const;
std::string getLocalEstimate() const;
- void startTransaction(TransactionType type,
- const char* method, LLXMLRPCValue params);
+ void startTransaction(TransactionType type, const char* method, const LLSD& params);
+
+ // return true if update needed
bool checkTransaction();
- // return true if update needed
void setError(const std::string& message, const std::string& uri);
void clearError();
+ // return true if update needed
bool considerUpdateCurrency();
- // return true if update needed
+
void currencyKey(S32);
static void onCurrencyKey(LLLineEditor* caller, void* data);
@@ -160,32 +161,29 @@ void LLCurrencyUIManager::Impl::updateCurrencyInfo()
return;
}
- LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
- keywordArgs.appendString("agentId", gAgent.getID().asString());
- keywordArgs.appendString(
- "secureSessionId",
- gAgent.getSecureSessionID().asString());
- keywordArgs.appendString("language", LLUI::getLanguage());
- keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy);
- keywordArgs.appendString("viewerChannel", LLVersionInfo::instance().getChannel());
- keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::instance().getMajor());
- keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::instance().getMinor());
- keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::instance().getPatch());
- // With GitHub builds, the build number is too big to fit in a 32-bit int,
- // and XMLRPC_VALUE doesn't deal with integers wider than int. Use string.
- keywordArgs.appendString("viewerBuildVersion", stringize(LLVersionInfo::instance().getBuild()));
+ const LLVersionInfo& vi(LLVersionInfo::instance());
- LLXMLRPCValue params = LLXMLRPCValue::createArray();
- params.append(keywordArgs);
+ LLSD params = LLSD::emptyMap();
+ params["agentId"] = gAgent.getID().asString();
+ params["secureSessionId"] = gAgent.getSecureSessionID().asString();
+ params["language"] = LLUI::getLanguage();
+ params["currencyBuy"] = mUserCurrencyBuy;
+ params["viewerChannel"] = vi.getChannel();
+ params["viewerMajorVersion"] = vi.getMajor();
+ params["viewerMinorVersion"] = vi.getMinor();
+ params["viewerPatchVersion"] = vi.getPatch();
+ // With GitHub builds, the build number is too big to fit in a 32-bit int,
+ // and XMLRPC value doesn't deal with integers wider than int. Use string.
+ params["viewerBuildVersion"] = std::to_string(vi.getBuild());
startTransaction(TransactionCurrency, "getCurrencyQuote", params);
}
void LLCurrencyUIManager::Impl::finishCurrencyInfo()
{
- LLXMLRPCValue result = mTransaction->responseValue();
+ const LLSD& result = mTransaction->response();
- bool success = result["success"].asBool();
+ bool success = result["success"].asBoolean();
if (!success)
{
setError(
@@ -195,24 +193,24 @@ void LLCurrencyUIManager::Impl::finishCurrencyInfo()
return;
}
- LLXMLRPCValue currency = result["currency"];
+ const LLSD& currency = result["currency"];
// old XML-RPC server: estimatedCost = value in US cents
- mUSDCurrencyEstimated = currency["estimatedCost"].isValid();
+ mUSDCurrencyEstimated = currency.has("estimatedCost");
if (mUSDCurrencyEstimated)
{
- mUSDCurrencyEstimatedCost = currency["estimatedCost"].asInt();
+ mUSDCurrencyEstimatedCost = currency["estimatedCost"].asInteger();
}
// newer XML-RPC server: estimatedLocalCost = local currency string
- mLocalCurrencyEstimated = currency["estimatedLocalCost"].isValid();
+ mLocalCurrencyEstimated = currency.has("estimatedLocalCost");
if (mLocalCurrencyEstimated)
{
mLocalCurrencyEstimatedCost = currency["estimatedLocalCost"].asString();
mSupportsInternationalBilling = true;
}
- S32 newCurrencyBuy = currency["currencyBuy"].asInt();
+ S32 newCurrencyBuy = currency["currencyBuy"].asInteger();
if (newCurrencyBuy != mUserCurrencyBuy)
{
mUserCurrencyBuy = newCurrencyBuy;
@@ -224,36 +222,36 @@ void LLCurrencyUIManager::Impl::finishCurrencyInfo()
void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password)
{
- LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
- keywordArgs.appendString("agentId", gAgent.getID().asString());
- keywordArgs.appendString(
- "secureSessionId",
- gAgent.getSecureSessionID().asString());
- keywordArgs.appendString("language", LLUI::getLanguage());
- keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy);
+ const LLVersionInfo& vi(LLVersionInfo::instance());
+
+ LLSD params = LLSD::emptyMap();
+ params["agentId"] = gAgent.getID().asString();
+ params["secureSessionId"] = gAgent.getSecureSessionID().asString();
+ params["language"] = LLUI::getLanguage();
+ params["currencyBuy"] = mUserCurrencyBuy;
+ params["confirm"] = mSiteConfirm;
+ params["viewerChannel"] = vi.getChannel();
+ params["viewerMajorVersion"] = vi.getMajor();
+ params["viewerMinorVersion"] = vi.getMinor();
+ params["viewerPatchVersion"] = vi.getPatch();
+ // With GitHub builds, the build number is too big to fit in a 32-bit int,
+ // and XMLRPC value doesn't deal with integers wider than int. Use string.
+ params["viewerBuildVersion"] = std::to_string(vi.getBuild());
+
if (mUSDCurrencyEstimated)
{
- keywordArgs.appendInt("estimatedCost", mUSDCurrencyEstimatedCost);
+ params["estimatedCost"] = mUSDCurrencyEstimatedCost;
}
+
if (mLocalCurrencyEstimated)
{
- keywordArgs.appendString("estimatedLocalCost", mLocalCurrencyEstimatedCost);
+ params["estimatedLocalCost"] = mLocalCurrencyEstimatedCost;
}
- keywordArgs.appendString("confirm", mSiteConfirm);
+
if (!password.empty())
{
- keywordArgs.appendString("password", password);
+ params["password"] = password;
}
- keywordArgs.appendString("viewerChannel", LLVersionInfo::instance().getChannel());
- keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::instance().getMajor());
- keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::instance().getMinor());
- keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::instance().getPatch());
- // With GitHub builds, the build number is too big to fit in a 32-bit int,
- // and XMLRPC_VALUE doesn't deal with integers wider than int. Use string.
- keywordArgs.appendString("viewerBuildVersion", stringize(LLVersionInfo::instance().getBuild()));
-
- LLXMLRPCValue params = LLXMLRPCValue::createArray();
- params.append(keywordArgs);
startTransaction(TransactionBuy, "buyCurrency", params);
@@ -263,9 +261,9 @@ void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password)
void LLCurrencyUIManager::Impl::finishCurrencyBuy()
{
- LLXMLRPCValue result = mTransaction->responseValue();
+ const LLSD& result = mTransaction->response();
- bool success = result["success"].asBool();
+ bool success = result["success"].asBoolean();
if (!success)
{
setError(
@@ -282,7 +280,7 @@ void LLCurrencyUIManager::Impl::finishCurrencyBuy()
}
void LLCurrencyUIManager::Impl::startTransaction(TransactionType type,
- const char* method, LLXMLRPCValue params)
+ const char* method, const LLSD& params)
{
//
//static std::string transactionURI;
@@ -302,12 +300,7 @@ void LLCurrencyUIManager::Impl::startTransaction(TransactionType type,
delete mTransaction;
mTransactionType = type;
- mTransaction = new LLXMLRPCTransaction(
- transactionURI,
- method,
- params,
- false /* don't use gzip */
- );
+ mTransaction = new LLXMLRPCTransaction(transactionURI, method, params);
clearError();
}
@@ -361,12 +354,17 @@ bool LLCurrencyUIManager::Impl::checkTransaction()
{
setError(mTransaction->statusMessage(), mTransaction->statusURI());
}
- else {
+ else
+ {
switch (mTransactionType)
{
- case TransactionCurrency: finishCurrencyInfo(); break;
- case TransactionBuy: finishCurrencyBuy(); break;
- default: ;
+ case TransactionCurrency:
+ finishCurrencyInfo();
+ break;
+ case TransactionBuy:
+ finishCurrencyBuy();
+ break;
+ default:;
}
}
@@ -394,9 +392,8 @@ void LLCurrencyUIManager::Impl::clearError()
bool LLCurrencyUIManager::Impl::considerUpdateCurrency()
{
- if (mCurrencyChanged
- && !mTransaction
- && mCurrencyKeyTimer.getElapsedTimeF32() >= CURRENCY_ESTIMATE_FREQUENCY)
+ if (mCurrencyChanged && !mTransaction &&
+ mCurrencyKeyTimer.getElapsedTimeF32() >= CURRENCY_ESTIMATE_FREQUENCY)
{
updateCurrencyInfo();
return true;
@@ -417,7 +414,8 @@ void LLCurrencyUIManager::Impl::currencyKey(S32 value)
mUserCurrencyBuy = value;
- if (hasEstimate()) {
+ if (hasEstimate())
+ {
clearEstimate();
//cannot just simply refresh the whole UI, as the edit field will
// get reset and the cursor will change...
@@ -430,8 +428,7 @@ void LLCurrencyUIManager::Impl::currencyKey(S32 value)
}
// static
-void LLCurrencyUIManager::Impl::onCurrencyKey(
- LLLineEditor* caller, void* data)
+void LLCurrencyUIManager::Impl::onCurrencyKey(LLLineEditor* caller, void* data)
{
S32 value = atoi(caller->getText().c_str());
LLCurrencyUIManager::Impl* self = (LLCurrencyUIManager::Impl*)data;
@@ -598,14 +595,12 @@ bool LLCurrencyUIManager::inProcess()
bool LLCurrencyUIManager::canCancel()
{
- return impl.mTransactionType != Impl::TransactionBuy;
+ return !buying();
}
bool LLCurrencyUIManager::canBuy()
{
- return impl.mTransactionType == Impl::TransactionNone
- && impl.hasEstimate()
- && impl.mUserCurrencyBuy > 0;
+ return !inProcess() && impl.hasEstimate() && impl.mUserCurrencyBuy > 0;
}
bool LLCurrencyUIManager::buying()
diff --git a/indra/newview/lldebugview.cpp b/indra/newview/lldebugview.cpp
index 92a3f1a7ad..37125b9e44 100644
--- a/indra/newview/lldebugview.cpp
+++ b/indra/newview/lldebugview.cpp
@@ -105,12 +105,9 @@ void LLDebugView::init()
addChild(gSceneMonitorView);
gSceneMonitorView->setRect(rect);
- r.setLeftTopAndSize(25, rect.getHeight() - 50, (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.75f),
- (S32) (gViewerWindow->getWindowRectScaled().getHeight() * 0.75f));
-
// Fix texture console width
//r.set(150, rect.getHeight() - 50, 820, 100);
- r.set(150, rect.getHeight() - 50, 965, 100);
+ r.set(150, rect.getHeight() - 60, 965, 100);
//
LLTextureView::Params tvp;
tvp.name("gTextureView");
@@ -119,7 +116,6 @@ void LLDebugView::init()
tvp.visible(false);
gTextureView = LLUICtrlFactory::create(tvp);
addChild(gTextureView);
- //gTextureView->reshape(r.getWidth(), r.getHeight(), true);
}
void LLDebugView::draw()
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 4d91cb121c..ee6a4b8637 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -79,11 +79,6 @@ static S32 diffuse_channel = -1;
static S32 bump_channel = -1;
static bool shiny = false;
-// Enabled after changing LLViewerTexture::mNeedsCreateTexture to an
-// LLAtomicBool; this should work just fine, now. HB
-#define LL_BUMPLIST_MULTITHREADED 1
-
-
// static
void LLStandardBumpmap::shutdown()
{
@@ -767,24 +762,21 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
llassert( (bump_code == BE_BRIGHTNESS) || (bump_code == BE_DARKNESS) );
- LLViewerTexture* bump = NULL;
+ LLViewerTexture* bump = nullptr;
- bump_image_map_t* entries_list = NULL;
- void (*callback_func)( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata ) = NULL;
+ bump_image_map_t* entries_list = nullptr;
switch( bump_code )
{
case BE_BRIGHTNESS:
entries_list = &mBrightnessEntries;
- callback_func = LLBumpImageList::onSourceBrightnessLoaded;
break;
case BE_DARKNESS:
entries_list = &mDarknessEntries;
- callback_func = LLBumpImageList::onSourceDarknessLoaded;
break;
default:
llassert(0);
- return NULL;
+ return nullptr;
}
bump_image_map_t::iterator iter = entries_list->find(src_image->getID());
@@ -792,51 +784,18 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText
{
bump = iter->second;
}
- else
+
+ if (bump == nullptr ||
+ src_image->getWidth() != bump->getWidth() ||
+ src_image->getHeight() != bump->getHeight())
{
- (*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( true );
- bump = (*entries_list)[src_image->getID()]; // In case callback was called immediately and replaced the image
+ onSourceUpdated(src_image, (EBumpEffect) bump_code);
}
- if (!src_image->hasCallbacks())
- { //if image has no callbacks but resolutions don't match, trigger raw image loaded callback again
- if (src_image->getWidth() != bump->getWidth() ||
- src_image->getHeight() != bump->getHeight())// ||
- //(LLPipeline::sRenderDeferred && bump->getComponents() != 4))
- {
- src_image->setBoostLevel(LLGLTexture::BOOST_BUMP) ;
- src_image->setLoadedCallback( callback_func, 0, true, false, new LLUUID(src_image->getID()), NULL );
- src_image->forceToSaveRawImage(0) ;
- }
- }
-
- return bump;
+ return (*entries_list)[src_image->getID()];
}
-// static
-void LLBumpImageList::onSourceBrightnessLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata )
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
- LLUUID* source_asset_id = (LLUUID*)userdata;
- LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_BRIGHTNESS );
- if( final )
- {
- delete source_asset_id;
- }
-}
-
-// static
-void LLBumpImageList::onSourceDarknessLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata )
-{
- LLUUID* source_asset_id = (LLUUID*)userdata;
- LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_DARKNESS );
- if( final )
- {
- delete source_asset_id;
- }
-}
-
void LLBumpImageList::onSourceStandardLoaded( bool success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata)
{
if (success && LLPipeline::sRenderDeferred)
@@ -916,289 +875,108 @@ void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nr
}
// static
-void LLBumpImageList::onSourceLoaded( bool success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code )
+void LLBumpImageList::onSourceUpdated(LLViewerTexture* src, EBumpEffect bump_code)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
- if( success )
- {
- LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
+ const LLUUID& src_id = src->getID();
- LLImageDataSharedLock lock(src);
+ bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries);
+ bump_image_map_t::iterator iter = entries_list.find(src_id);
- bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries );
- bump_image_map_t::iterator iter = entries_list.find(source_asset_id);
-
- {
- if (iter == entries_list.end() ||
- iter->second.isNull() ||
- iter->second->getWidth() != src->getWidth() ||
- iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution
- { //make sure an entry exists for this image
- entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture(true);
- iter = entries_list.find(src_vi->getID());
- }
- }
-
- if (iter->second->getWidth() != src->getWidth() ||
- iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution
- {
- LLPointer dst_image = new LLImageRaw(src->getWidth(), src->getHeight(), 1);
- U8* dst_data = dst_image->getData();
- S32 dst_data_size = dst_image->getDataSize();
-
- const U8* src_data = src->getData();
- S32 src_data_size = src->getDataSize();
-
- S32 src_components = src->getComponents();
-
- // Convert to luminance and then scale and bias that to get ready for
- // embossed bump mapping. (0-255 maps to 127-255)
-
- // Convert to fixed point so we don't have to worry about precision/clamping.
- const S32 FIXED_PT = 8;
- const S32 R_WEIGHT = S32(0.2995f * (1< maximum )
- {
- maximum = dst_data[i];
- }
- }
- }
- else
- {
- llassert(0);
- dst_image->clear();
- }
- }
- break;
- case 3:
- case 4:
- {
- if( src_data_size == dst_data_size * src_components )
- {
- for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components )
- {
- // RGB to luminance
- dst_data[i] = (R_WEIGHT * src_data[j] + G_WEIGHT * src_data[j+1] + B_WEIGHT * src_data[j+2]) >> FIXED_PT;
- //llassert( dst_data[i] <= 255 );true because it's 8bit
- if( dst_data[i] < minimum )
- {
- minimum = dst_data[i];
- }
- if( dst_data[i] > maximum )
- {
- maximum = dst_data[i];
- }
- }
- }
- else
- {
- llassert(0);
- dst_image->clear();
- }
- }
- break;
- default:
- llassert(0);
- dst_image->clear();
- break;
- }
-
- if( maximum > minimum )
- {
- U8 bias_and_scale_lut[256];
- F32 twice_one_over_range = 2.f / (maximum - minimum);
- S32 i;
-
- const F32 ARTIFICIAL_SCALE = 2.f; // Advantage: exaggerates the effect in midrange. Disadvantage: clamps at the extremes.
- if (BE_DARKNESS == bump_code)
- {
- for( i = minimum; i <= maximum; i++ )
- {
- F32 minus_one_to_one = F32(maximum - i) * twice_one_over_range - 1.f;
- bias_and_scale_lut[i] = llclampb(ll_round(127 * minus_one_to_one * ARTIFICIAL_SCALE + 128));
- }
- }
- else
- {
- for( i = minimum; i <= maximum; i++ )
- {
- F32 minus_one_to_one = F32(i - minimum) * twice_one_over_range - 1.f;
- bias_and_scale_lut[i] = llclampb(ll_round(127 * minus_one_to_one * ARTIFICIAL_SCALE + 128));
- }
- }
-
- for( i = 0; i < dst_data_size; i++ )
- {
- dst_data[i] = bias_and_scale_lut[dst_data[i]];
- }
- }
-
- //---------------------------------------------------
- // immediately assign bump to a smart pointer in case some local smart pointer
- // accidentally releases it.
- LLPointer bump = iter->second;
-
- if (!LLPipeline::sRenderDeferred)
- {
- bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA);
-
-#if LL_BUMPLIST_MULTITHREADED
- auto tex_queue = LLImageGLThread::sEnabledTextures ? sTexUpdateQueue.lock() : nullptr;
-
- if (tex_queue)
- { //dispatch creation to background thread
- LLImageRaw* dst_ptr = dst_image;
- LLViewerTexture* bump_ptr = bump;
- dst_ptr->ref();
- bump_ptr->ref();
- tex_queue->post(
- [=]()
- {
- LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("bil - create texture");
- bump_ptr->createGLTexture(0, dst_ptr);
- bump_ptr->unref();
- dst_ptr->unref();
- });
-
- }
- else
-#endif
- {
- bump->createGLTexture(0, dst_image);
- }
- }
- else
- { //convert to normal map
- LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("bil - create normal map");
- LLImageGL* img = bump->getGLTexture();
- LLImageRaw* dst_ptr = dst_image.get();
- LLGLTexture* bump_ptr = bump.get();
-
- dst_ptr->ref();
- img->ref();
- bump_ptr->ref();
- auto create_func = [=]()
- {
- img->setUseMipMaps(true);
- // upload dst_image to GPU (greyscale in red channel)
- img->setExplicitFormat(GL_RED, GL_RED);
-
- bump_ptr->createGLTexture(0, dst_ptr);
- dst_ptr->unref();
- };
-
- auto generate_func = [=]()
- {
- // Allocate an empty RGBA texture at "tex_name" the same size as bump
- // Note: bump will still point at GPU copy of dst_image
- bump_ptr->setExplicitFormat(GL_RGBA, GL_RGBA);
- LLGLuint tex_name;
- img->createGLTexture(0, nullptr, false, 0, true, &tex_name);
-
- // point render target at empty buffer
- sRenderTarget.setColorAttachment(img, tex_name);
-
- // generate normal map in empty texture
- {
- sRenderTarget.bindTarget();
-
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable cull(GL_CULL_FACE);
- LLGLDisable blend(GL_BLEND);
- gGL.setColorMask(true, true);
-
- gNormalMapGenProgram.bind();
-
- static LLStaticHashedString sNormScale("norm_scale");
- static LLStaticHashedString sStepX("stepX");
- static LLStaticHashedString sStepY("stepY");
-
- gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale"));
- gNormalMapGenProgram.uniform1f(sStepX, 1.f / bump_ptr->getWidth());
- gNormalMapGenProgram.uniform1f(sStepY, 1.f / bump_ptr->getHeight());
-
- gGL.getTexUnit(0)->bind(bump_ptr);
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(0, 0);
- gGL.vertex2f(0, 0);
-
- gGL.texCoord2f(0, 1);
- gGL.vertex2f(0, 1);
-
- gGL.texCoord2f(1, 0);
- gGL.vertex2f(1, 0);
-
- gGL.texCoord2f(1, 1);
- gGL.vertex2f(1, 1);
-
- gGL.end();
-
- gGL.flush();
-
- gNormalMapGenProgram.unbind();
-
- sRenderTarget.flush();
- sRenderTarget.releaseColorAttachment();
- }
-
- // point bump at normal map and free gpu copy of dst_image
- img->syncTexName(tex_name);
-
- // generate mipmap
- gGL.getTexUnit(0)->bind(img);
- glGenerateMipmap(GL_TEXTURE_2D);
- gGL.getTexUnit(0)->disable();
-
- bump_ptr->unref();
- img->unref();
- };
-
-#if LL_BUMPLIST_MULTITHREADED
- auto main_queue = LLImageGLThread::sEnabledTextures ? sMainQueue.lock() : nullptr;
-
- if (main_queue)
- { //dispatch texture upload to background thread, issue GPU commands to generate normal map on main thread
- main_queue->postTo(
- sTexUpdateQueue,
- create_func,
- generate_func);
- }
- else
-#endif
- { // immediate upload texture and generate normal map
- create_func();
- generate_func();
- }
-
-
- }
-
- iter->second = bump; // derefs (and deletes) old image
- //---------------------------------------------------
- }
+ if (iter == entries_list.end())
+ { //make sure an entry exists for this image
+ entries_list[src_id] = LLViewerTextureManager::getLocalTexture(true);
+ iter = entries_list.find(src_id);
}
+
+ //---------------------------------------------------
+ // immediately assign bump to a smart pointer in case some local smart pointer
+ // accidentally releases it.
+ LLPointer bump = iter->second;
+
+ if (bump->getWidth() != src->getWidth() ||
+ bump->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution
+ {
+ //convert to normal map
+ LL_PROFILE_ZONE_NAMED("bil - create normal map");
+
+ bump->setExplicitFormat(GL_RGBA, GL_RGBA);
+
+ LLImageGL* src_img = src->getGLTexture();
+ LLImageGL* dst_img = bump->getGLTexture();
+ dst_img->setSize(src->getWidth(), src->getHeight(), 4, 0);
+ dst_img->setUseMipMaps(true);
+ dst_img->setDiscardLevel(0);
+ dst_img->createGLTexture();
+
+ gGL.getTexUnit(0)->bind(bump);
+
+ LLImageGL::setManualImage(GL_TEXTURE_2D, 0, dst_img->getPrimaryFormat(), dst_img->getWidth(), dst_img->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false);
+
+ LLGLuint tex_name = dst_img->getTexName();
+ // point render target at empty buffer
+ sRenderTarget.setColorAttachment(bump->getGLTexture(), tex_name);
+
+ // generate normal map in empty texture
+ {
+ sRenderTarget.bindTarget();
+
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable cull(GL_CULL_FACE);
+ LLGLDisable blend(GL_BLEND);
+ gGL.setColorMask(true, true);
+
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ gNormalMapGenProgram.bind();
+
+ static LLStaticHashedString sNormScale("norm_scale");
+ static LLStaticHashedString sStepX("stepX");
+ static LLStaticHashedString sStepY("stepY");
+ static LLStaticHashedString sBumpCode("bump_code");
+
+ gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale"));
+ gNormalMapGenProgram.uniform1f(sStepX, 1.f / bump->getWidth());
+ gNormalMapGenProgram.uniform1f(sStepY, 1.f / bump->getHeight());
+ gNormalMapGenProgram.uniform1i(sBumpCode, bump_code);
+
+ gGL.getTexUnit(0)->bind(src);
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(0, 0);
+ gGL.vertex2f(0, 0);
+
+ gGL.texCoord2f(0, 1);
+ gGL.vertex2f(0, 1);
+
+ gGL.texCoord2f(1, 0);
+ gGL.vertex2f(1, 0);
+
+ gGL.texCoord2f(1, 1);
+ gGL.vertex2f(1, 1);
+
+ gGL.end();
+
+ gGL.flush();
+
+ sRenderTarget.flush();
+ sRenderTarget.releaseColorAttachment();
+
+ if (shader)
+ {
+ shader->bind();
+ }
+ }
+
+ // generate mipmap
+ gGL.getTexUnit(0)->bind(bump);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+
+ iter->second = bump; // derefs (and deletes) old image
+ //---------------------------------------------------
+
}
void LLDrawPoolBump::pushBumpBatches(U32 type)
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index 65cb9af015..15976884ca 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -140,14 +140,13 @@ public:
LLViewerTexture* getBrightnessDarknessImage(LLViewerFetchedTexture* src_image, U8 bump_code);
void addTextureStats(U8 bump, const LLUUID& base_image_id, F32 virtual_size);
- static void onSourceBrightnessLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata );
- static void onSourceDarknessLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata );
static void onSourceStandardLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata );
static void generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nrm_image);
private:
- static void onSourceLoaded( bool success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump );
+ // should be called whenever resolution of src_vi changes compared to the current entry
+ static void onSourceUpdated( LLViewerTexture *src_vi, EBumpEffect bump );
private:
typedef std::unordered_map > bump_image_map_t;
diff --git a/indra/newview/llfloateravatar.cpp b/indra/newview/llfloateravatar.cpp
index b6fd221923..4f25b2c0fd 100644
--- a/indra/newview/llfloateravatar.cpp
+++ b/indra/newview/llfloateravatar.cpp
@@ -25,11 +25,6 @@
* $/LicenseInfo$
*/
-/**
- * Floater that appears when buying an object, giving a preview
- * of its contents and their permissions.
- */
-
#include "llviewerprecompiledheaders.h"
#include "llfloateravatar.h"
diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp
index f7fee54255..281eb5348e 100644
--- a/indra/newview/llfloaterbuyland.cpp
+++ b/indra/newview/llfloaterbuyland.cpp
@@ -182,7 +182,7 @@ public:
void refreshUI();
- void startTransaction(TransactionType type, const LLXMLRPCValue& params);
+ void startTransaction(TransactionType type, const LLSD& params);
bool checkTransaction();
void tellUserError(const std::string& message, const std::string& uri);
@@ -396,11 +396,10 @@ void LLFloaterBuyLandUI::updateParcelInfo()
// Can't have more than region max tasks, regardless of parcel
// object bonus factor.
LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
- if(region)
+ if (region)
{
S32 max_tasks_per_region = (S32)region->getMaxTasks();
- mParcelSupportedObjects = llmin(
- mParcelSupportedObjects, max_tasks_per_region);
+ mParcelSupportedObjects = llmin(mParcelSupportedObjects, max_tasks_per_region);
}
mParcelSoldWithObjects = parcel->getSellWithObjects();
@@ -423,7 +422,7 @@ void LLFloaterBuyLandUI::updateParcelInfo()
// checks that we can buy the land
- if(mIsForGroup && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED))
+ if (mIsForGroup && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED))
{
mCannotBuyReason = getString("cant_buy_for_group");
return;
@@ -492,85 +491,56 @@ void LLFloaterBuyLandUI::updateParcelInfo()
void LLFloaterBuyLandUI::updateCovenantInfo()
{
LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
- if(!region) return;
+ if (!region)
+ return;
U8 sim_access = region->getSimAccess();
std::string rating = LLViewerRegion::accessToString(sim_access);
LLTextBox* region_name = getChild("region_name_text");
- if (region_name)
+ std::string region_name_txt = region->getName() + " ("+rating +")";
+ region_name->setText(region_name_txt);
+
+ LLIconCtrl* rating_icon = getChild("rating_icon");
+ LLRect rect = rating_icon->getRect();
+ S32 region_name_width = llmin(region_name->getRect().getWidth(), region_name->getTextBoundingRect().getWidth());
+ S32 icon_left_pad = region_name->getRect().mLeft + region_name_width + ICON_PAD;
+ region_name->setToolTip(region_name->getText());
+ rating_icon->setRect(rect.setOriginAndSize(icon_left_pad, rect.mBottom, rect.getWidth(), rect.getHeight()));
+
+ switch (sim_access)
{
- std::string region_name_txt = region->getName() + " ("+rating +")";
- region_name->setText(region_name_txt);
+ case SIM_ACCESS_PG:
+ rating_icon->setValue(getString("icon_PG"));
+ break;
- LLIconCtrl* rating_icon = getChild("rating_icon");
- LLRect rect = rating_icon->getRect();
- S32 region_name_width = llmin(region_name->getRect().getWidth(), region_name->getTextBoundingRect().getWidth());
- S32 icon_left_pad = region_name->getRect().mLeft + region_name_width + ICON_PAD;
- region_name->setToolTip(region_name->getText());
- rating_icon->setRect(rect.setOriginAndSize(icon_left_pad, rect.mBottom, rect.getWidth(), rect.getHeight()));
+ case SIM_ACCESS_ADULT:
+ rating_icon->setValue(getString("icon_R"));
+ break;
- switch(sim_access)
- {
- case SIM_ACCESS_PG:
- rating_icon->setValue(getString("icon_PG"));
- break;
-
- case SIM_ACCESS_ADULT:
- rating_icon->setValue(getString("icon_R"));
- break;
-
- default:
- rating_icon->setValue(getString("icon_M"));
- }
+ default:
+ rating_icon->setValue(getString("icon_M"));
}
LLTextBox* region_type = getChild("region_type_text");
- if (region_type)
- {
- region_type->setText(region->getLocalizedSimProductName());
- region_type->setToolTip(region->getLocalizedSimProductName());
- }
+ region_type->setText(region->getLocalizedSimProductName());
+ region_type->setToolTip(region->getLocalizedSimProductName());
LLTextBox* resellable_clause = getChild("resellable_clause");
- if (resellable_clause)
- {
- if (region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL))
- {
- resellable_clause->setText(getString("can_not_resell"));
- }
- else
- {
- resellable_clause->setText(getString("can_resell"));
- }
- }
+ const char* can_resell = region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL) ? "can_not_resell" : "can_resell";
+ resellable_clause->setText(getString(can_resell));
LLTextBox* changeable_clause = getChild("changeable_clause");
- if (changeable_clause)
- {
- if (region->getRegionFlag(REGION_FLAGS_ALLOW_PARCEL_CHANGES))
- {
- changeable_clause->setText(getString("can_change"));
- }
- else
- {
- changeable_clause->setText(getString("can_not_change"));
- }
- }
+ const char* can_change = region->getRegionFlag(REGION_FLAGS_ALLOW_PARCEL_CHANGES) ? "can_change" : "can_not_change";
+ changeable_clause->setText(getString(can_change));
LLCheckBoxCtrl* check = getChild("agree_covenant");
- if(check)
- {
- check->set(false);
- check->setEnabled(true);
- check->setCommitCallback(onChangeAgreeCovenant, this);
- }
+ check->set(false);
+ check->setEnabled(true);
+ check->setCommitCallback(onChangeAgreeCovenant, this);
LLTextBox* box = getChild("covenant_text");
- if(box)
- {
- box->setVisible(false);
- }
+ box->setVisible(false);
// send EstateCovenantInfo message
LLMessageSystem *msg = gMessageSystem;
@@ -584,10 +554,9 @@ void LLFloaterBuyLandUI::updateCovenantInfo()
// static
void LLFloaterBuyLandUI::onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data)
{
- LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)user_data;
- if(self)
+ if (user_data)
{
- self->refreshUI();
+ ((LLFloaterBuyLandUI*)user_data)->refreshUI();
}
}
@@ -626,13 +595,13 @@ void LLFloaterBuyLandUI::updateFloaterEstateName(const std::string& name)
void LLFloaterBuyLandUI::updateFloaterLastModified(const std::string& text)
{
LLTextBox* editor = getChild("covenant_timestamp_text");
- if (editor) editor->setText(text);
+ editor->setText(text);
}
void LLFloaterBuyLandUI::updateFloaterEstateOwnerName(const std::string& name)
{
LLTextBox* box = getChild("estate_owner_text");
- if (box) box->setText(name);
+ box->setText(name);
}
void LLFloaterBuyLandUI::updateWebSiteInfo()
@@ -640,9 +609,10 @@ void LLFloaterBuyLandUI::updateWebSiteInfo()
S32 askBillableArea = mIsForGroup ? 0 : mParcelBillableArea;
S32 askCurrencyBuy = mCurrency.getAmount();
- if (mTransaction && mTransactionType == TransactionPreflight
- && mPreflightAskBillableArea == askBillableArea
- && mPreflightAskCurrencyBuy == askCurrencyBuy)
+ if (mTransaction &&
+ mTransactionType == TransactionPreflight &&
+ mPreflightAskBillableArea == askBillableArea &&
+ mPreflightAskCurrencyBuy == askCurrencyBuy)
{
return;
}
@@ -664,27 +634,21 @@ void LLFloaterBuyLandUI::updateWebSiteInfo()
mSiteCurrencyEstimatedCost = 0;
#endif
- LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
- keywordArgs.appendString("agentId", gAgent.getID().asString());
- keywordArgs.appendString(
- "secureSessionId",
- gAgent.getSecureSessionID().asString());
- keywordArgs.appendString("language", LLUI::getLanguage());
- keywordArgs.appendInt("billableArea", mPreflightAskBillableArea);
- keywordArgs.appendInt("currencyBuy", mPreflightAskCurrencyBuy);
-
- LLXMLRPCValue params = LLXMLRPCValue::createArray();
- params.append(keywordArgs);
+ LLSD params = LLSD::emptyMap();
+ params["agentId"] = gAgent.getID().asString();
+ params["secureSessionId"] = gAgent.getSecureSessionID().asString();
+ params["language"] = LLUI::getLanguage();
+ params["billableArea"] = mPreflightAskBillableArea;
+ params["currencyBuy"] = mPreflightAskCurrencyBuy;
startTransaction(TransactionPreflight, params);
}
void LLFloaterBuyLandUI::finishWebSiteInfo()
{
+ const LLSD& result = mTransaction->response();
- LLXMLRPCValue result = mTransaction->responseValue();
-
- mSiteValid = result["success"].asBool();
+ mSiteValid = result["success"].asBoolean();
if (!mSiteValid)
{
tellUserError(
@@ -694,31 +658,30 @@ void LLFloaterBuyLandUI::finishWebSiteInfo()
return;
}
- LLXMLRPCValue membership = result["membership"];
- mSiteMembershipUpgrade = membership["upgrade"].asBool();
+ const LLSD& membership = result["membership"];
+ mSiteMembershipUpgrade = membership["upgrade"].asBoolean();
mSiteMembershipAction = membership["action"].asString();
mSiteMembershipPlanIDs.clear();
mSiteMembershipPlanNames.clear();
- LLXMLRPCValue levels = membership["levels"];
- for (LLXMLRPCValue level = levels.rewind();
- level.isValid();
- level = levels.next())
+ const LLSD& levels = membership["levels"];
+ for (auto it = levels.beginArray(); it != levels.endArray(); ++it)
{
+ const LLSD& level = *it;
mSiteMembershipPlanIDs.push_back(level["id"].asString());
mSiteMembershipPlanNames.push_back(level["description"].asString());
}
mUserPlanChoice = 0;
- LLXMLRPCValue landUse = result["landUse"];
- mSiteLandUseUpgrade = landUse["upgrade"].asBool();
+ const LLSD& landUse = result["landUse"];
+ mSiteLandUseUpgrade = landUse["upgrade"].asBoolean();
mSiteLandUseAction = landUse["action"].asString();
- LLXMLRPCValue currency = result["currency"];
- if (currency["estimatedCost"].isValid())
+ const LLSD& currency = result["currency"];
+ if (currency.has("estimatedCost"))
{
- mCurrency.setUSDEstimate(currency["estimatedCost"].asInt());
+ mCurrency.setUSDEstimate(currency["estimatedCost"].asInteger());
}
- if (currency["estimatedLocalCost"].isValid())
+ if (currency.has("estimatedLocalCost"))
{
mCurrency.setLocalEstimate(currency["estimatedLocalCost"].asString());
}
@@ -760,35 +723,30 @@ void LLFloaterBuyLandUI::runWebSitePrep(const std::string& password)
}
}
- LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
- keywordArgs.appendString("agentId", gAgent.getID().asString());
- keywordArgs.appendString(
- "secureSessionId",
- gAgent.getSecureSessionID().asString());
- keywordArgs.appendString("language", LLUI::getLanguage());
- keywordArgs.appendString("levelId", newLevel);
- keywordArgs.appendInt("billableArea",
- mIsForGroup ? 0 : mParcelBillableArea);
- keywordArgs.appendInt("currencyBuy", mCurrency.getAmount());
- keywordArgs.appendInt("estimatedCost", mCurrency.getUSDEstimate());
- keywordArgs.appendString("estimatedLocalCost", mCurrency.getLocalEstimate());
- keywordArgs.appendString("confirm", mSiteConfirm);
+ LLSD params = LLSD::emptyMap();
+ params["agentId"] = gAgent.getID().asString();
+ params["secureSessionId"] = gAgent.getSecureSessionID().asString();
+ params["language"] = LLUI::getLanguage();
+ params["levelId"] = newLevel;
+ params["billableArea"] = mIsForGroup ? 0 : mParcelBillableArea;
+ params["currencyBuy"] = mCurrency.getAmount();
+ params["estimatedCost"] = mCurrency.getUSDEstimate();
+ params["estimatedLocalCost"] = mCurrency.getLocalEstimate();
+ params["confirm"] = mSiteConfirm;
+
if (!password.empty())
{
- keywordArgs.appendString("password", password);
+ params["password"] = password;
}
- LLXMLRPCValue params = LLXMLRPCValue::createArray();
- params.append(keywordArgs);
-
startTransaction(TransactionBuy, params);
}
void LLFloaterBuyLandUI::finishWebSitePrep()
{
- LLXMLRPCValue result = mTransaction->responseValue();
+ const LLSD& result = mTransaction->response();
- bool success = result["success"].asBool();
+ bool success = result["success"].asBoolean();
if (!success)
{
tellUserError(
@@ -850,7 +808,7 @@ void LLFloaterBuyLandUI::updateGroupName(const LLUUID& id,
}
}
-void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCValue& params)
+void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLSD& params)
{
delete mTransaction;
mTransaction = NULL;
@@ -887,12 +845,7 @@ void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCVa
return;
}
- mTransaction = new LLXMLRPCTransaction(
- transaction_uri,
- method,
- params,
- false /* don't use gzip */
- );
+ mTransaction = new LLXMLRPCTransaction(transaction_uri, method, params);
}
bool LLFloaterBuyLandUI::checkTransaction()
diff --git a/indra/newview/llfloaterchangeitemthumbnail.cpp b/indra/newview/llfloaterchangeitemthumbnail.cpp
index 6008d954b3..cc52abc578 100644
--- a/indra/newview/llfloaterchangeitemthumbnail.cpp
+++ b/indra/newview/llfloaterchangeitemthumbnail.cpp
@@ -952,8 +952,8 @@ void LLFloaterChangeItemThumbnail::onTexturePickerCommit()
|| texturep->getFullWidth() == 0)
{
if (texturep->isFullyLoaded()
- && (texturep->getCachedRawImageLevel() == 0 || texturep->getRawImageLevel() == 0)
- && (texturep->isCachedRawImageReady() || texturep->isRawImageValid()))
+ && (texturep->getRawImageLevel() == 0)
+ && (texturep->isRawImageValid()))
{
LLUUID task_id = mTaskId;
uuid_set_t inventory_ids = mItemList;
@@ -963,20 +963,10 @@ void LLFloaterChangeItemThumbnail::onTexturePickerCommit()
{
onUploadComplete(asset_id, task_id, inventory_ids, handle);
};
- if (texturep->isRawImageValid())
- {
- LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getRawImage(),
- *mItemList.begin(),
- mTaskId,
- callback);
- }
- else
- {
- LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getCachedRawImage(),
- *mItemList.begin(),
- mTaskId,
- callback);
- }
+ LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getRawImage(),
+ *mItemList.begin(),
+ mTaskId,
+ callback);
}
else
{
diff --git a/indra/newview/llfloaterdestinations.cpp b/indra/newview/llfloaterdestinations.cpp
index 667f423df5..7a9ff1de3c 100644
--- a/indra/newview/llfloaterdestinations.cpp
+++ b/indra/newview/llfloaterdestinations.cpp
@@ -25,11 +25,6 @@
* $/LicenseInfo$
*/
-/**
- * Floater that appears when buying an object, giving a preview
- * of its contents and their permissions.
- */
-
#include "llviewerprecompiledheaders.h"
#include "llfloaterdestinations.h"
diff --git a/indra/newview/llfloaterfonttest.cpp b/indra/newview/llfloaterfonttest.cpp
index 95d08cb9ce..d39b061d40 100644
--- a/indra/newview/llfloaterfonttest.cpp
+++ b/indra/newview/llfloaterfonttest.cpp
@@ -25,11 +25,6 @@
* $/LicenseInfo$
*/
-/**
- * Floater that appears when buying an object, giving a preview
- * of its contents and their permissions.
- */
-
#include "llviewerprecompiledheaders.h"
#include "llfloaterfonttest.h"
diff --git a/indra/newview/llfloatergltfasseteditor.cpp b/indra/newview/llfloatergltfasseteditor.cpp
new file mode 100644
index 0000000000..f21b8032d0
--- /dev/null
+++ b/indra/newview/llfloatergltfasseteditor.cpp
@@ -0,0 +1,527 @@
+/**
+ * @file llfloatergltfasseteditor.cpp
+ * @author Andrii Kleshchev
+ * @brief LLFloaterGltfAssetEditor class implementation
+ *
+ * $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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloatergltfasseteditor.h"
+
+#include "gltf/asset.h"
+#include "llcallbacklist.h"
+#include "llmenubutton.h"
+#include "llselectmgr.h"
+#include "llspinctrl.h"
+#include "llviewerobject.h"
+
+const LLColor4U DEFAULT_WHITE(255, 255, 255);
+
+/// LLFloaterGLTFAssetEditor
+
+LLFloaterGLTFAssetEditor::LLFloaterGLTFAssetEditor(const LLSD& key)
+ : LLFloater(key)
+ , mUIColor(LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE))
+{
+ setTitle("GLTF Asset Editor (WIP)");
+
+ mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", [this](LLUICtrl* ctrl, const LLSD& data) { onMenuDoToSelected(data); });
+ mEnableCallbackRegistrar.add("PanelObject.menuEnable", [this](LLUICtrl* ctrl, const LLSD& data) { return onMenuEnableItem(data); });
+}
+
+LLFloaterGLTFAssetEditor::~LLFloaterGLTFAssetEditor()
+{
+ gIdleCallbacks.deleteFunction(idle, this);
+
+ if (mScroller)
+ {
+ removeChild(mScroller);
+ delete mScroller;
+ mScroller = NULL;
+ }
+}
+
+bool LLFloaterGLTFAssetEditor::postBuild()
+{
+ // Position
+ mMenuClipboardPos = getChild("clipboard_pos_btn");
+ mCtrlPosX = getChild("Pos X", true);
+ mCtrlPosX->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
+ mCtrlPosY = getChild("Pos Y", true);
+ mCtrlPosY->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
+ mCtrlPosZ = getChild("Pos Z", true);
+ mCtrlPosZ->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
+
+ // Scale
+ mMenuClipboardScale = getChild("clipboard_size_btn");
+ mCtrlScaleX = getChild("Scale X", true);
+ mCtrlScaleX->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
+ mCtrlScaleY = getChild("Scale Y", true);
+ mCtrlScaleY->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
+ mCtrlScaleZ = getChild("Scale Z", true);
+ mCtrlScaleZ->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
+
+ // Rotation
+ mMenuClipboardRot = getChild("clipboard_rot_btn");
+ mCtrlRotX = getChild("Rot X", true);
+ mCtrlRotX->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
+ mCtrlRotY = getChild("Rot Y", true);
+ mCtrlRotY->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
+ mCtrlRotZ = getChild("Rot Z", true);
+ mCtrlPosZ->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
+ setTransformsEnabled(false);
+ // todo: do multiple panels based on selected element.
+ mTransformsPanel = getChild("transform_panel", true);
+ mTransformsPanel->setVisible(false);
+
+ mItemListPanel = getChild("item_list_panel", true);
+ initFolderRoot();
+
+ return true;
+}
+
+void LLFloaterGLTFAssetEditor::initFolderRoot()
+{
+ if (mScroller || mFolderRoot)
+ {
+ LL_ERRS() << "Folder root already initialized" << LL_ENDL;
+ return;
+ }
+
+ LLRect scroller_view_rect = mItemListPanel->getRect();
+ scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
+ LLScrollContainer::Params scroller_params(LLUICtrlFactory::getDefaultParams());
+ scroller_params.rect(scroller_view_rect);
+ scroller_params.name("folder_scroller");
+ mScroller = LLUICtrlFactory::create(scroller_params);
+ mScroller->setFollowsAll();
+
+ // Insert that scroller into the panel widgets hierarchy
+ mItemListPanel->addChild(mScroller);
+
+ // Create the root model and view for all conversation sessions
+ LLGLTFFolderItem* base_item = new LLGLTFFolderItem(mGLTFViewModel);
+
+ LLFolderView::Params p(LLUICtrlFactory::getDefaultParams());
+ p.name = "Root";
+ p.title = "Root";
+ p.rect = LLRect(0, 0, getRect().getWidth(), 0);
+ p.parent_panel = mItemListPanel;
+ p.tool_tip = p.name;
+ p.listener = base_item;
+ p.view_model = &mGLTFViewModel;
+ p.root = NULL;
+ p.use_ellipses = true;
+ p.options_menu = "menu_gltf.xml"; // *TODO : create this or fix to be optional
+ mFolderRoot = LLUICtrlFactory::create(p);
+ mFolderRoot->setCallbackRegistrar(&mCommitCallbackRegistrar);
+ mFolderRoot->setEnableRegistrar(&mEnableCallbackRegistrar);
+ // Attach root to the scroller
+ mScroller->addChild(mFolderRoot);
+ mFolderRoot->setScrollContainer(mScroller);
+ mFolderRoot->setFollowsAll();
+ mFolderRoot->setOpen(true);
+ mFolderRoot->setSelectCallback([this](const std::deque& items, bool user_action) { onFolderSelectionChanged(items, user_action); });
+ mScroller->setVisible(true);
+
+ gIdleCallbacks.addFunction(idle, this);
+}
+
+void LLFloaterGLTFAssetEditor::onOpen(const LLSD& key)
+{
+ loadFromSelection();
+}
+
+void LLFloaterGLTFAssetEditor::idle(void* user_data)
+{
+ LLFloaterGLTFAssetEditor* floater = (LLFloaterGLTFAssetEditor*)user_data;
+
+ if (floater->mFolderRoot)
+ {
+ floater->mFolderRoot->update();
+ }
+}
+
+void LLFloaterGLTFAssetEditor::loadItem(S32 id, const std::string& name, LLGLTFFolderItem::EType type, LLFolderViewFolder* parent)
+{
+ LLGLTFFolderItem* listener = new LLGLTFFolderItem(id, name, type, mGLTFViewModel);
+
+ LLFolderViewItem::Params params;
+ params.name(name);
+ params.creation_date(0);
+ params.root(mFolderRoot);
+ params.listener(listener);
+ params.rect(LLRect());
+ params.tool_tip = params.name;
+ params.font_color = mUIColor;
+ params.font_highlight_color = mUIColor;
+ LLFolderViewItem* view = LLUICtrlFactory::create(params);
+
+ view->addToFolder(parent);
+ view->setVisible(true);
+}
+
+void LLFloaterGLTFAssetEditor::loadFromNode(S32 node_id, LLFolderViewFolder* parent)
+{
+ if (mAsset->mNodes.size() <= node_id)
+ {
+ return;
+ }
+
+ LL::GLTF::Node& node = mAsset->mNodes[node_id];
+
+ std::string name = node.mName;
+ if (node.mName.empty())
+ {
+ name = getString("node_tittle");
+ }
+ else
+ {
+ name = node.mName;
+ }
+
+ LLGLTFFolderItem* listener = new LLGLTFFolderItem(node_id, name, LLGLTFFolderItem::TYPE_NODE, mGLTFViewModel);
+
+ LLFolderViewFolder::Params p;
+ p.root = mFolderRoot;
+ p.listener = listener;
+ p.name = name;
+ p.tool_tip = name;
+ p.font_color = mUIColor;
+ p.font_highlight_color = mUIColor;
+ LLFolderViewFolder* view = LLUICtrlFactory::create(p);
+
+ view->addToFolder(parent);
+ view->setVisible(true);
+ view->setOpen(true);
+
+ for (S32& node_id : node.mChildren)
+ {
+ loadFromNode(node_id, view);
+ }
+
+ if (node.mMesh != LL::GLTF::INVALID_INDEX && mAsset->mMeshes.size() > node.mMesh)
+ {
+ std::string name = mAsset->mMeshes[node.mMesh].mName;
+ if (name.empty())
+ {
+ name = getString("mesh_tittle");
+ }
+ loadItem(node.mMesh, name, LLGLTFFolderItem::TYPE_MESH, view);
+ }
+
+ if (node.mSkin != LL::GLTF::INVALID_INDEX && mAsset->mSkins.size() > node.mSkin)
+ {
+ std::string name = mAsset->mSkins[node.mSkin].mName;
+ if (name.empty())
+ {
+ name = getString("skin_tittle");
+ }
+ loadItem(node.mSkin, name, LLGLTFFolderItem::TYPE_SKIN, view);
+ }
+
+ view->setChildrenInited(true);
+}
+
+void LLFloaterGLTFAssetEditor::loadFromSelection()
+{
+ if (!mFolderRoot || LLSelectMgr::getInstance()->getSelection()->getObjectCount() != 1)
+ {
+ return;
+ }
+
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(NULL);
+ LLViewerObject* objectp = node->getObject();
+ if (!objectp)
+ {
+ return;
+ }
+
+ mAsset = objectp->mGLTFAsset;
+ if (!mAsset)
+ {
+ return;
+ }
+
+ if (node->mName.empty())
+ {
+ setTitle(getString("floater_title"));
+ }
+ else
+ {
+ setTitle(node->mName);
+ }
+
+ LLUIColor item_color = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
+ for (S32 i = 0; i < mAsset->mScenes.size(); i++)
+ {
+ LL::GLTF::Scene& scene = mAsset->mScenes[i];
+ std::string name = scene.mName;
+ if (scene.mName.empty())
+ {
+ name = getString("scene_tittle");
+ }
+ else
+ {
+ name = scene.mName;
+ }
+
+ LLGLTFFolderItem* listener = new LLGLTFFolderItem(i, name, LLGLTFFolderItem::TYPE_SCENE, mGLTFViewModel);
+
+
+ LLFolderViewFolder::Params p;
+ p.name = name;
+ p.root = mFolderRoot;
+ p.listener = listener;
+ p.tool_tip = name;
+ p.font_color = mUIColor;
+ p.font_highlight_color = mUIColor;
+ LLFolderViewFolder* view = LLUICtrlFactory::create(p);
+
+ view->addToFolder(mFolderRoot);
+ view->setVisible(true);
+ view->setOpen(true);
+
+ for (S32& node_id : scene.mNodes)
+ {
+ loadFromNode(node_id, view);
+ }
+ view->setChildrenInited(true);
+ }
+
+ mGLTFViewModel.requestSortAll();
+ mFolderRoot->setChildrenInited(true);
+ mFolderRoot->arrangeAll();
+ mFolderRoot->update();
+}
+
+void LLFloaterGLTFAssetEditor::onFolderSelectionChanged(const std::deque& items, bool user_action)
+{
+ if (items.empty())
+ {
+ setTransformsEnabled(false);
+ return;
+ }
+
+ LLFolderViewItem* item = items.front();
+ LLGLTFFolderItem* vmi = static_cast(item->getViewModelItem());
+
+ switch (vmi->getType())
+ {
+ case LLGLTFFolderItem::TYPE_NODE:
+ {
+ setTransformsEnabled(true);
+ loadNodeTransforms(vmi->getItemId());
+ break;
+ }
+ default:
+ {
+ setTransformsEnabled(false);
+ break;
+ }
+ }
+}
+
+void LLFloaterGLTFAssetEditor::setTransformsEnabled(bool val)
+{
+ mMenuClipboardPos->setEnabled(val);
+ mCtrlPosX->setEnabled(val);
+ mCtrlPosY->setEnabled(val);
+ mCtrlPosZ->setEnabled(val);
+ mMenuClipboardScale->setEnabled(val);
+ mCtrlScaleX->setEnabled(val);
+ mCtrlScaleY->setEnabled(val);
+ mCtrlScaleZ->setEnabled(val);
+ mMenuClipboardRot->setEnabled(val);
+ mCtrlRotX->setEnabled(val);
+ mCtrlRotY->setEnabled(val);
+ mCtrlRotZ->setEnabled(val);
+}
+
+void LLFloaterGLTFAssetEditor::loadNodeTransforms(S32 node_id)
+{
+ if (node_id < 0 || node_id >= mAsset->mNodes.size())
+ {
+ LL_ERRS() << "Node id out of range: " << node_id << LL_ENDL;
+ return;
+ }
+
+ LL::GLTF::Node& node = mAsset->mNodes[node_id];
+
+ mCtrlPosX->set(node.mTranslation[0]);
+ mCtrlPosY->set(node.mTranslation[1]);
+ mCtrlPosZ->set(node.mTranslation[2]);
+
+ mCtrlScaleX->set(node.mScale[0]);
+ mCtrlScaleY->set(node.mScale[1]);
+ mCtrlScaleZ->set(node.mScale[2]);
+
+ LLQuaternion object_rot = LLQuaternion(node.mRotation[0], node.mRotation[1], node.mRotation[2], node.mRotation[3]);
+ object_rot.getEulerAngles(&(mLastEulerDegrees.mV[VX]), &(mLastEulerDegrees.mV[VY]), &(mLastEulerDegrees.mV[VZ]));
+ mLastEulerDegrees *= RAD_TO_DEG;
+ mLastEulerDegrees.mV[VX] = fmod(ll_round(mLastEulerDegrees.mV[VX], OBJECT_ROTATION_PRECISION) + 360.f, 360.f);
+ mLastEulerDegrees.mV[VY] = fmod(ll_round(mLastEulerDegrees.mV[VY], OBJECT_ROTATION_PRECISION) + 360.f, 360.f);
+ mLastEulerDegrees.mV[VZ] = fmod(ll_round(mLastEulerDegrees.mV[VZ], OBJECT_ROTATION_PRECISION) + 360.f, 360.f);
+
+ mCtrlRotX->set(mLastEulerDegrees.mV[VX]);
+ mCtrlRotY->set(mLastEulerDegrees.mV[VY]);
+ mCtrlRotZ->set(mLastEulerDegrees.mV[VZ]);
+}
+
+void LLFloaterGLTFAssetEditor::onCommitTransform()
+{
+ if (!mFolderRoot)
+ {
+ LL_ERRS() << "Folder root not initialized" << LL_ENDL;
+ return;
+ }
+
+ LLFolderViewItem* item = mFolderRoot->getCurSelectedItem();
+ if (!item)
+ {
+ LL_ERRS() << "Nothing selected" << LL_ENDL;
+ return;
+ }
+
+ LLGLTFFolderItem* vmi = static_cast(item->getViewModelItem());
+
+ if (!vmi || vmi->getType() != LLGLTFFolderItem::TYPE_NODE)
+ {
+ LL_ERRS() << "Only nodes implemented" << LL_ENDL;
+ return;
+ }
+ S32 node_id = vmi->getItemId();
+ LL::GLTF::Node& node = mAsset->mNodes[node_id];
+
+ LL::GLTF::vec3 tr(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get());
+ node.setTranslation(tr);
+
+ LL::GLTF::vec3 scale(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get());
+ node.setScale(scale);
+
+ LLVector3 new_rot(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get());
+ new_rot.mV[VX] = ll_round(new_rot.mV[VX], OBJECT_ROTATION_PRECISION);
+ new_rot.mV[VY] = ll_round(new_rot.mV[VY], OBJECT_ROTATION_PRECISION);
+ new_rot.mV[VZ] = ll_round(new_rot.mV[VZ], OBJECT_ROTATION_PRECISION);
+
+ // Note: must compare before conversion to radians, some value can go 'around' 360
+ LLVector3 delta = new_rot - mLastEulerDegrees;
+
+ if (delta.magVec() >= 0.0005f)
+ {
+ mLastEulerDegrees = new_rot;
+ new_rot *= DEG_TO_RAD;
+
+ LLQuaternion rotation;
+ rotation.setQuat(new_rot.mV[VX], new_rot.mV[VY], new_rot.mV[VZ]);
+ LL::GLTF::quat q;
+ q[0] = rotation.mQ[VX];
+ q[1] = rotation.mQ[VY];
+ q[2] = rotation.mQ[VZ];
+ q[3] = rotation.mQ[VW];
+
+ node.setRotation(q);
+ }
+
+ mAsset->updateTransforms();
+}
+
+void LLFloaterGLTFAssetEditor::onMenuDoToSelected(const LLSD& userdata)
+{
+ std::string command = userdata.asString();
+
+ if (command == "psr_paste")
+ {
+ // todo: implement
+ // onPastePos();
+ // onPasteSize();
+ // onPasteRot();
+ }
+ else if (command == "pos_paste")
+ {
+ // todo: implement
+ }
+ else if (command == "size_paste")
+ {
+ // todo: implement
+ }
+ else if (command == "rot_paste")
+ {
+ // todo: implement
+ }
+ else if (command == "psr_copy")
+ {
+ // onCopyPos();
+ // onCopySize();
+ // onCopyRot();
+ }
+ else if (command == "pos_copy")
+ {
+ // todo: implement
+ }
+ else if (command == "size_copy")
+ {
+ // todo: implement
+ }
+ else if (command == "rot_copy")
+ {
+ // todo: implement
+ }
+}
+
+bool LLFloaterGLTFAssetEditor::onMenuEnableItem(const LLSD& userdata)
+{
+ if (!mFolderRoot)
+ {
+ return false;
+ }
+
+ LLFolderViewItem* item = mFolderRoot->getCurSelectedItem();
+ if (!item)
+ {
+ return false;
+ }
+
+ LLGLTFFolderItem* vmi = static_cast(item->getViewModelItem());
+
+ if (!vmi || vmi->getType() != LLGLTFFolderItem::TYPE_NODE)
+ {
+ return false;
+ }
+
+ std::string command = userdata.asString();
+ if (command == "pos_paste" || command == "size_paste" || command == "rot_paste")
+ {
+ // todo: implement
+ return true;
+ }
+ if (command == "psr_copy")
+ {
+ // todo: implement
+ return true;
+ }
+
+ return false;
+}
+
diff --git a/indra/newview/llfloatergltfasseteditor.h b/indra/newview/llfloatergltfasseteditor.h
new file mode 100644
index 0000000000..e35ed30ed0
--- /dev/null
+++ b/indra/newview/llfloatergltfasseteditor.h
@@ -0,0 +1,101 @@
+/**
+ * @file llfloatergltfasseteditor.h
+ * @author Andrii Kleshchev
+ * @brief LLFloaterGltfAssetEditor header file
+ *
+ * $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$
+ */
+
+#ifndef LL_LLFLOATERGLTFASSETEDITOR_H
+#define LL_LLFLOATERGLTFASSETEDITOR_H
+
+#include "llfloater.h"
+
+#include "llgltffoldermodel.h"
+
+namespace LL
+{
+ namespace GLTF
+ {
+ class Asset;
+ }
+}
+
+class LLSpinCtrl;
+class LLMenuButton;
+
+class LLFloaterGLTFAssetEditor : public LLFloater
+{
+public:
+ LLFloaterGLTFAssetEditor(const LLSD& key);
+ ~LLFloaterGLTFAssetEditor();
+
+ bool postBuild() override;
+ void onOpen(const LLSD& key) override;
+ void initFolderRoot();
+
+ LLGLTFViewModel& getRootViewModel() { return mGLTFViewModel; }
+
+ static void idle(void* user_data);
+ void loadItem(S32 id, const std::string& name, LLGLTFFolderItem::EType type, LLFolderViewFolder* parent);
+ void loadFromNode(S32 node, LLFolderViewFolder* parent);
+ void loadFromSelection();
+
+protected:
+ void onFolderSelectionChanged(const std::deque& items, bool user_action);
+ void onCommitTransform();
+ void onMenuDoToSelected(const LLSD& userdata);
+ bool onMenuEnableItem(const LLSD& userdata);
+
+ void setTransformsEnabled(bool val);
+ void loadNodeTransforms(S32 id);
+
+private:
+
+ std::shared_ptr mAsset;
+
+ // Folder view related
+ LLUIColor mUIColor;
+ LLGLTFViewModel mGLTFViewModel;
+ LLPanel* mItemListPanel = nullptr;
+ LLFolderView* mFolderRoot = nullptr;
+ LLScrollContainer* mScroller = nullptr;
+
+ // Transforms panel
+ LLVector3 mLastEulerDegrees;
+
+ LLPanel* mTransformsPanel = nullptr;
+ LLMenuButton* mMenuClipboardPos = nullptr;
+ LLSpinCtrl* mCtrlPosX = nullptr;
+ LLSpinCtrl* mCtrlPosY = nullptr;
+ LLSpinCtrl* mCtrlPosZ = nullptr;
+ LLMenuButton* mMenuClipboardScale = nullptr;
+ LLSpinCtrl* mCtrlScaleX = nullptr;
+ LLSpinCtrl* mCtrlScaleY = nullptr;
+ LLSpinCtrl* mCtrlScaleZ = nullptr;
+ LLMenuButton* mMenuClipboardRot = nullptr;
+ LLSpinCtrl* mCtrlRotX = nullptr;
+ LLSpinCtrl* mCtrlRotY = nullptr;
+ LLSpinCtrl* mCtrlRotZ = nullptr;
+};
+
+#endif
diff --git a/indra/newview/llgltffolderitem.cpp b/indra/newview/llgltffolderitem.cpp
new file mode 100644
index 0000000000..77a19c060d
--- /dev/null
+++ b/indra/newview/llgltffolderitem.cpp
@@ -0,0 +1,164 @@
+/**
+ * @file llgltffolderitem.cpp
+ * @author Andrey Kleshchev
+ * @brief LLGLTFFolderItem class implementation
+ *
+ * $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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llgltffolderitem.h"
+
+#include "llinventoryicon.h"
+
+/// LLGLTFItem
+
+LLGLTFFolderItem::LLGLTFFolderItem(S32 id, const std::string &display_name, EType type, LLFolderViewModelInterface& root_view_model)
+ : LLFolderViewModelItemCommon(root_view_model)
+ , mName(display_name)
+ , mItemType(type)
+ , mItemId(id)
+{
+ init();
+}
+
+LLGLTFFolderItem::LLGLTFFolderItem(LLFolderViewModelInterface& root_view_model)
+ : LLFolderViewModelItemCommon(root_view_model)
+{
+ init();
+}
+
+LLGLTFFolderItem::~LLGLTFFolderItem()
+{
+
+}
+
+void LLGLTFFolderItem::init()
+{
+ // using inventory icons as a placeholder.
+ // Todo: GLTF needs to have own icons
+ switch (mItemType)
+ {
+ case TYPE_SCENE:
+ pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_OBJECT_MULTI);
+ break;
+ case TYPE_NODE:
+ pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_OBJECT);
+ break;
+ case TYPE_MESH:
+ pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_MESH);
+ break;
+ case TYPE_SKIN:
+ pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_BODYPART_SKIN);
+ break;
+ default:
+ pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_OBJECT);
+ break;
+ }
+}
+
+
+bool LLGLTFFolderItem::filterChildItem(LLFolderViewModelItem* item, LLFolderViewFilter& filter)
+{
+ S32 filter_generation = filter.getCurrentGeneration();
+
+ bool continue_filtering = true;
+ if (item)
+ {
+ if (item->getLastFilterGeneration() < filter_generation)
+ {
+ // Recursive application of the filter for child items (CHUI-849)
+ continue_filtering = item->filter(filter);
+ }
+
+ // Update latest generation to pass filter in parent and propagate up to root
+ if (item->passedFilter())
+ {
+ LLGLTFFolderItem* view_model = this;
+
+ while (view_model && view_model->mMostFilteredDescendantGeneration < filter_generation)
+ {
+ view_model->mMostFilteredDescendantGeneration = filter_generation;
+ view_model = static_cast(view_model->mParent);
+ }
+ }
+ }
+ return continue_filtering;
+}
+
+bool LLGLTFFolderItem::filter(LLFolderViewFilter& filter)
+{
+ const S32 filter_generation = filter.getCurrentGeneration();
+ const S32 must_pass_generation = filter.getFirstRequiredGeneration();
+
+ if (getLastFilterGeneration() >= must_pass_generation
+ && getLastFolderFilterGeneration() >= must_pass_generation
+ && !passedFilter(must_pass_generation))
+ {
+ // failed to pass an earlier filter that was a subset of the current one
+ // go ahead and flag this item as not pass
+ setPassedFilter(false, filter_generation);
+ setPassedFolderFilter(false, filter_generation);
+ return true;
+ }
+
+ bool is_folder = true;
+ const bool passed_filter_folder = is_folder ? filter.checkFolder(this) : true;
+ setPassedFolderFilter(passed_filter_folder, filter_generation);
+
+ bool continue_filtering = true;
+
+ if (!mChildren.empty()
+ && (getLastFilterGeneration() < must_pass_generation // haven't checked descendants against minimum required generation to pass
+ || descendantsPassedFilter(must_pass_generation))) // or at least one descendant has passed the minimum requirement
+ {
+ // now query children
+ for (child_list_t::iterator iter = mChildren.begin(), end_iter = mChildren.end(); iter != end_iter; ++iter)
+ {
+ continue_filtering = filterChildItem((*iter), filter);
+ if (!continue_filtering)
+ {
+ break;
+ }
+ }
+ }
+
+ // If we didn't use all the filter time that means we filtered all of our descendants so we can filter ourselves now
+ if (continue_filtering)
+ {
+ // This is where filter check on the item done (CHUI-849)
+ const bool passed_filter = filter.check(this);
+ if (passed_filter && mChildren.empty() && is_folder) // Update the latest filter generation for empty folders
+ {
+ LLGLTFFolderItem* view_model = this;
+ while (view_model && view_model->mMostFilteredDescendantGeneration < filter_generation)
+ {
+ view_model->mMostFilteredDescendantGeneration = filter_generation;
+ view_model = static_cast(view_model->mParent);
+ }
+ }
+ setPassedFilter(passed_filter, filter_generation, filter.getStringMatchOffset(this), filter.getFilterStringSize());
+ continue_filtering = !filter.isTimedOut();
+ }
+ return continue_filtering;
+}
diff --git a/indra/newview/llgltffolderitem.h b/indra/newview/llgltffolderitem.h
new file mode 100644
index 0000000000..f074af46e0
--- /dev/null
+++ b/indra/newview/llgltffolderitem.h
@@ -0,0 +1,130 @@
+/**
+ * @file llgltffolderitem.h
+ * @author Andrey Kleshchev
+ * @brief LLGLTFFolderItem header file
+ *
+ * $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$
+ */
+
+#ifndef LL_LLGLTFFOLDERITEM_H
+#define LL_LLGLTFFOLDERITEM_H
+
+#include "llfloater.h"
+
+#include "llfolderviewmodel.h"
+
+class LLGLTFFolderItem : public LLFolderViewModelItemCommon
+{
+public:
+ enum EType
+ {
+ TYPE_ROOT,
+ TYPE_SCENE,
+ TYPE_NODE,
+ TYPE_MESH,
+ TYPE_SKIN,
+ };
+
+ LLGLTFFolderItem(S32 id, const std::string &display_name, EType type, LLFolderViewModelInterface& root_view_model);
+ LLGLTFFolderItem(LLFolderViewModelInterface& root_view_model);
+ virtual ~LLGLTFFolderItem();
+
+ void init();
+
+ const std::string& getName() const override { return mName; }
+ const std::string& getDisplayName() const override { return mName; }
+ const std::string& getSearchableName() const override { return mName; }
+
+ std::string getSearchableDescription() const override { return std::string(); }
+ std::string getSearchableCreatorName()const override { return std::string(); }
+ std::string getSearchableUUIDString() const override { return std::string(); }
+ std::string getSearchableAll() const override { return std::string(); }; // Zi's extended inventory search
+
+
+ LLPointer getIcon() const override { return pIcon; }
+ LLPointer getIconOpen() const override { return getIcon(); }
+ LLPointer getIconOverlay() const override { return NULL; }
+
+ LLFontGL::StyleFlags getLabelStyle() const override { return LLFontGL::NORMAL; }
+ std::string getLabelSuffix() const override { return std::string(); }
+
+ void openItem(void) override {}
+ void closeItem(void) override {}
+ void selectItem(void) override {}
+
+ void navigateToFolder(bool new_window = false, bool change_mode = false) override {}
+
+ bool isItemWearable() const override { return false; }
+
+ bool isItemRenameable() const override { return false; }
+ bool renameItem(const std::string& new_name) override { return false; }
+
+ bool isItemMovable(void) const override { return false; } // Can be moved to another folder
+ void move(LLFolderViewModelItem* parent_listener) override {}
+
+ bool isItemRemovable(bool check_worn = true) const override { return false; }
+ bool removeItem() override { return false; }
+ void removeBatch(std::vector& batch) override {}
+
+ bool isItemCopyable(bool can_copy_as_link = true) const override { return false; }
+ bool copyToClipboard() const override { return false; }
+ bool cutToClipboard() override { return false; }
+ bool isCutToClipboard() override { return false; }
+
+ bool isClipboardPasteable() const override { return false; }
+ void pasteFromClipboard() override {}
+ void pasteLinkFromClipboard() override {}
+
+ void buildContextMenu(LLMenuGL& menu, U32 flags) override {};
+
+ bool potentiallyVisible() override { return true; }; // is the item definitely visible or we haven't made up our minds yet?
+
+ bool hasChildren() const override { return mChildren.size() > 0; }
+
+ bool dragOrDrop(
+ MASK mask,
+ bool drop,
+ EDragAndDropType cargo_type,
+ void* cargo_data,
+ std::string& tooltip_msg) override
+ {
+ return false;
+ }
+
+ bool filterChildItem(LLFolderViewModelItem* item, LLFolderViewFilter& filter);
+ bool filter(LLFolderViewFilter& filter) override;
+
+ EType getType() const { return mItemType; }
+ S32 getItemId() const { return mItemId; }
+
+private:
+ LLUIImagePtr pIcon;
+ std::string mName;
+ EType mItemType = TYPE_ROOT;
+
+ // mItemId can be an id in a mesh vector, node vector or any other vector.
+ // mItemId is not nessesarily unique, ex: some nodes can reuse the same
+ // mesh or skin, so mesh-items can have the same id.
+ S32 mItemId = -1;
+};
+
+#endif
diff --git a/indra/newview/llgltffoldermodel.cpp b/indra/newview/llgltffoldermodel.cpp
new file mode 100644
index 0000000000..de2510dc4a
--- /dev/null
+++ b/indra/newview/llgltffoldermodel.cpp
@@ -0,0 +1,73 @@
+/**
+ * @file llgltffoldermodel.cpp
+ * @author Andrey Kleshchev
+ * @brief gltf model's folder structure related classes
+ *
+ * $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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llgltffoldermodel.h"
+
+#include "llfolderviewitem.h"
+
+bool LLGLTFSort::operator()(const LLGLTFFolderItem* const& a, const LLGLTFFolderItem* const& b) const
+{
+ // Comparison operator: returns "true" is a comes before b, "false" otherwise
+ S32 compare = LLStringUtil::compareDict(a->getName(), b->getName());
+ return (compare < 0);
+}
+
+/// LLGLTFViewModel
+
+LLGLTFViewModel::LLGLTFViewModel()
+ : base_t(new LLGLTFSort(), new LLGLTFFilter())
+{}
+
+void LLGLTFViewModel::sort(LLFolderViewFolder* folder)
+{
+ base_t::sort(folder);
+}
+
+ /// LLGLTFNode
+// LLUICtrlFactory::create(params);
+class LLGLTFNode : public LLFolderViewItem
+{
+public:
+ struct Params : public LLInitParam::Block
+ {
+ Params();
+ };
+ ~LLGLTFNode();
+protected:
+ LLGLTFNode(const Params& p);
+};
+
+LLGLTFNode::LLGLTFNode(const LLGLTFNode::Params& p)
+ : LLFolderViewItem(p)
+{
+}
+
+LLGLTFNode::~LLGLTFNode()
+{
+}
diff --git a/indra/newview/llgltffoldermodel.h b/indra/newview/llgltffoldermodel.h
new file mode 100644
index 0000000000..69b284aa31
--- /dev/null
+++ b/indra/newview/llgltffoldermodel.h
@@ -0,0 +1,91 @@
+/**
+ * @file llfloatergltfasseteditor.h
+ * @author Andrey Kleshchev
+ * @brief gltf model's folder structure related classes
+ *
+ * $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$
+ */
+
+#ifndef LL_LLGLTFFOLDERMODEL_H
+#define LL_LLGLTFFOLDERMODEL_H
+
+#include "llfolderviewmodel.h"
+#include "llgltffolderitem.h"
+
+class LLGLTFSort
+{
+public:
+ LLGLTFSort() { }
+ bool operator()(const LLGLTFFolderItem* const& a, const LLGLTFFolderItem* const& b) const;
+private:
+};
+
+class LLGLTFFilter : public LLFolderViewFilter
+{
+public:
+ LLGLTFFilter() { mEmpty = ""; }
+ ~LLGLTFFilter() {}
+
+ bool check(const LLFolderViewModelItem* item) { return true; }
+ bool checkFolder(const LLFolderViewModelItem* folder) const { return true; }
+ void setEmptyLookupMessage(const std::string& message) { }
+ std::string getEmptyLookupMessage(bool is_empty_folder = false) const { return mEmpty; }
+ bool showAllResults() const { return true; }
+ std::string::size_type getStringMatchOffset(LLFolderViewModelItem* item) const { return std::string::npos; }
+ std::string::size_type getFilterStringSize() const { return 0; }
+
+ bool isActive() const { return false; }
+ bool isModified() const { return false; }
+ void clearModified() { }
+ const std::string& getName() const { return mEmpty; }
+ const std::string& getFilterText() { return mEmpty; }
+ void setModified(EFilterModified behavior = FILTER_RESTART) { }
+
+ void resetTime(S32 timeout) { }
+ bool isTimedOut() { return false; }
+
+ bool isDefault() const { return true; }
+ bool isNotDefault() const { return false; }
+ void markDefault() { }
+ void resetDefault() { }
+
+ S32 getCurrentGeneration() const { return 0; }
+ S32 getFirstSuccessGeneration() const { return 0; }
+ S32 getFirstRequiredGeneration() const { return 0; }
+private:
+ std::string mEmpty;
+};
+
+class LLGLTFViewModel
+ : public LLFolderViewModel
+{
+public:
+ typedef LLFolderViewModel< LLGLTFSort, LLGLTFFolderItem, LLGLTFFolderItem, LLGLTFFilter> base_t;
+ LLGLTFViewModel();
+
+ void sort(LLFolderViewFolder* folder);
+ bool startDrag(std::vector& items) { return false; }
+
+private:
+};
+
+#endif
diff --git a/indra/newview/llheroprobemanager.cpp b/indra/newview/llheroprobemanager.cpp
index 552edcbcb7..c352a36670 100644
--- a/indra/newview/llheroprobemanager.cpp
+++ b/indra/newview/llheroprobemanager.cpp
@@ -121,7 +121,7 @@ void LLHeroProbeManager::update()
// Find our nearest hero candidate.
float last_distance = 99999.f;
float camera_center_distance = 99999.f;
- mNearestHero = nullptr; // LL-1719/1721 Mirrors do not disable properly (interim fix)
+ mNearestHero = nullptr;
for (auto vo : mHeroVOList)
{
if (vo && !vo->isDead() && vo->mDrawable.notNull() && vo->isReflectionProbe() && vo->getReflectionProbeIsBox())
@@ -211,18 +211,16 @@ void LLHeroProbeManager::update()
else
{
mNearestHero = nullptr;
- mDefaultProbe->mViewerObject = nullptr; // FIRE-34201 TP crash
+ mDefaultProbe->mViewerObject = nullptr;
}
mHeroProbeStrength = 1;
}
- // LL-1719/1721 Mirrors do not disable properly (interim fix)
else
{
mNearestHero = nullptr;
- mDefaultProbe->mViewerObject = nullptr; // FIRE-34201 TP crash
+ mDefaultProbe->mViewerObject = nullptr;
}
- //
}
void LLHeroProbeManager::renderProbes()
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index f7ed9c4846..a6d2f02e9e 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -3903,11 +3903,11 @@ LLUUID LLIMMgr::addSession(
((IM_NOTHING_SPECIAL == dialog) || (IM_SESSION_P2P_INVITE == dialog) || (IM_SESSION_CONFERENCE_START == dialog)) &&
ids.size())
{
- LLIMModel::LLIMSession* ad_hoc_found = LLIMModel::getInstance()->findAdHocIMSession(ids);
- if (ad_hoc_found)
+ session = LLIMModel::getInstance()->findAdHocIMSession(ids);
+ if (session)
{
new_session = false;
- session_id = ad_hoc_found->mSessionID;
+ session_id = session->mSessionID;
}
}
@@ -4415,7 +4415,7 @@ bool LLIMMgr::startCall(const LLUUID& session_id, LLVoiceChannel::EDirection dir
{
LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(session_id);
if (!voice_channel) return false;
- if (!voice_channel_info.isUndefined())
+ if (voice_channel_info.isDefined() && voice_channel_info.isMap() && voice_channel_info.size() > 0)
{
voice_channel->setChannelInfo(voice_channel_info);
}
diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp
index b06e406013..f3906c05ae 100644
--- a/indra/newview/lllocalbitmaps.cpp
+++ b/indra/newview/lllocalbitmaps.cpp
@@ -215,7 +215,6 @@ bool LLLocalBitmap::updateSelf(EUpdateType optional_firstupdate)
("file://"+mFilename, FTT_LOCAL_FILE, mWorldID, LL_LOCAL_USE_MIPMAPS);
texture->createGLTexture(LL_LOCAL_DISCARD_LEVEL, raw_image);
- texture->setCachedRawImage(LL_LOCAL_DISCARD_LEVEL, raw_image);
texture->ref();
gTextureList.addImage(texture, TEX_LIST_STANDARD);
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 9aa6b22aec..0ebfcca5c4 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -33,9 +33,6 @@
#include "stringize.h"
#include "llsdserialize.h"
-// llmessage (!)
-#include "llfiltersd2xmlrpc.h" // for xml_escape_string()
-
// login
#include "lllogin.h"
@@ -628,7 +625,7 @@ std::string construct_start_string()
<< position[VX] << "&"
<< position[VY] << "&"
<< position[VZ]);
- start = xml_escape_string(unescaped_start);
+ start = LLStringFn::xml_encode(unescaped_start, true);
break;
}
case LLSLURL::HOME_LOCATION:
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index 2a57c15954..3423329905 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -89,6 +89,7 @@
#include "fsradar.h"
#include "lggcontactsets.h"
#include "fscommon.h"
+#include "llstartup.h"
static LLDefaultChildRegistry::Register r1("net_map");
@@ -547,45 +548,6 @@ void LLNetMap::draw()
}
gGL.end();
//
-
- // Draw water
- gGL.flush();
- {
- if (regionp->getLand().getWaterTexture())
- {
- gGL.getTexUnit(0)->bind(regionp->getLand().getWaterTexture());
- // Remove QUADS rendering mode
- //gGL.begin(LLRender::QUADS);
- // gGL.texCoord2f(0.f, 1.f);
- // gGL.vertex2f(left, top);
- // gGL.texCoord2f(0.f, 0.f);
- // gGL.vertex2f(left, bottom);
- // gGL.texCoord2f(1.f, 0.f);
- // gGL.vertex2f(right, bottom);
- // gGL.texCoord2f(1.f, 1.f);
- // gGL.vertex2f(right, top);
- //gGL.end();
- gGL.begin(LLRender::TRIANGLES);
- {
- gGL.texCoord2f(0.f, 1.f);
- gGL.vertex2f(left, top);
- gGL.texCoord2f(0.f, 0.f);
- gGL.vertex2f(left, bottom);
- gGL.texCoord2f(1.f, 0.f);
- gGL.vertex2f(right, bottom);
-
- gGL.texCoord2f(0.f, 1.f);
- gGL.vertex2f(left, top);
- gGL.texCoord2f(1.f, 0.f);
- gGL.vertex2f(right, bottom);
- gGL.texCoord2f(1.f, 1.f);
- gGL.vertex2f(right, top);
- }
- gGL.end();
- //
- }
- }
- gGL.flush();
// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-07-26 (Catznip-3.3)
}
gGL.flush();
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index c0af825278..1ed31c322a 100644
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -151,6 +151,7 @@ bool LLPanelVolume::postBuild()
{
childSetCommitCallback("Reflection Probe", onCommitIsReflectionProbe, this);
childSetCommitCallback("Probe Update Type", onCommitProbe, this);
+ childSetCommitCallback("Probe Dynamic", onCommitProbe, this);
childSetCommitCallback("Probe Volume Type", onCommitProbe, this);
childSetCommitCallback("Probe Ambiance", onCommitProbe, this);
childSetCommitCallback("Probe Near Clip", onCommitProbe, this);
@@ -416,6 +417,7 @@ void LLPanelVolume::getState( )
getChild("Probe Ambiance", true)->clear();
getChild("Probe Near Clip", true)->clear();
getChild("Probe Update Type", true)->clear();
+ getChild("Probe Dynamic")->setValue(false);
}
else
{
@@ -450,6 +452,7 @@ void LLPanelVolume::getState( )
getChild("Probe Ambiance", true)->setValue(volobjp->getReflectionProbeAmbiance());
getChild("Probe Near Clip", true)->setValue(volobjp->getReflectionProbeNearClip());
getChild("Probe Update Type", true)->setValue(update_type);
+ getChild("Probe Dynamic")->setValue(volobjp->getReflectionProbeIsDynamic());
}
// Animated Mesh
@@ -741,6 +744,7 @@ void LLPanelVolume::clearCtrls()
getChildView("Reflection Probe")->setEnabled(false);;
getChildView("Probe Volume Type")->setEnabled(false);
getChildView("Probe Update Type")->setEnabled(false);
+ getChildView("Probe Dynamic")->setEnabled(false);
getChildView("Probe Ambiance")->setEnabled(false);
getChildView("Probe Near Clip")->setEnabled(false);
getChildView("Animated Mesh Checkbox Ctrl")->setEnabled(false);
@@ -1488,15 +1492,26 @@ void LLPanelVolume::onCommitProbe(LLUICtrl* ctrl, void* userdata)
volobjp->setReflectionProbeAmbiance((F32)self->getChild("Probe Ambiance")->getValue().asReal());
volobjp->setReflectionProbeNearClip((F32)self->getChild("Probe Near Clip")->getValue().asReal());
- std::string update_type = self->getChild("Probe Update Type")->getValue().asString();
+ bool mirrors_enabled = LLPipeline::RenderMirrors;
+ bool is_mirror = false;
- bool is_mirror = update_type.find("Mirror") != std::string::npos;
+ if (mirrors_enabled)
+ {
+ std::string update_type = self->getChild("Probe Update Type")->getValue().asString();
+
+ is_mirror = update_type.find("Mirror") != std::string::npos;
+
+ volobjp->setReflectionProbeIsDynamic(update_type.find("Dynamic") != std::string::npos);
+ volobjp->setReflectionProbeIsMirror(is_mirror);
+ }
+ else
+ {
+ is_mirror = volobjp->getReflectionProbeIsMirror();
+ bool is_dynamic = self->getChild("Probe Dynamic")->getValue().asBoolean();
+ volobjp->setReflectionProbeIsDynamic(is_dynamic);
+ }
self->getChildView("Probe Volume Type")->setEnabled(!is_mirror);
-
- volobjp->setReflectionProbeIsDynamic(update_type.find("Dynamic") != std::string::npos);
- volobjp->setReflectionProbeIsMirror(is_mirror);
-
self->getChildView("Probe Ambiance")->setEnabled(!is_mirror);
self->getChildView("Probe Near Clip")->setEnabled(!is_mirror);
diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp
index 9ea82c47fb..1a2a7ca56b 100644
--- a/indra/newview/llslurl.cpp
+++ b/indra/newview/llslurl.cpp
@@ -32,7 +32,7 @@
#include "llpanellogin.h"
#include "llviewercontrol.h"
#include "llviewernetwork.h"
-#include "llfiltersd2xmlrpc.h"
+
#include "curl/curl.h"
#include "rlvhandler.h"
@@ -42,6 +42,7 @@ const char* LLSLURL::SLURL_HTTPS_SCHEME = "https";
const char* LLSLURL::SLURL_SECONDLIFE_SCHEME = "secondlife";
const char* LLSLURL::SLURL_SECONDLIFE_PATH = "secondlife";
const char* LLSLURL::SLURL_COM = "slurl.com";
+
// For DnD - even though www.slurl.com redirects to slurl.com in a browser, you can copy and drag
// text with www.slurl.com or a link explicitly pointing at www.slurl.com so testing for this
// version is required also.
@@ -453,7 +454,7 @@ std::string LLSLURL::getLoginString() const
LL_WARNS("AppInit") << "Unexpected SLURL type (" << (int)mType << ")for login string" << LL_ENDL;
break;
}
- return xml_escape_string(unescaped_start.str());
+ return LLStringFn::xml_encode(unescaped_start.str(), true);
}
bool LLSLURL::operator ==(const LLSLURL& rhs)
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp
index f8c04356e3..f6f0b5528f 100644
--- a/indra/newview/llsurface.cpp
+++ b/indra/newview/llsurface.cpp
@@ -54,6 +54,7 @@
#include "llglheaders.h"
#include "lldrawpoolterrain.h"
#include "lldrawable.h"
+#include "llworldmipmap.h"
extern LLPipeline gPipeline;
extern bool gShiftFrame;
@@ -74,7 +75,6 @@ LLSurface::LLSurface(U32 type, LLViewerRegion *regionp) :
mDetailTextureScale(0.f),
mOriginGlobal(0.0, 0.0, 0.0),
mSTexturep(NULL),
- mWaterTexturep(NULL),
mGridsPerPatchEdge(0),
mMetersPerGrid(1.0f),
mMetersPerEdge(1.0f),
@@ -129,14 +129,7 @@ LLSurface::~LLSurface()
{
gPipeline.removePool(poolp);
// Don't enable this until we blitz the draw pool for it as well. -- djs
- if (mSTexturep)
- {
- mSTexturep = NULL;
- }
- if (mWaterTexturep)
- {
- mWaterTexturep = NULL;
- }
+ mSTexturep = NULL;
}
else
{
@@ -229,62 +222,17 @@ LLViewerTexture* LLSurface::getSTexture()
return mSTexturep;
}
-LLViewerTexture* LLSurface::getWaterTexture()
-{
- if (mWaterTexturep.notNull() && !mWaterTexturep->hasGLTexture())
- {
- createWaterTexture();
- }
- return mWaterTexturep;
-}
-
void LLSurface::createSTexture()
{
if (!mSTexturep)
{
- // Fill with dummy gray data.
- // GL NOT ACTIVE HERE
- LLPointer raw = new LLImageRaw(sTextureSize, sTextureSize, 3);
- U8 *default_texture = raw->getData();
- for (S32 i = 0; i < sTextureSize; i++)
- {
- for (S32 j = 0; j < sTextureSize; j++)
- {
- *(default_texture + (i*sTextureSize + j)*3) = 128;
- *(default_texture + (i*sTextureSize + j)*3 + 1) = 128;
- *(default_texture + (i*sTextureSize + j)*3 + 2) = 128;
- }
- }
+ U64 handle = mRegionp->getHandle();
- mSTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), false);
- mSTexturep->dontDiscard();
- gGL.getTexUnit(0)->bind(mSTexturep);
- mSTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
- }
-}
+ U32 grid_x, grid_y;
-void LLSurface::createWaterTexture()
-{
- if (!mWaterTexturep)
- {
- // Create the water texture
- LLPointer raw = new LLImageRaw(sTextureSize/2, sTextureSize/2, 4);
- U8 *default_texture = raw->getData();
- for (S32 i = 0; i < sTextureSize/2; i++)
- {
- for (S32 j = 0; j < sTextureSize/2; j++)
- {
- *(default_texture + (i*sTextureSize/2 + j)*4) = MAX_WATER_COLOR.mV[0];
- *(default_texture + (i*sTextureSize/2 + j)*4 + 1) = MAX_WATER_COLOR.mV[1];
- *(default_texture + (i*sTextureSize/2 + j)*4 + 2) = MAX_WATER_COLOR.mV[2];
- *(default_texture + (i*sTextureSize/2 + j)*4 + 3) = MAX_WATER_COLOR.mV[3];
- }
- }
+ grid_from_region_handle(handle, &grid_x, &grid_y);
- mWaterTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), false);
- mWaterTexturep->dontDiscard();
- gGL.getTexUnit(0)->bind(mWaterTexturep);
- mWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
+ mSTexturep = LLWorldMipmap::loadObjectsTile(grid_x, grid_y, 1);
}
}
@@ -298,14 +246,13 @@ void LLSurface::initTextures()
///////////////////////
//
- // Water texture
+ // Water object
//
// Aurora Sim
//if (gSavedSettings.getBOOL("RenderWater") )
if (gSavedSettings.getBOOL("RenderWater") && LLWorld::getInstance()->getAllowRenderWater())
// Aurora Sim
{
- createWaterTexture();
mWaterObjp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, mRegionp);
gPipeline.createObject(mWaterObjp);
LLVector3d water_pos_global = from_region_handle(mRegionp->getHandle());
@@ -328,7 +275,6 @@ void LLSurface::rebuildWater()
if (!prev_renderwater && renderwater)
{
- createWaterTexture();
mWaterObjp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, mRegionp);
gPipeline.createObject(mWaterObjp);
LLVector3d water_pos_global = from_region_handle(mRegionp->getHandle());
@@ -867,11 +813,8 @@ bool LLSurface::idleUpdate(F32 max_update_time)
}
}
- if (did_update)
- {
- // some patches changed, update region reflection probes
- mRegionp->updateReflectionProbes();
- }
+ // some patches changed, update region reflection probes
+ mRegionp->updateReflectionProbes(did_update);
return did_update;
}
@@ -1420,101 +1363,3 @@ F32 LLSurface::getWaterHeight() const
}
}
-
-bool LLSurface::generateWaterTexture(const F32 x, const F32 y,
- const F32 width, const F32 height)
-{
- LL_PROFILE_ZONE_SCOPED
- if (!getWaterTexture())
- {
- return false;
- }
-
- S32 tex_width = mWaterTexturep->getWidth();
- S32 tex_height = mWaterTexturep->getHeight();
- S32 tex_comps = mWaterTexturep->getComponents();
- S32 tex_stride = tex_width * tex_comps;
- LLPointer raw = new LLImageRaw(tex_width, tex_height, tex_comps);
- U8 *rawp = raw->getData();
-
-// Aurora Sim
- //F32 scale = 256.f * getMetersPerGrid() / (F32)tex_width;
- F32 scale = getRegion()->getWidth() * getMetersPerGrid() / (F32)tex_width;
-// Aurora Sim
- F32 scale_inv = 1.f / scale;
-
- S32 x_begin, y_begin, x_end, y_end;
-
- x_begin = ll_round(x * scale_inv);
- y_begin = ll_round(y * scale_inv);
- x_end = ll_round((x + width) * scale_inv);
- y_end = ll_round((y + width) * scale_inv);
-
- if (x_end > tex_width)
- {
- x_end = tex_width;
- }
- if (y_end > tex_width)
- {
- y_end = tex_width;
- }
-
- // OK, for now, just have the composition value equal the height at the point.
- LLVector3 location;
- LLColor4U coloru;
-
- const F32 WATER_HEIGHT = getWaterHeight();
-
- S32 i, j, offset;
- for (j = y_begin; j < y_end; j++)
- {
- for (i = x_begin; i < x_end; i++)
- {
- //F32 nv[2];
- //nv[0] = i/256.f;
- //nv[1] = j/256.f;
- // const S32 modulation = noise2(nv)*40;
- offset = j*tex_stride + i*tex_comps;
- location.mV[VX] = i*scale;
- location.mV[VY] = j*scale;
-
- // Sample multiple points
- const F32 height = resolveHeightRegion(location);
-
- if (height > WATER_HEIGHT)
- {
- // Above water...
- coloru = MAX_WATER_COLOR;
- coloru.mV[3] = ABOVE_WATERLINE_ALPHA;
- *(rawp + offset++) = coloru.mV[0];
- *(rawp + offset++) = coloru.mV[1];
- *(rawp + offset++) = coloru.mV[2];
- *(rawp + offset++) = coloru.mV[3];
- }
- else
- {
- // Want non-linear curve for transparency gradient
- coloru = MAX_WATER_COLOR;
- const F32 frac = 1.f - 2.f/(2.f - (height - WATER_HEIGHT));
- S32 alpha = 64 + ll_round((255-64)*frac);
-
- alpha = llmin(ll_round((F32)MAX_WATER_COLOR.mV[3]), alpha);
- alpha = llmax(64, alpha);
-
- coloru.mV[3] = alpha;
- *(rawp + offset++) = coloru.mV[0];
- *(rawp + offset++) = coloru.mV[1];
- *(rawp + offset++) = coloru.mV[2];
- *(rawp + offset++) = coloru.mV[3];
- }
- }
- }
-
- if (!mWaterTexturep->hasGLTexture())
- {
- mWaterTexturep->createGLTexture(0, raw);
- }
-
- mWaterTexturep->setSubImage(raw, x_begin, y_begin, x_end - x_begin, y_end - y_begin);
- return true;
-}
diff --git a/indra/newview/llsurface.h b/indra/newview/llsurface.h
index 0bd4d85469..c5300757e8 100644
--- a/indra/newview/llsurface.h
+++ b/indra/newview/llsurface.h
@@ -131,7 +131,7 @@ public:
F32 getWaterHeight() const;
LLViewerTexture *getSTexture();
- LLViewerTexture *getWaterTexture();
+
bool hasZData() const { return mHasZData; }
void dirtyAllPatches(); // Use this to dirty all patches when changing terrain parameters
@@ -174,19 +174,11 @@ public:
protected:
void createSTexture();
- void createWaterTexture();
void initTextures();
- void initWater();
-
void createPatchData(); // Allocates memory for patches.
void destroyPatchData(); // Deallocates memory for patches.
- bool generateWaterTexture(const F32 x, const F32 y,
- const F32 width, const F32 height); // Generate texture from composition values.
-
- //F32 updateTexture(LLSurfacePatch *ppatch);
-
LLSurfacePatch *getPatch(const S32 x, const S32 y) const;
protected:
@@ -204,7 +196,6 @@ protected:
// The textures should never be directly initialized - use the setter methods!
LLPointer mSTexturep; // Texture for surface
- LLPointer mWaterTexturep; // Water texture
LLPointer mWaterObjp;
diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp
index dc3eec5268..16f3bbec26 100644
--- a/indra/newview/llsurfacepatch.cpp
+++ b/indra/newview/llsurfacepatch.cpp
@@ -1036,15 +1036,8 @@ void LLSurfacePatch::updateGL()
updateCompositionStats();
F32 tex_patch_size = meters_per_grid*grids_per_patch_edge;
- if (comp->generateMinimapTileLand((F32)origin_region[VX], (F32)origin_region[VY],
- tex_patch_size, tex_patch_size))
- {
- mSTexUpdate = false;
- // Also generate the water texture
- mSurfacep->generateWaterTexture((F32)origin_region.mdV[VX], (F32)origin_region.mdV[VY],
- tex_patch_size, tex_patch_size);
- }
+ mSTexUpdate = false;
}
void LLSurfacePatch::dirtyZ()
diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp
index f816dc7ec9..fa7656e81a 100644
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -59,8 +59,6 @@
#include "llvoavatarself.h"
#include "lltexlayer.h"
-extern F32 texmem_lower_bound_scale;
-
LLTextureView *gTextureView = NULL;
#define HIGH_PRIORITY 100000000.f
@@ -487,7 +485,7 @@ public:
: texture_view("texture_view")
{
S32 line_height = LLFontGL::getFontMonospace()->getLineHeight();
- changeDefault(rect, LLRect(0,0,100,line_height * 4));
+ changeDefault(rect, LLRect(0,0,0,line_height * 7));
}
};
@@ -518,19 +516,51 @@ void LLGLTexMemBar::draw()
U32 total_objects = gObjectList.getNumObjects();
F32 x_right = 0.0;
+ U32 image_count = gTextureList.getNumImages();
+ U32 raw_image_count = 0;
+ U64 raw_image_bytes = 0;
+
+ U32 saved_raw_image_count = 0;
+ U64 saved_raw_image_bytes = 0;
+
+ U32 aux_raw_image_count = 0;
+ U64 aux_raw_image_bytes = 0;
+
+ for (auto& image : gTextureList)
+ {
+ const LLImageRaw* raw_image = image->getRawImage();
+
+ if (raw_image)
+ {
+ raw_image_count++;
+ raw_image_bytes += raw_image->getDataSize();
+ }
+
+ raw_image = image->getSavedRawImage();
+ if (raw_image)
+ {
+ saved_raw_image_count++;
+ saved_raw_image_bytes += raw_image->getDataSize();
+ }
+
+ raw_image = image->getAuxRawImage();
+ if (raw_image)
+ {
+ aux_raw_image_count++;
+ aux_raw_image_bytes += raw_image->getDataSize();
+ }
+ }
+
+ F64 raw_image_bytes_MB = raw_image_bytes / (1024.0 * 1024.0);
+ F64 saved_raw_image_bytes_MB = saved_raw_image_bytes / (1024.0 * 1024.0);
+ F64 aux_raw_image_bytes_MB = aux_raw_image_bytes / (1024.0 * 1024.0);
+
//----------------------------------------------------------------------------
LLGLSUIDefault gls_ui;
LLColor4 text_color(1.f, 1.f, 1.f, 0.75f);
LLColor4 color;
- // Gray background using completely magic numbers
- gGL.color4f(0.f, 0.f, 0.f, 0.25f);
- // const LLRect & rect(getRect());
- // gl_rect_2d(-4, v_offset, rect.mRight - rect.mLeft + 2, v_offset + line_height*4);
-
std::string text = "";
- LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*6,
- text_color, LLFontGL::LEFT, LLFontGL::TOP);
LLTrace::Recording& recording = LLViewerStats::instance().getRecording();
@@ -551,6 +581,10 @@ void LLGLTexMemBar::draw()
U32 texFetchLatMed = U32(recording.getMean(LLTextureFetch::sTexFetchLatency).value() * 1000.0f);
U32 texFetchLatMax = U32(recording.getMax(LLTextureFetch::sTexFetchLatency).value() * 1000.0f);
+ // draw a background above first line.... no idea where the rest of the background comes from for the below text
+ gGL.color4f(0.f, 0.f, 0.f, 0.25f);
+ gl_rect_2d(-10, getRect().getHeight() + line_height + 1, getRect().getWidth()+2, getRect().getHeight()+2);
+
text = llformat("Est. Free: %d MB Sys Free: %d MB GL Tex: %d MB FBO: %d MB Bias: %.2f Cache: %.1f/%.1f MB",
(S32)LLViewerTexture::sFreeVRAMMegabytes,
LLMemory::getAvailableMemKB()/1024,
@@ -559,11 +593,9 @@ void LLGLTexMemBar::draw()
discard_bias,
cache_usage,
cache_max_usage);
- //, cache_entries, cache_max_entries
-
// Texture memory bars
//LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*6,
- LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*7,
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*8,
//
text_color, LLFontGL::LEFT, LLFontGL::TOP);
@@ -571,7 +603,7 @@ void LLGLTexMemBar::draw()
S32 bar_left = 0;
constexpr S32 bar_width = 200;
constexpr S32 bar_space = 10;
- S32 top = line_height*6 - 2 + v_offset;
+ S32 top = line_height*7 - 2 + v_offset;
S32 bottom = top - 6;
S32 left = bar_left;
S32 right = left + bar_width;
@@ -581,7 +613,7 @@ void LLGLTexMemBar::draw()
// VRAM Mem Bar
text = "VRAM";
- LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, v_offset + line_height*6,
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, v_offset + line_height*7,
text_color, LLFontGL::LEFT, LLFontGL::TOP);
left += 35;
right = left + bar_width;
@@ -590,7 +622,7 @@ void LLGLTexMemBar::draw()
gl_rect_2d(left, top, right, bottom);
U32 gpu_used = gGLManager.mVRAM - (S32)LLViewerTexture::sFreeVRAMMegabytes;
- color = (gpu_used < (U32)llfloor(gGLManager.mVRAM * texmem_lower_bound_scale)) ? LLColor4::green :
+ color = (gpu_used < (U32)llfloor(gGLManager.mVRAM * 0.85f)) ? LLColor4::green :
(gpu_used < gGLManager.mVRAM) ? LLColor4::yellow : LLColor4::red;
color[VALPHA] = .75f;
@@ -604,7 +636,7 @@ void LLGLTexMemBar::draw()
left = bar_left;
// VRAM Mem Bar
text = "CACHE";
- LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, v_offset + line_height*6,
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, v_offset + line_height*7,
text_color, LLFontGL::LEFT, LLFontGL::TOP);
left += 35;
@@ -623,6 +655,12 @@ void LLGLTexMemBar::draw()
gl_rect_2d(left, top, right, bottom, color);
//
+ text = llformat("Images: %d Raw: %d (%.2f MB) Saved: %d (%.2f MB) Aux: %d (%.2f MB)", image_count, raw_image_count, raw_image_bytes_MB,
+ saved_raw_image_count, saved_raw_image_bytes_MB,
+ aux_raw_image_count, aux_raw_image_bytes_MB);
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height * 6,
+ text_color, LLFontGL::LEFT, LLFontGL::TOP);
+
U32 cache_read(0U), cache_write(0U), res_wait(0U);
LLAppViewer::getTextureFetch()->getStateStats(&cache_read, &cache_write, &res_wait);
@@ -642,7 +680,6 @@ void LLGLTexMemBar::draw()
res_wait,
LLViewerTextureList::sNumFastCacheReads);
//
-
LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*5,
text_color, LLFontGL::LEFT, LLFontGL::TOP);
@@ -898,7 +935,7 @@ void LLTextureView::draw()
LL_INFOS() << "ID\tMEM\tBOOST\tPRI\tWIDTH\tHEIGHT\tDISCARD" << LL_ENDL;
}
- for (LLViewerTextureList::image_priority_list_t::iterator iter = gTextureList.mImageList.begin();
+ for (LLViewerTextureList::image_list_t::iterator iter = gTextureList.mImageList.begin();
iter != gTextureList.mImageList.end(); )
{
LLPointer imagep = *iter++;
diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp
index 36228ad91b..d66597bf05 100644
--- a/indra/newview/llversioninfo.cpp
+++ b/indra/newview/llversioninfo.cpp
@@ -63,6 +63,12 @@ LLVersionInfo::LLVersionInfo():
// immediately listen on mPump, store arriving URL into mReleaseNotes
mStore{new LLStoreListener(*mPump, mReleaseNotes)}
{
+ // Above macro hackery results in extra quotes - fix it if it happens
+ if (LLStringUtil::startsWith(mWorkingChannelName, "\"") && mWorkingChannelName.size() > 2)
+ {
+ mWorkingChannelName = mWorkingChannelName.substr(1, mWorkingChannelName.size() - 2);
+ }
+ //
}
void LLVersionInfo::initSingleton()
@@ -80,33 +86,33 @@ LLVersionInfo::~LLVersionInfo()
{
}
-S32 LLVersionInfo::getMajor()
+S32 LLVersionInfo::getMajor() const
{
return LL_VIEWER_VERSION_MAJOR;
}
-S32 LLVersionInfo::getMinor()
+S32 LLVersionInfo::getMinor() const
{
return LL_VIEWER_VERSION_MINOR;
}
-S32 LLVersionInfo::getPatch()
+S32 LLVersionInfo::getPatch() const
{
return LL_VIEWER_VERSION_PATCH;
}
-U64 LLVersionInfo::getBuild()
+U64 LLVersionInfo::getBuild() const
{
return LL_VIEWER_VERSION_BUILD;
}
-std::string LLVersionInfo::getVersion()
+std::string LLVersionInfo::getVersion() const
{
return version;
}
//
-std::string LLVersionInfo::getBuildVersion()
+std::string LLVersionInfo::getBuildVersion() const
{
static std::string build_version("");
if (build_version.empty())
@@ -119,12 +125,12 @@ std::string LLVersionInfo::getBuildVersion()
return build_version;
}
//
-std::string LLVersionInfo::getShortVersion()
+
+std::string LLVersionInfo::getShortVersion() const
{
return short_version;
}
-
std::string LLVersionInfo::getChannelAndVersion()
{
if (mVersionChannel.empty())
@@ -137,7 +143,7 @@ std::string LLVersionInfo::getChannelAndVersion()
}
// Get version and channel in the format needed for FSDATA.
-std::string LLVersionInfo::getChannelAndVersionFS()
+std::string LLVersionInfo::getChannelAndVersionFS() const
{
static std::string sVersionChannelFS;
if (sVersionChannelFS.empty())
@@ -156,14 +162,8 @@ std::string LLVersionInfo::getChannelAndVersionFS()
}
//
-std::string LLVersionInfo::getChannel()
+std::string LLVersionInfo::getChannel() const
{
- // Above macro hackery results in extra quotes - fix it if it happens
- if (LLStringUtil::startsWith(mWorkingChannelName, "\"") && mWorkingChannelName.size() > 2)
- {
- mWorkingChannelName = mWorkingChannelName.substr(1, mWorkingChannelName.size() - 2);
- }
- //
return mWorkingChannelName;
}
@@ -173,7 +173,7 @@ void LLVersionInfo::resetChannel(const std::string& channel)
mVersionChannel.clear(); // Reset version and channel string til next use.
}
-LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity()
+LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity() const
{
ViewerMaturity maturity;
@@ -212,7 +212,7 @@ LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity()
return maturity;
}
-std::string LLVersionInfo::getReleaseNotes()
+std::string LLVersionInfo::getReleaseNotes() const
{
return mReleaseNotes;
}
@@ -239,7 +239,7 @@ const char* getBuildPlatformString()
#endif
}
-std::string LLVersionInfo::getBuildPlatform()
+std::string LLVersionInfo::getBuildPlatform() const
{
std::string strPlatform = getBuildPlatformString();
return strPlatform;
@@ -247,7 +247,7 @@ std::string LLVersionInfo::getBuildPlatform()
// [/SL:KB]
-std::string LLVersionInfo::getBuildConfig()
+std::string LLVersionInfo::getBuildConfig() const
{
return build_configuration;
}
diff --git a/indra/newview/llversioninfo.h b/indra/newview/llversioninfo.h
index 3830e45f48..1e608ab6a3 100644
--- a/indra/newview/llversioninfo.h
+++ b/indra/newview/llversioninfo.h
@@ -52,27 +52,27 @@ public:
~LLVersionInfo();
/// return the major version number as an integer
- S32 getMajor();
+ S32 getMajor() const;
/// return the minor version number as an integer
- S32 getMinor();
+ S32 getMinor() const;
/// return the patch version number as an integer
- S32 getPatch();
+ S32 getPatch() const;
/// return the build number as an integer
- U64 getBuild();
+ U64 getBuild() const;
/// return the full viewer version as a string like "2.0.0.200030"
- std::string getVersion();
+ std::string getVersion() const;
//
/// return the full viewer version as a string like "200030"
- std::string getBuildVersion();
+ std::string getBuildVersion() const;
//
/// return the viewer version as a string like "2.0.0"
- std::string getShortVersion();
+ std::string getShortVersion() const;
/// return the viewer version and channel as a string
/// like "Second Life Release 2.0.0.200030"
@@ -81,24 +81,24 @@ public:
// Needed for fsdata version checking
/// return the viewer version and hardcoded channel as a string
/// like "Firestorm-Release 2.0.0 (200030)"
- std::string getChannelAndVersionFS();
+ std::string getChannelAndVersionFS() const;
/// return the channel name, e.g. "Second Life"
- std::string getChannel();
+ std::string getChannel() const;
/// return the CMake build type
- std::string getBuildConfig();
+ std::string getBuildConfig() const;
/// reset the channel name used by the viewer.
void resetChannel(const std::string& channel);
// [SL:KB] - Patch: Viewer-CrashReporting | Checked: 2011-05-08 (Catznip-2.6.0a) | Added: Catznip-2.6.0a
/// Return the platform the viewer was built for
- std::string getBuildPlatform();
+ std::string getBuildPlatform() const;
// [/SL:KB]
/// return the bit width of an address
- S32 getAddressSize() { return ADDRESS_SIZE; }
+ S32 getAddressSize() const { return ADDRESS_SIZE; }
typedef enum
{
@@ -107,11 +107,11 @@ public:
BETA_VIEWER,
RELEASE_VIEWER
} ViewerMaturity;
- ViewerMaturity getViewerMaturity();
+ ViewerMaturity getViewerMaturity() const;
/// get the release-notes URL, once it becomes available -- until then,
/// return empty string
- std::string getReleaseNotes();
+ std::string getReleaseNotes() const;
static std::string getGitHash();
private:
@@ -123,7 +123,7 @@ private:
std::string mWorkingChannelName;
// Storage for the "version and channel" string.
// This will get reset too.
- std::string mVersionChannel;
+ mutable std::string mVersionChannel;
std::string build_configuration;
std::string mReleaseNotes;
// Store unique_ptrs to the next couple things so we don't have to explain
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 75dd3d1155..924e5a56b4 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -76,6 +76,7 @@
#include "llfloaterfonttest.h"
#include "llfloaterforgetuser.h"
#include "llfloatergesture.h"
+#include "llfloatergltfasseteditor.h"
#include "llfloatergodtools.h"
#include "llfloatergridstatus.h"
#include "llfloatergroups.h"
@@ -444,6 +445,7 @@ void LLViewerFloaterReg::registerFloaters()
//LLFloaterReg::add("forget_username", "floater_forget_user.xml", (LLFloaterBuildFunc)&LLFloaterReg::build);
LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build);
+ LLFloaterReg::add("gltf_asset_editor", "floater_gltf_asset_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build);
LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build);
LLFloaterReg::add("grid_status", "floater_grid_status.xml", (LLFloaterBuildFunc)&LLFloaterReg::build);
LLFloaterReg::add("group_picker", "floater_choose_group.xml", (LLFloaterBuildFunc)&LLFloaterReg::build);
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 5f7ba7f7ca..995cf778c1 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -1277,41 +1277,46 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url)
hostEnd = authority.size();
}
- LLViewerMedia* inst = getInstance();
if (url.length())
{
- LLMediaCtrl* media_instance = LLFloaterReg::getInstance("destinations")->getChild("destination_guide_contents");
- if (media_instance)
- {
- std::string cookie_host = authority.substr(hostStart, hostEnd - hostStart);
- std::string cookie_name = "";
- std::string cookie_value = "";
- std::string cookie_path = "";
- bool httponly = true;
- bool secure = true;
- if (inst->parseRawCookie(inst->mOpenIDCookie, cookie_name, cookie_value, cookie_path, httponly, secure) &&
- media_instance->getMediaPlugin())
+ LLAppViewer::instance()->postToMainCoro([=]()
{
- // MAINT-5711 - inexplicably, the CEF setCookie function will no longer set the cookie if the
- // url and domain are not the same. This used to be my.sl.com and id.sl.com respectively and worked.
- // For now, we use the URL for the OpenID POST request since it will have the same authority
- // as the domain field.
- // (Feels like there must be a less dirty way to construct a URL from component LLURL parts)
- // MAINT-6392 - Rider: Do not change, however, the original URI requested, since it is used further
- // down.
- std::string cefUrl(std::string(inst->mOpenIDURL.mURI) + "://" + std::string(inst->mOpenIDURL.mAuthority));
+ LLMediaCtrl* media_instance = LLFloaterReg::getInstance("destinations")->getChild("destination_guide_contents");
+ if (media_instance)
+ {
+ LLViewerMedia* inst = getInstance();
+ std::string cookie_host = authority.substr(hostStart, hostEnd - hostStart);
+ std::string cookie_name = "";
+ std::string cookie_value = "";
+ std::string cookie_path = "";
+ bool httponly = true;
+ bool secure = true;
+ if (inst->parseRawCookie(inst->mOpenIDCookie, cookie_name, cookie_value, cookie_path, httponly, secure) &&
+ media_instance->getMediaPlugin())
+ {
+ // MAINT-5711 - inexplicably, the CEF setCookie function will no longer set the cookie if the
+ // url and domain are not the same. This used to be my.sl.com and id.sl.com respectively and worked.
+ // For now, we use the URL for the OpenID POST request since it will have the same authority
+ // as the domain field.
+ // (Feels like there must be a less dirty way to construct a URL from component LLURL parts)
+ // MAINT-6392 - Rider: Do not change, however, the original URI requested, since it is used further
+ // down.
+ std::string cefUrl(std::string(inst->mOpenIDURL.mURI) + "://" + std::string(inst->mOpenIDURL.mAuthority));
- media_instance->getMediaPlugin()->setCookie(cefUrl, cookie_name, cookie_value, cookie_host,
- cookie_path, httponly, secure);
+ media_instance->getMediaPlugin()->setCookie(cefUrl, cookie_name, cookie_value, cookie_host,
+ cookie_path, httponly, secure);
- // Now that we have parsed the raw cookie, we must store it so that each new media instance
- // can also get a copy and faciliate logging into internal SL sites.
- media_instance->getMediaPlugin()->storeOpenIDCookie(cefUrl, cookie_name, cookie_value,
- cookie_host, cookie_path, httponly, secure);
- }
- }
+ // Now that we have parsed the raw cookie, we must store it so that each new media instance
+ // can also get a copy and faciliate logging into internal SL sites.
+ media_instance->getMediaPlugin()->storeOpenIDCookie(cefUrl, cookie_name, cookie_value,
+ cookie_host, cookie_path, httponly, secure);
+ }
+ }
+ });
}
+ LLViewerMedia* inst = getInstance();
+
// Note: Rider: MAINT-6392 - Some viewer code requires access to the my.sl.com openid cookie for such
// actions as posting snapshots to the feed. This is handled through HTTPCore rather than CEF and so
// we must learn to SHARE the cookies.
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 3d0ed338ce..f59fe2fdf5 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -10125,6 +10125,15 @@ class LLAdvancedClickGLTFUpload: public view_listener_t
}
};
+class LLAdvancedClickGLTFEdit : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterReg::showInstance("gltf_asset_editor");
+ return true;
+ }
+};
+
class LLAdvancedClickResizeWindow : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
@@ -12021,15 +12030,6 @@ class LLUpdateMembershipLabel : public view_listener_t
}
};
-void handle_voice_morphing_subscribe()
-{
- LLWeb::loadURL(LLTrans::getString("voice_morphing_url"));
-}
-
-void handle_premium_voice_morphing_subscribe()
-{
- LLWeb::loadURL(LLTrans::getString("premium_voice_morphing_url"));
-}
class LLToggleUIHints : public view_listener_t
{
@@ -12452,16 +12452,6 @@ void initialize_menus()
// [FS Communication UI]
//view_listener_t::addMenu(new LLCommunicateNearbyChat(), "Communicate.NearbyChat");
- // Communicate > Voice morphing > Subscribe...
- commit.add("Communicate.VoiceMorphing.Subscribe", boost::bind(&handle_voice_morphing_subscribe));
- // Communicate > Voice morphing > Premium perk...
- commit.add("Communicate.VoiceMorphing.PremiumPerk", boost::bind(&handle_premium_voice_morphing_subscribe));
- LLVivoxVoiceClient * voice_clientp = LLVivoxVoiceClient::getInstance();
- enable.add("Communicate.VoiceMorphing.NoVoiceMorphing.Check"
- , boost::bind(&LLVivoxVoiceClient::onCheckVoiceEffect, voice_clientp, "NoVoiceMorphing"));
- commit.add("Communicate.VoiceMorphing.NoVoiceMorphing.Click"
- , boost::bind(&LLVivoxVoiceClient::onClickVoiceEffect, voice_clientp, "NoVoiceMorphing"));
-
// World menu
view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun");
view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark");
@@ -12600,6 +12590,7 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedClickGLTFOpen(), "Advanced.ClickGLTFOpen");
view_listener_t::addMenu(new LLAdvancedClickGLTFSaveAs(), "Advanced.ClickGLTFSaveAs");
view_listener_t::addMenu(new LLAdvancedClickGLTFUpload(), "Advanced.ClickGLTFUpload");
+ view_listener_t::addMenu(new LLAdvancedClickGLTFEdit(), "Advanced.ClickGLTFEdit");
view_listener_t::addMenu(new LLAdvancedClickResizeWindow(), "Advanced.ClickResizeWindow");
view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache");
view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain");
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index b7b7f9bb5c..daacc1d517 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -3827,7 +3827,9 @@ bool LLViewerObject::updateLOD()
bool LLViewerObject::updateGeometry(LLDrawable *drawable)
{
- return false;
+ // return true means "update complete", return false means "try again next frame"
+ // default should be return true
+ return true;
}
void LLViewerObject::updateGL()
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 024c0ea3f4..a399f54efb 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1356,8 +1356,12 @@ U32 LLViewerRegion::getNumOfVisibleGroups() const
return mImpl ? static_cast(mImpl->mVisibleGroups.size()) : 0;
}
-void LLViewerRegion::updateReflectionProbes()
+void LLViewerRegion::updateReflectionProbes(bool full_update)
{
+ if (!full_update && mReflectionMaps.empty())
+ {
+ return;
+ }
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
const F32 probe_spacing = 32.f;
const F32 probe_radius = sqrtf((probe_spacing * 0.5f) * (probe_spacing * 0.5f) * 3.f);
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 261492b99f..07388518f3 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -457,7 +457,7 @@ public:
static bool isNewObjectCreationThrottleDisabled() {return sNewObjectCreationThrottle < 0;}
// rebuild reflection probe list
- void updateReflectionProbes();
+ void updateReflectionProbes(bool full_update);
private:
void addToVOCacheTree(LLVOCacheEntry* entry);
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 5547504137..501421f8de 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -109,6 +109,7 @@ U32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA;
bool LLViewerTexture::sFreezeImageUpdates = false;
F32 LLViewerTexture::sCurrentTime = 0.0f;
+constexpr F32 MEMORY_CHECK_WAIT_TIME = 1.0f;
constexpr F32 MIN_VRAM_BUDGET = 768.f;
F32 LLViewerTexture::sFreeVRAMMegabytes = MIN_VRAM_BUDGET;
@@ -423,8 +424,6 @@ void LLViewerTextureManager::init()
}
}
imagep->createGLTexture(0, image_raw);
- //cache the raw image
- imagep->setCachedRawImage(0, image_raw);
image_raw = NULL;
#else
LLViewerFetchedTexture::sDefaultImagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, true, LLGLTexture::BOOST_UI);
@@ -503,34 +502,6 @@ void LLViewerTexture::initClass()
}
}
-// non-const (used externally
-F32 texmem_lower_bound_scale = 0.85f;
-F32 texmem_middle_bound_scale = 0.925f;
-
-bool LLViewerTexture::isMemoryForTextureLow()
-// Restrict texture memory by available physical system memory
-static bool isSystemMemoryForTextureLow()
-{
- static LLFrameTimer timer;
- static S32Megabytes physical_res = S32Megabytes(S32_MAX);
-
- static LLCachedControl fs_min_free_main_memory(gSavedSettings, "FSMinFreeMainMemoryTextureDiscardThreshold");
- const S32Megabytes MIN_FREE_MAIN_MEMORY(fs_min_free_main_memory);
-
- if (timer.getElapsedTimeF32() < GPU_MEMORY_CHECK_WAIT_TIME) //call this once per second.
- {
- return physical_res < MIN_FREE_MAIN_MEMORY;
- }
-
- timer.reset();
-
- //check main memory, only works for windows.
- LLMemory::updateMemoryInfo();
- physical_res = LLMemory::getAvailableMemKB();
- return physical_res < MIN_FREE_MAIN_MEMORY;
-}
-//
-
//static
void LLViewerTexture::updateClass()
{
@@ -562,20 +533,14 @@ void LLViewerTexture::updateClass()
sFreeVRAMMegabytes = target - used;
F32 over_pct = llmax((used-target) / target, 0.f);
- // Restrict texture memory by available physical system memory
- //sDesiredDiscardBias = llmax(sDesiredDiscardBias, 1.f + over_pct);
- //if (sDesiredDiscardBias > 1.f)
- //{
- // sDesiredDiscardBias -= gFrameIntervalSeconds * 0.01;
- //}
-
- if (isSystemMemoryForTextureLow())
+ if (isSystemMemoryLow())
{
// System RAM is low -> ramp up discard bias over time to free memory
- if (sEvaluationTimer.getElapsedTimeF32() > GPU_MEMORY_CHECK_WAIT_TIME)
+ if (sEvaluationTimer.getElapsedTimeF32() > MEMORY_CHECK_WAIT_TIME)
{
- sDesiredDiscardBias += llmax(.1f, over_pct); // add at least 10% over-percentage
+ static LLCachedControl low_mem_min_discard_increment(gSavedSettings, "RenderLowMemMinDiscardIncrement", .1f);
+ sDesiredDiscardBias += llmax(low_mem_min_discard_increment, over_pct);
sEvaluationTimer.reset();
}
}
@@ -588,9 +553,29 @@ void LLViewerTexture::updateClass()
sDesiredDiscardBias -= gFrameIntervalSeconds * 0.01;
}
}
- //
- LLViewerTexture::sFreezeImageUpdates = false; // sDesiredDiscardBias > (desired_discard_bias_max - 1.0f);
+ LLViewerTexture::sFreezeImageUpdates = false;
+}
+
+//static
+bool LLViewerTexture::isSystemMemoryLow()
+{
+ static LLFrameTimer timer;
+ static U32Megabytes physical_res = U32Megabytes(U32_MAX);
+
+ static LLCachedControl min_free_main_memory(gSavedSettings, "RenderMinFreeMainMemoryThreshold", 512);
+ const U32Megabytes MIN_FREE_MAIN_MEMORY(min_free_main_memory);
+
+ if (timer.getElapsedTimeF32() < MEMORY_CHECK_WAIT_TIME) //call this once per second.
+ {
+ return physical_res < MIN_FREE_MAIN_MEMORY;
+ }
+
+ timer.reset();
+
+ LLMemory::updateMemoryInfo();
+ physical_res = LLMemory::getAvailableMemKB();
+ return physical_res < MIN_FREE_MAIN_MEMORY;
}
//end of static functions
@@ -760,9 +745,6 @@ bool LLViewerTexture::bindDefaultImage(S32 stage)
}
stop_glerror();
- //check if there is cached raw image and switch to it if possible
- switchToCachedImage();
-
LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
if (tester)
{
@@ -963,18 +945,6 @@ void LLViewerTexture::reorganizeVolumeList()
}
}
-//virtual
-void LLViewerTexture::switchToCachedImage()
-{
- //nothing here.
-}
-
-//virtual
-void LLViewerTexture::setCachedRawImage(S32 discard_level, LLImageRaw* imageraw)
-{
- //nothing here.
-}
-
bool LLViewerTexture::isLargeImage()
{
return (S32)mTexelsPerImage > LLViewerTexture::sMinLargeImageSize;
@@ -1123,10 +1093,6 @@ void LLViewerFetchedTexture::init(bool firstinit)
mIsFetched = false;
mInFastCacheList = false;
- mCachedRawImage = NULL;
- mCachedRawDiscardLevel = -1;
- mCachedRawImageReady = false;
-
mSavedRawImage = NULL;
mForceToSaveRawImage = false;
mSaveRawImage = false;
@@ -1184,9 +1150,6 @@ void LLViewerFetchedTexture::cleanup()
// Clean up image data
destroyRawImage();
- mCachedRawImage = NULL;
- mCachedRawDiscardLevel = -1;
- mCachedRawImageReady = false;
mSavedRawImage = NULL;
mSavedRawDiscardLevel = -1;
}
@@ -1266,13 +1229,17 @@ void LLViewerFetchedTexture::setForSculpt()
{
static const S32 MAX_INTERVAL = 8; //frames
+ forceToSaveRawImage(0, F32_MAX);
+
+ setBoostLevel(llmax((S32)getBoostLevel(),
+ (S32)LLGLTexture::BOOST_SCULPTED));
+
mForSculpt = true;
if(isForSculptOnly() && hasGLTexture() && !getBoundRecently())
{
destroyGLTexture(); //sculpt image does not need gl texture.
mTextureState = ACTIVE;
}
- checkCachedRawSculptImage();
setMaxVirtualSizeResetInterval(MAX_INTERVAL);
}
@@ -1385,10 +1352,6 @@ void LLViewerFetchedTexture::addToCreateTexture()
}
}
- //discard the cached raw image and the saved raw image
- mCachedRawImageReady = false;
- mCachedRawDiscardLevel = -1;
- mCachedRawImage = NULL;
mSavedRawDiscardLevel = -1;
mSavedRawImage = NULL;
}
@@ -2131,13 +2094,6 @@ bool LLViewerFetchedTexture::updateFetch()
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - current < min");
make_request = false;
}
- else if(mCachedRawImage.notNull() // can be empty
- && mCachedRawImageReady
- && (current_discard < 0 || current_discard > mCachedRawDiscardLevel))
- {
- make_request = false;
- switchToCachedImage(); //use the cached raw data first
- }
if (make_request)
{
@@ -2637,20 +2593,6 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
}
}
- //
- // Do a readback if required, OR start off a texture decode
- //
- if (need_readback && (getMaxDiscardLevel() > gl_discard))
- {
- // Do a readback to get the GL data into the raw image
- // We have GL data.
-
- destroyRawImage();
- reloadRawImage(mLoadedCallbackDesiredDiscardLevel);
- llassert(mRawImage.notNull());
- llassert(!mNeedsAux || mAuxRawImage.notNull());
- }
-
//
// Run raw/auxiliary data callbacks
//
@@ -2758,61 +2700,6 @@ void LLViewerFetchedTexture::forceImmediateUpdate()
return;
}
-LLImageRaw* LLViewerFetchedTexture::reloadRawImage(S8 discard_level)
-{
- llassert(mGLTexturep.notNull());
- llassert(discard_level >= 0);
- llassert(mComponents > 0);
-
- if (mRawImage.notNull())
- {
- //mRawImage is in use by somebody else, do not delete it.
- return NULL;
- }
-
- if(mSavedRawDiscardLevel >= 0 && mSavedRawDiscardLevel <= discard_level)
- {
- if (mSavedRawDiscardLevel != discard_level
- && mBoostLevel != BOOST_ICON
- && mBoostLevel != BOOST_THUMBNAIL)
- {
- mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents());
- mRawImage->copy(getSavedRawImage());
- }
- else
- {
- mRawImage = getSavedRawImage();
- }
- mRawDiscardLevel = discard_level;
- }
- else
- {
- //force to fetch raw image again if cached raw image is not good enough.
- if(mCachedRawDiscardLevel > discard_level)
- {
- mRawImage = mCachedRawImage;
- mRawDiscardLevel = mCachedRawDiscardLevel;
- }
- else //cached raw image is good enough, copy it.
- {
- if(mCachedRawDiscardLevel != discard_level)
- {
- mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents());
- mRawImage->copy(mCachedRawImage);
- }
- else
- {
- mRawImage = mCachedRawImage;
- }
- mRawDiscardLevel = discard_level;
- }
- }
- mIsRawImageValid = true;
- sRawCount++;
-
- return mRawImage;
-}
-
bool LLViewerFetchedTexture::needsToSaveRawImage()
{
return mForceToSaveRawImage || mSaveRawImage;
@@ -2837,7 +2724,6 @@ void LLViewerFetchedTexture::destroyRawImage()
{
saveRawImage();
}
- setCachedRawImage();
}
mRawImage = NULL;
@@ -2847,151 +2733,6 @@ void LLViewerFetchedTexture::destroyRawImage()
}
}
-//use the mCachedRawImage to (re)generate the gl texture.
-//virtual
-void LLViewerFetchedTexture::switchToCachedImage()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
- if(mCachedRawImage.notNull() &&
- !mNeedsCreateTexture) // <--- texture creation is pending, don't step on it
- {
- mRawImage = mCachedRawImage;
-
- if (getComponents() != mRawImage->getComponents())
- {
- // We've changed the number of components, so we need to move any
- // objects using this pool to a different pool.
- mComponents = mRawImage->getComponents();
- mGLTexturep->setComponents(mComponents);
- gTextureList.dirtyImage(this);
- }
-
- mIsRawImageValid = true;
- mRawDiscardLevel = mCachedRawDiscardLevel;
-
- scheduleCreateTexture();
- }
-}
-
-//cache the imageraw forcefully.
-//virtual
-void LLViewerFetchedTexture::setCachedRawImage(S32 discard_level, LLImageRaw* imageraw)
-{
- if(imageraw != mRawImage.get())
- {
- if (mBoostLevel == LLGLTexture::BOOST_ICON)
- {
- S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENSIONS;
- S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENSIONS;
- if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)
- {
- mCachedRawImage = new LLImageRaw(expected_width, expected_height, imageraw->getComponents());
- mCachedRawImage->copyScaled(imageraw);
- }
- else
- {
- mCachedRawImage = imageraw;
- }
- }
- else if (mBoostLevel == LLGLTexture::BOOST_THUMBNAIL)
- {
- S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_THUMBNAIL_DIMENSIONS;
- S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_THUMBNAIL_DIMENSIONS;
- if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)
- {
- mCachedRawImage = new LLImageRaw(expected_width, expected_height, imageraw->getComponents());
- mCachedRawImage->copyScaled(imageraw);
- }
- else
- {
- mCachedRawImage = imageraw;
- }
- }
- else
- {
- mCachedRawImage = imageraw;
- }
- mCachedRawDiscardLevel = discard_level;
- mCachedRawImageReady = true;
- }
-}
-
-void LLViewerFetchedTexture::setCachedRawImage()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
- if(mRawImage == mCachedRawImage)
- {
- return;
- }
- if(!mIsRawImageValid)
- {
- return;
- }
-
- if(mCachedRawImageReady)
- {
- return;
- }
-
- if(mCachedRawDiscardLevel < 0 || mCachedRawDiscardLevel > mRawDiscardLevel)
- {
- S32 i = 0;
- S32 w = mRawImage->getWidth();
- S32 h = mRawImage->getHeight();
-
- S32 max_size = MAX_CACHED_RAW_IMAGE_AREA;
- if(LLGLTexture::BOOST_TERRAIN == mBoostLevel)
- {
- max_size = MAX_CACHED_RAW_TERRAIN_IMAGE_AREA;
- }
- if(mForSculpt)
- {
- max_size = MAX_CACHED_RAW_SCULPT_IMAGE_AREA;
- mCachedRawImageReady = !mRawDiscardLevel;
- }
- else
- {
- mCachedRawImageReady = (!mRawDiscardLevel || ((w * h) >= max_size));
- }
-
- while(((w >> i) * (h >> i)) > max_size)
- {
- ++i;
- }
-
- if(i)
- {
- if(!(w >> i) || !(h >> i))
- {
- --i;
- }
-
- {
- //make a duplicate in case somebody else is using this raw image
- mRawImage = mRawImage->scaled(w >> i, h >> i);
- }
- }
- mCachedRawImage = mRawImage;
- mRawDiscardLevel += i;
- mCachedRawDiscardLevel = mRawDiscardLevel;
- }
-}
-
-void LLViewerFetchedTexture::checkCachedRawSculptImage()
-{
- if(mCachedRawImageReady && mCachedRawDiscardLevel > 0)
- {
- if(getDiscardLevel() != 0)
- {
- mCachedRawImageReady = false;
- }
- else if(isForSculptOnly())
- {
- resetTextureStats(); //do not update this image any more.
- }
- }
-}
-
void LLViewerFetchedTexture::saveRawImage()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
@@ -3031,6 +2772,20 @@ void LLViewerFetchedTexture::saveRawImage()
mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents());
}
}
+ else if (mBoostLevel == LLGLTexture::BOOST_SCULPTED)
+ {
+ S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : sMaxSculptRez;
+ S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : sMaxSculptRez;
+ if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)
+ {
+ mSavedRawImage = new LLImageRaw(expected_width, expected_height, mRawImage->getComponents());
+ mSavedRawImage->copyScaled(mRawImage);
+ }
+ else
+ {
+ mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents());
+ }
+ }
else
{
mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents());
@@ -3076,20 +2831,23 @@ void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard, F32 kept_t
{
mForceToSaveRawImage = true;
mDesiredSavedRawDiscardLevel = desired_discard;
+ }
+}
- //copy from the cached raw image if exists.
- if(mCachedRawImage.notNull() && mRawImage.isNull() )
+void LLViewerFetchedTexture::readbackRawImage()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+
+ if (mGLTexturep.notNull() && mGLTexturep->getTexName() != 0 && mRawImage.isNull())
+ {
+ mRawImage = new LLImageRaw();
+ if (!mGLTexturep->readBackRaw(-1, mRawImage, false))
{
- mRawImage = mCachedRawImage;
- mRawDiscardLevel = mCachedRawDiscardLevel;
-
- saveRawImage();
-
- mRawImage = NULL;
- mRawDiscardLevel = INVALID_DISCARD_LEVEL;
+ mRawImage = nullptr;
}
}
}
+
void LLViewerFetchedTexture::destroySavedRawImage()
{
if(mLastReferencedSavedRawImageTime < mKeptSavedRawImageTime)
@@ -3124,6 +2882,11 @@ LLImageRaw* LLViewerFetchedTexture::getSavedRawImage()
return mSavedRawImage;
}
+const LLImageRaw* LLViewerFetchedTexture::getSavedRawImage() const
+{
+ return mSavedRawImage;
+}
+
bool LLViewerFetchedTexture::hasSavedRawImage() const
{
return mSavedRawImage.notNull();
@@ -3300,20 +3063,14 @@ void LLViewerLODTexture::processTextureStats()
bool LLViewerLODTexture::scaleDown()
{
- if(hasGLTexture() && mCachedRawDiscardLevel > getDiscardLevel())
+ if (mGLTexturep.isNull())
{
- switchToCachedImage();
-
- LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
- if (tester)
- {
- tester->setStablizingTime();
- }
-
- return true;
+ return false;
}
- return false;
+
+ return mGLTexturep->scaleDown(mDesiredDiscardLevel);
}
+
//----------------------------------------------------------------------------------------------
//end of LLViewerLODTexture
//----------------------------------------------------------------------------------------------
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index c1c7b712ef..d4971de935 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -123,6 +123,7 @@ protected:
public:
static void initClass();
static void updateClass();
+ static bool isSystemMemoryLow();
LLViewerTexture(bool usemipmaps = true);
LLViewerTexture(const LLUUID& id, bool usemipmaps) ;
@@ -171,8 +172,6 @@ public:
S32 getNumVolumes(U32 channel) const;
const ll_volume_list_t* getVolumeList(U32 channel) const { return &mVolumeList[channel]; }
-
- virtual void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ;
bool isLargeImage() ;
bool isInvisiprim() ;
static bool isInvisiprim(LLUUID id) ;
@@ -192,8 +191,6 @@ private:
friend class LLBumpImageList;
friend class LLUIImageList;
- virtual void switchToCachedImage();
-
protected:
friend class LLViewerTextureList;
LLUUID mID;
@@ -401,7 +398,6 @@ public:
U32 getFetchPriority() const { return mFetchPriority ;}
F32 getDownloadProgress() const {return mDownloadProgress ;}
- LLImageRaw* reloadRawImage(S8 discard_level) ;
void destroyRawImage();
bool needsToSaveRawImage();
@@ -420,17 +416,20 @@ public:
bool isForSculptOnly() const;
//raw image management
- void checkCachedRawSculptImage() ;
LLImageRaw* getRawImage()const { return mRawImage ;}
S32 getRawImageLevel() const {return mRawDiscardLevel;}
- LLImageRaw* getCachedRawImage() const { return mCachedRawImage ;}
- S32 getCachedRawImageLevel() const {return mCachedRawDiscardLevel;}
- bool isCachedRawImageReady() const {return mCachedRawImageReady ;}
bool isRawImageValid()const { return mIsRawImageValid ; }
void forceToSaveRawImage(S32 desired_discard = 0, F32 kept_time = 0.f) ;
- /*virtual*/ void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) override;
+
+ // readback the raw image from OpenGL if mRawImage is not valid
+ void readbackRawImage();
+
void destroySavedRawImage() ;
LLImageRaw* getSavedRawImage() ;
+ S32 getSavedRawImageLevel() const {return mSavedRawDiscardLevel; }
+
+ const LLImageRaw* getSavedRawImage() const;
+ const LLImageRaw* getAuxRawImage() const { return mAuxRawImage; }
bool hasSavedRawImage() const ;
F32 getElapsedLastReferencedSavedRawImageTime() const ;
bool isFullyLoaded() const;
@@ -451,7 +450,6 @@ public:
//
protected:
- /*virtual*/ void switchToCachedImage() override;
S32 getCurrentDiscardLevelForFetching() ;
public: // Needed for texture refresh
void forceToRefetchTexture(S32 desired_discard = 0, F32 kept_time = 60.f);
@@ -461,7 +459,6 @@ private:
void cleanup() ;
void saveRawImage() ;
- void setCachedRawImage() ;
//for atlas
void resetFaceAtlas() ;
@@ -533,11 +530,6 @@ protected:
F32 mLastReferencedSavedRawImageTime ;
F32 mKeptSavedRawImageTime ;
- //a small version of the copy of the raw image (<= 64 * 64)
- LLPointer mCachedRawImage;
- S32 mCachedRawDiscardLevel;
- bool mCachedRawImageReady; //the rez of the mCachedRawImage reaches the upper limit.
-
LLHost mTargetHost; // if invalid, just request from agent's simulator
// Timers
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 8bef436276..0509714bb4 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -303,7 +303,7 @@ void LLViewerTextureList::shutdown()
// Write out list of currently loaded textures for precaching on startup
typedef std::set > image_area_list_t;
image_area_list_t image_area_list;
- for (image_priority_list_t::iterator iter = mImageList.begin();
+ for (image_list_t::iterator iter = mImageList.begin();
iter != mImageList.end(); ++iter)
{
LLViewerFetchedTexture* image = *iter;
@@ -375,7 +375,7 @@ void LLViewerTextureList::dump()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
LL_INFOS() << "LLViewerTextureList::dump()" << LL_ENDL;
- for (image_priority_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it)
+ for (image_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it)
{
LLViewerFetchedTexture* image = *it;
@@ -389,15 +389,9 @@ void LLViewerTextureList::dump()
}
}
-void LLViewerTextureList::destroyGL(bool save_state)
+void LLViewerTextureList::destroyGL()
{
- LLImageGL::destroyGL(save_state);
-}
-
-void LLViewerTextureList::restoreGL()
-{
- llassert_always(mInitialized) ;
- LLImageGL::restoreGL();
+ LLImageGL::destroyGL();
}
/* Vertical tab container button image IDs
@@ -908,7 +902,7 @@ void LLViewerTextureList::clearFetchingRequests()
LLAppViewer::getTextureFetch()->deleteAllRequests();
- for (image_priority_list_t::iterator iter = mImageList.begin();
+ for (image_list_t::iterator iter = mImageList.begin();
iter != mImageList.end(); ++iter)
{
LLViewerFetchedTexture* imagep = *iter;
@@ -1233,7 +1227,7 @@ void LLViewerTextureList::updateImagesUpdateStats()
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
if (mForceResetTextureStats)
{
- for (image_priority_list_t::iterator iter = mImageList.begin();
+ for (image_list_t::iterator iter = mImageList.begin();
iter != mImageList.end(); )
{
LLViewerFetchedTexture* imagep = *iter++;
@@ -1253,7 +1247,7 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
// Update texture stats and priorities
std::vector > image_list;
- for (image_priority_list_t::iterator iter = mImageList.begin();
+ for (image_list_t::iterator iter = mImageList.begin();
iter != mImageList.end(); )
{
LLViewerFetchedTexture* imagep = *iter++;
@@ -1273,7 +1267,7 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
image_list.clear();
// Update fetch (decode)
- for (image_priority_list_t::iterator iter = mImageList.begin();
+ for (image_list_t::iterator iter = mImageList.begin();
iter != mImageList.end(); )
{
LLViewerFetchedTexture* imagep = *iter++;
@@ -1300,7 +1294,7 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
}
}
// Update fetch again
- for (image_priority_list_t::iterator iter = mImageList.begin();
+ for (image_list_t::iterator iter = mImageList.begin();
iter != mImageList.end(); )
{
LLViewerFetchedTexture* imagep = *iter++;
diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h
index a21d65286d..a13a9d34a0 100644
--- a/indra/newview/llviewertexturelist.h
+++ b/indra/newview/llviewertexturelist.h
@@ -33,7 +33,7 @@
#include "llviewertexture.h"
#include "llui.h"
#include
-#include
+#include
#include "lluiimage.h"
const U32 LL_IMAGE_REZ_LOSSLESS_CUTOFF = 128;
@@ -119,8 +119,7 @@ public:
void init();
void shutdown();
void dump();
- void destroyGL(bool save_state = true);
- void restoreGL();
+ void destroyGL();
bool isInitialized() const {return mInitialized;}
void findTexturesByID(const LLUUID &image_id, std::vector &output);
@@ -194,7 +193,7 @@ private: // PoundLife - Improved Object Inspect
LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE, // Get the requested level immediately upon creation.
S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
LLGLint internal_format = 0,
- LLGLenum primary_format = 0,
+ LLGLenum primary_format = 0,
const LLUUID& force_id = LLUUID::null
);
@@ -217,7 +216,7 @@ private: // PoundLife - Improved Object Inspect
{ return getImage(image_id, f_type, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); }
public:
- typedef std::set > image_list_t;
+ typedef std::unordered_set > image_list_t;
image_list_t mLoadingStreamList;
image_list_t mCreateTextureList;
image_list_t mCallbackList;
@@ -228,6 +227,10 @@ public:
bool mForceResetTextureStats;
+ // to make "for (auto& imagep : gTextureList)" work
+ const image_list_t::iterator begin() const { return mImageList.begin(); }
+ const image_list_t::iterator end() const { return mImageList.end(); }
+
// Fast cache stats
static U32 sNumFastCacheReads;
@@ -236,11 +239,10 @@ private:
uuid_map_t mUUIDMap;
LLTextureKey mLastUpdateKey;
- typedef std::set < LLPointer > image_priority_list_t;
- image_priority_list_t mImageList;
+ image_list_t mImageList;
// simply holds on to LLViewerFetchedTexture references to stop them from being purged too soon
- std::set > mImagePreloads;
+ std::unordered_set > mImagePreloads;
bool mInitialized ;
LLFrameTimer mForceDecodeTimer;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 6822cb6c2f..f8c0b1d0fa 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1930,10 +1930,8 @@ LLViewerWindow::LLViewerWindow(const Params& p)
mToolStored( NULL ),
mHideCursorPermanent( false ),
mCursorHidden(false),
- mIgnoreActivate( false ),
mResDirty(false),
mStatesDirty(false),
- mCurrResolutionIndex(0),
mProgressView(NULL),
mProgressViewMini(NULL)
{
@@ -2687,7 +2685,7 @@ void LLViewerWindow::shutdownGL()
LLSelectMgr::getInstance()->cleanup();
LL_INFOS() << "Stopping GL during shutdown" << LL_ENDL;
- stopGL(false);
+ stopGL();
stop_glerror();
gGL.shutdown();
@@ -6959,7 +6957,7 @@ void LLViewerWindow::dumpState()
<< LL_ENDL;
}
-void LLViewerWindow::stopGL(bool save_state)
+void LLViewerWindow::stopGL()
{
//Note: --bao
//if not necessary, do not change the order of the function calls in this function.
@@ -7005,7 +7003,7 @@ void LLViewerWindow::stopGL(bool save_state)
gPostProcess->invalidate();
}
- gTextureList.destroyGL(save_state);
+ gTextureList.destroyGL();
stop_glerror();
gGLManager.mIsDisabled = true;
@@ -7022,6 +7020,14 @@ void LLViewerWindow::stopGL(bool save_state)
void LLViewerWindow::restoreGL(const std::string& progress_message)
{
+ llassert(false);
+ // DEPRECATED -- this is left over from when we would completely destroy and restore a GL context
+ // when switching from windowed to fullscreen. None of this machinery has been exercised in years
+ // and is unreliable. If we ever *do* have another use case where completely unloading and reloading
+ // everthing is necessary, requiring a viewer restart for that operation is a fine thing to do.
+ // -- davep
+
+
//Note: --bao
//if not necessary, do not change the order of the function calls in this function.
//if change something, make sure it will not break anything.
@@ -7034,8 +7040,6 @@ void LLViewerWindow::restoreGL(const std::string& progress_message)
initGLDefaults();
LLGLState::restoreGL();
- gTextureList.restoreGL();
-
// for future support of non-square pixels, and fonts that are properly stretched
//LLFontGL::destroyDefaultFonts();
initFonts();
@@ -7113,122 +7117,6 @@ void LLViewerWindow::checkSettings()
}
}
-void LLViewerWindow::restartDisplay(bool show_progress_bar)
-{
- LL_INFOS() << "Restaring GL" << LL_ENDL;
- stopGL();
- if (show_progress_bar)
- {
- restoreGL(LLTrans::getString("ProgressChangingResolution"));
- }
- else
- {
- restoreGL();
- }
-}
-
-bool LLViewerWindow::changeDisplaySettings(LLCoordScreen size, bool enable_vsync, bool show_progress_bar)
-{
- //bool was_maximized = gSavedSettings.getBOOL("WindowMaximized");
-
- //gResizeScreenTexture = true;
-
-
- //U32 fsaa = gSavedSettings.getU32("RenderFSAASamples");
- //U32 old_fsaa = mWindow->getFSAASamples();
-
- // if not maximized, use the request size
- if (!mWindow->getMaximized())
- {
- mWindow->setSize(size);
- }
-
- //if (fsaa == old_fsaa)
- {
- return true;
- }
-
-/*
-
- // Close floaters that don't handle settings change
- LLFloaterReg::hideInstance("snapshot");
-
- bool result_first_try = false;
- bool result_second_try = false;
-
- LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
- send_agent_pause();
- LL_INFOS() << "Stopping GL during changeDisplaySettings" << LL_ENDL;
- stopGL();
- mIgnoreActivate = true;
- LLCoordScreen old_size;
- LLCoordScreen old_pos;
- mWindow->getSize(&old_size);
-
- //mWindow->setFSAASamples(fsaa);
-
- result_first_try = mWindow->switchContext(false, size, disable_vsync);
- if (!result_first_try)
- {
- // try to switch back
- //mWindow->setFSAASamples(old_fsaa);
- result_second_try = mWindow->switchContext(false, old_size, disable_vsync);
-
- if (!result_second_try)
- {
- // we are stuck...try once again with a minimal resolution?
- send_agent_resume();
- mIgnoreActivate = false;
- return false;
- }
- }
- send_agent_resume();
-
- LL_INFOS() << "Restoring GL during resolution change" << LL_ENDL;
- if (show_progress_bar)
- {
- restoreGL(LLTrans::getString("ProgressChangingResolution"));
- }
- else
- {
- restoreGL();
- }
-
- if (!result_first_try)
- {
- LLSD args;
- args["RESX"] = llformat("%d",size.mX);
- args["RESY"] = llformat("%d",size.mY);
- LLNotificationsUtil::add("ResolutionSwitchFail", args);
- size = old_size; // for reshape below
- }
-
- bool success = result_first_try || result_second_try;
-
- if (success)
- {
- // maximize window if was maximized, else reposition
- if (was_maximized)
- {
- mWindow->maximize();
- }
- else
- {
- S32 windowX = gSavedSettings.getS32("WindowX");
- S32 windowY = gSavedSettings.getS32("WindowY");
-
- mWindow->setPosition(LLCoordScreen ( windowX, windowY ) );
- }
- }
-
- mIgnoreActivate = false;
- gFocusMgr.setKeyboardFocus(keyboard_focus);
-
- return success;
-
- */
-}
-
F32 LLViewerWindow::getWorldViewAspectRatio() const
{
F32 world_aspect = (F32)mWorldViewRectRaw.getWidth() / (F32)mWorldViewRectRaw.getHeight();
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index ca11838f0b..200009234a 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -457,9 +457,7 @@ public:
// handle shutting down GL and bringing it back up
void requestResolutionUpdate();
void checkSettings();
- void restartDisplay(bool show_progress_bar);
- bool changeDisplaySettings(LLCoordScreen size, bool enable_vsync, bool show_progress_bar);
- bool getIgnoreDestroyWindow() { return mIgnoreActivate; }
+
F32 getWorldViewAspectRatio() const;
const LLVector2& getDisplayScale() const { return mDisplayScale; }
void calcDisplayScale();
@@ -476,7 +474,7 @@ private:
void switchToolByMask(MASK mask);
void destroyWindow();
void drawMouselookInstructions();
- void stopGL(bool save_state = true);
+ void stopGL();
void restoreGL(const std::string& progress_message = LLStringUtil::null);
void initFonts(F32 zoom_factor = 1.f);
void schedulePick(LLPickInfo& pick_info);
@@ -534,8 +532,6 @@ private:
std::string mOverlayTitle; // Used for special titles such as "Second Life - Special E3 2003 Beta"
- bool mIgnoreActivate;
-
std::string mInitAlert; // Window / GL initialization requires an alert
LLHandle mWorldViewPlaceholder; // widget that spans the portion of screen dedicated to rendering the 3d world
@@ -548,7 +544,6 @@ private:
bool mResDirty;
bool mStatesDirty;
- U32 mCurrResolutionIndex;
std::unique_ptr mWindowListener;
std::unique_ptr mViewerWindowListener;
diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp
index d8c37cd311..8e62531e30 100644
--- a/indra/newview/llvlcomposition.cpp
+++ b/indra/newview/llvlcomposition.cpp
@@ -317,7 +317,7 @@ bool LLTerrainMaterials::makeMaterialsReady(bool boost, bool strict)
// static
bool LLTerrainMaterials::makeTextureReady(LLPointer& tex, bool boost)
{
- llassert(tex);
+ //llassert(tex); ??? maybe ok ???
if (!tex) { return false; }
if (tex->getDiscardLevel() < 0)
@@ -574,424 +574,6 @@ bool LLVLComposition::generateComposition()
return LLTerrainMaterials::generateMaterials();
}
-namespace
-{
- void prepare_fallback_image(LLImageRaw* raw_image)
- {
- raw_image->resize(BASE_SIZE, BASE_SIZE, 4);
- raw_image->fill(LLColor4U::white);
- }
-
- // Check if the raw image is loaded for this texture at a discard
- // level the minimap can use, and if not then try to get it loaded.
- bool prepare_raw_image(LLPointer& raw_image, bool emissive, LLViewerFetchedTexture* tex, bool& delete_raw_post)
- {
- if (!tex)
- {
- if (!emissive)
- {
- prepare_fallback_image(raw_image);
- }
- else
- {
- llassert(!raw_image);
- raw_image = nullptr;
- }
- return true;
- }
- if (raw_image)
- {
- // Callback already initiated
- if (raw_image->getDataSize() > 0)
- {
- // Callback finished
- delete_raw_post = true;
- return true;
- }
- else
- {
- return false;
- }
- }
-
- raw_image = new LLImageRaw();
-
- S32 ddiscard = 0;
- {
- S32 min_dim = llmin(tex->getFullWidth(), tex->getFullHeight());
- while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL)
- {
- ddiscard++;
- min_dim /= 2;
- }
- }
-
- struct PendingImage
- {
- LLImageRaw* mRawImage;
- S32 mDesiredDiscard;
- LLUUID mTextureId;
- PendingImage(LLImageRaw* raw_image, S32 ddiscard, const LLUUID& texture_id)
- : mRawImage(raw_image)
- , mDesiredDiscard(ddiscard)
- , mTextureId(texture_id)
- {
- mRawImage->ref();
- }
- ~PendingImage()
- {
- mRawImage->unref();
- }
- };
- PendingImage* pending_image = new PendingImage(raw_image, ddiscard, tex->getID());
-
- loaded_callback_func cb = [](bool success, LLViewerFetchedTexture * src_vi, LLImageRaw * src, LLImageRaw * src_aux, S32 discard_level, bool is_final, void* userdata) {
- PendingImage* pending = (PendingImage*)userdata;
- // Owning LLVLComposition still exists
-
- // Assume mRawImage only used by single LLVLComposition for now
- const bool in_use_by_composition = pending->mRawImage->getNumRefs() > 1;
- llassert(pending->mRawImage->getNumRefs());
- llassert(pending->mRawImage->getNumRefs() <= 2);
- const bool needs_data = !pending->mRawImage->getDataSize();
- if (in_use_by_composition && needs_data)
- {
- if (success && pending->mDesiredDiscard == discard_level)
- {
- pending->mRawImage->resize(BASE_SIZE, BASE_SIZE, src->getComponents());
- pending->mRawImage->copyScaled(src);
- }
- else if (is_final)
- {
- prepare_fallback_image(pending->mRawImage);
- }
- }
-
- if (is_final) { delete pending; }
- };
- tex->setLoadedCallback(cb, ddiscard, true, false, pending_image, nullptr);
- tex->forceToSaveRawImage(ddiscard);
-
- return false;
- }
-};
-
-bool LLVLComposition::generateMinimapTileLand(const F32 x, const F32 y,
- const F32 width, const F32 height)
-{
- LL_PROFILE_ZONE_SCOPED
- llassert(mSurfacep);
- llassert(x >= 0.f);
- llassert(y >= 0.f);
-
- ///////////////////////////
- //
- // Generate raw data arrays for surface textures
- //
- //
-
- // These have already been validated by generateComposition.
- U8* st_data[ASSET_COUNT];
- S32 st_data_size[ASSET_COUNT]; // for debugging
-
- const bool use_textures = getMaterialType() != LLTerrainMaterials::Type::PBR;
- if (use_textures)
- {
- if (!makeTexturesReady(true, true)) { return false; }
- }
- else
- {
- if (!makeMaterialsReady(true, true)) { return false; }
- }
-
- for (S32 i = 0; i < ASSET_COUNT; i++)
- {
- if (mRawImages[i].isNull())
- {
- // Read back a raw image for this discard level, if it exists
- LLViewerFetchedTexture* tex;
- LLViewerFetchedTexture* tex_emissive; // Can be null
- bool has_base_color_factor;
- bool has_emissive_factor;
- bool has_alpha;
- LLColor3 base_color_factor;
- LLColor3 emissive_factor;
- if (use_textures)
- {
- tex = mDetailTextures[i];
- tex_emissive = nullptr;
- has_base_color_factor = false;
- has_emissive_factor = false;
- has_alpha = false;
- llassert(tex);
- }
- else
- {
- LLPointer& mat = mDetailRenderMaterials[i];
- tex = mat->mBaseColorTexture;
- tex_emissive = mat->mEmissiveTexture;
- base_color_factor = LLColor3(mat->mBaseColor);
- // *HACK: Treat alpha as black
- base_color_factor *= (mat->mBaseColor.mV[VW]);
- emissive_factor = mat->mEmissiveColor;
- has_base_color_factor = (base_color_factor.mV[VX] != 1.f ||
- base_color_factor.mV[VY] != 1.f ||
- base_color_factor.mV[VZ] != 1.f);
- has_emissive_factor = (emissive_factor.mV[VX] != 1.f ||
- emissive_factor.mV[VY] != 1.f ||
- emissive_factor.mV[VZ] != 1.f);
- has_alpha = mat->mAlphaMode != LLGLTFMaterial::ALPHA_MODE_OPAQUE;
- }
-
- if (!tex) { tex = LLViewerFetchedTexture::sWhiteImagep; }
-
- bool delete_raw_post = false;
- bool delete_raw_post_emissive = false;
- if (!prepare_raw_image(mRawImagesBaseColor[i], false, tex, delete_raw_post)) { return false; }
- if (tex_emissive && !prepare_raw_image(mRawImagesEmissive[i], true, tex_emissive, delete_raw_post_emissive)) { return false; }
- // tex_emissive can be null, and then will be ignored
-
- // In the simplest case, the minimap image is just the base color.
- // This will be replaced if we need to do any tinting/compositing.
- mRawImages[i] = mRawImagesBaseColor[i];
-
- // *TODO: This isn't quite right for PBR:
- // 1) It does not convert the color images from SRGB to linear
- // before mixing (which will always require copying the image).
- // 2) It mixes emissive and base color before mixing terrain
- // materials, but it should be the other way around
- // Long-term, we should consider a method that is more
- // maintainable. Shaders, perhaps? Bake shaders to textures?
- LLPointer raw_emissive;
- if (tex_emissive)
- {
- raw_emissive = mRawImagesEmissive[i];
- if (has_emissive_factor ||
- tex_emissive->getWidth(tex_emissive->getRawImageLevel()) != BASE_SIZE ||
- tex_emissive->getHeight(tex_emissive->getRawImageLevel()) != BASE_SIZE ||
- tex_emissive->getComponents() != 4)
- {
- LLPointer newraw_emissive = new LLImageRaw(BASE_SIZE, BASE_SIZE, 4);
- // Copy RGB, leave alpha alone (set to opaque by default)
- newraw_emissive->copy(mRawImagesEmissive[i]);
- if (has_emissive_factor)
- {
- newraw_emissive->tint(emissive_factor);
- }
- raw_emissive = newraw_emissive;
- }
- }
- if (has_base_color_factor ||
- raw_emissive ||
- has_alpha ||
- tex->getWidth(tex->getRawImageLevel()) != BASE_SIZE ||
- tex->getHeight(tex->getRawImageLevel()) != BASE_SIZE ||
- tex->getComponents() != 3)
- {
- LLPointer newraw = new LLImageRaw(BASE_SIZE, BASE_SIZE, 3);
- // guard against bad alloc here that leads to crash in composite
- if(!newraw)
- {
- // Not much that is useful to do here, this ship is sinking it seems.
- LL_WARNS("Terrain") << "allocation of new raw image failed" << LL_ENDL;
- return(false);
- }
- //
- if (has_alpha)
- {
- // Approximate the water underneath terrain alpha with solid water color
- newraw->clear(
- MAX_WATER_COLOR.mV[VX],
- MAX_WATER_COLOR.mV[VY],
- MAX_WATER_COLOR.mV[VZ],
- 255);
- }
- newraw->composite(mRawImagesBaseColor[i]);
- if (has_base_color_factor)
- {
- newraw->tint(base_color_factor);
- }
- // Apply emissive texture
- if (raw_emissive)
- {
- newraw->addEmissive(raw_emissive);
- }
-
- mRawImages[i] = newraw; // deletes old
- }
-
- if (delete_raw_post)
- {
- tex->destroyRawImage();
- }
- if (delete_raw_post_emissive)
- {
- tex_emissive->destroyRawImage();
- }
-
- // Remove intermediary image references
- mRawImagesBaseColor[i] = nullptr;
- mRawImagesEmissive[i] = nullptr;
- }
- st_data[i] = mRawImages[i]->getData();
- st_data_size[i] = mRawImages[i]->getDataSize();
- }
-
- ///////////////////////////////////////
- //
- // Generate and clamp x/y bounding box.
- //
- //
-
- S32 x_begin, y_begin, x_end, y_end;
- x_begin = (S32)(x * mScaleInv);
- y_begin = (S32)(y * mScaleInv);
- x_end = ll_round( (x + width) * mScaleInv );
- y_end = ll_round( (y + width) * mScaleInv );
-
- if (x_end > mWidth)
- {
- llassert(false);
- x_end = mWidth;
- }
- if (y_end > mWidth)
- {
- llassert(false);
- y_end = mWidth;
- }
-
-
- ///////////////////////////////////////////
- //
- // Generate target texture information, stride ratios.
- //
- //
-
- LLViewerTexture *texturep;
- U32 tex_width, tex_height, tex_comps;
- U32 tex_stride;
- F32 tex_x_scalef, tex_y_scalef;
- S32 tex_x_begin, tex_y_begin, tex_x_end, tex_y_end;
- F32 tex_x_ratiof, tex_y_ratiof;
-
- texturep = mSurfacep->getSTexture();
- tex_width = texturep->getWidth();
- tex_height = texturep->getHeight();
- tex_comps = texturep->getComponents();
- tex_stride = tex_width * tex_comps;
-
- U32 st_comps = 3;
- U32 st_width = BASE_SIZE;
- U32 st_height = BASE_SIZE;
-
- if (tex_comps != st_comps)
- {
- llassert(false);
- return false;
- }
-
- tex_x_scalef = (F32)tex_width / (F32)mWidth;
- tex_y_scalef = (F32)tex_height / (F32)mWidth;
- tex_x_begin = (S32)((F32)x_begin * tex_x_scalef);
- tex_y_begin = (S32)((F32)y_begin * tex_y_scalef);
- tex_x_end = (S32)((F32)x_end * tex_x_scalef);
- tex_y_end = (S32)((F32)y_end * tex_y_scalef);
-
- tex_x_ratiof = (F32)mWidth*mScale / (F32)tex_width;
- tex_y_ratiof = (F32)mWidth*mScale / (F32)tex_height;
-
- LLPointer raw = new LLImageRaw(tex_width, tex_height, tex_comps);
- U8 *rawp = raw->getData();
-
- F32 st_x_stride, st_y_stride;
- st_x_stride = ((F32)st_width / (F32)mTexScaleX)*((F32)mWidth / (F32)tex_width);
- st_y_stride = ((F32)st_height / (F32)mTexScaleY)*((F32)mWidth / (F32)tex_height);
-
- llassert(st_x_stride > 0.f);
- llassert(st_y_stride > 0.f);
- ////////////////////////////////
- //
- // Iterate through the target texture, striding through the
- // subtextures and interpolating appropriately.
- //
- //
-
- F32 sti, stj;
- S32 st_offset;
- sti = (tex_x_begin * st_x_stride) - st_width*(llfloor((tex_x_begin * st_x_stride)/st_width));
- stj = (tex_y_begin * st_y_stride) - st_height*(llfloor((tex_y_begin * st_y_stride)/st_height));
-
- st_offset = (llfloor(stj * st_width) + llfloor(sti)) * st_comps;
- for (S32 j = tex_y_begin; j < tex_y_end; j++)
- {
- U32 offset = j * tex_stride + tex_x_begin * tex_comps;
- sti = (tex_x_begin * st_x_stride) - st_width*((U32)(tex_x_begin * st_x_stride)/st_width);
- for (S32 i = tex_x_begin; i < tex_x_end; i++)
- {
- S32 tex0, tex1;
- F32 composition = getValueScaled(i*tex_x_ratiof, j*tex_y_ratiof);
-
- tex0 = llfloor( composition );
- tex0 = llclamp(tex0, 0, 3);
- composition -= tex0;
- tex1 = tex0 + 1;
- tex1 = llclamp(tex1, 0, 3);
-
- st_offset = (lltrunc(sti) + lltrunc(stj)*st_width) * st_comps;
- for (U32 k = 0; k < tex_comps; k++)
- {
- // Linearly interpolate based on composition.
- if (st_offset >= st_data_size[tex0] || st_offset >= st_data_size[tex1])
- {
- // SJB: This shouldn't be happening, but does... Rounding error?
- //LL_WARNS() << "offset 0 [" << tex0 << "] =" << st_offset << " >= size=" << st_data_size[tex0] << LL_ENDL;
- //LL_WARNS() << "offset 1 [" << tex1 << "] =" << st_offset << " >= size=" << st_data_size[tex1] << LL_ENDL;
- }
- else
- {
- F32 a = *(st_data[tex0] + st_offset);
- F32 b = *(st_data[tex1] + st_offset);
- rawp[ offset ] = (U8)lltrunc( a + composition * (b - a) );
- }
- offset++;
- st_offset++;
- }
-
- sti += st_x_stride;
- if (sti >= st_width)
- {
- sti -= st_width;
- }
- }
-
- stj += st_y_stride;
- if (stj >= st_height)
- {
- stj -= st_height;
- }
- }
-
- if (!texturep->hasGLTexture())
- {
- texturep->createGLTexture(0, raw);
- }
- texturep->setSubImage(raw, tex_x_begin, tex_y_begin, tex_x_end - tex_x_begin, tex_y_end - tex_y_begin);
-
- // Un-boost detail textures (will get re-boosted if rendering in high detail)
- for (S32 i = 0; i < ASSET_COUNT; i++)
- {
- unboost_minimap_texture(mDetailTextures[i]);
- }
-
- // Un-boost textures for each detail material (will get re-boosted if rendering in high detail)
- for (S32 i = 0; i < ASSET_COUNT; i++)
- {
- unboost_minimap_material(mDetailMaterials[i]);
- }
-
- return true;
-}
-
F32 LLVLComposition::getStartHeight(S32 corner)
{
return mStartHeight[corner];
diff --git a/indra/newview/llvlcomposition.h b/indra/newview/llvlcomposition.h
index 61c35ade28..2637d77183 100644
--- a/indra/newview/llvlcomposition.h
+++ b/indra/newview/llvlcomposition.h
@@ -114,8 +114,6 @@ public:
// Viewer side hack to generate composition values
bool generateHeights(const F32 x, const F32 y, const F32 width, const F32 height);
bool generateComposition();
- // Generate texture from composition values.
- bool generateMinimapTileLand(const F32 x, const F32 y, const F32 width, const F32 height);
// Use these as indeces ito the get/setters below that use 'corner'
enum ECorner
diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp
index b665eb69a2..b95e43da8d 100644
--- a/indra/newview/llvoicechannel.cpp
+++ b/indra/newview/llvoicechannel.cpp
@@ -96,7 +96,7 @@ void LLVoiceChannel::setChannelInfo(const LLSD &channelInfo)
if (mState == STATE_NO_CHANNEL_INFO)
{
- if (mChannelInfo.isUndefined())
+ if (mChannelInfo.isUndefined() || !mChannelInfo.isMap() || mChannelInfo.size() == 0)
{
LLNotificationsUtil::add("VoiceChannelJoinFailed", mNotifyArgs);
LL_WARNS("Voice") << "Received empty channel info for channel " << mSessionName << LL_ENDL;
@@ -122,7 +122,7 @@ void LLVoiceChannel::onChange(EStatusType type, const LLSD& channelInfo, bool pr
{
LL_DEBUGS("Voice") << "Incoming channel info: " << channelInfo << LL_ENDL;
LL_DEBUGS("Voice") << "Current channel info: " << mChannelInfo << LL_ENDL;
- if (mChannelInfo.isUndefined())
+ if (mChannelInfo.isUndefined() || (mChannelInfo.isMap() && mChannelInfo.size() == 0))
{
mChannelInfo = channelInfo;
}
@@ -477,7 +477,7 @@ void LLVoiceChannelGroup::setChannelInfo(const LLSD& channelInfo)
if (mState == STATE_NO_CHANNEL_INFO)
{
- if(!mChannelInfo.isUndefined())
+ if(mChannelInfo.isDefined() && mChannelInfo.isMap())
{
setState(STATE_READY);
@@ -676,9 +676,9 @@ void LLVoiceChannelProximal::activate()
// we're connected to a non-spatial channel, so disconnect.
LLVoiceClient::getInstance()->leaveNonSpatialChannel();
}
+
LLVoiceClient::getInstance()->activateSpatialChannel(true);
LLVoiceChannel::activate();
-
}
void LLVoiceChannelProximal::onChange(EStatusType type, const LLSD& channelInfo, bool proximal)
@@ -751,7 +751,7 @@ void LLVoiceChannelProximal::deactivate()
{
setState(STATE_HUNG_UP);
}
-
+ LLVoiceClient::getInstance()->removeObserver(this);
LLVoiceClient::getInstance()->activateSpatialChannel(false);
}
@@ -907,7 +907,7 @@ void LLVoiceChannelP2P::setChannelInfo(const LLSD& channel_info)
}
mReceivedCall = true;
- if (!channel_info.isUndefined())
+ if (channel_info.isDefined() && channel_info.isMap())
{
mIncomingCallInterface = LLVoiceClient::getInstance()->getIncomingCallInterface(channel_info);
}
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index f4a6438bbf..13f6488567 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -145,8 +145,9 @@ LLVoiceClient::LLVoiceClient(LLPumpIO *pump)
mSpatialVoiceModule(NULL),
mNonSpatialVoiceModule(NULL),
m_servicePump(NULL),
- mVoiceEffectEnabled(LLCachedControl(gSavedSettings, "VoiceMorphingEnabled", true)),
+ mVoiceEffectEnabled(LLCachedControl(gSavedSettings, "VoiceMorphingEnabled", false)),
mVoiceEffectDefault(LLCachedControl(gSavedPerAccountSettings, "VoiceEffectDefault", "00000000-0000-0000-0000-000000000000")),
+ mVoiceEffectSupportNotified(false),
mPTTDirty(true),
mPTT(true),
mUsePTT(true),
@@ -582,6 +583,26 @@ void LLVoiceClient::setMicGain(F32 gain)
//------------------------------------------
// enable/disable voice features
+// static
+bool LLVoiceClient::onVoiceEffectsNotSupported(const LLSD ¬ification, const LLSD &response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ switch (option)
+ {
+ case 0: // "Okay"
+ gSavedSettings.setBOOL("VoiceMorphingEnabled", FALSE);
+ break;
+
+ case 1: // "Cancel"
+ break;
+
+ default:
+ llassert(0);
+ break;
+ }
+ return false;
+}
+
// Bypass LLCachedControls for voice status update
//bool LLVoiceClient::voiceEnabled()
bool LLVoiceClient::voiceEnabled(bool no_cache)
@@ -594,7 +615,13 @@ bool LLVoiceClient::voiceEnabled(bool no_cache)
static LLCachedControl enable_voice_chat(gSavedSettings, "EnableVoiceChat");
static LLCachedControl cmd_line_disable_voice(gSavedSettings, "CmdLineDisableVoice");
- return enable_voice_chat && !cmd_line_disable_voice && !gNonInteractive;
+ bool enabled = enable_voice_chat && !cmd_line_disable_voice && !gNonInteractive;
+ if (enabled && !mVoiceEffectSupportNotified && getVoiceEffectEnabled() && !getVoiceEffectDefault().isNull())
+ {
+ LLNotificationsUtil::add("VoiceEffectsNotSupported", LLSD(), LLSD(), &LLVoiceClient::onVoiceEffectsNotSupported);
+ mVoiceEffectSupportNotified = true;
+ }
+ return enabled;
}
void LLVoiceClient::setVoiceEnabled(bool enabled)
@@ -875,7 +902,7 @@ std::string LLVoiceClient::sipURIFromID(const LLUUID &id)
LLVoiceEffectInterface* LLVoiceClient::getVoiceEffectInterface() const
{
- return getVoiceEffectEnabled() ? dynamic_cast(mSpatialVoiceModule) : NULL;
+ return NULL;
}
///////////////////
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index 89242863ac..d6078c656b 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -539,6 +539,8 @@ public:
protected:
+ static bool onVoiceEffectsNotSupported(const LLSD ¬ification, const LLSD &response);
+
LLVoiceModuleInterface* mSpatialVoiceModule;
LLVoiceModuleInterface* mNonSpatialVoiceModule;
LLSD mSpatialCredentials; // used to store spatial credentials for vivox
@@ -550,6 +552,7 @@ protected:
LLCachedControl mVoiceEffectEnabled;
LLCachedControl mVoiceEffectDefault;
+ bool mVoiceEffectSupportNotified;
bool mPTTDirty;
bool mPTT;
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index 1296bba5c5..bd994739ec 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -5248,25 +5248,31 @@ void LLVivoxVoiceClient::processChannels(bool process)
bool LLVivoxVoiceClient::isCurrentChannel(const LLSD &channelInfo)
{
- if (!mProcessChannels || (channelInfo["voice_server_type"].asString() != VIVOX_VOICE_SERVER_TYPE))
+ if (!mProcessChannels || (channelInfo.has("voice_server_type") && channelInfo["voice_server_type"].asString() != VIVOX_VOICE_SERVER_TYPE))
{
return false;
}
- if (mAudioSession)
+ // favor the next audio session, as that's the one we're bringing up.
+ sessionStatePtr_t session = mNextAudioSession;
+ if (!session)
+ {
+ session = mAudioSession;
+ }
+ if (session)
{
if (!channelInfo["session_handle"].asString().empty())
{
- return mAudioSession->mHandle == channelInfo["session_handle"].asString();
+ return session->mHandle == channelInfo["session_handle"].asString();
}
- return channelInfo["channel_uri"].asString() == mAudioSession->mSIPURI;
+ return channelInfo["channel_uri"].asString() == session->mSIPURI;
}
return false;
}
bool LLVivoxVoiceClient::compareChannels(const LLSD& channelInfo1, const LLSD& channelInfo2)
{
- return (channelInfo1["voice_server_type"] == VIVOX_VOICE_SERVER_TYPE) &&
- (channelInfo1["voice_server_type"] == channelInfo2["voice_server_type"]) &&
+ return (!channelInfo1.has("voice_server_type") || (channelInfo1["voice_server_type"] == VIVOX_VOICE_SERVER_TYPE)) &&
+ (!channelInfo2.has("voice_server_type") || (channelInfo2["voice_server_type"] == VIVOX_VOICE_SERVER_TYPE)) &&
(channelInfo1["channel_uri"] == channelInfo2["channel_uri"]);
}
diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp
index e0d6d6ec24..802b3a4337 100644
--- a/indra/newview/llvoicewebrtc.cpp
+++ b/indra/newview/llvoicewebrtc.cpp
@@ -24,7 +24,6 @@
* $/LicenseInfo$
*/
#include
-#include
#include "llvoicewebrtc.h"
#include "llsdutil.h"
@@ -86,7 +85,7 @@ namespace {
const F32 VOLUME_SCALE_WEBRTC = 0.01f;
const F32 LEVEL_SCALE_WEBRTC = 0.008f;
- const F32 SPEAKING_AUDIO_LEVEL = 0.35;
+ const F32 SPEAKING_AUDIO_LEVEL = 0.30;
static const std::string REPORTED_VOICE_SERVER_TYPE = "Secondlife WebRTC Gateway";
@@ -1486,14 +1485,10 @@ void LLWebRTCVoiceClient::setMicGain(F32 gain)
if (gain != mMicGain)
{
mMicGain = gain;
- sessionState::for_each(boost::bind(predSetMicGain, _1, gain));
+ mWebRTCDeviceInterface->setPeerConnectionGain(gain);
}
}
-void LLWebRTCVoiceClient::predSetMicGain(const LLWebRTCVoiceClient::sessionStatePtr_t &session, F32 gain)
-{
- session->setMicGain(gain);
-}
void LLWebRTCVoiceClient::setVoiceEnabled(bool enabled)
{
@@ -1692,7 +1687,6 @@ std::map LLWebRTCVoiceCli
LLWebRTCVoiceClient::sessionState::sessionState() :
mHangupOnLastLeave(false),
mNotifyOnFirstJoin(false),
- mMicGain(1.0),
mMuted(false),
mSpeakerVolume(1.0),
mShuttingDown(false)
@@ -1737,15 +1731,6 @@ void LLWebRTCVoiceClient::sessionState::setMuteMic(bool muted)
}
}
-void LLWebRTCVoiceClient::sessionState::setMicGain(F32 gain)
-{
- mMicGain = gain;
- for (auto &connection : mWebRTCConnections)
- {
- connection->setMicGain(gain);
- }
-}
-
void LLWebRTCVoiceClient::sessionState::setSpeakerVolume(F32 volume)
{
mSpeakerVolume = volume;
@@ -1850,7 +1835,6 @@ LLWebRTCVoiceClient::sessionStatePtr_t LLWebRTCVoiceClient::addSession(const std
LL_DEBUGS("Voice") << "adding new session with channel: " << channel_id << LL_ENDL;
session->setMuteMic(mMuteMic);
- session->setMicGain(mMicGain);
session->setSpeakerVolume(mSpeakerVolume);
sessionState::addSession(channel_id, session);
@@ -1976,7 +1960,6 @@ bool LLWebRTCVoiceClient::estateSessionState::processConnectionStates()
connectionPtr_t connection(new LLVoiceWebRTCSpatialConnection(neighbor, INVALID_PARCEL_ID, mChannelID));
mWebRTCConnections.push_back(connection);
- connection->setMicGain(mMicGain);
connection->setMuteMic(mMuted);
connection->setSpeakerVolume(mSpeakerVolume);
}
@@ -2106,7 +2089,6 @@ LLVoiceWebRTCConnection::LLVoiceWebRTCConnection(const LLUUID ®ionID, const s
mShutDown(false),
mIceCompleted(false),
mSpeakerVolume(0.0),
- mMicGain(0.0),
mOutstandingRequests(0),
mChannelID(channelID),
mRegionID(regionID),
@@ -2369,15 +2351,6 @@ void LLVoiceWebRTCConnection::setMuteMic(bool muted)
}
}
-void LLVoiceWebRTCConnection::setMicGain(F32 gain)
-{
- mMicGain = gain;
- if (mWebRTCAudioInterface)
- {
- mWebRTCAudioInterface->setSendVolume(gain);
- }
-}
-
void LLVoiceWebRTCConnection::setSpeakerVolume(F32 volume)
{
mSpeakerVolume = volume;
@@ -2679,7 +2652,6 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
// this connection.
mWebRTCAudioInterface->setMute(mMuted);
mWebRTCAudioInterface->setReceiveVolume(mSpeakerVolume);
- mWebRTCAudioInterface->setSendVolume(mMicGain);
LLWebRTCVoiceClient::getInstance()->OnConnectionEstablished(mChannelID, mRegionID);
setVoiceConnectionState(VOICE_STATE_WAIT_FOR_DATA_CHANNEL);
break;
diff --git a/indra/newview/llvoicewebrtc.h b/indra/newview/llvoicewebrtc.h
index c341ea6c94..480a7897cd 100644
--- a/indra/newview/llvoicewebrtc.h
+++ b/indra/newview/llvoicewebrtc.h
@@ -282,7 +282,6 @@ public:
virtual void sendData(const std::string &data);
void setMuteMic(bool muted);
- void setMicGain(F32 volume);
void setSpeakerVolume(F32 volume);
void setUserVolume(const LLUUID& id, F32 volume);
@@ -303,7 +302,6 @@ public:
std::string mName;
bool mMuted; // this session is muted.
- F32 mMicGain; // gain for this session.
F32 mSpeakerVolume; // volume for this session.
bool mShuttingDown;
@@ -382,7 +380,6 @@ public:
static void predSendData(const LLWebRTCVoiceClient::sessionStatePtr_t &session, const std::string& spatial_data);
static void predUpdateOwnVolume(const LLWebRTCVoiceClient::sessionStatePtr_t &session, F32 audio_level);
static void predSetMuteMic(const LLWebRTCVoiceClient::sessionStatePtr_t &session, bool mute);
- static void predSetMicGain(const LLWebRTCVoiceClient::sessionStatePtr_t &session, F32 volume);
static void predSetSpeakerVolume(const LLWebRTCVoiceClient::sessionStatePtr_t &session, F32 volume);
static void predShutdownSession(const LLWebRTCVoiceClient::sessionStatePtr_t &session);
static void predSetUserMute(const LLWebRTCVoiceClient::sessionStatePtr_t &session, const LLUUID& id, bool mute);
@@ -607,7 +604,6 @@ class LLVoiceWebRTCConnection :
void processIceUpdatesCoro();
virtual void setMuteMic(bool muted);
- virtual void setMicGain(F32 volume);
virtual void setSpeakerVolume(F32 volume);
void setUserVolume(const LLUUID& id, F32 volume);
@@ -686,7 +682,6 @@ class LLVoiceWebRTCConnection :
std::string mRemoteChannelSDP;
bool mMuted;
- F32 mMicGain;
F32 mSpeakerVolume;
bool mShutDown;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 1c46157376..346c4e31d5 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -979,19 +979,9 @@ void LLVOVolume::updateTextureVirtualSize(bool forced)
if (mSculptTexture.notNull())
{
- mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(),
- (S32)LLGLTexture::BOOST_SCULPTED));
mSculptTexture->setForSculpt() ;
- if(!mSculptTexture->isCachedRawImageReady())
- {
- S32 lod = llmin(mLOD, 3);
- F32 lodf = ((F32)(lod + 1.0f)/4.f);
- F32 tex_size = lodf * LLViewerTexture::sMaxSculptRez ;
- mSculptTexture->addTextureStats(2.f * tex_size * tex_size, false);
- }
-
- S32 texture_discard = mSculptTexture->getCachedRawImageLevel(); //try to match the texture
+ S32 texture_discard = mSculptTexture->getRawImageLevel(); //try to match the texture
S32 current_discard = getVolume() ? getVolume()->getSculptLevel() : -2 ;
if (texture_discard >= 0 && //texture has some data available
@@ -1316,7 +1306,9 @@ void LLVOVolume::updateSculptTexture()
LLUUID id = sculpt_params->getSculptTexture();
if (id.notNull())
{
- mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
+ mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, true, LLGLTexture::BOOST_SCULPTED, LLViewerTexture::LOD_TEXTURE);
+ mSculptTexture->forceToSaveRawImage(0, F32_MAX);
+ mSculptTexture->addTextureStats(256.f*256.f);
}
mSkinInfoUnavaliable = false;
@@ -1409,8 +1401,22 @@ void LLVOVolume::sculpt()
S8 sculpt_components = 0;
const U8* sculpt_data = NULL;
- S32 discard_level = mSculptTexture->getCachedRawImageLevel() ;
- LLImageRaw* raw_image = mSculptTexture->getCachedRawImage() ;
+ S32 discard_level = mSculptTexture->getRawImageLevel() ;
+ LLImageRaw* raw_image = mSculptTexture->getRawImage() ;
+
+ if (!raw_image)
+ {
+ raw_image = mSculptTexture->getSavedRawImage();
+ S32 discard_level = mSculptTexture->getSavedRawImageLevel();
+ }
+
+ if (!raw_image)
+ {
+ // last resort, read back from GL
+ mSculptTexture->readbackRawImage();
+ raw_image = mSculptTexture->getRawImage();
+ discard_level = mSculptTexture->getRawImageLevel();
+ }
S32 max_discard = mSculptTexture->getMaxDiscardLevel();
if (discard_level > max_discard)
@@ -1467,8 +1473,6 @@ void LLVOVolume::sculpt()
if(!raw_image)
{
- llassert(discard_level < 0) ;
-
sculpt_width = 0;
sculpt_height = 0;
sculpt_data = NULL ;
@@ -2222,6 +2226,7 @@ bool LLVOVolume::updateGeometry(LLDrawable *drawable)
if (mDrawable->isState(LLDrawable::REBUILD_RIGGED))
{
+ LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("rebuild rigged");
updateRiggedVolume(false);
genBBoxes(false);
mDrawable->clearState(LLDrawable::REBUILD_RIGGED);
diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp
index 87fd58a6ea..fedfa7299e 100644
--- a/indra/newview/llvowater.cpp
+++ b/indra/newview/llvowater.cpp
@@ -62,7 +62,6 @@ LLVOWater::LLVOWater(const LLUUID &id,
setScale(LLVector3(mRegionp->getWidth(), mRegionp->getWidth(), 0.f));
//
Aurora Sim
- mUseTexture = true;
mIsEdgePatch = false;
}
@@ -104,14 +103,7 @@ LLDrawable *LLVOWater::createDrawable(LLPipeline *pipeline)
LLDrawPoolWater *pool = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER);
- if (mUseTexture)
- {
- mDrawable->setNumFaces(1, pool, mRegionp->getLand().getWaterTexture());
- }
- else
- {
- mDrawable->setNumFaces(1, pool, LLWorld::getInstance()->getDefaultWaterTexture());
- }
+ mDrawable->setNumFaces(1, pool, LLWorld::getInstance()->getDefaultWaterTexture());
return mDrawable;
}
@@ -252,11 +244,6 @@ void setVecZ(LLVector3& v)
v.mV[VZ] = 1;
}
-void LLVOWater::setUseTexture(const bool use_texture)
-{
- mUseTexture = use_texture;
-}
-
void LLVOWater::setIsEdgePatch(const bool edge_patch)
{
mIsEdgePatch = edge_patch;
diff --git a/indra/newview/llvowater.h b/indra/newview/llvowater.h
index adae86691a..ba3da510c4 100644
--- a/indra/newview/llvowater.h
+++ b/indra/newview/llvowater.h
@@ -70,13 +70,10 @@ public:
/*virtual*/ bool isActive() const; // Whether this object needs to do an idleUpdate.
- void setUseTexture(const bool use_texture);
void setIsEdgePatch(const bool edge_patch);
- bool getUseTexture() const { return mUseTexture; }
bool getIsEdgePatch() const { return mIsEdgePatch; }
protected:
- bool mUseTexture;
bool mIsEdgePatch;
S32 mRenderType;
};
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 781ea257b5..e5088239ff 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -1416,7 +1416,6 @@ void LLWorld::updateWaterObjects()
if (!getRegionFromHandle(region_handle))
{ // No region at that area, so make water
LLVOWater* waterp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, gAgent.getRegion());
- waterp->setUseTexture(false);
// Fix water height on regions larger than 2048x2048
//waterp->setPositionGlobal(LLVector3d(x + rwidth/2,
// y + rwidth/2,
@@ -1484,7 +1483,6 @@ void LLWorld::updateWaterObjects()
mEdgeWaterObjects[dir] = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER,
gAgent.getRegion());
waterp = mEdgeWaterObjects[dir];
- waterp->setUseTexture(false);
waterp->setIsEdgePatch(true);
gPipeline.createObject(waterp);
}
diff --git a/indra/newview/llworldmipmap.cpp b/indra/newview/llworldmipmap.cpp
index 769ed2a4a2..6f8869a2aa 100644
--- a/indra/newview/llworldmipmap.cpp
+++ b/indra/newview/llworldmipmap.cpp
@@ -186,6 +186,7 @@ LLPointer LLWorldMipmap::getObjectsTile(U32 grid_x, U32
}
}
+//static
LLPointer LLWorldMipmap::loadObjectsTile(U32 grid_x, U32 grid_y, S32 level)
{
// Get the grid coordinates
diff --git a/indra/newview/llworldmipmap.h b/indra/newview/llworldmipmap.h
index ab98b55b72..907f24d1e7 100644
--- a/indra/newview/llworldmipmap.h
+++ b/indra/newview/llworldmipmap.h
@@ -74,11 +74,13 @@ public:
// Convert world coordinates to mipmap grid coordinates at a given level
static void globalToMipmap(F64 global_x, F64 global_y, S32 level, U32* grid_x, U32* grid_y);
+ // Load the relevant tile from S3
+ static LLPointer loadObjectsTile(U32 grid_x, U32 grid_y, S32 level);
+
private:
// Get a handle (key) from grid coordinates
U64 convertGridToHandle(U32 grid_x, U32 grid_y) { return to_region_handle(grid_x * REGION_WIDTH_UNITS, grid_y * REGION_WIDTH_UNITS); }
- // Load the relevant tile from S3
- LLPointer loadObjectsTile(U32 grid_x, U32 grid_y, S32 level);
+
// Clear a level from its "missing" tiles
void cleanMissedTilesFromLevel(S32 level);
diff --git a/indra/newview/llxmlrpclistener.cpp b/indra/newview/llxmlrpclistener.cpp
index 1148e81fd5..7c7bd98bcd 100644
--- a/indra/newview/llxmlrpclistener.cpp
+++ b/indra/newview/llxmlrpclistener.cpp
@@ -39,12 +39,6 @@
#include
#include // boost::begin(), boost::end()
-#ifdef LL_USESYSTEMLIBS
-#include
-#else
-#include
-#endif
-
#include "curl/curl.h"
// other Linden headers
@@ -178,13 +172,6 @@ public:
static const CURLcodeMapper sCURLcodeMapper;
-LLXMLRPCListener::LLXMLRPCListener(const std::string& pumpname):
- mBoundListener(LLEventPumps::instance().
- obtain(pumpname).
- listen("LLXMLRPCListener", boost::bind(&LLXMLRPCListener::process, this, _1)))
-{
-}
-
/**
* Capture an outstanding LLXMLRPCTransaction and poll it periodically until
* done.
@@ -213,38 +200,20 @@ public:
mMethod(command["method"]),
mReplyPump(command["reply"])
{
- // LL_ERRS if any of these are missing
- const char* required[] = { "uri", "method", "reply" };
- // optional: "options" (array of string)
- // Validate the request
- std::set missing;
- for (const char** ri = boost::begin(required); ri != boost::end(required); ++ri)
+ // LL_ERRS if any of these keys are missing or empty
+ if (mUri.empty() || mMethod.empty() || mReplyPump.empty())
{
- // If the command does not contain this required entry, add it to 'missing'.
- if (! command.has(*ri))
- {
- missing.insert(*ri);
- }
- }
- if (! missing.empty())
- {
- LL_ERRS("LLXMLRPCListener") << mMethod << " request missing params: ";
- const char* separator = "";
- for (std::set::const_iterator mi(missing.begin()), mend(missing.end());
- mi != mend; ++mi)
- {
- LL_CONT << separator << *mi;
- separator = ", ";
- }
- LL_CONT << LL_ENDL;
+ LL_ERRS("LLXMLRPCListener")
+ << "Some params are missing: "
+ << "reply: '" << mReplyPump << "', "
+ << "method: '" << mMethod << "', "
+ << "uri: '" << mUri << "'"
+ << LL_ENDL;
}
- // Build the XMLRPC request.
- XMLRPC_REQUEST request = XMLRPC_RequestNew();
- XMLRPC_RequestSetMethodName(request, mMethod.c_str());
- XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
- XMLRPC_VALUE xparams = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
- LLSD params(command["params"]);
+ LLSD request_params = LLSD::emptyMap();
+
+ LLSD params = command.get("params");
if (params.isMap())
{
for (LLSD::map_const_iterator pi(params.beginMap()), pend(params.endMap());
@@ -252,44 +221,33 @@ public:
{
std::string name(pi->first);
LLSD param(pi->second);
- if (param.isString())
+ switch (param.type())
{
- XMLRPC_VectorAppendString(xparams, name.c_str(), param.asString().c_str(), 0);
- }
- else if (param.isInteger() || param.isBoolean())
- {
- XMLRPC_VectorAppendInt(xparams, name.c_str(), param.asInteger());
- }
- else if (param.isReal())
- {
- XMLRPC_VectorAppendDouble(xparams, name.c_str(), param.asReal());
- }
- else
- {
- LL_ERRS("LLXMLRPCListener") << mMethod << " request param "
- << name << " has unknown type: " << param << LL_ENDL;
+ case LLSD::TypeString:
+ case LLSD::TypeInteger:
+ case LLSD::TypeReal:
+ request_params.insert(name, param);
+ break;
+ case LLSD::TypeBoolean:
+ request_params.insert(name, param.asInteger());
+ break;
+ default:
+ LL_ERRS("LLXMLRPCListener") << mMethod
+ << " request param '" << name << "' has unknown type: " << param << LL_ENDL;
}
}
}
- LLSD options(command["options"]);
+
+ LLSD options = command.get("options");
if (options.isArray())
{
- XMLRPC_VALUE xoptions = XMLRPC_CreateVector("options", xmlrpc_vector_array);
- for (LLSD::array_const_iterator oi(options.beginArray()), oend(options.endArray());
- oi != oend; ++oi)
- {
- XMLRPC_VectorAppendString(xoptions, NULL, oi->asString().c_str(), 0);
- }
- XMLRPC_AddValueToVector(xparams, xoptions);
+ request_params.insert("options", options);
}
- XMLRPC_RequestSetData(request, xparams);
- mTransaction.reset(new LLXMLRPCTransaction(mUri, request, true, command.has("http_params")? LLSD(command["http_params"]) : LLSD()));
+ LLSD http_params = command.get("http_params");
+ mTransaction.reset(new LLXMLRPCTransaction(mUri, mMethod, request_params, http_params));
mPreviousStatus = mTransaction->status(NULL);
- // Free the XMLRPC_REQUEST object and the attached data values.
- XMLRPC_RequestFree(request, 1);
-
// Now ensure that we get regular callbacks to poll for completion.
mBoundListener =
LLEventPumps::instance().
@@ -323,7 +281,7 @@ public:
data["error"] = "";
data["transfer_rate"] = 0.0;
LLEventPump& replyPump(LLEventPumps::instance().obtain(mReplyPump));
- if (! done)
+ if (!done)
{
// Not done yet, carry on.
if (status == LLXMLRPCTransaction::StatusDownloading
@@ -367,10 +325,8 @@ public:
// Given 'message', need we care?
if (status == LLXMLRPCTransaction::StatusComplete)
{
- // Success! Parse data.
- std::string status_string(data["status"]);
- data["responses"] = parseResponse(status_string);
- data["status"] = status_string;
+ // Success! Retrieve response data.
+ data["responses"] = mTransaction->response();
}
// whether successful or not, send reply on requested LLEventPump
@@ -388,159 +344,6 @@ public:
}
private:
- /// Derived from LLUserAuth::parseResponse() and parseOptionInto()
- LLSD parseResponse(std::string& status_string)
- {
- // Extract every member into data["responses"] (a map of string
- // values).
- XMLRPC_REQUEST response = mTransaction->response();
- if (! response)
- {
- LL_DEBUGS("LLXMLRPCListener") << "No response" << LL_ENDL;
- return LLSD();
- }
-
- XMLRPC_VALUE param = XMLRPC_RequestGetData(response);
- if (! param)
- {
- LL_DEBUGS("LLXMLRPCListener") << "Response contains no data" << LL_ENDL;
- return LLSD();
- }
-
- // Now, parse everything
- return parseValues(status_string, "", param);
- }
-
- LLSD parseValue(std::string& status_string, const std::string& key, const std::string& key_pfx, XMLRPC_VALUE param)
- {
- LLSD response;
-
- XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(param);
- switch (type)
- {
- case xmlrpc_type_empty:
- LL_INFOS("LLXMLRPCListener") << "Empty result for key " << key_pfx << key << LL_ENDL;
- break;
- case xmlrpc_type_base64:
- {
- S32 len = XMLRPC_GetValueStringLen(param);
- const char* buf = XMLRPC_GetValueBase64(param);
- if ((len > 0) && buf)
- {
- // During implementation this code was not tested
- // If you encounter this, please make sure this is correct,
- // then remove llassert
- llassert(0);
-
- LLSD::Binary data;
- data.resize(len);
- memcpy((void*)&data[0], (void*)buf, len);
- response = data;
- }
- else
- {
- LL_WARNS("LLXMLRPCListener") << "Potentially malformed xmlrpc_type_base64 for key "
- << key_pfx << key << LL_ENDL;
- }
- break;
- }
- case xmlrpc_type_boolean:
- {
- response = LLSD::Boolean(XMLRPC_GetValueBoolean(param));
- LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL;
- break;
- }
- case xmlrpc_type_datetime:
- {
- std::string iso8601_date(XMLRPC_GetValueDateTime_ISO8601(param));
- LL_DEBUGS("LLXMLRPCListener") << "val: " << iso8601_date << LL_ENDL;
- response = LLSD::Date(iso8601_date);
- break;
- }
- case xmlrpc_type_double:
- {
- response = LLSD::Real(XMLRPC_GetValueDouble(param));
- LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL;
- break;
- }
- case xmlrpc_type_int:
- {
- response = LLSD::Integer(XMLRPC_GetValueInt(param));
- LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL;
- break;
- }
- case xmlrpc_type_string:
- {
- response = LLSD::String(XMLRPC_GetValueString(param));
- LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL;
- break;
- }
- case xmlrpc_type_mixed:
- case xmlrpc_type_array:
- {
- // We expect this to be an array of submaps. Walk the array,
- // recursively parsing each submap and collecting them.
- LLSD array;
- int i = 0; // for descriptive purposes
- for (XMLRPC_VALUE row = XMLRPC_VectorRewind(param); row;
- row = XMLRPC_VectorNext(param), ++i)
- {
- // Recursive call. For the lower-level key_pfx, if 'key'
- // is "foo", pass "foo[0]:", then "foo[1]:", etc. In the
- // nested call, a subkey "bar" will then be logged as
- // "foo[0]:bar", and so forth.
- // Parse the scalar subkey/value pairs from this array
- // entry into a temp submap. Collect such submaps in 'array'.
-
- array.append(parseValue(status_string, "",
- STRINGIZE(key_pfx << key << '[' << i << "]:"),
- row));
- }
- // Having collected an 'array' of 'submap's, insert that whole
- // 'array' as the value of this 'key'.
- response = array;
- break;
- }
- case xmlrpc_type_struct:
- {
- response = parseValues(status_string,
- STRINGIZE(key_pfx << key << ':'),
- param);
- break;
- }
- case xmlrpc_type_none: // Not expected
- default:
- // whoops - unrecognized type
- LL_WARNS("LLXMLRPCListener") << "Unhandled xmlrpc type " << type << " for key "
- << key_pfx << key << LL_ENDL;
- response = STRINGIZE("');
- status_string = "BadType";
- }
- return response;
- }
-
- /**
- * Parse key/value pairs from a given XMLRPC_VALUE into an LLSD map.
- * @param key_pfx Used to describe a given key in log messages. At top
- * level, pass "". When parsing an options array, pass the top-level key
- * name of the array plus the index of the array entry; to this we'll
- * append the subkey of interest.
- * @param param XMLRPC_VALUE iterator. At top level, pass
- * XMLRPC_RequestGetData(XMLRPC_REQUEST).
- */
- LLSD parseValues(std::string& status_string, const std::string& key_pfx, XMLRPC_VALUE param)
- {
- LLSD responses;
- for (XMLRPC_VALUE current = XMLRPC_VectorRewind(param); current;
- current = XMLRPC_VectorNext(param))
- {
- std::string key(XMLRPC_GetValueID(current));
- LL_DEBUGS("LLXMLRPCListener") << "key: " << key_pfx << key << LL_ENDL;
- responses.insert(key, parseValue(status_string, key, key_pfx, current));
- }
- return responses;
- }
-
const LLReqID mReqID;
const std::string mUri;
const std::string mMethod;
@@ -550,11 +353,18 @@ private:
LLXMLRPCTransaction::EStatus mPreviousStatus; // To detect state changes.
};
-bool LLXMLRPCListener::process(const LLSD& command)
+LLXMLRPCListener::LLXMLRPCListener(const std::string& pumpname)
+: mBoundListener(LLEventPumps::instance().obtain(pumpname).listen
+(
+ "LLXMLRPCListener",
+ [&](const LLSD& command) -> bool
+ {
+ // Allocate a new heap Poller, but do not save a pointer to it. Poller
+ // will check its own status and free itself on completion of the request.
+ (new Poller(command));
+ // Conventional event listener return
+ return false;
+ }
+))
{
- // Allocate a new heap Poller, but do not save a pointer to it. Poller
- // will check its own status and free itself on completion of the request.
- (new Poller(command));
- // conventional event listener return
- return false;
}
diff --git a/indra/newview/llxmlrpclistener.h b/indra/newview/llxmlrpclistener.h
index aaed98eec5..fd75acb8b1 100644
--- a/indra/newview/llxmlrpclistener.h
+++ b/indra/newview/llxmlrpclistener.h
@@ -42,9 +42,6 @@ public:
/// Specify the pump name on which to listen
LLXMLRPCListener(const std::string& pumpname);
- /// Handle request events on the event pump specified at construction time
- bool process(const LLSD& command);
-
private:
LLTempBoundListener mBoundListener;
};
diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp
index 549cfbb484..36630c8b42 100644
--- a/indra/newview/llxmlrpctransaction.cpp
+++ b/indra/newview/llxmlrpctransaction.cpp
@@ -42,22 +42,11 @@
#include "bufferarray.h"
#include "llversioninfo.h"
#include "llviewercontrol.h"
+#include "llxmlnode.h"
#include "stringize.h"
// Have to include these last to avoid queue redefinition!
-#ifdef LL_USESYSTEMLIBS
-#include
-#else
-#include
-#endif
-// contains a harmful #define queue xmlrpc_queue. This
-// breaks any use of std::queue. Ditch that #define: if any of our code wants
-// to reference xmlrpc_queue, let it reference it directly.
-#if defined(queue)
-#undef queue
-#endif
-
#include "llappviewer.h"
#include "lltrans.h"
@@ -75,111 +64,6 @@ namespace boost
// nothing.
static LLXMLRPCListener listener("LLXMLRPCTransaction");
-LLXMLRPCValue LLXMLRPCValue::operator[](const char* id) const
-{
- return LLXMLRPCValue(XMLRPC_VectorGetValueWithID(mV, id));
-}
-
-std::string LLXMLRPCValue::asString() const
-{
- const char* s = XMLRPC_GetValueString(mV);
- return s ? s : "";
-}
-
-int LLXMLRPCValue::asInt() const { return XMLRPC_GetValueInt(mV); }
-bool LLXMLRPCValue::asBool() const { return XMLRPC_GetValueBoolean(mV) != 0; }
-double LLXMLRPCValue::asDouble() const { return XMLRPC_GetValueDouble(mV); }
-
-LLXMLRPCValue LLXMLRPCValue::rewind()
-{
- return LLXMLRPCValue(XMLRPC_VectorRewind(mV));
-}
-
-LLXMLRPCValue LLXMLRPCValue::next()
-{
- return LLXMLRPCValue(XMLRPC_VectorNext(mV));
-}
-
-bool LLXMLRPCValue::isValid() const
-{
- return mV != NULL;
-}
-
-LLXMLRPCValue LLXMLRPCValue::createArray()
-{
- return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_array));
-}
-
-LLXMLRPCValue LLXMLRPCValue::createStruct()
-{
- return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_struct));
-}
-
-
-void LLXMLRPCValue::append(LLXMLRPCValue& v)
-{
- XMLRPC_AddValueToVector(mV, v.mV);
-}
-
-void LLXMLRPCValue::appendString(const std::string& v)
-{
- XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(NULL, v.c_str(), 0));
-}
-
-void LLXMLRPCValue::appendInt(int v)
-{
- XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(NULL, v));
-}
-
-void LLXMLRPCValue::appendBool(bool v)
-{
- XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(NULL, v));
-}
-
-void LLXMLRPCValue::appendDouble(double v)
-{
- XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(NULL, v));
-}
-
-
-void LLXMLRPCValue::append(const char* id, LLXMLRPCValue& v)
-{
- XMLRPC_SetValueID(v.mV, id, 0);
- XMLRPC_AddValueToVector(mV, v.mV);
-}
-
-void LLXMLRPCValue::appendString(const char* id, const std::string& v)
-{
- XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(id, v.c_str(), 0));
-}
-
-void LLXMLRPCValue::appendInt(const char* id, int v)
-{
- XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(id, v));
-}
-
-void LLXMLRPCValue::appendBool(const char* id, bool v)
-{
- XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(id, v));
-}
-
-void LLXMLRPCValue::appendDouble(const char* id, double v)
-{
- XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(id, v));
-}
-
-void LLXMLRPCValue::cleanup()
-{
- XMLRPC_CleanupValue(mV);
- mV = NULL;
-}
-
-XMLRPC_VALUE LLXMLRPCValue::getValue() const
-{
- return mV;
-}
-
-
class LLXMLRPCTransaction::Handler : public LLCore::HttpHandler
{
public:
@@ -192,6 +76,9 @@ public:
private:
+ bool parseResponse(LLXMLNodePtr root);
+ bool parseValue(LLSD& target, LLXMLNodePtr source);
+
LLXMLRPCTransaction::Impl *mImpl;
LLCore::HttpRequest::ptr_t mRequest;
};
@@ -213,26 +100,26 @@ public:
LLCore::HttpHandle mPostH;
std::string mURI;
-
std::string mProxyAddress;
std::string mResponseText;
- XMLRPC_REQUEST mResponse;
- std::string mCertStore;
- LLSD mErrorCertData;
+ LLSD mResponseData;
- Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams);
- Impl(const std::string& uri,
- const std::string& method, LLXMLRPCValue params, bool useGzip);
- ~Impl();
+ std::string mCertStore;
+ LLSD mErrorCertData;
+
+ Impl
+ (
+ const std::string& uri,
+ const std::string& method,
+ const LLSD& params,
+ const LLSD& httpParams
+ );
bool process();
void setStatus(EStatus code, const std::string& message = "", const std::string& uri = "");
void setHttpStatus(const LLCore::HttpStatus &status);
-
-private:
- void init(XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams);
};
LLXMLRPCTransaction::Handler::Handler(LLCore::HttpRequest::ptr_t &request,
@@ -275,7 +162,7 @@ void LLXMLRPCTransaction::Handler::onCompleted(LLCore::HttpHandle handle,
mImpl->setStatus(LLXMLRPCTransaction::StatusComplete);
mImpl->mTransferStats = response->getTransferStats();
- // the contents of a buffer array are potentially noncontiguous, so we
+ // The contents of a buffer array are potentially noncontiguous, so we
// will need to copy them into an contiguous block of memory for XMLRPC.
LLCore::BufferArray *body = response->getBody();
@@ -294,85 +181,109 @@ void LLXMLRPCTransaction::Handler::onCompleted(LLCore::HttpHandle handle,
return;
}
//
- char * bodydata = new char[body->size()];
+ mImpl->mResponseText.resize(body->size());
- body->read(0, bodydata, body->size());
+ body->read(0, mImpl->mResponseText.data(), body->size());
- mImpl->mResponse = XMLRPC_REQUEST_FromXML(bodydata, static_cast(body->size()), 0);
-
- delete[] bodydata;
-
- bool hasError = false;
- bool hasFault = false;
- int faultCode = 0;
- std::string faultString;
-
- LLXMLRPCValue error(XMLRPC_RequestGetError(mImpl->mResponse));
- if (error.isValid())
+ LLXMLNodePtr root;
+ if (!LLXMLNode::parseBuffer(mImpl->mResponseText.data(), body->size(), root, nullptr))
{
- hasError = true;
- faultCode = error["faultCode"].asInt();
- faultString = error["faultString"].asString();
- }
- else if (XMLRPC_ResponseIsFault(mImpl->mResponse))
- {
- hasFault = true;
- faultCode = XMLRPC_GetResponseFaultCode(mImpl->mResponse);
- faultString = XMLRPC_GetResponseFaultString(mImpl->mResponse);
+ LL_WARNS() << "Failed parsing XML response; request URI: " << mImpl->mURI << LL_ENDL;
+ return;
}
- if (hasError || hasFault)
- {
- mImpl->setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
+ if (!parseResponse(root))
+ return;
- LL_WARNS() << "LLXMLRPCTransaction XMLRPC "
- << (hasError ? "error " : "fault ")
- << faultCode << ": "
- << faultString << LL_ENDL;
- LL_WARNS() << "LLXMLRPCTransaction request URI: "
- << mImpl->mURI << LL_ENDL;
+ LL_INFOS() << "XML response parsed successfully; request URI: " << mImpl->mURI << LL_ENDL;
+}
+
+struct XMLTreeNode final : public LLSD::TreeNode
+{
+ XMLTreeNode(const LLXMLNodePtr impl)
+ : mImpl(impl)
+ , mFirstChild(impl ? create(impl->getFirstChild()) : nullptr)
+ , mNextSibling(impl ? create(impl->getNextSibling()) : nullptr)
+ {
}
+
+ static XMLTreeNode* create(LLXMLNodePtr node) { return node ? new XMLTreeNode(node) : nullptr; }
+
+ virtual bool hasName(const LLSD::String& name) const override { return mImpl && mImpl->hasName(name); }
+ virtual LLSD::String getTextContents() const override { return mImpl ? mImpl->getTextContents() : LLStringUtil::null; }
+ virtual TreeNode* getFirstChild() const override { return mFirstChild.get(); }
+ virtual TreeNode* getNextSibling() const override { return mNextSibling.get(); }
+
+private:
+ const LLXMLNodePtr mImpl;
+ const std::shared_ptr mFirstChild;
+ const std::shared_ptr mNextSibling;
+};
+
+bool LLXMLRPCTransaction::Handler::parseResponse(LLXMLNodePtr root)
+{
+ // We have alreasy checked in LLXMLNode::parseBuffer()
+ // that root contains exactly one child
+ if (!root->hasName("methodResponse"))
+ {
+ LL_WARNS() << "Invalid root element in XML response; request URI: " << mImpl->mURI << LL_ENDL;
+ return false;
+ }
+
+ LLXMLNodePtr first = root->getFirstChild();
+ LLXMLNodePtr second = first->getFirstChild();
+ if (!first->getNextSibling() && second && !second->getNextSibling())
+ {
+ if (first->hasName("fault"))
+ {
+ LLSD fault;
+ if (parseValue(fault, second) &&
+ fault.isMap() && fault.has("faultCode") && fault.has("faultString"))
+ {
+ LL_WARNS() << "Request failed;"
+ << " faultCode: '" << fault.get("faultCode").asString() << "',"
+ << " faultString: '" << fault.get("faultString").asString() << "',"
+ << " request URI: " << mImpl->mURI << LL_ENDL;
+ return false;
+ }
+ }
+ else if (first->hasName("params") &&
+ second->hasName("param") && !second->getNextSibling())
+ {
+ LLXMLNodePtr third = second->getFirstChild();
+ if (third && !third->getNextSibling() && parseValue(mImpl->mResponseData, third))
+ {
+ return true;
+ }
+ }
+ }
+ LL_WARNS() << "Invalid response format; request URI: " << mImpl->mURI << LL_ENDL;
+
+ return false;
+}
+
+bool LLXMLRPCTransaction::Handler::parseValue(LLSD& target, LLXMLNodePtr source)
+{
+ XMLTreeNode tn(source);
+ return target.fromXMLRPCValue(&tn);
}
//=========================================================================
-LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
- XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams)
- : mHttpRequest(),
- mStatus(LLXMLRPCTransaction::StatusNotStarted),
- mURI(uri),
- mResponse(0)
-{
- init(request, useGzip, httpParams);
-}
-
-
-LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
- const std::string& method, LLXMLRPCValue params, bool useGzip)
- : mHttpRequest(),
- mStatus(LLXMLRPCTransaction::StatusNotStarted),
- mURI(uri),
- mResponse(0)
-{
- XMLRPC_REQUEST request = XMLRPC_RequestNew();
- XMLRPC_RequestSetMethodName(request, method.c_str());
- XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
- XMLRPC_RequestSetData(request, params.getValue());
-
- init(request, useGzip, LLSD());
- // DEV-28398: without this XMLRPC_RequestFree() call, it looks as though
- // the 'request' object is simply leaked. It's less clear to me whether we
- // should also ask to free request value data (second param 1), since the
- // data come from 'params'.
- XMLRPC_RequestFree(request, 1);
-}
-
-void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams)
+LLXMLRPCTransaction::Impl::Impl
+(
+ const std::string& uri,
+ const std::string& method,
+ const LLSD& params,
+ const LLSD& http_params
+)
+ : mHttpRequest()
+ , mStatus(LLXMLRPCTransaction::StatusNotStarted)
+ , mURI(uri)
{
LLCore::HttpOptions::ptr_t httpOpts;
LLCore::HttpHeaders::ptr_t httpHeaders;
-
if (!mHttpRequest)
{
mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest);
@@ -381,37 +292,34 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const
// LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer
httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions());
- // delay between repeats will start from 5 sec and grow to 20 sec with each repeat
+ // Delay between repeats will start from 5 sec and grow to 20 sec with each repeat
httpOpts->setMinBackoff(5E6L);
httpOpts->setMaxBackoff(20E6L);
- httpOpts->setTimeout(httpParams.has("timeout") ? httpParams["timeout"].asInteger() : 40L);
- if (httpParams.has("retries"))
+ httpOpts->setTimeout(http_params.has("timeout") ? http_params["timeout"].asInteger() : 40L);
+ if (http_params.has("retries"))
{
- httpOpts->setRetries(httpParams["retries"].asInteger());
+ httpOpts->setRetries(http_params["retries"].asInteger());
}
- if (httpParams.has("DNSCacheTimeout"))
+ if (http_params.has("DNSCacheTimeout"))
{
- httpOpts->setDNSCacheTimeout(httpParams["DNSCacheTimeout"].asInteger());
+ httpOpts->setDNSCacheTimeout(http_params["DNSCacheTimeout"].asInteger());
}
bool vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
mCertStore = gSavedSettings.getString("CertStore");
- httpOpts->setSSLVerifyPeer( vefifySSLCert );
- httpOpts->setSSLVerifyHost( vefifySSLCert );
+ httpOpts->setSSLVerifyPeer(vefifySSLCert);
+ httpOpts->setSSLVerifyHost(vefifySSLCert);
// LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer
httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders());
httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
- std::string user_agent = stringize(
- LLVersionInfo::instance().getChannel(), ' ',
- LLVersionInfo::instance().getMajor(), '.',
- LLVersionInfo::instance().getMinor(), '.',
- LLVersionInfo::instance().getPatch(), " (",
- LLVersionInfo::instance().getBuild(), ')');
+ const LLVersionInfo& vi(LLVersionInfo::instance());
+ std::string user_agent = vi.getChannel() + llformat(" %d.%d.%d (%llu)",
+ vi.getMajor(), vi.getMinor(), vi.getPatch(), vi.getBuild());
httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
@@ -419,31 +327,19 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const
//This might help with bug #503 */
//httpOpts->setDNSCacheTimeout(-1);
+ std::string request =
+ "" + method +
+ "" + params.asXMLRPCValue() +
+ "";
+
LLCore::BufferArray::ptr_t body = LLCore::BufferArray::ptr_t(new LLCore::BufferArray());
- // TODO: See if there is a way to serialize to a preallocated buffer I'm
- // not fond of the copy here.
- int requestSize(0);
- char * requestText = XMLRPC_REQUEST_ToXML(request, &requestSize);
+ body->append(request.c_str(), request.size());
- body->append(requestText, requestSize);
-
- XMLRPC_Free(requestText);
-
- mHandler = LLXMLRPCTransaction::Handler::ptr_t(new Handler( mHttpRequest, this ));
+ mHandler = LLXMLRPCTransaction::Handler::ptr_t(new Handler(mHttpRequest, this));
mPostH = mHttpRequest->requestPost(LLCore::HttpRequest::DEFAULT_POLICY_ID,
mURI, body.get(), httpOpts, httpHeaders, mHandler);
-
-}
-
-
-LLXMLRPCTransaction::Impl::~Impl()
-{
- if (mResponse)
- {
- XMLRPC_RequestFree(mResponse, 1);
- }
}
bool LLXMLRPCTransaction::Impl::process()
@@ -557,18 +453,16 @@ void LLXMLRPCTransaction::Impl::setHttpStatus(const LLCore::HttpStatus &status)
}
-
-LLXMLRPCTransaction::LLXMLRPCTransaction(
- const std::string& uri, XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams)
-: impl(* new Impl(uri, request, useGzip, httpParams))
-{ }
-
-
-LLXMLRPCTransaction::LLXMLRPCTransaction(
+LLXMLRPCTransaction::LLXMLRPCTransaction
+(
const std::string& uri,
- const std::string& method, LLXMLRPCValue params, bool useGzip)
-: impl(* new Impl(uri, method, params, useGzip))
-{ }
+ const std::string& method,
+ const LLSD& params,
+ const LLSD& http_params
+)
+: impl(*new Impl(uri, method, params, http_params))
+{
+}
LLXMLRPCTransaction::~LLXMLRPCTransaction()
{
@@ -608,14 +502,9 @@ std::string LLXMLRPCTransaction::statusURI()
return impl.mStatusURI;
}
-XMLRPC_REQUEST LLXMLRPCTransaction::response()
+const LLSD& LLXMLRPCTransaction::response()
{
- return impl.mResponse;
-}
-
-LLXMLRPCValue LLXMLRPCTransaction::responseValue()
-{
- return LLXMLRPCValue(XMLRPC_RequestGetData(impl.mResponse));
+ return impl.mResponseData;
}
diff --git a/indra/newview/llxmlrpctransaction.h b/indra/newview/llxmlrpctransaction.h
index 4c8796f936..f7a38f5f90 100644
--- a/indra/newview/llxmlrpctransaction.h
+++ b/indra/newview/llxmlrpctransaction.h
@@ -29,73 +29,22 @@
#include
-typedef struct _xmlrpc_request* XMLRPC_REQUEST;
-typedef struct _xmlrpc_value* XMLRPC_VALUE;
- // foward decl of types from xmlrpc.h (this usage is type safe)
-class LLCertificate;
-
-class LLXMLRPCValue
- // a c++ wrapper around XMLRPC_VALUE
-{
-public:
- LLXMLRPCValue() : mV(NULL) { }
- LLXMLRPCValue(XMLRPC_VALUE value) : mV(value) { }
-
- bool isValid() const;
-
- std::string asString() const;
- int asInt() const;
- bool asBool() const;
- double asDouble() const;
-
- LLXMLRPCValue operator[](const char*) const;
-
- LLXMLRPCValue rewind();
- LLXMLRPCValue next();
-
- static LLXMLRPCValue createArray();
- static LLXMLRPCValue createStruct();
-
- void append(LLXMLRPCValue&);
- void appendString(const std::string&);
- void appendInt(int);
- void appendBool(bool);
- void appendDouble(double);
- void appendValue(LLXMLRPCValue&);
-
- void append(const char*, LLXMLRPCValue&);
- void appendString(const char*, const std::string&);
- void appendInt(const char*, int);
- void appendBool(const char*, bool);
- void appendDouble(const char*, double);
- void appendValue(const char*, LLXMLRPCValue&);
-
- void cleanup();
- // only call this on the top level created value
-
- XMLRPC_VALUE getValue() const;
-
-private:
- XMLRPC_VALUE mV;
-};
-
-
+/// An asynchronous request and responses via XML-RPC
class LLXMLRPCTransaction
- // an asynchronous request and responses via XML-RPC
{
public:
- LLXMLRPCTransaction(const std::string& uri,
- XMLRPC_REQUEST request, bool useGzip = true, const LLSD& httpParams = LLSD());
- // does not take ownership of the request object
- // request can be freed as soon as the transaction is constructed
-
- LLXMLRPCTransaction(const std::string& uri,
- const std::string& method, LLXMLRPCValue params, bool useGzip = true);
- // *does* take control of the request value, you must not free it
+ LLXMLRPCTransaction
+ (
+ const std::string& uri,
+ const std::string& method,
+ const LLSD& params,
+ const LLSD& http_params = LLSD()
+ );
~LLXMLRPCTransaction();
- typedef enum e_status {
+ typedef enum e_status
+ {
StatusNotStarted,
StatusStarted,
StatusDownloading,
@@ -105,26 +54,25 @@ public:
StatusOtherError
} EStatus;
+ /// Run the request a little, returns true when done
bool process();
- // run the request a little, returns true when done
+ /// Return a status, and extended CURL code, if code isn't null
EStatus status(int* curlCode);
- // return status, and extended CURL code, if code isn't null
LLSD getErrorCertData();
+
+ /// Return a message string, suitable for showing the user
std::string statusMessage();
- // return a message string, suitable for showing the user
+
+ /// Return a URI for the user with more information (can be empty)
std::string statusURI();
- // return a URI for the user with more information
- // can be empty
- XMLRPC_REQUEST response();
- LLXMLRPCValue responseValue();
- // only valid if StatusComplete, otherwise NULL
- // retains ownership of the result object, don't free it
+ /// Only non-empty if StatusComplete, otherwise Undefined
+ const LLSD& response();
+ /// Only valid if StsatusComplete, otherwise 0.0
F64 transferRate();
- // only valid if StsatusComplete, otherwise 0.0
private:
class Handler;
@@ -133,6 +81,4 @@ private:
Impl& impl;
};
-
-
#endif // LLXMLRPCTRANSACTION_H
diff --git a/indra/newview/skins/default/xui/de/floater_about.xml b/indra/newview/skins/default/xui/de/floater_about.xml
index 5f2c7b75b1..55184e819b 100644
--- a/indra/newview/skins/default/xui/de/floater_about.xml
+++ b/indra/newview/skins/default/xui/de/floater_about.xml
@@ -64,7 +64,6 @@ OpenSSL Copyright (C) 1998-2008 The OpenSSL Project.
PCRE Copyright (c) 1997-2012 University of Cambridge.
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga.
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com).
-xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
xxHash Copyright (C) 2012-2020 Yann Collet.
zlib Copyright (C) 1995-2012 Jean-loup Gailly und Mark Adler.
diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml
index 3c03868004..bafcebb6d0 100644
--- a/indra/newview/skins/default/xui/de/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/de/menu_viewer.xml
@@ -104,12 +104,7 @@
-
+
diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml
index ee964be9c1..d7cc6fdbb7 100644
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -259,7 +259,6 @@ OpenSSL Copyright (C) 1998-2008 The OpenSSL Project.
PCRE Copyright (c) 1997-2012 University of Cambridge
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
-xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
xxHash Copyright (C) 2012-2020 Yann Collet.
zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler.
Some icons by Joseph Wain / glyphish.com
diff --git a/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml b/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml
new file mode 100644
index 0000000000..b17d0aa5b6
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml
@@ -0,0 +1,284 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Position (m)
+
+
+
+
+
+
+ Size (m)
+
+
+
+
+
+
+ Rotation (°)
+
+
+
+
+
+
+
+
+
+
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 277101531b..9d994f8295 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -847,42 +847,6 @@
parameter="fs_discord"/>
-
@@ -4157,6 +4121,14 @@
+
+
+
+