# Conflicts:
#	indra/llcommon/llmemory.cpp
#	indra/llmessage/CMakeLists.txt
#	indra/llmessage/llfiltersd2xmlrpc.cpp
#	indra/newview/lldebugview.cpp
#	indra/newview/lldrawpoolbump.cpp
#	indra/newview/llheroprobemanager.cpp
#	indra/newview/llnetmap.cpp
#	indra/newview/llslurl.cpp
#	indra/newview/llsurface.cpp
#	indra/newview/lltextureview.cpp
#	indra/newview/llversioninfo.cpp
#	indra/newview/llviewertexture.cpp
#	indra/newview/llviewertexturelist.h
#	indra/newview/llviewerwindow.cpp
#	indra/newview/llvlcomposition.cpp
#	indra/newview/llvoiceclient.cpp
#	indra/newview/llworld.cpp
#	indra/newview/llxmlrpctransaction.cpp
#	indra/newview/skins/default/xui/da/floater_about.xml
#	indra/newview/skins/default/xui/de/floater_about.xml
#	indra/newview/skins/default/xui/de/menu_viewer.xml
#	indra/newview/skins/default/xui/en/floater_about.xml
#	indra/newview/skins/default/xui/es/floater_about.xml
#	indra/newview/skins/default/xui/es/menu_viewer.xml
#	indra/newview/skins/default/xui/fr/floater_about.xml
#	indra/newview/skins/default/xui/it/floater_about.xml
#	indra/newview/skins/default/xui/it/menu_viewer.xml
#	indra/newview/skins/default/xui/ja/menu_viewer.xml
#	indra/newview/skins/default/xui/pl/menu_viewer.xml
#	indra/newview/skins/default/xui/pt/floater_about.xml
#	indra/newview/skins/default/xui/pt/menu_viewer.xml
#	indra/newview/skins/default/xui/ru/floater_about.xml
#	indra/newview/skins/default/xui/ru/menu_viewer.xml
#	indra/newview/skins/default/xui/tr/floater_about.xml
#	indra/newview/skins/default/xui/tr/menu_viewer.xml
#	indra/newview/skins/default/xui/zh/floater_about.xml
#	indra/newview/skins/default/xui/zh/menu_viewer.xml
#	scripts/messages/message_template.msg.sha1
master
Ansariel 2024-07-02 18:08:57 +02:00
commit 9a2b83b294
120 changed files with 2948 additions and 4102 deletions

View File

@ -1,5 +1,6 @@
# Replace tabs with spaces
1b68f71348ecf3983b76b40d7940da8377f049b7
33418a77b716e122da9778869cdbabe97c83ff37
# Trim trailing whitespace
a0b3021bdcf76859054fda8e30abb3ed47749e83
8444cd9562a6a7b755fcb075864e205122354192

View File

@ -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
)
})

View File

@ -3063,66 +3063,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>name</key>
<string>vlc-bin</string>
</map>
<key>xmlrpc-epi</key>
<map>
<key>platforms</key>
<map>
<key>darwin64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>aa12611374876196b3ebb6bda8d419a697217b8b</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-darwin64-8a05acf.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
</map>
<key>linux64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>ad0c8b41ee4b4de216382bec46ee1c25962a3f12</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-linux64-8a05acf.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
</map>
<key>windows64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>e53fd38c14b8c47c7c84dead8a1b211bb8be170c</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-windows64-8a05acf.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
</map>
</map>
<key>license</key>
<string>xmlrpc-epi</string>
<key>license_file</key>
<string>LICENSES/xmlrpc-epi.txt</string>
<key>copyright</key>
<string>Copyright: (C) 2000 Epinions, Inc.</string>
<key>version</key>
<string>0.54.1.8a05acf</string>
<key>name</key>
<string>xmlrpc-epi</string>
<key>description</key>
<string>XMLRPC Library</string>
</map>
<key>vulkan_gltf</key>
<map>
<key>platforms</key>

View File

@ -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.

View File

@ -66,7 +66,6 @@ set(cmake_SOURCE_FILES
VisualLeakDetector.cmake
LibVLCPlugin.cmake
WebRTC.cmake
XmlRpcEpi.cmake
xxHash.cmake
ZLIBNG.cmake
)

View File

@ -6,5 +6,3 @@ include(EXPAT)
include(Tracy)
include(xxHash)
include(ZLIBNG)
include(XmlRpcEpi)

View File

@ -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)

View File

