Merge branch 'develop' of https://github.com/secondlife/viewer
# 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.sha1master
commit
9a2b83b294
|
|
@ -1,5 +1,6 @@
|
|||
# Replace tabs with spaces
|
||||
1b68f71348ecf3983b76b40d7940da8377f049b7
|
||||
33418a77b716e122da9778869cdbabe97c83ff37
|
||||
# Trim trailing whitespace
|
||||
a0b3021bdcf76859054fda8e30abb3ed47749e83
|
||||
8444cd9562a6a7b755fcb075864e205122354192
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ set(cmake_SOURCE_FILES
|
|||
VisualLeakDetector.cmake
|
||||
LibVLCPlugin.cmake
|
||||
WebRTC.cmake
|
||||
XmlRpcEpi.cmake
|
||||
xxHash.cmake
|
||||
ZLIBNG.cmake
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,5 +6,3 @@ include(EXPAT)
|
|||
include(Tracy)
|
||||
include(xxHash)
|
||||
include(ZLIBNG)
|
||||
|
||||
include(XmlRpcEpi)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 ;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1280,6 +1280,75 @@ namespace LLStringFn
|
|||
return output;
|
||||
}
|
||||
|
||||
using literals_t = std::map<char, std::string>;
|
||||
static const literals_t xml_elem_literals =
|
||||
{
|
||||
{ '<', "<" },
|
||||
{ '>', ">" },
|
||||
{ '&', "&" }
|
||||
};
|
||||
static const literals_t xml_attr_literals =
|
||||
{
|
||||
{ '"', """ },
|
||||
{ '\'', "'" }
|
||||
};
|
||||
|
||||
static void literals_encode(std::string& text, const literals_t& literals)
|
||||
{
|
||||
for (const std::pair<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: [ < > & ] => [ < > & ]
|
||||
*/
|
||||
std::string xml_encode(const std::string& input, bool for_attribute)
|
||||
{
|
||||
std::string result(input);
|
||||
literals_encode(result, xml_elem_literals);
|
||||
if (for_attribute)
|
||||
{
|
||||
literals_encode(result, xml_attr_literals);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replace some of XML literals that are defined in XML 1.0
|
||||
* with corresponding characters: [ < > & ] => [ < > & ]
|
||||
*/
|
||||
std::string xml_decode(const std::string& input, bool for_attribute)
|
||||
{
|
||||
std::string result(input);
|
||||
literals_decode(result, xml_elem_literals);
|
||||
if (for_attribute)
|
||||
{
|
||||
literals_decode(result, xml_attr_literals);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replace all control characters (c < 0x20) with replacement in
|
||||
* string.
|
||||
|
|
|
|||
|
|
@ -902,6 +902,20 @@ namespace LLStringFn
|
|||
LL_COMMON_API std::string strip_invalid_xml(const std::string& input);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Replace all characters that are not allowed in XML 1.0
|
||||
* with corresponding literals: [ < > & ] => [ < > & ]
|
||||
*/
|
||||
LL_COMMON_API std::string xml_encode(const std::string& input, bool for_attribute = false);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Replace some of XML literals that are defined in XML 1.0
|
||||
* with corresponding characters: [ < > & ] => [ < > & ]
|
||||
*/
|
||||
LL_COMMON_API std::string xml_decode(const std::string& input, bool for_attribute = false);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Replace all control characters (0 <= c < 0x20) with replacement in
|
||||
* string. This is safe for utf-8
|
||||
|
|
|
|||
|
|
@ -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})
|
||||
|
|
|
|||
|
|
@ -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 << "<";
|
||||
break;
|
||||
case '>':
|
||||
out << ">";
|
||||
break;
|
||||
case '&':
|
||||
out << "&";
|
||||
break;
|
||||
case '\'':
|
||||
out << "'";
|
||||
break;
|
||||
case '"':
|
||||
out << """;
|
||||
break;
|
||||
default:
|
||||
out << (*it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
|
||||
void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd)
|
||||
{
|
||||
ostr << "<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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ¬ification, const LLSD &response)
|
||||
{
|
||||
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
||||
switch (option)
|
||||
{
|
||||
case 0: // "Okay"
|
||||
gSavedSettings.setBOOL("VoiceMorphingEnabled", FALSE);
|
||||
break;
|
||||
|
||||
case 1: // "Cancel"
|
||||
break;
|
||||
|
||||
default:
|
||||
llassert(0);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// <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;
|
||||
}
|
||||
|
||||
///////////////////
|
||||
|
|
|
|||
|
|
@ -539,6 +539,8 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
static bool onVoiceEffectsNotSupported(const LLSD ¬ification, const LLSD &response);
|
||||
|
||||
LLVoiceModuleInterface* mSpatialVoiceModule;
|
||||
LLVoiceModuleInterface* mNonSpatialVoiceModule;
|
||||
LLSD mSpatialCredentials; // used to store spatial credentials for vivox
|
||||
|
|
@ -550,6 +552,7 @@ protected:
|
|||
|
||||
LLCachedControl<bool> mVoiceEffectEnabled;
|
||||
LLCachedControl<std::string> mVoiceEffectDefault;
|
||||
bool mVoiceEffectSupportNotified;
|
||||
|
||||
bool mPTTDirty;
|
||||
bool mPTT;
|
||||
|
|
|
|||
|
|
@ -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"]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ®ionID, const s
|
|||
mShutDown(false),
|
||||
mIceCompleted(false),
|
||||
mSpeakerVolume(0.0),
|
||||
mMicGain(0.0),
|
||||
mOutstandingRequests(0),
|
||||
mChannelID(channelID),
|
||||
mRegionID(regionID),
|
||||
|
|
@ -2369,15 +2351,6 @@ void LLVoiceWebRTCConnection::setMuteMic(bool muted)
|
|||
}
|
||||
}
|
||||
|
||||
void LLVoiceWebRTCConnection::setMicGain(F32 gain)
|
||||
{
|
||||
mMicGain = gain;
|
||||
if (mWebRTCAudioInterface)
|
||||
{
|
||||
mWebRTCAudioInterface->setSendVolume(gain);
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceWebRTCConnection::setSpeakerVolume(F32 volume)
|
||||
{
|
||||
mSpeakerVolume = volume;
|
||||
|
|
@ -2679,7 +2652,6 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
|
|||
// this connection.
|
||||
mWebRTCAudioInterface->setMute(mMuted);
|
||||
mWebRTCAudioInterface->setReceiveVolume(mSpeakerVolume);
|
||||
mWebRTCAudioInterface->setSendVolume(mMicGain);
|
||||
LLWebRTCVoiceClient::getInstance()->OnConnectionEstablished(mChannelID, mRegionID);
|
||||
setVoiceConnectionState(VOICE_STATE_WAIT_FOR_DATA_CHANNEL);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue