Merge brad/2549-downrez-controls into release/2024.09-ExtraFPS (#2864)

master
Brad Linden 2024-10-29 15:43:21 -07:00
commit 74b0c86e48
329 changed files with 29908 additions and 6672 deletions

View File

@ -2,7 +2,7 @@
# clang-format version 10.0.0+
Language: Cpp
# BasedOnStyle: Microsoft
AccessModifierOffset: -2
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: true
AlignConsecutiveAssignments: true
@ -15,14 +15,14 @@ AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortFunctionsOnASingleLine: InlineOnly
AllowShortLambdasOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BreakBeforeBinaryOperators: None
@ -67,7 +67,7 @@ IndentCaseLabels: true
IndentGotoLabels: true
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
IndentWrappedFunctionNames: true
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
@ -91,9 +91,9 @@ PointerAlignment: Left
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterCStyleCast: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
@ -102,8 +102,8 @@ SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false

View File

@ -5,7 +5,11 @@
a0b3021bdcf76859054fda8e30abb3ed47749e83
8444cd9562a6a7b755fcb075864e205122354192
863c541ce0b2e3e1e566cc88423d3e87aaedb6ca
743a1a6d8eabf069d95777c96e5b657cb8702593
4a00da1ada89af6f313cee30f5177634b0b180a9
# Wrong line endings
1b67dd855c41f5a0cda7ec2a68d98071986ca703
6cc7dd09d5e69cf57e6de7fb568a0ad2693f9c9a
e2e37cced861b98de8c1a7c9c0d3a50d2d90e433
# multiple problems
5370a6d323e14d7b4e32a3f41ef78f7744e361c5

View File

@ -2099,11 +2099,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>c16deaf773cb2a5d001732122ee3ec74db1dceeb</string>
<string>76444e37be0cfccdbb5921370ba150ded2bf3c59</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.0.ea12248/openjpeg-2.5.0.ea12248-darwin64-ea12248.tar.zst</string>
<string>https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.2-r1/openjpeg-2.5.2.10604495243-darwin64-10604495243.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -2113,11 +2113,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>8c277dde6076fb682cb07264dd70f6f2298b633f</string>
<string>6bd289a9c4564b80369ce40ecbb24a213c2732ff</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.0.ea12248/openjpeg-2.5.0.ea12248-linux64-ea12248.tar.zst</string>
<string>https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.2-r1/openjpeg-2.5.2.10604495243-linux64-10604495243.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@ -2127,11 +2127,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>2abf9535adf21ebdf2295f8a680300432abe6280</string>
<string>5e6e0180adc01e07438cb98daec96543b5d85019</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.0.ea12248/openjpeg-2.5.0.ea12248-windows64-ea12248.tar.zst</string>
<string>https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.2-r1/openjpeg-2.5.2.10604495243-windows64-10604495243.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@ -2210,6 +2210,68 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>description</key>
<string>Secure Sockets Layer (SSL v2/v3) and Transport Layer Security (TLS v1) Library</string>
</map>
<key>openxr</key>
<map>
<key>platforms</key>
<map>
<key>windows64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>3cccc3e3f3137066c286270b35abc00ee0c0bb0c</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openxr/releases/download/v1.1.40-r1/openxr-1.1.40-r1-windows64-10710818432.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
</map>
<key>linux64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>f0ad0418a98fb8cb6e158fca3902c15ac1de9d2a</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openxr/releases/download/v1.1.40-r1/openxr-1.1.40-r1-linux64-10710818432.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
</map>
<key>darwin64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>a9bfabec63a987bd34bcfdc295b928bd0696e1d7</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openxr/releases/download/v1.1.40-r1/openxr-1.1.40-r1-darwin64-10710818432.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
</map>
</map>
<key>license</key>
<string>Apache 2.0</string>
<key>license_file</key>
<string>LICENSES/openxr.txt</string>
<key>copyright</key>
<string>Copyright 2017-2024, The Khronos Group Inc.</string>
<key>version</key>
<string>1.1.40-r1</string>
<key>name</key>
<string>openxr</string>
<key>canonical_repo</key>
<string>https://github.com/secondlife/3p-openxr</string>
<key>description</key>
<string>Generated headers and sources for OpenXR loader.</string>
</map>
<key>slvoice</key>
<map>
<key>platforms</key>

View File

@ -517,15 +517,6 @@ then
fi
fi
# Some of the uploads takes a long time to finish in the codeticket backend,
# causing the next codeticket upload attempt to fail.
# Inserting this after each potentially large upload may prevent those errors.
# JJ is making changes to Codeticket that we hope will eliminate this failure, then this can be removed
wait_for_codeticket()
{
sleep $(( 60 * 6 ))
}
# check status and upload results to S3
if $succeeded
then

View File

@ -1210,6 +1210,7 @@ PanteraPolnocy
SL-18937
SL-19207
SL-19681
secondlife/viewer#2483
Parvati Silverweb
Patric Mills
VWR-2645

View File

@ -68,9 +68,12 @@ if (WINDOWS)
/NODEFAULTLIB:LIBCMT
/IGNORE:4099)
add_definitions(
-DNOMINMAX
# /DDOM_DYNAMIC # For shared library colladadom
add_compile_definitions(
WIN32_LEAN_AND_MEAN
NOMINMAX
# DOM_DYNAMIC # For shared library colladadom
_CRT_SECURE_NO_WARNINGS # Allow use of sprintf etc
_WINSOCK_DEPRECATED_NO_WARNINGS # Disable deprecated WinSock API warnings
)
add_compile_options(
/Zo
@ -106,9 +109,6 @@ if (WINDOWS)
string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
endif()
# Allow use of sprintf etc
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
endif (WINDOWS)

View File

@ -26,6 +26,7 @@ set(cmake_SOURCE_FILES
FreeType.cmake
GLEXT.cmake
GLH.cmake
GLM.cmake
Havok.cmake
Hunspell.cmake
LLAddBuildTest.cmake

22
indra/cmake/OpenXR.cmake Normal file
View File

@ -0,0 +1,22 @@
# -*- cmake -*-
include(Prebuilt)
include_guard()
add_library( ll::openxr INTERFACE IMPORTED )
if(USE_CONAN )
target_link_libraries( ll::openxr INTERFACE CONAN_PKG::openxr )
return()
endif()
use_prebuilt_binary(openxr)
if (WINDOWS)
target_link_libraries( ll::openxr INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/openxr_loader.lib )
else()
target_link_libraries( ll::openxr INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libopenxr_loader.a )
endif (WINDOWS)
if( NOT LINUX )
target_include_directories( ll::openxr SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include)
endif()

View File

@ -6,7 +6,7 @@ add_library( ll::tracy INTERFACE IMPORTED )
# default Tracy profiling on for test builds, but off for all others
string(TOLOWER ${VIEWER_CHANNEL} channel_lower)
if(WINDOWS AND channel_lower MATCHES "^second life test")
if(channel_lower MATCHES "^second life test")
option(USE_TRACY "Use Tracy profiler." ON)
else()
option(USE_TRACY "Use Tracy profiler." OFF)
@ -31,6 +31,11 @@ if (USE_TRACY)
target_compile_definitions(ll::tracy INTERFACE -DTRACY_NO_BROADCAST=1 -DTRACY_ONLY_LOCALHOST=1)
endif ()
# GHA runners don't always provide invariant TSC support, but always build with LL_TESTS enabled
if (DARWIN AND LL_TESTS)
target_compile_definitions(ll::tracy INTERFACE -DTRACY_TIMER_FALLBACK=1)
endif ()
# See: indra/llcommon/llprofiler.h
add_compile_definitions(LL_PROFILER_CONFIGURATION=3)
endif (USE_TRACY)

View File

@ -28,8 +28,8 @@
#include "llavatarappearancedefines.h"
#include "indra_constants.h"
const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH = 1024;
const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT = 1024;
const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH = 2048;
const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT = 2048;
using namespace LLAvatarAppearanceDefines;

View File

@ -119,6 +119,7 @@ set(llcommon_HEADER_FILES
commoncontrol.h
ctype_workaround.h
fix_macros.h
fsyspath.h
function_types.h
indra_constants.h
lazyeventapi.h
@ -240,7 +241,6 @@ set(llcommon_HEADER_FILES
lluriparser.h
lluuid.h
llwin32headers.h
llwin32headerslean.h
llworkerthread.h
hbxxh.h
lockstatic.h

79
indra/llcommon/fsyspath.h Normal file
View File

@ -0,0 +1,79 @@
/**
* @file fsyspath.h
* @author Nat Goodspeed
* @date 2024-04-03
* @brief Adapt our UTF-8 std::strings for std::filesystem::path
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Copyright (c) 2024, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_FSYSPATH_H)
#define LL_FSYSPATH_H
#include <filesystem>
// While std::filesystem::path can be directly constructed from std::string on
// both Posix and Windows, that's not what we want on Windows. Per
// https://en.cppreference.com/w/cpp/filesystem/path/path:
// ... the method of conversion to the native character set depends on the
// character type used by source.
//
// * If the source character type is char, the encoding of the source is
// assumed to be the native narrow encoding (so no conversion takes place on
// POSIX systems).
// * If the source character type is char8_t, conversion from UTF-8 to native
// filesystem encoding is used. (since C++20)
// * If the source character type is wchar_t, the input is assumed to be the
// native wide encoding (so no conversion takes places on Windows).
// The trouble is that on Windows, from std::string ("source character type is
// char"), the "native narrow encoding" isn't UTF-8, so file paths containing
// non-ASCII characters get mangled.
//
// Once we're building with C++20, we could pass a UTF-8 std::string through a
// vector<char8_t> to engage std::filesystem::path's own UTF-8 conversion. But
// sigh, as of 2024-04-03 we're not yet there.
//
// Anyway, encapsulating the important UTF-8 conversions in our own subclass
// allows us to migrate forward to C++20 conventions without changing
// referencing code.
class fsyspath: public std::filesystem::path
{
using super = std::filesystem::path;
public:
// default
fsyspath() {}
// construct from UTF-8 encoded std::string
fsyspath(const std::string& path): super(std::filesystem::u8path(path)) {}
// construct from UTF-8 encoded const char*
fsyspath(const char* path): super(std::filesystem::u8path(path)) {}
// construct from existing path
fsyspath(const super& path): super(path) {}
fsyspath& operator=(const super& p) { super::operator=(p); return *this; }
fsyspath& operator=(const std::string& p)
{
super::operator=(std::filesystem::u8path(p));
return *this;
}
fsyspath& operator=(const char* p)
{
super::operator=(std::filesystem::u8path(p));
return *this;
}
// shadow base-class string() method with UTF-8 aware method
std::string string() const { return super::u8string(); }
// On Posix systems, where value_type is already char, this operator
// std::string() method shadows the base class operator string_type()
// method. But on Windows, where value_type is wchar_t, the base class
// doesn't have operator std::string(). Provide it.
operator std::string() const { return string(); }
};
#endif /* ! defined(LL_FSYSPATH_H) */

106
indra/llcommon/hexdump.h Executable file
View File

@ -0,0 +1,106 @@
/**
* @file hexdump.h
* @author Nat Goodspeed
* @date 2023-10-03
* @brief iostream manipulators to stream hex, or string with nonprinting chars
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Copyright (c) 2023, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_HEXDUMP_H)
#define LL_HEXDUMP_H
#include <cctype>
#include <iomanip>
#include <iostream>
#include <string_view>
namespace LL
{
// Format a given byte string as 2-digit hex values, no separators
// Usage: std::cout << hexdump(somestring) << ...
class hexdump
{
public:
hexdump(const std::string_view& data):
hexdump(data.data(), data.length())
{}
hexdump(const char* data, size_t len):
hexdump(reinterpret_cast<const unsigned char*>(data), len)
{}
hexdump(const std::vector<unsigned char>& data):
hexdump(data.data(), data.size())
{}
hexdump(const unsigned char* data, size_t len):
mData(data, data + len)
{}
friend std::ostream& operator<<(std::ostream& out, const hexdump& self)
{
auto oldfmt{ out.flags() };
auto oldfill{ out.fill() };
out.setf(std::ios_base::hex, std::ios_base::basefield);
out.fill('0');
for (auto c : self.mData)
{
out << std::setw(2) << unsigned(c);
}
out.setf(oldfmt, std::ios_base::basefield);
out.fill(oldfill);
return out;
}
private:
std::vector<unsigned char> mData;
};
// Format a given byte string as a mix of printable characters and, for each
// non-printable character, "\xnn"
// Usage: std::cout << hexmix(somestring) << ...
class hexmix
{
public:
hexmix(const std::string_view& data):
mData(data)
{}
hexmix(const char* data, size_t len):
mData(data, len)
{}
friend std::ostream& operator<<(std::ostream& out, const hexmix& self)
{
auto oldfmt{ out.flags() };
auto oldfill{ out.fill() };
out.setf(std::ios_base::hex, std::ios_base::basefield);
out.fill('0');
for (auto c : self.mData)
{
// std::isprint() must be passed an unsigned char!
if (std::isprint(static_cast<unsigned char>(c)))
{
out << c;
}
else
{
out << "\\x" << std::setw(2) << unsigned(c);
}
}
out.setf(oldfmt, std::ios_base::basefield);
out.fill(oldfill);
return out;
}
private:
std::string mData;
};
} // namespace LL
#endif /* ! defined(LL_HEXDUMP_H) */

View File

@ -88,10 +88,6 @@ LLApp* LLApp::sApplication = NULL;
// and disables crashlogger
bool LLApp::sDisableCrashlogger = false;
// Local flag for whether or not to do logging in signal handlers.
//static
bool LLApp::sLogInSignal = true;
// static
// Keeps track of application status
LLScalarCond<LLApp::EAppStatus> LLApp::sStatus{LLApp::APP_STATUS_STOPPED};
@ -226,7 +222,7 @@ bool LLApp::parseCommandOptions(int argc, wchar_t** wargv)
if(wargv[ii][0] != '-')
{
LL_INFOS() << "Did not find option identifier while parsing token: "
<< wargv[ii] << LL_ENDL;
<< (intptr_t)wargv[ii] << LL_ENDL;
return false;
}
int offset = 1;
@ -596,6 +592,10 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
// We do the somewhat sketchy operation of blocking in here until the error handler
// has gracefully stopped the app.
// FIXME(brad) - we are using this handler for asynchronous signals as well, so sLogInSignal is currently
// disabled for safety. we need to find a way to selectively reenable it when it is safe.
// see issue secondlife/viewer#2566
if (LLApp::sLogInSignal)
{
LL_INFOS() << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << LL_ENDL;

View File

@ -339,8 +339,12 @@ private:
friend void default_unix_signal_handler(int signum, siginfo_t *info, void *);
#endif
public:
static bool sLogInSignal;
private:
#ifdef LL_RELEASE_FOR_DOWNLOAD
static constexpr bool sLogInSignal = false;
#else
static constexpr bool sLogInSignal = true;
#endif
};
#endif // LL_LLAPP_H

View File

@ -34,7 +34,7 @@
#endif
#include <boost/noncopyable.hpp>
#include "llwin32headerslean.h"
#include "llwin32headers.h"
#include "apr_thread_proc.h"
#include "apr_getopt.h"
#include "apr_signal.h"

View File

@ -110,7 +110,7 @@ namespace {
virtual void recordMessage(LLError::ELevel level,
const std::string& message) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING;
int syslogPriority = LOG_CRIT;
switch (level) {
case LLError::LEVEL_DEBUG: syslogPriority = LOG_DEBUG; break;

View File

@ -34,7 +34,7 @@
#include "stringize.h"
#if LL_WINDOWS
#include "llwin32headerslean.h"
#include "llwin32headers.h"
#include <stdlib.h> // Windows errno
#include <vector>
#else

View File

@ -89,10 +89,10 @@ private:
}
// Given arbitrary CALLABLE, which might be a lambda, how are we
// supposed to obtain its signature for std::packaged_task? It seems
// redundant to have to add an argument list to engage result_of, then
// redundant to have to add an argument list to engage invoke_result_t, then
// add the argument list again to complete the signature. At least we
// only support a nullary CALLABLE.
std::packaged_task<typename std::result_of<CALLABLE()>::type()> mTask;
std::packaged_task<std::invoke_result_t<CALLABLE>()> mTask;
};
};

View File

@ -68,10 +68,6 @@ documentation and/or software.
*/
#include "linden_common.h"
#include "llmd5.h"
@ -81,232 +77,203 @@ documentation and/or software.
// how many bytes to grab at a time when checking files
const int LLMD5::BLOCK_LEN = 4096;
// LLMD5 simple initialization method
LLMD5::LLMD5()
{
init();
init();
}
// MD5 block update operation. Continues an MD5 message-digest
// operation, processing another message block, and updating the
// context.
void LLMD5::update(const uint8_t* input, const size_t input_length)
{
size_t input_index, buffer_index;
size_t buffer_space; // how much space is left in buffer
void LLMD5::update (const uint8_t *input, const size_t input_length) {
if (finalized)
{ // so we can't update!
std::cerr << "LLMD5::update: Can't update a finalized digest!" << std::endl;
return;
}
size_t input_index, buffer_index;
size_t buffer_space; // how much space is left in buffer
// Compute number of bytes mod 64
buffer_index = size_t((count >> 3) & 0x3F);
if (finalized){ // so we can't update!
std::cerr << "LLMD5::update: Can't update a finalized digest!" << std::endl;
return;
}
// Update number of bits
count += input_length << 3;
// Compute number of bytes mod 64
buffer_index = size_t((count >> 3) & 0x3F);
buffer_space = 64 - buffer_index; // how much space is left in buffer
// Update number of bits
count += input_length << 3;
// now, transform each 64-byte piece of the input, bypassing the buffer
if (input == NULL || input_length == 0)
{
std::cerr << "LLMD5::update: Invalid input!" << std::endl;
return;
}
buffer_space = 64 - buffer_index; // how much space is left in buffer
// Transform as many times as possible.
if (input_length >= buffer_space) // ie. we have enough to fill the buffer
{
// fill the rest of the buffer and transform
memcpy(/* Flawfinder: ignore */
buffer + buffer_index,
input,
buffer_space);
transform(buffer);
// now, transform each 64-byte piece of the input, bypassing the buffer
if (input == NULL || input_length == 0){
std::cerr << "LLMD5::update: Invalid input!" << std::endl;
return;
}
for (input_index = buffer_space; input_index + 63 < input_length; input_index += 64)
transform(input + input_index);
// Transform as many times as possible.
if (input_length >= buffer_space) { // ie. we have enough to fill the buffer
// fill the rest of the buffer and transform
memcpy( /* Flawfinder: ignore */
buffer + buffer_index,
input,
buffer_space);
transform (buffer);
buffer_index = 0; // so we can buffer remaining
}
else
input_index = 0; // so we can buffer the whole input
for (input_index = buffer_space; input_index + 63 < input_length;
input_index += 64)
transform (input+input_index);
buffer_index = 0; // so we can buffer remaining
}
else
input_index=0; // so we can buffer the whole input
// and here we do the buffering:
memcpy(buffer+buffer_index, input+input_index, input_length-input_index); /* Flawfinder: ignore */
// and here we do the buffering:
memcpy(buffer + buffer_index, input + input_index, input_length - input_index); /* Flawfinder: ignore */
}
// MD5 update for files.
// Like above, except that it works on files (and uses above as a primitive.)
void LLMD5::update(FILE* file)
{
unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */
int len;
void LLMD5::update(FILE* file){
unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */
int len;
while ( (len=(int)fread(buffer, 1, BLOCK_LEN, file)) )
update(buffer, len);
fclose (file);
while ((len = (int)fread(buffer, 1, BLOCK_LEN, file)))
update(buffer, len);
fclose(file);
}
// MD5 update for istreams.
// Like update for files; see above.
void LLMD5::update(std::istream& stream)
{
unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */
int len;
void LLMD5::update(std::istream& stream){
unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */
int len;
while (stream.good()){
stream.read( (char*)buffer, BLOCK_LEN); /* Flawfinder: ignore */ // note that return value of read is unusable.
len=(int)stream.gcount();
update(buffer, len);
}
while (stream.good())
{
stream.read((char*)buffer, BLOCK_LEN); /* Flawfinder: ignore */ // note that return value of read is unusable.
len = (int)stream.gcount();
update(buffer, len);
}
}
void LLMD5::update(const std::string& s)
void LLMD5::update(const std::string& s)
{
update((unsigned char *)s.c_str(),s.length());
update((unsigned char*)s.c_str(), s.length());
}
// MD5 finalization. Ends an MD5 message-digest operation, writing the
// the message digest and zeroizing the context.
void LLMD5::finalize (){
unsigned char bits[8]; /* Flawfinder: ignore */
size_t index, padLen;
static uint8_t PADDING[64]={
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
void LLMD5::finalize()
{
unsigned char bits[8]; /* Flawfinder: ignore */
size_t index, padLen;
static uint8_t PADDING[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
if (finalized){
std::cerr << "LLMD5::finalize: Already finalized this digest!" << std::endl;
return;
}
if (finalized)
{
std::cerr << "LLMD5::finalize: Already finalized this digest!" << std::endl;
return;
}
// Save number of bits.
// Treat count, a uint64_t, as uint32_t[2].
encode (bits, reinterpret_cast<uint32_t*>(&count), 8);
// Save number of bits.
// Treat count, a uint64_t, as uint32_t[2].
encode(bits, reinterpret_cast<uint32_t*>(&count), 8);
// Pad out to 56 mod 64.
index = size_t((count >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
update (PADDING, padLen);
// Pad out to 56 mod 64.
index = size_t((count >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
update(PADDING, padLen);
// Append length (before padding)
update (bits, 8);
// Append length (before padding)
update(bits, 8);
// Store state in digest
encode (digest, state, 16);
// Store state in digest
encode(digest, state, 16);
// Zeroize sensitive information
memset (buffer, 0, sizeof(*buffer));
finalized=1;
// Zeroize sensitive information
memset(buffer, 0, sizeof(buffer));
finalized = true;
}
LLMD5::LLMD5(FILE *file){
init(); // must be called be all constructors
update(file);
finalize ();
LLMD5::LLMD5(FILE* file)
{
init(); // must be called be all constructors
update(file);
finalize();
}
LLMD5::LLMD5(std::istream& stream){
init(); // must called by all constructors
update (stream);
finalize();
LLMD5::LLMD5(std::istream& stream)
{
init(); // must called by all constructors
update(stream);
finalize();
}
// Digest a string of the format ("%s:%i" % (s, number))
LLMD5::LLMD5(const unsigned char *string, const unsigned int number)
LLMD5::LLMD5(const unsigned char* string, const unsigned int number)
{
const char *colon = ":";
char tbuf[16]; /* Flawfinder: ignore */
const char* colon = ":";
char tbuf[16]; /* Flawfinder: ignore */
init();
update(string, (U32)strlen((const char *) string)); /* Flawfinder: ignore */
update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */
snprintf(tbuf, sizeof(tbuf), "%i", number); /* Flawfinder: ignore */
update((const unsigned char *) tbuf, (U32)strlen(tbuf)); /* Flawfinder: ignore */
update(string, (U32)strlen((const char*)string)); /* Flawfinder: ignore */
update((const unsigned char*)colon, (U32)strlen(colon)); /* Flawfinder: ignore */
snprintf(tbuf, sizeof(tbuf), "%i", number); /* Flawfinder: ignore */
update((const unsigned char*)tbuf, (U32)strlen(tbuf)); /* Flawfinder: ignore */
finalize();
}
// Digest a string
LLMD5::LLMD5(const unsigned char *s)
LLMD5::LLMD5(const unsigned char* s)
{
init();
update(s, (U32)strlen((const char *) s)); /* Flawfinder: ignore */
update(s, (U32)strlen((const char*)s)); /* Flawfinder: ignore */
finalize();
}
void LLMD5::raw_digest(unsigned char *s) const
void LLMD5::raw_digest(unsigned char* s) const
{
if (!finalized)
{
std::cerr << "LLMD5::raw_digest: Can't get digest if you haven't "<<
"finalized the digest!" << std::endl;
std::cerr << "LLMD5::raw_digest: Can't get digest if you haven't "
<< "finalized the digest!" << std::endl;
s[0] = '\0';
return;
}
memcpy(s, digest, 16); /* Flawfinder: ignore */
return;
memcpy(s, digest, 16); /* Flawfinder: ignore */
}
void LLMD5::hex_digest(char *s) const
void LLMD5::hex_digest(char* s) const
{
int i;
if (!finalized)
{
std::cerr << "LLMD5::hex_digest: Can't get digest if you haven't "<<
"finalized the digest!" <<std::endl;
std::cerr << "LLMD5::hex_digest: Can't get digest if you haven't "
<< "finalized the digest!" << std::endl;
s[0] = '\0';
return;
}
for (i=0; i<16; i++)
for (int i = 0; i < 16; i++)
{
sprintf(s+i*2, "%02x", digest[i]); /* Flawfinder: ignore */
sprintf(s + i * 2, "%02x", digest[i]); /* Flawfinder: ignore */
}
s[32]='\0';
return;
s[32] = '\0';
}
std::ostream& operator<<(std::ostream &stream, LLMD5 context)
std::ostream& operator<<(std::ostream& stream, const LLMD5& context)
{
char s[33]; /* Flawfinder: ignore */
context.hex_digest(s);
@ -320,7 +287,7 @@ bool operator==(const LLMD5& a, const LLMD5& b)
unsigned char b_guts[16];
a.raw_digest(a_guts);
b.raw_digest(b_guts);
if (memcmp(a_guts,b_guts,16)==0)
if (memcmp(a_guts, b_guts, 16) == 0)
return true;
else
return false;
@ -328,30 +295,27 @@ bool operator==(const LLMD5& a, const LLMD5& b)
bool operator!=(const LLMD5& a, const LLMD5& b)
{
return !(a==b);
return !(a == b);
}
// PRIVATE METHODS:
void LLMD5::init()
{
finalized = false; // we just started!
void LLMD5::init(){
finalized=0; // we just started!
// Nothing counted, so count=0
count = 0;
// Nothing counted, so count=0
count = 0;
// Load magic initialization constants.
state[0] = 0x67452301;
state[1] = 0xefcdab89;
state[2] = 0x98badcfe;
state[3] = 0x10325476;
// Load magic initialization constants.
state[0] = 0x67452301;
state[1] = 0xefcdab89;
state[2] = 0x98badcfe;
state[3] = 0x10325476;
}
// Constants for MD5Transform routine.
// Although we could use C++ style constants, defines are actually better,
// since they let us easily evade scope clashes.
#define S11 7
#define S12 12
#define S13 17
@ -381,153 +345,144 @@ void LLMD5::init(){
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (U32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (U32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (U32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (U32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define FF(a, b, c, d, x, s, ac) \
{ \
(a) += F((b), (c), (d)) + (x) + (U32)(ac); \
(a) = ROTATE_LEFT((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) \
{ \
(a) += G((b), (c), (d)) + (x) + (U32)(ac); \
(a) = ROTATE_LEFT((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) \
{ \
(a) += H((b), (c), (d)) + (x) + (U32)(ac); \
(a) = ROTATE_LEFT((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) \
{ \
(a) += I((b), (c), (d)) + (x) + (U32)(ac); \
(a) = ROTATE_LEFT((a), (s)); \
(a) += (b); \
}
// LLMD5 basic transformation. Transforms state based on block.
void LLMD5::transform (const U8 block[64]){
void LLMD5::transform(const U8 block[64])
{
uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
decode(x, block, 64);
decode (x, block, 64);
assert(!finalized); // not just a user error, since the method is private
assert(!finalized); // not just a user error, since the method is private
/* Round 1 */
FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
// Zeroize sensitive information.
memset ( (uint8_t *) x, 0, sizeof(x));
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
// Zeroize sensitive information.
memset(x, 0, sizeof(x));
}
// Encodes input (uint32_t) into output (unsigned char). Assumes len is
// a multiple of 4.
void LLMD5::encode (uint8_t *output, const uint32_t *input, const size_t len) {
size_t i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (uint8_t) (input[i] & 0xff);
output[j+1] = (uint8_t) ((input[i] >> 8) & 0xff);
output[j+2] = (uint8_t) ((input[i] >> 16) & 0xff);
output[j+3] = (uint8_t) ((input[i] >> 24) & 0xff);
}
void LLMD5::encode(uint8_t* output, const uint32_t* input, const size_t len)
{
for (size_t i = 0, j = 0; j < len; i++, j += 4)
{
output[j] = (uint8_t)(input[i] & 0xff);
output[j + 1] = (uint8_t)((input[i] >> 8) & 0xff);
output[j + 2] = (uint8_t)((input[i] >> 16) & 0xff);
output[j + 3] = (uint8_t)((input[i] >> 24) & 0xff);
}
}
// Decodes input (unsigned char) into output (uint32_t). Assumes len is
// a multiple of 4.
void LLMD5::decode (uint32_t *output, const uint8_t *input, const size_t len){
size_t i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) |
(((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24);
void LLMD5::decode(uint32_t* output, const uint8_t* input, const size_t len)
{
for (size_t i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) |
(((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24);
}

View File

@ -67,59 +67,57 @@ documentation and/or software.
*/
#include <cstdint> // uint32_t et al.
#include <cstdint> // uint32_t et al.
// use for the raw digest output
const int MD5RAW_BYTES = 16;
// use for outputting hex digests
const int MD5HEX_STR_SIZE = 33; // char hex[MD5HEX_STR_SIZE]; with null
const int MD5HEX_STR_SIZE = 33; // char hex[MD5HEX_STR_SIZE]; with null
const int MD5HEX_STR_BYTES = 32; // message system fixed size
class LL_COMMON_API LLMD5 {
// how many bytes to grab at a time when checking files
static const int BLOCK_LEN;
class LL_COMMON_API LLMD5
{
// how many bytes to grab at a time when checking files
static const int BLOCK_LEN;
public:
// methods for controlled operation:
LLMD5 (); // simple initializer
void update (const uint8_t *input, const size_t input_length);
void update (std::istream& stream);
void update (FILE *file);
void update (const std::string& str);
void finalize ();
// methods for controlled operation:
LLMD5(); // simple initializer
void update(const uint8_t* input, const size_t input_length);
void update(std::istream& stream);
void update(FILE* file);
void update(const std::string& str);
void finalize();
// constructors for special circumstances. All these constructors finalize
// the MD5 context.
LLMD5 (const unsigned char *string); // digest string, finalize
LLMD5 (std::istream& stream); // digest stream, finalize
LLMD5 (FILE *file); // digest file, close, finalize
LLMD5 (const unsigned char *string, const unsigned int number);
// constructors for special circumstances. All these constructors finalize
// the MD5 context.
LLMD5(const unsigned char* string); // digest string, finalize
LLMD5(std::istream& stream); // digest stream, finalize
LLMD5(FILE* file); // digest file, close, finalize
LLMD5(const unsigned char* string, const unsigned int number);
// methods to acquire finalized result
void raw_digest(unsigned char *array) const; // provide 16-byte array for binary data
void hex_digest(char *string) const; // provide 33-byte array for ascii-hex string
// methods to acquire finalized result
void raw_digest(unsigned char* array) const; // provide 16-byte array for binary data
void hex_digest(char* string) const; // provide 33-byte array for ascii-hex string
friend LL_COMMON_API std::ostream& operator<< (std::ostream&, LLMD5 context);
friend LL_COMMON_API std::ostream& operator<<(std::ostream&, const LLMD5& context);
private:
// next, the private data:
uint32_t state[4];
uint64_t count; // number of *bits*, mod 2^64
uint8_t buffer[64]; // input buffer
uint8_t digest[16];
bool finalized;
// last, the private methods, mostly static:
void init(); // called by all constructors
void transform(const uint8_t* buffer); // does the real update work. Note
// that length is implied to be 64.
// next, the private data:
uint32_t state[4];
uint64_t count; // number of *bits*, mod 2^64
uint8_t buffer[64]; // input buffer
uint8_t digest[16];
uint8_t finalized;
// last, the private methods, mostly static:
void init (); // called by all constructors
void transform (const uint8_t *buffer); // does the real update work. Note
// that length is implied to be 64.
static void encode (uint8_t *dest, const uint32_t *src, const size_t length);
static void decode (uint32_t *dest, const uint8_t *src, const size_t length);
static void encode(uint8_t* dest, const uint32_t* src, const size_t length);
static void decode(uint32_t* dest, const uint8_t* src, const size_t length);
};
LL_COMMON_API bool operator==(const LLMD5& a, const LLMD5& b);

View File

@ -194,6 +194,18 @@ public:
mSharedMutex->unlock<SHARED>();
}
void lock()
{
if (mSharedMutex)
mSharedMutex->lock<SHARED>();
}
void unlock()
{
if (mSharedMutex)
mSharedMutex->unlock<SHARED>();
}
private:
LLSharedMutex* mSharedMutex;
};

View File

@ -418,6 +418,17 @@ private:
bool mStayUnique;
};
template<typename Type>
bool operator!=(Type* lhs, const LLPointer<Type>& rhs)
{
return (lhs != rhs.get());
}
template<typename Type>
bool operator==(Type* lhs, const LLPointer<Type>& rhs)
{
return (lhs == rhs.get());
}
// boost hash adapter
template <class Type>

View File

@ -139,7 +139,7 @@ namespace LLPredicate
Rule()
{}
void require(ENUM e, bool match)
void mandate(ENUM e, bool match)
{
mRule.set(e, match);
}
@ -154,7 +154,7 @@ namespace LLPredicate
return (mRule && value).someSet();
}
bool requires(const Value<ENUM> value) const
bool mandates(const Value<ENUM> value) const
{
return (mRule && value).someSet() && (!mRule && value).noneSet();
}

View File

@ -98,15 +98,6 @@
# define LL_THREAD_LOCAL __thread
#endif
// Static linking with apr on windows needs to be declared.
#if LL_WINDOWS && !LL_COMMON_LINK_SHARED
#ifndef APR_DECLARE_STATIC
#define APR_DECLARE_STATIC // For APR on Windows
#endif
#ifndef APU_DECLARE_STATIC
#define APU_DECLARE_STATIC // For APR util on Windows
#endif
#endif
#if defined(LL_WINDOWS)
#define BOOST_REGEX_NO_LIB 1
@ -119,13 +110,6 @@
// Deal with VC++ problems
#if LL_MSVC
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS // disable warnings for methods considered unsafe
#endif
#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS // disable deprecated WinSock API warnings
#endif
// level 4 warnings that we need to disable:
#pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class
#pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class

View File

@ -29,7 +29,6 @@
#include "llinitparam.h"
#include "llsdparam.h"
#include "llwin32headerslean.h"
#include "llexception.h"
#include "apr_thread_proc.h"
#include <boost/ptr_container/ptr_vector.hpp>
@ -38,7 +37,7 @@
#include <iosfwd> // std::ostream
#if LL_WINDOWS
#include "llwin32headerslean.h" // for HANDLE
#include "llwin32headers.h" // for HANDLE
#elif LL_LINUX
#if defined(Status)
#undef Status

View File

@ -34,7 +34,7 @@
//#include <memory>
#if LL_WINDOWS
# include "llwin32headerslean.h"
# include "llwin32headers.h"
# define _interlockedbittestandset _renamed_interlockedbittestandset
# define _interlockedbittestandreset _renamed_interlockedbittestandreset
# include <intrin.h>

View File

@ -61,12 +61,20 @@ LLSD LlsdFromJson(const boost::json::value& val)
result = LLSD(val.as_bool());
break;
case boost::json::kind::array:
{
result = LLSD::emptyArray();
for (const auto &element : val.as_array())
auto& array = val.as_array();
// allocate elements 0 .. (size() - 1) to avoid incremental allocation
if (! array.empty())
{
result[array.size() - 1] = LLSD();
}
for (const auto &element : array)
{
result.append(LlsdFromJson(element));
}
break;
}
case boost::json::kind::object:
result = LLSD::emptyMap();
for (const auto& element : val.as_object())
@ -106,6 +114,7 @@ boost::json::value LlsdToJson(const LLSD &val)
case LLSD::TypeMap:
{
boost::json::object& obj = result.emplace_object();
obj.reserve(val.size());
for (const auto& llsd_dat : llsd::inMap(val))
{
obj[llsd_dat.first] = LlsdToJson(llsd_dat.second);
@ -115,6 +124,7 @@ boost::json::value LlsdToJson(const LLSD &val)
case LLSD::TypeArray:
{
boost::json::array& json_array = result.emplace_array();
json_array.reserve(val.size());
for (const auto& llsd_dat : llsd::inArray(val))
{
json_array.push_back(LlsdToJson(llsd_dat));
@ -123,7 +133,8 @@ boost::json::value LlsdToJson(const LLSD &val)
}
case LLSD::TypeBinary:
default:
LL_ERRS("LlsdToJson") << "Unsupported conversion to JSON from LLSD type (" << val.type() << ")." << LL_ENDL;
LL_ERRS("LlsdToJson") << "Unsupported conversion to JSON from LLSD type ("
<< val.type() << ")." << LL_ENDL;
break;
}

View File

@ -32,8 +32,7 @@
#include <sstream>
#if LL_WINDOWS
# define WIN32_LEAN_AND_MEAN
# include <winsock2.h> // for htonl
# include "llwin32headers.h" // for htonl
#elif LL_LINUX
# include <netinet/in.h>
#elif LL_DARWIN

View File

@ -32,7 +32,7 @@
#include <iostream>
#include <sstream>
#include "llwin32headerslean.h"
#include "llwin32headers.h"
#include <dbghelp.h>
typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(

View File

@ -41,6 +41,13 @@ public:
LLStrider(Object* first) { mObjectp = first; mSkip = sizeof(Object); }
~LLStrider() { }
const LLStrider<Object>& operator=(const LLStrider<Object>& rhs)
{
mBytep = rhs.mBytep;
mSkip = rhs.mSkip;
return *this;
}
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}
void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));}

View File

@ -33,8 +33,7 @@
#include <vector>
#if LL_WINDOWS
#include "llwin32headerslean.h"
#include <winnls.h> // for WideCharToMultiByte
#include "llwin32headers.h"
#endif
std::string ll_safe_string(const char* in)
@ -1410,6 +1409,14 @@ bool LLStringUtil::simpleReplacement(std::string &replacement, std::string token
template<>
void LLStringUtil::setLocale(std::string inLocale)
{
if(startsWith(inLocale, "MissingString"))
{
// it seems this hasn't been working for some time, and I'm not sure how it is intentded to
// properly discover the correct locale. early out now to avoid failures later in
// formatNumber()
LL_WARNS() << "Failed attempting to set invalid locale: " << inLocale << LL_ENDL;
return;
}
sLocale = inLocale;
};

View File

@ -59,7 +59,7 @@
using namespace llsd;
#if LL_WINDOWS
# include "llwin32headerslean.h"
# include "llwin32headers.h"
# include <psapi.h> // GetPerformanceInfo() et al.
# include <VersionHelpers.h>
#elif LL_DARWIN

View File

@ -34,7 +34,7 @@
#include <thread>
#if LL_WINDOWS
# include "llwin32headerslean.h"
# include "llwin32headers.h"
#elif LL_LINUX || LL_DARWIN
# include <errno.h>
# include <sys/time.h>

View File

@ -25,11 +25,8 @@
#include "linden_common.h"
// We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes.
#if LL_WINDOWS
#include "llwin32headers.h"
// ugh, this is ugly. We need to straighten out our linking for this library
#pragma comment(lib, "IPHLPAPI.lib")
#include <iphlpapi.h>
#include <nb30.h>
#endif

View File

@ -28,15 +28,8 @@
#define LL_LLWINDOWS_H
#ifdef LL_WINDOWS
#ifndef NOMINMAX
#define NOMINMAX
#endif
#undef WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
// reset to default, which is lean
#define WIN32_LEAN_AND_MEAN
#undef NOMINMAX
#include <windows.h> // Does not include winsock.h because WIN32_LEAN_AND_MEAN is defined
#include <winsock2.h> // Requires windows.h
#endif
#endif

View File

@ -92,7 +92,7 @@ namespace tut
op->setReplyPath(LLCore::HttpOperation::HttpReplyQueuePtr_t(), h1);
// Check ref count
ensure(op.unique() == 1);
ensure(op.use_count() == 1);
// release the reference, releasing the operation but
// not the handlers.

View File

@ -721,6 +721,8 @@ std::vector<std::string> LLDir::findSkinnedFilenames(const std::string& subdir,
const std::string& filename,
ESkinConstraint constraint) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
// Recognize subdirs that have no localization.
static const std::set<std::string> sUnlocalized = list_of
("") // top-level directory not localized

View File

@ -179,7 +179,7 @@ private:
public:
template<bool SHARED>
class DataLock : LLSharedMutexLockTemplate<SHARED>
class DataLock : public LLSharedMutexLockTemplate<SHARED>
{
public:
DataLock(const LLImageBase* image)

View File

@ -276,16 +276,20 @@ S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 r
// Estimate the number of layers. This is consistent with what's done for j2c encoding in LLImageJ2CKDU::encodeImpl().
constexpr S32 precision = 8; // assumed bitrate per component channel, might change in future for HDR support
constexpr S32 max_components = 4; // assumed the file has four components; three color and alpha
S32 nb_layers = 1;
const S32 surface = w*h;
S32 s = 64*64;
S32 totalbytes = (S32)(s * max_components * precision * rate); // first level computed before loop
while (surface > s)
// Use MAX_IMAGE_SIZE_DEFAULT (currently 2048) if either dimension is unknown (zero)
S32 width = (w > 0) ? w : 2048;
S32 height = (h > 0) ? h : 2048;
S32 max_dimension = llmax(width, height); // Find largest dimension
S32 block_area = MAX_BLOCK_SIZE * MAX_BLOCK_SIZE; // Calculated initial block area from established max block size (currently 64)
block_area *= llmax((max_dimension / MAX_BLOCK_SIZE / max_components), 1); // Adjust initial block area by ratio of largest dimension to block size per component
S32 totalbytes = (S32) (block_area * max_components * precision); // First block layer computed before loop without compression rate
S32 block_layers = 1; // Start at layer 1 since first block layer is computed outside loop
while (block_layers < 6) // Walk five layers for the five discards in JPEG2000
{
if (nb_layers <= (5 - discard_level))
totalbytes += (S32)(s * max_components * precision * rate);
nb_layers++;
s *= 4;
if (block_layers <= (5 - discard_level)) // Walk backwards from discard 5 to required discard layer.
totalbytes += (S32) (block_area * max_components * precision * rate); // Add each block layer reduced by assumed compression rate
block_layers++; // Move to next layer
block_area *= 4; // Increase block area by power of four
}
totalbytes /= 8; // to bytes

View File

@ -37,48 +37,48 @@ typedef U32 PermissionBit;
// Do you have permission to transfer ownership of the object or
// item. Fair use rules dictate that if you cannot copy, you can
// always transfer.
const PermissionBit PERM_TRANSFER = (1 << 13); // 0x00002000
constexpr PermissionBit PERM_TRANSFER = (1 << 13); // 0x00002000
// objects, scale or change textures
// parcels, allow building on it
const PermissionBit PERM_MODIFY = (1 << 14); // 0x00004000
constexpr PermissionBit PERM_MODIFY = (1 << 14); // 0x00004000
// objects, allow copy
const PermissionBit PERM_COPY = (1 << 15); // 0x00008000
constexpr PermissionBit PERM_COPY = (1 << 15); // 0x00008000
// parcels, allow entry, deprecated
//const PermissionBit PERM_ENTER = (1 << 16); // 0x00010000
//constexpr PermissionBit PERM_ENTER = (1 << 16); // 0x00010000
// parcels, allow terraform, deprecated
//const PermissionBit PERM_TERRAFORM = (1 << 17); // 0x00020000
//constexpr PermissionBit PERM_TERRAFORM = (1 << 17); // 0x00020000
// NOTA BENE: This flag is NO LONGER USED!!! However, it is possible that some
// objects in the universe have it set so DON"T USE IT going forward.
//const PermissionBit PERM_OWNER_DEBIT = (1 << 18); // 0x00040000
//constexpr PermissionBit PERM_OWNER_DEBIT = (1 << 18); // 0x00040000
// objects, can grab/translate/rotate
const PermissionBit PERM_MOVE = (1 << 19); // 0x00080000
constexpr PermissionBit PERM_MOVE = (1 << 19); // 0x00080000
// parcels, avatars take damage, deprecated
//const PermissionBit PERM_DAMAGE = (1 << 20); // 0x00100000
// don't use bit 31 -- printf/scanf with "%x" assume signed numbers
const PermissionBit PERM_RESERVED = ((U32)1) << 31;
constexpr PermissionBit PERM_RESERVED = ((U32)1) << 31;
const PermissionMask PERM_NONE = 0x00000000;
const PermissionMask PERM_ALL = 0x7FFFFFFF;
//const PermissionMask PERM_ALL_PARCEL = PERM_MODIFY | PERM_ENTER | PERM_TERRAFORM | PERM_DAMAGE;
const PermissionMask PERM_ITEM_UNRESTRICTED = PERM_MODIFY | PERM_COPY | PERM_TRANSFER;
constexpr PermissionMask PERM_NONE = 0x00000000;
constexpr PermissionMask PERM_ALL = 0x7FFFFFFF;
//constexpr PermissionMask PERM_ALL_PARCEL = PERM_MODIFY | PERM_ENTER | PERM_TERRAFORM | PERM_DAMAGE;
constexpr PermissionMask PERM_ITEM_UNRESTRICTED = PERM_MODIFY | PERM_COPY | PERM_TRANSFER;
// Useful stuff for transmission.
// Which permissions field are we trying to change?
const U8 PERM_BASE = 0x01;
constexpr U8 PERM_BASE = 0x01;
// TODO: Add another PERM_OWNER operation type for allowOperationBy DK 04/03/06
const U8 PERM_OWNER = 0x02;
const U8 PERM_GROUP = 0x04;
const U8 PERM_EVERYONE = 0x08;
const U8 PERM_NEXT_OWNER = 0x10;
constexpr U8 PERM_OWNER = 0x02;
constexpr U8 PERM_GROUP = 0x04;
constexpr U8 PERM_EVERYONE = 0x08;
constexpr U8 PERM_NEXT_OWNER = 0x10;
// This is just a quickie debugging key
// no modify: PERM_ALL & ~PERM_MODIFY = 0x7fffbfff

View File

@ -69,25 +69,99 @@ const U32 LLSettingsBase::Validator::VALIDATION_PARTIAL(0x01 << 0);
LLSettingsBase::LLSettingsBase():
mSettings(LLSD::emptyMap()),
mDirty(true),
mBlendedFactor(0.0)
mLLSDDirty(true),
mReplaced(false),
mBlendedFactor(0.0),
mSettingFlags(0)
{
}
LLSettingsBase::LLSettingsBase(const LLSD setting) :
mSettings(setting),
mLLSDDirty(true),
mDirty(true),
mBlendedFactor(0.0)
mReplaced(false),
mBlendedFactor(0.0),
mSettingFlags(0)
{
}
//virtual
void LLSettingsBase::loadValuesFromLLSD()
{
mLLSDDirty = false;
mAssetId = mSettings[SETTING_ASSETID].asUUID();
mSettingId = getValue(SETTING_ID).asUUID();
mSettingName = getValue(SETTING_NAME).asString();
if (mSettings.has(SETTING_FLAGS))
{
mSettingFlags = (U32)mSettings[SETTING_FLAGS].asInteger();
}
else
{
mSettingFlags = 0;
}
}
//virtual
void LLSettingsBase::saveValuesToLLSD()
{
mLLSDDirty = false;
mSettings[SETTING_NAME] = mSettingName;
if (mAssetId.isNull())
{
mSettings.erase(SETTING_ASSETID);
}
else
{
mSettings[SETTING_ASSETID] = mAssetId;
}
mSettings[SETTING_FLAGS] = LLSD::Integer(mSettingFlags);
}
void LLSettingsBase::saveValuesIfNeeded()
{
if (mLLSDDirty)
{
saveValuesToLLSD();
}
}
//=========================================================================
void LLSettingsBase::lerpSettings(const LLSettingsBase &other, F64 mix)
void LLSettingsBase::lerpSettings(LLSettingsBase &other, F64 mix)
{
mSettings = interpolateSDMap(mSettings, other.mSettings, other.getParameterMap(), mix);
LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
saveValuesIfNeeded();
stringset_t skip = getSkipInterpolateKeys();
stringset_t slerps = getSlerpKeys();
mSettings = interpolateSDMap(mSettings, other.getSettings(), other.getParameterMap(), mix, skip, slerps);
setDirtyFlag(true);
loadValuesFromLLSD();
}
LLSD LLSettingsBase::combineSDMaps(const LLSD &settings, const LLSD &other) const
void LLSettingsBase::lerpVector2(LLVector2& a, const LLVector2& b, F32 mix)
{
a.mV[0] = lerp(a.mV[0], b.mV[0], mix);
a.mV[1] = lerp(a.mV[1], b.mV[1], mix);
}
void LLSettingsBase::lerpVector3(LLVector3& a, const LLVector3& b, F32 mix)
{
a.mV[0] = lerp(a.mV[0], b.mV[0], mix);
a.mV[1] = lerp(a.mV[1], b.mV[1], mix);
a.mV[2] = lerp(a.mV[2], b.mV[2], mix);
}
void LLSettingsBase::lerpColor(LLColor3& a, const LLColor3& b, F32 mix)
{
a.mV[0] = lerp(a.mV[0], b.mV[0], mix);
a.mV[1] = lerp(a.mV[1], b.mV[1], mix);
a.mV[2] = lerp(a.mV[2], b.mV[2], mix);
}
LLSD LLSettingsBase::combineSDMaps(const LLSD &settings, const LLSD &other)
{
LLSD newSettings;
@ -161,13 +235,10 @@ LLSD LLSettingsBase::combineSDMaps(const LLSD &settings, const LLSD &other) cons
return newSettings;
}
LLSD LLSettingsBase::interpolateSDMap(const LLSD &settings, const LLSD &other, const parammapping_t& defaults, F64 mix) const
LLSD LLSettingsBase::interpolateSDMap(const LLSD &settings, const LLSD &other, const parammapping_t& defaults, F64 mix, const stringset_t& skip, const stringset_t& slerps)
{
LLSD newSettings;
stringset_t skip = getSkipInterpolateKeys();
stringset_t slerps = getSlerpKeys();
llassert(mix >= 0.0f && mix <= 1.0f);
for (LLSD::map_const_iterator it = settings.beginMap(); it != settings.endMap(); ++it)
@ -204,7 +275,7 @@ LLSD LLSettingsBase::interpolateSDMap(const LLSD &settings, const LLSD &other, c
}
}
newSettings[key_name] = interpolateSDValue(key_name, value, other_value, defaults, mix, slerps);
newSettings[key_name] = interpolateSDValue(key_name, value, other_value, defaults, mix, skip, slerps);
}
// Special handling cases
@ -233,12 +304,12 @@ LLSD LLSettingsBase::interpolateSDMap(const LLSD &settings, const LLSD &other, c
if (def_iter != defaults.end())
{
// Blend against default value
newSettings[key_name] = interpolateSDValue(key_name, def_iter->second.getDefaultValue(), (*it).second, defaults, mix, slerps);
newSettings[key_name] = interpolateSDValue(key_name, def_iter->second.getDefaultValue(), (*it).second, defaults, mix, skip, slerps);
}
else if ((*it).second.type() == LLSD::TypeMap)
{
// interpolate in case there are defaults inside (part of legacy)
newSettings[key_name] = interpolateSDValue(key_name, LLSDMap(), (*it).second, defaults, mix, slerps);
newSettings[key_name] = interpolateSDValue(key_name, LLSDMap(), (*it).second, defaults, mix, skip, slerps);
}
// else do nothing when no known defaults
// TODO: Should I blend this out instead?
@ -260,7 +331,7 @@ LLSD LLSettingsBase::interpolateSDMap(const LLSD &settings, const LLSD &other, c
return newSettings;
}
LLSD LLSettingsBase::interpolateSDValue(const std::string& key_name, const LLSD &value, const LLSD &other_value, const parammapping_t& defaults, BlendFactor mix, const stringset_t& slerps) const
LLSD LLSettingsBase::interpolateSDValue(const std::string& key_name, const LLSD &value, const LLSD &other_value, const parammapping_t& defaults, BlendFactor mix, const stringset_t& skip, const stringset_t& slerps)
{
LLSD new_value;
@ -286,7 +357,7 @@ LLSD LLSettingsBase::interpolateSDValue(const std::string& key_name, const LLSD
break;
case LLSD::TypeMap:
// deep copy.
new_value = interpolateSDMap(value, other_value, defaults, mix);
new_value = interpolateSDMap(value, other_value, defaults, mix, skip, slerps);
break;
case LLSD::TypeArray:
@ -348,21 +419,24 @@ LLSettingsBase::stringset_t LLSettingsBase::getSkipInterpolateKeys() const
return skipSet;
}
LLSD LLSettingsBase::getSettings() const
LLSD& LLSettingsBase::getSettings()
{
saveValuesIfNeeded();
return mSettings;
}
LLSD LLSettingsBase::cloneSettings() const
LLSD LLSettingsBase::cloneSettings()
{
U32 flags = getFlags();
LLSD settings (combineSDMaps(getSettings(), LLSD()));
if (flags)
saveValuesIfNeeded();
LLSD settings(combineSDMaps(getSettings(), LLSD()));
if (U32 flags = getFlags())
{
settings[SETTING_FLAGS] = LLSD::Integer(flags);
}
return settings;
}
size_t LLSettingsBase::getHash() const
size_t LLSettingsBase::getHash()
{ // get a shallow copy of the LLSD filtering out values to not include in the hash
LLSD hash_settings = llsd_shallow(getSettings(),
LLSDMap(SETTING_NAME, false)(SETTING_ID, false)(SETTING_HASH, false)("*", true));
@ -380,7 +454,9 @@ bool LLSettingsBase::validate()
mSettings[SETTING_TYPE] = getSettingsType();
}
saveValuesIfNeeded();
LLSD result = LLSettingsBase::settingValidation(mSettings, validations);
loadValuesFromLLSD();
if (result["errors"].size() > 0)
{
@ -703,7 +779,7 @@ F64 LLSettingsBlender::setBlendFactor(const LLSettingsBase::BlendFactor& blendf_
if (mTarget)
{
mTarget->replaceSettings(mInitial->getSettings());
mTarget->replaceSettings(mInitial);
mTarget->blend(mFinal, blendf);
}
else
@ -718,7 +794,7 @@ void LLSettingsBlender::triggerComplete()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
if (mTarget)
mTarget->replaceSettings(mFinal->getSettings());
mTarget->replaceSettings(mFinal);
LLSettingsBlender::ptr_t hold = shared_from_this(); // prevents this from deleting too soon
mTarget->update();
mOnFinished(shared_from_this());

View File

@ -109,72 +109,59 @@ public:
virtual bool isDirty() const { return mDirty; }
virtual bool isVeryDirty() const { return mReplaced; }
inline void setDirtyFlag(bool dirty) { mDirty = dirty; clearAssetId(); }
inline void setReplaced() { mReplaced = true; }
size_t getHash() const; // Hash will not include Name, ID or a previously stored Hash
size_t getHash(); // Hash will not include Name, ID or a previously stored Hash
inline LLUUID getId() const
{
return getValue(SETTING_ID).asUUID();
return mSettingId;
}
inline std::string getName() const
{
return getValue(SETTING_NAME).asString();
return mSettingName;
}
inline void setName(std::string val)
{
setValue(SETTING_NAME, val);
mSettingName = val;
setDirtyFlag(true);
setLLSDDirty();
}
inline LLUUID getAssetId() const
{
if (mSettings.has(SETTING_ASSETID))
return mSettings[SETTING_ASSETID].asUUID();
return LLUUID();
return mAssetId;
}
inline U32 getFlags() const
{
if (mSettings.has(SETTING_FLAGS))
return static_cast<U32>(mSettings[SETTING_FLAGS].asInteger());
return 0;
return mSettingFlags;
}
inline void setFlags(U32 value)
{
setLLSD(SETTING_FLAGS, LLSD::Integer(value));
mSettingFlags = value;
setDirtyFlag(true);
setLLSDDirty();
}
inline bool getFlag(U32 flag) const
{
if (mSettings.has(SETTING_FLAGS))
return ((U32)mSettings[SETTING_FLAGS].asInteger() & flag) == flag;
return false;
return (mSettingFlags & flag) == flag;
}
inline void setFlag(U32 flag)
{
U32 flags((mSettings.has(SETTING_FLAGS)) ? (U32)mSettings[SETTING_FLAGS].asInteger() : 0);
flags |= flag;
if (flags)
mSettings[SETTING_FLAGS] = LLSD::Integer(flags);
else
mSettings.erase(SETTING_FLAGS);
mSettingFlags |= flag;
setLLSDDirty();
}
inline void clearFlag(U32 flag)
{
U32 flags((mSettings.has(SETTING_FLAGS)) ? (U32)mSettings[SETTING_FLAGS].asInteger() : 0);
flags &= ~flag;
if (flags)
mSettings[SETTING_FLAGS] = LLSD::Integer(flags);
else
mSettings.erase(SETTING_FLAGS);
mSettingFlags &= ~flag;
setLLSDDirty();
}
virtual void replaceSettings(LLSD settings)
@ -183,14 +170,41 @@ public:
setDirtyFlag(true);
mReplaced = true;
mSettings = settings;
loadValuesFromLLSD();
}
virtual LLSD getSettings() const;
virtual void replaceSettings(const ptr_t& other)
{
mBlendedFactor = 0.0;
setDirtyFlag(true);
mReplaced = true;
mSettingFlags = other->getFlags();
mSettingName = other->getName();
mSettingId = other->getId();
mAssetId = other->getAssetId();
setLLSDDirty();
}
void setSettings(LLSD settings)
{
setDirtyFlag(true);
mSettings = settings;
loadValuesFromLLSD();
}
// if you are using getSettings to edit them, call setSettings(settings),
// replaceSettings(settings) or loadValuesFromLLSD() afterwards
virtual LLSD& getSettings();
virtual void setLLSDDirty()
{
mLLSDDirty = true;
}
//---------------------------------------------------------------------
//
inline void setLLSD(const std::string &name, const LLSD &value)
{
saveValuesIfNeeded();
mSettings[name] = value;
mDirty = true;
if (name != SETTING_ASSETID)
@ -202,8 +216,9 @@ public:
setLLSD(name, value);
}
inline LLSD getValue(const std::string &name, const LLSD &deflt = LLSD()) const
inline LLSD getValue(const std::string &name, const LLSD &deflt = LLSD())
{
saveValuesIfNeeded();
if (!mSettings.has(name))
return deflt;
return mSettings[name];
@ -259,11 +274,11 @@ public:
(const_cast<LLSettingsBase *>(this))->updateSettings();
}
virtual void blend(const ptr_t &end, BlendFactor blendf) = 0;
virtual void blend(ptr_t &end, BlendFactor blendf) = 0;
virtual bool validate();
virtual ptr_t buildDerivedClone() const = 0;
virtual ptr_t buildDerivedClone() = 0;
class Validator
{
@ -310,17 +325,24 @@ public:
inline void setAssetId(LLUUID value)
{ // note that this skips setLLSD
mSettings[SETTING_ASSETID] = value;
mAssetId = value;
mLLSDDirty = true;
}
inline void clearAssetId()
{
if (mSettings.has(SETTING_ASSETID))
mSettings.erase(SETTING_ASSETID);
mAssetId.setNull();
mLLSDDirty = true;
}
// Calculate any custom settings that may need to be cached.
virtual void updateSettings() { mDirty = false; mReplaced = false; }
LLSD cloneSettings();
static void lerpVector2(LLVector2& a, const LLVector2& b, F32 mix);
static void lerpVector3(LLVector3& a, const LLVector3& b, F32 mix);
static void lerpColor(LLColor3& a, const LLColor3& b, F32 mix);
protected:
LLSettingsBase();
@ -331,7 +353,7 @@ protected:
typedef std::set<std::string> stringset_t;
// combining settings objects. Customize for specific setting types
virtual void lerpSettings(const LLSettingsBase &other, BlendFactor mix);
virtual void lerpSettings(LLSettingsBase &other, BlendFactor mix);
// combining settings maps where it can based on mix rate
// @settings initial value (mix==0)
@ -339,8 +361,8 @@ protected:
// @defaults list of default values for legacy fields and (re)setting shaders
// @mix from 0 to 1, ratio or rate of transition from initial 'settings' to 'other'
// return interpolated and combined LLSD map
LLSD interpolateSDMap(const LLSD &settings, const LLSD &other, const parammapping_t& defaults, BlendFactor mix) const;
LLSD interpolateSDValue(const std::string& name, const LLSD &value, const LLSD &other, const parammapping_t& defaults, BlendFactor mix, const stringset_t& slerps) const;
static LLSD interpolateSDMap(const LLSD &settings, const LLSD &other, const parammapping_t& defaults, BlendFactor mix, const stringset_t& skip, const stringset_t& slerps);
static LLSD interpolateSDValue(const std::string& name, const LLSD &value, const LLSD &other, const parammapping_t& defaults, BlendFactor mix, const stringset_t& skip, const stringset_t& slerps);
/// when lerping between settings, some may require special handling.
/// Get a list of these key to be skipped by the default settings lerp.
@ -353,32 +375,40 @@ protected:
virtual validation_list_t getValidationList() const = 0;
// Apply any settings that need special handling.
virtual void applySpecial(void *, bool force = false) { };
// Apply settings.
virtual void applyToUniforms(void *) { };
virtual void applySpecial(void*, bool force = false) { };
virtual parammapping_t getParameterMap() const { return parammapping_t(); }
LLSD mSettings;
LLSD cloneSettings() const;
inline void setBlendFactor(BlendFactor blendfactor)
{
mBlendedFactor = blendfactor;
}
void replaceWith(LLSettingsBase::ptr_t other)
virtual void replaceWith(const LLSettingsBase::ptr_t other)
{
replaceSettings(other->cloneSettings());
replaceSettings(other);
setBlendFactor(other->getBlendFactor());
}
virtual void loadValuesFromLLSD();
virtual void saveValuesToLLSD();
void saveValuesIfNeeded();
LLUUID mAssetId;
LLUUID mSettingId;
std::string mSettingName;
U32 mSettingFlags;
private:
bool mLLSDDirty;
bool mDirty;
bool mReplaced; // super dirty!
LLSD combineSDMaps(const LLSD &first, const LLSD &other) const;
static LLSD combineSDMaps(const LLSD &first, const LLSD &other);
LLSD mSettings;
BlendFactor mBlendedFactor;
};

View File

@ -124,33 +124,38 @@ static const F32 DEFAULT_MULTISLIDER_INCREMENT(0.005f);
//=========================================================================
LLSettingsDay::LLSettingsDay(const LLSD &data) :
LLSettingsBase(data),
mInitialized(false)
mInitialized(false),
mDaySettings(LLSD::emptyMap())
{
mDayTracks.resize(TRACK_MAX);
loadValuesFromLLSD();
}
LLSettingsDay::LLSettingsDay() :
LLSettingsBase(),
mInitialized(false)
mInitialized(false),
mDaySettings(LLSD::emptyMap())
{
mDayTracks.resize(TRACK_MAX);
replaceSettings(defaults());
}
//=========================================================================
LLSD LLSettingsDay::getSettings() const
LLSD& LLSettingsDay::getSettings()
{
LLSD settings(LLSD::emptyMap());
mDaySettings = LLSD::emptyMap();
LLSD& settings = LLSettingsBase::getSettings();
if (mSettings.has(SETTING_NAME))
settings[SETTING_NAME] = mSettings[SETTING_NAME];
if (settings.has(SETTING_NAME))
mDaySettings[SETTING_NAME] = settings[SETTING_NAME];
if (mSettings.has(SETTING_ID))
settings[SETTING_ID] = mSettings[SETTING_ID];
if (settings.has(SETTING_ID))
mDaySettings[SETTING_ID] = settings[SETTING_ID];
if (mSettings.has(SETTING_ASSETID))
settings[SETTING_ASSETID] = mSettings[SETTING_ASSETID];
if (settings.has(SETTING_ASSETID))
mDaySettings[SETTING_ASSETID] = settings[SETTING_ASSETID];
settings[SETTING_TYPE] = getSettingsType();
mDaySettings[SETTING_TYPE] = getSettingsType();
std::map<std::string, LLSettingsBase::ptr_t> in_use;
@ -174,7 +179,7 @@ LLSD LLSettingsDay::getSettings() const
}
tracks.append(trackout);
}
settings[SETTING_TRACKS] = tracks;
mDaySettings[SETTING_TRACKS] = tracks;
LLSD frames(LLSD::emptyMap());
for (std::map<std::string, LLSettingsBase::ptr_t>::iterator itFrame = in_use.begin(); itFrame != in_use.end(); ++itFrame)
@ -184,9 +189,15 @@ LLSD LLSettingsDay::getSettings() const
frames[(*itFrame).first] = framesettings;
}
settings[SETTING_FRAMES] = frames;
mDaySettings[SETTING_FRAMES] = frames;
return settings;
return mDaySettings;
}
void LLSettingsDay::setLLSDDirty()
{
mDaySettings = LLSD::emptyMap();
LLSettingsBase::setLLSDDirty();
}
bool LLSettingsDay::initialize(bool validate_frames)
@ -392,6 +403,8 @@ bool LLSettingsDay::initialize(bool validate_frames)
mSettings[SETTING_ASSETID] = assetid;
}
loadValuesFromLLSD();
mInitialized = true;
return true;
}
@ -449,7 +462,7 @@ LLSD LLSettingsDay::defaults()
return dfltsetting;
}
void LLSettingsDay::blend(const LLSettingsBase::ptr_t &other, F64 mix)
void LLSettingsDay::blend(LLSettingsBase::ptr_t &other, F64 mix)
{
LL_ERRS("DAYCYCLE") << "Day cycles are not blendable!" << LL_ENDL;
}

View File

@ -81,9 +81,10 @@ public:
bool initialize(bool validate_frames = false);
virtual ptr_t buildClone() const = 0;
virtual ptr_t buildDeepCloneAndUncompress() const = 0;
virtual LLSD getSettings() const SETTINGS_OVERRIDE;
virtual ptr_t buildClone() = 0;
virtual ptr_t buildDeepCloneAndUncompress() = 0;
virtual LLSD& getSettings() SETTINGS_OVERRIDE;
virtual void setLLSDDirty() override;
virtual LLSettingsType::type_e getSettingsTypeValue() const SETTINGS_OVERRIDE { return LLSettingsType::ST_DAYCYCLE; }
@ -91,7 +92,7 @@ public:
virtual std::string getSettingsType() const SETTINGS_OVERRIDE { return std::string("daycycle"); }
// Settings status
virtual void blend(const LLSettingsBase::ptr_t &other, F64 mix) SETTINGS_OVERRIDE;
virtual void blend(LLSettingsBase::ptr_t &other, F64 mix) SETTINGS_OVERRIDE;
static LLSD defaults();
@ -127,7 +128,7 @@ public:
virtual validation_list_t getValidationList() const SETTINGS_OVERRIDE;
static validation_list_t validationList();
virtual LLSettingsBase::ptr_t buildDerivedClone() const SETTINGS_OVERRIDE { return buildClone(); }
virtual LLSettingsBase::ptr_t buildDerivedClone() SETTINGS_OVERRIDE { return buildClone(); }
LLSettingsBase::TrackPosition getUpperBoundFrame(S32 track, const LLSettingsBase::TrackPosition& keyframe);
LLSettingsBase::TrackPosition getLowerBoundFrame(S32 track, const LLSettingsBase::TrackPosition& keyframe);
@ -143,6 +144,7 @@ protected:
private:
CycleList_t mDayTracks;
LLSD mDaySettings;
LLSettingsBase::Seconds mLastUpdateTime;

File diff suppressed because it is too large Load Diff

View File

@ -111,20 +111,24 @@ public:
LLSettingsSky(const LLSD &data);
virtual ~LLSettingsSky() { };
virtual ptr_t buildClone() const = 0;
virtual ptr_t buildClone() = 0;
//---------------------------------------------------------------------
virtual std::string getSettingsType() const SETTINGS_OVERRIDE { return std::string("sky"); }
virtual LLSettingsType::type_e getSettingsTypeValue() const SETTINGS_OVERRIDE { return LLSettingsType::ST_SKY; }
// Settings status
virtual void blend(const LLSettingsBase::ptr_t &end, F64 blendf) SETTINGS_OVERRIDE;
virtual void blend(LLSettingsBase::ptr_t &end, F64 blendf) SETTINGS_OVERRIDE;
virtual void replaceSettings(LLSD settings) SETTINGS_OVERRIDE;
virtual void replaceSettings(const LLSettingsBase::ptr_t& other_sky) override;
void replaceWithSky(LLSettingsSky::ptr_t pother);
void replaceWithSky(const LLSettingsSky::ptr_t& pother);
static LLSD defaults(const LLSettingsBase::TrackPosition& position = 0.0f);
void loadValuesFromLLSD() override;
void saveValuesToLLSD() override;
F32 getPlanetRadius() const;
F32 getSkyBottomRadius() const;
F32 getSkyTopRadius() const;
@ -306,7 +310,7 @@ public:
LLColor3 getSunlightColorClamped() const;
LLColor3 getAmbientColorClamped() const;
virtual LLSettingsBase::ptr_t buildDerivedClone() const SETTINGS_OVERRIDE { return buildClone(); }
virtual LLSettingsBase::ptr_t buildDerivedClone() SETTINGS_OVERRIDE { return buildClone(); }
static LLUUID GetDefaultAssetId();
static LLUUID GetDefaultSunTextureId();
@ -348,6 +352,12 @@ protected:
virtual stringset_t getSlerpKeys() const SETTINGS_OVERRIDE;
virtual stringset_t getSkipInterpolateKeys() const SETTINGS_OVERRIDE;
LLUUID mSunTextureId;
LLUUID mMoonTextureId;
LLUUID mCloudTextureId;
LLUUID mBloomTextureId;
LLUUID mRainbowTextureId;
LLUUID mHaloTextureId;
LLUUID mNextSunTextureId;
LLUUID mNextMoonTextureId;
LLUUID mNextCloudTextureId;
@ -355,17 +365,64 @@ protected:
LLUUID mNextRainbowTextureId;
LLUUID mNextHaloTextureId;
bool mCanAutoAdjust;
LLQuaternion mSunRotation;
LLQuaternion mMoonRotation;
LLColor3 mSunlightColor;
LLColor3 mGlow;
F32 mReflectionProbeAmbiance;
F32 mSunScale;
F32 mStarBrightness;
F32 mMoonBrightness;
F32 mMoonScale;
F32 mMaxY;
F32 mGamma;
F32 mCloudVariance;
F32 mCloudShadow;
F32 mCloudScale;
LLVector2 mScrollRate;
LLColor3 mCloudPosDensity1;
LLColor3 mCloudPosDensity2;
LLColor3 mCloudColor;
LLSD mAbsorptionConfigs;
LLSD mMieConfigs;
LLSD mRayleighConfigs;
F32 mSunArcRadians;
F32 mSkyTopRadius;
F32 mSkyBottomRadius;
F32 mSkyMoistureLevel;
F32 mSkyDropletRadius;
F32 mSkyIceLevel;
F32 mPlanetRadius;
F32 mHazeHorizon;
F32 mHazeDensity;
F32 mDistanceMultiplier;
F32 mDensityMultiplier;
LLColor3 mBlueHorizon;
LLColor3 mBlueDensity;
LLColor3 mAmbientColor;
bool mHasLegacyHaze;
bool mLegacyHazeHorizon;
bool mLegacyHazeDensity;
bool mLegacyDistanceMultiplier;
bool mLegacyDensityMultiplier;
bool mLegacyBlueHorizon;
bool mLegacyBlueDensity;
bool mLegacyAmbientColor;
private:
static LLSD rayleighConfigDefault();
static LLSD absorptionConfigDefault();
static LLSD mieConfigDefault();
LLColor3 getColor(const std::string& key, const LLColor3& default_value) const;
F32 getFloat(const std::string& key, F32 default_value) const;
LLColor3 getColor(const std::string& key, const LLColor3& default_value);
F32 getFloat(const std::string& key, F32 default_value);
void calculateHeavenlyBodyPositions() const;
void calculateLightSettings() const;
void clampColor(LLColor3& color, F32 gamma, const F32 scale = 1.0f) const;
static void clampColor(LLColor3& color, F32 gamma, const F32 scale = 1.0f);
mutable LLVector3 mSunDirection;
mutable LLVector3 mMoonDirection;

View File

@ -68,14 +68,18 @@ static const LLUUID DEFAULT_OPAQUE_WATER_TEXTURE("43c32285-d658-1793-c123-bf8631
//=========================================================================
LLSettingsWater::LLSettingsWater(const LLSD &data) :
LLSettingsBase(data),
mNextNormalMapID()
mNextNormalMapID(),
mNextTransparentTextureID()
{
loadValuesFromLLSD();
}
LLSettingsWater::LLSettingsWater() :
LLSettingsBase(),
mNextNormalMapID()
mNextNormalMapID(),
mNextTransparentTextureID()
{
replaceSettings(defaults());
}
//=========================================================================
@ -109,6 +113,53 @@ LLSD LLSettingsWater::defaults(const LLSettingsBase::TrackPosition& position)
return dfltsetting;
}
void LLSettingsWater::loadValuesFromLLSD()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
LLSettingsBase::loadValuesFromLLSD();
LLSD& settings = getSettings();
mBlurMultiplier = (F32)settings[SETTING_BLUR_MULTIPLIER].asReal();
mWaterFogColor = LLColor3(settings[SETTING_FOG_COLOR]);
mWaterFogDensity = (F32)settings[SETTING_FOG_DENSITY].asReal();
mFogMod = (F32)settings[SETTING_FOG_MOD].asReal();
mFresnelOffset = (F32)settings[SETTING_FRESNEL_OFFSET].asReal();
mFresnelScale = (F32)settings[SETTING_FRESNEL_SCALE].asReal();
mNormalScale = LLVector3(settings[SETTING_NORMAL_SCALE]);
mScaleAbove = (F32)settings[SETTING_SCALE_ABOVE].asReal();
mScaleBelow = (F32)settings[SETTING_SCALE_BELOW].asReal();
mWave1Dir = LLVector2(settings[SETTING_WAVE1_DIR]);
mWave2Dir = LLVector2(settings[SETTING_WAVE2_DIR]);
mNormalMapID = getNormalMapID();
mTransparentTextureID = getTransparentTextureID();
}
void LLSettingsWater::saveValuesToLLSD()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
LLSettingsBase::saveValuesToLLSD();
LLSD & settings = getSettings();
settings[SETTING_BLUR_MULTIPLIER] = LLSD::Real(mBlurMultiplier);
settings[SETTING_FOG_COLOR] = mWaterFogColor.getValue();
settings[SETTING_FOG_DENSITY] = LLSD::Real(mWaterFogDensity);
settings[SETTING_FOG_MOD] = LLSD::Real(mFogMod);
settings[SETTING_FRESNEL_OFFSET] = LLSD::Real(mFresnelOffset);
settings[SETTING_FRESNEL_SCALE] = LLSD::Real(mFresnelScale);
settings[SETTING_NORMAL_SCALE] = mNormalScale.getValue();
settings[SETTING_SCALE_ABOVE] = LLSD::Real(mScaleAbove);
settings[SETTING_SCALE_BELOW] = LLSD::Real(mScaleBelow);
settings[SETTING_WAVE1_DIR] = mWave1Dir.getValue();
settings[SETTING_WAVE2_DIR] = mWave2Dir.getValue();
settings[SETTING_NORMAL_MAP] = mNormalMapID;
settings[SETTING_TRANSPARENT_TEXTURE] = mTransparentTextureID;
}
LLSD LLSettingsWater::translateLegacySettings(LLSD legacy)
{
bool converted_something(false);
@ -180,13 +231,30 @@ LLSD LLSettingsWater::translateLegacySettings(LLSD legacy)
return newsettings;
}
void LLSettingsWater::blend(const LLSettingsBase::ptr_t &end, F64 blendf)
void LLSettingsWater::blend(LLSettingsBase::ptr_t &end, F64 blendf)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
LLSettingsWater::ptr_t other = PTR_NAMESPACE::static_pointer_cast<LLSettingsWater>(end);
if (other)
{
LLSD blenddata = interpolateSDMap(mSettings, other->mSettings, other->getParameterMap(), blendf);
replaceSettings(blenddata);
mSettingFlags |= other->mSettingFlags;
mBlurMultiplier = lerp(mBlurMultiplier, other->mBlurMultiplier, (F32)blendf);
lerpColor(mWaterFogColor, other->mWaterFogColor, (F32)blendf);
mWaterFogDensity = lerp(mWaterFogDensity, other->mWaterFogDensity, (F32)blendf);
mFogMod = lerp(mFogMod, other->mFogMod, (F32)blendf);
mFresnelOffset = lerp(mFresnelOffset, other->mFresnelOffset, (F32)blendf);
mFresnelScale = lerp(mFresnelScale, other->mFresnelScale, (F32)blendf);
lerpVector3(mNormalScale, other->mNormalScale, (F32)blendf);
mScaleAbove = lerp(mScaleAbove, other->mScaleAbove, (F32)blendf);
mScaleBelow = lerp(mScaleBelow, other->mScaleBelow, (F32)blendf);
lerpVector2(mWave1Dir, other->mWave1Dir, (F32)blendf);
lerpVector2(mWave2Dir, other->mWave2Dir, (F32)blendf);
setDirtyFlag(true);
setReplaced();
setLLSDDirty();
mNextNormalMapID = other->getNormalMapID();
mNextTransparentTextureID = other->getTransparentTextureID();
}
@ -204,7 +272,34 @@ void LLSettingsWater::replaceSettings(LLSD settings)
mNextTransparentTextureID.setNull();
}
void LLSettingsWater::replaceWithWater(LLSettingsWater::ptr_t other)
void LLSettingsWater::replaceSettings(const LLSettingsBase::ptr_t& other_water)
{
LLSettingsBase::replaceSettings(other_water);
llassert(getSettingsType() == other_water->getSettingsType());
LLSettingsWater::ptr_t other = PTR_NAMESPACE::dynamic_pointer_cast<LLSettingsWater>(other_water);
mBlurMultiplier = other->mBlurMultiplier;
mWaterFogColor = other->mWaterFogColor;
mWaterFogDensity = other->mWaterFogDensity;
mFogMod = other->mFogMod;
mFresnelOffset = other->mFresnelOffset;
mFresnelScale = other->mFresnelScale;
mNormalScale = other->mNormalScale;
mScaleAbove = other->mScaleAbove;
mScaleBelow = other->mScaleBelow;
mWave1Dir = other->mWave1Dir;
mWave2Dir = other->mWave2Dir;
mNormalMapID = other->mNormalMapID;
mTransparentTextureID = other->mTransparentTextureID;
mNextNormalMapID.setNull();
mNextTransparentTextureID.setNull();
}
void LLSettingsWater::replaceWithWater(const LLSettingsWater::ptr_t& other)
{
replaceWith(other);

View File

@ -55,151 +55,181 @@ public:
LLSettingsWater(const LLSD &data);
virtual ~LLSettingsWater() { };
virtual ptr_t buildClone() const = 0;
virtual ptr_t buildClone() = 0;
//---------------------------------------------------------------------
virtual std::string getSettingsType() const SETTINGS_OVERRIDE { return std::string("water"); }
virtual LLSettingsType::type_e getSettingsTypeValue() const SETTINGS_OVERRIDE { return LLSettingsType::ST_WATER; }
// Settings status
virtual void blend(const LLSettingsBase::ptr_t &end, F64 blendf) SETTINGS_OVERRIDE;
virtual void blend(LLSettingsBase::ptr_t &end, F64 blendf) SETTINGS_OVERRIDE;
virtual void replaceSettings(LLSD settings) SETTINGS_OVERRIDE;
void replaceWithWater(LLSettingsWater::ptr_t other);
virtual void replaceSettings(const LLSettingsBase::ptr_t& other_water) override;
void replaceWithWater(const LLSettingsWater::ptr_t& other);
static LLSD defaults(const LLSettingsBase::TrackPosition& position = 0.0f);
void loadValuesFromLLSD() override;
void saveValuesToLLSD() override;
//---------------------------------------------------------------------
F32 getBlurMultiplier() const
{
return (F32)mSettings[SETTING_BLUR_MULTIPLIER].asReal();
return mBlurMultiplier;
}
void setBlurMultiplier(F32 val)
{
setValue(SETTING_BLUR_MULTIPLIER, val);
mBlurMultiplier = val;
setDirtyFlag(true);
setLLSDDirty();
}
LLColor3 getWaterFogColor() const
{
return LLColor3(mSettings[SETTING_FOG_COLOR]);
return mWaterFogColor;
}
void setWaterFogColor(LLColor3 val)
{
setValue(SETTING_FOG_COLOR, val);
mWaterFogColor = val;
setDirtyFlag(true);
setLLSDDirty();
}
F32 getWaterFogDensity() const
{
return (F32)mSettings[SETTING_FOG_DENSITY].asReal();
return mWaterFogDensity;
}
F32 getModifiedWaterFogDensity(bool underwater) const;
void setWaterFogDensity(F32 val)
{
setValue(SETTING_FOG_DENSITY, val);
mWaterFogDensity = val;
setDirtyFlag(true);
setLLSDDirty();
}
F32 getFogMod() const
{
return (F32)mSettings[SETTING_FOG_MOD].asReal();
return mFogMod;
}
void setFogMod(F32 val)
{
setValue(SETTING_FOG_MOD, val);
mFogMod = val;
setDirtyFlag(true);
setLLSDDirty();
}
F32 getFresnelOffset() const
{
return (F32)mSettings[SETTING_FRESNEL_OFFSET].asReal();
return mFresnelOffset;
}
void setFresnelOffset(F32 val)
{
setValue(SETTING_FRESNEL_OFFSET, val);
mFresnelOffset = val;
setDirtyFlag(true);
setLLSDDirty();
}
F32 getFresnelScale() const
{
return (F32)mSettings[SETTING_FRESNEL_SCALE].asReal();
return mFresnelScale;
}
void setFresnelScale(F32 val)
{
setValue(SETTING_FRESNEL_SCALE, val);
mFresnelScale = val;
setDirtyFlag(true);
setLLSDDirty();
}
LLUUID getTransparentTextureID() const
{
return mSettings[SETTING_TRANSPARENT_TEXTURE].asUUID();
return mTransparentTextureID;
}
void setTransparentTextureID(LLUUID val)
{
setValue(SETTING_TRANSPARENT_TEXTURE, val);
mTransparentTextureID = val;
setDirtyFlag(true);
setLLSDDirty();
}
LLUUID getNormalMapID() const
{
return mSettings[SETTING_NORMAL_MAP].asUUID();
return mNormalMapID;
}
void setNormalMapID(LLUUID val)
{
setValue(SETTING_NORMAL_MAP, val);
mNormalMapID = val;
setDirtyFlag(true);
setLLSDDirty();
}
LLVector3 getNormalScale() const
{
return LLVector3(mSettings[SETTING_NORMAL_SCALE]);
return mNormalScale;
}
void setNormalScale(LLVector3 val)
{
setValue(SETTING_NORMAL_SCALE, val);
mNormalScale = val;
setDirtyFlag(true);
setLLSDDirty();
}
F32 getScaleAbove() const
{
return (F32)mSettings[SETTING_SCALE_ABOVE].asReal();
return mScaleAbove;
}
void setScaleAbove(F32 val)
{
setValue(SETTING_SCALE_ABOVE, val);
mScaleAbove = val;
setDirtyFlag(true);
setLLSDDirty();
}
F32 getScaleBelow() const
{
return (F32)mSettings[SETTING_SCALE_BELOW].asReal();
return mScaleBelow;
}
void setScaleBelow(F32 val)
{
setValue(SETTING_SCALE_BELOW, val);
mScaleBelow = val;
setDirtyFlag(true);
setLLSDDirty();
}
LLVector2 getWave1Dir() const
{
return LLVector2(mSettings[SETTING_WAVE1_DIR]);
return mWave1Dir;
}
void setWave1Dir(LLVector2 val)
{
setValue(SETTING_WAVE1_DIR, val);
mWave1Dir = val;
setDirtyFlag(true);
setLLSDDirty();
}
LLVector2 getWave2Dir() const
{
return LLVector2(mSettings[SETTING_WAVE2_DIR]);
return mWave2Dir;
}
void setWave2Dir(LLVector2 val)
{
setValue(SETTING_WAVE2_DIR, val);
mWave2Dir = val;
setDirtyFlag(true);
setLLSDDirty();
}
//-------------------------------------------
@ -218,7 +248,7 @@ public:
static LLSD translateLegacySettings(LLSD legacy);
virtual LLSettingsBase::ptr_t buildDerivedClone() const SETTINGS_OVERRIDE { return buildClone(); }
virtual LLSettingsBase::ptr_t buildDerivedClone() SETTINGS_OVERRIDE { return buildClone(); }
static LLUUID GetDefaultAssetId();
static LLUUID GetDefaultWaterNormalAssetId();
@ -241,9 +271,22 @@ protected:
LLSettingsWater();
LLUUID mTransparentTextureID;
LLUUID mNormalMapID;
LLUUID mNextTransparentTextureID;
LLUUID mNextNormalMapID;
F32 mBlurMultiplier;
LLColor3 mWaterFogColor;
F32 mWaterFogDensity;
F32 mFogMod;
F32 mFresnelOffset;
F32 mFresnelScale;
LLVector3 mNormalScale;
F32 mScaleAbove;
F32 mScaleBelow;
LLVector2 mWave1Dir;
LLVector2 mWave2Dir;
};
#endif

View File

@ -66,6 +66,10 @@ public:
const LLJointRiggingInfo& operator[](S32 i) const { return mRigInfoPtr[i]; };
bool needsUpdate() { return mNeedsUpdate; }
void setNeedsUpdate(bool val) { mNeedsUpdate = val; }
LLJointRiggingInfo* begin() { return mRigInfoPtr; }
LLJointRiggingInfo* end() { return mRigInfoPtr + mSize; }
private:
// Not implemented
LLJointRiggingInfoTab& operator=(const LLJointRiggingInfoTab& src);

View File

@ -38,8 +38,7 @@
#include "v4color.h"
#if LL_WINDOWS
# define WIN32_LEAN_AND_MEAN
# include <winsock2.h> // for htonl
# include "llwin32headers.h" // for htonl
#elif LL_LINUX
# include <netinet/in.h>
#elif LL_DARWIN

View File

@ -2710,7 +2710,7 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
}
bool LLVolume::isMeshAssetLoaded()
bool LLVolume::isMeshAssetLoaded() const
{
return mIsMeshAssetLoaded;
}
@ -2733,7 +2733,7 @@ void LLVolume::setMeshAssetUnavaliable(bool unavaliable)
}
}
bool LLVolume::isMeshAssetUnavaliable()
bool LLVolume::isMeshAssetUnavaliable() const
{
return mIsMeshAssetUnavaliable;
}
@ -3730,6 +3730,207 @@ S32 LLVolume::getNumTriangles(S32* vcount) const
return triangle_count;
}
void LLVolumeFace::generateSilhouetteEdge(const LLVolume* volume, std::vector<S32>& edge) const
{
llassert(edge.empty()); // edge is supposed to be a scratch array
if (volume->isMeshAssetLoaded()) { return; }
if (mTypeMask & CAP_MASK)
{
// Logic copied from LLVolumeFace::createCap - indicates a face created via
// createUnCutCubeCap.
if (!(mTypeMask & HOLLOW_MASK) &&
!(mTypeMask & OPEN_MASK) &&
((volume->getParams().getPathParams().getBegin()==0.0f)&&
(volume->getParams().getPathParams().getEnd()==1.0f))&&
(volume->getParams().getProfileParams().getCurveType()==LL_PCODE_PROFILE_SQUARE &&
volume->getParams().getPathParams().getCurveType()==LL_PCODE_PATH_LINE)
)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfgse - CAP_MASK");
const LLAlignedArray<LLVector4a,64>& profile = volume->getProfile().mProfile;
S32 grid_size = (profile.size()-1)/4;
edge.resize(mNumIndices);
llassert(edge.size() == 6*grid_size*grid_size);
S32 cur_edge = 0;
for(S32 gx = 0;gx<grid_size;gx++)
{
for(S32 gy = 0;gy<grid_size;gy++)
{
if (mTypeMask & TOP_MASK)
{
S32 edge_value = grid_size * 2 * gy + gx * 2;
if (gx > 0)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1; // Mark face to higlight it
}
if (gy < grid_size - 1)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
edge[cur_edge++] = edge_value;
if (gx < grid_size - 1)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
if (gy > 0)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
edge[cur_edge++] = edge_value;
}
else
{
S32 edge_value = grid_size * 2 * gy + gx * 2;
if (gy > 0)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
if (gx < grid_size - 1)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
edge[cur_edge++] = edge_value;
if (gy < grid_size - 1)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
if (gx > 0)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
edge[cur_edge++] = edge_value;
}
}
}
}
}
else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK))
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfgse - END_MASK or SIDE_MASK");
edge.resize(mNumIndices);
llassert(edge.size() == 6*(mNumS-1)*(mNumT-1));
S32 cur_edge = 0;
const bool flat_face = mTypeMask & FLAT_MASK;
for (S32 t = 0; t < (mNumT-1); t++)
{
for (S32 s = 0; s < (mNumS-1); s++)
{
// bottom left/top right neighbor face
edge[cur_edge++] = (mNumS-1)*2*t+s*2+1;
if (t < mNumT-2)
{ // top right/top left neighbor face
edge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1;
}
else if (mNumT <= 3 || volume->getPath().isOpen())
{ // no neighbor
edge[cur_edge++] = -1;
}
else
{ // wrap on T
edge[cur_edge++] = s*2+1;
}
if (s > 0)
{ // top left/bottom left neighbor face
edge[cur_edge++] = (mNumS-1)*2*t+s*2-1;
}
else if (flat_face || volume->getProfile().isOpen())
{ // no neighbor
edge[cur_edge++] = -1;
}
else
{ // wrap on S
edge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1;
}
if (t > 0)
{ // bottom left/bottom right neighbor face
edge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2;
}
else if (mNumT <= 3 || volume->getPath().isOpen())
{ // no neighbor
edge[cur_edge++] = -1;
}
else
{ // wrap on T
edge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2;
}
if (s < mNumS-2)
{ // bottom right/top right neighbor face
edge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2;
}
else if (flat_face || volume->getProfile().isOpen())
{ // no neighbor
edge[cur_edge++] = -1;
}
else
{ // wrap on S
edge[cur_edge++] = (mNumS-1)*2*t;
}
// top right/bottom left neighbor face
edge[cur_edge++] = (mNumS-1)*2*t+s*2;
}
}
}
else
{
LL_ERRS() << "Unknown/uninitialized face type!" << LL_ENDL;
}
}
//-----------------------------------------------------------------------------
// generateSilhouetteVertices()
@ -3761,6 +3962,13 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
}
S32 cur_index = 0;
// Scratch array for per-face silhouette edge information. This also has a
// lot of dev-only debug information that we might not care about anymore.
// (see DEBUG_SILHOUETTE_EDGE_MAP)
// *TODO: Consider removing the debug associated with
// DEBUG_SILHOUETTE_EDGE_MAP, and remove its associated computational
// overhead in generateSilhouetteEdge.
std::vector<S32> edge;
//for each face
for (face_list_t::iterator iter = mVolumeFaces.begin();
iter != mVolumeFaces.end(); ++iter)
@ -3768,7 +3976,16 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
LLVolumeFace& face = *iter;
if (!(face_mask & (0x1 << cur_index++)) ||
face.mNumIndices == 0 || face.mEdge.empty())
face.mNumIndices == 0)
{
continue;
}
// Attempt to generate "edge" info for this silhouette, which is used
// for some prims. If the edge array remains empty, then this
// silhouette generation method is not supported for this face.
edge.clear();
face.generateSilhouetteEdge(this, edge);
if (edge.empty())
{
continue;
}
@ -3782,7 +3999,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
{
for (S32 k = 0; k < 3; k++)
{
S32 index = face.mEdge[j * 3 + k];
S32 index = edge[j * 3 + k];
if (index == -1)
{
@ -3834,7 +4051,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
//for each edge
for (S32 k = 0; k < 3; k++) {
S32 nIndex = face.mEdge[j*3+k];
S32 nIndex = edge[j*3+k];
if (nIndex <= -1) {
continue;
}
@ -3949,7 +4166,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
// *FIX IF NEEDED: this does not deal with neighboring degenerate faces
for (S32 k = 0; k < 3; k++)
{
S32 index = face.mEdge[j*3+k];
S32 index = edge[j*3+k];
if (index != -1)
{
fFacing[j] = fFacing[index];
@ -3961,10 +4178,10 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
//for each edge
for (S32 k = 0; k < 3; k++) {
S32 index = face.mEdge[j*3+k];
S32 index = edge[j*3+k];
if (index != -1 && fFacing[index] == (AWAY | TOWARDS)) {
//our neighbor is degenerate, make him face our direction
fFacing[face.mEdge[j*3+k]] = fFacing[j];
fFacing[edge[j*3+k]] = fFacing[j];
continue;
}
@ -5775,30 +5992,16 @@ bool LLVolumeFace::createUnCutCubeCap(LLVolume* volume, bool partial_build)
if (!partial_build)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfcuccm - generate indices");
resizeIndices(grid_size*grid_size*6);
if (!volume->isMeshAssetLoaded())
{
S32 size = grid_size * grid_size * 6;
try
{
mEdge.resize(size);
}
catch (std::bad_alloc&)
{
LL_WARNS("LLVOLUME") << "Resize of mEdge to " << size << " failed" << LL_ENDL;
return false;
}
}
U16* out = mIndices;
S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0};
int cur_edge = 0;
for(S32 gx = 0;gx<grid_size;gx++)
{
for(S32 gy = 0;gy<grid_size;gy++)
{
if (mTypeMask & TOP_MASK)
@ -5808,47 +6011,6 @@ bool LLVolumeFace::createUnCutCubeCap(LLVolume* volume, bool partial_build)
*out++ = ((gy*(grid_size+1))+gx+idxs[i]);
}
S32 edge_value = grid_size * 2 * gy + gx * 2;
if (gx > 0)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1; // Mark face to higlight it
}
if (gy < grid_size - 1)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
mEdge[cur_edge++] = edge_value;
if (gx < grid_size - 1)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
if (gy > 0)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
mEdge[cur_edge++] = edge_value;
}
else
{
@ -5856,48 +6018,6 @@ bool LLVolumeFace::createUnCutCubeCap(LLVolume* volume, bool partial_build)
{
*out++ = ((gy*(grid_size+1))+gx+idxs[i]);
}
S32 edge_value = grid_size * 2 * gy + gx * 2;
if (gy > 0)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
if (gx < grid_size - 1)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
mEdge[cur_edge++] = edge_value;
if (gy < grid_size - 1)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
if (gx > 0)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
mEdge[cur_edge++] = edge_value;
}
}
}
@ -6377,6 +6497,8 @@ void LLVolumeFace::createTangents()
void LLVolumeFace::resizeVertices(S32 num_verts)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
ll_aligned_free<64>(mPositions);
//DO NOT free mNormals and mTexCoords as they are part of mPositions buffer
ll_aligned_free_16(mTangents);
@ -6499,6 +6621,8 @@ void LLVolumeFace::allocateJointIndices(S32 num_verts)
void LLVolumeFace::resizeIndices(S32 num_indices)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
ll_aligned_free_16(mIndices);
llassert(num_indices % 3 == 0);
@ -6591,19 +6715,6 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build)
{
resizeVertices(num_vertices);
resizeIndices(num_indices);
if (!volume->isMeshAssetLoaded())
{
try
{
mEdge.resize(num_indices);
}
catch (std::bad_alloc&)
{
LL_WARNS("LLVOLUME") << "Resize of mEdge to " << num_indices << " failed" << LL_ENDL;
return false;
}
}
}
LL_CHECK_MEMORY
@ -6618,6 +6729,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build)
bool test = (mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2;
// Copy the vertices into the array
{ LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfcs - copy verts");
for (t = mBeginT; t < end_t; t++)
{
tt = path_data[t].mTexT;
@ -6702,6 +6814,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build)
cur_vertex++;
}
}
}
LL_CHECK_MEMORY
mCenter->clear();
@ -6755,11 +6868,11 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build)
mCenter->mul(0.5f);
S32 cur_index = 0;
S32 cur_edge = 0;
bool flat_face = mTypeMask & FLAT_MASK;
if (!partial_build)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfcs - generate indices");
// Now we generate the indices.
for (t = 0; t < (mNumT-1); t++)
{
@ -6771,64 +6884,6 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build)
mIndices[cur_index++] = s + mNumS*t; //bottom left
mIndices[cur_index++] = s+1 + mNumS*t; //bottom right
mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right
// bottom left/top right neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1;
if (t < mNumT-2)
{ // top right/top left neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1;
}
else if (mNumT <= 3 || volume->getPath().isOpen())
{ // no neighbor
mEdge[cur_edge++] = -1;
}
else
{ // wrap on T
mEdge[cur_edge++] = s*2+1;
}
if (s > 0)
{ // top left/bottom left neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1;
}
else if (flat_face || volume->getProfile().isOpen())
{ // no neighbor
mEdge[cur_edge++] = -1;
}
else
{ // wrap on S
mEdge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1;
}
if (t > 0)
{ // bottom left/bottom right neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2;
}
else if (mNumT <= 3 || volume->getPath().isOpen())
{ // no neighbor
mEdge[cur_edge++] = -1;
}
else
{ // wrap on T
mEdge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2;
}
if (s < mNumS-2)
{ // bottom right/top right neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2;
}
else if (flat_face || volume->getProfile().isOpen())
{ // no neighbor
mEdge[cur_edge++] = -1;
}
else
{ // wrap on S
mEdge[cur_edge++] = (mNumS-1)*2*t;
}
// top right/bottom left neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*t+s*2;
}
}
}

View File

@ -918,6 +918,15 @@ public:
// Get a reference to the octree, which may be null
const LLVolumeOctree* getOctree() const;
// Part of silhouette generation (used by selection outlines)
// Populates the provided edge array with numbers corresponding to
// *partial* logic of whether a particular index should be rendered
// as a silhouette edge. -1 indicates the index should be rendered as a
// silhouette edge. See generateSilhouetteVertices for the full logic.
// Silhouette edges can only be generated for some types of prims. If a
// silhouette edge cannot be generated, the edge array will be left empty.
void generateSilhouetteEdge(const LLVolume* volume, std::vector<S32>& edge) const;
enum
{
SINGLE_MASK = 0x0001,
@ -963,8 +972,6 @@ public:
// indexes for mPositions/mNormals/mTexCoords
U16* mIndices;
std::vector<S32> mEdge;
//list of skin weights for rigged volumes
// format is mWeights[vertex_index].mV[influence] = <joint_index>.<weight>
// mWeights.size() should be empty or match mVertices.size()
@ -1113,9 +1120,9 @@ private:
public:
virtual void setMeshAssetLoaded(bool loaded);
virtual bool isMeshAssetLoaded();
virtual bool isMeshAssetLoaded() const;
virtual void setMeshAssetUnavaliable(bool unavaliable);
virtual bool isMeshAssetUnavaliable();
virtual bool isMeshAssetUnavaliable() const;
protected:
bool mUnique;

View File

@ -31,8 +31,7 @@
#include "llerror.h"
#if LL_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <llwin32headers.h>
#else
#include <netdb.h>
#include <netinet/in.h> // ntonl()

View File

@ -30,7 +30,7 @@
#define LL_LLIOPIPE_H
#include <boost/intrusive_ptr.hpp>
#include "llwin32headerslean.h"
#include "llwin32headers.h"
#include "apr_poll.h"
#include "llsd.h"

View File

@ -38,7 +38,7 @@
*/
#include "lliopipe.h"
#include "llwin32headerslean.h"
#include "llwin32headers.h"
#include "apr_pools.h"
#include "apr_network_io.h"
#include "llchainio.h"

View File

@ -28,7 +28,6 @@
#include "llmail.h"
// APR on Windows needs full windows headers
#include "llwin32headers.h"
#include <string>
#include <sstream>

View File

@ -32,7 +32,7 @@
#include <stdexcept>
#if LL_WINDOWS
#include "llwin32headerslean.h"
#include "llwin32headers.h"
#else
#include <sys/types.h>
#include <sys/socket.h>

View File

@ -48,7 +48,7 @@ LLPluginProcessParentOwner::~LLPluginProcessParentOwner()
bool LLPluginProcessParent::sUseReadThread = false;
apr_pollset_t *LLPluginProcessParent::sPollSet = NULL;
bool LLPluginProcessParent::sPollsetNeedsRebuild = false;
LLCoros::Mutex *LLPluginProcessParent::sInstancesMutex;
LLCoros::Mutex *LLPluginProcessParent::sInstancesMutex = nullptr;
LLPluginProcessParent::mapInstances_t LLPluginProcessParent::sInstances;
LLThread *LLPluginProcessParent::sReadThread = NULL;
@ -155,6 +155,12 @@ LLPluginProcessParent::ptr_t LLPluginProcessParent::create(LLPluginProcessParent
/*static*/
void LLPluginProcessParent::shutdown()
{
if (!sInstancesMutex)
{
// setup was not complete, skip shutdown
return;
}
LLCoros::LockType lock(*sInstancesMutex);
mapInstances_t::iterator it;

View File

@ -7,7 +7,6 @@ include(LLCommon)
include(LLCoreHttp)
include(LLPhysicsExtensions)
include(LLPrimitive)
include(GLH)
include(GLM)
include(TinyGLTF)
@ -70,7 +69,7 @@ target_link_libraries(llprimitive
llrender
llphysicsextensions_impl
ll::colladadom
ll::glh_linear
ll::glm
)
#add unit tests

View File

@ -51,7 +51,8 @@
#include "llsdserialize.h"
#include "lljoint.h"
#include "glh/glh_linear.h"
#include "glm/mat4x4.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "llmatrix4a.h"
#include <boost/regex.hpp>
@ -1114,19 +1115,17 @@ bool LLDAELoader::OpenFile(const std::string& filename)
if (skin)
{
domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement());
if (geom)
if (domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement()))
{
domMesh* mesh = geom->getMesh();
if (mesh)
if (domMesh* mesh = geom->getMesh())
{
std::vector< LLPointer< LLModel > >::iterator i = mModelsMap[mesh].begin();
while (i != mModelsMap[mesh].end())
dae_model_map::const_iterator it = mModelsMap.find(mesh);
if (it != mModelsMap.end())
{
LLPointer<LLModel> mdl = *i;
LLDAELoader::processDomModel(mdl, &dae, root, mesh, skin);
i++;
for (const LLPointer<LLModel>& model : it->second)
{
LLDAELoader::processDomModel(model, &dae, root, mesh, skin);
}
}
}
}
@ -1218,9 +1217,9 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
mesh_scale *= normalized_transformation;
normalized_transformation = mesh_scale;
glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix);
inv_mat = inv_mat.inverse();
LLMatrix4 inverse_normalized_transformation(inv_mat.m);
glm::mat4 inv_mat = glm::make_mat4((F32*)normalized_transformation.mMatrix);
inv_mat = glm::inverse(inv_mat);
LLMatrix4 inverse_normalized_transformation(glm::value_ptr(inv_mat));
domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix();
@ -1296,6 +1295,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
}
}
else
{
//Has one or more skeletons
for (std::vector<domInstance_controller::domSkeleton*>::iterator skel_it = skeletons.begin();
skel_it != skeletons.end(); ++skel_it)
@ -1380,6 +1380,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
}
}//got skeleton?
}
}
domSkin::domJoints* joints = skin->getJoints();
@ -1680,7 +1681,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
materials[model->mMaterialList[i]] = LLImportMaterial();
}
mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials));
stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
stretch_extents(model, transformation);
}
}
@ -2073,21 +2074,14 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da
mTransform.condition();
}
domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element);
if (instance_geo)
if (domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element))
{
domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement());
if (geo)
if (domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement()))
{
domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID())));
if (mesh)
if (domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID()))))
{
std::vector< LLPointer< LLModel > >::iterator i = mModelsMap[mesh].begin();
while (i != mModelsMap[mesh].end())
for (LLModel* model : mModelsMap.find(mesh)->second)
{
LLModel* model = *i;
LLMatrix4 transformation = mTransform;
if (mTransform.determinant() < 0)
@ -2158,8 +2152,7 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da
}
mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials));
stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
i++;
stretch_extents(model, transformation);
}
}
}

View File

@ -51,7 +51,6 @@
#include "llsdserialize.h"
#include "lljoint.h"
#include "glh/glh_linear.h"
#include "llmatrix4a.h"
#include <boost/regex.hpp>

View File

@ -91,19 +91,15 @@ std::string LLModel::getStatusString(U32 status)
}
void LLModel::offsetMesh( const LLVector3& pivotPoint )
void LLModel::offsetMesh(const LLVector3& pivotPoint)
{
LLVector4a pivot( pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ] );
LLVector4a pivot(pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ]);
for (std::vector<LLVolumeFace>::iterator faceIt = mVolumeFaces.begin(); faceIt != mVolumeFaces.end(); )
for (LLVolumeFace& face : mVolumeFaces)
{
std::vector<LLVolumeFace>:: iterator currentFaceIt = faceIt++;
LLVolumeFace& face = *currentFaceIt;
LLVector4a *pos = (LLVector4a*) face.mPositions;
for (S32 i=0; i<face.mNumVertices; ++i )
for (S32 i = 0; i < face.mNumVertices; ++i)
{
pos[i].add( pivot );
face.mPositions[i].add(pivot);
}
}
}
@ -338,7 +334,7 @@ void LLModel::normalizeVolumeFaces()
}
}
void LLModel::getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out)
void LLModel::getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out) const
{
scale_out = mNormalizedScale;
translation_out = mNormalizedTranslation;
@ -1547,6 +1543,13 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin)
mLockScaleIfJointPosition = false;
}
// combine mBindShapeMatrix and mInvBindMatrix into mBindPoseMatrix
mBindPoseMatrix.resize(mInvBindMatrix.size());
for (U32 i = 0; i < mInvBindMatrix.size(); ++i)
{
matMul(mBindShapeMatrix, mInvBindMatrix[i], mBindPoseMatrix[i]);
}
updateHash();
}