@ -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<char> 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)
{

View File

@ -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.

View File

@ -86,7 +86,7 @@ void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size)
void LLMemory::updateMemoryInfo()
{
LL_PROFILE_ZONE_SCOPED
U32Kilobytes avail_phys; // <FS:Beq/> 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); // <FS:Beq/> align MemInfo across platforms
sAllocatedPageSizeInKB = U32Kilobytes::convert(U64Bytes(counters.PagefileUsage));
sample(sVirtualMem, sAllocatedPageSizeInKB);
// <FS:Beq> 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) ;
// </FS:Beq>
#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.
// <FS:Beq> 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();
// </FS:Beq>
}
else
{
LL_WARNS() << "task_info failed" << LL_ENDL;
}
// <FS:Beq> 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)
// </FS:Beq>
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
// <FS:Beq> 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);
}
// </FS:Beq>
return ;
}

View File

@ -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 "<nil/>"; }
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 ? "<boolean>1</boolean>" : "<boolean>0</boolean>"; }
};
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 "<int>" + std::to_string(mValue) + "</int>"; }
};
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 "<double>" + std::to_string(mValue) + "</double>"; }
};
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 "<string>" + LLStringFn::xml_encode(mValue) + "</string>"; }
};
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 "<string>" + mValue.asString() + "</string>"; }
};
@ -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 "<dateTime.iso8601>" + mValue.toHTTPDateString("%FT%T") + "</dateTime.iso8601>"; }
};
@ -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 "<string>" + LLStringFn::xml_encode(mValue.asString()) + "</string>"; }
};
@ -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 "<base64>" + LLBase64::encode(mValue.data(), mValue.size()) + "</base64>"; }
};
class ImplMap : public LLSD::Impl
{
private:
typedef std::map<LLSD::String, LLSD> DataMap;
typedef std::map<LLSD::String, LLSD> 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 << "<struct>";
for (const auto& it : mData)
{
os << "<member><name>" << LLStringFn::xml_encode(it.first) << "</name>"
<< it.second.asXMLRPCValue() << "</member>";
}
os << "</struct>";
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<LLSD> DataVector;
typedef std::vector<LLSD> 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 << "<array><data>";
for (const auto& it : mData)
{
os << it.asXMLRPCValue();
}
os << "</data></array>";
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 "<value>" + safe(impl).asXMLRPCValue() + "</value>"; }
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 (<data> expected)") ||
!check(data->hasName("data"), "Invalid array inner XML element (<data> expected)") ||
!check(!data->getNextSibling(), "Multiple array inner XML elements (single <data> 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 (<member> 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 (<value> 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)

View File

@ -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 "<value><((type))>((scalar value or recursive calls))</((type))></value>"
// 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

View File

@ -1280,6 +1280,75 @@ namespace LLStringFn
return output;
}
using literals_t = std::map<char, std::string>;
static const literals_t xml_elem_literals =
{
{ '<', "&lt;" },
{ '>', "&gt;" },
{ '&', "&amp;" }
};
static const literals_t xml_attr_literals =
{
{ '"', "&quot;" },
{ '\'', "&apos;" }
};
static void literals_encode(std::string& text, const literals_t& literals)
{
for (const std::pair<char, std::string> 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<char, std::string> 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: [ < > & ] => [ &lt; &gt; &amp; ]
*/
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: [ &lt; &gt; &amp; ] => [ < > & ]
*/
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.

View File

@ -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: [ < > & ] => [ &lt; &gt; &amp; ]
*/
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: [ &lt; &gt; &amp; ] => [ < > & ]
*/
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

View File

@ -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 #<FS:Ansariel> For accessing settings
)
target_include_directories( llmessage INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

View File

@ -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:
* <code>
* <?xml version="1.0"?>
* <methodCall><methodName>examples.getStateName</methodName>
* <params><param><value><i4>41</i4></value></param></params>
* </methodCall>
* </code>
*
* xml rpc response:
* <code>
* <?xml version="1.0"?>
* <methodResponse>
* <params><param><value><string>South Dakota</string></value></param></params>
* </methodResponse>
* </code>
*
* xml rpc fault:
* </code>
* <?xml version="1.0"?>
* <methodResponse>
* <fault><value><struct>
* <member><name>faultCode</name><value><int>4</int></value></member>
* <member><name>faultString</name><value><string>...</string></value></member>
* </struct></value></fault>
* </methodResponse>
* </code>
*
* llsd rpc request:
* <code>
* { 'method':'...', 'parameter':...]}
* </code>
*
* llsd rpc response:
* <code>
* { 'response':... }
* </code>
*
* llsd rpc fault:
* <code>
* { 'fault': {'code':i..., 'description':'...'} }
* </code>
*
*/
#include "linden_common.h"
#include "llfiltersd2xmlrpc.h"
#include <sstream>
#include <iterator>
#ifdef LL_USESYSTEMLIBS
#include <xmlrpc.h>
#else
#include <xmlrpc-epi/xmlrpc.h>
#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[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
static const char XMLRPC_REQUEST_HEADER_1[] = "<methodCall><methodName>";
static const char XMLRPC_REQUEST_HEADER_2[] = "</methodName><params>";
static const char XMLRPC_REQUEST_FOOTER[] = "</params></methodCall>";
static const char XMLRPC_METHOD_RESPONSE_HEADER[] = "<methodResponse>";
static const char XMLRPC_METHOD_RESPONSE_FOOTER[] = "</methodResponse>";
static const char XMLRPC_RESPONSE_HEADER[] = "<params><param>";
static const char XMLRPC_RESPONSE_FOOTER[] = "</param></params>";
static const char XMLRPC_FAULT_1[] = "<fault><value><struct><member><name>faultCode</name><value><int>";
static const char XMLRPC_FAULT_2[] = "</int></value></member><member><name>faultString</name><value><string>";
static const char XMLRPC_FAULT_3[] = "</string></value></member></struct></value></fault>";
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)
{
// <FS:ND> 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;
}
// </FS:ND>
switch((*it))
{
case '<':
out << "&lt;";
break;
case '>':
out << "&gt;";
break;
case '&':
out << "&amp;";
break;
case '\'':
out << "&apos;";
break;
case '"':
out << "&quot;";
break;
default:
out << (*it);
break;
}
}
return out.str();
}
void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd)
{
ostr << "<value>";
switch(sd.type())
{
case LLSD::TypeMap:
{
#if LL_SPEW_STREAM_OUT_DEBUGGING
LL_INFOS() << "streamOut(map) BEGIN" << LL_ENDL;
#endif
ostr << "<struct>";
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 << "<member><name>" << xml_escape_string((*it).first)
<< "</name>";
streamOut(ostr, (*it).second);
if(ostr.fail())
{
LL_INFOS() << "STREAM FAILURE writing '" << (*it).first
<< "' with sd type " << (*it).second.type() << LL_ENDL;
}
ostr << "</member>";
}
ostr << "</struct>";
#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 << "<array><data>";
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 << "</data></array>";
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 << "<boolean>" << (sd.asBoolean() ? "1" : "0") << "</boolean>";
break;
case LLSD::TypeInteger:
#if LL_SPEW_STREAM_OUT_DEBUGGING
LL_INFOS() << "streamOut(int)" << LL_ENDL;
#endif
ostr << "<i4>" << sd.asInteger() << "</i4>";
break;
case LLSD::TypeReal:
#if LL_SPEW_STREAM_OUT_DEBUGGING
LL_INFOS() << "streamOut(real)" << LL_ENDL;
#endif
ostr << "<double>" << sd.asReal() << "</double>";
break;
case LLSD::TypeString:
#if LL_SPEW_STREAM_OUT_DEBUGGING
LL_INFOS() << "streamOut(string)" << LL_ENDL;
#endif
ostr << "<string>" << xml_escape_string(sd.asString()) << "</string>";
break;
case LLSD::TypeUUID:
#if LL_SPEW_STREAM_OUT_DEBUGGING
LL_INFOS() << "streamOut(uuid)" << LL_ENDL;
#endif
// serialize it as a string
ostr << "<string>" << sd.asString() << "</string>";
break;
case LLSD::TypeURI:
{
#if LL_SPEW_STREAM_OUT_DEBUGGING
LL_INFOS() << "streamOut(uri)" << LL_ENDL;
#endif
// serialize it as a string
ostr << "<string>" << xml_escape_string(sd.asString()) << "</string>";
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 << "<base64>";
LLSD::Binary buffer = sd.asBinary();
if(!buffer.empty())
{
// *TODO: convert to LLBase64
int b64_buffer_length = apr_base64_encode_len(static_cast<int>(buffer.size()));
char* b64_buffer = new char[b64_buffer_length];
b64_buffer_length = apr_base64_encode_binary(
b64_buffer,
&buffer[0],
static_cast<int>(buffer.size()));
ostr.write(b64_buffer, b64_buffer_length - 1);
delete[] b64_buffer;
}
ostr << "</base64>";
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 << "<dateTime.iso8601>" << sd.asString() << "</dateTime.iso8601>";
break;
default:
// unhandled type
LL_WARNS() << "Unhandled structured data type: " << sd.type()
<< LL_ENDL;
break;
}
ostr << "</value>";
}
/**
* 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 << "<param>";
streamOut(ostream, param_sd);
ostream << "</param>";
break;
case LLSD::TypeArray:
{
LLSD::array_iterator it = param_sd.beginArray();
LLSD::array_iterator end = param_sd.endArray();
for(; it != end; ++it)
{
ostream << "<param>";
streamOut(ostream, *it);
ostream << "</param>";
}
break;
}
default:
ostream << "<param>";
streamOut(ostream, param_sd);
ostream << "</param>";
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)
<< "'" <<LLSDRPC_FAULT_FOOTER;
}
else
{
PUMP_DEBUG;
stream << LLSDRPC_RESPONSE_HEADER;
XMLRPC_VALUE param = XMLRPC_RequestGetData(response);
if(param)
{
stream_out(stream, param);
}
stream << LLSDRPC_RESPONSE_FOOTER;
}
PUMP_DEBUG;
XMLRPC_RequestFree(response, 1);
delete[] buf;
PUMP_DEBUG;
return STATUS_DONE;
}
/**
* LLFilterXMLRPCRequest2LLSD
*/
LLFilterXMLRPCRequest2LLSD::LLFilterXMLRPCRequest2LLSD()
{
}
LLFilterXMLRPCRequest2LLSD::~LLFilterXMLRPCRequest2LLSD()
{
}
LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::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 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<bytes; i++)
{
cur_char = *cur_pBuf;
if ( cur_char < 0x20
&& 0x09 != cur_char
&& 0x0a != cur_char
&& 0x0d != cur_char )
{
*cur_pBuf = '?';
}
++cur_pBuf;
}
PUMP_DEBUG;
XMLRPC_REQUEST request = XMLRPC_REQUEST_FromXML(
buf,
bytes,
NULL);
if(!request)
{
LL_WARNS() << "XML -> 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;
}

View File

@ -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 <iosfwd>
#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:
* <code>{'response':[ i200, r3.4, {"foo":"bar"} ]}</code>
* Would generate:
* <code>
* <?xml version="1.0"?>
* <methodResponse><params><param><array><data>
* <value><int>200</int></value>
* <value><double>3.4</double></value>
* <value><struct><member>
* <name>foo</name><value><string>bar</string></value></member>
* </struct></value>
* </data></array></param></params></methodResponse>
* </code>
*/
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:
* <code>
* {'method'='foo', 'parameter':[i200, r3.4, {"foo":"bar"}]}
* </code>
* To generate:
* <code>
* <?xml version="1.0"?>
* <methodCall><params>
* <param><value><int>200</int></value></param>
* <param><value><double>3.4</double></value></param>
* <param><value><struct><member>
* <name>foo</name><value><string>bar</string></value></member>
* </struct></value></param>
* </params></methodCall>
*
* 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:
* <code>
* <?xml version=\"1.0\"?><methodResponse><params><param>
* <value><string>ok</string></value></param></params></methodResponse>
* </code>
* And processes it into:
* <code>'ok'</code>
*
*/
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:
* <code>
* <?xml version=\"1.0\"?><methodCall>
* <methodName>repeat</methodName>
* <params>
* <param><value><i4>4</i4></value></param>
* <param><value><string>ok</string></value></param>
* </params></methodCall>
* </code>
* And processes it into:
* <code>{ 'method':'repeat', 'params':[i4, 'ok'] }</code>
*/
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