View File

@ -56,12 +56,15 @@ public:
LLUUID mMeshID;
std::vector<std::string> mJointNames;
mutable std::vector<S32> mJointNums;
typedef std::vector<LLMatrix4a, boost::alignment::aligned_allocator<LLMatrix4a, 16>> matrix_list_t;
typedef std::vector<LLMatrix4a> matrix_list_t;
matrix_list_t mInvBindMatrix;
// bones/joints position overrides
matrix_list_t mAlternateBindMatrix;
// cached multiply of mBindShapeMatrix and mInvBindMatrix
matrix_list_t mBindPoseMatrix;
LL_ALIGN_16(LLMatrix4a mBindShapeMatrix);
float mPelvisOffset;
@ -203,7 +206,7 @@ public:
void remapVolumeFaces();
void optimizeVolumeFaces();
void offsetMesh( const LLVector3& pivotPoint );
void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out);
void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out) const;
LLVector3 getTransformedCenter(const LLMatrix4& mat);
//reorder face list based on mMaterialList in this and reference so

View File

@ -31,13 +31,12 @@
#include "lljoint.h"
#include "llcallbacklist.h"
#include "glh/glh_linear.h"
#include "llmatrix4a.h"
#include <boost/bind.hpp>
std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList;
void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, bool& first_transform)
static void stretch_extents(const LLModel* model, const LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, bool& first_transform)
{
LLVector4a box[] =
{
@ -85,19 +84,19 @@ void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4
}
}
void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, bool& first_transform)
void LLModelLoader::stretch_extents(const LLModel* model, const LLMatrix4& mat)
{
LLVector4a mina, maxa;
LLMatrix4a mata;
mata.loadu(mat);
mina.load3(min.mV);
maxa.load3(max.mV);
mina.load3(mExtents[0].mV);
maxa.load3(mExtents[1].mV);
stretch_extents(model, mata, mina, maxa, first_transform);
::stretch_extents(model, mata, mina, maxa, mFirstTransform);
min.set(mina.getF32ptr());
max.set(maxa.getF32ptr());
mExtents[0].set(mina.getF32ptr());
mExtents[1].set(maxa.getF32ptr());
}
//-----------------------------------------------------------------------------
@ -292,14 +291,7 @@ bool LLModelLoader::loadFromSLM(const std::string& filename)
{
if (idx >= model[lod].size())
{
if (model[lod].size())
{
instance_list[i].mLOD[lod] = model[lod][0];
}
else
{
instance_list[i].mLOD[lod] = NULL;
}
instance_list[i].mLOD[lod] = model[lod].front();
continue;
}
@ -342,7 +334,7 @@ bool LLModelLoader::loadFromSLM(const std::string& filename)
{
LLModelInstance& cur_instance = instance_list[i];
mScene[cur_instance.mTransform].push_back(cur_instance);
stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform);
stretch_extents(cur_instance.mModel, cur_instance.mTransform);
}
setLoadState( DONE );

View File

@ -34,13 +34,13 @@
class LLJoint;
typedef std::map<std::string, LLMatrix4> JointTransformMap;
typedef std::map<std::string, LLMatrix4>::iterator JointTransformMapIt;
typedef std::map<std::string, std::string> JointMap;
typedef std::deque<std::string> JointNameSet;
typedef std::map<std::string, LLMatrix4> JointTransformMap;
typedef std::map<std::string, LLMatrix4>::iterator JointTransformMapIt;
typedef std::map<std::string, std::string> JointMap;
typedef std::deque<std::string> JointNameSet;
const S32 SLM_SUPPORTED_VERSION = 3;
const S32 NUM_LOD = 4;
const S32 NUM_LOD = 4;
const U32 LEGACY_RIG_OK = 0;
const U32 LEGACY_RIG_FLAG_TOO_MANY_JOINTS = 1;
@ -50,32 +50,32 @@ class LLModelLoader : public LLThread
{
public:
typedef std::map<std::string, LLImportMaterial> material_map;
typedef std::vector<LLPointer<LLModel > > model_list;
typedef std::vector<LLModelInstance> model_instance_list;
typedef std::map<LLMatrix4, model_instance_list > scene;
typedef std::map<std::string, LLImportMaterial> material_map;
typedef std::vector<LLPointer<LLModel>> model_list;
typedef std::vector<LLModelInstance> model_instance_list;
typedef std::map<LLMatrix4, model_instance_list> scene;
// Callback with loaded model data and loaded LoD
//
typedef boost::function<void (scene&,model_list&,S32,void*) > load_callback_t;
typedef boost::function<void (scene&, model_list&, S32, void*)> load_callback_t;
// Function to provide joint lookup by name
// (within preview avi skeleton, for example)
//
typedef boost::function<LLJoint* (const std::string&,void*) > joint_lookup_func_t;
typedef boost::function<LLJoint* (const std::string&, void*)> joint_lookup_func_t;
// Func to load and associate material with all it's textures,
// returned value is the number of textures loaded
// intentionally non-const so func can modify material to
// store platform-specific data
//
typedef boost::function<U32 (LLImportMaterial&,void*) > texture_load_func_t;
typedef boost::function<U32 (LLImportMaterial&, void*)> texture_load_func_t;
// Callback to inform client of state changes
// during loading process (errors will be reported
// as state changes here as well)
//
typedef boost::function<void (U32,void*) > state_callback_t;
typedef boost::function<void (U32, void*)> state_callback_t;
typedef enum
{
@ -136,7 +136,7 @@ public:
JointNameSet& jointsFromNodes,
JointMap& legalJointNamesMap,
U32 maxJointsPerMesh);
virtual ~LLModelLoader() ;
virtual ~LLModelLoader();
virtual void setNoNormalize() { mNoNormalize = true; }
virtual void setNoOptimize() { mNoOptimize = true; }
@ -156,13 +156,13 @@ public:
bool loadFromSLM(const std::string& filename);
void loadModelCallback();
void loadTextures() ; //called in the main thread.
void loadTextures() ; // called in the main thread.
void setLoadState(U32 state);
void stretch_extents(const LLModel* model, const LLMatrix4& mat);
S32 mNumOfFetchingTextures ; //updated in the main thread
bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread.
S32 mNumOfFetchingTextures ; // updated in the main thread
bool areTexturesReady() { return !mNumOfFetchingTextures; } // called in the main thread.
bool verifyCount( int expected, int result );
@ -212,10 +212,7 @@ protected:
LLSD mWarningsArray; // preview floater will pull logs from here
static std::list<LLModelLoader*> sActiveLoaderList;
static bool isAlive(LLModelLoader* loader) ;
static bool isAlive(LLModelLoader* loader);
};
class LLMatrix4a;
void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, bool& first_transform);
void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, bool& first_transform);
#endif // LL_LLMODELLOADER_H

View File

@ -17,6 +17,7 @@ set(llrender_SOURCE_FILES
llfontfreetype.cpp
llfontfreetypesvg.cpp
llfontgl.cpp
llfontvertexbuffer.cpp
llfontregistry.cpp
llgl.cpp
llglslshader.cpp
@ -43,6 +44,7 @@ set(llrender_HEADER_FILES
llcubemap.h
llcubemaparray.h
llfontgl.h
llfontvertexbuffer.h
llfontfreetype.h
llfontfreetypesvg.h
llfontbitmapcache.h

View File

@ -125,27 +125,25 @@ void LLCubeMapArray::allocate(U32 resolution, U32 components, U32 count, bool us
mImage->setHasMipMaps(use_mips);
bind(0);
U32 format = components == 4 ? GL_RGBA16F : GL_RGB16F;
U32 mip = 0;
free_cur_tex_image();
while (resolution >= 1)
U32 format = components == 4 ? GL_RGBA16F : GL_RGB16F;
U32 mip = 0;
U32 mip_resolution = resolution;
while (mip_resolution >= 1)
{
glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, format, resolution, resolution, count * 6, 0,
glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, format, mip_resolution, mip_resolution, count * 6, 0,
GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
if (!use_mips)
{
break;
}
resolution /= 2;
mip_resolution /= 2;
++mip;
}
alloc_tex_image(resolution * 6, resolution, format);
alloc_tex_image(resolution, resolution, format, count * 6);
mImage->setAddressMode(LLTexUnit::TAM_CLAMP);

View File

@ -117,7 +117,7 @@ bool LLFontBitmapCache::nextOpenPos(S32 width, S32& pos_x, S32& pos_y, EFontGlyp
}
// Make corresponding GL image.
mImageGLVec[bitmap_idx].push_back(new LLImageGL(image_raw, false));
mImageGLVec[bitmap_idx].push_back(new LLImageGL(image_raw, false, false));
LLImageGL* image_gl = getImageGL(bitmap_type, bitmap_num);
// Start at beginning of the new image.

View File

@ -270,10 +270,10 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
const LLFontGlyphInfo* next_glyph = NULL;
const S32 GLYPH_BATCH_SIZE = 30;
LLVector3 vertices[GLYPH_BATCH_SIZE * 4];
LLVector2 uvs[GLYPH_BATCH_SIZE * 4];
LLColor4U colors[GLYPH_BATCH_SIZE * 4];
static constexpr S32 GLYPH_BATCH_SIZE = 30;
static thread_local LLVector4a vertices[GLYPH_BATCH_SIZE * 6];
static thread_local LLVector2 uvs[GLYPH_BATCH_SIZE * 6];
static thread_local LLColor4U colors[GLYPH_BATCH_SIZE * 6];
LLColor4U text_color(color);
// Preserve the transparency to render fading emojis in fading text (e.g.
@ -305,9 +305,9 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
// otherwise the queued glyphs will be taken from wrong textures.
if (glyph_count > 0)
{
gGL.begin(LLRender::QUADS);
gGL.begin(LLRender::TRIANGLES);
{
gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 6);
}
gGL.end();
glyph_count = 0;
@ -338,9 +338,9 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
if (glyph_count >= GLYPH_BATCH_SIZE)
{
gGL.begin(LLRender::QUADS);
gGL.begin(LLRender::TRIANGLES);
{
gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 6);
}
gGL.end();
@ -376,9 +376,9 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
cur_render_y = cur_y;
}
gGL.begin(LLRender::QUADS);
gGL.begin(LLRender::TRIANGLES);
{
gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 6);
}
gGL.end();
@ -402,10 +402,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
if (draw_ellipses)
{
// recursively render ellipses at end of string
// we've already reserved enough room
gGL.pushUIMatrix();
static LLWString elipses_wstr(utf8string_to_wstring(std::string("...")));
render(elipses_wstr,
0,
@ -418,7 +416,6 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
right_x,
false,
use_color);
gGL.popUIMatrix();
}
gGL.popUIMatrix();
@ -504,6 +501,7 @@ F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max
F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars, bool no_padding) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;
F32 cur_x = 0;
@ -1227,31 +1225,42 @@ LLFontGL &LLFontGL::operator=(const LLFontGL &source)
return *this;
}
void LLFontGL::renderQuad(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const
void LLFontGL::renderTriangle(LLVector4a* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const
{
S32 index = 0;
vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mTop, 0.f);
uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
vertex_out[index].set(screen_rect.mRight, screen_rect.mTop, 0.f);
uv_out[index].set(uv_rect.mRight, uv_rect.mTop);
colors_out[index] = color;
index++;
vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mTop, 0.f);
uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop);
vertex_out[index].set(screen_rect.mLeft, screen_rect.mTop, 0.f);
uv_out[index].set(uv_rect.mLeft, uv_rect.mTop);
colors_out[index] = color;
index++;
vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 0.f);
uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
vertex_out[index].set(screen_rect.mLeft, screen_rect.mBottom, 0.f);
uv_out[index].set(uv_rect.mLeft, uv_rect.mBottom);
colors_out[index] = color;
index++;
vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mBottom, 0.f);
uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom);
vertex_out[index].set(screen_rect.mRight, screen_rect.mTop, 0.f);
uv_out[index].set(uv_rect.mRight, uv_rect.mTop);
colors_out[index] = color;
index++;
vertex_out[index].set(screen_rect.mLeft, screen_rect.mBottom, 0.f);
uv_out[index].set(uv_rect.mLeft, uv_rect.mBottom);
colors_out[index] = color;
index++;
vertex_out[index].set(screen_rect.mRight, screen_rect.mBottom, 0.f);
uv_out[index].set(uv_rect.mRight, uv_rect.mBottom);
colors_out[index] = color;
}
void LLFontGL::drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const
void LLFontGL::drawGlyph(S32& glyph_count, LLVector4a* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const
{
F32 slant_offset;
slant_offset = ((style & ITALIC) ? ( -mFontFreetype->getAscenderHeight() * 0.2f) : 0.f);
@ -1265,7 +1274,7 @@ void LLFontGL::drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_
LLRectf screen_rect_offset = screen_rect;
screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f);
renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, color, slant_offset);
renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect_offset, uv_rect, color, slant_offset);
glyph_count++;
}
}
@ -1296,10 +1305,10 @@ void LLFontGL::drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_
break;
}
renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, shadow_color, slant_offset);
renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect_offset, uv_rect, shadow_color, slant_offset);
glyph_count++;
}
renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset);
renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect, uv_rect, color, slant_offset);
glyph_count++;
}
else if (shadow == DROP_SHADOW)
@ -1308,14 +1317,14 @@ void LLFontGL::drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_
shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength);
LLRectf screen_rect_shadow = screen_rect;
screen_rect_shadow.translate(1.f, -1.f);
renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_shadow, uv_rect, shadow_color, slant_offset);
renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect_shadow, uv_rect, shadow_color, slant_offset);
glyph_count++;
renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset);
renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect, uv_rect, color, slant_offset);
glyph_count++;
}
else // normal rendering
{
renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset);
renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect, uv_rect, color, slant_offset);
glyph_count++;
}
}

View File