View File

@ -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())

View File

@ -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; }
//---------------------------------------------------------------------------------------------

View File

@ -41,6 +41,7 @@
#include "llrender.h"
#include "llwindow.h"
#include "llframetimer.h"
#include <unordered_set>
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*> LLImageGL::sImageList;
std::unordered_set<LLImageGL*> 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<LLImageGL*>::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<LLImageGL*>::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<LLImageGL*>::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<LLImageGL*>::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()

View File

@ -39,6 +39,7 @@
#include "llrender.h"
#include "threadpool.h"
#include "workqueue.h"
#include <unordered_set>
#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<LLImageGL*> sImageList;
static std::unordered_set<LLImageGL*> 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.

View File

@ -390,12 +390,10 @@ void LLAccordionCtrl::initNoTabsWidget(const LLTextBox::Params& tb_params)
void LLAccordionCtrl::updateNoTabsHelpTextVisibility()
{
bool visible_exists = false;
std::vector<LLAccordionCtrlTab*>::const_iterator it = mAccordionTabs.begin();
const std::vector<LLAccordionCtrlTab*>::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;

View File

@ -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()

View File

@ -1274,17 +1274,15 @@ void LLFlatListView::detachItems(std::vector<LLPanel*>& 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<LLPanel*>& 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<LLPanel*>& detached_items)
}
else
{
std::vector<LLPanel*>::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);
}

View File

@ -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);
}
}
});

View File

@ -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

View File

@ -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
//

View File

@ -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<U32>(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."

View File

@ -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);

View File

@ -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

View File

@ -11129,6 +11129,28 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>0</integer>
</map>
<key>RenderMinFreeMainMemoryThreshold</key>
<map>
<key>Comment</key>
<string>Minimum of available physical memory in MB before textures get scaled down</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>512</integer>
</map>
<key>RenderLowMemMinDiscardIncrement</key>
<map>
<key>Comment</key>
<string>Minimum increment of discard level if system memory gets low</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>0.1</real>
</map>
<key>RenderMaxTextureIndex</key>
<map>
<key>Comment</key>
@ -17355,7 +17377,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
<integer>0</integer>
</map>
<key>AutoDisengageMic</key>
<map>
@ -25741,16 +25763,5 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>1</integer>
</map>
<key>FSMinFreeMainMemoryTextureDiscardThreshold</key>
<map>
<key>Comment</key>
<string>Minimum of available physical memory in MB before textures get scaled down</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>512</integer>
</map>
</map>
</llsd>

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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)

View File

@ -180,6 +180,16 @@ namespace LL
data[3] = src[3];
}
template<>
inline void copyVec4<U8, U64>(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, LLColor4U>(U16* src, LLColor4U& dst)
{

View File

@ -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);

View File

@ -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)
{
// <COLOSI opensim multi-currency support>
//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()

View File

@ -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));
// <FS:Ansariel> 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);
// </FS:Ansariel>
LLTextureView::Params tvp;
tvp.name("gTextureView");
@ -119,7 +116,6 @@ void LLDebugView::init()
tvp.visible(false);
gTextureView = LLUICtrlFactory::create<LLTextureView>(tvp);
addChild(gTextureView);
//gTextureView->reshape(r.getWidth(), r.getHeight(), true);
}
void LLDebugView::draw()

View File