@ -238,8 +238,8 @@ private:
LLFontDescriptor mFontDescriptor;
LLPointer<LLFontFreetype> mFontFreetype;
void renderQuad(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const;
void drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const;
void renderTriangle(LLVector4a* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const;
void drawGlyph(S32& glyph_count, LLVector4a* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const;
// Registry holds all instantiated fonts.
static LLFontRegistry* sFontRegistry;

View File

@ -0,0 +1,233 @@
/**
* @file llfontvertexbuffer.cpp
* @brief Buffer storage for font rendering.
*
* $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 "linden_common.h"
#include "llfontvertexbuffer.h"
#include "llvertexbuffer.h"
bool LLFontVertexBuffer::sEnableBufferCollection = true;
LLFontVertexBuffer::LLFontVertexBuffer()
{
}
LLFontVertexBuffer::~LLFontVertexBuffer()
{
reset();
}
void LLFontVertexBuffer::reset()
{
// Todo: some form of debug only frequecy check&assert to see if this is happening too often.
// Regenerating this list is expensive
mBufferList.clear();
}
S32 LLFontVertexBuffer::render(
const LLFontGL* fontp,
const LLWString& text,
S32 begin_offset,
LLRect rect,
const LLColor4& color,
LLFontGL::HAlign halign, LLFontGL::VAlign valign,
U8 style,
LLFontGL::ShadowType shadow,
S32 max_chars, S32 max_pixels,
F32* right_x,
bool use_ellipses,
bool use_color)
{
LLRectf rect_float((F32)rect.mLeft, (F32)rect.mTop, (F32)rect.mRight, (F32)rect.mBottom);
return render(fontp, text, begin_offset, rect_float, color, halign, valign, style, shadow, max_chars, right_x, use_ellipses, use_color);
}
S32 LLFontVertexBuffer::render(
const LLFontGL* fontp,
const LLWString& text,
S32 begin_offset,
LLRectf rect,
const LLColor4& color,
LLFontGL::HAlign halign, LLFontGL::VAlign valign,
U8 style,
LLFontGL::ShadowType shadow,
S32 max_chars,
F32* right_x,
bool use_ellipses,
bool use_color)
{
F32 x = rect.mLeft;
F32 y = 0.f;
switch (valign)
{
case LLFontGL::TOP:
y = rect.mTop;
break;
case LLFontGL::VCENTER:
y = rect.getCenterY();
break;
case LLFontGL::BASELINE:
case LLFontGL::BOTTOM:
y = rect.mBottom;
break;
default:
y = rect.mBottom;
break;
}
return render(fontp, text, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, (S32)rect.getWidth(), right_x, use_ellipses, use_color);
}
S32 LLFontVertexBuffer::render(
const LLFontGL* fontp,
const LLWString& text,
S32 begin_offset,
F32 x, F32 y,
const LLColor4& color,
LLFontGL::HAlign halign, LLFontGL::VAlign valign,
U8 style,
LLFontGL::ShadowType shadow,
S32 max_chars , S32 max_pixels,
F32* right_x,
bool use_ellipses,
bool use_color )
{
if (!LLFontGL::sDisplayFont) //do not display texts
{
return static_cast<S32>(text.length());
}
if (!sEnableBufferCollection)
{
// For debug purposes and performance testing
return fontp->render(text, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
}
if (mBufferList.empty())
{
genBuffers(fontp, text, begin_offset, x, y, color, halign, valign,
style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
}
else if (mLastX != x
|| mLastY != y
|| mLastFont != fontp
|| mLastColor != color // alphas change often
|| mLastHalign != halign
|| mLastValign != valign
|| mLastOffset != begin_offset
|| mLastMaxChars != max_chars
|| mLastMaxPixels != max_pixels
|| mLastStyle != style
|| mLastShadow != shadow // ex: buttons change shadow state
|| mLastScaleX != LLFontGL::sScaleX
|| mLastScaleY != LLFontGL::sScaleY
|| mLastVertDPI != LLFontGL::sVertDPI
|| mLastHorizDPI != LLFontGL::sHorizDPI
|| mLastOrigin != LLFontGL::sCurOrigin)
{
genBuffers(fontp, text, begin_offset, x, y, color, halign, valign,
style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
}
else
{
renderBuffers();
if (right_x)
{
*right_x = mLastRightX;
}
}
return mChars;
}
void LLFontVertexBuffer::genBuffers(
const LLFontGL* fontp,
const LLWString& text,
S32 begin_offset,
F32 x, F32 y,
const LLColor4& color,
LLFontGL::HAlign halign, LLFontGL::VAlign valign,
U8 style, LLFontGL::ShadowType shadow,
S32 max_chars, S32 max_pixels,
F32* right_x,
bool use_ellipses,
bool use_color)
{
// todo: add a debug build assert if this triggers too often for to long?
mBufferList.clear();
gGL.beginList(&mBufferList);
mChars = fontp->render(text, begin_offset, x, y, color, halign, valign,
style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
gGL.endList();
mLastFont = fontp;
mLastOffset = begin_offset;
mLastMaxChars = max_chars;
mLastMaxPixels = max_pixels;
mLastX = x;
mLastY = y;
mLastColor = color;
mLastHalign = halign;
mLastValign = valign;
mLastStyle = style;
mLastShadow = shadow;
mLastScaleX = LLFontGL::sScaleX;
mLastScaleY = LLFontGL::sScaleY;
mLastVertDPI = LLFontGL::sVertDPI;
mLastHorizDPI = LLFontGL::sHorizDPI;
mLastOrigin = LLFontGL::sCurOrigin;
if (right_x)
{
mLastRightX = *right_x;
}
}
void LLFontVertexBuffer::renderBuffers()
{
gGL.flush(); // deliberately empty pending verts
gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
gGL.pushUIMatrix();
gGL.loadUIIdentity();
// Depth translation, so that floating text appears 'in-world'
// and is correctly occluded.
gGL.translatef(0.f, 0.f, LLFontGL::sCurDepth);
gGL.setSceneBlendType(LLRender::BT_ALPHA);
// Note: ellipses should technically be covered by push/load/translate of their own
// but it's more complexity, values do not change, skipping doesn't appear to break
// anything, so we can skip that until it proves to cause issues.
for (LLVertexBufferData& buffer : mBufferList)
{
buffer.draw();
}
gGL.popUIMatrix();
}

View File

@ -0,0 +1,125 @@
/**
* @file llfontgl.h
* @author Andrii Kleshchev
* @brief Buffer storage for font rendering.
*
* $LicenseInfo:firstyear=2001&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_LLFONTVERTEXBUFFER_H
#define LL_LLFONTVERTEXBUFFER_H
#include "llfontgl.h"
class LLVertexBufferData;
class LLFontVertexBuffer
{
public:
LLFontVertexBuffer();
~LLFontVertexBuffer();
void reset();
S32 render(const LLFontGL* fontp,
const LLWString& text,
S32 begin_offset,
LLRect rect,
const LLColor4& color,
LLFontGL::HAlign halign = LLFontGL::LEFT, LLFontGL::VAlign valign = LLFontGL::BASELINE,
U8 style = LLFontGL::NORMAL,
LLFontGL::ShadowType shadow = LLFontGL::NO_SHADOW,
S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX,
F32* right_x = NULL,
bool use_ellipses = false,
bool use_color = true);
S32 render(const LLFontGL* fontp,
const LLWString& text,
S32 begin_offset,
LLRectf rect,
const LLColor4& color,
LLFontGL::HAlign halign = LLFontGL::LEFT, LLFontGL::VAlign valign = LLFontGL::BASELINE,
U8 style = LLFontGL::NORMAL,
LLFontGL::ShadowType shadow = LLFontGL::NO_SHADOW,
S32 max_chars = S32_MAX,
F32* right_x = NULL,
bool use_ellipses = false,
bool use_color = true);
S32 render(const LLFontGL* fontp,
const LLWString& text,
S32 begin_offset,
F32 x, F32 y,
const LLColor4& color,
LLFontGL::HAlign halign = LLFontGL::LEFT, LLFontGL::VAlign valign = LLFontGL::BASELINE,
U8 style = LLFontGL::NORMAL,
LLFontGL::ShadowType shadow = LLFontGL::NO_SHADOW,
S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX,
F32* right_x = NULL,
bool use_ellipses = false,
bool use_color = true);
static void enableBufferCollection(bool enable) { sEnableBufferCollection = enable; }
private:
void genBuffers(const LLFontGL* fontp,
const LLWString& text,
S32 begin_offset,
F32 x, F32 y,
const LLColor4& color,
LLFontGL::HAlign halign, LLFontGL::VAlign valign,
U8 style,
LLFontGL::ShadowType shadow,
S32 max_chars, S32 max_pixels,
F32* right_x,
bool use_ellipses,
bool use_color);
void renderBuffers();
std::list<LLVertexBufferData> mBufferList;
S32 mChars = 0;
const LLFontGL *mLastFont = nullptr;
S32 mLastOffset = 0;
S32 mLastMaxChars = 0;
S32 mLastMaxPixels = 0;
F32 mLastX = 0.f;
F32 mLastY = 0.f;
LLColor4 mLastColor;
LLFontGL::HAlign mLastHalign = LLFontGL::LEFT;
LLFontGL::VAlign mLastValign = LLFontGL::BASELINE;
U8 mLastStyle = LLFontGL::NORMAL;
LLFontGL::ShadowType mLastShadow = LLFontGL::NO_SHADOW;
F32 mLastRightX = 0.f;
// LLFontGL's statics
F32 mLastScaleX = 1.f;
F32 mLastScaleY = 1.f;
F32 mLastVertDPI = 0.f;
F32 mLastHorizDPI = 0.f;
LLCoordGL mLastOrigin;
static bool sEnableBufferCollection;
};
#endif

View File

@ -50,6 +50,10 @@
#include "llglheaders.h"
#include "llglslshader.h"
#include "glm/glm.hpp"
#include <glm/gtc/matrix_access.hpp>
#include "glm/gtc/type_ptr.hpp"
#if LL_WINDOWS
#include "lldxhardware.h"
#endif
@ -1166,6 +1170,11 @@ bool LLGLManager::initGL()
mGLVendorShort = "INTEL";
mIsIntel = true;
}
else if (mGLVendor.find("APPLE") != std::string::npos)
{
mGLVendorShort = "APPLE";
mIsApple = true;
}
else
{
mGLVendorShort = "MISC";
@ -2694,7 +2703,7 @@ void parse_glsl_version(S32& major, S32& minor)
LLStringUtil::convertToS32(minor_str, minor);
}
LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& modelview, const glh::matrix4f& projection, bool apply)
LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glm::mat4& modelview, const glm::mat4& projection, bool apply)
{
mApply = apply;
@ -2721,13 +2730,12 @@ void LLGLUserClipPlane::disable()
void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d)
{
glh::matrix4f& P = mProjection;
glh::matrix4f& M = mModelview;
const glm::mat4& P = mProjection;
const glm::mat4& M = mModelview;
glh::matrix4f invtrans_MVP = (P * M).inverse().transpose();
glh::vec4f oplane(a,b,c,d);
glh::vec4f cplane;
invtrans_MVP.mult_matrix_vec(oplane, cplane);
glm::mat4 invtrans_MVP = glm::transpose(glm::inverse(P*M));
glm::vec4 oplane(a,b,c,d);
glm::vec4 cplane = invtrans_MVP * oplane;
cplane /= fabs(cplane[2]); // normalize such that depth is not scaled
cplane[3] -= 1;
@ -2735,13 +2743,13 @@ void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d)
if(cplane[2] < 0)
cplane *= -1;
glh::matrix4f suffix;
suffix.set_row(2, cplane);
glh::matrix4f newP = suffix * P;
glm::mat4 suffix;
suffix = glm::row(suffix, 2, cplane);
glm::mat4 newP = suffix * P;
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.pushMatrix();
gGL.loadMatrix(newP.m);
gGLObliqueProjectionInverse = LLMatrix4(newP.inverse().transpose().m);
gGL.loadMatrix(glm::value_ptr(newP));
gGLObliqueProjectionInverse = LLMatrix4(glm::value_ptr(glm::transpose(glm::inverse(newP))));
gGL.matrixMode(LLRender::MM_MODELVIEW);
}
@ -2754,7 +2762,7 @@ LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, G
: mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled)
{
stop_glerror();
LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
checkState();
if (!depth_enabled)
@ -2787,6 +2795,7 @@ LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, G
LLGLDepthTest::~LLGLDepthTest()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
checkState();
if (sDepthEnabled != mPrevDepthEnabled )
{
@ -2837,31 +2846,27 @@ void LLGLDepthTest::checkState()
LLGLSquashToFarClip::LLGLSquashToFarClip()
{
glh::matrix4f proj = get_current_projection();
glm::mat4 proj = get_current_projection();
setProjectionMatrix(proj, 0);
}
LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f& P, U32 layer)
LLGLSquashToFarClip::LLGLSquashToFarClip(const glm::mat4& P, U32 layer)
{
setProjectionMatrix(P, layer);
}
void LLGLSquashToFarClip::setProjectionMatrix(glh::matrix4f& projection, U32 layer)
void LLGLSquashToFarClip::setProjectionMatrix(glm::mat4 projection, U32 layer)
{
F32 depth = 0.99999f - 0.0001f * layer;
for (U32 i = 0; i < 4; i++)
{
projection.element(2, i) = projection.element(3, i) * depth;
}
glm::vec4 P_row_3 = glm::row(projection, 3) * depth;
projection = glm::row(projection, 2, P_row_3);
LLRender::eMatrixMode last_matrix_mode = gGL.getMatrixMode();
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.pushMatrix();
gGL.loadMatrix(projection.m);
gGL.loadMatrix(glm::value_ptr(projection));
gGL.matrixMode(last_matrix_mode);
}

View File

@ -43,7 +43,7 @@
#include "llinstancetracker.h"
#include "llglheaders.h"
#include "glh/glh_linear.h"
#include "glm/mat4x4.hpp"
extern bool gDebugGL;
extern bool gDebugSession;
@ -102,6 +102,7 @@ public:
bool mIsAMD;
bool mIsNVIDIA;
bool mIsIntel;
bool mIsApple = false;
// hints to the render pipe
U32 mDownScaleMethod = 0; // see settings.xml RenderDownScaleMethod
@ -317,7 +318,7 @@ class LLGLUserClipPlane
{
public:
LLGLUserClipPlane(const LLPlane& plane, const glh::matrix4f& modelview, const glh::matrix4f& projection, bool apply = true);
LLGLUserClipPlane(const LLPlane& plane, const glm::mat4& modelview, const glm::mat4& projection, bool apply = true);
~LLGLUserClipPlane();
void setPlane(F32 a, F32 b, F32 c, F32 d);
@ -326,8 +327,8 @@ public:
private:
bool mApply;
glh::matrix4f mProjection;
glh::matrix4f mModelview;
glm::mat4 mProjection;
glm::mat4 mModelview;
};
/*
@ -341,9 +342,9 @@ class LLGLSquashToFarClip
{
public:
LLGLSquashToFarClip();
LLGLSquashToFarClip(glh::matrix4f& projection, U32 layer = 0);
LLGLSquashToFarClip(const glm::mat4& projection, U32 layer = 0);
void setProjectionMatrix(glh::matrix4f& projection, U32 layer);
void setProjectionMatrix(glm::mat4 projection, U32 layer);
~LLGLSquashToFarClip();
};

View File

@ -46,7 +46,7 @@
// LL_WINDOWS
// windows gl headers depend on things like APIENTRY, so include windows.
#include "llwin32headerslean.h"
#include "llwin32headers.h"
//----------------------------------------------------------------------------
#include <GL/gl.h>

View File

@ -63,6 +63,7 @@ U64 LLGLSLShader::sTotalTimeElapsed = 0;
U32 LLGLSLShader::sTotalTrianglesDrawn = 0;
U64 LLGLSLShader::sTotalSamplesDrawn = 0;
U32 LLGLSLShader::sTotalBinds = 0;
boost::json::value LLGLSLShader::sDefaultStats;
//UI shader -- declared here so llui_libtest will link properly
LLGLSLShader gUIProgram;
@ -101,9 +102,9 @@ void LLGLSLShader::initProfile()
sTotalSamplesDrawn = 0;
sTotalBinds = 0;
for (std::set<LLGLSLShader*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
for (auto ptr : sInstances)
{
(*iter)->clearStats();
ptr->clearStats();
}
}
@ -117,45 +118,57 @@ struct LLGLSLShaderCompareTimeElapsed
};
//static
void LLGLSLShader::finishProfile(bool emit_report)
void LLGLSLShader::finishProfile(boost::json::value& statsv)
{
sProfileEnabled = false;
if (emit_report)
if (! statsv.is_null())
{
std::vector<LLGLSLShader*> sorted;
for (std::set<LLGLSLShader*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
{
sorted.push_back(*iter);
}
std::vector<LLGLSLShader*> sorted(sInstances.begin(), sInstances.end());
std::sort(sorted.begin(), sorted.end(), LLGLSLShaderCompareTimeElapsed());
auto& stats = statsv.as_object();
auto shadersit = stats.emplace("shaders", boost::json::array_kind).first;
auto& shaders = shadersit->value().as_array();
bool unbound = false;
for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter)
for (auto ptr : sorted)
{
(*iter)->dumpStats();
if ((*iter)->mBinds == 0)
if (ptr->mBinds == 0)
{
unbound = true;
}
else
{
auto& shaderit = shaders.emplace_back(boost::json::object_kind);
ptr->dumpStats(shaderit.as_object());
}
}
constexpr float mega = 1'000'000.f;
float totalTimeMs = sTotalTimeElapsed / mega;
LL_INFOS() << "-----------------------------------" << LL_ENDL;
LL_INFOS() << "Total rendering time: " << llformat("%.4f ms", sTotalTimeElapsed / 1000000.f) << LL_ENDL;
LL_INFOS() << "Total samples drawn: " << llformat("%.4f million", sTotalSamplesDrawn / 1000000.f) << LL_ENDL;
LL_INFOS() << "Total triangles drawn: " << llformat("%.3f million", sTotalTrianglesDrawn / 1000000.f) << LL_ENDL;
LL_INFOS() << "Total rendering time: " << llformat("%.4f ms", totalTimeMs) << LL_ENDL;
LL_INFOS() << "Total samples drawn: " << llformat("%.4f million", sTotalSamplesDrawn / mega) << LL_ENDL;
LL_INFOS() << "Total triangles drawn: " << llformat("%.3f million", sTotalTrianglesDrawn / mega) << LL_ENDL;
LL_INFOS() << "-----------------------------------" << LL_ENDL;
auto totalsit = stats.emplace("totals", boost::json::object_kind).first;
auto& totals = totalsit->value().as_object();
totals.emplace("time", totalTimeMs / 1000.0);
totals.emplace("binds", sTotalBinds);
totals.emplace("samples", sTotalSamplesDrawn);
totals.emplace("triangles", sTotalTrianglesDrawn);
auto unusedit = stats.emplace("unused", boost::json::array_kind).first;
auto& unused = unusedit->value().as_array();
if (unbound)
{
LL_INFOS() << "The following shaders were unused: " << LL_ENDL;
for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter)
for (auto ptr : sorted)
{
if ((*iter)->mBinds == 0)
if (ptr->mBinds == 0)
{
LL_INFOS() << (*iter)->mName << LL_ENDL;
LL_INFOS() << ptr->mName << LL_ENDL;
unused.emplace_back(ptr->mName);
}
}
}
@ -170,36 +183,43 @@ void LLGLSLShader::clearStats()
mBinds = 0;
}
void LLGLSLShader::dumpStats()
void LLGLSLShader::dumpStats(boost::json::object& stats)
{
if (mBinds > 0)
stats.emplace("name", mName);
auto filesit = stats.emplace("files", boost::json::array_kind).first;
auto& files = filesit->value().as_array();
LL_INFOS() << "=============================================" << LL_ENDL;
LL_INFOS() << mName << LL_ENDL;
for (U32 i = 0; i < mShaderFiles.size(); ++i)
{
LL_INFOS() << "=============================================" << LL_ENDL;
LL_INFOS() << mName << LL_ENDL;
for (U32 i = 0; i < mShaderFiles.size(); ++i)
{
LL_INFOS() << mShaderFiles[i].first << LL_ENDL;
}
LL_INFOS() << "=============================================" << LL_ENDL;
F32 ms = mTimeElapsed / 1000000.f;
F32 seconds = ms / 1000.f;
F32 pct_tris = (F32)mTrianglesDrawn / (F32)sTotalTrianglesDrawn * 100.f;
F32 tris_sec = (F32)(mTrianglesDrawn / 1000000.0);
tris_sec /= seconds;
F32 pct_samples = (F32)((F64)mSamplesDrawn / (F64)sTotalSamplesDrawn) * 100.f;
F32 samples_sec = (F32)(mSamplesDrawn / 1000000000.0);
samples_sec /= seconds;
F32 pct_binds = (F32)mBinds / (F32)sTotalBinds * 100.f;
LL_INFOS() << "Triangles Drawn: " << mTrianglesDrawn << " " << llformat("(%.2f pct of total, %.3f million/sec)", pct_tris, tris_sec) << LL_ENDL;
LL_INFOS() << "Binds: " << mBinds << " " << llformat("(%.2f pct of total)", pct_binds) << LL_ENDL;
LL_INFOS() << "SamplesDrawn: " << mSamplesDrawn << " " << llformat("(%.2f pct of total, %.3f billion/sec)", pct_samples, samples_sec) << LL_ENDL;
LL_INFOS() << "Time Elapsed: " << mTimeElapsed << " " << llformat("(%.2f pct of total, %.5f ms)\n", (F32)((F64)mTimeElapsed / (F64)sTotalTimeElapsed) * 100.f, ms) << LL_ENDL;
LL_INFOS() << mShaderFiles[i].first << LL_ENDL;
files.emplace_back(mShaderFiles[i].first);
}
LL_INFOS() << "=============================================" << LL_ENDL;
constexpr float mega = 1'000'000.f;
constexpr double giga = 1'000'000'000.0;
F32 ms = mTimeElapsed / mega;
F32 seconds = ms / 1000.f;
F32 pct_tris = (F32)mTrianglesDrawn / (F32)sTotalTrianglesDrawn * 100.f;
F32 tris_sec = (F32)(mTrianglesDrawn / mega);
tris_sec /= seconds;
F32 pct_samples = (F32)((F64)mSamplesDrawn / (F64)sTotalSamplesDrawn) * 100.f;
F32 samples_sec = (F32)(mSamplesDrawn / giga);
samples_sec /= seconds;
F32 pct_binds = (F32)mBinds / (F32)sTotalBinds * 100.f;
LL_INFOS() << "Triangles Drawn: " << mTrianglesDrawn << " " << llformat("(%.2f pct of total, %.3f million/sec)", pct_tris, tris_sec) << LL_ENDL;
LL_INFOS() << "Binds: " << mBinds << " " << llformat("(%.2f pct of total)", pct_binds) << LL_ENDL;
LL_INFOS() << "SamplesDrawn: " << mSamplesDrawn << " " << llformat("(%.2f pct of total, %.3f billion/sec)", pct_samples, samples_sec) << LL_ENDL;
LL_INFOS() << "Time Elapsed: " << mTimeElapsed << " " << llformat("(%.2f pct of total, %.5f ms)\n", (F32)((F64)mTimeElapsed / (F64)sTotalTimeElapsed) * 100.f, ms) << LL_ENDL;
stats.emplace("time", seconds);
stats.emplace("binds", mBinds);
stats.emplace("samples", mSamplesDrawn);
stats.emplace("triangles", mTrianglesDrawn);
}
//static
@ -1087,17 +1107,17 @@ void LLGLSLShader::unbind(void)
sCurBoundShaderPtr = NULL;
}
S32 LLGLSLShader::bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace)
S32 LLGLSLShader::bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
S32 channel = 0;
channel = getUniformLocation(uniform);
return bindTexture(channel, texture, mode, colorspace);
return bindTexture(channel, texture, mode);
}
S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace)
S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
@ -1113,7 +1133,6 @@ S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextu
if (uniform > -1)
{
gGL.getTexUnit(uniform)->bindFast(texture);
gGL.getTexUnit(uniform)->setTextureColorSpace(colorspace);
}
return uniform;
@ -1194,7 +1213,7 @@ S32 LLGLSLShader::getTextureChannel(S32 uniform) const
return mTexture[uniform];
}
S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
@ -1211,12 +1230,11 @@ S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTex
{
gGL.getTexUnit(index)->activate();
gGL.getTexUnit(index)->enable(mode);
gGL.getTexUnit(index)->setTextureColorSpace(space);
}
return index;
}
S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
@ -1229,7 +1247,7 @@ S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTe
S32 index = mTexture[uniform];
if (index != -1 && gGL.getTexUnit(index)->getCurrType() != LLTexUnit::TT_NONE)
{
if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode && gGL.getTexUnit(index)->getCurrColorSpace() != space)
if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode)
{
if (gDebugSession)
{
@ -1552,6 +1570,34 @@ void LLGLSLShader::uniform4fv(U32 index, U32 count, const GLfloat* v)
}
}
void LLGLSLShader::uniform4uiv(U32 index, U32 count, const GLuint* v)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
llassert(sCurBoundShaderPtr == this);
if (mProgramObject)
{
if (mUniform.size() <= index)
{
LL_WARNS_ONCE("Shader") << "Uniform index out of bounds. Size: " << (S32)mUniform.size() << " index: " << index << LL_ENDL;
llassert(false);
return;
}
if (mUniform[index] >= 0)
{
const auto& iter = mValue.find(mUniform[index]);
LLVector4 vec((F32)v[0], (F32)v[1], (F32)v[2], (F32)v[3]);
if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
glUniform4uiv(mUniform[index], count, v);
mValue[mUniform[index]] = vec;
}
}
}
}
void LLGLSLShader::uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
@ -1886,6 +1932,24 @@ void LLGLSLShader::uniform4fv(const LLStaticHashedString& uniform, U32 count, co
}
}
void LLGLSLShader::uniform4uiv(const LLStaticHashedString& uniform, U32 count, const GLuint* v)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
GLint location = getUniformLocation(uniform);
if (location >= 0)
{
LLVector4 vec((F32)v[0], (F32)v[1], (F32)v[2], (F32)v[3]);
const auto& iter = mValue.find(location);
if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
glUniform4uiv(location, count, v);
mValue[location] = vec;
}
}
}
void LLGLSLShader::uniformMatrix4fv(const LLStaticHashedString& uniform, U32 count, GLboolean transpose, const GLfloat* v)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;

View File

@ -30,6 +30,7 @@
#include "llgl.h"
#include "llrender.h"
#include "llstaticstringtable.h"
#include <boost/json.hpp>
#include <unordered_map>
class LLShaderFeatures
@ -169,14 +170,14 @@ public:
static U32 sMaxGLTFNodes;
static void initProfile();
static void finishProfile(bool emit_report = true);
static void finishProfile(boost::json::value& stats=sDefaultStats);
static void startProfile();
static void stopProfile();
void unload();
void clearStats();
void dumpStats();
void dumpStats(boost::json::object& stats);
// place query objects for profiling if profiling is enabled
// if for_runtime is true, will place timer query only whether or not profiling is enabled
@ -208,6 +209,7 @@ public:
void uniform2fv(U32 index, U32 count, const GLfloat* v);
void uniform3fv(U32 index, U32 count, const GLfloat* v);
void uniform4fv(U32 index, U32 count, const GLfloat* v);
void uniform4uiv(U32 index, U32 count, const GLuint* v);
void uniform2i(const LLStaticHashedString& uniform, GLint i, GLint j);
void uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v);
void uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v);
@ -223,6 +225,7 @@ public:
void uniform2fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v);
void uniform3fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v);
void uniform4fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v);
void uniform4uiv(const LLStaticHashedString& uniform, U32 count, const GLuint* v);
void uniformMatrix4fv(const LLStaticHashedString& uniform, U32 count, GLboolean transpose, const GLfloat* v);
void setMinimumAlpha(F32 minimum);
@ -239,6 +242,10 @@ public:
void clearPermutations();
void addPermutation(std::string name, std::string value);
void addPermutations(const std::map<std::string, std::string>& defines)
{
mDefines.insert(defines.begin(), defines.end());
}
void removePermutation(std::string name);
void addConstant(const LLGLSLShader::eShaderConsts shader_const);
@ -247,16 +254,16 @@ public:
//if given texture uniform is active in the shader,
//the corresponding channel will be active upon return
//returns channel texture is enabled in from [0-MAX)
S32 enableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR);
S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR);
S32 enableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
// get the texture channel of the given uniform, or -1 if uniform is not used as a texture
S32 getTextureChannel(S32 uniform) const;
// bindTexture returns the texture unit we've bound the texture to.
// You can reuse the return value to unbind a texture when required.
S32 bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR);
S32 bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR);
S32 bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
S32 bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
S32 bindTexture(const std::string& uniform, LLRenderTarget* texture, bool depth = false, LLTexUnit::eTextureFilterOptions mode = LLTexUnit::TFO_BILINEAR);
S32 bindTexture(S32 uniform, LLRenderTarget* texture, bool depth = false, LLTexUnit::eTextureFilterOptions mode = LLTexUnit::TFO_BILINEAR, U32 index = 0);
S32 unbindTexture(const std::string& uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
@ -357,6 +364,11 @@ public:
private:
void unloadInternal();
// This must be static because finishProfile() is called at least once
// within a __try block. If we default its stats parameter to a temporary
// json::value, that temporary must be destroyed when the stack is
// unwound, which __try forbids.
static boost::json::value sDefaultStats;
};
//UI shader (declared here so llui_libtest will link properly)

View File

@ -51,6 +51,7 @@ extern LL_COMMON_API bool on_main_thread();
//----------------------------------------------------------------------------
const F32 MIN_TEXTURE_LIFETIME = 10.f;
const F32 CONVERSION_SCRATCH_BUFFER_GL_VERSION = 3.29f;
//which power of 2 is i?
//assumes i is a power of 2 > 0
@ -67,12 +68,13 @@ static U64 sTextureBytes = 0;
// track a texture alloc on the currently bound texture.
// asserts that no currently tracked alloc exists
void LLImageGLMemory::alloc_tex_image(U32 width, U32 height, U32 pixformat)
void LLImageGLMemory::alloc_tex_image(U32 width, U32 height, U32 intformat, U32 count)
{
U32 texUnit = gGL.getCurrentTexUnitIndex();
llassert(texUnit == 0); // allocations should always be done on tex unit 0
U32 texName = gGL.getTexUnit(texUnit)->getCurrTexture();
U64 size = LLImageGL::dataFormatBytes(pixformat, width, height);
U64 size = LLImageGL::dataFormatBytes(intformat, width, height);
size *= count;
llassert(size >= 0);
@ -159,6 +161,7 @@ S32 LLImageGL::sMaxCategories = 1 ;
bool LLImageGL::sSkipAnalyzeAlpha;
U32 LLImageGL::sScratchPBO = 0;
U32 LLImageGL::sScratchPBOSize = 0;
U32* LLImageGL::sManualScratch = nullptr;
//------------------------
@ -261,6 +264,22 @@ void LLImageGL::initClass(LLWindow* window, S32 num_catagories, bool skip_analyz
}
}
void LLImageGL::allocateConversionBuffer()
{
if (gGLManager.mGLVersion < CONVERSION_SCRATCH_BUFFER_GL_VERSION)
{
try
{
sManualScratch = new U32[MAX_IMAGE_AREA];
}
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "Failed to allocate sManualScratch" << LL_ENDL;
}
}
}
//static
void LLImageGL::cleanupClass()
{
@ -272,6 +291,8 @@ void LLImageGL::cleanupClass()
sScratchPBO = 0;
sScratchPBOSize = 0;
}
delete[] sManualScratch;
}
@ -280,6 +301,15 @@ S32 LLImageGL::dataFormatBits(S32 dataformat)
{
switch (dataformat)
{
case GL_COMPRESSED_RED: return 8;
case GL_COMPRESSED_RG: return 16;
case GL_COMPRESSED_RGB: return 24;
case GL_COMPRESSED_SRGB: return 32;
case GL_COMPRESSED_RGBA: return 32;
case GL_COMPRESSED_SRGB_ALPHA: return 32;
case GL_COMPRESSED_LUMINANCE: return 8;
case GL_COMPRESSED_LUMINANCE_ALPHA: return 16;
case GL_COMPRESSED_ALPHA: return 8;
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 4;
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: return 4;
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 8;
@ -287,21 +317,35 @@ S32 LLImageGL::dataFormatBits(S32 dataformat)
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 8;
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return 8;
case GL_LUMINANCE: return 8;
case GL_LUMINANCE8: return 8;
case GL_ALPHA: return 8;
case GL_ALPHA8: return 8;
case GL_RED: return 8;
case GL_R8: return 8;
case GL_COLOR_INDEX: return 8;
case GL_LUMINANCE_ALPHA: return 16;
case GL_LUMINANCE8_ALPHA8: return 16;
case GL_RG: return 16;
case GL_RG8: return 16;
case GL_RGB: return 24;
case GL_SRGB: return 24;
case GL_RGB8: return 24;
case GL_RGBA: return 32;
case GL_RGBA8: return 32;
case GL_SRGB_ALPHA: return 32;
case GL_BGRA: return 32; // Used for QuickTime media textures on the Mac
case GL_DEPTH_COMPONENT: return 24;
case GL_DEPTH_COMPONENT24: return 24;
case GL_R16F: return 16;
case GL_RG16F: return 32;
case GL_RGB16F: return 48;
case GL_RGBA16F: return 64;
case GL_R32F: return 32;
case GL_RG32F: return 64;
case GL_RGB32F: return 96;
case GL_RGBA32F: return 128;
default:
LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL;
LL_ERRS() << "LLImageGL::Unknown format: " << std::hex << dataformat << std::dec << LL_ENDL;
return 0;
}
}
@ -344,13 +388,14 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat)
case GL_RED: return 1;
case GL_COLOR_INDEX: return 1;
case GL_LUMINANCE_ALPHA: return 2;
case GL_RG: return 2;
case GL_RGB: return 3;
case GL_SRGB: return 3;
case GL_RGBA: return 4;
case GL_SRGB_ALPHA: return 4;
case GL_BGRA: return 4; // Used for QuickTime media textures on the Mac
default:
LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL;
LL_ERRS() << "LLImageGL::Unknown format: " << std::hex << dataformat << std::dec << LL_ENDL;
return 0;
}
}
@ -411,29 +456,29 @@ bool LLImageGL::create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, b
//----------------------------------------------------------------------------
LLImageGL::LLImageGL(bool usemipmaps)
LLImageGL::LLImageGL(bool usemipmaps/* = true*/, bool allow_compression/* = true*/)
: mSaveData(0), mExternalTexture(false)
{
init(usemipmaps);
init(usemipmaps, allow_compression);
setSize(0, 0, 0);
sImageList.insert(this);
sCount++;
}
LLImageGL::LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps)
LLImageGL::LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps/* = true*/, bool allow_compression/* = true*/)
: mSaveData(0), mExternalTexture(false)
{
llassert( components <= 4 );
init(usemipmaps);
init(usemipmaps, allow_compression);
setSize(width, height, components);
sImageList.insert(this);
sCount++;
}
LLImageGL::LLImageGL(const LLImageRaw* imageraw, bool usemipmaps)
LLImageGL::LLImageGL(const LLImageRaw* imageraw, bool usemipmaps/* = true*/, bool allow_compression/* = true*/)
: mSaveData(0), mExternalTexture(false)
{
init(usemipmaps);
init(usemipmaps, allow_compression);
setSize(0, 0, 0);
sImageList.insert(this);
sCount++;
@ -450,7 +495,7 @@ LLImageGL::LLImageGL(
LLGLenum formatType,
LLTexUnit::eTextureAddressMode addressMode)
{
init(false);
init(false, true);
mTexName = texName;
mTarget = target;
mComponents = components;
@ -472,7 +517,7 @@ LLImageGL::~LLImageGL()
}
}
void LLImageGL::init(bool usemipmaps)
void LLImageGL::init(bool usemipmaps, bool allow_compression)
{
#if LL_IMAGEGL_THREAD_CHECK
mActiveThread = LLThread::currentID();
@ -502,7 +547,7 @@ void LLImageGL::init(bool usemipmaps)
mHeight = 0;
mCurrentDiscardLevel = -1;
mAllowCompression = true;
mAllowCompression = allow_compression;
mTarget = GL_TEXTURE_2D;
mBindTarget = LLTexUnit::TT_TEXTURE;
@ -1020,15 +1065,47 @@ void sub_image_lines(U32 target, S32 miplevel, S32 x_offset, S32 y_offset, S32 w
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
LL_PROFILE_ZONE_NUM(width);
LL_PROFILE_ZONE_NUM(height);
U32 components = LLImageGL::dataFormatComponents(pixformat);
U32 type_width = type_width_from_pixtype(pixtype);
const U32 line_width = data_width * components * type_width;
const U32 y_offset_end = y_offset + height;
for (U32 y_pos = y_offset; y_pos < y_offset_end; ++y_pos)
if (width == data_width && height % 32 == 0)
{
glTexSubImage2D(target, miplevel, x_offset, y_pos, width, 1, pixformat, pixtype, src);
src += line_width;
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("subimage - batched lines");
// full width, batch multiple lines at a time
// set batch size based on width
U32 batch_size = 32;
if (width > 1024)
{
batch_size = 8;
}
else if (width > 512)
{
batch_size = 16;
}
// full width texture, do 32 lines at a time
for (U32 y_pos = y_offset; y_pos < y_offset_end; y_pos += batch_size)
{
glTexSubImage2D(target, miplevel, x_offset, y_pos, width, batch_size, pixformat, pixtype, src);
src += line_width * batch_size;
}
}
else
{
// partial width or strange height
for (U32 y_pos = y_offset; y_pos < y_offset_end; y_pos += 1)
{
glTexSubImage2D(target, miplevel, x_offset, y_pos, width, 1, pixformat, pixtype, src);
src += line_width;
}
}
}
@ -1230,90 +1307,97 @@ void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures)
void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void* pixels, bool allow_compression)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
bool use_scratch = false;
U32* scratch = NULL;
if (LLRender::sGLCoreProfile)
{
if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE)
{ //GL_ALPHA is deprecated, convert to RGBA
if (pixels != nullptr)
{
use_scratch = true;
scratch = new(std::nothrow) U32[width * height];
if (!scratch)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
<< " bytes for a manual image W" << width << " H" << height << LL_ENDL;
}
U32 pixel_count = (U32)(width * height);
for (U32 i = 0; i < pixel_count; i++)
{
U8* pix = (U8*)&scratch[i];
pix[0] = pix[1] = pix[2] = 0;
pix[3] = ((U8*)pixels)[i];
}
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
if (gGLManager.mGLVersion >= CONVERSION_SCRATCH_BUFFER_GL_VERSION)
{
if (pixformat == GL_ALPHA)
{ //GL_ALPHA is deprecated, convert to RGBA
const GLint mask[] = { GL_ZERO, GL_ZERO, GL_ZERO, GL_RED };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask);
pixformat = GL_RED;
intformat = GL_R8;
}
pixformat = GL_RGBA;
intformat = GL_RGBA8;
if (pixformat == GL_LUMINANCE)
{ //GL_LUMINANCE is deprecated, convert to GL_RGBA
const GLint mask[] = { GL_RED, GL_RED, GL_RED, GL_ONE };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask);
pixformat = GL_RED;
intformat = GL_R8;
}
if (pixformat == GL_LUMINANCE_ALPHA)
{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
const GLint mask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask);
pixformat = GL_RG;
intformat = GL_RG8;
}
}
if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE)
{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
if (pixels != nullptr)
{
use_scratch = true;
scratch = new(std::nothrow) U32[width * height];
if (!scratch)
else
{
if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE)
{ //GL_ALPHA is deprecated, convert to RGBA
if (pixels != nullptr)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
<< " bytes for a manual image W" << width << " H" << height << LL_ENDL;
U32 pixel_count = (U32)(width * height);
for (U32 i = 0; i < pixel_count; i++)
{
U8* pix = (U8*)&sManualScratch[i];
pix[0] = pix[1] = pix[2] = 0;
pix[3] = ((U8*)pixels)[i];
}
pixels = sManualScratch;
}
U32 pixel_count = (U32)(width * height);
for (U32 i = 0; i < pixel_count; i++)
{
U8 lum = ((U8*)pixels)[i * 2 + 0];
U8 alpha = ((U8*)pixels)[i * 2 + 1];
U8* pix = (U8*)&scratch[i];
pix[0] = pix[1] = pix[2] = lum;
pix[3] = alpha;
}
pixformat = GL_RGBA;
intformat = GL_RGBA8;
}
pixformat = GL_RGBA;
intformat = GL_RGBA8;
}
if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE)
{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGB
if (pixels != nullptr)
{
use_scratch = true;
scratch = new(std::nothrow) U32[width * height];
if (!scratch)
if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE)
{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
if (pixels != nullptr)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
<< " bytes for a manual image W" << width << " H" << height << LL_ENDL;
U32 pixel_count = (U32)(width * height);
for (U32 i = 0; i < pixel_count; i++)
{
U8 lum = ((U8*)pixels)[i * 2 + 0];
U8 alpha = ((U8*)pixels)[i * 2 + 1];
U8* pix = (U8*)&sManualScratch[i];
pix[0] = pix[1] = pix[2] = lum;
pix[3] = alpha;
}
pixels = sManualScratch;
}
U32 pixel_count = (U32)(width * height);
for (U32 i = 0; i < pixel_count; i++)
{
U8 lum = ((U8*)pixels)[i];
U8* pix = (U8*)&scratch[i];
pix[0] = pix[1] = pix[2] = lum;
pix[3] = 255;
}
pixformat = GL_RGBA;
intformat = GL_RGBA8;
}
if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE)
{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGB
if (pixels != nullptr)
{
U32 pixel_count = (U32)(width * height);
for (U32 i = 0; i < pixel_count; i++)
{
U8 lum = ((U8*)pixels)[i];
U8* pix = (U8*)&sManualScratch[i];
pix[0] = pix[1] = pix[2] = lum;
pix[3] = 255;
}
pixels = sManualScratch;
}
pixformat = GL_RGBA;
intformat = GL_RGB8;
}
pixformat = GL_RGBA;
intformat = GL_RGB8;
}
}
@ -1322,6 +1406,14 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
{
switch (intformat)
{
case GL_RED:
case GL_R8:
intformat = GL_COMPRESSED_RED;
break;
case GL_RG:
case GL_RG8:
intformat = GL_COMPRESSED_RG;
break;
case GL_RGB:
case GL_RGB8:
intformat = GL_COMPRESSED_RGB;
@ -1350,12 +1442,8 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
case GL_ALPHA8:
intformat = GL_COMPRESSED_ALPHA;
break;
case GL_RED:
case GL_R8:
intformat = GL_COMPRESSED_RED;
break;
default:
LL_WARNS() << "Could not compress format: " << std::hex << intformat << LL_ENDL;
LL_WARNS() << "Could not compress format: " << std::hex << intformat << std::dec << LL_ENDL;
break;
}
}
@ -1371,7 +1459,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
if (!use_sub_image)
{
LL_PROFILE_ZONE_NAMED("glTexImage2D alloc + copy");
glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels);
glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, pixels);
}
else
{
@ -1381,21 +1469,16 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, nullptr);
}
U8* src = (U8*)(use_scratch ? scratch : pixels);
U8* src = (U8*)(pixels);
if (src)
{
LL_PROFILE_ZONE_NAMED("glTexImage2D copy");
sub_image_lines(target, miplevel, 0, 0, width, height, pixformat, pixtype, src, width);
}
}
alloc_tex_image(width, height, pixformat);
alloc_tex_image(width, height, intformat, 1);
}
stop_glerror();
if (use_scratch)
{
delete[] scratch;
}
}
//create an empty GL texture: just create a texture name
@ -2083,6 +2166,8 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
return ;
}
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
U32 length = w * h;
U32 alphatotal = 0;
@ -2094,15 +2179,15 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
// this will mid-skew the data (and thus increase the chances of not
// being used as a mask) from high-frequency alpha maps which
// suffer the worst from aliasing when used as alpha masks.
if (w >= 2 && h >= 2)
if (w >= 4 && h >= 4)
{
llassert(w%2 == 0);
llassert(h%2 == 0);
llassert(w%4 == 0);
llassert(h%4 == 0);
const GLubyte* rowstart = ((const GLubyte*) data_in) + mAlphaOffset;
for (U32 y = 0; y < h; y+=2)
for (U32 y = 0; y < h; y+=4)
{
const GLubyte* current = rowstart;
for (U32 x = 0; x < w; x+=2)
for (U32 x = 0; x < w; x+=4)
{
const U32 s1 = current[0];
alphatotal += s1;
@ -2126,7 +2211,7 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
}
rowstart += 2 * w * mAlphaStride;
rowstart += 4 * w * mAlphaStride;
}
length *= 2; // we sampled everything twice, essentially
}
@ -2374,11 +2459,11 @@ bool LLImageGL::scaleDown(S32 desired_discard)
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, temp_texname, true);
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glTexImage2D");
glTexImage2D(mTarget, 0, mFormatPrimary, desired_width, desired_height, 0, mFormatPrimary, mFormatType, NULL);
glTexImage2D(mTarget, 0, mFormatInternal, desired_width, desired_height, 0, mFormatPrimary, mFormatType, NULL);
}
// account for new texture getting created
alloc_tex_image(desired_width, desired_height, mFormatPrimary);
alloc_tex_image(desired_width, desired_height, mFormatInternal, 1);
// Use render-to-texture to scale down the texture
{
@ -2432,10 +2517,10 @@ bool LLImageGL::scaleDown(S32 desired_discard)
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, sScratchPBO);
glTexImage2D(mTarget, 0, mFormatPrimary, desired_width, desired_height, 0, mFormatPrimary, mFormatType, nullptr);
glTexImage2D(mTarget, 0, mFormatInternal, desired_width, desired_height, 0, mFormatPrimary, mFormatType, nullptr);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
alloc_tex_image(desired_width, desired_height, mFormatPrimary);
alloc_tex_image(desired_width, desired_height, mFormatInternal, 1);
if (mHasMipMaps)
{

View File

@ -50,7 +50,7 @@ class LLWindow;
namespace LLImageGLMemory
{
void alloc_tex_image(U32 width, U32 height, U32 pixformat);
void alloc_tex_image(U32 width, U32 height, U32 intformat, U32 count);
void free_tex_image(U32 texName);
void free_tex_images(U32 count, const U32* texNames);
void free_cur_tex_image();
@ -101,9 +101,9 @@ public:
static bool create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, bool usemipmaps = true);
public:
LLImageGL(bool usemipmaps = true);
LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps = true);
LLImageGL(const LLImageRaw* imageraw, bool usemipmaps = true);
LLImageGL(bool usemipmaps = true, bool allow_compression = true);
LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps = true, bool allow_compression = true);
LLImageGL(const LLImageRaw* imageraw, bool usemipmaps = true, bool allow_compression = true);
// For wrapping textures created via GL elsewhere with our API only. Use with caution.
LLImageGL(LLGLuint mTexName, U32 components, LLGLenum target, LLGLint formatInternal, LLGLenum formatPrimary, LLGLenum formatType, LLTexUnit::eTextureAddressMode addressMode);
@ -203,7 +203,7 @@ public:
LLGLenum getTexTarget()const { return mTarget; }
void init(bool usemipmaps);
void init(bool usemipmaps, bool allow_compression);
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);
@ -298,6 +298,7 @@ public:
public:
static void initClass(LLWindow* window, S32 num_catagories, bool skip_analyze_alpha = false, bool thread_texture_loads = false, bool thread_media_updates = false);
static void allocateConversionBuffer();
static void cleanupClass() ;
private:
@ -305,6 +306,7 @@ private:
static bool sSkipAnalyzeAlpha;
static U32 sScratchPBO;
static U32 sScratchPBOSize;
static U32* sManualScratch;
//the flag to allow to call readBackRaw(...).
//can be removed if we do not use that function at all.