@ -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<LLImageRaw> 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<<FIXED_PT));
const S32 G_WEIGHT = S32(0.5875f * (1<<FIXED_PT));
const S32 B_WEIGHT = S32(0.1145f * (1<<FIXED_PT));
S32 minimum = 255;
S32 maximum = 0;
switch( src_components )
{
case 1:
case 2:
{
if( src_data_size == dst_data_size * src_components )
{
for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components )
{
dst_data[i] = src_data[j];
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;
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<LLViewerTexture> 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<LLViewerTexture> 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)

View File

@ -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<LLUUID, LLPointer<LLViewerTexture> > bump_image_map_t;

View File

@ -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"

View File

@ -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<LLTextBox>("region_name_text");
if (region_name)
std::string region_name_txt = region->getName() + " ("+rating +")";
region_name->setText(region_name_txt);
LLIconCtrl* rating_icon = getChild<LLIconCtrl>("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<LLIconCtrl>("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<LLTextBox>("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<LLTextBox>("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<LLTextBox>("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<LLCheckBoxCtrl>("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<LLTextBox>("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<LLTextBox>("covenant_timestamp_text");
if (editor) editor->setText(text);
editor->setText(text);
}
void LLFloaterBuyLandUI::updateFloaterEstateOwnerName(const std::string& name)
{
LLTextBox* box = getChild<LLTextBox>("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()

View File

@ -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
{

View File

@ -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"

View File

@ -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"

View File

@ -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<LLMenuButton>("clipboard_pos_btn");
mCtrlPosX = getChild<LLSpinCtrl>("Pos X", true);
mCtrlPosX->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
mCtrlPosY = getChild<LLSpinCtrl>("Pos Y", true);
mCtrlPosY->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
mCtrlPosZ = getChild<LLSpinCtrl>("Pos Z", true);
mCtrlPosZ->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
// Scale
mMenuClipboardScale = getChild<LLMenuButton>("clipboard_size_btn");
mCtrlScaleX = getChild<LLSpinCtrl>("Scale X", true);
mCtrlScaleX->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
mCtrlScaleY = getChild<LLSpinCtrl>("Scale Y", true);
mCtrlScaleY->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
mCtrlScaleZ = getChild<LLSpinCtrl>("Scale Z", true);
mCtrlScaleZ->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
// Rotation
mMenuClipboardRot = getChild<LLMenuButton>("clipboard_rot_btn");
mCtrlRotX = getChild<LLSpinCtrl>("Rot X", true);
mCtrlRotX->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
mCtrlRotY = getChild<LLSpinCtrl>("Rot Y", true);
mCtrlRotY->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
mCtrlRotZ = getChild<LLSpinCtrl>("Rot Z", true);
mCtrlPosZ->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
setTransformsEnabled(false);
// todo: do multiple panels based on selected element.
mTransformsPanel = getChild<LLPanel>("transform_panel", true);
mTransformsPanel->setVisible(false);
mItemListPanel = getChild<LLPanel>("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<LLFolderViewScrollContainer>());
scroller_params.rect(scroller_view_rect);
scroller_params.name("folder_scroller");
mScroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(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<LLFolderView>());
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<LLFolderView>(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<LLFolderViewItem*>& 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<LLFolderViewItem>(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<LLFolderViewFolder>(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<LLFolderViewFolder>(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<LLFolderViewItem*>& items, bool user_action)
{
if (items.empty())
{
setTransformsEnabled(false);
return;
}
LLFolderViewItem* item = items.front();
LLGLTFFolderItem* vmi = static_cast<LLGLTFFolderItem*>(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<LLGLTFFolderItem*>(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<LLGLTFFolderItem*>(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;
}

View File

@ -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<LLFolderViewItem*>& 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<LL::GLTF::Asset> 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

View File

@ -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<LLGLTFFolderItem*>(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<LLGLTFFolderItem*>(view_model->mParent);
}
}
setPassedFilter(passed_filter, filter_generation, filter.getStringMatchOffset(this), filter.getFilterStringSize());
continue_filtering = !filter.isTimedOut();
}
return continue_filtering;
}

View File

@ -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(); }; // <FS:Ansariel> Zi's extended inventory search
LLPointer<LLUIImage> getIcon() const override { return pIcon; }
LLPointer<LLUIImage> getIconOpen() const override { return getIcon(); }
LLPointer<LLUIImage> 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<LLFolderViewModelItem*>& 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

View File

@ -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<LLGLTFNode>(params);
class LLGLTFNode : public LLFolderViewItem
{
public:
struct Params : public LLInitParam::Block<Params, LLFolderViewItem::Params>
{
Params();
};
~LLGLTFNode();
protected:
LLGLTFNode(const Params& p);
};
LLGLTFNode::LLGLTFNode(const LLGLTFNode::Params& p)
: LLFolderViewItem(p)
{
}
LLGLTFNode::~LLGLTFNode()
{
}

View File

@ -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<LLGLTFSort, LLGLTFFolderItem, LLGLTFFolderItem, LLGLTFFilter>
{
public:
typedef LLFolderViewModel< LLGLTFSort, LLGLTFFolderItem, LLGLTFFolderItem, LLGLTFFilter> base_t;
LLGLTFViewModel();
void sort(LLFolderViewFolder* folder);
bool startDrag(std::vector<LLFolderViewModelItem*>& items) { return false; }
private:
};
#endif

View File

@ -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; // <FS:Beq/> 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; // <FS:Beq/> FIRE-34201 TP crash
mDefaultProbe->mViewerObject = nullptr;
}
mHeroProbeStrength = 1;
}
// <FS:Beq> LL-1719/1721 Mirrors do not disable properly (interim fix)
else
{
mNearestHero = nullptr;
mDefaultProbe->mViewerObject = nullptr; // <FS:Beq/> FIRE-34201 TP crash
mDefaultProbe->mViewerObject = nullptr;
}
// </FS:Beq>
}
void LLHeroProbeManager::renderProbes()

View File

@ -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);
}

View File

@ -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);

View File

@ -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:

View File

@ -89,6 +89,7 @@
#include "fsradar.h"
#include "lggcontactsets.h"
#include "fscommon.h"
#include "llstartup.h"
static LLDefaultChildRegistry::Register<LLNetMap> r1("net_map");
@ -547,45 +548,6 @@ void LLNetMap::draw()
}
gGL.end();
// </FS:Ansariel>
// Draw water
gGL.flush();
{
if (regionp->getLand().getWaterTexture())
{
gGL.getTexUnit(0)->bind(regionp->getLand().getWaterTexture());
// <FS:Ansariel> 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();
// </FS:Ansariel>
}
}
gGL.flush();
// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-07-26 (Catznip-3.3)
}
gGL.flush();

View File

@ -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<LLSpinCtrl>("Probe Ambiance", true)->clear();
getChild<LLSpinCtrl>("Probe Near Clip", true)->clear();
getChild<LLComboBox>("Probe Update Type", true)->clear();
getChild<LLUICtrl>("Probe Dynamic")->setValue(false);
}
else
{
@ -450,6 +452,7 @@ void LLPanelVolume::getState( )
getChild<LLSpinCtrl>("Probe Ambiance", true)->setValue(volobjp->getReflectionProbeAmbiance());
getChild<LLSpinCtrl>("Probe Near Clip", true)->setValue(volobjp->getReflectionProbeNearClip());
getChild<LLComboBox>("Probe Update Type", true)->setValue(update_type);
getChild<LLUICtrl>("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<LLUICtrl>("Probe Ambiance")->getValue().asReal());
volobjp->setReflectionProbeNearClip((F32)self->getChild<LLUICtrl>("Probe Near Clip")->getValue().asReal());
std::string update_type = self->getChild<LLUICtrl>("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<LLUICtrl>("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<LLUICtrl>("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);

View File

@ -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)

View File

@ -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<LLImageRaw> 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<LLImageRaw> 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
//
// <FS:CR> Aurora Sim
//if (gSavedSettings.getBOOL("RenderWater") )
if (gSavedSettings.getBOOL("RenderWater") && LLWorld::getInstance()->getAllowRenderWater())
// </FS:CR> 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<LLImageRaw> raw = new LLImageRaw(tex_width, tex_height, tex_comps);
U8 *rawp = raw->getData();
// <FS:CR> Aurora Sim
//F32 scale = 256.f * getMetersPerGrid() / (F32)tex_width;
F32 scale = getRegion()->getWidth() * getMetersPerGrid() / (F32)tex_width;
// <FS:CR> 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;
}

View File

@ -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<LLViewerTexture> mSTexturep; // Texture for surface
LLPointer<LLViewerTexture> mWaterTexturep; // Water texture
LLPointer<LLVOWater> mWaterObjp;

View File

@ -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()

View File

@ -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
// <FS:Ansariel> 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,
// </FS:Ansariel>
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);
// </FS:Beq>
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);
// </FS:Ansariel>
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<LLViewerFetchedTexture> imagep = *iter++;

View File

@ -63,6 +63,12 @@ LLVersionInfo::LLVersionInfo():
// immediately listen on mPump, store arriving URL into mReleaseNotes
mStore{new LLStoreListener<std::string>(*mPump, mReleaseNotes)}
{
// <FS:Ansariel> 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);
}
// </FS:Ansariel>
}
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;
}
//<FS:CZ>
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;
}
//</FS:CZ>
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()
}
//<FS:TS> 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()
}
//</FS:TS>
std::string LLVersionInfo::getChannel()
std::string LLVersionInfo::getChannel() const
{
// <FS:Ansariel> 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);
}
// </FS:Ansariel>
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;
}