File diff suppressed because it is too large Load Diff

View File

@ -42,15 +42,17 @@
#include "llpointer.h"
#include "llglheaders.h"
#include "llmatrix4a.h"
#include "glh/glh_linear.h"
#include "glm/mat4x4.hpp"
#include <array>
#include <list>
class LLVertexBuffer;
class LLCubeMap;
class LLImageGL;
class LLRenderTarget;
class LLTexture ;
class LLTexture;
class LLVertexBufferData;
#define LL_MATRIX_STACK_DEPTH 32
@ -219,17 +221,12 @@ public:
void setHasMipMaps(bool hasMips) { mHasMipMaps = hasMips; }
void setTextureColorSpace(eTextureColorSpace space);
eTextureColorSpace getCurrColorSpace() { return mTexColorSpace; }
protected:
friend class LLRender;
S32 mIndex;
U32 mCurrTexture;
eTextureType mCurrTexType;
eTextureColorSpace mTexColorSpace;
S32 mCurrColorScale;
S32 mCurrAlphaScale;
bool mHasMipMaps;
@ -322,7 +319,6 @@ public:
POINTS,
LINES,
LINE_STRIP,
QUADS,
LINE_LOOP,
NUM_MODES
};
@ -404,8 +400,8 @@ public:
void matrixMode(eMatrixMode mode);
eMatrixMode getMatrixMode();
const glh::matrix4f& getModelviewMatrix();
const glh::matrix4f& getProjectionMatrix();
const glm::mat4& getModelviewMatrix();
const glm::mat4& getProjectionMatrix();
void syncMatrices();
void syncLightState();
@ -420,8 +416,15 @@ public:
void flush();
// if list is set, will store buffers in list for later use, if list isn't set, will use cache
void beginList(std::list<LLVertexBufferData> *list);
void endList();
void begin(const GLuint& mode);
void end();
U8 getMode() const { return mMode; }
void vertex2i(const GLint& x, const GLint& y);
void vertex2f(const GLfloat& x, const GLfloat& y);
void vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z);
@ -446,9 +449,9 @@ public:
void diffuseColor4ubv(const U8* c);
void diffuseColor4ub(U8 r, U8 g, U8 b, U8 a);
void vertexBatchPreTransformed(LLVector3* verts, S32 vert_count);
void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count);
void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U*, S32 vert_count);
void vertexBatchPreTransformed(LLVector4a* verts, S32 vert_count);
void vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, S32 vert_count);
void vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, LLColor4U*, S32 vert_count);
void setColorMask(bool writeColor, bool writeAlpha);
void setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha);
@ -490,23 +493,27 @@ public:
private:
friend class LLLightState;
LLVertexBuffer* bufferfromCache(U32 attribute_mask, U32 count);
LLVertexBuffer* genBuffer(U32 attribute_mask, S32 count);
void drawBuffer(LLVertexBuffer* vb, U32 mode, S32 count);
void resetStriders(S32 count);
eMatrixMode mMatrixMode;
U32 mMatIdx[NUM_MATRIX_MODES];
U32 mMatHash[NUM_MATRIX_MODES];
glh::matrix4f mMatrix[NUM_MATRIX_MODES][LL_MATRIX_STACK_DEPTH];
glm::mat4 mMatrix[NUM_MATRIX_MODES][LL_MATRIX_STACK_DEPTH];
U32 mCurMatHash[NUM_MATRIX_MODES];
U32 mLightHash;
LLColor4 mAmbientLightColor;
bool mDirty;
U32 mQuadCycle;
U32 mCount;
U32 mMode;
U32 mCurrTextureUnitIndex;
bool mCurrColorMask[4];
LLPointer<LLVertexBuffer> mBuffer;
LLStrider<LLVector3> mVerticesp;
LLStrider<LLVector4a> mVerticesp;
LLStrider<LLVector2> mTexcoordsp;
LLStrider<LLColor4U> mColorsp;
std::array<LLTexUnit, LL_NUM_TEXTURE_LAYERS> mTexUnits;
@ -520,7 +527,6 @@ private:
std::vector<LLVector3> mUIOffset;
std::vector<LLVector3> mUIScale;
};
extern F32 gGLModelView[16];
@ -528,8 +534,8 @@ extern F32 gGLLastModelView[16];
extern F32 gGLLastProjection[16];
extern F32 gGLProjection[16];
extern S32 gGLViewport[4];
extern F32 gGLDeltaModelView[16];
extern F32 gGLInverseDeltaModelView[16];
extern glm::mat4 gGLDeltaModelView;
extern glm::mat4 gGLInverseDeltaModelView;
extern thread_local LLRender gGL;
@ -540,19 +546,20 @@ const F32 OGL_TO_CFR_ROTATION[16] = { 0.f, 0.f, -1.f, 0.f, // -Z becomes X
0.f, 1.f, 0.f, 0.f, // Y becomes Z
0.f, 0.f, 0.f, 1.f };
glh::matrix4f copy_matrix(F32* src);
glh::matrix4f get_current_modelview();
glh::matrix4f get_current_projection();
glh::matrix4f get_last_modelview();
glh::matrix4f get_last_projection();
glm::mat4 copy_matrix(F32* src);
glm::mat4 get_current_modelview();
glm::mat4 get_current_projection();
glm::mat4 get_last_modelview();
glm::mat4 get_last_projection();
void copy_matrix(const glh::matrix4f& src, F32* dst);
void set_current_modelview(const glh::matrix4f& mat);
void set_current_projection(glh::matrix4f& mat);
void copy_matrix(const glm::mat4& src, F32* dst);
void set_current_modelview(const glm::mat4& mat);
void set_current_projection(const glm::mat4& mat);
void set_last_modelview(const glm::mat4& mat);
void set_last_projection(const glm::mat4& mat);
glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar);
glh::matrix4f gl_perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar);
glh::matrix4f gl_lookat(LLVector3 eye, LLVector3 center, LLVector3 up);
// glh compat
glm::vec3 mul_mat4_vec3(const glm::mat4& mat, const glm::vec3& vec);
#define LL_SHADER_LOADING_WARNS(...) LL_WARNS()

View File

@ -122,10 +122,13 @@ void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, bool filled )
// Counterclockwise quad will face the viewer
if( filled )
{
gGL.begin( LLRender::QUADS );
gGL.begin( LLRender::TRIANGLES );
gGL.vertex2i(left, top);
gGL.vertex2i(left, bottom);
gGL.vertex2i(right, bottom);
gGL.vertex2i(left, top);
gGL.vertex2i(right, bottom);
gGL.vertex2i(right, top);
gGL.end();
}
@ -172,50 +175,70 @@ void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &st
LLColor4 end_color = start_color;
end_color.mV[VALPHA] = 0.f;
gGL.begin(LLRender::QUADS);
gGL.begin(LLRender::TRIANGLES);
// Right edge, CCW faces screen
gGL.color4fv(start_color.mV);
gGL.vertex2i(right, top-lines);
gGL.vertex2i(right, bottom);
gGL.vertex2i(right, top - lines);
gGL.vertex2i(right, bottom);
gGL.color4fv(end_color.mV);
gGL.vertex2i(right+lines, bottom);
gGL.vertex2i(right+lines, top-lines);
gGL.vertex2i(right + lines, bottom);
gGL.color4fv(start_color.mV);
gGL.vertex2i(right, top - lines);
gGL.color4fv(end_color.mV);
gGL.vertex2i(right + lines, bottom);
gGL.vertex2i(right + lines, top - lines);
// Bottom edge, CCW faces screen
gGL.color4fv(start_color.mV);
gGL.vertex2i(right, bottom);
gGL.vertex2i(left+lines, bottom);
gGL.vertex2i(right, bottom);
gGL.vertex2i(left + lines, bottom);
gGL.color4fv(end_color.mV);
gGL.vertex2i(left+lines, bottom-lines);
gGL.vertex2i(right, bottom-lines);
gGL.vertex2i(left + lines, bottom - lines);
gGL.color4fv(start_color.mV);
gGL.vertex2i(right, bottom);
gGL.color4fv(end_color.mV);
gGL.vertex2i(left + lines, bottom - lines);
gGL.vertex2i(right, bottom - lines);
// bottom left Corner
gGL.color4fv(start_color.mV);
gGL.vertex2i(left+lines, bottom);
gGL.vertex2i(left + lines, bottom);
gGL.color4fv(end_color.mV);
gGL.vertex2i(left, bottom);
gGL.vertex2i(left, bottom);
// make the bottom left corner not sharp
gGL.vertex2i(left+1, bottom-lines+1);
gGL.vertex2i(left+lines, bottom-lines);
gGL.vertex2i(left + 1, bottom - lines + 1);
gGL.color4fv(start_color.mV);
gGL.vertex2i(left + lines, bottom);
gGL.color4fv(end_color.mV);
gGL.vertex2i(left + 1, bottom - lines + 1);
gGL.vertex2i(left + lines, bottom - lines);
// bottom right corner
gGL.color4fv(start_color.mV);
gGL.vertex2i(right, bottom);
gGL.vertex2i(right, bottom);
gGL.color4fv(end_color.mV);
gGL.vertex2i(right, bottom-lines);
gGL.vertex2i(right, bottom - lines);
// make the rightmost corner not sharp
gGL.vertex2i(right+lines-1, bottom-lines+1);
gGL.vertex2i(right+lines, bottom);
gGL.vertex2i(right + lines - 1, bottom - lines + 1);
gGL.color4fv(start_color.mV);
gGL.vertex2i(right, bottom);
gGL.color4fv(end_color.mV);
gGL.vertex2i(right + lines - 1, bottom - lines + 1);
gGL.vertex2i(right + lines, bottom);
// top right corner
gGL.color4fv(start_color.mV);
gGL.vertex2i( right, top-lines );
gGL.vertex2i(right, top - lines);
gGL.color4fv(end_color.mV);
gGL.vertex2i( right+lines, top-lines );
gGL.vertex2i(right + lines, top - lines);
// make the corner not sharp
gGL.vertex2i( right+lines-1, top-1 );
gGL.vertex2i( right, top );
gGL.vertex2i(right + lines - 1, top - 1);
gGL.color4fv(start_color.mV);
gGL.vertex2i(right, top - lines);
gGL.color4fv(end_color.mV);
gGL.vertex2i(right + lines - 1, top - 1);
gGL.vertex2i(right, top);
gGL.end();
stop_glerror();
@ -423,171 +446,251 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
ui_translation.mV[VX] + width * ui_scale.mV[VX],
ui_translation.mV[VY]);
LLGLSUIDefault gls_ui;
gGL.getTexUnit(0)->bind(image, true);
gGL.color4fv(color.mV);
const S32 NUM_VERTICES = 9 * 4; // 9 quads
LLVector2 uv[NUM_VERTICES];
LLVector3 pos[NUM_VERTICES];
constexpr S32 NUM_VERTICES = 9 * 2 * 3; // 9 quads, 2 triangles per quad, 3 vertices per triangle
static thread_local LLVector2 uv[NUM_VERTICES];
static thread_local LLVector4a pos[NUM_VERTICES];
S32 index = 0;
gGL.begin(LLRender::QUADS);
gGL.begin(LLRender::TRIANGLES);
{
// draw bottom left
uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mBottom);
pos[index] = LLVector3(draw_outer_rect.mLeft, draw_outer_rect.mBottom, 0.f);
// draw bottom left triangles
// 1
uv[index].set(uv_outer_rect.mLeft, uv_outer_rect.mBottom);
pos[index].set(draw_outer_rect.mLeft, draw_outer_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom);
pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
uv[index].set(uv_center_rect.mLeft, uv_outer_rect.mBottom);
pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
uv[index].set(uv_center_rect.mLeft, uv_center_rect.mBottom);
pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom);
pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
// 2
uv[index].set(uv_outer_rect.mLeft, uv_outer_rect.mBottom);
pos[index].set(draw_outer_rect.mLeft, draw_outer_rect.mBottom, 0.f);
index++;
// draw bottom middle
uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom);
pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
uv[index].set(uv_center_rect.mLeft, uv_center_rect.mBottom);
pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom);
pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
uv[index].set(uv_outer_rect.mLeft, uv_center_rect.mBottom);
pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
// draw bottom middle triangles
uv[index].set(uv_center_rect.mLeft, uv_outer_rect.mBottom);
pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
uv[index].set(uv_center_rect.mRight, uv_outer_rect.mBottom);
pos[index].set(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
index++;
// draw bottom right
uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom);
pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
uv[index].set(uv_center_rect.mRight, uv_center_rect.mBottom);
pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mBottom);
pos[index] = LLVector3(draw_outer_rect.mRight, draw_outer_rect.mBottom, 0.f);
// 2
uv[index].set(uv_center_rect.mLeft, uv_outer_rect.mBottom);
pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom);
pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
uv[index].set(uv_center_rect.mRight, uv_center_rect.mBottom);
pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
uv[index].set(uv_center_rect.mLeft, uv_center_rect.mBottom);
pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
// draw left
uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom);
pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
// draw bottom right triangles
uv[index].set(uv_center_rect.mRight, uv_outer_rect.mBottom);
pos[index].set(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
uv[index].set(uv_outer_rect.mRight, uv_outer_rect.mBottom);
pos[index].set(draw_outer_rect.mRight, draw_outer_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
uv[index].set(uv_outer_rect.mRight, uv_center_rect.mBottom);
pos[index].set(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop);
pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
// 2
uv[index].set(uv_center_rect.mRight, uv_outer_rect.mBottom);
pos[index].set(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
index++;
// draw middle
uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
uv[index].set(uv_outer_rect.mRight, uv_center_rect.mBottom);
pos[index].set(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
uv[index].set(uv_center_rect.mRight, uv_center_rect.mBottom);
pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
// draw left triangles
uv[index].set(uv_outer_rect.mLeft, uv_center_rect.mBottom);
pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
uv[index].set(uv_center_rect.mLeft, uv_center_rect.mBottom);
pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
// draw right
uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
uv[index].set(uv_center_rect.mLeft, uv_center_rect.mTop);
pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom);
pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
// 2
uv[index].set(uv_outer_rect.mLeft, uv_center_rect.mBottom);
pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop);
pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
uv[index].set(uv_center_rect.mLeft, uv_center_rect.mTop);
pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
uv[index].set(uv_outer_rect.mLeft, uv_center_rect.mTop);
pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
// draw top left
uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop);
pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
// draw middle triangles
uv[index].set(uv_center_rect.mLeft, uv_center_rect.mBottom);
pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
uv[index].set(uv_center_rect.mRight, uv_center_rect.mBottom);
pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop);
pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
uv[index].set(uv_center_rect.mRight, uv_center_rect.mTop);
pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mTop);
pos[index] = LLVector3(draw_outer_rect.mLeft, draw_outer_rect.mTop, 0.f);
// 2
uv[index].set(uv_center_rect.mLeft, uv_center_rect.mBottom);
pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
index++;
// draw top middle
uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
uv[index].set(uv_center_rect.mRight, uv_center_rect.mTop);
pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
uv[index].set(uv_center_rect.mLeft, uv_center_rect.mTop);
pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop);
pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
// draw right triangles
uv[index].set(uv_center_rect.mRight, uv_center_rect.mBottom);
pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop);
pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
uv[index].set(uv_outer_rect.mRight, uv_center_rect.mBottom);
pos[index].set(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
// draw top right
uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
uv[index].set(uv_outer_rect.mRight, uv_center_rect.mTop);
pos[index].set(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop);
pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
// 2
uv[index].set(uv_center_rect.mRight, uv_center_rect.mBottom);
pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
index++;
uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mTop);
pos[index] = LLVector3(draw_outer_rect.mRight, draw_outer_rect.mTop, 0.f);
uv[index].set(uv_outer_rect.mRight, uv_center_rect.mTop);
pos[index].set(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop);
pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
uv[index].set(uv_center_rect.mRight, uv_center_rect.mTop);
pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
// draw top left triangles
uv[index].set(uv_outer_rect.mLeft, uv_center_rect.mTop);
pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
uv[index].set(uv_center_rect.mLeft, uv_center_rect.mTop);
pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
uv[index].set(uv_center_rect.mLeft, uv_outer_rect.mTop);
pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
index++;
// 2
uv[index].set(uv_outer_rect.mLeft, uv_center_rect.mTop);
pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
uv[index].set(uv_center_rect.mLeft, uv_outer_rect.mTop);
pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
index++;
uv[index].set(uv_outer_rect.mLeft, uv_outer_rect.mTop);
pos[index].set(draw_outer_rect.mLeft, draw_outer_rect.mTop, 0.f);
index++;
// draw top middle triangles
uv[index].set(uv_center_rect.mLeft, uv_center_rect.mTop);
pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
uv[index].set(uv_center_rect.mRight, uv_center_rect.mTop);
pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
uv[index].set(uv_center_rect.mRight, uv_outer_rect.mTop);
pos[index].set(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
index++;
// 2
uv[index].set(uv_center_rect.mLeft, uv_center_rect.mTop);
pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
index++;
uv[index].set(uv_center_rect.mRight, uv_outer_rect.mTop);
pos[index].set(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
index++;
uv[index].set(uv_center_rect.mLeft, uv_outer_rect.mTop);
pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
index++;
// draw top right triangles
uv[index].set(uv_center_rect.mRight, uv_center_rect.mTop);
pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
uv[index].set(uv_outer_rect.mRight, uv_center_rect.mTop);
pos[index].set(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
uv[index].set(uv_outer_rect.mRight, uv_outer_rect.mTop);
pos[index].set(draw_outer_rect.mRight, draw_outer_rect.mTop, 0.f);
index++;
// 2
uv[index].set(uv_center_rect.mRight, uv_center_rect.mTop);
pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
index++;
uv[index].set(uv_outer_rect.mRight, uv_outer_rect.mTop);
pos[index].set(draw_outer_rect.mRight, draw_outer_rect.mTop, 0.f);
index++;
uv[index].set(uv_center_rect.mRight, uv_outer_rect.mTop);
pos[index].set(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
index++;
gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES);
@ -614,8 +717,6 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
return;
}
LLGLSUIDefault gls_ui;
if(image != NULL)
{
gGL.getTexUnit(0)->bind(image, true);
@ -629,11 +730,11 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
if (degrees == 0.f)
{
const S32 NUM_VERTICES = 4; // 9 quads
LLVector2 uv[NUM_VERTICES];
LLVector3 pos[NUM_VERTICES];
constexpr S32 NUM_VERTICES = 2 * 3;
static thread_local LLVector2 uv[NUM_VERTICES +1];
static thread_local LLVector4a pos[NUM_VERTICES +1];
gGL.begin(LLRender::QUADS);
gGL.begin(LLRender::TRIANGLES);
{
LLVector3 ui_scale = gGL.getUIScale();
LLVector3 ui_translation = gGL.getUITranslation();
@ -644,20 +745,28 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
S32 scaled_width = ll_round(width * ui_scale.mV[VX]);
S32 scaled_height = ll_round(height * ui_scale.mV[VY]);
uv[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
pos[index] = LLVector3(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY] + scaled_height, 0.f);
uv[index].set(uv_rect.mRight, uv_rect.mTop);
pos[index].set(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY] + scaled_height, 0.f);
index++;
uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop);
pos[index] = LLVector3(ui_translation.mV[VX], ui_translation.mV[VY] + scaled_height, 0.f);
uv[index].set(uv_rect.mLeft, uv_rect.mTop);
pos[index].set(ui_translation.mV[VX], ui_translation.mV[VY] + scaled_height, 0.f);
index++;
uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
pos[index] = LLVector3(ui_translation.mV[VX], ui_translation.mV[VY], 0.f);
uv[index].set(uv_rect.mLeft, uv_rect.mBottom);
pos[index].set(ui_translation.mV[VX], ui_translation.mV[VY], 0.f);
index++;
uv[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom);
pos[index] = LLVector3(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY], 0.f);
uv[index].set(uv_rect.mRight, uv_rect.mTop);
pos[index].set(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY] + scaled_height, 0.f);
index++;
uv[index].set(uv_rect.mLeft, uv_rect.mBottom);
pos[index].set(ui_translation.mV[VX], ui_translation.mV[VY], 0.f);
index++;
uv[index].set(uv_rect.mRight, uv_rect.mBottom);
pos[index].set(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY], 0.f);
index++;
gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES);
@ -687,7 +796,7 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
gGL.color4fv(color.mV);
gGL.begin(LLRender::QUADS);
gGL.begin(LLRender::TRIANGLES);
{
LLVector3 v;
@ -703,6 +812,14 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
gGL.vertex2f(v.mV[0], v.mV[1] );
v = LLVector3(offset_x, offset_y, 0.f) * quat;
gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
gGL.vertex2f(v.mV[0], v.mV[1]);
v = LLVector3(-offset_x, -offset_y, 0.f) * quat;
gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
gGL.vertex2f(v.mV[0], v.mV[1]);
v = LLVector3(offset_x, -offset_y, 0.f) * quat;
gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
gGL.vertex2f(v.mV[0], v.mV[1] );
@ -948,7 +1065,7 @@ void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians,
void gl_rect_2d_simple_tex( S32 width, S32 height )
{
gGL.begin( LLRender::QUADS );
gGL.begin( LLRender::TRIANGLES );
gGL.texCoord2f(1.f, 1.f);
gGL.vertex2i(width, height);
@ -959,6 +1076,12 @@ void gl_rect_2d_simple_tex( S32 width, S32 height )
gGL.texCoord2f(0.f, 0.f);
gGL.vertex2i(0, 0);
gGL.texCoord2f(1.f, 1.f);
gGL.vertex2i(width, height);
gGL.texCoord2f(0.f, 0.f);
gGL.vertex2i(0, 0);
gGL.texCoord2f(1.f, 0.f);
gGL.vertex2i(width, 0);
@ -967,10 +1090,13 @@ void gl_rect_2d_simple_tex( S32 width, S32 height )
void gl_rect_2d_simple( S32 width, S32 height )
{
gGL.begin( LLRender::QUADS );
gGL.begin( LLRender::TRIANGLES );
gGL.vertex2i(width, height);
gGL.vertex2i(0, height);
gGL.vertex2i(0, 0);
gGL.vertex2i(width, height);
gGL.vertex2i(0, 0);
gGL.vertex2i(width, 0);
gGL.end();
}
@ -1011,7 +1137,7 @@ void gl_segmented_rect_2d_tex(const S32 left,
LLVector2 width_vec((F32)width, 0.f);
LLVector2 height_vec(0.f, (F32)height);
gGL.begin(LLRender::QUADS);
gGL.begin(LLRender::TRIANGLES);
{
// draw bottom left
gGL.texCoord2f(0.f, 0.f);
@ -1023,6 +1149,12 @@ void gl_segmented_rect_2d_tex(const S32 left,
gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
gGL.vertex2fv((border_width_left + border_height_bottom).mV);
gGL.texCoord2f(0.f, 0.f);
gGL.vertex2f(0.f, 0.f);
gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
gGL.vertex2fv((border_width_left + border_height_bottom).mV);
gGL.texCoord2f(0.f, border_uv_scale.mV[VY]);
gGL.vertex2fv(border_height_bottom.mV);
@ -1036,6 +1168,12 @@ void gl_segmented_rect_2d_tex(const S32 left,
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
gGL.vertex2fv(border_width_left.mV);
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
gGL.vertex2fv((border_width_left + border_height_bottom).mV);
@ -1049,6 +1187,12 @@ void gl_segmented_rect_2d_tex(const S32 left,
gGL.texCoord2f(1.f, border_uv_scale.mV[VY]);
gGL.vertex2fv((width_vec + border_height_bottom).mV);
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
gGL.vertex2fv((width_vec - border_width_right).mV);
gGL.texCoord2f(1.f, border_uv_scale.mV[VY]);
gGL.vertex2fv((width_vec + border_height_bottom).mV);
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
@ -1062,6 +1206,12 @@ void gl_segmented_rect_2d_tex(const S32 left,
gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
gGL.texCoord2f(0.f, border_uv_scale.mV[VY]);
gGL.vertex2fv(border_height_bottom.mV);
gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((height_vec - border_height_top).mV);
@ -1075,6 +1225,12 @@ void gl_segmented_rect_2d_tex(const S32 left,
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
gGL.vertex2fv((border_width_left + border_height_bottom).mV);
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
@ -1088,6 +1244,12 @@ void gl_segmented_rect_2d_tex(const S32 left,
gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((width_vec + height_vec - border_height_top).mV);
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((width_vec + height_vec - border_height_top).mV);
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
@ -1101,6 +1263,12 @@ void gl_segmented_rect_2d_tex(const S32 left,
gGL.texCoord2f(border_uv_scale.mV[VX], 1.f);
gGL.vertex2fv((border_width_left + height_vec).mV);
gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((height_vec - border_height_top).mV);
gGL.texCoord2f(border_uv_scale.mV[VX], 1.f);
gGL.vertex2fv((border_width_left + height_vec).mV);
gGL.texCoord2f(0.f, 1.f);
gGL.vertex2fv((height_vec).mV);
@ -1114,6 +1282,12 @@ void gl_segmented_rect_2d_tex(const S32 left,
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
gGL.vertex2fv((width_vec - border_width_right + height_vec).mV);
gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
gGL.vertex2fv((width_vec - border_width_right + height_vec).mV);
gGL.texCoord2f(border_uv_scale.mV[VX], 1.f);
gGL.vertex2fv((border_width_left + height_vec).mV);
@ -1127,6 +1301,12 @@ void gl_segmented_rect_2d_tex(const S32 left,
gGL.texCoord2f(1.f, 1.f);
gGL.vertex2fv((width_vec + height_vec).mV);
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
gGL.texCoord2f(1.f, 1.f);
gGL.vertex2fv((width_vec + height_vec).mV);
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
gGL.vertex2fv((width_vec - border_width_right + height_vec).mV);
}
@ -1181,7 +1361,7 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
LLVector2 x_min;
LLVector2 x_max;
gGL.begin(LLRender::QUADS);
gGL.begin(LLRender::TRIANGLES);
{
if (start_fragment < middle_start)
{
@ -1200,6 +1380,12 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
gGL.vertex2fv((x_max + border_height_bottom).mV);
gGL.texCoord2f(u_min, 0.f);
gGL.vertex2fv(x_min.mV);
gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
gGL.vertex2fv((x_max + border_height_bottom).mV);
gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
gGL.vertex2fv((x_min + border_height_bottom).mV);
@ -1213,6 +1399,12 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
gGL.vertex2fv((x_min + border_height_bottom).mV);
gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
@ -1226,6 +1418,12 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
gGL.texCoord2f(u_max, 1.f);
gGL.vertex2fv((x_max + height_vec).mV);
gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
gGL.texCoord2f(u_max, 1.f);
gGL.vertex2fv((x_max + height_vec).mV);
gGL.texCoord2f(u_min, 1.f);
gGL.vertex2fv((x_min + height_vec).mV);
}
@ -1245,6 +1443,12 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
gGL.vertex2fv((x_max + border_height_bottom).mV);
gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
gGL.vertex2fv(x_min.mV);
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
gGL.vertex2fv((x_max + border_height_bottom).mV);
gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
gGL.vertex2fv((x_min + border_height_bottom).mV);
@ -1258,6 +1462,12 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
gGL.vertex2fv((x_min + border_height_bottom).mV);
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
@ -1271,6 +1481,12 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
gGL.vertex2fv((x_max + height_vec).mV);
gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
gGL.vertex2fv((x_max + height_vec).mV);
gGL.texCoord2f(border_uv_scale.mV[VX], 1.f);
gGL.vertex2fv((x_min + height_vec).mV);
}
@ -1292,6 +1508,12 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
gGL.vertex2fv((x_max + border_height_bottom).mV);
gGL.texCoord2f(u_min, 0.f);
gGL.vertex2fv((x_min).mV);
gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
gGL.vertex2fv((x_max + border_height_bottom).mV);
gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
gGL.vertex2fv((x_min + border_height_bottom).mV);
@ -1305,6 +1527,12 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
gGL.vertex2fv((x_min + border_height_bottom).mV);
gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
@ -1318,6 +1546,12 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect,
gGL.texCoord2f(u_max, 1.f);
gGL.vertex2fv((x_max + height_vec).mV);
gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
gGL.texCoord2f(u_max, 1.f);
gGL.vertex2fv((x_max + height_vec).mV);
gGL.texCoord2f(u_min, 1.f);
gGL.vertex2fv((x_min + height_vec).mV);
}
@ -1332,7 +1566,7 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
gGL.begin(LLRender::QUADS);
gGL.begin(LLRender::TRIANGLES);
{
// draw bottom left
gGL.texCoord2f(clip_rect.mLeft, clip_rect.mBottom);
@ -1344,6 +1578,12 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv
gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(clip_rect.mLeft, clip_rect.mBottom);
gGL.vertex3f(0.f, 0.f, 0.f);
gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mBottom * height_vec).mV);
@ -1357,6 +1597,12 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec).mV);
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV);
@ -1370,6 +1616,12 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv
gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mBottom);
gGL.vertex3fv((width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mRight * width_vec).mV);
gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mBottom);
gGL.vertex3fv((width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV);
@ -1383,6 +1635,12 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv
gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mTop * height_vec).mV);
@ -1396,6 +1654,12 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV);
@ -1409,6 +1673,12 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv
gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mTop);
gGL.vertex3fv((width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mRight* width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mTop);
gGL.vertex3fv((width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV);
@ -1422,6 +1692,12 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv
gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mTop);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV);
gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mTop);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV);
gGL.texCoord2f(clip_rect.mLeft, clip_rect.mTop);
gGL.vertex3fv((height_vec).mV);
@ -1435,6 +1711,12 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv
gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mTop);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + height_vec).mV);
gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mTop);
gGL.vertex3fv((center_draw_rect.mRight* width_vec + height_vec).mV);
gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mTop);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV);
@ -1448,6 +1730,12 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv
gGL.texCoord2f(clip_rect.mRight, clip_rect.mTop);
gGL.vertex3fv((width_vec + height_vec).mV);
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mRight* width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(clip_rect.mRight, clip_rect.mTop);
gGL.vertex3fv((width_vec + height_vec).mV);
gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mTop);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + height_vec).mV);
}