View File

@ -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;
//<FS:CZ>
/// return the full viewer version as a string like "200030"
std::string getBuildVersion();
std::string getBuildVersion() const;
//</FS:CZ>
/// 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:
//<FS:TS> 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

View File

@ -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<LLFloaterForgetUser>);
LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGesture>);
LLFloaterReg::add("gltf_asset_editor", "floater_gltf_asset_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGLTFAssetEditor>);
LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGodTools>);
LLFloaterReg::add("grid_status", "floater_grid_status.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGridStatus>);
LLFloaterReg::add("group_picker", "floater_choose_group.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGroupPicker>);

View File

@ -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<LLMediaCtrl>("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<LLMediaCtrl>("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.

View File

@ -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:Ansariel> [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");

View File

@ -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()

View File

@ -1356,8 +1356,12 @@ U32 LLViewerRegion::getNumOfVisibleGroups() const
return mImpl ? static_cast<U32>(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);

View File

@ -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);

View File

@ -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()
// <FS:Ansariel> Restrict texture memory by available physical system memory
static bool isSystemMemoryForTextureLow()
{
static LLFrameTimer timer;
static S32Megabytes physical_res = S32Megabytes(S32_MAX);
static LLCachedControl<S32> 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;
}
// </FS:Ansariel>
//static
void LLViewerTexture::updateClass()
{
@ -562,20 +533,14 @@ void LLViewerTexture::updateClass()
sFreeVRAMMegabytes = target - used;
F32 over_pct = llmax((used-target) / target, 0.f);
// <FS:Ansariel> 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<F32> 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;
}
}
// </FS:Ansariel>
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<U32> 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
//----------------------------------------------------------------------------------------------

View File

@ -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:
// </FS:Techwolf Lupindo>
protected:
/*virtual*/ void switchToCachedImage() override;
S32 getCurrentDiscardLevelForFetching() ;
public: // <FS:Ansariel> 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<LLImageRaw> 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

View File

@ -303,7 +303,7 @@ void LLViewerTextureList::shutdown()
// Write out list of currently loaded textures for precaching on startup
typedef std::set<std::pair<S32,LLViewerFetchedTexture*> > 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<LLPointer<LLViewerFetchedTexture> > 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++;

View File

@ -33,7 +33,7 @@
#include "llviewertexture.h"
#include "llui.h"
#include <list>
#include <set>
#include <unordered_set>
#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<LLViewerFetchedTexture*> &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<LLPointer<LLViewerFetchedTexture> > image_list_t;
typedef std::unordered_set<LLPointer<LLViewerFetchedTexture> > 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(); }
// <FS:Ansariel> Fast cache stats
static U32 sNumFastCacheReads;
@ -236,11 +239,10 @@ private:
uuid_map_t mUUIDMap;
LLTextureKey mLastUpdateKey;
typedef std::set < LLPointer<LLViewerFetchedTexture> > 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<LLPointer<LLViewerFetchedTexture> > mImagePreloads;
std::unordered_set<LLPointer<LLViewerFetchedTexture> > mImagePreloads;
bool mInitialized ;
LLFrameTimer mForceDecodeTimer;

View File

@ -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();

View File

@ -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<LLView> 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<LLWindowListener> mWindowListener;
std::unique_ptr<LLViewerWindowListener> mViewerWindowListener;

View File

@ -317,7 +317,7 @@ bool LLTerrainMaterials::makeMaterialsReady(bool boost, bool strict)
// static
bool LLTerrainMaterials::makeTextureReady(LLPointer<LLViewerFetchedTexture>& 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<LLImageRaw>& 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<LLFetchedGLTFMaterial>& 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<LLImageRaw> 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<LLImageRaw> 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<LLImageRaw> newraw = new LLImageRaw(BASE_SIZE, BASE_SIZE, 3);
//<FS:Beq> 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);
}
// </FS:Beq>
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<LLImageRaw> 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];