View File

@ -34,6 +34,8 @@
#include "llerror.h"
#include "llglheaders.h"
#include "llvertexbuffer.h"
#include "llglslshader.h"
LLRenderSphere gSphere;
@ -53,12 +55,20 @@ inline LLVector3 polar_to_cart(F32 latitude, F32 longitude)
void LLRenderSphere::renderGGL()
{
LL_PROFILE_ZONE_SCOPED;
S32 const LATITUDE_SLICES = 20;
S32 const LONGITUDE_SLICES = 30;
if (mSpherePoints.empty())
if (mVertexBuffer.isNull())
{
mSpherePoints.resize(LATITUDE_SLICES + 1);
mVertexBuffer = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX);
mVertexBuffer->allocateBuffer((U32)(LATITUDE_SLICES + 1) * (LONGITUDE_SLICES + 1), LATITUDE_SLICES * LONGITUDE_SLICES * 6);
LLStrider<LLVector3> v;
mVertexBuffer->getVertexStrider(v);
for (S32 lat_i = 0; lat_i < LATITUDE_SLICES + 1; lat_i++)
{
mSpherePoints[lat_i].resize(LONGITUDE_SLICES + 1);
@ -68,24 +78,52 @@ void LLRenderSphere::renderGGL()
F32 lon = (F32)lon_i / LONGITUDE_SLICES;
mSpherePoints[lat_i][lon_i] = polar_to_cart(lat, lon);
v[lat_i * (LONGITUDE_SLICES + 1) + lon_i] = mSpherePoints[lat_i][lon_i];
}
}
}
gGL.begin(LLRender::TRIANGLES);
LLStrider<U16> i;
mVertexBuffer->getIndexStrider(i);
for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++)
{
for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++)
for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++)
{
gGL.vertex3fv(mSpherePoints[lat_i][lon_i].mV);
gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV);
gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV);
for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++)
{
i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 0] = lat_i * (LONGITUDE_SLICES + 1) + lon_i;
i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 1] = lat_i * (LONGITUDE_SLICES + 1) + lon_i + 1;
i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 2] = (lat_i + 1) * (LONGITUDE_SLICES + 1) + lon_i;
gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV);
gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV);
gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i+1].mV);
i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 3] = (lat_i + 1) * (LONGITUDE_SLICES + 1) + lon_i;
i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 4] = lat_i * (LONGITUDE_SLICES + 1) + lon_i + 1;
i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 5] = (lat_i + 1) * (LONGITUDE_SLICES + 1) + lon_i + 1;
}
}
mVertexBuffer->unmapBuffer();
}
if (LLGLSLShader::sCurBoundShaderPtr->mAttributeMask == LLVertexBuffer::MAP_VERTEX)
{ // shader expects only vertex positions in vertex buffer, use fast path
mVertexBuffer->setBuffer();
mVertexBuffer->drawRange(LLRender::TRIANGLES, 0, mVertexBuffer->getNumVerts(), mVertexBuffer->getNumIndices(), 0);
}
else
{ //shader wants colors in the vertex stream, use slow path
gGL.begin(LLRender::TRIANGLES);
for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++)
{
for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++)
{
gGL.vertex3fv(mSpherePoints[lat_i][lon_i].mV);
gGL.vertex3fv(mSpherePoints[lat_i][lon_i + 1].mV);
gGL.vertex3fv(mSpherePoints[lat_i + 1][lon_i].mV);
gGL.vertex3fv(mSpherePoints[lat_i + 1][lon_i].mV);
gGL.vertex3fv(mSpherePoints[lat_i][lon_i + 1].mV);
gGL.vertex3fv(mSpherePoints[lat_i + 1][lon_i + 1].mV);
}
}
gGL.end();
}
gGL.end();
}

View File

@ -45,6 +45,7 @@ public:
private:
std::vector< std::vector<LLVector3> > mSpherePoints;
LLPointer<LLVertexBuffer> mVertexBuffer;
};
extern LLRenderSphere gSphere;

View File

@ -475,12 +475,10 @@ void LLRenderTarget::clear(U32 mask_in)
U32 LLRenderTarget::getTexture(U32 attachment) const
{
if (attachment > mTex.size()-1)
{
LL_ERRS() << "Invalid attachment index." << LL_ENDL;
}
if (mTex.empty())
if (attachment >= mTex.size())
{
LL_WARNS() << "Invalid attachment index " << attachment << " for size " << mTex.size() << LL_ENDL;
llassert(false);
return 0;
}
return mTex[attachment];
@ -511,7 +509,6 @@ void LLRenderTarget::bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilt
}
gGL.getTexUnit(channel)->setTextureFilteringOption(filter_options);
gGL.getTexUnit(channel)->setTextureColorSpace(isSRGB ? LLTexUnit::TCS_SRGB : LLTexUnit::TCS_LINEAR);
}
void LLRenderTarget::flush()

View File

@ -595,8 +595,15 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
extra_code_text[extra_code_count++] = strdup("precision highp float;\n");
}
}
}
extra_code_text[extra_code_count++] = strdup("#define FXAA_GLSL_130 1\n");
if (type == GL_FRAGMENT_SHADER)
{
extra_code_text[extra_code_count++] = strdup("#define FRAGMENT_SHADER 1\n");
}
else
{
extra_code_text[extra_code_count++] = strdup("#define VERTEX_SHADER 1\n");
}
// Use alpha float to store bit flags
@ -1470,6 +1477,11 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("debug_normal_draw_length");
mReservedUniforms.push_back("edgesTex");
mReservedUniforms.push_back("areaTex");
mReservedUniforms.push_back("searchTex");
mReservedUniforms.push_back("blendTex");
llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS);
std::set<std::string> dupe_check;

View File

@ -332,6 +332,11 @@ public:
DEBUG_NORMAL_DRAW_LENGTH, // "debug_normal_draw_length"
SMAA_EDGE_TEX, // "edgesTex"
SMAA_AREA_TEX, // "areaTex"
SMAA_SEARCH_TEX, // "searchTex"
SMAA_BLEND_TEX, // "blendTex"
END_RESERVED_UNIFORMS
} eGLSLReservedUniforms;
// clang-format on

View File

@ -36,6 +36,7 @@
#include "llshadermgr.h"
#include "llglslshader.h"
#include "llmemory.h"
#include <glm/gtc/type_ptr.hpp>
//Next Highest Power Of Two
//helper function, returns first number > v that is a power of 2, or v if v is already a power of 2
@ -288,22 +289,58 @@ static GLuint gen_buffer()
return ret;
}
static void delete_buffers(S32 count, GLuint* buffers)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
// wait a few frames before actually deleting the buffers to avoid
// synchronization issues with the GPU
static std::vector<GLuint> sFreeList[4];
if (gGLManager.mInited)
{
U32 idx = LLImageGL::sFrameCount % 4;
for (S32 i = 0; i < count; ++i)
{
sFreeList[idx].push_back(buffers[i]);
}
idx = (LLImageGL::sFrameCount + 3) % 4;
if (!sFreeList[idx].empty())
{
glDeleteBuffers((GLsizei)sFreeList[idx].size(), sFreeList[idx].data());
sFreeList[idx].resize(0);
}
}
}
#define ANALYZE_VBO_POOL 0
#if LL_DARWIN
// experimental -- disable VBO pooling on OS X and use glMapBuffer
// VBO Pool interface
class LLVBOPool
{
public:
virtual ~LLVBOPool() = default;
virtual void allocate(GLenum type, U32 size, GLuint& name, U8*& data) = 0;
virtual void free(GLenum type, U32 size, GLuint name, U8* data) = 0;
virtual U64 getVramBytesUsed() = 0;
};
// VBO Pool for Apple GPUs (as in M1/M2 etc, not Intel macs)
// Effectively disables VBO pooling
class LLAppleVBOPool final: public LLVBOPool
{
public:
U64 mAllocated = 0;
U64 getVramBytesUsed()
U64 getVramBytesUsed() override
{
return mAllocated;
}
void allocate(GLenum type, U32 size, GLuint& name, U8*& data)
void allocate(GLenum type, U32 size, GLuint& name, U8*& data) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
STOP_GLERROR;
@ -323,7 +360,7 @@ public:
}
}
void free(GLenum type, U32 size, GLuint name, U8* data)
void free(GLenum type, U32 size, GLuint name, U8* data) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
@ -338,19 +375,17 @@ public:
STOP_GLERROR;
if (name)
{
glDeleteBuffers(1, &name);
delete_buffers(1, &name);
}
STOP_GLERROR;
}
};
#else
class LLVBOPool
// VBO Pool for GPUs that benefit from VBO pooling
class LLDefaultVBOPool final : public LLVBOPool
{
public:
typedef std::chrono::steady_clock::time_point Time;
struct Entry
{
U8* mData;
@ -358,7 +393,7 @@ public:
Time mAge;
};
~LLVBOPool()
~LLDefaultVBOPool() override
{
clear();
}
@ -376,7 +411,7 @@ public:
U32 mMisses = 0;
U32 mHits = 0;
U64 getVramBytesUsed()
U64 getVramBytesUsed() override
{
return mAllocated + mReserved;
}
@ -392,7 +427,7 @@ public:
size += block_size - (size % block_size);
}
void allocate(GLenum type, U32 size, GLuint& name, U8*& data)
void allocate(GLenum type, U32 size, GLuint& name, U8*& data) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
@ -448,7 +483,7 @@ public:
clean();
}
void free(GLenum type, U32 size, GLuint name, U8* data)
void free(GLenum type, U32 size, GLuint name, U8* data) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
@ -511,7 +546,7 @@ public:
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vbo cache timeout");
auto& entry = entries.back();
ll_aligned_free_16(entry.mData);
glDeleteBuffers(1, &entry.mGLName);
delete_buffers(1, &entry.mGLName);
llassert(mReserved >= iter->first);
mReserved -= iter->first;
entries.pop_back();
@ -547,7 +582,7 @@ public:
for (auto& entry : entries.second)
{
ll_aligned_free_16(entry.mData);
glDeleteBuffers(1, &entry.mGLName);
delete_buffers(1, &entry.mGLName);
}
}
@ -556,7 +591,7 @@ public:
for (auto& entry : entries.second)
{
ll_aligned_free_16(entry.mData);
glDeleteBuffers(1, &entry.mGLName);
delete_buffers(1, &entry.mGLName);
}
}
@ -566,10 +601,71 @@ public:
mVBOPool.clear();
}
};
#endif
static LLVBOPool* sVBOPool = nullptr;
void LLVertexBufferData::drawWithMatrix()
{
if (!mVB)
{
llassert(false);
// Not supposed to happen, check buffer generation
return;
}
if (mTexName)
{
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTexName);
}
else
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.pushMatrix();
gGL.loadMatrix(glm::value_ptr(mModelView));
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.pushMatrix();
gGL.loadMatrix(glm::value_ptr(mProjection));
gGL.matrixMode(LLRender::MM_TEXTURE0);
gGL.pushMatrix();
gGL.loadMatrix(glm::value_ptr(mTexture0));
mVB->setBuffer();
mVB->drawArrays(mMode, 0, mCount);
gGL.popMatrix();
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.popMatrix();
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.popMatrix();
}
void LLVertexBufferData::draw()
{
if (!mVB)
{
llassert(false);
// Not supposed to happen, check buffer generation
return;
}
if (mTexName)
{
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTexName);
}
else
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
mVB->setBuffer();
mVB->drawArrays(mMode, 0, mCount);
}
//============================================================================
//static
U64 LLVertexBuffer::getBytesAllocated()
{
@ -632,7 +728,6 @@ const U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
GL_POINTS,
GL_LINES,
GL_LINE_STRIP,
GL_QUADS,
GL_LINE_LOOP,
};
@ -847,7 +942,16 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
void LLVertexBuffer::initClass(LLWindow* window)
{
llassert(sVBOPool == nullptr);
sVBOPool = new LLVBOPool();
if (gGLManager.mIsApple)
{
LL_INFOS() << "VBO Pooling Disabled" << LL_ENDL;
sVBOPool = new LLAppleVBOPool();
}
else
{
LL_INFOS() << "VBO Pooling Enabled" << LL_ENDL;
sVBOPool = new LLDefaultVBOPool();
}
#if ENABLE_GL_WORK_QUEUE
sQueue = new GLWorkQueue();
@ -906,6 +1010,24 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask)
}
}
// list of mapped buffers
// NOTE: must not be LLPointer<LLVertexBuffer> to avoid breaking non-ref-counted LLVertexBuffer instances
static std::vector<LLVertexBuffer*> sMappedBuffers;
//static
void LLVertexBuffer::flushBuffers()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
// must only be called from main thread
for (auto& buffer : sMappedBuffers)
{
buffer->_unmapBuffer();
buffer->mMapped = false;
}
sMappedBuffers.resize(0);
}
//static
U32 LLVertexBuffer::calcOffsets(const U32& typemask, U32* offsets, U32 num_vertices)
{
@ -949,6 +1071,12 @@ U32 LLVertexBuffer::calcVertexSize(const U32& typemask)
//virtual
LLVertexBuffer::~LLVertexBuffer()
{
if (mMapped)
{ // is on the mapped buffer list but doesn't need to be flushed
mMapped = false;
unmapBuffer();
}
destroyGLBuffer();
destroyGLIndices();
@ -1150,34 +1278,36 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, U32 start, U32 end)
U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 index, S32 count)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
_mapBuffer();
if (count == -1)
{
count = mNumVerts - index;
}
#if !LL_DARWIN
U32 start = mOffsets[type] + sTypeSize[type] * index;
U32 end = start + sTypeSize[type] * count-1;
bool flagged = false;
// flag region as mapped
for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
if (!gGLManager.mIsApple)
{
MappedRegion& region = mMappedVertexRegions[i];
if (expand_region(region, start, end))
U32 start = mOffsets[type] + sTypeSize[type] * index;
U32 end = start + sTypeSize[type] * count-1;
bool flagged = false;
// flag region as mapped
for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
{
flagged = true;
break;
MappedRegion& region = mMappedVertexRegions[i];
if (expand_region(region, start, end))
{
flagged = true;
break;
}
}
if (!flagged)
{
//didn't expand an existing region, make a new one
mMappedVertexRegions.push_back({ start, end });
}
}
if (!flagged)
{
//didn't expand an existing region, make a new one
mMappedVertexRegions.push_back({ start, end });
}
#endif
return mMappedData+mOffsets[type]+sTypeSize[type]*index;
}
@ -1185,35 +1315,37 @@ U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 inde
U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
_mapBuffer();
if (count == -1)
{
count = mNumIndices-index;
}
#if !LL_DARWIN
U32 start = sizeof(U16) * index;
U32 end = start + sizeof(U16) * count-1;
bool flagged = false;
// flag region as mapped
for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
if (!gGLManager.mIsApple)
{
MappedRegion& region = mMappedIndexRegions[i];
if (expand_region(region, start, end))
U32 start = sizeof(U16) * index;
U32 end = start + sizeof(U16) * count-1;
bool flagged = false;
// flag region as mapped
for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
{
flagged = true;
break;
MappedRegion& region = mMappedIndexRegions[i];
if (expand_region(region, start, end))
{
flagged = true;
break;
}
}
if (!flagged)
{
//didn't expand an existing region, make a new one
mMappedIndexRegions.push_back({ start, end });
}
}
if (!flagged)
{
//didn't expand an existing region, make a new one
mMappedIndexRegions.push_back({ start, end });
}
#endif
return mMappedIndexData + sizeof(U16)*index;
}
@ -1225,39 +1357,64 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)
// dst -- mMappedData or mMappedIndexData
void LLVertexBuffer::flush_vbo(GLenum target, U32 start, U32 end, void* data, U8* dst)
{
#if LL_DARWIN
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb memcpy");
STOP_GLERROR;
// copy into mapped buffer
memcpy(dst+start, data, end-start+1);
#else
llassert(target == GL_ARRAY_BUFFER ? sGLRenderBuffer == mGLBuffer : sGLRenderIndices == mGLIndices);
// skip mapped data and stream to GPU via glBufferSubData
if (end != 0)
if (gGLManager.mIsApple)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData");
LL_PROFILE_ZONE_NUM(start);
LL_PROFILE_ZONE_NUM(end);
LL_PROFILE_ZONE_NUM(end-start);
// on OS X, flush_vbo doesn't actually write to the GL buffer, so be sure to call
// _mapBuffer to tag the buffer for flushing to GL
_mapBuffer();
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb memcpy");
STOP_GLERROR;
// copy into mapped buffer
memcpy(dst+start, data, end-start+1);
}
else
{
llassert(target == GL_ARRAY_BUFFER ? sGLRenderBuffer == mGLBuffer : sGLRenderIndices == mGLIndices);
constexpr U32 block_size = 8192;
for (U32 i = start; i <= end; i += block_size)
// skip mapped data and stream to GPU via glBufferSubData
if (end != 0)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData block");
//LL_PROFILE_GPU_ZONE("glBufferSubData");
U32 tend = llmin(i + block_size, end);
U32 size = tend - i + 1;
glBufferSubData(target, i, size, (U8*) data + (i-start));
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData");
LL_PROFILE_ZONE_NUM(start);
LL_PROFILE_ZONE_NUM(end);
LL_PROFILE_ZONE_NUM(end-start);
constexpr U32 block_size = 65536;
for (U32 i = start; i <= end; i += block_size)
{
//LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData block");
//LL_PROFILE_GPU_ZONE("glBufferSubData");
U32 tend = llmin(i + block_size, end);
U32 size = tend - i + 1;
glBufferSubData(target, i, size, (U8*) data + (i-start));
}
}
}
#endif
}
void LLVertexBuffer::unmapBuffer()
{
flushBuffers();
}
void LLVertexBuffer::_mapBuffer()
{
if (!mMapped)
{
mMapped = true;
sMappedBuffers.push_back(this);
}
}
void LLVertexBuffer::_unmapBuffer()
{
STOP_GLERROR;
if (!mMapped)
{
return;
}
struct SortMappedRegion
{
bool operator()(const MappedRegion& lhs, const MappedRegion& rhs)
@ -1266,114 +1423,116 @@ void LLVertexBuffer::unmapBuffer()
}
};
#if LL_DARWIN
STOP_GLERROR;
if (mMappedData)
if (gGLManager.mIsApple)
{
if (mGLBuffer)
STOP_GLERROR;
if (mMappedData)
{
glDeleteBuffers(1, &mGLBuffer);
if (mGLBuffer)
{
delete_buffers(1, &mGLBuffer);
}
mGLBuffer = gen_buffer();
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
glBufferData(GL_ARRAY_BUFFER, mSize, mMappedData, GL_STATIC_DRAW);
}
mGLBuffer = gen_buffer();
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
glBufferData(GL_ARRAY_BUFFER, mSize, mMappedData, GL_STATIC_DRAW);
}
else if (mGLBuffer != sGLRenderBuffer)
{
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
}
STOP_GLERROR;
if (mMappedIndexData)
{
if (mGLIndices)
{
glDeleteBuffers(1, &mGLIndices);
}
mGLIndices = gen_buffer();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mMappedIndexData, GL_STATIC_DRAW);
}
else if (mGLIndices != sGLRenderIndices)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
}
STOP_GLERROR;
#else
if (!mMappedVertexRegions.empty())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex");
if (sGLRenderBuffer != mGLBuffer)
else if (mGLBuffer != sGLRenderBuffer)
{
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
}
STOP_GLERROR;
U32 start = 0;
U32 end = 0;
std::sort(mMappedVertexRegions.begin(), mMappedVertexRegions.end(), SortMappedRegion());
for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
if (mMappedIndexData)
{
const MappedRegion& region = mMappedVertexRegions[i];
if (region.mStart == end + 1)
if (mGLIndices)
{
end = region.mEnd;
}
else
{
flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
start = region.mStart;
end = region.mEnd;
delete_buffers(1, &mGLIndices);
}
mGLIndices = gen_buffer();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mMappedIndexData, GL_STATIC_DRAW);
}
flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
mMappedVertexRegions.clear();
}
if (!mMappedIndexRegions.empty())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index");
if (mGLIndices != sGLRenderIndices)
else if (mGLIndices != sGLRenderIndices)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
}
U32 start = 0;
U32 end = 0;
std::sort(mMappedIndexRegions.begin(), mMappedIndexRegions.end(), SortMappedRegion());
for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
STOP_GLERROR;
}
else
{
if (!mMappedVertexRegions.empty())
{
const MappedRegion& region = mMappedIndexRegions[i];
if (region.mStart == end + 1)
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex");
if (sGLRenderBuffer != mGLBuffer)
{
end = region.mEnd;
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
}
else
U32 start = 0;
U32 end = 0;
std::sort(mMappedVertexRegions.begin(), mMappedVertexRegions.end(), SortMappedRegion());
for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
{
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
start = region.mStart;
end = region.mEnd;
const MappedRegion& region = mMappedVertexRegions[i];
if (region.mStart == end + 1)
{
end = region.mEnd;
}
else
{
flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
start = region.mStart;
end = region.mEnd;
}
}
flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
mMappedVertexRegions.clear();
}
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
mMappedIndexRegions.clear();
if (!mMappedIndexRegions.empty())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index");
if (mGLIndices != sGLRenderIndices)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
}
U32 start = 0;
U32 end = 0;
std::sort(mMappedIndexRegions.begin(), mMappedIndexRegions.end(), SortMappedRegion());
for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
{
const MappedRegion& region = mMappedIndexRegions[i];
if (region.mStart == end + 1)
{
end = region.mEnd;
}
else
{
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
start = region.mStart;
end = region.mEnd;
}
}
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
mMappedIndexRegions.clear();
}
}
#endif
}
//----------------------------------------------------------------------------
@ -1495,12 +1654,13 @@ bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, U32 in
void LLVertexBuffer::setBuffer()
{
STOP_GLERROR;
#if LL_DARWIN
if (!mGLBuffer)
{ // OS X doesn't allocate a buffer until we call unmapBuffer
return;
if (mMapped)
{
LL_WARNS_ONCE() << "Missing call to unmapBuffer or flushBuffers" << LL_ENDL;
_unmapBuffer();
}
#endif
// no data may be pending
llassert(mMappedVertexRegions.empty());
llassert(mMappedIndexRegions.empty());

View File

@ -38,6 +38,7 @@
#include <set>
#include <vector>
#include <list>
#include <glm/gtc/matrix_transform.hpp>
#define LL_MAX_VERTEX_ATTRIB_LOCATION 64
@ -53,6 +54,41 @@
//============================================================================
// base class
class LLPrivateMemoryPool;
class LLVertexBuffer;
class LLVertexBufferData
{
public:
LLVertexBufferData()
: mVB(nullptr)
, mMode(0)
, mCount(0)
, mTexName(0)
, mProjection(glm::identity<glm::mat4>())
, mModelView(glm::identity<glm::mat4>())
, mTexture0(glm::identity<glm::mat4>())
{}
LLVertexBufferData(LLVertexBuffer* buffer, U8 mode, U32 count, U32 tex_name, const glm::mat4& model_view, const glm::mat4& projection, const glm::mat4& texture0)
: mVB(buffer)
, mMode(mode)
, mCount(count)
, mTexName(tex_name)
, mProjection(model_view)
, mModelView(projection)
, mTexture0(texture0)
{}
void drawWithMatrix();
void draw();
LLPointer<LLVertexBuffer> mVB;
U8 mMode;
U32 mCount;
U32 mTexName;
glm::mat4 mProjection;
glm::mat4 mModelView;
glm::mat4 mTexture0;
};
typedef std::list<LLVertexBufferData> buffer_data_list_t;
class LLVertexBuffer final : public LLRefCount
{
public:
@ -89,6 +125,9 @@ public:
// indexed by the following enum
static U32 calcOffsets(const U32& typemask, U32* offsets, U32 num_vertices);
// flush any pending mapped buffers
static void flushBuffers();
//WARNING -- when updating these enums you MUST
// 1 - update LLVertexBuffer::sTypeSize
// 2 - update LLVertexBuffer::vb_type_name
@ -159,6 +198,8 @@ public:
// map for data access (see also getFooStrider below)
U8* mapVertexBuffer(AttributeType type, U32 index, S32 count = -1);
U8* mapIndexBuffer(U32 index, S32 count = -1);
// synonym for flushBuffers
void unmapBuffer();
// set for rendering
@ -281,6 +322,13 @@ private:
bool allocateBuffer(S32 nverts, S32 nindices, bool create) { return allocateBuffer(nverts, nindices); }
// actually unmap buffer
void _unmapBuffer();
// add to set of mapped buffers
void _mapBuffer();
bool mMapped = false;
public:
static U64 getBytesAllocated();

View File

@ -27,6 +27,8 @@
#define LLBADGE_CPP
#include "llbadge.h"
#include "llfontgl.h"
#include "llfontvertexbuffer.h"
#include "llscrollcontainer.h"
#include "lluictrlfactory.h"
@ -202,13 +204,13 @@ void renderBadgeBackground(F32 centerX, F32 centerY, F32 width, F32 height, cons
(F32)ll_round(x) + width,
(F32)ll_round(y) + height);
LLVector3 vertices[4];
vertices[0] = LLVector3(screen_rect.mRight, screen_rect.mTop, 1.0f);
vertices[1] = LLVector3(screen_rect.mLeft, screen_rect.mTop, 1.0f);
vertices[2] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 1.0f);
vertices[3] = LLVector3(screen_rect.mRight, screen_rect.mBottom, 1.0f);
LLVector4a vertices[4];
vertices[0].set(screen_rect.mLeft, screen_rect.mTop, 1.0f);
vertices[1].set(screen_rect.mRight, screen_rect.mTop, 1.0f);
vertices[2].set(screen_rect.mLeft, screen_rect.mBottom, 1.0f);
vertices[3].set(screen_rect.mRight, screen_rect.mBottom, 1.0f);
gGL.begin(LLRender::QUADS);
gGL.begin(LLRender::TRIANGLE_STRIP);
{
gGL.vertexBatchPreTransformed(vertices, 4);
}
@ -351,17 +353,17 @@ void LLBadge::draw()
//
// Draw the label
//
mGLFont->render(mLabel.getWString(),
badge_label_begin_offset,
badge_center_x + mLabelOffsetHoriz,
badge_center_y + mLabelOffsetVert,
mLabelColor % alpha,
LLFontGL::HCENTER, LLFontGL::VCENTER, // centered around the position
LLFontGL::NORMAL, // normal text (not bold, italics, etc.)
LLFontGL::DROP_SHADOW_SOFT,
badge_char_length, badge_pixel_length,
right_position_out, do_not_use_ellipses);
mFontBuffer.render(mGLFont,
mLabel.getWString(),
badge_label_begin_offset,
badge_center_x + mLabelOffsetHoriz,
badge_center_y + mLabelOffsetVert,
mLabelColor % alpha,
LLFontGL::HCENTER, LLFontGL::VCENTER, // centered around the position
LLFontGL::NORMAL, // normal text (not bold, italics, etc.)
LLFontGL::DROP_SHADOW_SOFT,
badge_char_length, badge_pixel_length,
right_position_out, do_not_use_ellipses);
}
}
}

View File

@ -34,12 +34,14 @@
#include "llstring.h"
#include "lluiimage.h"
#include "llview.h"
#include "llfontvertexbuffer.h"
//
// Declarations
//
class LLFontGL;
class LLFontVertexBuffer;
class LLScrollContainer;
class LLUICtrlFactory;
@ -144,6 +146,7 @@ private:
LLUIColor mBorderColor;
const LLFontGL* mGLFont;
LLFontVertexBuffer mFontBuffer;
LLPointer< LLUIImage > mImage;
LLUIColor mImageColor;

View File