View File

@ -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

View File

@ -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);
}

View File

@ -145,8 +145,9 @@ LLVoiceClient::LLVoiceClient(LLPumpIO *pump)
mSpatialVoiceModule(NULL),
mNonSpatialVoiceModule(NULL),
m_servicePump(NULL),
mVoiceEffectEnabled(LLCachedControl<bool>(gSavedSettings, "VoiceMorphingEnabled", true)),
mVoiceEffectEnabled(LLCachedControl<bool>(gSavedSettings, "VoiceMorphingEnabled", false)),
mVoiceEffectDefault(LLCachedControl<std::string>(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 &notification, 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;
}
// <FS:Ansariel> 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<bool> enable_voice_chat(gSavedSettings, "EnableVoiceChat");
static LLCachedControl<bool> 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<LLVoiceEffectInterface*>(mSpatialVoiceModule) : NULL;
return NULL;
}
///////////////////

View File

@ -539,6 +539,8 @@ public:
protected:
static bool onVoiceEffectsNotSupported(const LLSD &notification, const LLSD &response);
LLVoiceModuleInterface* mSpatialVoiceModule;
LLVoiceModuleInterface* mNonSpatialVoiceModule;
LLSD mSpatialCredentials; // used to store spatial credentials for vivox
@ -550,6 +552,7 @@ protected:
LLCachedControl<bool> mVoiceEffectEnabled;
LLCachedControl<std::string> mVoiceEffectDefault;
bool mVoiceEffectSupportNotified;
bool mPTTDirty;
bool mPTT;

View File

@ -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"]);
}

View File

@ -24,7 +24,6 @@
* $/LicenseInfo$
*/
#include <algorithm>
#include <format>
#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<std::string, LLWebRTCVoiceClient::sessionState::ptr_t> 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 &regionID, 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;

View File

@ -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;

View File

@ -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);

View File

@ -62,7 +62,6 @@ LLVOWater::LLVOWater(const LLUUID &id,
setScale(LLVector3(mRegionp->getWidth(), mRegionp->getWidth(), 0.f));
// </FS:CR> 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;

View File

@ -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;
};

View File

@ -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);
// <FS:CR> 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);
}

View File

@ -186,6 +186,7 @@ LLPointer<LLViewerFetchedTexture> LLWorldMipmap::getObjectsTile(U32 grid_x, U32
}
}
//static
LLPointer<LLViewerFetchedTexture> LLWorldMipmap::loadObjectsTile(U32 grid_x, U32 grid_y, S32 level)
{
// Get the grid coordinates

View File

@ -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<LLViewerFetchedTexture> 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<LLViewerFetchedTexture> loadObjectsTile(U32 grid_x, U32 grid_y, S32 level);
// Clear a level from its "missing" tiles
void cleanMissedTilesFromLevel(S32 level);

View File

@ -39,12 +39,6 @@
#include <boost/scoped_ptr.hpp>
#include <boost/range.hpp> // boost::begin(), boost::end()
#ifdef LL_USESYSTEMLIBS
#include <xmlrpc.h>
#else
#include <xmlrpc-epi/xmlrpc.h>
#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<std::string> 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<std::string>::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("<bad XMLRPC type " << type << '>');
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;
}

View File

@ -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;
};

View File

@ -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 <xmlrpc.h>
#else
#include <xmlrpc-epi/xmlrpc.h>
#endif
// <xmlrpc-epi/queue.h> 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;
}
//</FS:Beq>
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<int>(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<XMLTreeNode> mFirstChild;
const std::shared_ptr<XMLTreeNode> 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 =
"<?xml version=\"1.0\"?><methodCall><methodName>" + method +
"</methodName><params><param>" + params.asXMLRPCValue() +
"</param></params></methodCall>";
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;
}

View File

@ -29,73 +29,22 @@
#include <string>
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

View File

@ -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.

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