@ -43,6 +43,8 @@
#include "llfloater.h"
#include "llfloaterreg.h"
#include "llfocusmgr.h"
#include "llfontgl.h"
#include "llfontvertexbuffer.h"
#include "llwindow.h"
#include "llnotificationsutil.h"
#include "llrender.h"
@ -120,11 +122,10 @@ LLButton::Params::Params()
LLButton::LLButton(const LLButton::Params& p)
: LLUICtrl(p),
: LLUICtrl(p),
LLBadgeOwner(getHandle()),
mMouseDownFrame(0),
mMouseHeldDownCount(0),
mBorderEnabled( false ),
mFlashing( false ),
mCurGlowStrength(0.f),
mNeedsHighlight(false),
@ -329,6 +330,30 @@ void LLButton::onCommit()
LLUICtrl::onCommit();
}
void LLButton::setUnselectedLabelColor(const LLUIColor& c)
{
mUnselectedLabelColor = c;
mFontBuffer.reset();
}
void LLButton::setSelectedLabelColor(const LLUIColor& c)
{
mSelectedLabelColor = c;
mFontBuffer.reset();
}
void LLButton::setUseEllipses(bool use_ellipses)
{
mUseEllipses = use_ellipses;
mFontBuffer.reset();
}
void LLButton::setUseFontColor(bool use_font_color)
{
mUseFontColor = use_font_color;
mFontBuffer.reset();
}
boost::signals2::connection LLButton::setClickedCallback(const CommitCallbackParam& cb)
{
return setClickedCallback(initCommitCallback(cb));
@ -396,6 +421,18 @@ bool LLButton::postBuild()
return LLUICtrl::postBuild();
}
void LLButton::onVisibilityChange(bool new_visibility)
{
mFontBuffer.reset();
return LLUICtrl::onVisibilityChange(new_visibility);
}
void LLButton::dirtyRect()
{
LLUICtrl::dirtyRect();
mFontBuffer.reset();
}
bool LLButton::handleUnicodeCharHere(llwchar uni_char)
{
bool handled = false;
@ -582,19 +619,25 @@ void LLButton::onMouseLeave(S32 x, S32 y, MASK mask)
{
LLUICtrl::onMouseLeave(x, y, mask);
mNeedsHighlight = false;
setHighlight(false);
}
void LLButton::setHighlight(bool b)
{
mNeedsHighlight = b;
if (mNeedsHighlight != b)
{
mNeedsHighlight = b;
mFontBuffer.reset();
}
}
bool LLButton::handleHover(S32 x, S32 y, MASK mask)
{
if (isInEnabledChain()
&& (!gFocusMgr.getMouseCapture() || gFocusMgr.getMouseCapture() == this))
mNeedsHighlight = true;
{
setHighlight(true);
}
if (!childrenHandleHover(x, y, mask))
{
@ -954,7 +997,7 @@ void LLButton::draw()
// LLFontGL::render expects S32 max_chars variable but process in a separate way -1 value.
// Due to U32_MAX is equal to S32 -1 value I have rest this value for non-ellipses mode.
// Not sure if it is really needed. Probably S32_MAX should be always passed as max_chars.
mLastDrawCharsCount = mGLFont->render(label, 0,
mLastDrawCharsCount = mFontBuffer.render(mGLFont, label, 0,
(F32)x,
(F32)(getRect().getHeight() / 2 + mBottomVPad),
label_color % alpha,
@ -996,6 +1039,7 @@ void LLButton::setToggleState(bool b)
setFlashing(false); // stop flash state whenever the selected/unselected state if reset
// Unselected label assignments
autoResize();
mFontBuffer.reset();
}
}
@ -1025,11 +1069,13 @@ bool LLButton::toggleState()
void LLButton::setLabel( const std::string& label )
{
mUnselectedLabel = mSelectedLabel = label;
mFontBuffer.reset();
}
void LLButton::setLabel( const LLUIString& label )
{
mUnselectedLabel = mSelectedLabel = label;
mFontBuffer.reset();
}
void LLButton::setLabel( const LLStringExplicit& label )
@ -1043,17 +1089,32 @@ bool LLButton::setLabelArg( const std::string& key, const LLStringExplicit& text
{
mUnselectedLabel.setArg(key, text);
mSelectedLabel.setArg(key, text);
mFontBuffer.reset();
return true;
}
void LLButton::setLabelUnselected( const LLStringExplicit& label )
{
mUnselectedLabel = label;
mFontBuffer.reset();
}
void LLButton::setLabelSelected( const LLStringExplicit& label )
{
mSelectedLabel = label;
mFontBuffer.reset();
}
void LLButton::setDisabledLabelColor(const LLUIColor& c)
{
mDisabledLabelColor = c;
mFontBuffer.reset();
}
void LLButton::setFont(const LLFontGL* font)
{
mGLFont = (font ? font : LLFontGL::getFontSansSerif());
mFontBuffer.reset();
}
bool LLButton::labelIsTruncated() const
@ -1066,6 +1127,12 @@ const LLUIString& LLButton::getCurrentLabel() const
return getToggleState() ? mSelectedLabel : mUnselectedLabel;
}
void LLButton::setDropShadowedText(bool b)
{
mDropShadowedText = b;
mFontBuffer.reset();
}
void LLButton::setImageUnselected(LLPointer<LLUIImage> image)
{
mImageUnselected = image;
@ -1149,6 +1216,7 @@ void LLButton::setImageDisabledSelected(LLPointer<LLUIImage> image)
mImageDisabledSelected = image;
mDisabledImageColor = mImageColor;
mFadeWhenDisabled = true;
mFontBuffer.reset();
}
void LLButton::setImagePressed(LLPointer<LLUIImage> image)

View File

@ -34,7 +34,6 @@
#include "lluictrl.h"
#include "v4color.h"
#include "llframetimer.h"
#include "llfontgl.h"
#include "lluiimage.h"
#include "lluistring.h"
@ -55,6 +54,8 @@ S32 round_up(S32 grid, S32 value);
class LLUICtrlFactory;
class LLFontGL;
class LLFontVertexBuffer;
//
// Classes
@ -156,26 +157,29 @@ public:
void addImageAttributeToXML(LLXMLNodePtr node, const std::string& imageName,
const LLUUID& imageID,const std::string& xmlTagName) const;
virtual bool handleUnicodeCharHere(llwchar uni_char);
virtual bool handleKeyHere(KEY key, MASK mask);
virtual bool handleMouseDown(S32 x, S32 y, MASK mask);
virtual bool handleMouseUp(S32 x, S32 y, MASK mask);
virtual bool handleHover(S32 x, S32 y, MASK mask);
virtual bool handleRightMouseDown(S32 x, S32 y, MASK mask);
virtual bool handleRightMouseUp(S32 x, S32 y, MASK mask);
virtual bool handleDoubleClick(S32 x, S32 y, MASK mask);
virtual void draw();
/*virtual*/ bool postBuild();
virtual bool handleUnicodeCharHere(llwchar uni_char) override;
virtual bool handleKeyHere(KEY key, MASK mask) override;
virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override;
virtual bool handleMouseUp(S32 x, S32 y, MASK mask) override;
virtual bool handleHover(S32 x, S32 y, MASK mask) override;
virtual bool handleRightMouseDown(S32 x, S32 y, MASK mask) override;
virtual bool handleRightMouseUp(S32 x, S32 y, MASK mask) override;
virtual bool handleDoubleClick(S32 x, S32 y, MASK mask) override;
virtual void draw() override;
/*virtual*/ bool postBuild() override;
virtual void onMouseLeave(S32 x, S32 y, MASK mask);
virtual void onMouseCaptureLost();
void onVisibilityChange(bool visible) override;
void dirtyRect() override;
virtual void onCommit();
virtual void onMouseLeave(S32 x, S32 y, MASK mask) override;
virtual void onMouseCaptureLost() override;
void setUnselectedLabelColor( const LLUIColor& c ) { mUnselectedLabelColor = c; }
void setSelectedLabelColor( const LLUIColor& c ) { mSelectedLabelColor = c; }
void setUseEllipses( bool use_ellipses ) { mUseEllipses = use_ellipses; }
void setUseFontColor( bool use_font_color) { mUseFontColor = use_font_color; }
virtual void onCommit() override;
void setUnselectedLabelColor(const LLUIColor& c);
void setSelectedLabelColor(const LLUIColor& c);
void setUseEllipses(bool use_ellipses);
void setUseFontColor(bool use_font_color);
boost::signals2::connection setClickedCallback(const CommitCallbackParam& cb);
@ -223,9 +227,8 @@ public:
const std::string getLabelUnselected() const { return wstring_to_utf8str(mUnselectedLabel); }
const std::string getLabelSelected() const { return wstring_to_utf8str(mSelectedLabel); }
void setImageColor(const std::string& color_control);
void setImageColor(const LLUIColor& c);
/*virtual*/ void setColor(const LLUIColor& c);
/*virtual*/ void setColor(const LLUIColor& c) override;
void setImages(const std::string &image_name, const std::string &selected_name);
@ -243,15 +246,14 @@ public:
void setLabel(const std::string& label);
void setLabel(const LLUIString& label);
void setLabel( const LLStringExplicit& label);
virtual bool setLabelArg( const std::string& key, const LLStringExplicit& text );
virtual bool setLabelArg( const std::string& key, const LLStringExplicit& text ) override;
void setLabelUnselected(const LLStringExplicit& label);
void setLabelSelected(const LLStringExplicit& label);
void setDisabledLabelColor( const LLUIColor& c ) { mDisabledLabelColor = c; }
void setDisabledLabelColor(const LLUIColor& c);
void setFont(const LLFontGL *font)
{ mGLFont = ( font ? font : LLFontGL::getFontSansSerif()); }
const LLFontGL* getFont() const { return mGLFont; }
const std::string& getText() const { return getCurrentLabel().getString(); }
void setFont(const LLFontGL* font);
const LLFontGL* getFont() const override { return mGLFont; }
const std::string& getText() const override { return getCurrentLabel().getString(); }
S32 getLastDrawCharsCount() const { return mLastDrawCharsCount; }
bool labelIsTruncated() const;
@ -260,9 +262,7 @@ public:
void setScaleImage(bool scale) { mScaleImage = scale; }
bool getScaleImage() const { return mScaleImage; }
void setDropShadowedText(bool b) { mDropShadowedText = b; }
void setBorderEnabled(bool b) { mBorderEnabled = b; }
void setDropShadowedText(bool b);
void setHoverGlowStrength(F32 strength) { mHoverGlowStrength = strength; }
@ -278,7 +278,6 @@ public:
void setCommitOnReturn(bool commit) { mCommitOnReturn = commit; }
bool getCommitOnReturn() const { return mCommitOnReturn; }
static void onHeldDown(void *userdata); // to be called by gIdleCallbacks
static void toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname);
static void setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname);
static void setDockableFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname);
@ -305,8 +304,6 @@ protected:
commit_signal_t* mMouseUpSignal;
commit_signal_t* mHeldDownSignal;
const LLFontGL* mGLFont;
S32 mMouseDownFrame;
S32 mMouseHeldDownCount; // Counter for parameter passed to held-down callback
F32 mHeldDownDelay; // seconds, after which held-down callbacks get called
@ -358,7 +355,6 @@ protected:
bool mAutoResize;
bool mUseEllipses;
bool mUseFontColor;
bool mBorderEnabled;
bool mFlashing;
LLFontGL::HAlign mHAlign;
@ -390,8 +386,12 @@ protected:
bool mForceFlashing; // Stick flashing color even if button is pressed
bool mHandleRightMouse;
private:
const LLFontGL* mGLFont;
LLFontVertexBuffer mFontBuffer;
protected:
virtual std::string _getSearchText() const
virtual std::string _getSearchText() const override
{
return getLabelUnselected() + getToolTip();
}

View File

@ -107,7 +107,7 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)
button_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_BOTTOM|FOLLOWS_RIGHT);
button_params.rect(p.rect);
if(mAllowTextEntry)
if (mAllowTextEntry)
{
button_params.pad_right(2);
}
@ -121,7 +121,7 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)
mButton = LLUICtrlFactory::create<LLButton>(button_params);
if(mAllowTextEntry)
if (mAllowTextEntry)
{
//redo to compensate for button hack that leaves space for a character
//unless it is a "minimal combobox"(drop down)
@ -207,14 +207,27 @@ void LLComboBox::clear()
void LLComboBox::onCommit()
{
if (mAllowTextEntry && getCurrentIndex() != -1)
if (LLScrollListItem* item = mList->getFirstSelected())
{
// we have selected an existing item, blitz the manual text entry with
// the properly capitalized item
mTextEntry->setValue(getSimple());
mTextEntry->setTentative(false);
if (mAllowTextEntry && mTextEntry)
{
// we have selected an existing item, blitz the manual text entry with
// the properly capitalized item
LLSD label = item->getColumn(0)->getValue();
mTextEntry->setValue(label);
mTextEntry->setTentative(false);
}
setControlValue(item->getValue());
}
setControlValue(getValue());
else if (mAllowTextEntry)
{
setControlValue(mTextEntry->getValue());
}
else
{
setControlValue(LLSD());
}
LLUICtrl::onCommit();
}
@ -349,6 +362,13 @@ bool LLComboBox::setSimple(const LLStringExplicit& name)
// virtual
void LLComboBox::setValue(const LLSD& value)
{
if (LLScrollListItem* item = mList->getFirstSelected())
{
LLSD item_value = item->getValue();
if (item_value.asString() == value.asString())
return;
}
bool found = mList->selectByValue(value);
if (found)
{
@ -372,10 +392,8 @@ const std::string LLComboBox::getSimple() const
{
return mTextEntry->getText();
}
else
{
return res;
}
return res;
}
const std::string LLComboBox::getSelectedItemLabel(S32 column) const
@ -386,24 +404,22 @@ const std::string LLComboBox::getSelectedItemLabel(S32 column) const
// virtual
LLSD LLComboBox::getValue() const
{
LLScrollListItem* item = mList->getFirstSelected();
if( item )
if (LLScrollListItem* item = mList->getFirstSelected())
{
return item->getValue();
}
else if (mAllowTextEntry)
if (mAllowTextEntry)
{
return mTextEntry->getValue();
}
else
{
return LLSD();
}
return LLSD();
}
void LLComboBox::setLabel(const LLStringExplicit& name)
{
if ( mTextEntry )
if (mTextEntry)
{
mTextEntry->setText(name);
if (mList->selectItemByLabel(name, false))
@ -498,27 +514,80 @@ void LLComboBox::setButtonVisible(bool visible)
}
}
bool LLComboBox::setCurrentByIndex( S32 index )
bool LLComboBox::setCurrentByIndex(S32 index)
{
bool found = mList->selectNthItem( index );
if (found)
if (LLScrollListItem* item = mList->getItemByIndex(index))
{
setLabel(getSelectedItemLabel());
mLastSelectedIndex = index;
if (item->getEnabled())
{
mList->selectItem(item, -1, true);
LLSD::String label = item->getColumn(0)->getValue().asString();
if (mTextEntry)
{
mTextEntry->setText(label);
mTextEntry->setTentative(false);
}
if (!mAllowTextEntry)
{
mButton->setLabel(label);
}
mLastSelectedIndex = index;
return true;
}
}
return found;
return false;
}
S32 LLComboBox::getCurrentIndex() const
{
LLScrollListItem* item = mList->getFirstSelected();
if( item )
if (LLScrollListItem* item = mList->getFirstSelected())
{
return mList->getItemIndex( item );
return mList->getItemIndex(item);
}
return -1;
}
bool LLComboBox::selectNextItem()
{
S32 last_index = getItemCount() - 1;
if (last_index < 0)
return false;
S32 current_index = getCurrentIndex();
if (current_index >= last_index)
return false;
S32 new_index = llmax(current_index, -1);
while (++new_index <= last_index)
{
if (setCurrentByIndex(new_index))
return true;
}
return false;
}
bool LLComboBox::selectPrevItem()
{
S32 last_index = getItemCount() - 1;
if (last_index < 0)
return false;
S32 current_index = getCurrentIndex();
if (!current_index)
return false;
S32 new_index = current_index > 0 ? current_index : last_index + 1;
while (--new_index >= 0)
{
if (setCurrentByIndex(new_index))
return true;
}
return false;
}
void LLComboBox::setEnabledByValue(const LLSD& value, bool enabled)
{
LLScrollListItem *found = mList->getItem(value);
@ -878,15 +947,46 @@ bool LLComboBox::handleUnicodeCharHere(llwchar uni_char)
// virtual
bool LLComboBox::handleScrollWheel(S32 x, S32 y, S32 clicks)
{
if (mList->getVisible()) return mList->handleScrollWheel(x, y, clicks);
if (mAllowTextEntry) // We might be editable
if (!mList->getFirstSelected()) // We aren't in the list, don't kill their text
return false;
if (mList->getVisible())
{
return mList->handleScrollWheel(x, y, clicks);
}
setCurrentByIndex(llclamp(getCurrentIndex() + clicks, 0, getItemCount() - 1));
prearrangeList();
onCommit();
return true;
if (mAllowTextEntry) // We might be editable
{
if (!mList->getFirstSelected()) // We aren't in the list, don't kill their text
{
return false;
}
}
S32 current_index = getCurrentIndex();
if (clicks > 0)
{
for (S32 i = 0; i < clicks; ++i)
{
if (!selectNextItem())
break;
}
}
else
{
for (S32 i = 0; i < -clicks; ++i)
{
if (!selectPrevItem())
break;
}
}
S32 new_index = getCurrentIndex();
if (new_index != current_index)
{
prearrangeList();
onCommit();
return true;
}
return false;
}
void LLComboBox::setTextEntry(const LLStringExplicit& text)

View File

@ -163,9 +163,12 @@ public:
bool remove(const std::string& name); // remove item "name", return true if found and removed
bool setCurrentByIndex( S32 index );
bool setCurrentByIndex(S32 index);
S32 getCurrentIndex() const;
bool selectNextItem();
bool selectPrevItem();
void setEnabledByValue(const LLSD& value, bool enabled);
void createLineEditor(const Params&);

View File

@ -1983,6 +1983,9 @@ void LLFloater::onClickCloseBtn(bool app_quitting)
// virtual
void LLFloater::draw()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
LL_PROFILE_ZONE_TEXT(getTitle().c_str(), getTitle().length());
const F32 alpha = getCurrentTransparency();
// draw background
@ -2039,21 +2042,6 @@ void LLFloater::draw()
LLPanel::updateDefaultBtn();
if( getDefaultButton() )
{
if (hasFocus() && getDefaultButton()->getEnabled())
{
LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus();
// is this button a direct descendent and not a nested widget (e.g. checkbox)?
bool focus_is_child_button = dynamic_cast<LLButton*>(focus_ctrl) != NULL && dynamic_cast<LLButton*>(focus_ctrl)->getParent() == this;
// only enable default button when current focus is not a button
getDefaultButton()->setBorderEnabled(!focus_is_child_button);
}
else
{
getDefaultButton()->setBorderEnabled(false);
}
}
if (isMinimized())
{
for (S32 i = 0; i < BUTTON_COUNT; i++)
@ -2287,36 +2275,28 @@ void LLFloater::drawConeToOwner(F32 &context_cone_opacity,
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
LLGLEnable(GL_CULL_FACE);
gGL.begin(LLRender::QUADS);
gGL.begin(LLRender::TRIANGLE_STRIP);
{
gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
gGL.vertex2i(local_rect.mRight, local_rect.mTop);
gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
gGL.vertex2i(local_rect.mRight, local_rect.mTop);
gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
}
gGL.end();
}

View File

@ -1649,7 +1649,7 @@ void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constr
{
LLRect local_rect = item->getLocalRect();
S32 icon_height = mIcon.isNull() ? 0 : mIcon->getHeight();
S32 label_height = getLabelFontForStyle(mLabelStyle)->getLineHeight();
S32 label_height = getLabelFont()->getLineHeight();
// when navigating with keyboard, only move top of opened folder on screen, otherwise show whole folder
S32 max_height_to_show = item->isOpen() && mScrollContainer->hasFocus() ? (llmax( icon_height, label_height ) + item->getIconPad()) : local_rect.getHeight();

View File

@ -48,7 +48,6 @@ static LLDefaultChildRegistry::Register<LLFolderViewItem> r("folder_view_item");
// statics
std::map<U8, LLFontGL*> LLFolderViewItem::sFonts; // map of styles to fonts
bool LLFolderViewItem::sColorSetInitialized = false;
LLUIColor LLFolderViewItem::sFgColor;
LLUIColor LLFolderViewItem::sHighlightBgColor;
LLUIColor LLFolderViewItem::sFlashBgColor;
@ -58,6 +57,10 @@ LLUIColor LLFolderViewItem::sFilterBGColor;
LLUIColor LLFolderViewItem::sFilterTextColor;
LLUIColor LLFolderViewItem::sSuffixColor;
LLUIColor LLFolderViewItem::sSearchStatusColor;
S32 LLFolderViewItem::sTopPad = 0;
LLUIImagePtr LLFolderViewItem::sFolderArrowImg;
LLUIImagePtr LLFolderViewItem::sSelectionImg;
LLFontGL* LLFolderViewItem::sSuffixFont = nullptr;
// only integers can be initialized in header
const F32 LLFolderViewItem::FOLDER_CLOSE_TIME_CONSTANT = 0.02f;
@ -83,15 +86,42 @@ LLFontGL* LLFolderViewItem::getLabelFontForStyle(U8 style)
return rtn;
}
const LLFontGL* LLFolderViewItem::getLabelFont()
{
if (!pLabelFont)
{
pLabelFont = getLabelFontForStyle(mLabelStyle);
}
return pLabelFont;
}
//static
void LLFolderViewItem::initClass()
{
const Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>();
sTopPad = default_params.item_top_pad;
sFolderArrowImg = default_params.folder_arrow_image;
sSelectionImg = default_params.selection_image;
sSuffixFont = getLabelFontForStyle(LLFontGL::NORMAL);
sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE);
sFlashBgColor = LLUIColorTable::instance().getColor("MenuItemFlashBgColor", DEFAULT_WHITE);
sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE);
sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE);
sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE);
sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE);
}
//static
void LLFolderViewItem::cleanupClass()
{
sFonts.clear();
sFolderArrowImg = nullptr;
sSelectionImg = nullptr;
sSuffixFont = nullptr;
}
@ -134,6 +164,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
mIsItemCut(false),
mCutGeneration(0),
mLabelStyle( LLFontGL::NORMAL ),
pLabelFont(nullptr),
mHasVisibleChildren(false),
mLocalIndentation(p.folder_indentation),
mIndentation(0),
@ -158,20 +189,6 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
mMaxFolderItemOverlap(p.max_folder_item_overlap),
mDoubleClickOverride(p.double_click_override)
{
if (!sColorSetInitialized)
{
sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE);
sFlashBgColor = LLUIColorTable::instance().getColor("MenuItemFlashBgColor", DEFAULT_WHITE);
sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE);
sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE);
sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE);
sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE);
sColorSetInitialized = true;
}
if (mViewModelItem)
{
mViewModelItem->setFolderViewItem(this);
@ -307,6 +324,7 @@ void LLFolderViewItem::refresh()
LLFolderViewModelItem& vmi = *getViewModelItem();
mLabel = utf8str_to_wstring(vmi.getDisplayName());
mLabelFontBuffer.reset();
setToolTip(vmi.getName());
// icons are slightly expensive to get, can be optimized
// see LLInventoryIcon::getIcon()
@ -319,7 +337,9 @@ void LLFolderViewItem::refresh()
// Very Expensive!
// Can do a number of expensive checks, like checking active motions, wearables or friend list
mLabelStyle = vmi.getLabelStyle();
pLabelFont = nullptr; // refresh can be called from a coro, don't use getLabelFontForStyle, coro trips font list tread safety
mLabelSuffix = utf8str_to_wstring(vmi.getLabelSuffix());
mSuffixFontBuffer.reset();
}
// Dirty the filter flag of the model from the view (CHUI-849)
@ -344,6 +364,7 @@ void LLFolderViewItem::refreshSuffix()
// Very Expensive!
// Can do a number of expensive checks, like checking active motions, wearables or friend list
mLabelStyle = vmi->getLabelStyle();
pLabelFont = nullptr;
mLabelSuffix = utf8str_to_wstring(vmi->getLabelSuffix());
}
@ -736,19 +757,17 @@ bool LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
return handled;
}
void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const LLUIColor& fg_color)
void LLFolderViewItem::drawOpenFolderArrow()
{
//--------------------------------------------------------------------------------//
// Draw open folder arrow
//
const S32 TOP_PAD = default_params.item_top_pad;
if (hasVisibleChildren() || !isFolderComplete())
{
LLUIImage* arrow_image = default_params.folder_arrow_image;
gl_draw_scaled_rotated_image(
mIndentation, getRect().getHeight() - mArrowSize - mTextPad - TOP_PAD,
mArrowSize, mArrowSize, mControlLabelRotation, arrow_image->getImage(), fg_color);
mIndentation, getRect().getHeight() - mArrowSize - mTextPad - sTopPad,
mArrowSize, mArrowSize, mControlLabelRotation, sFolderArrowImg->getImage(), sFgColor);
}
}
@ -764,7 +783,7 @@ void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const L
/*virtual*/ bool LLFolderViewItem::isFadeItem()
{
LLClipboard& clipboard = LLClipboard::instance();
static const LLClipboard& clipboard = LLClipboard::instance(); // Make it a 'simpleton'?
if (mCutGeneration != clipboard.getGeneration())
{
mCutGeneration = clipboard.getGeneration();
@ -775,8 +794,9 @@ void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const L
return mIsItemCut;
}
void LLFolderViewItem::drawHighlight(const bool showContent, const bool hasKeyboardFocus, const LLUIColor &selectColor, const LLUIColor &flashColor,
const LLUIColor &focusOutlineColor, const LLUIColor &mouseOverColor)
void LLFolderViewItem::drawHighlight(bool showContent, bool hasKeyboardFocus,
const LLUIColor& selectColor, const LLUIColor& flashColor,
const LLUIColor& focusOutlineColor, const LLUIColor& mouseOverColor)
{
const S32 focus_top = getRect().getHeight();
const S32 focus_bottom = getRect().getHeight() - mItemHeight;
@ -784,7 +804,7 @@ void LLFolderViewItem::drawHighlight(const bool showContent, const bool hasKeybo
const S32 FOCUS_LEFT = 1;
// Determine which background color to use for highlighting
const LLUIColor& bgColor = (isFlashing() ? flashColor : selectColor);
const LLUIColor& bgColor = isFlashing() ? flashColor : selectColor;
//--------------------------------------------------------------------------------//
// Draw highlight for selected items
@ -792,7 +812,6 @@ void LLFolderViewItem::drawHighlight(const bool showContent, const bool hasKeybo
// items if mShowSingleSelection is false.
//
if (isHighlightAllowed())
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@ -801,7 +820,7 @@ void LLFolderViewItem::drawHighlight(const bool showContent, const bool hasKeybo
{
LLColor4 bg_color = bgColor;
// do time-based fade of extra objects
F32 fade_time = (getRoot() ? getRoot()->getSelectionFadeElapsedTime() : 0.0f);
F32 fade_time = getRoot() ? getRoot()->getSelectionFadeElapsedTime() : 0.f;
if (getRoot() && getRoot()->getShowSingleSelection())
{
// fading out
@ -890,7 +909,7 @@ void LLFolderViewItem::drawLabel(const LLFontGL * font, const F32 x, const F32 y
//--------------------------------------------------------------------------------//
// Draw the actual label text
//
font->render(mLabel, 0, x, y, color,
mLabelFontBuffer.render(font, mLabel, 0, x, y, color,
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
S32_MAX, getRect().getWidth() - (S32) x - mLabelPaddingRight, &right_x, /*use_ellipses*/true);
}
@ -900,16 +919,14 @@ void LLFolderViewItem::draw()
const bool show_context = (getRoot() ? getRoot()->getShowSelectionContext() : false);
const bool filled = show_context || (getRoot() ? getRoot()->getParentPanel()->hasFocus() : false); // If we have keyboard focus, draw selection filled
const Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>();
const S32 TOP_PAD = default_params.item_top_pad;
const LLFontGL* font = getLabelFontForStyle(mLabelStyle);
const LLFontGL* font = getLabelFont();
S32 line_height = font->getLineHeight();
getViewModelItem()->update();
if(!mSingleFolderMode)
if (!mSingleFolderMode)
{
drawOpenFolderArrow(default_params, sFgColor);
drawOpenFolderArrow();
}
drawHighlight(show_context, filled, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor);
@ -918,18 +935,19 @@ void LLFolderViewItem::draw()
// Draw open icon
//
const S32 icon_x = mIndentation + mArrowSize + mTextPad;
const S32 rect_height = getRect().getHeight();
if (!mIconOpen.isNull() && (llabs(mControlLabelRotation) > 80)) // For open folders
{
mIconOpen->draw(icon_x, getRect().getHeight() - mIconOpen->getHeight() - TOP_PAD + 1);
mIconOpen->draw(icon_x, rect_height - mIconOpen->getHeight() - sTopPad + 1);
}
else if (mIcon)
{
mIcon->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1);
mIcon->draw(icon_x, rect_height - mIcon->getHeight() - sTopPad + 1);
}
if (mIconOverlay && getRoot()->showItemLinkOverlays())
{
mIconOverlay->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1);
mIconOverlay->draw(icon_x, rect_height - mIcon->getHeight() - sTopPad + 1);
}
//--------------------------------------------------------------------------------//
@ -940,26 +958,24 @@ void LLFolderViewItem::draw()
return;
}
auto filter_string_length = mViewModelItem->hasFilterStringMatch() ? static_cast<S32>(mViewModelItem->getFilterStringSize()) : 0;
S32 filter_string_length = mViewModelItem->hasFilterStringMatch() ? (S32)mViewModelItem->getFilterStringSize() : 0;
F32 right_x = 0;
F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
F32 y = (F32)rect_height - line_height - (F32)mTextPad - (F32)sTopPad;
F32 text_left = (F32)getLabelXPos();
LLWString combined_string = mLabel + mLabelSuffix;
const LLFontGL* suffix_font = getLabelFontForStyle(LLFontGL::NORMAL);
S32 filter_offset = static_cast<S32>(mViewModelItem->getFilterStringOffset());
if (filter_string_length > 0)
{
S32 bottom = getRect().getHeight() - font->getLineHeight() - 3 - TOP_PAD;
S32 top = getRect().getHeight() - TOP_PAD;
if(mLabelSuffix.empty() || (font == suffix_font))
S32 bottom = rect_height - line_height - 3 - sTopPad;
S32 top = rect_height - sTopPad;
if(mLabelSuffix.empty() || (font == sSuffixFont))
{
S32 left = ll_round(text_left) + font->getWidth(combined_string.c_str(), 0, static_cast<S32>(mViewModelItem->getFilterStringOffset())) - 2;
S32 right = left + font->getWidth(combined_string.c_str(), static_cast<S32>(mViewModelItem->getFilterStringOffset()), filter_string_length) + 2;
S32 left = ll_round(text_left) + font->getWidth(combined_string.c_str(), 0, filter_offset) - 2;
S32 right = left + font->getWidth(combined_string.c_str(), filter_offset, filter_string_length) + 2;
LLUIImage* box_image = default_params.selection_image;
LLRect box_rect(left, top, right, bottom);
box_image->draw(box_rect, sFilterBGColor);
LLRect box_rect(left, top, right, bottom);
sSelectionImg->draw(box_rect, sFilterBGColor);
}
else
{
@ -968,19 +984,17 @@ void LLFolderViewItem::draw()
{
S32 left = (S32)(ll_round(text_left) + font->getWidthF32(mLabel.c_str(), 0, llmin(filter_offset, (S32)mLabel.size()))) - 2;
S32 right = left + (S32)font->getWidthF32(mLabel.c_str(), filter_offset, label_filter_length) + 2;
LLUIImage* box_image = default_params.selection_image;
LLRect box_rect(left, top, right, bottom);
box_image->draw(box_rect, sFilterBGColor);
sSelectionImg->draw(box_rect, sFilterBGColor);
}
S32 suffix_filter_length = label_filter_length > 0 ? filter_string_length - label_filter_length : filter_string_length;
if(suffix_filter_length > 0)
{
S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size());
S32 left = (S32)(ll_round(text_left) + font->getWidthF32(mLabel.c_str(), 0, static_cast<S32>(mLabel.size())) + suffix_font->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset)) - 2;
S32 right = left + (S32)suffix_font->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length) + 2;
LLUIImage* box_image = default_params.selection_image;
S32 left = (S32)(ll_round(text_left) + font->getWidthF32(mLabel.c_str(), 0, static_cast<S32>(mLabel.size())) + sSuffixFont->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset)) - 2;
S32 right = left + (S32)sSuffixFont->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length) + 2;
LLRect box_rect(left, top, right, bottom);
box_image->draw(box_rect, sFilterBGColor);
sSelectionImg->draw(box_rect, sFilterBGColor);
}
}
}
@ -999,9 +1013,9 @@ void LLFolderViewItem::draw()
//
if (!mLabelSuffix.empty())
{
suffix_font->render( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : sSuffixColor.get(),
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
S32_MAX, S32_MAX, &right_x);
mSuffixFontBuffer.render(sSuffixFont, mLabelSuffix, 0, right_x, y, isFadeItem() ? color : sSuffixColor.get(),
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
S32_MAX, S32_MAX, &right_x);
}
//--------------------------------------------------------------------------------//
@ -1009,10 +1023,10 @@ void LLFolderViewItem::draw()
//
if (filter_string_length > 0)
{
if(mLabelSuffix.empty() || (font == suffix_font))
if(mLabelSuffix.empty() || (font == sSuffixFont))
{
F32 match_string_left = text_left + font->getWidthF32(combined_string.c_str(), 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string.c_str(), filter_offset, filter_string_length);
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
F32 yy = (F32)rect_height - line_height - (F32)mTextPad - (F32)sTopPad;
font->render(combined_string, filter_offset, match_string_left, yy,
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
filter_string_length, S32_MAX, &right_x);
@ -1023,7 +1037,7 @@ void LLFolderViewItem::draw()
if(label_filter_length > 0)
{
F32 match_string_left = text_left + font->getWidthF32(mLabel.c_str(), 0, filter_offset + label_filter_length) - font->getWidthF32(mLabel.c_str(), filter_offset, label_filter_length);
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
F32 yy = (F32)rect_height - line_height - (F32)mTextPad - (F32)sTopPad;
font->render(mLabel, filter_offset, match_string_left, yy,
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
label_filter_length, S32_MAX, &right_x);
@ -1033,9 +1047,9 @@ void LLFolderViewItem::draw()
if(suffix_filter_length > 0)
{
S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size());
F32 match_string_left = text_left + font->getWidthF32(mLabel.c_str(), 0, static_cast<S32>(mLabel.size())) + suffix_font->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset + suffix_filter_length) - suffix_font->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length);
F32 yy = (F32)getRect().getHeight() - suffix_font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
suffix_font->render(mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor,
F32 match_string_left = text_left + font->getWidthF32(mLabel.c_str(), 0, static_cast<S32>(mLabel.size())) + sSuffixFont->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset + suffix_filter_length) - sSuffixFont->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length);
F32 yy = (F32)rect_height - sSuffixFont->getLineHeight() - (F32)mTextPad - (F32)sTopPad;
sSuffixFont->render(mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor,
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
suffix_filter_length, S32_MAX, &right_x);
}

View File

@ -29,6 +29,7 @@
#include "llflashtimer.h"
#include "llview.h"
#include "lluiimage.h"
#include "llfontvertexbuffer.h"
class LLFolderView;
class LLFolderViewModelItem;
@ -134,7 +135,6 @@ protected:
LLUIColor mFontHighlightColor;
// For now assuming all colors are the same in derived classes.
static bool sColorSetInitialized;
static LLUIColor sFgColor;
static LLUIColor sFgDisabledColor;
static LLUIColor sHighlightBgColor;
@ -157,6 +157,7 @@ protected:
virtual void setFlashState(bool) { }
static LLFontGL* getLabelFontForStyle(U8 style);
const LLFontGL* getLabelFont();
bool mIsSelected;
@ -296,9 +297,9 @@ public:
// virtual void handleDropped();
virtual void draw();
void drawOpenFolderArrow(const Params& default_params, const LLUIColor& fg_color);
void drawHighlight(const bool showContent, const bool hasKeyboardFocus, const LLUIColor &selectColor, const LLUIColor &flashColor, const LLUIColor &outlineColor, const LLUIColor &mouseOverColor);
void drawLabel(const LLFontGL * font, const F32 x, const F32 y, const LLColor4& color, F32 &right_x);
void drawOpenFolderArrow();
void drawHighlight(bool showContent, bool hasKeyboardFocus, const LLUIColor& selectColor, const LLUIColor& flashColor, const LLUIColor& outlineColor, const LLUIColor& mouseOverColor);
void drawLabel(const LLFontGL* font, const F32 x, const F32 y, const LLColor4& color, F32 &right_x);
virtual bool handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
EDragAndDropType cargo_type,
void* cargo_data,
@ -307,6 +308,14 @@ public:
private:
static std::map<U8, LLFontGL*> sFonts; // map of styles to fonts
static S32 sTopPad;
static LLUIImagePtr sFolderArrowImg;
static LLUIImagePtr sSelectionImg;
static LLFontGL* sSuffixFont;
LLFontVertexBuffer mLabelFontBuffer;
LLFontVertexBuffer mSuffixFontBuffer;
LLFontGL* pLabelFont{nullptr};
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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